This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[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
15 #include <mono/metadata/appdomain.h>
16 #include <mono/metadata/debug-helpers.h>
17 #include <mono/metadata/profiler-private.h>
18 #include <mono/utils/mono-math.h>
19
20 #include "trace.h"
21 #include "mini-x86.h"
22 #include "inssel.h"
23 #include "cpu-pentium.h"
24
25 static gint lmf_tls_offset = -1;
26
27 #ifdef PLATFORM_WIN32
28 /* Under windows, the default pinvoke calling convention is stdcall */
29 #define CALLCONV_IS_STDCALL(call_conv) (((call_conv) == MONO_CALL_STDCALL) || ((call_conv) == MONO_CALL_DEFAULT))
30 #else
31 #define CALLCONV_IS_STDCALL(call_conv) ((call_conv) == MONO_CALL_STDCALL)
32 #endif
33
34 #define SIGNAL_STACK_SIZE (64 * 1024)
35
36 const char*
37 mono_arch_regname (int reg) {
38         switch (reg) {
39         case X86_EAX: return "%eax";
40         case X86_EBX: return "%ebx";
41         case X86_ECX: return "%ecx";
42         case X86_EDX: return "%edx";
43         case X86_ESP: return "%esp";    case X86_EBP: return "%ebp";
44         case X86_EDI: return "%edi";
45         case X86_ESI: return "%esi";
46         }
47         return "unknown";
48 }
49
50 /*
51  * mono_arch_get_argument_info:
52  * @csig:  a method signature
53  * @param_count: the number of parameters to consider
54  * @arg_info: an array to store the result infos
55  *
56  * Gathers information on parameters such as size, alignment and
57  * padding. arg_info should be large enought to hold param_count + 1 entries. 
58  *
59  * Returns the size of the activation frame.
60  */
61 int
62 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
63 {
64         int k, frame_size = 0;
65         int size, align, pad;
66         int offset = 8;
67
68         if (MONO_TYPE_ISSTRUCT (csig->ret)) { 
69                 frame_size += sizeof (gpointer);
70                 offset += 4;
71         }
72
73         arg_info [0].offset = offset;
74
75         if (csig->hasthis) {
76                 frame_size += sizeof (gpointer);
77                 offset += 4;
78         }
79
80         arg_info [0].size = frame_size;
81
82         for (k = 0; k < param_count; k++) {
83                 
84                 if (csig->pinvoke)
85                         size = mono_type_native_stack_size (csig->params [k], &align);
86                 else
87                         size = mono_type_stack_size (csig->params [k], &align);
88
89                 /* ignore alignment for now */
90                 align = 1;
91
92                 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); 
93                 arg_info [k].pad = pad;
94                 frame_size += size;
95                 arg_info [k + 1].pad = 0;
96                 arg_info [k + 1].size = size;
97                 offset += pad;
98                 arg_info [k + 1].offset = offset;
99                 offset += size;
100         }
101
102         align = MONO_ARCH_FRAME_ALIGNMENT;
103         frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
104         arg_info [k].pad = pad;
105
106         return frame_size;
107 }
108
109 static const guchar cpuid_impl [] = {
110         0x55,                           /* push   %ebp */
111         0x89, 0xe5,                     /* mov    %esp,%ebp */
112         0x53,                           /* push   %ebx */
113         0x8b, 0x45, 0x08,               /* mov    0x8(%ebp),%eax */
114         0x0f, 0xa2,                     /* cpuid   */
115         0x50,                           /* push   %eax */
116         0x8b, 0x45, 0x10,               /* mov    0x10(%ebp),%eax */
117         0x89, 0x18,                     /* mov    %ebx,(%eax) */
118         0x8b, 0x45, 0x14,               /* mov    0x14(%ebp),%eax */
119         0x89, 0x08,                     /* mov    %ecx,(%eax) */
120         0x8b, 0x45, 0x18,               /* mov    0x18(%ebp),%eax */
121         0x89, 0x10,                     /* mov    %edx,(%eax) */
122         0x58,                           /* pop    %eax */
123         0x8b, 0x55, 0x0c,               /* mov    0xc(%ebp),%edx */
124         0x89, 0x02,                     /* mov    %eax,(%edx) */
125         0x5b,                           /* pop    %ebx */
126         0xc9,                           /* leave   */
127         0xc3,                           /* ret     */
128 };
129
130 typedef void (*CpuidFunc) (int id, int* p_eax, int* p_ebx, int* p_ecx, int* p_edx);
131
132 static int 
133 cpuid (int id, int* p_eax, int* p_ebx, int* p_ecx, int* p_edx)
134 {
135         int have_cpuid = 0;
136         __asm__  __volatile__ (
137                 "pushfl\n"
138                 "popl %%eax\n"
139                 "movl %%eax, %%edx\n"
140                 "xorl $0x200000, %%eax\n"
141                 "pushl %%eax\n"
142                 "popfl\n"
143                 "pushfl\n"
144                 "popl %%eax\n"
145                 "xorl %%edx, %%eax\n"
146                 "andl $0x200000, %%eax\n"
147                 "movl %%eax, %0"
148                 : "=r" (have_cpuid)
149                 :
150                 : "%eax", "%edx"
151         );
152
153         if (have_cpuid) {
154                 CpuidFunc func = (CpuidFunc)cpuid_impl;
155                 func (id, p_eax, p_ebx, p_ecx, p_edx);
156                 /*
157                  * We use this approach because of issues with gcc and pic code, see:
158                  * http://gcc.gnu.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=gcc&pr=7329
159                 __asm__ __volatile__ ("cpuid"
160                         : "=a" (*p_eax), "=b" (*p_ebx), "=c" (*p_ecx), "=d" (*p_edx)
161                         : "a" (id));
162                 */
163                 return 1;
164         }
165         return 0;
166 }
167
168 /*
169  * Initialize the cpu to execute managed code.
170  */
171 void
172 mono_arch_cpu_init (void)
173 {
174         guint16 fpcw;
175
176         /* spec compliance requires running with double precision */
177         __asm__  __volatile__ ("fnstcw %0\n": "=m" (fpcw));
178         fpcw &= ~X86_FPCW_PRECC_MASK;
179         fpcw |= X86_FPCW_PREC_DOUBLE;
180         __asm__  __volatile__ ("fldcw %0\n": : "m" (fpcw));
181         __asm__  __volatile__ ("fnstcw %0\n": "=m" (fpcw));
182
183 }
184
185 /*
186  * This function returns the optimizations supported on this cpu.
187  */
188 guint32
189 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
190 {
191         int eax, ebx, ecx, edx;
192         guint32 opts = 0;
193         
194         *exclude_mask = 0;
195         /* Feature Flags function, flags returned in EDX. */
196         if (cpuid (1, &eax, &ebx, &ecx, &edx)) {
197                 if (edx & (1 << 15)) {
198                         opts |= MONO_OPT_CMOV;
199                         if (edx & 1)
200                                 opts |= MONO_OPT_FCMOV;
201                         else
202                                 *exclude_mask |= MONO_OPT_FCMOV;
203                 } else
204                         *exclude_mask |= MONO_OPT_CMOV;
205         }
206         return opts;
207 }
208
209 static gboolean
210 is_regsize_var (MonoType *t) {
211         if (t->byref)
212                 return TRUE;
213         switch (t->type) {
214         case MONO_TYPE_I4:
215         case MONO_TYPE_U4:
216         case MONO_TYPE_I:
217         case MONO_TYPE_U:
218         case MONO_TYPE_PTR:
219                 return TRUE;
220         case MONO_TYPE_OBJECT:
221         case MONO_TYPE_STRING:
222         case MONO_TYPE_CLASS:
223         case MONO_TYPE_SZARRAY:
224         case MONO_TYPE_ARRAY:
225                 return TRUE;
226         case MONO_TYPE_VALUETYPE:
227                 if (t->data.klass->enumtype)
228                         return is_regsize_var (t->data.klass->enum_basetype);
229                 return FALSE;
230         }
231         return FALSE;
232 }
233
234 GList *
235 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
236 {
237         GList *vars = NULL;
238         int i;
239
240         for (i = 0; i < cfg->num_varinfo; i++) {
241                 MonoInst *ins = cfg->varinfo [i];
242                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
243
244                 /* unused vars */
245                 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
246                         continue;
247
248                 if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) || 
249                     (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
250                         continue;
251
252                 /* we dont allocate I1 to registers because there is no simply way to sign extend 
253                  * 8bit quantities in caller saved registers on x86 */
254                 if (is_regsize_var (ins->inst_vtype) || (ins->inst_vtype->type == MONO_TYPE_BOOLEAN) || 
255                     (ins->inst_vtype->type == MONO_TYPE_U1) || (ins->inst_vtype->type == MONO_TYPE_U2)||
256                     (ins->inst_vtype->type == MONO_TYPE_I2) || (ins->inst_vtype->type == MONO_TYPE_CHAR)) {
257                         g_assert (MONO_VARINFO (cfg, i)->reg == -1);
258                         g_assert (i == vmv->idx);
259                         vars = g_list_prepend (vars, vmv);
260                 }
261         }
262
263         vars = mono_varlist_sort (cfg, vars, 0);
264
265         return vars;
266 }
267
268 GList *
269 mono_arch_get_global_int_regs (MonoCompile *cfg)
270 {
271         GList *regs = NULL;
272
273         /* we can use 3 registers for global allocation */
274         regs = g_list_prepend (regs, (gpointer)X86_EBX);
275         regs = g_list_prepend (regs, (gpointer)X86_ESI);
276         regs = g_list_prepend (regs, (gpointer)X86_EDI);
277
278         return regs;
279 }
280
281 /*
282  * mono_arch_regalloc_cost:
283  *
284  *  Return the cost, in number of memory references, of the action of 
285  * allocating the variable VMV into a register during global register
286  * allocation.
287  */
288 guint32
289 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
290 {
291         MonoInst *ins = cfg->varinfo [vmv->idx];
292
293         if (cfg->method->save_lmf)
294                 /* The register is already saved */
295                 return (ins->opcode == OP_ARG) ? 1 : 0;
296         else
297                 /* push+pop+possible load if it is an argument */
298                 return (ins->opcode == OP_ARG) ? 3 : 2;
299 }
300  
301 /*
302  * Set var information according to the calling convention. X86 version.
303  * The locals var stuff should most likely be split in another method.
304  */
305 void
306 mono_arch_allocate_vars (MonoCompile *m)
307 {
308         MonoMethodSignature *sig;
309         MonoMethodHeader *header;
310         MonoInst *inst;
311         int i, offset, size, align, curinst;
312
313         header = ((MonoMethodNormal *)m->method)->header;
314
315         sig = m->method->signature;
316
317         offset = 8;
318         curinst = 0;
319         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
320                 m->ret->opcode = OP_REGOFFSET;
321                 m->ret->inst_basereg = X86_EBP;
322                 m->ret->inst_offset = offset;
323                 offset += sizeof (gpointer);
324         } else {
325                 /* FIXME: handle long and FP values */
326                 switch (sig->ret->type) {
327                 case MONO_TYPE_VOID:
328                         break;
329                 default:
330                         m->ret->opcode = OP_REGVAR;
331                         m->ret->inst_c0 = X86_EAX;
332                         break;
333                 }
334         }
335         if (sig->hasthis) {
336                 inst = m->varinfo [curinst];
337                 if (inst->opcode != OP_REGVAR) {
338                         inst->opcode = OP_REGOFFSET;
339                         inst->inst_basereg = X86_EBP;
340                 }
341                 inst->inst_offset = offset;
342                 offset += sizeof (gpointer);
343                 curinst++;
344         }
345
346         if (sig->call_convention == MONO_CALL_VARARG) {
347                 m->sig_cookie = offset;
348                 offset += sizeof (gpointer);
349         }
350
351         for (i = 0; i < sig->param_count; ++i) {
352                 inst = m->varinfo [curinst];
353                 if (inst->opcode != OP_REGVAR) {
354                         inst->opcode = OP_REGOFFSET;
355                         inst->inst_basereg = X86_EBP;
356                 }
357                 inst->inst_offset = offset;
358                 size = mono_type_size (sig->params [i], &align);
359                 size += 4 - 1;
360                 size &= ~(4 - 1);
361                 offset += size;
362                 curinst++;
363         }
364
365         offset = 0;
366
367         /* reserve space to save LMF and caller saved registers */
368
369         if (m->method->save_lmf) {
370                 offset += sizeof (MonoLMF);
371         } else {
372                 if (m->used_int_regs & (1 << X86_EBX)) {
373                         offset += 4;
374                 }
375
376                 if (m->used_int_regs & (1 << X86_EDI)) {
377                         offset += 4;
378                 }
379
380                 if (m->used_int_regs & (1 << X86_ESI)) {
381                         offset += 4;
382                 }
383         }
384
385         for (i = curinst; i < m->num_varinfo; ++i) {
386                 inst = m->varinfo [i];
387
388                 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
389                         continue;
390
391                 /* inst->unused indicates native sized value types, this is used by the
392                 * pinvoke wrappers when they call functions returning structure */
393                 if (inst->unused && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
394                         size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
395                 else
396                         size = mono_type_size (inst->inst_vtype, &align);
397
398                 offset += size;
399                 offset += align - 1;
400                 offset &= ~(align - 1);
401                 inst->opcode = OP_REGOFFSET;
402                 inst->inst_basereg = X86_EBP;
403                 inst->inst_offset = -offset;
404                 //g_print ("allocating local %d to %d\n", i, -offset);
405         }
406         offset += (MONO_ARCH_FRAME_ALIGNMENT - 1);
407         offset &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
408
409         /* change sign? */
410         m->stack_offset = -offset;
411 }
412
413 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
414  * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info 
415  */
416
417 /* 
418  * take the arguments and generate the arch-specific
419  * instructions to properly call the function in call.
420  * This includes pushing, moving arguments to the right register
421  * etc.
422  * Issue: who does the spilling if needed, and when?
423  */
424 MonoCallInst*
425 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
426         MonoInst *arg, *in;
427         MonoMethodSignature *sig;
428         int i, n, stack_size, type;
429         MonoType *ptype;
430
431         stack_size = 0;
432         /* add the vararg cookie before the non-implicit args */
433         if (call->signature->call_convention == MONO_CALL_VARARG) {
434                 MonoInst *sig_arg;
435                 /* FIXME: Add support for signature tokens to AOT */
436                 cfg->disable_aot = TRUE;
437                 MONO_INST_NEW (cfg, arg, OP_OUTARG);
438                 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
439                 sig_arg->inst_p0 = call->signature;
440                 arg->inst_left = sig_arg;
441                 arg->type = STACK_PTR;
442                 /* prepend, so they get reversed */
443                 arg->next = call->out_args;
444                 call->out_args = arg;
445                 stack_size += sizeof (gpointer);
446         }
447         sig = call->signature;
448         n = sig->param_count + sig->hasthis;
449
450         if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
451                 stack_size += sizeof (gpointer);
452         for (i = 0; i < n; ++i) {
453                 if (is_virtual && i == 0) {
454                         /* the argument will be attached to the call instrucion */
455                         in = call->args [i];
456                         stack_size += 4;
457                 } else {
458                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
459                         in = call->args [i];
460                         arg->cil_code = in->cil_code;
461                         arg->inst_left = in;
462                         arg->type = in->type;
463                         /* prepend, so they get reversed */
464                         arg->next = call->out_args;
465                         call->out_args = arg;
466                         if (i >= sig->hasthis) {
467                                 ptype = sig->params [i - sig->hasthis];
468                                 if (ptype->byref)
469                                         type = MONO_TYPE_U;
470                                 else
471                                         type = ptype->type;
472 handle_enum:
473                                 /* FIXME: validate arguments... */
474                                 switch (type) {
475                                 case MONO_TYPE_I:
476                                 case MONO_TYPE_U:
477                                 case MONO_TYPE_BOOLEAN:
478                                 case MONO_TYPE_CHAR:
479                                 case MONO_TYPE_I1:
480                                 case MONO_TYPE_U1:
481                                 case MONO_TYPE_I2:
482                                 case MONO_TYPE_U2:
483                                 case MONO_TYPE_I4:
484                                 case MONO_TYPE_U4:
485                                 case MONO_TYPE_STRING:
486                                 case MONO_TYPE_CLASS:
487                                 case MONO_TYPE_OBJECT:
488                                 case MONO_TYPE_PTR:
489                                 case MONO_TYPE_FNPTR:
490                                 case MONO_TYPE_ARRAY:
491                                 case MONO_TYPE_SZARRAY:
492                                         stack_size += 4;
493                                         break;
494                                 case MONO_TYPE_I8:
495                                 case MONO_TYPE_U8:
496                                         stack_size += 8;
497                                         break;
498                                 case MONO_TYPE_R4:
499                                         stack_size += 4;
500                                         arg->opcode = OP_OUTARG_R4;
501                                         break;
502                                 case MONO_TYPE_R8:
503                                         stack_size += 8;
504                                         arg->opcode = OP_OUTARG_R8;
505                                         break;
506                                 case MONO_TYPE_VALUETYPE:
507                                         if (MONO_TYPE_ISSTRUCT (ptype)) {
508                                                 int size;
509                                                 if (sig->pinvoke) 
510                                                         size = mono_type_native_stack_size (&in->klass->byval_arg, NULL);
511                                                 else 
512                                                         size = mono_type_stack_size (&in->klass->byval_arg, NULL);
513
514                                                 stack_size += size;
515                                                 arg->opcode = OP_OUTARG_VT;
516                                                 arg->klass = in->klass;
517                                                 arg->unused = sig->pinvoke;
518                                                 arg->inst_imm = size; 
519                                         } else {
520                                                 type = ptype->data.klass->enum_basetype->type;
521                                                 goto handle_enum;
522                                         }
523                                         break;
524                                 case MONO_TYPE_TYPEDBYREF:
525                                         stack_size += sizeof (MonoTypedRef);
526                                         arg->opcode = OP_OUTARG_VT;
527                                         arg->klass = in->klass;
528                                         arg->unused = sig->pinvoke;
529                                         arg->inst_imm = sizeof (MonoTypedRef); 
530                                         break;
531                                 case MONO_TYPE_GENERICINST:
532                                         type = ptype->data.generic_inst->generic_type->type;
533                                         goto handle_enum;
534
535                                 default:
536                                         g_error ("unknown type 0x%02x in mono_arch_call_opcode\n", type);
537                                 }
538                         } else {
539                                 /* the this argument */
540                                 stack_size += 4;
541                         }
542                 }
543         }
544         /* if the function returns a struct, the called method already does a ret $0x4 */
545         if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
546                 stack_size -= 4;
547         call->stack_usage = stack_size;
548         /* 
549          * should set more info in call, such as the stack space
550          * used by the args that needs to be added back to esp
551          */
552
553         return call;
554 }
555
556 /*
557  * Allow tracing to work with this interface (with an optional argument)
558  */
559
560 /*
561  * This may be needed on some archs or for debugging support.
562  */
563 void
564 mono_arch_instrument_mem_needs (MonoMethod *method, int *stack, int *code)
565 {
566         /* no stack room needed now (may be needed for FASTCALL-trace support) */
567         *stack = 0;
568         /* split prolog-epilog requirements? */
569         *code = 50; /* max bytes needed: check this number */
570 }
571
572 void*
573 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
574 {
575         guchar *code = p;
576
577         /* if some args are passed in registers, we need to save them here */
578         x86_push_reg (code, X86_EBP);
579         mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_METHODCONST, cfg->method);
580         x86_push_imm (code, cfg->method);
581         mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_ABS, func);
582         x86_call_code (code, 0);
583         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
584
585         return code;
586 }
587
588 enum {
589         SAVE_NONE,
590         SAVE_STRUCT,
591         SAVE_EAX,
592         SAVE_EAX_EDX,
593         SAVE_FP
594 };
595
596 void*
597 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
598 {
599         guchar *code = p;
600         int arg_size = 0, save_mode = SAVE_NONE;
601         MonoMethod *method = cfg->method;
602         int rtype = method->signature->ret->type;
603         
604 handle_enum:
605         switch (rtype) {
606         case MONO_TYPE_VOID:
607                 /* special case string .ctor icall */
608                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
609                         save_mode = SAVE_EAX;
610                 else
611                         save_mode = SAVE_NONE;
612                 break;
613         case MONO_TYPE_I8:
614         case MONO_TYPE_U8:
615                 save_mode = SAVE_EAX_EDX;
616                 break;
617         case MONO_TYPE_R4:
618         case MONO_TYPE_R8:
619                 save_mode = SAVE_FP;
620                 break;
621         case MONO_TYPE_VALUETYPE:
622                 if (method->signature->ret->data.klass->enumtype) {
623                         rtype = method->signature->ret->data.klass->enum_basetype->type;
624                         goto handle_enum;
625                 }
626                 save_mode = SAVE_STRUCT;
627                 break;
628         default:
629                 save_mode = SAVE_EAX;
630                 break;
631         }
632
633         switch (save_mode) {
634         case SAVE_EAX_EDX:
635                 x86_push_reg (code, X86_EDX);
636                 x86_push_reg (code, X86_EAX);
637                 if (enable_arguments) {
638                         x86_push_reg (code, X86_EDX);
639                         x86_push_reg (code, X86_EAX);
640                         arg_size = 8;
641                 }
642                 break;
643         case SAVE_EAX:
644                 x86_push_reg (code, X86_EAX);
645                 if (enable_arguments) {
646                         x86_push_reg (code, X86_EAX);
647                         arg_size = 4;
648                 }
649                 break;
650         case SAVE_FP:
651                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
652                 x86_fst_membase (code, X86_ESP, 0, TRUE, TRUE);
653                 if (enable_arguments) {
654                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
655                         x86_fst_membase (code, X86_ESP, 0, TRUE, TRUE);
656                         arg_size = 8;
657                 }
658                 break;
659         case SAVE_STRUCT:
660                 if (enable_arguments) {
661                         x86_push_membase (code, X86_EBP, 8);
662                         arg_size = 4;
663                 }
664                 break;
665         case SAVE_NONE:
666         default:
667                 break;
668         }
669
670
671         mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_METHODCONST, method);
672         x86_push_imm (code, method);
673         mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_ABS, func);
674         x86_call_code (code, 0);
675         x86_alu_reg_imm (code, X86_ADD, X86_ESP, arg_size + 4);
676
677         switch (save_mode) {
678         case SAVE_EAX_EDX:
679                 x86_pop_reg (code, X86_EAX);
680                 x86_pop_reg (code, X86_EDX);
681                 break;
682         case SAVE_EAX:
683                 x86_pop_reg (code, X86_EAX);
684                 break;
685         case SAVE_FP:
686                 x86_fld_membase (code, X86_ESP, 0, TRUE);
687                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
688                 break;
689         case SAVE_NONE:
690         default:
691                 break;
692         }
693
694         return code;
695 }
696
697 #define EMIT_COND_BRANCH(ins,cond,sign) \
698 if (ins->flags & MONO_INST_BRLABEL) { \
699         if (ins->inst_i0->inst_c0) { \
700                 x86_branch (code, cond, cfg->native_code + ins->inst_i0->inst_c0, sign); \
701         } else { \
702                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
703                 if ((cfg->opt & MONO_OPT_BRANCH) && \
704                     x86_is_imm8 (ins->inst_i0->inst_c1 - cpos)) \
705                         x86_branch8 (code, cond, 0, sign); \
706                 else \
707                         x86_branch32 (code, cond, 0, sign); \
708         } \
709 } else { \
710         if (ins->inst_true_bb->native_offset) { \
711                 x86_branch (code, cond, cfg->native_code + ins->inst_true_bb->native_offset, sign); \
712         } else { \
713                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
714                 if ((cfg->opt & MONO_OPT_BRANCH) && \
715                     x86_is_imm8 (ins->inst_true_bb->max_offset - cpos)) \
716                         x86_branch8 (code, cond, 0, sign); \
717                 else \
718                         x86_branch32 (code, cond, 0, sign); \
719         } \
720 }
721
722 /* emit an exception if condition is fail */
723 #define EMIT_COND_SYSTEM_EXCEPTION(cond,signed,exc_name)            \
724         do {                                                        \
725                 mono_add_patch_info (cfg, code - cfg->native_code,   \
726                                     MONO_PATCH_INFO_EXC, exc_name);  \
727                 x86_branch32 (code, cond, 0, signed);               \
728         } while (0); 
729
730 #define EMIT_FPCOMPARE(code) do { \
731         x86_fcompp (code); \
732         x86_fnstsw (code); \
733 } while (0); 
734
735 /* FIXME: Add more instructions */
736 #define INST_IGNORES_CFLAGS(ins) (((ins)->opcode == CEE_BR) || ((ins)->opcode == OP_STORE_MEMBASE_IMM))
737
738 static void
739 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
740 {
741         MonoInst *ins, *last_ins = NULL;
742         ins = bb->code;
743
744         while (ins) {
745
746                 switch (ins->opcode) {
747                 case OP_ICONST:
748                         /* reg = 0 -> XOR (reg, reg) */
749                         /* XOR sets cflags on x86, so we cant do it always */
750                         if (ins->inst_c0 == 0 && ins->next && INST_IGNORES_CFLAGS (ins->next)) {
751                                 ins->opcode = CEE_XOR;
752                                 ins->sreg1 = ins->dreg;
753                                 ins->sreg2 = ins->dreg;
754                         }
755                         break;
756                 case OP_MUL_IMM: 
757                         /* remove unnecessary multiplication with 1 */
758                         if (ins->inst_imm == 1) {
759                                 if (ins->dreg != ins->sreg1) {
760                                         ins->opcode = OP_MOVE;
761                                 } else {
762                                         last_ins->next = ins->next;
763                                         ins = ins->next;
764                                         continue;
765                                 }
766                         }
767                         break;
768                 case OP_COMPARE_IMM:
769                         /* OP_COMPARE_IMM (reg, 0) 
770                          * --> 
771                          * OP_X86_TEST_NULL (reg) 
772                          */
773                         if (ins->inst_imm == 0 && ins->next &&
774                             (ins->next->opcode == CEE_BEQ || ins->next->opcode == CEE_BNE_UN ||
775                              ins->next->opcode == OP_CEQ)) {
776                                 ins->opcode = OP_X86_TEST_NULL;
777                         }     
778                         break;
779                 case OP_X86_COMPARE_MEMBASE_IMM:
780                         /* 
781                          * OP_STORE_MEMBASE_REG reg, offset(basereg)
782                          * OP_X86_COMPARE_MEMBASE_IMM offset(basereg), imm
783                          * -->
784                          * OP_STORE_MEMBASE_REG reg, offset(basereg)
785                          * OP_COMPARE_IMM reg, imm
786                          *
787                          * Note: if imm = 0 then OP_COMPARE_IMM replaced with OP_X86_TEST_NULL
788                          */
789                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
790                             ins->inst_basereg == last_ins->inst_destbasereg &&
791                             ins->inst_offset == last_ins->inst_offset) {
792                                         ins->opcode = OP_COMPARE_IMM;
793                                         ins->sreg1 = last_ins->sreg1;
794
795                                         /* check if we can remove cmp reg,0 with test null */
796                                         if (ins->inst_imm == 0 && ins->next &&
797                                                 (ins->next->opcode == CEE_BEQ || ins->next->opcode == CEE_BNE_UN ||
798                                                 ins->next->opcode == OP_CEQ)) {
799                                                 ins->opcode = OP_X86_TEST_NULL;
800                                         }     
801                                 }
802
803                         break;
804                 case OP_LOAD_MEMBASE:
805                 case OP_LOADI4_MEMBASE:
806                         /* 
807                          * Note: if reg1 = reg2 the load op is removed
808                          *
809                          * OP_STORE_MEMBASE_REG reg1, offset(basereg) 
810                          * OP_LOAD_MEMBASE offset(basereg), reg2
811                          * -->
812                          * OP_STORE_MEMBASE_REG reg1, offset(basereg)
813                          * OP_MOVE reg1, reg2
814                          */
815                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG 
816                                          || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
817                             ins->inst_basereg == last_ins->inst_destbasereg &&
818                             ins->inst_offset == last_ins->inst_offset) {
819                                 if (ins->dreg == last_ins->sreg1) {
820                                         last_ins->next = ins->next;                             
821                                         ins = ins->next;                                
822                                         continue;
823                                 } else {
824                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
825                                         ins->opcode = OP_MOVE;
826                                         ins->sreg1 = last_ins->sreg1;
827                                 }
828
829                         /* 
830                          * Note: reg1 must be different from the basereg in the second load
831                          * Note: if reg1 = reg2 is equal then second load is removed
832                          *
833                          * OP_LOAD_MEMBASE offset(basereg), reg1
834                          * OP_LOAD_MEMBASE offset(basereg), reg2
835                          * -->
836                          * OP_LOAD_MEMBASE offset(basereg), reg1
837                          * OP_MOVE reg1, reg2
838                          */
839                         } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
840                                            || last_ins->opcode == OP_LOAD_MEMBASE) &&
841                               ins->inst_basereg != last_ins->dreg &&
842                               ins->inst_basereg == last_ins->inst_basereg &&
843                               ins->inst_offset == last_ins->inst_offset) {
844
845                                 if (ins->dreg == last_ins->dreg) {
846                                         last_ins->next = ins->next;                             
847                                         ins = ins->next;                                
848                                         continue;
849                                 } else {
850                                         ins->opcode = OP_MOVE;
851                                         ins->sreg1 = last_ins->dreg;
852                                 }
853
854                                 //g_assert_not_reached ();
855
856 #if 0
857                         /* 
858                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
859                          * OP_LOAD_MEMBASE offset(basereg), reg
860                          * -->
861                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
862                          * OP_ICONST reg, imm
863                          */
864                         } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
865                                                 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
866                                    ins->inst_basereg == last_ins->inst_destbasereg &&
867                                    ins->inst_offset == last_ins->inst_offset) {
868                                 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
869                                 ins->opcode = OP_ICONST;
870                                 ins->inst_c0 = last_ins->inst_imm;
871                                 g_assert_not_reached (); // check this rule
872 #endif
873                         }
874                         break;
875                 case OP_LOADU1_MEMBASE:
876                 case OP_LOADI1_MEMBASE:
877                         /* 
878                          * Note: if reg1 = reg2 the load op is removed
879                          *
880                          * OP_STORE_MEMBASE_REG reg1, offset(basereg) 
881                          * OP_LOAD_MEMBASE offset(basereg), reg2
882                          * -->
883                          * OP_STORE_MEMBASE_REG reg1, offset(basereg)
884                          * OP_MOVE reg1, reg2
885                          */
886                         if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
887                                         ins->inst_basereg == last_ins->inst_destbasereg &&
888                                         ins->inst_offset == last_ins->inst_offset) {
889                                 if (ins->dreg == last_ins->sreg1) {
890                                         last_ins->next = ins->next;                             
891                                         ins = ins->next;                                
892                                         continue;
893                                 } else {
894                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
895                                         ins->opcode = OP_MOVE;
896                                         ins->sreg1 = last_ins->sreg1;
897                                 }
898                         }
899                         break;
900                 case OP_LOADU2_MEMBASE:
901                 case OP_LOADI2_MEMBASE:
902                         /* 
903                          * Note: if reg1 = reg2 the load op is removed
904                          *
905                          * OP_STORE_MEMBASE_REG reg1, offset(basereg) 
906                          * OP_LOAD_MEMBASE offset(basereg), reg2
907                          * -->
908                          * OP_STORE_MEMBASE_REG reg1, offset(basereg)
909                          * OP_MOVE reg1, reg2
910                          */
911                         if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
912                                         ins->inst_basereg == last_ins->inst_destbasereg &&
913                                         ins->inst_offset == last_ins->inst_offset) {
914                                 if (ins->dreg == last_ins->sreg1) {
915                                         last_ins->next = ins->next;                             
916                                         ins = ins->next;                                
917                                         continue;
918                                 } else {
919                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
920                                         ins->opcode = OP_MOVE;
921                                         ins->sreg1 = last_ins->sreg1;
922                                 }
923                         }
924                         break;
925                 case CEE_CONV_I4:
926                 case CEE_CONV_U4:
927                 case OP_MOVE:
928                         /*
929                          * Removes:
930                          *
931                          * OP_MOVE reg, reg 
932                          */
933                         if (ins->dreg == ins->sreg1) {
934                                 if (last_ins)
935                                         last_ins->next = ins->next;                             
936                                 ins = ins->next;
937                                 continue;
938                         }
939                         /* 
940                          * Removes:
941                          *
942                          * OP_MOVE sreg, dreg 
943                          * OP_MOVE dreg, sreg
944                          */
945                         if (last_ins && last_ins->opcode == OP_MOVE &&
946                             ins->sreg1 == last_ins->dreg &&
947                             ins->dreg == last_ins->sreg1) {
948                                 last_ins->next = ins->next;                             
949                                 ins = ins->next;                                
950                                 continue;
951                         }
952                         break;
953                 }
954                 last_ins = ins;
955                 ins = ins->next;
956         }
957         bb->last_ins = last_ins;
958 }
959
960 static const int 
961 branch_cc_table [] = {
962         X86_CC_EQ, X86_CC_GE, X86_CC_GT, X86_CC_LE, X86_CC_LT,
963         X86_CC_NE, X86_CC_GE, X86_CC_GT, X86_CC_LE, X86_CC_LT,
964         X86_CC_O, X86_CC_NO, X86_CC_C, X86_CC_NC
965 };
966
967 #define DEBUG(a) if (cfg->verbose_level > 1) a
968 //#define DEBUG(a)
969
970 /*
971  * returns the offset used by spillvar. It allocates a new
972  * spill variable if necessary. 
973  */
974 static int
975 mono_spillvar_offset (MonoCompile *cfg, int spillvar)
976 {
977         MonoSpillInfo **si, *info;
978         int i = 0;
979
980         si = &cfg->spill_info; 
981         
982         while (i <= spillvar) {
983
984                 if (!*si) {
985                         *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
986                         info->next = NULL;
987                         cfg->stack_offset -= sizeof (gpointer);
988                         info->offset = cfg->stack_offset;
989                 }
990
991                 if (i == spillvar)
992                         return (*si)->offset;
993
994                 i++;
995                 si = &(*si)->next;
996         }
997
998         g_assert_not_reached ();
999         return 0;
1000 }
1001
1002 /*
1003  * returns the offset used by spillvar. It allocates a new
1004  * spill float variable if necessary. 
1005  * (same as mono_spillvar_offset but for float)
1006  */
1007 static int
1008 mono_spillvar_offset_float (MonoCompile *cfg, int spillvar)
1009 {
1010         MonoSpillInfo **si, *info;
1011         int i = 0;
1012
1013         si = &cfg->spill_info_float; 
1014         
1015         while (i <= spillvar) {
1016
1017                 if (!*si) {
1018                         *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
1019                         info->next = NULL;
1020                         cfg->stack_offset -= sizeof (double);
1021                         info->offset = cfg->stack_offset;
1022                 }
1023
1024                 if (i == spillvar)
1025                         return (*si)->offset;
1026
1027                 i++;
1028                 si = &(*si)->next;
1029         }
1030
1031         g_assert_not_reached ();
1032         return 0;
1033 }
1034
1035 /*
1036  * Creates a store for spilled floating point items
1037  */
1038 static MonoInst*
1039 create_spilled_store_float (MonoCompile *cfg, int spill, int reg, MonoInst *ins)
1040 {
1041         MonoInst *store;
1042         MONO_INST_NEW (cfg, store, OP_STORER8_MEMBASE_REG);
1043         store->sreg1 = reg;
1044         store->inst_destbasereg = X86_EBP;
1045         store->inst_offset = mono_spillvar_offset_float (cfg, spill);
1046
1047         DEBUG (g_print ("SPILLED FLOAT STORE (%d at 0x%08x(%%sp)) (from %d)\n", spill, store->inst_offset, reg));
1048         return store;
1049 }
1050
1051 /*
1052  * Creates a load for spilled floating point items 
1053  */
1054 static MonoInst*
1055 create_spilled_load_float (MonoCompile *cfg, int spill, int reg, MonoInst *ins)
1056 {
1057         MonoInst *load;
1058         MONO_INST_NEW (cfg, load, OP_LOADR8_SPILL_MEMBASE);
1059         load->dreg = reg;
1060         load->inst_basereg = X86_EBP;
1061         load->inst_offset = mono_spillvar_offset_float (cfg, spill);
1062
1063         DEBUG (g_print ("SPILLED FLOAT LOAD (%d at 0x%08x(%%sp)) (from %d)\n", spill, load->inst_offset, reg));
1064         return load;
1065 }
1066
1067 #define reg_is_freeable(r) ((r) >= 0 && (r) <= 7 && X86_IS_CALLEE ((r)))
1068
1069 typedef struct {
1070         int born_in;
1071         int killed_in;
1072         int last_use;
1073         int prev_use;
1074         int flags;              /* used to track fp spill/load */
1075 } RegTrack;
1076
1077 static const char*const * ins_spec = pentium_desc;
1078
1079 static void
1080 print_ins (int i, MonoInst *ins)
1081 {
1082         const char *spec = ins_spec [ins->opcode];
1083         g_print ("\t%-2d %s", i, mono_inst_name (ins->opcode));
1084         if (spec [MONO_INST_DEST]) {
1085                 if (ins->dreg >= MONO_MAX_IREGS)
1086                         g_print (" R%d <-", ins->dreg);
1087                 else
1088                         g_print (" %s <-", mono_arch_regname (ins->dreg));
1089         }
1090         if (spec [MONO_INST_SRC1]) {
1091                 if (ins->sreg1 >= MONO_MAX_IREGS)
1092                         g_print (" R%d", ins->sreg1);
1093                 else
1094                         g_print (" %s", mono_arch_regname (ins->sreg1));
1095         }
1096         if (spec [MONO_INST_SRC2]) {
1097                 if (ins->sreg2 >= MONO_MAX_IREGS)
1098                         g_print (" R%d", ins->sreg2);
1099                 else
1100                         g_print (" %s", mono_arch_regname (ins->sreg2));
1101         }
1102         if (spec [MONO_INST_CLOB])
1103                 g_print (" clobbers: %c", spec [MONO_INST_CLOB]);
1104         g_print ("\n");
1105 }
1106
1107 static void
1108 print_regtrack (RegTrack *t, int num)
1109 {
1110         int i;
1111         char buf [32];
1112         const char *r;
1113         
1114         for (i = 0; i < num; ++i) {
1115                 if (!t [i].born_in)
1116                         continue;
1117                 if (i >= MONO_MAX_IREGS) {
1118                         g_snprintf (buf, sizeof(buf), "R%d", i);
1119                         r = buf;
1120                 } else
1121                         r = mono_arch_regname (i);
1122                 g_print ("liveness: %s [%d - %d]\n", r, t [i].born_in, t[i].last_use);
1123         }
1124 }
1125
1126 typedef struct InstList InstList;
1127
1128 struct InstList {
1129         InstList *prev;
1130         InstList *next;
1131         MonoInst *data;
1132 };
1133
1134 static inline InstList*
1135 inst_list_prepend (MonoMemPool *pool, InstList *list, MonoInst *data)
1136 {
1137         InstList *item = mono_mempool_alloc (pool, sizeof (InstList));
1138         item->data = data;
1139         item->prev = NULL;
1140         item->next = list;
1141         if (list)
1142                 list->prev = item;
1143         return item;
1144 }
1145
1146 /*
1147  * Force the spilling of the variable in the symbolic register 'reg'.
1148  */
1149 static int
1150 get_register_force_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, int reg)
1151 {
1152         MonoInst *load;
1153         int i, sel, spill;
1154         
1155         sel = cfg->rs->iassign [reg];
1156         /*i = cfg->rs->isymbolic [sel];
1157         g_assert (i == reg);*/
1158         i = reg;
1159         spill = ++cfg->spill_count;
1160         cfg->rs->iassign [i] = -spill - 1;
1161         mono_regstate_free_int (cfg->rs, sel);
1162         /* we need to create a spill var and insert a load to sel after the current instruction */
1163         MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE);
1164         load->dreg = sel;
1165         load->inst_basereg = X86_EBP;
1166         load->inst_offset = mono_spillvar_offset (cfg, spill);
1167         if (item->prev) {
1168                 while (ins->next != item->prev->data)
1169                         ins = ins->next;
1170         }
1171         load->next = ins->next;
1172         ins->next = load;
1173         DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%ebp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel)));
1174         i = mono_regstate_alloc_int (cfg->rs, 1 << sel);
1175         g_assert (i == sel);
1176
1177         return sel;
1178 }
1179
1180 static int
1181 get_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, guint32 regmask, int reg)
1182 {
1183         MonoInst *load;
1184         int i, sel, spill;
1185
1186         DEBUG (g_print ("\tstart regmask to assign R%d: 0x%08x (R%d <- R%d R%d)\n", reg, regmask, ins->dreg, ins->sreg1, ins->sreg2));
1187         /* exclude the registers in the current instruction */
1188         if (reg != ins->sreg1 && (reg_is_freeable (ins->sreg1) || (ins->sreg1 >= MONO_MAX_IREGS && cfg->rs->iassign [ins->sreg1] >= 0))) {
1189                 if (ins->sreg1 >= MONO_MAX_IREGS)
1190                         regmask &= ~ (1 << cfg->rs->iassign [ins->sreg1]);
1191                 else
1192                         regmask &= ~ (1 << ins->sreg1);
1193                 DEBUG (g_print ("\t\texcluding sreg1 %s\n", mono_arch_regname (ins->sreg1)));
1194         }
1195         if (reg != ins->sreg2 && (reg_is_freeable (ins->sreg2) || (ins->sreg2 >= MONO_MAX_IREGS && cfg->rs->iassign [ins->sreg2] >= 0))) {
1196                 if (ins->sreg2 >= MONO_MAX_IREGS)
1197                         regmask &= ~ (1 << cfg->rs->iassign [ins->sreg2]);
1198                 else
1199                         regmask &= ~ (1 << ins->sreg2);
1200                 DEBUG (g_print ("\t\texcluding sreg2 %s %d\n", mono_arch_regname (ins->sreg2), ins->sreg2));
1201         }
1202         if (reg != ins->dreg && reg_is_freeable (ins->dreg)) {
1203                 regmask &= ~ (1 << ins->dreg);
1204                 DEBUG (g_print ("\t\texcluding dreg %s\n", mono_arch_regname (ins->dreg)));
1205         }
1206
1207         DEBUG (g_print ("\t\tavailable regmask: 0x%08x\n", regmask));
1208         g_assert (regmask); /* need at least a register we can free */
1209         sel = -1;
1210         /* we should track prev_use and spill the register that's farther */
1211         for (i = 0; i < MONO_MAX_IREGS; ++i) {
1212                 if (regmask & (1 << i)) {
1213                         sel = i;
1214                         DEBUG (g_print ("\t\tselected register %s has assignment %d\n", mono_arch_regname (sel), cfg->rs->iassign [sel]));
1215                         break;
1216                 }
1217         }
1218         i = cfg->rs->isymbolic [sel];
1219         spill = ++cfg->spill_count;
1220         cfg->rs->iassign [i] = -spill - 1;
1221         mono_regstate_free_int (cfg->rs, sel);
1222         /* we need to create a spill var and insert a load to sel after the current instruction */
1223         MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE);
1224         load->dreg = sel;
1225         load->inst_basereg = X86_EBP;
1226         load->inst_offset = mono_spillvar_offset (cfg, spill);
1227         if (item->prev) {
1228                 while (ins->next != item->prev->data)
1229                         ins = ins->next;
1230         }
1231         load->next = ins->next;
1232         ins->next = load;
1233         DEBUG (g_print ("\tSPILLED LOAD (%d at 0x%08x(%%ebp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel)));
1234         i = mono_regstate_alloc_int (cfg->rs, 1 << sel);
1235         g_assert (i == sel);
1236         
1237         return sel;
1238 }
1239
1240 static MonoInst*
1241 create_copy_ins (MonoCompile *cfg, int dest, int src, MonoInst *ins)
1242 {
1243         MonoInst *copy;
1244         MONO_INST_NEW (cfg, copy, OP_MOVE);
1245         copy->dreg = dest;
1246         copy->sreg1 = src;
1247         if (ins) {
1248                 copy->next = ins->next;
1249                 ins->next = copy;
1250         }
1251         DEBUG (g_print ("\tforced copy from %s to %s\n", mono_arch_regname (src), mono_arch_regname (dest)));
1252         return copy;
1253 }
1254
1255 static MonoInst*
1256 create_spilled_store (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins)
1257 {
1258         MonoInst *store;
1259         MONO_INST_NEW (cfg, store, OP_STORE_MEMBASE_REG);
1260         store->sreg1 = reg;
1261         store->inst_destbasereg = X86_EBP;
1262         store->inst_offset = mono_spillvar_offset (cfg, spill);
1263         if (ins) {
1264                 store->next = ins->next;
1265                 ins->next = store;
1266         }
1267         DEBUG (g_print ("\tSPILLED STORE (%d at 0x%08x(%%ebp)) R%d (from %s)\n", spill, store->inst_offset, prev_reg, mono_arch_regname (reg)));
1268         return store;
1269 }
1270
1271 static void
1272 insert_before_ins (MonoInst *ins, InstList *item, MonoInst* to_insert)
1273 {
1274         MonoInst *prev;
1275         if (item->next) {
1276                 prev = item->next->data;
1277
1278                 while (prev->next != ins)
1279                         prev = prev->next;
1280                 to_insert->next = ins;
1281                 prev->next = to_insert;
1282         } else {
1283                 to_insert->next = ins;
1284         }
1285         /* 
1286          * needed otherwise in the next instruction we can add an ins to the 
1287          * end and that would get past this instruction.
1288          */
1289         item->data = to_insert; 
1290 }
1291
1292
1293 #if  0
1294 static int
1295 alloc_int_reg (MonoCompile *cfg, InstList *curinst, MonoInst *ins, int sym_reg, guint32 allow_mask)
1296 {
1297         int val = cfg->rs->iassign [sym_reg];
1298         if (val < 0) {
1299                 int spill = 0;
1300                 if (val < -1) {
1301                         /* the register gets spilled after this inst */
1302                         spill = -val -1;
1303                 }
1304                 val = mono_regstate_alloc_int (cfg->rs, allow_mask);
1305                 if (val < 0)
1306                         val = get_register_spilling (cfg, curinst, ins, allow_mask, sym_reg);
1307                 cfg->rs->iassign [sym_reg] = val;
1308                 /* add option to store before the instruction for src registers */
1309                 if (spill)
1310                         create_spilled_store (cfg, spill, val, sym_reg, ins);
1311         }
1312         cfg->rs->isymbolic [val] = sym_reg;
1313         return val;
1314 }
1315 #endif
1316
1317 /* flags used in reginfo->flags */
1318 enum {
1319         MONO_X86_FP_NEEDS_LOAD_SPILL    = 1 << 0,
1320         MONO_X86_FP_NEEDS_SPILL                 = 1 << 1,
1321         MONO_X86_FP_NEEDS_LOAD                  = 1 << 2,
1322         MONO_X86_REG_NOT_ECX                    = 1 << 3,
1323         MONO_X86_REG_EAX                                = 1 << 4,
1324         MONO_X86_REG_EDX                                = 1 << 5,
1325         MONO_X86_REG_ECX                                = 1 << 6
1326 };
1327
1328 static int
1329 mono_x86_alloc_int_reg (MonoCompile *cfg, InstList *tmp, MonoInst *ins, guint32 dest_mask, int sym_reg, int flags)
1330 {
1331         int val;
1332         int test_mask = dest_mask;
1333
1334         if (flags & MONO_X86_REG_EAX)
1335                 test_mask &= (1 << X86_EAX);
1336         else if (flags & MONO_X86_REG_EDX)
1337                 test_mask &= (1 << X86_EDX);
1338         else if (flags & MONO_X86_REG_ECX)
1339                 test_mask &= (1 << X86_ECX);
1340         else if (flags & MONO_X86_REG_NOT_ECX)
1341                 test_mask &= ~ (1 << X86_ECX);
1342
1343         val = mono_regstate_alloc_int (cfg->rs, test_mask);
1344         if (val >= 0 && test_mask != dest_mask)
1345                 DEBUG(g_print ("\tUsed flag to allocate reg %s for R%u\n", mono_arch_regname (val), sym_reg));
1346
1347         if (val < 0 && (flags & MONO_X86_REG_NOT_ECX)) {
1348                 DEBUG(g_print ("\tFailed to allocate flag suggested mask (%u) but exluding ECX\n", test_mask));
1349                 val = mono_regstate_alloc_int (cfg->rs, (dest_mask & (~1 << X86_ECX)));
1350         }
1351
1352         if (val < 0) {
1353                 val = mono_regstate_alloc_int (cfg->rs, dest_mask);
1354                 if (val < 0)
1355                         val = get_register_spilling (cfg, tmp, ins, dest_mask, sym_reg);
1356         }
1357
1358         return val;
1359 }
1360
1361
1362 /*#include "cprop.c"*/
1363
1364 /*
1365  * Local register allocation.
1366  * We first scan the list of instructions and we save the liveness info of
1367  * each register (when the register is first used, when it's value is set etc.).
1368  * We also reverse the list of instructions (in the InstList list) because assigning
1369  * registers backwards allows for more tricks to be used.
1370  */
1371 void
1372 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1373 {
1374         MonoInst *ins;
1375         MonoRegState *rs = cfg->rs;
1376         int i, val, fpcount;
1377         RegTrack *reginfo, *reginfof;
1378         RegTrack *reginfo1, *reginfo2, *reginfod;
1379         InstList *tmp, *reversed = NULL;
1380         const char *spec;
1381         guint32 src1_mask, src2_mask, dest_mask;
1382         GList *fspill_list = NULL;
1383         int fspill = 0;
1384
1385         if (!bb->code)
1386                 return;
1387         rs->next_vireg = bb->max_ireg;
1388         rs->next_vfreg = bb->max_freg;
1389         mono_regstate_assign (rs);
1390         reginfo = g_malloc0 (sizeof (RegTrack) * rs->next_vireg);
1391         reginfof = g_malloc0 (sizeof (RegTrack) * rs->next_vfreg);
1392         rs->ifree_mask = X86_CALLEE_REGS;
1393
1394         ins = bb->code;
1395
1396         /*if (cfg->opt & MONO_OPT_COPYPROP)
1397                 local_copy_prop (cfg, ins);*/
1398
1399         i = 1;
1400         fpcount = 0;
1401         DEBUG (g_print ("LOCAL regalloc: basic block: %d\n", bb->block_num));
1402         /* forward pass on the instructions to collect register liveness info */
1403         while (ins) {
1404                 spec = ins_spec [ins->opcode];
1405                 
1406                 DEBUG (print_ins (i, ins));
1407
1408                 if (spec [MONO_INST_SRC1]) {
1409                         if (spec [MONO_INST_SRC1] == 'f') {
1410                                 GList *spill;
1411                                 reginfo1 = reginfof;
1412
1413                                 spill = g_list_first (fspill_list);
1414                                 if (spill && fpcount < MONO_MAX_FREGS) {
1415                                         reginfo1 [ins->sreg1].flags |= MONO_X86_FP_NEEDS_LOAD;
1416                                         fspill_list = g_list_remove (fspill_list, spill->data);
1417                                 } else
1418                                         fpcount--;
1419                         }
1420                         else
1421                                 reginfo1 = reginfo;
1422                         reginfo1 [ins->sreg1].prev_use = reginfo1 [ins->sreg1].last_use;
1423                         reginfo1 [ins->sreg1].last_use = i;
1424                         if (spec [MONO_INST_SRC1] == 'L') {
1425                                 /* The virtual register is allocated sequentially */
1426                                 reginfo1 [ins->sreg1 + 1].prev_use = reginfo1 [ins->sreg1 + 1].last_use;
1427                                 reginfo1 [ins->sreg1 + 1].last_use = i;
1428                                 if (reginfo1 [ins->sreg1 + 1].born_in == 0 || reginfo1 [ins->sreg1 + 1].born_in > i)
1429                                         reginfo1 [ins->sreg1 + 1].born_in = i;
1430
1431                                 reginfo1 [ins->sreg1].flags |= MONO_X86_REG_EAX;
1432                                 reginfo1 [ins->sreg1 + 1].flags |= MONO_X86_REG_EDX;
1433                         }
1434                 } else {
1435                         ins->sreg1 = -1;
1436                 }
1437                 if (spec [MONO_INST_SRC2]) {
1438                         if (spec [MONO_INST_SRC2] == 'f') {
1439                                 GList *spill;
1440                                 reginfo2 = reginfof;
1441                                 spill = g_list_first (fspill_list);
1442                                 if (spill) {
1443                                         reginfo2 [ins->sreg2].flags |= MONO_X86_FP_NEEDS_LOAD;
1444                                         fspill_list = g_list_remove (fspill_list, spill->data);
1445                                         if (fpcount >= MONO_MAX_FREGS) {
1446                                                 fspill++;
1447                                                 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
1448                                                 reginfo2 [ins->sreg2].flags |= MONO_X86_FP_NEEDS_LOAD_SPILL;
1449                                         }
1450                                 } else
1451                                         fpcount--;
1452                         }
1453                         else
1454                                 reginfo2 = reginfo;
1455                         reginfo2 [ins->sreg2].prev_use = reginfo2 [ins->sreg2].last_use;
1456                         reginfo2 [ins->sreg2].last_use = i;
1457                         if (spec [MONO_INST_SRC2] == 'L') {
1458                                 /* The virtual register is allocated sequentially */
1459                                 reginfo2 [ins->sreg2 + 1].prev_use = reginfo2 [ins->sreg2 + 1].last_use;
1460                                 reginfo2 [ins->sreg2 + 1].last_use = i;
1461                                 if (reginfo2 [ins->sreg2 + 1].born_in == 0 || reginfo2 [ins->sreg2 + 1].born_in > i)
1462                                         reginfo2 [ins->sreg2 + 1].born_in = i;
1463                         }
1464                         if (spec [MONO_INST_CLOB] == 's') {
1465                                 reginfo2 [ins->sreg1].flags |= MONO_X86_REG_NOT_ECX;
1466                                 reginfo2 [ins->sreg2].flags |= MONO_X86_REG_ECX;
1467                         }
1468                 } else {
1469                         ins->sreg2 = -1;
1470                 }
1471                 if (spec [MONO_INST_DEST]) {
1472                         if (spec [MONO_INST_DEST] == 'f') {
1473                                 reginfod = reginfof;
1474                                 if (fpcount >= MONO_MAX_FREGS) {
1475                                         reginfod [ins->dreg].flags |= MONO_X86_FP_NEEDS_SPILL;
1476                                         fspill++;
1477                                         fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
1478                                         fpcount--;
1479                                 }
1480                                 fpcount++;
1481                         }
1482                         else
1483                                 reginfod = reginfo;
1484                         if (spec [MONO_INST_DEST] != 'b') /* it's not just a base register */
1485                                 reginfod [ins->dreg].killed_in = i;
1486                         reginfod [ins->dreg].prev_use = reginfod [ins->dreg].last_use;
1487                         reginfod [ins->dreg].last_use = i;
1488                         if (reginfod [ins->dreg].born_in == 0 || reginfod [ins->dreg].born_in > i)
1489                                 reginfod [ins->dreg].born_in = i;
1490                         if (spec [MONO_INST_DEST] == 'l' || spec [MONO_INST_DEST] == 'L') {
1491                                 /* The virtual register is allocated sequentially */
1492                                 reginfod [ins->dreg + 1].prev_use = reginfod [ins->dreg + 1].last_use;
1493                                 reginfod [ins->dreg + 1].last_use = i;
1494                                 if (reginfod [ins->dreg + 1].born_in == 0 || reginfod [ins->dreg + 1].born_in > i)
1495                                         reginfod [ins->dreg + 1].born_in = i;
1496
1497                                 reginfod [ins->dreg].flags |= MONO_X86_REG_EAX;
1498                                 reginfod [ins->dreg + 1].flags |= MONO_X86_REG_EDX;
1499                         }
1500                 } else {
1501                         ins->dreg = -1;
1502                 }
1503
1504                 reversed = inst_list_prepend (cfg->mempool, reversed, ins);
1505                 ++i;
1506                 ins = ins->next;
1507         }
1508
1509         // todo: check if we have anything left on fp stack, in verify mode?
1510         fspill = 0;
1511
1512         DEBUG (print_regtrack (reginfo, rs->next_vireg));
1513         DEBUG (print_regtrack (reginfof, rs->next_vfreg));
1514         tmp = reversed;
1515         while (tmp) {
1516                 int prev_dreg, prev_sreg1, prev_sreg2, clob_dreg;
1517                 dest_mask = src1_mask = src2_mask = X86_CALLEE_REGS;
1518                 --i;
1519                 ins = tmp->data;
1520                 spec = ins_spec [ins->opcode];
1521                 prev_dreg = -1;
1522                 clob_dreg = -1;
1523                 DEBUG (g_print ("processing:"));
1524                 DEBUG (print_ins (i, ins));
1525                 if (spec [MONO_INST_CLOB] == 's') {
1526                         if (rs->ifree_mask & (1 << X86_ECX)) {
1527                                 DEBUG (g_print ("\tshortcut assignment of R%d to ECX\n", ins->sreg2));
1528                                 rs->iassign [ins->sreg2] = X86_ECX;
1529                                 rs->isymbolic [X86_ECX] = ins->sreg2;
1530                                 ins->sreg2 = X86_ECX;
1531                                 rs->ifree_mask &= ~ (1 << X86_ECX);
1532                         } else {
1533                                 int need_ecx_spill = TRUE;
1534                                 /* 
1535                                  * we first check if src1/dreg is already assigned a register
1536                                  * and then we force a spill of the var assigned to ECX.
1537                                  */
1538                                 /* the destination register can't be ECX */
1539                                 dest_mask &= ~ (1 << X86_ECX);
1540                                 src1_mask &= ~ (1 << X86_ECX);
1541                                 val = rs->iassign [ins->dreg];
1542                                 /* 
1543                                  * the destination register is already assigned to ECX:
1544                                  * we need to allocate another register for it and then
1545                                  * copy from this to ECX.
1546                                  */
1547                                 if (val == X86_ECX && ins->dreg != ins->sreg2) {
1548                                         int new_dest;
1549                                         new_dest = mono_x86_alloc_int_reg (cfg, tmp, ins, dest_mask, ins->dreg, reginfo [ins->dreg].flags);
1550                                         g_assert (new_dest >= 0);
1551                                         DEBUG (g_print ("\tclob:s changing dreg R%d to %s from ECX\n", ins->dreg, mono_arch_regname (new_dest)));
1552
1553                                         rs->isymbolic [new_dest] = ins->dreg;
1554                                         rs->iassign [ins->dreg] = new_dest;
1555                                         clob_dreg = ins->dreg;
1556                                         ins->dreg = new_dest;
1557                                         create_copy_ins (cfg, X86_ECX, new_dest, ins);
1558                                         need_ecx_spill = FALSE;
1559                                         /*DEBUG (g_print ("\tforced spill of R%d\n", ins->dreg));
1560                                         val = get_register_force_spilling (cfg, tmp, ins, ins->dreg);
1561                                         rs->iassign [ins->dreg] = val;
1562                                         rs->isymbolic [val] = prev_dreg;
1563                                         ins->dreg = val;*/
1564                                 }
1565                                 val = rs->iassign [ins->sreg1];
1566                                 if (val == X86_ECX) {
1567                                         g_assert_not_reached ();
1568                                 } else if (val >= 0) {
1569                                         /* 
1570                                          * the first src reg was already assigned to a register,
1571                                          * we need to copy it to the dest register because the 
1572                                          * shift instruction clobbers the first operand.
1573                                          */
1574                                         MonoInst *copy = create_copy_ins (cfg, ins->dreg, val, NULL);
1575                                         DEBUG (g_print ("\tclob:s moved sreg1 from R%d to R%d\n", val, ins->dreg));
1576                                         insert_before_ins (ins, tmp, copy);
1577                                 }
1578                                 val = rs->iassign [ins->sreg2];
1579                                 if (val >= 0 && val != X86_ECX) {
1580                                         MonoInst *move = create_copy_ins (cfg, X86_ECX, val, NULL);
1581                                         DEBUG (g_print ("\tmoved arg from R%d (%d) to ECX\n", val, ins->sreg2));
1582                                         move->next = ins;
1583                                         g_assert_not_reached ();
1584                                         /* FIXME: where is move connected to the instruction list? */
1585                                         //tmp->prev->data->next = move;
1586                                 }
1587                                 if (need_ecx_spill && !(rs->ifree_mask & (1 << X86_ECX))) {
1588                                         DEBUG (g_print ("\tforced spill of R%d\n", rs->isymbolic [X86_ECX]));
1589                                         get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [X86_ECX]);
1590                                         mono_regstate_free_int (rs, X86_ECX);
1591                                 }
1592                                 /* force-set sreg2 */
1593                                 rs->iassign [ins->sreg2] = X86_ECX;
1594                                 rs->isymbolic [X86_ECX] = ins->sreg2;
1595                                 ins->sreg2 = X86_ECX;
1596                                 rs->ifree_mask &= ~ (1 << X86_ECX);
1597                         }
1598                 } else if (spec [MONO_INST_CLOB] == 'd') { /* division */
1599                         int dest_reg = X86_EAX;
1600                         int clob_reg = X86_EDX;
1601                         if (spec [MONO_INST_DEST] == 'd') {
1602                                 dest_reg = X86_EDX; /* reminder */
1603                                 clob_reg = X86_EAX;
1604                         }
1605                         val = rs->iassign [ins->dreg];
1606                         if (0 && val >= 0 && val != dest_reg && !(rs->ifree_mask & (1 << dest_reg))) {
1607                                 DEBUG (g_print ("\tforced spill of R%d\n", rs->isymbolic [dest_reg]));
1608                                 get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [dest_reg]);
1609                                 mono_regstate_free_int (rs, dest_reg);
1610                         }
1611                         if (val < 0) {
1612                                 if (val < -1) {
1613                                         /* the register gets spilled after this inst */
1614                                         int spill = -val -1;
1615                                         dest_mask = 1 << clob_reg;
1616                                         prev_dreg = ins->dreg;
1617                                         val = mono_regstate_alloc_int (rs, dest_mask);
1618                                         if (val < 0)
1619                                                 val = get_register_spilling (cfg, tmp, ins, dest_mask, ins->dreg);
1620                                         rs->iassign [ins->dreg] = val;
1621                                         if (spill)
1622                                                 create_spilled_store (cfg, spill, val, prev_dreg, ins);
1623                                         DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_arch_regname (val), ins->dreg));
1624                                         rs->isymbolic [val] = prev_dreg;
1625                                         ins->dreg = val;
1626                                         if (val != dest_reg) { /* force a copy */
1627                                                 create_copy_ins (cfg, val, dest_reg, ins);
1628                                         }
1629                                 } else {
1630                                         DEBUG (g_print ("\tshortcut assignment of R%d to %s\n", ins->dreg, mono_arch_regname (dest_reg)));
1631                                         prev_dreg = ins->dreg;
1632                                         rs->iassign [ins->dreg] = dest_reg;
1633                                         rs->isymbolic [dest_reg] = ins->dreg;
1634                                         ins->dreg = dest_reg;
1635                                         rs->ifree_mask &= ~ (1 << dest_reg);
1636                                 }
1637                         } else {
1638                                 //DEBUG (g_print ("dest reg in div assigned: %s\n", mono_arch_regname (val)));
1639                                 if (val != dest_reg) { /* force a copy */
1640                                         create_copy_ins (cfg, val, dest_reg, ins);
1641                                         if (!(rs->ifree_mask & (1 << dest_reg)) && rs->isymbolic [dest_reg] >= MONO_MAX_IREGS) {
1642                                                 DEBUG (g_print ("\tforced spill of R%d\n", rs->isymbolic [dest_reg]));
1643                                                 get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [dest_reg]);
1644                                                 mono_regstate_free_int (rs, dest_reg);
1645                                         }
1646                                 }
1647                         }
1648                         if (!(rs->ifree_mask & (1 << clob_reg)) && (clob_reg != val) && (rs->isymbolic [clob_reg] >= 8)) {
1649                                 DEBUG (g_print ("\tforced spill of clobbered reg R%d\n", rs->isymbolic [clob_reg]));
1650                                 get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [clob_reg]);
1651                                 mono_regstate_free_int (rs, clob_reg);
1652                         }
1653                         src1_mask = 1 << X86_EAX;
1654                         src2_mask = 1 << X86_ECX;
1655                 }
1656                 if (spec [MONO_INST_DEST] == 'l') {
1657                         int hreg;
1658                         val = rs->iassign [ins->dreg];
1659                         /* check special case when dreg have been moved from ecx (clob shift) */
1660                         if (spec [MONO_INST_CLOB] == 's' && clob_dreg != -1)
1661                                 hreg = clob_dreg + 1;
1662                         else
1663                                 hreg = ins->dreg + 1;
1664
1665                         /* base prev_dreg on fixed hreg, handle clob case */
1666                         val = hreg - 1;
1667
1668                         if (val != rs->isymbolic [X86_EAX] && !(rs->ifree_mask & (1 << X86_EAX))) {
1669                                 DEBUG (g_print ("\t(long-low) forced spill of R%d\n", rs->isymbolic [X86_EAX]));
1670                                 get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [X86_EAX]);
1671                                 mono_regstate_free_int (rs, X86_EAX);
1672                         }
1673                         if (hreg != rs->isymbolic [X86_EDX] && !(rs->ifree_mask & (1 << X86_EDX))) {
1674                                 DEBUG (g_print ("\t(long-high) forced spill of R%d\n", rs->isymbolic [X86_EDX]));
1675                                 get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [X86_EDX]);
1676                                 mono_regstate_free_int (rs, X86_EDX);
1677                         }
1678                 }
1679
1680                 /* Track dreg */
1681                 if (spec [MONO_INST_DEST] == 'f') {
1682                         if (reginfof [ins->dreg].flags & MONO_X86_FP_NEEDS_SPILL) {
1683                                 GList *spill_node;
1684                                 MonoInst *store;
1685                                 spill_node = g_list_first (fspill_list);
1686                                 g_assert (spill_node);
1687
1688                                 store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->dreg, ins);
1689                                 insert_before_ins (ins, tmp, store);
1690                                 fspill_list = g_list_remove (fspill_list, spill_node->data);
1691                                 fspill--;
1692                         }
1693                 } else if (spec [MONO_INST_DEST] == 'L') {
1694                         int hreg;
1695                         val = rs->iassign [ins->dreg];
1696                         /* check special case when dreg have been moved from ecx (clob shift) */
1697                         if (spec [MONO_INST_CLOB] == 's' && clob_dreg != -1)
1698                                 hreg = clob_dreg + 1;
1699                         else
1700                                 hreg = ins->dreg + 1;
1701
1702                         /* base prev_dreg on fixed hreg, handle clob case */
1703                         prev_dreg = hreg - 1;
1704
1705                         if (val < 0) {
1706                                 int spill = 0;
1707                                 if (val < -1) {
1708                                         /* the register gets spilled after this inst */
1709                                         spill = -val -1;
1710                                 }
1711                                 val = mono_x86_alloc_int_reg (cfg, tmp, ins, dest_mask, ins->dreg, reginfo [ins->dreg].flags);
1712                                 rs->iassign [ins->dreg] = val;
1713                                 if (spill)
1714                                         create_spilled_store (cfg, spill, val, prev_dreg, ins);
1715                         }
1716
1717                         DEBUG (g_print ("\tassigned dreg (long) %s to dest R%d\n", mono_arch_regname (val), hreg - 1));
1718  
1719                         rs->isymbolic [val] = hreg - 1;
1720                         ins->dreg = val;
1721                         
1722                         val = rs->iassign [hreg];
1723                         if (val < 0) {
1724                                 int spill = 0;
1725                                 if (val < -1) {
1726                                         /* the register gets spilled after this inst */
1727                                         spill = -val -1;
1728                                 }
1729                                 val = mono_x86_alloc_int_reg (cfg, tmp, ins, dest_mask, hreg, reginfo [hreg].flags);
1730                                 rs->iassign [hreg] = val;
1731                                 if (spill)
1732                                         create_spilled_store (cfg, spill, val, hreg, ins);
1733                         }
1734
1735                         DEBUG (g_print ("\tassigned hreg (long-high) %s to dest R%d\n", mono_arch_regname (val), hreg));
1736                         rs->isymbolic [val] = hreg;
1737                         /* save reg allocating into unused */
1738                         ins->unused = val;
1739
1740                         /* check if we can free our long reg */
1741                         if (reg_is_freeable (val) && hreg >= 0 && reginfo [hreg].born_in >= i) {
1742                                 DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (val), hreg, reginfo [hreg].born_in));
1743                                 mono_regstate_free_int (rs, val);
1744                         }
1745                 }
1746                 else if (ins->dreg >= MONO_MAX_IREGS) {
1747                         int hreg;
1748                         val = rs->iassign [ins->dreg];
1749                         if (spec [MONO_INST_DEST] == 'l') {
1750                                 /* check special case when dreg have been moved from ecx (clob shift) */
1751                                 if (spec [MONO_INST_CLOB] == 's' && clob_dreg != -1)
1752                                         hreg = clob_dreg + 1;
1753                                 else
1754                                         hreg = ins->dreg + 1;
1755
1756                                 /* base prev_dreg on fixed hreg, handle clob case */
1757                                 prev_dreg = hreg - 1;
1758                         } else
1759                                 prev_dreg = ins->dreg;
1760
1761                         if (val < 0) {
1762                                 int spill = 0;
1763                                 if (val < -1) {
1764                                         /* the register gets spilled after this inst */
1765                                         spill = -val -1;
1766                                 }
1767                                 val = mono_x86_alloc_int_reg (cfg, tmp, ins, dest_mask, ins->dreg, reginfo [ins->dreg].flags);
1768                                 rs->iassign [ins->dreg] = val;
1769                                 if (spill)
1770                                         create_spilled_store (cfg, spill, val, prev_dreg, ins);
1771                         }
1772                         DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_arch_regname (val), ins->dreg));
1773                         rs->isymbolic [val] = prev_dreg;
1774                         ins->dreg = val;
1775                         /* handle cases where lreg needs to be eax:edx */
1776                         if (spec [MONO_INST_DEST] == 'l') {
1777                                 /* check special case when dreg have been moved from ecx (clob shift) */
1778                                 int hreg = prev_dreg + 1;
1779                                 val = rs->iassign [hreg];
1780                                 if (val < 0) {
1781                                         int spill = 0;
1782                                         if (val < -1) {
1783                                                 /* the register gets spilled after this inst */
1784                                                 spill = -val -1;
1785                                         }
1786                                         val = mono_x86_alloc_int_reg (cfg, tmp, ins, dest_mask, hreg, reginfo [hreg].flags);
1787                                         rs->iassign [hreg] = val;
1788                                         if (spill)
1789                                                 create_spilled_store (cfg, spill, val, hreg, ins);
1790                                 }
1791                                 DEBUG (g_print ("\tassigned hreg %s to dest R%d\n", mono_arch_regname (val), hreg));
1792                                 rs->isymbolic [val] = hreg;
1793                                 if (ins->dreg == X86_EAX) {
1794                                         if (val != X86_EDX)
1795                                                 create_copy_ins (cfg, val, X86_EDX, ins);
1796                                 } else if (ins->dreg == X86_EDX) {
1797                                         if (val == X86_EAX) {
1798                                                 /* swap */
1799                                                 g_assert_not_reached ();
1800                                         } else {
1801                                                 /* two forced copies */
1802                                                 create_copy_ins (cfg, val, X86_EDX, ins);
1803                                                 create_copy_ins (cfg, ins->dreg, X86_EAX, ins);
1804                                         }
1805                                 } else {
1806                                         if (val == X86_EDX) {
1807                                                 create_copy_ins (cfg, ins->dreg, X86_EAX, ins);
1808                                         } else {
1809                                                 /* two forced copies */
1810                                                 create_copy_ins (cfg, val, X86_EDX, ins);
1811                                                 create_copy_ins (cfg, ins->dreg, X86_EAX, ins);
1812                                         }
1813                                 }
1814                                 if (reg_is_freeable (val) && hreg >= 0 && reginfo [hreg].born_in >= i) {
1815                                         DEBUG (g_print ("\tfreeable %s (R%d)\n", mono_arch_regname (val), hreg));
1816                                         mono_regstate_free_int (rs, val);
1817                                 }
1818                         } else if (spec [MONO_INST_DEST] == 'a' && ins->dreg != X86_EAX && spec [MONO_INST_CLOB] != 'd') {
1819                                 /* this instruction only outputs to EAX, need to copy */
1820                                 create_copy_ins (cfg, ins->dreg, X86_EAX, ins);
1821                         } else if (spec [MONO_INST_DEST] == 'd' && ins->dreg != X86_EDX && spec [MONO_INST_CLOB] != 'd') {
1822                                 create_copy_ins (cfg, ins->dreg, X86_EDX, ins);
1823                         }
1824                 }
1825                 if (spec [MONO_INST_DEST] != 'f' && reg_is_freeable (ins->dreg) && prev_dreg >= 0 && reginfo [prev_dreg].born_in >= i) {
1826                         DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins->dreg), prev_dreg, reginfo [prev_dreg].born_in));
1827                         mono_regstate_free_int (rs, ins->dreg);
1828                 }
1829                 /* put src1 in EAX if it needs to be */
1830                 if (spec [MONO_INST_SRC1] == 'a') {
1831                         if (!(rs->ifree_mask & (1 << X86_EAX))) {
1832                                 DEBUG (g_print ("\tforced spill of R%d\n", rs->isymbolic [X86_EAX]));
1833                                 get_register_force_spilling (cfg, tmp, ins, rs->isymbolic [X86_EAX]);
1834                                 mono_regstate_free_int (rs, X86_EAX);
1835                         }
1836                         /* force-set sreg1 */
1837                         rs->iassign [ins->sreg1] = X86_EAX;
1838                         rs->isymbolic [X86_EAX] = ins->sreg1;
1839                         ins->sreg1 = X86_EAX;
1840                         rs->ifree_mask &= ~ (1 << X86_EAX);
1841                 }
1842
1843                 /* Track sreg1 */
1844                 if (spec [MONO_INST_SRC1] == 'f') {
1845                         if (reginfof [ins->sreg1].flags & MONO_X86_FP_NEEDS_LOAD) {
1846                                 MonoInst *load;
1847                                 MonoInst *store = NULL;
1848
1849                                 if (reginfof [ins->sreg1].flags & MONO_X86_FP_NEEDS_LOAD_SPILL) {
1850                                         GList *spill_node;
1851                                         spill_node = g_list_first (fspill_list);
1852                                         g_assert (spill_node);
1853
1854                                         store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->sreg1, ins);          
1855                                         fspill_list = g_list_remove (fspill_list, spill_node->data);
1856                                 }
1857
1858                                 fspill++;
1859                                 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
1860                                 load = create_spilled_load_float (cfg, fspill, ins->sreg1, ins);
1861                                 insert_before_ins (ins, tmp, load);
1862                                 if (store) 
1863                                         insert_before_ins (load, tmp, store);
1864                         }
1865                 } else if ((spec [MONO_INST_DEST] == 'L') && (spec [MONO_INST_SRC1] == 'L')) {
1866                         /* force source to be same as dest */
1867                         rs->iassign [ins->sreg1] = ins->dreg;
1868                         rs->iassign [ins->sreg1 + 1] = ins->unused;
1869
1870                         DEBUG (g_print ("\tassigned sreg1 (long) %s to sreg1 R%d\n", mono_arch_regname (ins->dreg), ins->sreg1));
1871                         DEBUG (g_print ("\tassigned sreg1 (long-high) %s to sreg1 R%d\n", mono_arch_regname (ins->unused), ins->sreg1 + 1));
1872
1873                         ins->sreg1 = ins->dreg;
1874                         /* 
1875                          * No need for saving the reg, we know that src1=dest in this cases
1876                          * ins->inst_c0 = ins->unused;
1877                          */
1878
1879                         /* make sure that we remove them from free mask */
1880                         rs->ifree_mask &= ~ (1 << ins->dreg);
1881                         rs->ifree_mask &= ~ (1 << ins->unused);
1882                 }
1883                 else if (ins->sreg1 >= MONO_MAX_IREGS) {
1884                         val = rs->iassign [ins->sreg1];
1885                         prev_sreg1 = ins->sreg1;
1886                         if (val < 0) {
1887                                 int spill = 0;
1888                                 if (val < -1) {
1889                                         /* the register gets spilled after this inst */
1890                                         spill = -val -1;
1891                                 }
1892                                 if (0 && ins->opcode == OP_MOVE) {
1893                                         /* 
1894                                          * small optimization: the dest register is already allocated
1895                                          * but the src one is not: we can simply assign the same register
1896                                          * here and peephole will get rid of the instruction later.
1897                                          * This optimization may interfere with the clobbering handling:
1898                                          * it removes a mov operation that will be added again to handle clobbering.
1899                                          * There are also some other issues that should with make testjit.
1900                                          */
1901                                         mono_regstate_alloc_int (rs, 1 << ins->dreg);
1902                                         val = rs->iassign [ins->sreg1] = ins->dreg;
1903                                         //g_assert (val >= 0);
1904                                         DEBUG (g_print ("\tfast assigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1));
1905                                 } else {
1906                                         //g_assert (val == -1); /* source cannot be spilled */
1907                                         val = mono_x86_alloc_int_reg (cfg, tmp, ins, src1_mask, ins->sreg1, reginfo [ins->sreg1].flags);
1908                                         rs->iassign [ins->sreg1] = val;
1909                                         DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1));
1910                                 }
1911                                 if (spill) {
1912                                         MonoInst *store = create_spilled_store (cfg, spill, val, prev_sreg1, NULL);
1913                                         insert_before_ins (ins, tmp, store);
1914                                 }
1915                         }
1916                         rs->isymbolic [val] = prev_sreg1;
1917                         ins->sreg1 = val;
1918                 } else {
1919                         prev_sreg1 = -1;
1920                 }
1921                 /* handle clobbering of sreg1 */
1922                 if ((spec [MONO_INST_CLOB] == '1' || spec [MONO_INST_CLOB] == 's') && ins->dreg != ins->sreg1) {
1923                         MonoInst *copy = create_copy_ins (cfg, ins->dreg, ins->sreg1, NULL);
1924                         DEBUG (g_print ("\tneed to copy sreg1 %s to dreg %s\n", mono_arch_regname (ins->sreg1), mono_arch_regname (ins->dreg)));
1925                         if (ins->sreg2 == -1 || spec [MONO_INST_CLOB] == 's') {
1926                                 /* note: the copy is inserted before the current instruction! */
1927                                 insert_before_ins (ins, tmp, copy);
1928                                 /* we set sreg1 to dest as well */
1929                                 prev_sreg1 = ins->sreg1 = ins->dreg;
1930                         } else {
1931                                 /* inserted after the operation */
1932                                 copy->next = ins->next;
1933                                 ins->next = copy;
1934                         }
1935                 }
1936                 /* track sreg2 */
1937                 if (spec [MONO_INST_SRC2] == 'f') {
1938                         if (reginfof [ins->sreg2].flags & MONO_X86_FP_NEEDS_LOAD) {
1939                                 MonoInst *load;
1940                                 MonoInst *store = NULL;
1941
1942                                 if (reginfof [ins->sreg2].flags & MONO_X86_FP_NEEDS_LOAD_SPILL) {
1943                                         GList *spill_node;
1944
1945                                         spill_node = g_list_first (fspill_list);
1946                                         g_assert (spill_node);
1947                                         if (spec [MONO_INST_SRC1] == 'f' && (reginfof [ins->sreg1].flags & MONO_X86_FP_NEEDS_LOAD_SPILL))
1948                                                 spill_node = g_list_next (spill_node);
1949         
1950                                         store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->sreg2, ins);
1951                                         fspill_list = g_list_remove (fspill_list, spill_node->data);
1952                                 } 
1953                                 
1954                                 fspill++;
1955                                 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
1956                                 load = create_spilled_load_float (cfg, fspill, ins->sreg2, ins);
1957                                 insert_before_ins (ins, tmp, load);
1958                                 if (store) 
1959                                         insert_before_ins (load, tmp, store);
1960                         }
1961                 } 
1962                 else if (ins->sreg2 >= MONO_MAX_IREGS) {
1963                         val = rs->iassign [ins->sreg2];
1964                         prev_sreg2 = ins->sreg2;
1965                         if (val < 0) {
1966                                 int spill = 0;
1967                                 if (val < -1) {
1968                                         /* the register gets spilled after this inst */
1969                                         spill = -val -1;
1970                                 }
1971                                 val = mono_x86_alloc_int_reg (cfg, tmp, ins, src2_mask, ins->sreg2, reginfo [ins->sreg2].flags);
1972                                 rs->iassign [ins->sreg2] = val;
1973                                 DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val), ins->sreg2));
1974                                 if (spill)
1975                                         create_spilled_store (cfg, spill, val, prev_sreg2, ins);
1976                         }
1977                         rs->isymbolic [val] = prev_sreg2;
1978                         ins->sreg2 = val;
1979                         if (spec [MONO_INST_CLOB] == 's' && ins->sreg2 != X86_ECX) {
1980                                 DEBUG (g_print ("\tassigned sreg2 %s to R%d, but ECX is needed (R%d)\n", mono_arch_regname (val), ins->sreg2, rs->iassign [X86_ECX]));
1981                         }
1982                 } else {
1983                         prev_sreg2 = -1;
1984                 }
1985
1986                 if (spec [MONO_INST_CLOB] == 'c') {
1987                         int j, s;
1988                         guint32 clob_mask = X86_CALLEE_REGS;
1989                         for (j = 0; j < MONO_MAX_IREGS; ++j) {
1990                                 s = 1 << j;
1991                                 if ((clob_mask & s) && !(rs->ifree_mask & s) && j != ins->sreg1) {
1992                                         //g_warning ("register %s busy at call site\n", mono_arch_regname (j));
1993                                 }
1994                         }
1995                 }
1996                 /*if (reg_is_freeable (ins->sreg1) && prev_sreg1 >= 0 && reginfo [prev_sreg1].born_in >= i) {
1997                         DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg1)));
1998                         mono_regstate_free_int (rs, ins->sreg1);
1999                 }
2000                 if (reg_is_freeable (ins->sreg2) && prev_sreg2 >= 0 && reginfo [prev_sreg2].born_in >= i) {
2001                         DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg2)));
2002                         mono_regstate_free_int (rs, ins->sreg2);
2003                 }*/
2004         
2005                 //DEBUG (print_ins (i, ins));
2006                 /* this may result from a insert_before call */
2007                 if (!tmp->next)
2008                         bb->code = tmp->data;
2009                 tmp = tmp->next;
2010         }
2011
2012         g_free (reginfo);
2013         g_free (reginfof);
2014         g_list_free (fspill_list);
2015 }
2016
2017 static unsigned char*
2018 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int size, gboolean is_signed)
2019 {
2020         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 4);
2021         x86_fnstcw_membase(code, X86_ESP, 0);
2022         x86_mov_reg_membase (code, dreg, X86_ESP, 0, 2);
2023         x86_alu_reg_imm (code, X86_OR, dreg, 0xc00);
2024         x86_mov_membase_reg (code, X86_ESP, 2, dreg, 2);
2025         x86_fldcw_membase (code, X86_ESP, 2);
2026         if (size == 8) {
2027                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
2028                 x86_fist_pop_membase (code, X86_ESP, 0, TRUE);
2029                 x86_pop_reg (code, dreg);
2030                 /* FIXME: need the high register 
2031                  * x86_pop_reg (code, dreg_high);
2032                  */
2033         } else {
2034                 x86_push_reg (code, X86_EAX); // SP = SP - 4
2035                 x86_fist_pop_membase (code, X86_ESP, 0, FALSE);
2036                 x86_pop_reg (code, dreg);
2037         }
2038         x86_fldcw_membase (code, X86_ESP, 0);
2039         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
2040
2041         if (size == 1)
2042                 x86_widen_reg (code, dreg, dreg, is_signed, FALSE);
2043         else if (size == 2)
2044                 x86_widen_reg (code, dreg, dreg, is_signed, TRUE);
2045         return code;
2046 }
2047
2048 static unsigned char*
2049 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
2050 {
2051         int sreg = tree->sreg1;
2052 #ifdef PLATFORM_WIN32
2053         guint8* br[5];
2054
2055         /*
2056          * Under Windows:
2057          * If requested stack size is larger than one page,
2058          * perform stack-touch operation
2059          */
2060         /*
2061          * Generate stack probe code.
2062          * Under Windows, it is necessary to allocate one page at a time,
2063          * "touching" stack after each successful sub-allocation. This is
2064          * because of the way stack growth is implemented - there is a
2065          * guard page before the lowest stack page that is currently commited.
2066          * Stack normally grows sequentially so OS traps access to the
2067          * guard page and commits more pages when needed.
2068          */
2069         x86_test_reg_imm (code, sreg, ~0xFFF);
2070         br[0] = code; x86_branch8 (code, X86_CC_Z, 0, FALSE);
2071
2072         br[2] = code; /* loop */
2073         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x1000);
2074         x86_test_membase_reg (code, X86_ESP, 0, X86_ESP);
2075         x86_alu_reg_imm (code, X86_SUB, sreg, 0x1000);
2076         x86_alu_reg_imm (code, X86_CMP, sreg, 0x1000);
2077         br[3] = code; x86_branch8 (code, X86_CC_AE, 0, FALSE);
2078         x86_patch (br[3], br[2]);
2079         x86_test_reg_reg (code, sreg, sreg);
2080         br[4] = code; x86_branch8 (code, X86_CC_Z, 0, FALSE);
2081         x86_alu_reg_reg (code, X86_SUB, X86_ESP, sreg);
2082
2083         br[1] = code; x86_jump8 (code, 0);
2084
2085         x86_patch (br[0], code);
2086         x86_alu_reg_reg (code, X86_SUB, X86_ESP, sreg);
2087         x86_patch (br[1], code);
2088         x86_patch (br[4], code);
2089 #else /* PLATFORM_WIN32 */
2090         x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
2091 #endif
2092         if (tree->flags & MONO_INST_INIT) {
2093                 int offset = 0;
2094                 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
2095                         x86_push_reg (code, X86_EAX);
2096                         offset += 4;
2097                 }
2098                 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
2099                         x86_push_reg (code, X86_ECX);
2100                         offset += 4;
2101                 }
2102                 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
2103                         x86_push_reg (code, X86_EDI);
2104                         offset += 4;
2105                 }
2106                 
2107                 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
2108                 if (sreg != X86_ECX)
2109                         x86_mov_reg_reg (code, X86_ECX, sreg, 4);
2110                 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
2111                                 
2112                 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
2113                 x86_cld (code);
2114                 x86_prefix (code, X86_REP_PREFIX);
2115                 x86_stosl (code);
2116                 
2117                 if (tree->dreg != X86_EDI && sreg != X86_EDI)
2118                         x86_pop_reg (code, X86_EDI);
2119                 if (tree->dreg != X86_ECX && sreg != X86_ECX)
2120                         x86_pop_reg (code, X86_ECX);
2121                 if (tree->dreg != X86_EAX && sreg != X86_EAX)
2122                         x86_pop_reg (code, X86_EAX);
2123         }
2124         return code;
2125 }
2126
2127 #define REAL_PRINT_REG(text,reg) \
2128 mono_assert (reg >= 0); \
2129 x86_push_reg (code, X86_EAX); \
2130 x86_push_reg (code, X86_EDX); \
2131 x86_push_reg (code, X86_ECX); \
2132 x86_push_reg (code, reg); \
2133 x86_push_imm (code, reg); \
2134 x86_push_imm (code, text " %d %p\n"); \
2135 x86_mov_reg_imm (code, X86_EAX, printf); \
2136 x86_call_reg (code, X86_EAX); \
2137 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 3*4); \
2138 x86_pop_reg (code, X86_ECX); \
2139 x86_pop_reg (code, X86_EDX); \
2140 x86_pop_reg (code, X86_EAX);
2141
2142 /* benchmark and set based on cpu */
2143 #define LOOP_ALIGNMENT 8
2144 #define bb_is_loop_start(bb) ((bb)->nesting && ((bb)->in_count == 1))
2145
2146 void
2147 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2148 {
2149         MonoInst *ins;
2150         MonoCallInst *call;
2151         guint offset;
2152         guint8 *code = cfg->native_code + cfg->code_len;
2153         MonoInst *last_ins = NULL;
2154         guint last_offset = 0;
2155         int max_len, cpos;
2156
2157         if (cfg->opt & MONO_OPT_PEEPHOLE)
2158                 peephole_pass (cfg, bb);
2159
2160         if (cfg->opt & MONO_OPT_LOOP) {
2161                 int pad, align = LOOP_ALIGNMENT;
2162                 /* set alignment depending on cpu */
2163                 if (bb_is_loop_start (bb) && (pad = (cfg->code_len & (align - 1)))) {
2164                         pad = align - pad;
2165                         /*g_print ("adding %d pad at %x to loop in %s\n", pad, cfg->code_len, cfg->method->name);*/
2166                         x86_padding (code, pad);
2167                         cfg->code_len += pad;
2168                         bb->native_offset = cfg->code_len;
2169                 }
2170         }
2171
2172         if (cfg->verbose_level > 2)
2173                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2174
2175         cpos = bb->max_offset;
2176
2177         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2178                 MonoProfileCoverageInfo *cov = cfg->coverage_info;
2179                 g_assert (!mono_compile_aot);
2180                 cpos += 6;
2181
2182                 cov->data [bb->dfn].cil_code = bb->cil_code;
2183                 /* this is not thread save, but good enough */
2184                 x86_inc_mem (code, &cov->data [bb->dfn].count); 
2185         }
2186
2187         offset = code - cfg->native_code;
2188
2189         ins = bb->code;
2190         while (ins) {
2191                 offset = code - cfg->native_code;
2192
2193                 max_len = ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
2194
2195                 if (offset > (cfg->code_size - max_len - 16)) {
2196                         cfg->code_size *= 2;
2197                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2198                         code = cfg->native_code + offset;
2199                         mono_jit_stats.code_reallocs++;
2200                 }
2201
2202                 mono_debug_record_line_number (cfg, ins, offset);
2203
2204                 switch (ins->opcode) {
2205                 case OP_BIGMUL:
2206                         x86_mul_reg (code, ins->sreg2, TRUE);
2207                         break;
2208                 case OP_BIGMUL_UN:
2209                         x86_mul_reg (code, ins->sreg2, FALSE);
2210                         break;
2211                 case OP_X86_SETEQ_MEMBASE:
2212                         x86_set_membase (code, X86_CC_EQ, ins->inst_basereg, ins->inst_offset, TRUE);
2213                         break;
2214                 case OP_STOREI1_MEMBASE_IMM:
2215                         x86_mov_membase_imm (code, ins->inst_destbasereg, ins->inst_offset, ins->inst_imm, 1);
2216                         break;
2217                 case OP_STOREI2_MEMBASE_IMM:
2218                         x86_mov_membase_imm (code, ins->inst_destbasereg, ins->inst_offset, ins->inst_imm, 2);
2219                         break;
2220                 case OP_STORE_MEMBASE_IMM:
2221                 case OP_STOREI4_MEMBASE_IMM:
2222                         x86_mov_membase_imm (code, ins->inst_destbasereg, ins->inst_offset, ins->inst_imm, 4);
2223                         break;
2224                 case OP_STOREI1_MEMBASE_REG:
2225                         x86_mov_membase_reg (code, ins->inst_destbasereg, ins->inst_offset, ins->sreg1, 1);
2226                         break;
2227                 case OP_STOREI2_MEMBASE_REG:
2228                         x86_mov_membase_reg (code, ins->inst_destbasereg, ins->inst_offset, ins->sreg1, 2);
2229                         break;
2230                 case OP_STORE_MEMBASE_REG:
2231                 case OP_STOREI4_MEMBASE_REG:
2232                         x86_mov_membase_reg (code, ins->inst_destbasereg, ins->inst_offset, ins->sreg1, 4);
2233                         break;
2234                 case CEE_LDIND_I:
2235                 case CEE_LDIND_I4:
2236                 case CEE_LDIND_U4:
2237                         x86_mov_reg_mem (code, ins->dreg, ins->inst_p0, 4);
2238                         break;
2239                 case OP_LOADU4_MEM:
2240                         x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
2241                         x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
2242                         break;
2243                 case OP_LOAD_MEMBASE:
2244                 case OP_LOADI4_MEMBASE:
2245                 case OP_LOADU4_MEMBASE:
2246                         x86_mov_reg_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, 4);
2247                         break;
2248                 case OP_LOADU1_MEMBASE:
2249                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, FALSE, FALSE);
2250                         break;
2251                 case OP_LOADI1_MEMBASE:
2252                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, TRUE, FALSE);
2253                         break;
2254                 case OP_LOADU2_MEMBASE:
2255                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, FALSE, TRUE);
2256                         break;
2257                 case OP_LOADI2_MEMBASE:
2258                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, TRUE, TRUE);
2259                         break;
2260                 case CEE_CONV_I1:
2261                         x86_widen_reg (code, ins->dreg, ins->sreg1, TRUE, FALSE);
2262                         break;
2263                 case CEE_CONV_I2:
2264                         x86_widen_reg (code, ins->dreg, ins->sreg1, TRUE, TRUE);
2265                         break;
2266                 case CEE_CONV_U1:
2267                         x86_widen_reg (code, ins->dreg, ins->sreg1, FALSE, FALSE);
2268                         break;
2269                 case CEE_CONV_U2:
2270                         x86_widen_reg (code, ins->dreg, ins->sreg1, FALSE, TRUE);
2271                         break;
2272                 case OP_COMPARE:
2273                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
2274                         break;
2275                 case OP_COMPARE_IMM:
2276                         x86_alu_reg_imm (code, X86_CMP, ins->sreg1, ins->inst_imm);
2277                         break;
2278                 case OP_X86_COMPARE_MEMBASE_REG:
2279                         x86_alu_membase_reg (code, X86_CMP, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2280                         break;
2281                 case OP_X86_COMPARE_MEMBASE_IMM:
2282                         x86_alu_membase_imm (code, X86_CMP, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2283                         break;
2284                 case OP_X86_COMPARE_REG_MEMBASE:
2285                         x86_alu_reg_membase (code, X86_CMP, ins->sreg1, ins->sreg2, ins->inst_offset);
2286                         break;
2287                 case OP_X86_TEST_NULL:
2288                         x86_test_reg_reg (code, ins->sreg1, ins->sreg1);
2289                         break;
2290                 case OP_X86_ADD_MEMBASE_IMM:
2291                         x86_alu_membase_imm (code, X86_ADD, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2292                         break;
2293                 case OP_X86_ADD_MEMBASE:
2294                         x86_alu_reg_membase (code, X86_ADD, ins->sreg1, ins->sreg2, ins->inst_offset);
2295                         break;
2296                 case OP_X86_SUB_MEMBASE_IMM:
2297                         x86_alu_membase_imm (code, X86_SUB, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2298                         break;
2299                 case OP_X86_SUB_MEMBASE:
2300                         x86_alu_reg_membase (code, X86_SUB, ins->sreg1, ins->sreg2, ins->inst_offset);
2301                         break;
2302                 case OP_X86_INC_MEMBASE:
2303                         x86_inc_membase (code, ins->inst_basereg, ins->inst_offset);
2304                         break;
2305                 case OP_X86_INC_REG:
2306                         x86_inc_reg (code, ins->dreg);
2307                         break;
2308                 case OP_X86_DEC_MEMBASE:
2309                         x86_dec_membase (code, ins->inst_basereg, ins->inst_offset);
2310                         break;
2311                 case OP_X86_DEC_REG:
2312                         x86_dec_reg (code, ins->dreg);
2313                         break;
2314                 case OP_X86_MUL_MEMBASE:
2315                         x86_imul_reg_membase (code, ins->sreg1, ins->sreg2, ins->inst_offset);
2316                         break;
2317                 case CEE_BREAK:
2318                         x86_breakpoint (code);
2319                         break;
2320                 case OP_ADDCC:
2321                 case CEE_ADD:
2322                         x86_alu_reg_reg (code, X86_ADD, ins->sreg1, ins->sreg2);
2323                         break;
2324                 case OP_ADC:
2325                         x86_alu_reg_reg (code, X86_ADC, ins->sreg1, ins->sreg2);
2326                         break;
2327                 case OP_ADD_IMM:
2328                         x86_alu_reg_imm (code, X86_ADD, ins->dreg, ins->inst_imm);
2329                         break;
2330                 case OP_ADC_IMM:
2331                         x86_alu_reg_imm (code, X86_ADC, ins->dreg, ins->inst_imm);
2332                         break;
2333                 case OP_SUBCC:
2334                 case CEE_SUB:
2335                         x86_alu_reg_reg (code, X86_SUB, ins->sreg1, ins->sreg2);
2336                         break;
2337                 case OP_SBB:
2338                         x86_alu_reg_reg (code, X86_SBB, ins->sreg1, ins->sreg2);
2339                         break;
2340                 case OP_SUB_IMM:
2341                         x86_alu_reg_imm (code, X86_SUB, ins->dreg, ins->inst_imm);
2342                         break;
2343                 case OP_SBB_IMM:
2344                         x86_alu_reg_imm (code, X86_SBB, ins->dreg, ins->inst_imm);
2345                         break;
2346                 case CEE_AND:
2347                         x86_alu_reg_reg (code, X86_AND, ins->sreg1, ins->sreg2);
2348                         break;
2349                 case OP_AND_IMM:
2350                         x86_alu_reg_imm (code, X86_AND, ins->sreg1, ins->inst_imm);
2351                         break;
2352                 case CEE_DIV:
2353                         x86_cdq (code);
2354                         x86_div_reg (code, ins->sreg2, TRUE);
2355                         break;
2356                 case CEE_DIV_UN:
2357                         x86_alu_reg_reg (code, X86_XOR, X86_EDX, X86_EDX);
2358                         x86_div_reg (code, ins->sreg2, FALSE);
2359                         break;
2360                 case OP_DIV_IMM:
2361                         x86_mov_reg_imm (code, ins->sreg2, ins->inst_imm);
2362                         x86_cdq (code);
2363                         x86_div_reg (code, ins->sreg2, TRUE);
2364                         break;
2365                 case CEE_REM:
2366                         x86_cdq (code);
2367                         x86_div_reg (code, ins->sreg2, TRUE);
2368                         break;
2369                 case CEE_REM_UN:
2370                         x86_alu_reg_reg (code, X86_XOR, X86_EDX, X86_EDX);
2371                         x86_div_reg (code, ins->sreg2, FALSE);
2372                         break;
2373                 case OP_REM_IMM:
2374                         x86_mov_reg_imm (code, ins->sreg2, ins->inst_imm);
2375                         x86_cdq (code);
2376                         x86_div_reg (code, ins->sreg2, TRUE);
2377                         break;
2378                 case CEE_OR:
2379                         x86_alu_reg_reg (code, X86_OR, ins->sreg1, ins->sreg2);
2380                         break;
2381                 case OP_OR_IMM:
2382                         x86_alu_reg_imm (code, X86_OR, ins->sreg1, ins->inst_imm);
2383                         break;
2384                 case CEE_XOR:
2385                         x86_alu_reg_reg (code, X86_XOR, ins->sreg1, ins->sreg2);
2386                         break;
2387                 case OP_XOR_IMM:
2388                         x86_alu_reg_imm (code, X86_XOR, ins->sreg1, ins->inst_imm);
2389                         break;
2390                 case CEE_SHL:
2391                         g_assert (ins->sreg2 == X86_ECX);
2392                         x86_shift_reg (code, X86_SHL, ins->dreg);
2393                         break;
2394                 case CEE_SHR:
2395                         g_assert (ins->sreg2 == X86_ECX);
2396                         x86_shift_reg (code, X86_SAR, ins->dreg);
2397                         break;
2398                 case OP_SHR_IMM:
2399                         x86_shift_reg_imm (code, X86_SAR, ins->dreg, ins->inst_imm);
2400                         break;
2401                 case OP_SHR_UN_IMM:
2402                         x86_shift_reg_imm (code, X86_SHR, ins->dreg, ins->inst_imm);
2403                         break;
2404                 case CEE_SHR_UN:
2405                         g_assert (ins->sreg2 == X86_ECX);
2406                         x86_shift_reg (code, X86_SHR, ins->dreg);
2407                         break;
2408                 case OP_SHL_IMM:
2409                         x86_shift_reg_imm (code, X86_SHL, ins->dreg, ins->inst_imm);
2410                         break;
2411                 case OP_LSHL: {
2412                         guint8 *jump_to_end;
2413
2414                         /* handle shifts below 32 bits */
2415                         x86_shld_reg (code, ins->unused, ins->sreg1);
2416                         x86_shift_reg (code, X86_SHL, ins->sreg1);
2417
2418                         x86_test_reg_imm (code, X86_ECX, 32);
2419                         jump_to_end = code; x86_branch8 (code, X86_CC_EQ, 0, TRUE);
2420
2421                         /* handle shift over 32 bit */
2422                         x86_mov_reg_reg (code, ins->unused, ins->sreg1, 4);
2423                         x86_clear_reg (code, ins->sreg1);
2424                         
2425                         x86_patch (jump_to_end, code);
2426                         }
2427                         break;
2428                 case OP_LSHR: {
2429                         guint8 *jump_to_end;
2430
2431                         /* handle shifts below 32 bits */
2432                         x86_shrd_reg (code, ins->sreg1, ins->unused);
2433                         x86_shift_reg (code, X86_SAR, ins->unused);
2434
2435                         x86_test_reg_imm (code, X86_ECX, 32);
2436                         jump_to_end = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE);
2437
2438                         /* handle shifts over 31 bits */
2439                         x86_mov_reg_reg (code, ins->sreg1, ins->unused, 4);
2440                         x86_shift_reg_imm (code, X86_SAR, ins->unused, 31);
2441                         
2442                         x86_patch (jump_to_end, code);
2443                         }
2444                         break;
2445                 case OP_LSHR_UN: {
2446                         guint8 *jump_to_end;
2447
2448                         /* handle shifts below 32 bits */
2449                         x86_shrd_reg (code, ins->sreg1, ins->unused);
2450                         x86_shift_reg (code, X86_SHR, ins->unused);
2451
2452                         x86_test_reg_imm (code, X86_ECX, 32);
2453                         jump_to_end = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE);
2454
2455                         /* handle shifts over 31 bits */
2456                         x86_mov_reg_reg (code, ins->sreg1, ins->unused, 4);
2457                         x86_shift_reg_imm (code, X86_SHR, ins->unused, 31);
2458                         
2459                         x86_patch (jump_to_end, code);
2460                         }
2461                         break;
2462                 case OP_LSHL_IMM:
2463                         if (ins->inst_imm >= 32) {
2464                                 x86_mov_reg_reg (code, ins->unused, ins->sreg1, 4);
2465                                 x86_clear_reg (code, ins->sreg1);
2466                                 x86_shift_reg_imm (code, X86_SHL, ins->unused, ins->inst_imm - 32);
2467                         } else {
2468                                 x86_shld_reg_imm (code, ins->unused, ins->sreg1, ins->inst_imm);
2469                                 x86_shift_reg_imm (code, X86_SHL, ins->sreg1, ins->inst_imm);
2470                         }
2471                         break;
2472                 case OP_LSHR_IMM:
2473                         if (ins->inst_imm >= 32) {
2474                                 x86_mov_reg_reg (code, ins->sreg1, ins->unused,  4);
2475                                 x86_shift_reg_imm (code, X86_SAR, ins->unused, 0x1f);
2476                                 x86_shift_reg_imm (code, X86_SAR, ins->sreg1, ins->inst_imm - 32);
2477                         } else {
2478                                 x86_shrd_reg_imm (code, ins->sreg1, ins->unused, ins->inst_imm);
2479                                 x86_shift_reg_imm (code, X86_SAR, ins->unused, ins->inst_imm);
2480                         }
2481                         break;
2482                 case OP_LSHR_UN_IMM:
2483                         if (ins->inst_imm >= 32) {
2484                                 x86_mov_reg_reg (code, ins->sreg1, ins->unused, 4);
2485                                 x86_clear_reg (code, ins->unused);
2486                                 x86_shift_reg_imm (code, X86_SHR, ins->sreg1, ins->inst_imm - 32);
2487                         } else {
2488                                 x86_shrd_reg_imm (code, ins->sreg1, ins->unused, ins->inst_imm);
2489                                 x86_shift_reg_imm (code, X86_SHR, ins->unused, ins->inst_imm);
2490                         }
2491                         break;
2492                 case CEE_NOT:
2493                         x86_not_reg (code, ins->sreg1);
2494                         break;
2495                 case CEE_NEG:
2496                         x86_neg_reg (code, ins->sreg1);
2497                         break;
2498                 case OP_SEXT_I1:
2499                         x86_widen_reg (code, ins->dreg, ins->sreg1, TRUE, FALSE);
2500                         break;
2501                 case OP_SEXT_I2:
2502                         x86_widen_reg (code, ins->dreg, ins->sreg1, TRUE, TRUE);
2503                         break;
2504                 case CEE_MUL:
2505                         x86_imul_reg_reg (code, ins->sreg1, ins->sreg2);
2506                         break;
2507                 case OP_MUL_IMM:
2508                         x86_imul_reg_reg_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2509                         break;
2510                 case CEE_MUL_OVF:
2511                         x86_imul_reg_reg (code, ins->sreg1, ins->sreg2);
2512                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_O, FALSE, "OverflowException");
2513                         break;
2514                 case CEE_MUL_OVF_UN: {
2515                         /* the mul operation and the exception check should most likely be split */
2516                         int non_eax_reg, saved_eax = FALSE, saved_edx = FALSE;
2517                         /*g_assert (ins->sreg2 == X86_EAX);
2518                         g_assert (ins->dreg == X86_EAX);*/
2519                         if (ins->sreg2 == X86_EAX) {
2520                                 non_eax_reg = ins->sreg1;
2521                         } else if (ins->sreg1 == X86_EAX) {
2522                                 non_eax_reg = ins->sreg2;
2523                         } else {
2524                                 /* no need to save since we're going to store to it anyway */
2525                                 if (ins->dreg != X86_EAX) {
2526                                         saved_eax = TRUE;
2527                                         x86_push_reg (code, X86_EAX);
2528                                 }
2529                                 x86_mov_reg_reg (code, X86_EAX, ins->sreg1, 4);
2530                                 non_eax_reg = ins->sreg2;
2531                         }
2532                         if (ins->dreg == X86_EDX) {
2533                                 if (!saved_eax) {
2534                                         saved_eax = TRUE;
2535                                         x86_push_reg (code, X86_EAX);
2536                                 }
2537                         } else if (ins->dreg != X86_EAX) {
2538                                 saved_edx = TRUE;
2539                                 x86_push_reg (code, X86_EDX);
2540                         }
2541                         x86_mul_reg (code, non_eax_reg, FALSE);
2542                         /* save before the check since pop and mov don't change the flags */
2543                         if (ins->dreg != X86_EAX)
2544                                 x86_mov_reg_reg (code, ins->dreg, X86_EAX, 4);
2545                         if (saved_edx)
2546                                 x86_pop_reg (code, X86_EDX);
2547                         if (saved_eax)
2548                                 x86_pop_reg (code, X86_EAX);
2549                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_O, FALSE, "OverflowException");
2550                         break;
2551                 }
2552                 case OP_ICONST:
2553                         x86_mov_reg_imm (code, ins->dreg, ins->inst_c0);
2554                         break;
2555                 case OP_AOTCONST:
2556                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2557                         x86_mov_reg_imm (code, ins->dreg, 0);
2558                         break;
2559                 case CEE_CONV_I4:
2560                 case OP_MOVE:
2561                         x86_mov_reg_reg (code, ins->dreg, ins->sreg1, 4);
2562                         break;
2563                 case CEE_CONV_U4:
2564                         g_assert_not_reached ();
2565                 case CEE_JMP: {
2566                         /*
2567                          * Note: this 'frame destruction' logic is useful for tail calls, too.
2568                          * Keep in sync with the code in emit_epilog.
2569                          */
2570                         int pos = 0;
2571
2572                         /* FIXME: no tracing support... */
2573                         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
2574                                 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
2575                         /* reset offset to make max_len work */
2576                         offset = code - cfg->native_code;
2577
2578                         g_assert (!cfg->method->save_lmf);
2579
2580                         if (cfg->used_int_regs & (1 << X86_EBX))
2581                                 pos -= 4;
2582                         if (cfg->used_int_regs & (1 << X86_EDI))
2583                                 pos -= 4;
2584                         if (cfg->used_int_regs & (1 << X86_ESI))
2585                                 pos -= 4;
2586                         if (pos)
2587                                 x86_lea_membase (code, X86_ESP, X86_EBP, pos);
2588         
2589                         if (cfg->used_int_regs & (1 << X86_ESI))
2590                                 x86_pop_reg (code, X86_ESI);
2591                         if (cfg->used_int_regs & (1 << X86_EDI))
2592                                 x86_pop_reg (code, X86_EDI);
2593                         if (cfg->used_int_regs & (1 << X86_EBX))
2594                                 x86_pop_reg (code, X86_EBX);
2595         
2596                         /* restore ESP/EBP */
2597                         x86_leave (code);
2598                         offset = code - cfg->native_code;
2599                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2600                         x86_jump32 (code, 0);
2601                         break;
2602                 }
2603                 case OP_CHECK_THIS:
2604                         /* ensure ins->sreg1 is not NULL */
2605                         x86_alu_membase_imm (code, X86_CMP, ins->sreg1, 0, 0);
2606                         break;
2607                 case OP_ARGLIST: {
2608                         int hreg = ins->sreg1 == X86_EAX? X86_ECX: X86_EAX;
2609                         x86_push_reg (code, hreg);
2610                         x86_lea_membase (code, hreg, X86_EBP, cfg->sig_cookie);
2611                         x86_mov_membase_reg (code, ins->sreg1, 0, hreg, 4);
2612                         x86_pop_reg (code, hreg);
2613                         break;
2614                 }
2615                 case OP_FCALL:
2616                 case OP_LCALL:
2617                 case OP_VCALL:
2618                 case OP_VOIDCALL:
2619                 case CEE_CALL:
2620                         call = (MonoCallInst*)ins;
2621                         if (ins->flags & MONO_INST_HAS_METHOD)
2622                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2623                         else {
2624                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2625                         }
2626                         x86_call_code (code, 0);
2627                         if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature->call_convention))
2628                                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, call->stack_usage);
2629                         break;
2630                 case OP_FCALL_REG:
2631                 case OP_LCALL_REG:
2632                 case OP_VCALL_REG:
2633                 case OP_VOIDCALL_REG:
2634                 case OP_CALL_REG:
2635                         call = (MonoCallInst*)ins;
2636                         x86_call_reg (code, ins->sreg1);
2637                         if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature->call_convention))
2638                                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, call->stack_usage);
2639                         break;
2640                 case OP_FCALL_MEMBASE:
2641                 case OP_LCALL_MEMBASE:
2642                 case OP_VCALL_MEMBASE:
2643                 case OP_VOIDCALL_MEMBASE:
2644                 case OP_CALL_MEMBASE:
2645                         call = (MonoCallInst*)ins;
2646                         x86_call_membase (code, ins->sreg1, ins->inst_offset);
2647                         if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature->call_convention))
2648                                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, call->stack_usage);
2649                         break;
2650                 case OP_OUTARG:
2651                 case OP_X86_PUSH:
2652                         x86_push_reg (code, ins->sreg1);
2653                         break;
2654                 case OP_X86_PUSH_IMM:
2655                         x86_push_imm (code, ins->inst_imm);
2656                         break;
2657                 case OP_X86_PUSH_MEMBASE:
2658                         x86_push_membase (code, ins->inst_basereg, ins->inst_offset);
2659                         break;
2660                 case OP_X86_PUSH_OBJ: 
2661                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, ins->inst_imm);
2662                         x86_push_reg (code, X86_EDI);
2663                         x86_push_reg (code, X86_ESI);
2664                         x86_push_reg (code, X86_ECX);
2665                         if (ins->inst_offset)
2666                                 x86_lea_membase (code, X86_ESI, ins->inst_basereg, ins->inst_offset);
2667                         else
2668                                 x86_mov_reg_reg (code, X86_ESI, ins->inst_basereg, 4);
2669                         x86_lea_membase (code, X86_EDI, X86_ESP, 12);
2670                         x86_mov_reg_imm (code, X86_ECX, (ins->inst_imm >> 2));
2671                         x86_cld (code);
2672                         x86_prefix (code, X86_REP_PREFIX);
2673                         x86_movsd (code);
2674                         x86_pop_reg (code, X86_ECX);
2675                         x86_pop_reg (code, X86_ESI);
2676                         x86_pop_reg (code, X86_EDI);
2677                         break;
2678                 case OP_X86_LEA:
2679                         x86_lea_memindex (code, ins->dreg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->unused);
2680                         break;
2681                 case OP_X86_LEA_MEMBASE:
2682                         x86_lea_membase (code, ins->dreg, ins->sreg1, ins->inst_imm);
2683                         break;
2684                 case OP_X86_XCHG:
2685                         x86_xchg_reg_reg (code, ins->sreg1, ins->sreg2, 4);
2686                         break;
2687                 case OP_LOCALLOC:
2688                         /* keep alignment */
2689                         x86_alu_reg_imm (code, X86_ADD, ins->sreg1, MONO_ARCH_FRAME_ALIGNMENT - 1);
2690                         x86_alu_reg_imm (code, X86_AND, ins->sreg1, ~(MONO_ARCH_FRAME_ALIGNMENT - 1));
2691                         code = mono_emit_stack_alloc (code, ins);
2692                         x86_mov_reg_reg (code, ins->dreg, X86_ESP, 4);
2693                         break;
2694                 case CEE_RET:
2695                         x86_ret (code);
2696                         break;
2697                 case CEE_THROW: {
2698                         x86_push_reg (code, ins->sreg1);
2699                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2700                                              (gpointer)"mono_arch_throw_exception");
2701                         x86_call_code (code, 0);
2702                         break;
2703                 }
2704                 case OP_CALL_HANDLER: 
2705                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2706                         x86_call_imm (code, 0);
2707                         break;
2708                 case OP_LABEL:
2709                         ins->inst_c0 = code - cfg->native_code;
2710                         break;
2711                 case CEE_BR:
2712                         //g_print ("target: %p, next: %p, curr: %p, last: %p\n", ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
2713                         //if ((ins->inst_target_bb == bb->next_bb) && ins == bb->last_ins)
2714                         //break;
2715                         if (ins->flags & MONO_INST_BRLABEL) {
2716                                 if (ins->inst_i0->inst_c0) {
2717                                         x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
2718                                 } else {
2719                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2720                                         if ((cfg->opt & MONO_OPT_BRANCH) &&
2721                                             x86_is_imm8 (ins->inst_i0->inst_c1 - cpos))
2722                                                 x86_jump8 (code, 0);
2723                                         else 
2724                                                 x86_jump32 (code, 0);
2725                                 }
2726                         } else {
2727                                 if (ins->inst_target_bb->native_offset) {
2728                                         x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); 
2729                                 } else {
2730                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2731                                         if ((cfg->opt & MONO_OPT_BRANCH) &&
2732                                             x86_is_imm8 (ins->inst_target_bb->max_offset - cpos))
2733                                                 x86_jump8 (code, 0);
2734                                         else 
2735                                                 x86_jump32 (code, 0);
2736                                 } 
2737                         }
2738                         break;
2739                 case OP_BR_REG:
2740                         x86_jump_reg (code, ins->sreg1);
2741                         break;
2742                 case OP_CEQ:
2743                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
2744                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
2745                         break;
2746                 case OP_CLT:
2747                         x86_set_reg (code, X86_CC_LT, ins->dreg, TRUE);
2748                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
2749                         break;
2750                 case OP_CLT_UN:
2751                         x86_set_reg (code, X86_CC_LT, ins->dreg, FALSE);
2752                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
2753                         break;
2754                 case OP_CGT:
2755                         x86_set_reg (code, X86_CC_GT, ins->dreg, TRUE);
2756                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
2757                         break;
2758                 case OP_CGT_UN:
2759                         x86_set_reg (code, X86_CC_GT, ins->dreg, FALSE);
2760                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
2761                         break;
2762                 case OP_COND_EXC_EQ:
2763                 case OP_COND_EXC_NE_UN:
2764                 case OP_COND_EXC_LT:
2765                 case OP_COND_EXC_LT_UN:
2766                 case OP_COND_EXC_GT:
2767                 case OP_COND_EXC_GT_UN:
2768                 case OP_COND_EXC_GE:
2769                 case OP_COND_EXC_GE_UN:
2770                 case OP_COND_EXC_LE:
2771                 case OP_COND_EXC_LE_UN:
2772                 case OP_COND_EXC_OV:
2773                 case OP_COND_EXC_NO:
2774                 case OP_COND_EXC_C:
2775                 case OP_COND_EXC_NC:
2776                         EMIT_COND_SYSTEM_EXCEPTION (branch_cc_table [ins->opcode - OP_COND_EXC_EQ], 
2777                                                     (ins->opcode < OP_COND_EXC_NE_UN), ins->inst_p1);
2778                         break;
2779                 case CEE_BEQ:
2780                 case CEE_BNE_UN:
2781                 case CEE_BLT:
2782                 case CEE_BLT_UN:
2783                 case CEE_BGT:
2784                 case CEE_BGT_UN:
2785                 case CEE_BGE:
2786                 case CEE_BGE_UN:
2787                 case CEE_BLE:
2788                 case CEE_BLE_UN:
2789                         EMIT_COND_BRANCH (ins, branch_cc_table [ins->opcode - CEE_BEQ], (ins->opcode < CEE_BNE_UN));
2790                         break;
2791
2792                 /* floating point opcodes */
2793                 case OP_R8CONST: {
2794                         double d = *(double *)ins->inst_p0;
2795
2796                         if ((d == 0.0) && (mono_signbit (d) == 0)) {
2797                                 x86_fldz (code);
2798                         } else if (d == 1.0) {
2799                                 x86_fld1 (code);
2800                         } else {
2801                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R8, ins->inst_p0);
2802                                 x86_fld (code, NULL, TRUE);
2803                         }
2804                         break;
2805                 }
2806                 case OP_R4CONST: {
2807                         float f = *(float *)ins->inst_p0;
2808
2809                         if ((f == 0.0) && (mono_signbit (f) == 0)) {
2810                                 x86_fldz (code);
2811                         } else if (f == 1.0) {
2812                                 x86_fld1 (code);
2813                         } else {
2814                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R4, ins->inst_p0);
2815                                 x86_fld (code, NULL, FALSE);
2816                         }
2817                         break;
2818                 }
2819                 case OP_STORER8_MEMBASE_REG:
2820                         x86_fst_membase (code, ins->inst_destbasereg, ins->inst_offset, TRUE, TRUE);
2821                         break;
2822                 case OP_LOADR8_SPILL_MEMBASE:
2823                         x86_fld_membase (code, ins->inst_basereg, ins->inst_offset, TRUE);
2824                         x86_fxch (code, 1);
2825                         break;
2826                 case OP_LOADR8_MEMBASE:
2827                         x86_fld_membase (code, ins->inst_basereg, ins->inst_offset, TRUE);
2828                         break;
2829                 case OP_STORER4_MEMBASE_REG:
2830                         x86_fst_membase (code, ins->inst_destbasereg, ins->inst_offset, FALSE, TRUE);
2831                         break;
2832                 case OP_LOADR4_MEMBASE:
2833                         x86_fld_membase (code, ins->inst_basereg, ins->inst_offset, FALSE);
2834                         break;
2835                 case CEE_CONV_R4: /* FIXME: change precision */
2836                 case CEE_CONV_R8:
2837                         x86_push_reg (code, ins->sreg1);
2838                         x86_fild_membase (code, X86_ESP, 0, FALSE);
2839                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
2840                         break;
2841                 case OP_X86_FP_LOAD_I8:
2842                         x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, TRUE);
2843                         break;
2844                 case OP_X86_FP_LOAD_I4:
2845                         x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, FALSE);
2846                         break;
2847                 case OP_FCONV_TO_I1:
2848                         code = emit_float_to_int (cfg, code, ins->dreg, 1, TRUE);
2849                         break;
2850                 case OP_FCONV_TO_U1:
2851                         code = emit_float_to_int (cfg, code, ins->dreg, 1, FALSE);
2852                         break;
2853                 case OP_FCONV_TO_I2:
2854                         code = emit_float_to_int (cfg, code, ins->dreg, 2, TRUE);
2855                         break;
2856                 case OP_FCONV_TO_U2:
2857                         code = emit_float_to_int (cfg, code, ins->dreg, 2, FALSE);
2858                         break;
2859                 case OP_FCONV_TO_I4:
2860                 case OP_FCONV_TO_I:
2861                         code = emit_float_to_int (cfg, code, ins->dreg, 4, TRUE);
2862                         break;
2863                 case OP_FCONV_TO_I8:
2864                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 4);
2865                         x86_fnstcw_membase(code, X86_ESP, 0);
2866                         x86_mov_reg_membase (code, ins->dreg, X86_ESP, 0, 2);
2867                         x86_alu_reg_imm (code, X86_OR, ins->dreg, 0xc00);
2868                         x86_mov_membase_reg (code, X86_ESP, 2, ins->dreg, 2);
2869                         x86_fldcw_membase (code, X86_ESP, 2);
2870                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
2871                         x86_fist_pop_membase (code, X86_ESP, 0, TRUE);
2872                         x86_pop_reg (code, ins->dreg);
2873                         x86_pop_reg (code, ins->unused);
2874                         x86_fldcw_membase (code, X86_ESP, 0);
2875                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
2876                         break;
2877                 case OP_LCONV_TO_R_UN: { 
2878                         static guint8 mn[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x40 };
2879                         guint8 *br;
2880
2881                         /* load 64bit integer to FP stack */
2882                         x86_push_imm (code, 0);
2883                         x86_push_reg (code, ins->sreg2);
2884                         x86_push_reg (code, ins->sreg1);
2885                         x86_fild_membase (code, X86_ESP, 0, TRUE);
2886                         /* store as 80bit FP value */
2887                         x86_fst80_membase (code, X86_ESP, 0);
2888                         
2889                         /* test if lreg is negative */
2890                         x86_test_reg_reg (code, ins->sreg2, ins->sreg2);
2891                         br = code; x86_branch8 (code, X86_CC_GEZ, 0, TRUE);
2892         
2893                         /* add correction constant mn */
2894                         x86_fld80_mem (code, mn);
2895                         x86_fld80_membase (code, X86_ESP, 0);
2896                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
2897                         x86_fst80_membase (code, X86_ESP, 0);
2898
2899                         x86_patch (br, code);
2900
2901                         x86_fld80_membase (code, X86_ESP, 0);
2902                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
2903
2904                         break;
2905                 }
2906                 case OP_LCONV_TO_OVF_I: {
2907                         guint8 *br [3], *label [1];
2908
2909                         /* 
2910                          * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
2911                          */
2912                         x86_test_reg_reg (code, ins->sreg1, ins->sreg1);
2913
2914                         /* If the low word top bit is set, see if we are negative */
2915                         br [0] = code; x86_branch8 (code, X86_CC_LT, 0, TRUE);
2916                         /* We are not negative (no top bit set, check for our top word to be zero */
2917                         x86_test_reg_reg (code, ins->sreg2, ins->sreg2);
2918                         br [1] = code; x86_branch8 (code, X86_CC_EQ, 0, TRUE);
2919                         label [0] = code;
2920
2921                         /* throw exception */
2922                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC, "OverflowException");
2923                         x86_jump32 (code, 0);
2924         
2925                         x86_patch (br [0], code);
2926                         /* our top bit is set, check that top word is 0xfffffff */
2927                         x86_alu_reg_imm (code, X86_CMP, ins->sreg2, 0xffffffff);
2928                 
2929                         x86_patch (br [1], code);
2930                         /* nope, emit exception */
2931                         br [2] = code; x86_branch8 (code, X86_CC_NE, 0, TRUE);
2932                         x86_patch (br [2], label [0]);
2933
2934                         if (ins->dreg != ins->sreg1)
2935                                 x86_mov_reg_reg (code, ins->dreg, ins->sreg1, 4);
2936                         break;
2937                 }
2938                 case OP_FADD:
2939                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
2940                         break;
2941                 case OP_FSUB:
2942                         x86_fp_op_reg (code, X86_FSUB, 1, TRUE);
2943                         break;          
2944                 case OP_FMUL:
2945                         x86_fp_op_reg (code, X86_FMUL, 1, TRUE);
2946                         break;          
2947                 case OP_FDIV:
2948                         x86_fp_op_reg (code, X86_FDIV, 1, TRUE);
2949                         break;          
2950                 case OP_FNEG:
2951                         x86_fchs (code);
2952                         break;          
2953                 case OP_SIN:
2954                         x86_fsin (code);
2955                         x86_fldz (code);
2956                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
2957                         break;          
2958                 case OP_COS:
2959                         x86_fcos (code);
2960                         x86_fldz (code);
2961                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
2962                         break;          
2963                 case OP_ABS:
2964                         x86_fabs (code);
2965                         break;          
2966                 case OP_TAN: {
2967                         /* 
2968                          * it really doesn't make sense to inline all this code,
2969                          * it's here just to show that things may not be as simple 
2970                          * as they appear.
2971                          */
2972                         guchar *check_pos, *end_tan, *pop_jump;
2973                         x86_push_reg (code, X86_EAX);
2974                         x86_fptan (code);
2975                         x86_fnstsw (code);
2976                         x86_test_reg_imm (code, X86_EAX, X86_FP_C2);
2977                         check_pos = code;
2978                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
2979                         x86_fstp (code, 0); /* pop the 1.0 */
2980                         end_tan = code;
2981                         x86_jump8 (code, 0);
2982                         x86_fldpi (code);
2983                         x86_fp_op (code, X86_FADD, 0);
2984                         x86_fxch (code, 1);
2985                         x86_fprem1 (code);
2986                         x86_fstsw (code);
2987                         x86_test_reg_imm (code, X86_EAX, X86_FP_C2);
2988                         pop_jump = code;
2989                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
2990                         x86_fstp (code, 1);
2991                         x86_fptan (code);
2992                         x86_patch (pop_jump, code);
2993                         x86_fstp (code, 0); /* pop the 1.0 */
2994                         x86_patch (check_pos, code);
2995                         x86_patch (end_tan, code);
2996                         x86_fldz (code);
2997                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
2998                         x86_pop_reg (code, X86_EAX);
2999                         break;
3000                 }
3001                 case OP_ATAN:
3002                         x86_fld1 (code);
3003                         x86_fpatan (code);
3004                         x86_fldz (code);
3005                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3006                         break;          
3007                 case OP_SQRT:
3008                         x86_fsqrt (code);
3009                         break;          
3010                 case OP_X86_FPOP:
3011                         x86_fstp (code, 0);
3012                         break;          
3013                 case OP_FREM: {
3014                         guint8 *l1, *l2;
3015
3016                         x86_push_reg (code, X86_EAX);
3017                         /* we need to exchange ST(0) with ST(1) */
3018                         x86_fxch (code, 1);
3019
3020                         /* this requires a loop, because fprem somtimes 
3021                          * returns a partial remainder */
3022                         l1 = code;
3023                         /* looks like MS is using fprem instead of the IEEE compatible fprem1 */
3024                         /* x86_fprem1 (code); */
3025                         x86_fprem (code);
3026                         x86_fnstsw (code);
3027                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_C2);
3028                         l2 = code + 2;
3029                         x86_branch8 (code, X86_CC_NE, l1 - l2, FALSE);
3030
3031                         /* pop result */
3032                         x86_fstp (code, 1);
3033
3034                         x86_pop_reg (code, X86_EAX);
3035                         break;
3036                 }
3037                 case OP_FCOMPARE:
3038                         if (cfg->opt & MONO_OPT_FCMOV) {
3039                                 x86_fcomip (code, 1);
3040                                 x86_fstp (code, 0);
3041                                 break;
3042                         }
3043                         /* this overwrites EAX */
3044                         EMIT_FPCOMPARE(code);
3045                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3046                         break;
3047                 case OP_FCEQ:
3048                         if (cfg->opt & MONO_OPT_FCMOV) {
3049                                 /* zeroing the register at the start results in 
3050                                  * shorter and faster code (we can also remove the widening op)
3051                                  */
3052                                 guchar *unordered_check;
3053                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
3054                                 x86_fcomip (code, 1);
3055                                 x86_fstp (code, 0);
3056                                 unordered_check = code;
3057                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
3058                                 x86_set_reg (code, X86_CC_EQ, ins->dreg, FALSE);
3059                                 x86_patch (unordered_check, code);
3060                                 break;
3061                         }
3062                         if (ins->dreg != X86_EAX) 
3063                                 x86_push_reg (code, X86_EAX);
3064
3065                         EMIT_FPCOMPARE(code);
3066                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3067                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0x4000);
3068                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
3069                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3070
3071                         if (ins->dreg != X86_EAX) 
3072                                 x86_pop_reg (code, X86_EAX);
3073                         break;
3074                 case OP_FCLT:
3075                 case OP_FCLT_UN:
3076                         if (cfg->opt & MONO_OPT_FCMOV) {
3077                                 /* zeroing the register at the start results in 
3078                                  * shorter and faster code (we can also remove the widening op)
3079                                  */
3080                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
3081                                 x86_fcomip (code, 1);
3082                                 x86_fstp (code, 0);
3083                                 if (ins->opcode == OP_FCLT_UN) {
3084                                         guchar *unordered_check = code;
3085                                         guchar *jump_to_end;
3086                                         x86_branch8 (code, X86_CC_P, 0, FALSE);
3087                                         x86_set_reg (code, X86_CC_GT, ins->dreg, FALSE);
3088                                         jump_to_end = code;
3089                                         x86_jump8 (code, 0);
3090                                         x86_patch (unordered_check, code);
3091                                         x86_inc_reg (code, ins->dreg);
3092                                         x86_patch (jump_to_end, code);
3093                                 } else {
3094                                         x86_set_reg (code, X86_CC_GT, ins->dreg, FALSE);
3095                                 }
3096                                 break;
3097                         }
3098                         if (ins->dreg != X86_EAX) 
3099                                 x86_push_reg (code, X86_EAX);
3100
3101                         EMIT_FPCOMPARE(code);
3102                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3103                         if (ins->opcode == OP_FCLT_UN) {
3104                                 guchar *is_not_zero_check, *end_jump;
3105                                 is_not_zero_check = code;
3106                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3107                                 end_jump = code;
3108                                 x86_jump8 (code, 0);
3109                                 x86_patch (is_not_zero_check, code);
3110                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3111
3112                                 x86_patch (end_jump, code);
3113                         }
3114                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
3115                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3116
3117                         if (ins->dreg != X86_EAX) 
3118                                 x86_pop_reg (code, X86_EAX);
3119                         break;
3120                 case OP_FCGT:
3121                 case OP_FCGT_UN:
3122                         if (cfg->opt & MONO_OPT_FCMOV) {
3123                                 /* zeroing the register at the start results in 
3124                                  * shorter and faster code (we can also remove the widening op)
3125                                  */
3126                                 guchar *unordered_check;
3127                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
3128                                 x86_fcomip (code, 1);
3129                                 x86_fstp (code, 0);
3130                                 if (ins->opcode == OP_FCGT) {
3131                                         unordered_check = code;
3132                                         x86_branch8 (code, X86_CC_P, 0, FALSE);
3133                                         x86_set_reg (code, X86_CC_LT, ins->dreg, FALSE);
3134                                         x86_patch (unordered_check, code);
3135                                 } else {
3136                                         x86_set_reg (code, X86_CC_LT, ins->dreg, FALSE);
3137                                 }
3138                                 break;
3139                         }
3140                         if (ins->dreg != X86_EAX) 
3141                                 x86_push_reg (code, X86_EAX);
3142
3143                         EMIT_FPCOMPARE(code);
3144                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3145                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3146                         if (ins->opcode == OP_FCGT_UN) {
3147                                 guchar *is_not_zero_check, *end_jump;
3148                                 is_not_zero_check = code;
3149                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3150                                 end_jump = code;
3151                                 x86_jump8 (code, 0);
3152                                 x86_patch (is_not_zero_check, code);
3153                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3154
3155                                 x86_patch (end_jump, code);
3156                         }
3157                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
3158                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3159
3160                         if (ins->dreg != X86_EAX) 
3161                                 x86_pop_reg (code, X86_EAX);
3162                         break;
3163                 case OP_FBEQ:
3164                         if (cfg->opt & MONO_OPT_FCMOV) {
3165                                 guchar *jump = code;
3166                                 x86_branch8 (code, X86_CC_P, 0, TRUE);
3167                                 EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3168                                 x86_patch (jump, code);
3169                                 break;
3170                         }
3171                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0x4000);
3172                         EMIT_COND_BRANCH (ins, X86_CC_EQ, TRUE);
3173                         break;
3174                 case OP_FBNE_UN:
3175                         /* Branch if C013 != 100 */
3176                         if (cfg->opt & MONO_OPT_FCMOV) {
3177                                 /* branch if !ZF or (PF|CF) */
3178                                 EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3179                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
3180                                 EMIT_COND_BRANCH (ins, X86_CC_B, FALSE);
3181                                 break;
3182                         }
3183                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C3);
3184                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3185                         break;
3186                 case OP_FBLT:
3187                         if (cfg->opt & MONO_OPT_FCMOV) {
3188                                 EMIT_COND_BRANCH (ins, X86_CC_GT, FALSE);
3189                                 break;
3190                         }
3191                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3192                         break;
3193                 case OP_FBLT_UN:
3194                         if (cfg->opt & MONO_OPT_FCMOV) {
3195                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
3196                                 EMIT_COND_BRANCH (ins, X86_CC_GT, FALSE);
3197                                 break;
3198                         }
3199                         if (ins->opcode == OP_FBLT_UN) {
3200                                 guchar *is_not_zero_check, *end_jump;
3201                                 is_not_zero_check = code;
3202                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3203                                 end_jump = code;
3204                                 x86_jump8 (code, 0);
3205                                 x86_patch (is_not_zero_check, code);
3206                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3207
3208                                 x86_patch (end_jump, code);
3209                         }
3210                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3211                         break;
3212                 case OP_FBGT:
3213                 case OP_FBGT_UN:
3214                         if (cfg->opt & MONO_OPT_FCMOV) {
3215                                 EMIT_COND_BRANCH (ins, X86_CC_LT, FALSE);
3216                                 break;
3217                         }
3218                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3219                         if (ins->opcode == OP_FBGT_UN) {
3220                                 guchar *is_not_zero_check, *end_jump;
3221                                 is_not_zero_check = code;
3222                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3223                                 end_jump = code;
3224                                 x86_jump8 (code, 0);
3225                                 x86_patch (is_not_zero_check, code);
3226                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3227
3228                                 x86_patch (end_jump, code);
3229                         }
3230                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3231                         break;
3232                 case OP_FBGE:
3233                         /* Branch if C013 == 100 or 001 */
3234                         if (cfg->opt & MONO_OPT_FCMOV) {
3235                                 guchar *br1;
3236
3237                                 /* skip branch if C1=1 */
3238                                 br1 = code;
3239                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
3240                                 /* branch if (C0 | C3) = 1 */
3241                                 EMIT_COND_BRANCH (ins, X86_CC_BE, FALSE);
3242                                 x86_patch (br1, code);
3243                                 break;
3244                         }
3245                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3246                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3247                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C3);
3248                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3249                         break;
3250                 case OP_FBGE_UN:
3251                         /* Branch if C013 == 000 */
3252                         if (cfg->opt & MONO_OPT_FCMOV) {
3253                                 EMIT_COND_BRANCH (ins, X86_CC_LE, FALSE);
3254                                 break;
3255                         }
3256                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3257                         break;
3258                 case OP_FBLE:
3259                         /* Branch if C013=000 or 100 */
3260                         if (cfg->opt & MONO_OPT_FCMOV) {
3261                                 guchar *br1;
3262
3263                                 /* skip branch if C1=1 */
3264                                 br1 = code;
3265                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
3266                                 /* branch if C0=0 */
3267                                 EMIT_COND_BRANCH (ins, X86_CC_NB, FALSE);
3268                                 x86_patch (br1, code);
3269                                 break;
3270                         }
3271                         x86_alu_reg_imm (code, X86_AND, X86_EAX, (X86_FP_C0|X86_FP_C1));
3272                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0);
3273                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3274                         break;
3275                 case OP_FBLE_UN:
3276                         /* Branch if C013 != 001 */
3277                         if (cfg->opt & MONO_OPT_FCMOV) {
3278                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
3279                                 EMIT_COND_BRANCH (ins, X86_CC_GE, FALSE);
3280                                 break;
3281                         }
3282                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3283                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3284                         break;
3285                 case CEE_CKFINITE: {
3286                         x86_push_reg (code, X86_EAX);
3287                         x86_fxam (code);
3288                         x86_fnstsw (code);
3289                         x86_alu_reg_imm (code, X86_AND, X86_EAX, 0x4100);
3290                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3291                         x86_pop_reg (code, X86_EAX);
3292                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "ArithmeticException");
3293                         break;
3294                 }
3295                 default:
3296                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3297                         g_assert_not_reached ();
3298                 }
3299
3300                 if ((code - cfg->native_code - offset) > max_len) {
3301                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3302                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3303                         g_assert_not_reached ();
3304                 }
3305                
3306                 cpos += max_len;
3307
3308                 last_ins = ins;
3309                 last_offset = offset;
3310                 
3311                 ins = ins->next;
3312         }
3313
3314         cfg->code_len = code - cfg->native_code;
3315 }
3316
3317 void
3318 mono_arch_register_lowlevel_calls (void)
3319 {
3320 }
3321
3322 void
3323 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3324 {
3325         MonoJumpInfo *patch_info;
3326
3327         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3328                 unsigned char *ip = patch_info->ip.i + code;
3329                 const unsigned char *target;
3330
3331                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3332
3333                 switch (patch_info->type) {
3334                 case MONO_PATCH_INFO_IP:
3335                         *((gconstpointer *)(ip)) = target;
3336                         continue;
3337                 case MONO_PATCH_INFO_METHOD_REL:
3338                         *((gconstpointer *)(ip)) = target;
3339                         continue;
3340                 case MONO_PATCH_INFO_SWITCH: {
3341                         *((gconstpointer *)(ip + 2)) = target;
3342                         /* we put into the table the absolute address, no need for x86_patch in this case */
3343                         continue;
3344                 }
3345                 case MONO_PATCH_INFO_IID:
3346                         *((guint32 *)(ip + 1)) = (guint32)target;
3347                         continue;                       
3348                 case MONO_PATCH_INFO_CLASS_INIT: {
3349                         guint8 *code = ip;
3350                         /* Might already been changed to a nop */
3351                         x86_call_imm (code, 0);
3352                         break;
3353                 }
3354                 case MONO_PATCH_INFO_R4:
3355                 case MONO_PATCH_INFO_R8:
3356                         *((gconstpointer *)(ip + 2)) = target;
3357                         continue;
3358                 case MONO_PATCH_INFO_METHODCONST:
3359                 case MONO_PATCH_INFO_CLASS:
3360                 case MONO_PATCH_INFO_IMAGE:
3361                 case MONO_PATCH_INFO_FIELD:
3362                 case MONO_PATCH_INFO_VTABLE:
3363                 case MONO_PATCH_INFO_SFLDA:
3364                 case MONO_PATCH_INFO_EXC_NAME:
3365                 case MONO_PATCH_INFO_LDSTR:
3366                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3367                 case MONO_PATCH_INFO_LDTOKEN:
3368                         *((gconstpointer *)(ip + 1)) = target;
3369                         continue;
3370                 default:
3371                         break;
3372                 }
3373                 x86_patch (ip, target);
3374         }
3375 }
3376
3377 int
3378 mono_arch_max_epilog_size (MonoCompile *cfg)
3379 {
3380         int exc_count = 0, max_epilog_size = 16;
3381         MonoJumpInfo *patch_info;
3382         
3383         if (cfg->method->save_lmf)
3384                 max_epilog_size += 128;
3385         
3386         if (mono_jit_trace_calls != NULL)
3387                 max_epilog_size += 50;
3388
3389         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3390                 max_epilog_size += 50;
3391
3392         /* count the number of exception infos */
3393      
3394         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3395                 if (patch_info->type == MONO_PATCH_INFO_EXC)
3396                         exc_count++;
3397         }
3398
3399         /* 
3400          * make sure we have enough space for exceptions
3401          * 16 is the size of two push_imm instructions and a call
3402          */
3403         max_epilog_size += exc_count*16;
3404
3405         return max_epilog_size;
3406 }
3407
3408 guint8 *
3409 mono_arch_emit_prolog (MonoCompile *cfg)
3410 {
3411         MonoMethod *method = cfg->method;
3412         MonoBasicBlock *bb;
3413         MonoMethodSignature *sig;
3414         MonoInst *inst;
3415         int alloc_size, pos, max_offset, i;
3416         guint8 *code;
3417
3418         cfg->code_size =  MAX (((MonoMethodNormal *)method)->header->code_size * 4, 256);
3419         code = cfg->native_code = g_malloc (cfg->code_size);
3420
3421         x86_push_reg (code, X86_EBP);
3422         x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
3423
3424         alloc_size = - cfg->stack_offset;
3425         pos = 0;
3426
3427         if (method->save_lmf) {
3428                 pos += sizeof (MonoLMF);
3429
3430                 /* save the current IP */
3431                 mono_add_patch_info (cfg, code + 1 - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3432                 x86_push_imm (code, 0);
3433
3434                 /* save all caller saved regs */
3435                 x86_push_reg (code, X86_EBP);
3436                 x86_push_reg (code, X86_ESI);
3437                 x86_push_reg (code, X86_EDI);
3438                 x86_push_reg (code, X86_EBX);
3439
3440                 /* save method info */
3441                 x86_push_imm (code, method);
3442
3443                 /* get the address of lmf for the current thread */
3444                 /* 
3445                  * This is performance critical so we try to use some tricks to make
3446                  * it fast.
3447                  */
3448                 if (lmf_tls_offset != -1) {
3449                         /* Load lmf quicky using the GS register */
3450                         x86_prefix (code, X86_GS_PREFIX);
3451                         x86_mov_reg_mem (code, X86_EAX, 0, 4);
3452                         x86_mov_reg_membase (code, X86_EAX, X86_EAX, lmf_tls_offset, 4);
3453                 }
3454                 else {
3455                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3456                                                                  (gpointer)"mono_get_lmf_addr");
3457                         x86_call_code (code, 0);
3458                 }
3459
3460                 /* push lmf */
3461                 x86_push_reg (code, X86_EAX); 
3462                 /* push *lfm (previous_lmf) */
3463                 x86_push_membase (code, X86_EAX, 0);
3464                 /* *(lmf) = ESP */
3465                 x86_mov_membase_reg (code, X86_EAX, 0, X86_ESP, 4);
3466         } else {
3467
3468                 if (cfg->used_int_regs & (1 << X86_EBX)) {
3469                         x86_push_reg (code, X86_EBX);
3470                         pos += 4;
3471                 }
3472
3473                 if (cfg->used_int_regs & (1 << X86_EDI)) {
3474                         x86_push_reg (code, X86_EDI);
3475                         pos += 4;
3476                 }
3477
3478                 if (cfg->used_int_regs & (1 << X86_ESI)) {
3479                         x86_push_reg (code, X86_ESI);
3480                         pos += 4;
3481                 }
3482         }
3483
3484         alloc_size -= pos;
3485
3486         if (alloc_size) {
3487                 /* See mono_emit_stack_alloc */
3488 #ifdef PLATFORM_WIN32
3489                 guint32 remaining_size = alloc_size;
3490                 while (remaining_size >= 0x1000) {
3491                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x1000);
3492                         x86_test_membase_reg (code, X86_ESP, 0, X86_ESP);
3493                         remaining_size -= 0x1000;
3494                 }
3495                 if (remaining_size)
3496                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, remaining_size);
3497 #else
3498                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, alloc_size);
3499 #endif
3500         }
3501
3502         /* compute max_offset in order to use short forward jumps */
3503         max_offset = 0;
3504         if (cfg->opt & MONO_OPT_BRANCH) {
3505                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3506                         MonoInst *ins = bb->code;
3507                         bb->max_offset = max_offset;
3508
3509                         if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3510                                 max_offset += 6;
3511                         /* max alignment for loops */
3512                         if ((cfg->opt & MONO_OPT_LOOP) && bb_is_loop_start (bb))
3513                                 max_offset += LOOP_ALIGNMENT;
3514
3515                         while (ins) {
3516                                 if (ins->opcode == OP_LABEL)
3517                                         ins->inst_c1 = max_offset;
3518                                 
3519                                 max_offset += ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
3520                                 ins = ins->next;
3521                         }
3522                 }
3523         }
3524
3525         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3526                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3527
3528         /* load arguments allocated to register from the stack */
3529         sig = method->signature;
3530         pos = 0;
3531
3532         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3533                 inst = cfg->varinfo [pos];
3534                 if (inst->opcode == OP_REGVAR) {
3535                         x86_mov_reg_membase (code, inst->dreg, X86_EBP, inst->inst_offset, 4);
3536                         if (cfg->verbose_level > 2)
3537                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3538                 }
3539                 pos++;
3540         }
3541
3542         cfg->code_len = code - cfg->native_code;
3543
3544         return code;
3545 }
3546
3547 void
3548 mono_arch_emit_epilog (MonoCompile *cfg)
3549 {
3550         MonoJumpInfo *patch_info;
3551         MonoMethod *method = cfg->method;
3552         MonoMethodSignature *sig = method->signature;
3553         int pos;
3554         guint32 stack_to_pop;
3555         guint8 *code;
3556
3557         code = cfg->native_code + cfg->code_len;
3558
3559         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3560                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3561
3562         /* the code restoring the registers must be kept in sync with CEE_JMP */
3563         pos = 0;
3564         
3565         if (method->save_lmf) {
3566                 gint32 prev_lmf_reg;
3567
3568                 /* Find a spare register */
3569                 switch (sig->ret->type) {
3570                 case MONO_TYPE_I8:
3571                 case MONO_TYPE_U8:
3572                         prev_lmf_reg = X86_EDI;
3573                         cfg->used_int_regs |= (1 << X86_EDI);
3574                         break;
3575                 default:
3576                         prev_lmf_reg = X86_EDX;
3577                         break;
3578                 }
3579
3580                 /* reg = previous_lmf */
3581                 x86_mov_reg_membase (code, prev_lmf_reg, X86_EBP, -32, 4);
3582
3583                 /* ecx = lmf */
3584                 x86_mov_reg_membase (code, X86_ECX, X86_EBP, -28, 4);
3585
3586                 /* *(lmf) = previous_lmf */
3587                 x86_mov_membase_reg (code, X86_ECX, 0, prev_lmf_reg, 4);
3588
3589                 /* restore caller saved regs */
3590                 if (cfg->used_int_regs & (1 << X86_EBX)) {
3591                         x86_mov_reg_membase (code, X86_EBX, X86_EBP, -20, 4);
3592                 }
3593
3594                 if (cfg->used_int_regs & (1 << X86_EDI)) {
3595                         x86_mov_reg_membase (code, X86_EDI, X86_EBP, -16, 4);
3596                 }
3597                 if (cfg->used_int_regs & (1 << X86_ESI)) {
3598                         x86_mov_reg_membase (code, X86_ESI, X86_EBP, -12, 4);
3599                 }
3600
3601                 /* EBP is restored by LEAVE */
3602         } else {
3603                 if (cfg->used_int_regs & (1 << X86_EBX)) {
3604                         pos -= 4;
3605                 }
3606                 if (cfg->used_int_regs & (1 << X86_EDI)) {
3607                         pos -= 4;
3608                 }
3609                 if (cfg->used_int_regs & (1 << X86_ESI)) {
3610                         pos -= 4;
3611                 }
3612
3613                 if (pos)
3614                         x86_lea_membase (code, X86_ESP, X86_EBP, pos);
3615
3616                 if (cfg->used_int_regs & (1 << X86_ESI)) {
3617                         x86_pop_reg (code, X86_ESI);
3618                 }
3619                 if (cfg->used_int_regs & (1 << X86_EDI)) {
3620                         x86_pop_reg (code, X86_EDI);
3621                 }
3622                 if (cfg->used_int_regs & (1 << X86_EBX)) {
3623                         x86_pop_reg (code, X86_EBX);
3624                 }
3625         }
3626
3627         x86_leave (code);
3628
3629         if (CALLCONV_IS_STDCALL (sig->call_convention)) {
3630                 MonoJitArgumentInfo *arg_info = alloca (sizeof (MonoJitArgumentInfo) * (sig->param_count + 1));
3631
3632                 stack_to_pop = mono_arch_get_argument_info (sig, sig->param_count, arg_info);
3633         } else if (MONO_TYPE_ISSTRUCT (cfg->method->signature->ret))
3634                 stack_to_pop = 4;
3635         else
3636                 stack_to_pop = 0;
3637
3638         if (stack_to_pop)
3639                 x86_ret_imm (code, stack_to_pop);
3640         else
3641                 x86_ret (code);
3642
3643         /* add code to raise exceptions */
3644         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3645                 switch (patch_info->type) {
3646                 case MONO_PATCH_INFO_EXC:
3647                         x86_patch (patch_info->ip.i + cfg->native_code, code);
3648                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);
3649                         x86_push_imm (code, patch_info->data.target);
3650                         mono_add_patch_info (cfg, code + 1 - cfg->native_code, MONO_PATCH_INFO_METHOD_REL, (gpointer)patch_info->ip.i);
3651                         x86_push_imm (code, patch_info->ip.i + cfg->native_code);
3652                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3653                         patch_info->data.name = "mono_arch_throw_exception_by_name";
3654                         patch_info->ip.i = code - cfg->native_code;
3655                         x86_jump_code (code, 0);
3656                         break;
3657                 default:
3658                         /* do nothing */
3659                         break;
3660                 }
3661         }
3662
3663         cfg->code_len = code - cfg->native_code;
3664
3665         g_assert (cfg->code_len < cfg->code_size);
3666
3667 }
3668
3669 void
3670 mono_arch_flush_icache (guint8 *code, gint size)
3671 {
3672         /* not needed */
3673 }
3674
3675 void
3676 mono_arch_flush_register_windows (void)
3677 {
3678 }
3679
3680 /*
3681  * Support for fast access to the thread-local lmf structure using the GS
3682  * segment register on NPTL + kernel 2.6.x.
3683  */
3684
3685 static gboolean tls_offset_inited = FALSE;
3686
3687 void
3688 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3689 {
3690 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3691         pthread_t self = pthread_self();
3692         pthread_attr_t attr;
3693         void *staddr = NULL;
3694         size_t stsize = 0;
3695         struct sigaltstack sa;
3696 #endif
3697
3698         if (!tls_offset_inited) {
3699                 guint8 *code;
3700
3701                 tls_offset_inited = TRUE;
3702
3703                 code = (guint8*)mono_get_lmf_addr;
3704
3705                 if (getenv ("MONO_NPTL")) {
3706                         /* 
3707                          * Determine the offset of mono_lfm_addr inside the TLS structures
3708                          * by disassembling the function above.
3709                          */
3710
3711                         /* This is generated by gcc 3.3.2 */
3712                         if ((code [0] == 0x55) && (code [1] == 0x89) && (code [2] == 0xe5) &&
3713                                 (code [3] == 0x65) && (code [4] == 0xa1) && (code [5] == 0x00) &&
3714                                 (code [6] == 0x00) && (code [7] == 0x00) && (code [8] == 0x00) &&
3715                                 (code [9] == 0x8b) && (code [10] == 0x80)) {
3716                                 lmf_tls_offset = *(int*)&(code [11]);
3717                         }
3718                         else
3719                                 /* This is generated by gcc-3.4 */
3720                                 if ((code [0] == 0x55) && (code [1] == 0x89) && (code [2] == 0xe5) &&
3721                                         (code [3] == 0x65) && (code [4] == 0xa1)) {
3722                                         lmf_tls_offset = *(int*)&(code [5]);
3723                                 }
3724                 }
3725         }               
3726
3727 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3728
3729         /* Determine stack boundaries */
3730         if (!mono_running_on_valgrind ()) {
3731 #ifdef HAVE_PTHREAD_GETATTR_NP
3732                 pthread_getattr_np( self, &attr );
3733 #else
3734 #ifdef HAVE_PTHREAD_ATTR_GET_NP
3735                 pthread_attr_get_np( self, &attr );
3736 #elif defined(sun)
3737                 pthread_attr_init( &attr );
3738                 pthread_attr_getstacksize( &attr, &stsize );
3739 #else
3740 #error "Not implemented"
3741 #endif
3742 #endif
3743 #ifndef sun
3744                 pthread_attr_getstack( &attr, &staddr, &stsize );
3745 #endif
3746         }
3747
3748         /* 
3749          * staddr seems to be wrong for the main thread, so we keep the value in
3750          * tls->end_of_stack
3751          */
3752         tls->stack_size = stsize;
3753
3754         /* Setup an alternate signal stack */
3755         tls->signal_stack = g_malloc (SIGNAL_STACK_SIZE);
3756         tls->signal_stack_size = SIGNAL_STACK_SIZE;
3757
3758         sa.ss_sp = tls->signal_stack;
3759         sa.ss_size = SIGNAL_STACK_SIZE;
3760         sa.ss_flags = SS_ONSTACK;
3761         sigaltstack (&sa, NULL);
3762 #endif
3763 }
3764
3765 void
3766 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3767 {
3768 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3769         struct sigaltstack sa;
3770
3771         sa.ss_sp = tls->signal_stack;
3772         sa.ss_size = SIGNAL_STACK_SIZE;
3773         sa.ss_flags = SS_DISABLE;
3774         sigaltstack  (&sa, NULL);
3775
3776         if (tls->signal_stack)
3777                 g_free (tls->signal_stack);
3778 #endif
3779 }
3780
3781 void
3782 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3783 {
3784
3785         /* add the this argument */
3786         if (this_reg != -1) {
3787                 MonoInst *this;
3788                 MONO_INST_NEW (cfg, this, OP_OUTARG);
3789                 this->type = this_type;
3790                 this->sreg1 = this_reg;
3791                 mono_bblock_add_inst (cfg->cbb, this);
3792         }
3793
3794         if (vt_reg != -1) {
3795                 MonoInst *vtarg;
3796                 MONO_INST_NEW (cfg, vtarg, OP_OUTARG);
3797                 vtarg->type = STACK_MP;
3798                 vtarg->sreg1 = vt_reg;
3799                 mono_bblock_add_inst (cfg->cbb, vtarg);
3800         }
3801 }
3802
3803
3804 gint
3805 mono_arch_get_opcode_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3806 {
3807         if (cmethod->klass == mono_defaults.math_class) {
3808                 if (strcmp (cmethod->name, "Sin") == 0)
3809                         return OP_SIN;
3810                 else if (strcmp (cmethod->name, "Cos") == 0)
3811                         return OP_COS;
3812                 else if (strcmp (cmethod->name, "Tan") == 0)
3813                         return OP_TAN;
3814                 else if (strcmp (cmethod->name, "Atan") == 0)
3815                         return OP_ATAN;
3816                 else if (strcmp (cmethod->name, "Sqrt") == 0)
3817                         return OP_SQRT;
3818                 else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8)
3819                         return OP_ABS;
3820 #if 0
3821                 /* OP_FREM is not IEEE compatible */
3822                 else if (strcmp (cmethod->name, "IEEERemainder") == 0)
3823                         return OP_FREM;
3824 #endif
3825                 else
3826                         return -1;
3827         } else {
3828                 return -1;
3829         }
3830         return -1;
3831 }
3832
3833
3834 gboolean
3835 mono_arch_print_tree (MonoInst *tree, int arity)
3836 {
3837         return 0;
3838 }