2004-11-03 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mono / mini / mini-x86.c
1 /*
2  * mini-x86.c: x86 backend for the Mono code generator
3  *
4  * Authors:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *   Patrik Torstensson
8  *
9  * (C) 2003 Ximian, Inc.
10  */
11 #include "mini.h"
12 #include <string.h>
13 #include <math.h>
14
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                         rs->isymbolic [ins->dreg] = ins->sreg1;
1870                         rs->isymbolic [ins->unused] = ins->sreg1 + 1;
1871
1872                         DEBUG (g_print ("\tassigned sreg1 (long) %s to sreg1 R%d\n", mono_arch_regname (ins->dreg), ins->sreg1));
1873                         DEBUG (g_print ("\tassigned sreg1 (long-high) %s to sreg1 R%d\n", mono_arch_regname (ins->unused), ins->sreg1 + 1));
1874
1875                         ins->sreg1 = ins->dreg;
1876                         /* 
1877                          * No need for saving the reg, we know that src1=dest in this cases
1878                          * ins->inst_c0 = ins->unused;
1879                          */
1880
1881                         /* make sure that we remove them from free mask */
1882                         rs->ifree_mask &= ~ (1 << ins->dreg);
1883                         rs->ifree_mask &= ~ (1 << ins->unused);
1884                 }
1885                 else if (ins->sreg1 >= MONO_MAX_IREGS) {
1886                         val = rs->iassign [ins->sreg1];
1887                         prev_sreg1 = ins->sreg1;
1888                         if (val < 0) {
1889                                 int spill = 0;
1890                                 if (val < -1) {
1891                                         /* the register gets spilled after this inst */
1892                                         spill = -val -1;
1893                                 }
1894                                 if (0 && ins->opcode == OP_MOVE) {
1895                                         /* 
1896                                          * small optimization: the dest register is already allocated
1897                                          * but the src one is not: we can simply assign the same register
1898                                          * here and peephole will get rid of the instruction later.
1899                                          * This optimization may interfere with the clobbering handling:
1900                                          * it removes a mov operation that will be added again to handle clobbering.
1901                                          * There are also some other issues that should with make testjit.
1902                                          */
1903                                         mono_regstate_alloc_int (rs, 1 << ins->dreg);
1904                                         val = rs->iassign [ins->sreg1] = ins->dreg;
1905                                         //g_assert (val >= 0);
1906                                         DEBUG (g_print ("\tfast assigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1));
1907                                 } else {
1908                                         //g_assert (val == -1); /* source cannot be spilled */
1909                                         val = mono_x86_alloc_int_reg (cfg, tmp, ins, src1_mask, ins->sreg1, reginfo [ins->sreg1].flags);
1910                                         rs->iassign [ins->sreg1] = val;
1911                                         DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1));
1912                                 }
1913                                 if (spill) {
1914                                         MonoInst *store = create_spilled_store (cfg, spill, val, prev_sreg1, NULL);
1915                                         insert_before_ins (ins, tmp, store);
1916                                 }
1917                         }
1918                         rs->isymbolic [val] = prev_sreg1;
1919                         ins->sreg1 = val;
1920                 } else {
1921                         prev_sreg1 = -1;
1922                 }
1923                 /* handle clobbering of sreg1 */
1924                 if ((spec [MONO_INST_CLOB] == '1' || spec [MONO_INST_CLOB] == 's') && ins->dreg != ins->sreg1) {
1925                         MonoInst *copy = create_copy_ins (cfg, ins->dreg, ins->sreg1, NULL);
1926                         DEBUG (g_print ("\tneed to copy sreg1 %s to dreg %s\n", mono_arch_regname (ins->sreg1), mono_arch_regname (ins->dreg)));
1927                         if (ins->sreg2 == -1 || spec [MONO_INST_CLOB] == 's') {
1928                                 /* note: the copy is inserted before the current instruction! */
1929                                 insert_before_ins (ins, tmp, copy);
1930                                 /* we set sreg1 to dest as well */
1931                                 prev_sreg1 = ins->sreg1 = ins->dreg;
1932                         } else {
1933                                 /* inserted after the operation */
1934                                 copy->next = ins->next;
1935                                 ins->next = copy;
1936                         }
1937                 }
1938                 /* track sreg2 */
1939                 if (spec [MONO_INST_SRC2] == 'f') {
1940                         if (reginfof [ins->sreg2].flags & MONO_X86_FP_NEEDS_LOAD) {
1941                                 MonoInst *load;
1942                                 MonoInst *store = NULL;
1943
1944                                 if (reginfof [ins->sreg2].flags & MONO_X86_FP_NEEDS_LOAD_SPILL) {
1945                                         GList *spill_node;
1946
1947                                         spill_node = g_list_first (fspill_list);
1948                                         g_assert (spill_node);
1949                                         if (spec [MONO_INST_SRC1] == 'f' && (reginfof [ins->sreg1].flags & MONO_X86_FP_NEEDS_LOAD_SPILL))
1950                                                 spill_node = g_list_next (spill_node);
1951         
1952                                         store = create_spilled_store_float (cfg, GPOINTER_TO_INT (spill_node->data), ins->sreg2, ins);
1953                                         fspill_list = g_list_remove (fspill_list, spill_node->data);
1954                                 } 
1955                                 
1956                                 fspill++;
1957                                 fspill_list = g_list_prepend (fspill_list, GINT_TO_POINTER(fspill));
1958                                 load = create_spilled_load_float (cfg, fspill, ins->sreg2, ins);
1959                                 insert_before_ins (ins, tmp, load);
1960                                 if (store) 
1961                                         insert_before_ins (load, tmp, store);
1962                         }
1963                 } 
1964                 else if (ins->sreg2 >= MONO_MAX_IREGS) {
1965                         val = rs->iassign [ins->sreg2];
1966                         prev_sreg2 = ins->sreg2;
1967                         if (val < 0) {
1968                                 int spill = 0;
1969                                 if (val < -1) {
1970                                         /* the register gets spilled after this inst */
1971                                         spill = -val -1;
1972                                 }
1973                                 val = mono_x86_alloc_int_reg (cfg, tmp, ins, src2_mask, ins->sreg2, reginfo [ins->sreg2].flags);
1974                                 rs->iassign [ins->sreg2] = val;
1975                                 DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val), ins->sreg2));
1976                                 if (spill)
1977                                         create_spilled_store (cfg, spill, val, prev_sreg2, ins);
1978                         }
1979                         rs->isymbolic [val] = prev_sreg2;
1980                         ins->sreg2 = val;
1981                         if (spec [MONO_INST_CLOB] == 's' && ins->sreg2 != X86_ECX) {
1982                                 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]));
1983                         }
1984                 } else {
1985                         prev_sreg2 = -1;
1986                 }
1987
1988                 if (spec [MONO_INST_CLOB] == 'c') {
1989                         int j, s;
1990                         guint32 clob_mask = X86_CALLEE_REGS;
1991                         for (j = 0; j < MONO_MAX_IREGS; ++j) {
1992                                 s = 1 << j;
1993                                 if ((clob_mask & s) && !(rs->ifree_mask & s) && j != ins->sreg1) {
1994                                         //g_warning ("register %s busy at call site\n", mono_arch_regname (j));
1995                                 }
1996                         }
1997                 }
1998                 /*if (reg_is_freeable (ins->sreg1) && prev_sreg1 >= 0 && reginfo [prev_sreg1].born_in >= i) {
1999                         DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg1)));
2000                         mono_regstate_free_int (rs, ins->sreg1);
2001                 }
2002                 if (reg_is_freeable (ins->sreg2) && prev_sreg2 >= 0 && reginfo [prev_sreg2].born_in >= i) {
2003                         DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg2)));
2004                         mono_regstate_free_int (rs, ins->sreg2);
2005                 }*/
2006         
2007                 //DEBUG (print_ins (i, ins));
2008                 /* this may result from a insert_before call */
2009                 if (!tmp->next)
2010                         bb->code = tmp->data;
2011                 tmp = tmp->next;
2012         }
2013
2014         g_free (reginfo);
2015         g_free (reginfof);
2016         g_list_free (fspill_list);
2017 }
2018
2019 static unsigned char*
2020 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int size, gboolean is_signed)
2021 {
2022         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 4);
2023         x86_fnstcw_membase(code, X86_ESP, 0);
2024         x86_mov_reg_membase (code, dreg, X86_ESP, 0, 2);
2025         x86_alu_reg_imm (code, X86_OR, dreg, 0xc00);
2026         x86_mov_membase_reg (code, X86_ESP, 2, dreg, 2);
2027         x86_fldcw_membase (code, X86_ESP, 2);
2028         if (size == 8) {
2029                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
2030                 x86_fist_pop_membase (code, X86_ESP, 0, TRUE);
2031                 x86_pop_reg (code, dreg);
2032                 /* FIXME: need the high register 
2033                  * x86_pop_reg (code, dreg_high);
2034                  */
2035         } else {
2036                 x86_push_reg (code, X86_EAX); // SP = SP - 4
2037                 x86_fist_pop_membase (code, X86_ESP, 0, FALSE);
2038                 x86_pop_reg (code, dreg);
2039         }
2040         x86_fldcw_membase (code, X86_ESP, 0);
2041         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
2042
2043         if (size == 1)
2044                 x86_widen_reg (code, dreg, dreg, is_signed, FALSE);
2045         else if (size == 2)
2046                 x86_widen_reg (code, dreg, dreg, is_signed, TRUE);
2047         return code;
2048 }
2049
2050 static unsigned char*
2051 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
2052 {
2053         int sreg = tree->sreg1;
2054 #ifdef PLATFORM_WIN32
2055         guint8* br[5];
2056
2057         /*
2058          * Under Windows:
2059          * If requested stack size is larger than one page,
2060          * perform stack-touch operation
2061          */
2062         /*
2063          * Generate stack probe code.
2064          * Under Windows, it is necessary to allocate one page at a time,
2065          * "touching" stack after each successful sub-allocation. This is
2066          * because of the way stack growth is implemented - there is a
2067          * guard page before the lowest stack page that is currently commited.
2068          * Stack normally grows sequentially so OS traps access to the
2069          * guard page and commits more pages when needed.
2070          */
2071         x86_test_reg_imm (code, sreg, ~0xFFF);
2072         br[0] = code; x86_branch8 (code, X86_CC_Z, 0, FALSE);
2073
2074         br[2] = code; /* loop */
2075         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x1000);
2076         x86_test_membase_reg (code, X86_ESP, 0, X86_ESP);
2077         x86_alu_reg_imm (code, X86_SUB, sreg, 0x1000);
2078         x86_alu_reg_imm (code, X86_CMP, sreg, 0x1000);
2079         br[3] = code; x86_branch8 (code, X86_CC_AE, 0, FALSE);
2080         x86_patch (br[3], br[2]);
2081         x86_test_reg_reg (code, sreg, sreg);
2082         br[4] = code; x86_branch8 (code, X86_CC_Z, 0, FALSE);
2083         x86_alu_reg_reg (code, X86_SUB, X86_ESP, sreg);
2084
2085         br[1] = code; x86_jump8 (code, 0);
2086
2087         x86_patch (br[0], code);
2088         x86_alu_reg_reg (code, X86_SUB, X86_ESP, sreg);
2089         x86_patch (br[1], code);
2090         x86_patch (br[4], code);
2091 #else /* PLATFORM_WIN32 */
2092         x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
2093 #endif
2094         if (tree->flags & MONO_INST_INIT) {
2095                 int offset = 0;
2096                 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
2097                         x86_push_reg (code, X86_EAX);
2098                         offset += 4;
2099                 }
2100                 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
2101                         x86_push_reg (code, X86_ECX);
2102                         offset += 4;
2103                 }
2104                 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
2105                         x86_push_reg (code, X86_EDI);
2106                         offset += 4;
2107                 }
2108                 
2109                 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
2110                 if (sreg != X86_ECX)
2111                         x86_mov_reg_reg (code, X86_ECX, sreg, 4);
2112                 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
2113                                 
2114                 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
2115                 x86_cld (code);
2116                 x86_prefix (code, X86_REP_PREFIX);
2117                 x86_stosl (code);
2118                 
2119                 if (tree->dreg != X86_EDI && sreg != X86_EDI)
2120                         x86_pop_reg (code, X86_EDI);
2121                 if (tree->dreg != X86_ECX && sreg != X86_ECX)
2122                         x86_pop_reg (code, X86_ECX);
2123                 if (tree->dreg != X86_EAX && sreg != X86_EAX)
2124                         x86_pop_reg (code, X86_EAX);
2125         }
2126         return code;
2127 }
2128
2129 #define REAL_PRINT_REG(text,reg) \
2130 mono_assert (reg >= 0); \
2131 x86_push_reg (code, X86_EAX); \
2132 x86_push_reg (code, X86_EDX); \
2133 x86_push_reg (code, X86_ECX); \
2134 x86_push_reg (code, reg); \
2135 x86_push_imm (code, reg); \
2136 x86_push_imm (code, text " %d %p\n"); \
2137 x86_mov_reg_imm (code, X86_EAX, printf); \
2138 x86_call_reg (code, X86_EAX); \
2139 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 3*4); \
2140 x86_pop_reg (code, X86_ECX); \
2141 x86_pop_reg (code, X86_EDX); \
2142 x86_pop_reg (code, X86_EAX);
2143
2144 /* benchmark and set based on cpu */
2145 #define LOOP_ALIGNMENT 8
2146 #define bb_is_loop_start(bb) ((bb)->nesting && ((bb)->in_count == 1))
2147
2148 void
2149 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2150 {
2151         MonoInst *ins;
2152         MonoCallInst *call;
2153         guint offset;
2154         guint8 *code = cfg->native_code + cfg->code_len;
2155         MonoInst *last_ins = NULL;
2156         guint last_offset = 0;
2157         int max_len, cpos;
2158
2159         if (cfg->opt & MONO_OPT_PEEPHOLE)
2160                 peephole_pass (cfg, bb);
2161
2162         if (cfg->opt & MONO_OPT_LOOP) {
2163                 int pad, align = LOOP_ALIGNMENT;
2164                 /* set alignment depending on cpu */
2165                 if (bb_is_loop_start (bb) && (pad = (cfg->code_len & (align - 1)))) {
2166                         pad = align - pad;
2167                         /*g_print ("adding %d pad at %x to loop in %s\n", pad, cfg->code_len, cfg->method->name);*/
2168                         x86_padding (code, pad);
2169                         cfg->code_len += pad;
2170                         bb->native_offset = cfg->code_len;
2171                 }
2172         }
2173
2174         if (cfg->verbose_level > 2)
2175                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2176
2177         cpos = bb->max_offset;
2178
2179         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2180                 MonoProfileCoverageInfo *cov = cfg->coverage_info;
2181                 g_assert (!mono_compile_aot);
2182                 cpos += 6;
2183
2184                 cov->data [bb->dfn].cil_code = bb->cil_code;
2185                 /* this is not thread save, but good enough */
2186                 x86_inc_mem (code, &cov->data [bb->dfn].count); 
2187         }
2188
2189         offset = code - cfg->native_code;
2190
2191         ins = bb->code;
2192         while (ins) {
2193                 offset = code - cfg->native_code;
2194
2195                 max_len = ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
2196
2197                 if (offset > (cfg->code_size - max_len - 16)) {
2198                         cfg->code_size *= 2;
2199                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2200                         code = cfg->native_code + offset;
2201                         mono_jit_stats.code_reallocs++;
2202                 }
2203
2204                 mono_debug_record_line_number (cfg, ins, offset);
2205
2206                 switch (ins->opcode) {
2207                 case OP_BIGMUL:
2208                         x86_mul_reg (code, ins->sreg2, TRUE);
2209                         break;
2210                 case OP_BIGMUL_UN:
2211                         x86_mul_reg (code, ins->sreg2, FALSE);
2212                         break;
2213                 case OP_X86_SETEQ_MEMBASE:
2214                         x86_set_membase (code, X86_CC_EQ, ins->inst_basereg, ins->inst_offset, TRUE);
2215                         break;
2216                 case OP_STOREI1_MEMBASE_IMM:
2217                         x86_mov_membase_imm (code, ins->inst_destbasereg, ins->inst_offset, ins->inst_imm, 1);
2218                         break;
2219                 case OP_STOREI2_MEMBASE_IMM:
2220                         x86_mov_membase_imm (code, ins->inst_destbasereg, ins->inst_offset, ins->inst_imm, 2);
2221                         break;
2222                 case OP_STORE_MEMBASE_IMM:
2223                 case OP_STOREI4_MEMBASE_IMM:
2224                         x86_mov_membase_imm (code, ins->inst_destbasereg, ins->inst_offset, ins->inst_imm, 4);
2225                         break;
2226                 case OP_STOREI1_MEMBASE_REG:
2227                         x86_mov_membase_reg (code, ins->inst_destbasereg, ins->inst_offset, ins->sreg1, 1);
2228                         break;
2229                 case OP_STOREI2_MEMBASE_REG:
2230                         x86_mov_membase_reg (code, ins->inst_destbasereg, ins->inst_offset, ins->sreg1, 2);
2231                         break;
2232                 case OP_STORE_MEMBASE_REG:
2233                 case OP_STOREI4_MEMBASE_REG:
2234                         x86_mov_membase_reg (code, ins->inst_destbasereg, ins->inst_offset, ins->sreg1, 4);
2235                         break;
2236                 case CEE_LDIND_I:
2237                 case CEE_LDIND_I4:
2238                 case CEE_LDIND_U4:
2239                         x86_mov_reg_mem (code, ins->dreg, ins->inst_p0, 4);
2240                         break;
2241                 case OP_LOADU4_MEM:
2242                         x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
2243                         x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
2244                         break;
2245                 case OP_LOAD_MEMBASE:
2246                 case OP_LOADI4_MEMBASE:
2247                 case OP_LOADU4_MEMBASE:
2248                         x86_mov_reg_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, 4);
2249                         break;
2250                 case OP_LOADU1_MEMBASE:
2251                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, FALSE, FALSE);
2252                         break;
2253                 case OP_LOADI1_MEMBASE:
2254                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, TRUE, FALSE);
2255                         break;
2256                 case OP_LOADU2_MEMBASE:
2257                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, FALSE, TRUE);
2258                         break;
2259                 case OP_LOADI2_MEMBASE:
2260                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, TRUE, TRUE);
2261                         break;
2262                 case CEE_CONV_I1:
2263                         x86_widen_reg (code, ins->dreg, ins->sreg1, TRUE, FALSE);
2264                         break;
2265                 case CEE_CONV_I2:
2266                         x86_widen_reg (code, ins->dreg, ins->sreg1, TRUE, TRUE);
2267                         break;
2268                 case CEE_CONV_U1:
2269                         x86_widen_reg (code, ins->dreg, ins->sreg1, FALSE, FALSE);
2270                         break;
2271                 case CEE_CONV_U2:
2272                         x86_widen_reg (code, ins->dreg, ins->sreg1, FALSE, TRUE);
2273                         break;
2274                 case OP_COMPARE:
2275                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
2276                         break;
2277                 case OP_COMPARE_IMM:
2278                         x86_alu_reg_imm (code, X86_CMP, ins->sreg1, ins->inst_imm);
2279                         break;
2280                 case OP_X86_COMPARE_MEMBASE_REG:
2281                         x86_alu_membase_reg (code, X86_CMP, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2282                         break;
2283                 case OP_X86_COMPARE_MEMBASE_IMM:
2284                         x86_alu_membase_imm (code, X86_CMP, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2285                         break;
2286                 case OP_X86_COMPARE_REG_MEMBASE:
2287                         x86_alu_reg_membase (code, X86_CMP, ins->sreg1, ins->sreg2, ins->inst_offset);
2288                         break;
2289                 case OP_X86_TEST_NULL:
2290                         x86_test_reg_reg (code, ins->sreg1, ins->sreg1);
2291                         break;
2292                 case OP_X86_ADD_MEMBASE_IMM:
2293                         x86_alu_membase_imm (code, X86_ADD, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2294                         break;
2295                 case OP_X86_ADD_MEMBASE:
2296                         x86_alu_reg_membase (code, X86_ADD, ins->sreg1, ins->sreg2, ins->inst_offset);
2297                         break;
2298                 case OP_X86_SUB_MEMBASE_IMM:
2299                         x86_alu_membase_imm (code, X86_SUB, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2300                         break;
2301                 case OP_X86_SUB_MEMBASE:
2302                         x86_alu_reg_membase (code, X86_SUB, ins->sreg1, ins->sreg2, ins->inst_offset);
2303                         break;
2304                 case OP_X86_INC_MEMBASE:
2305                         x86_inc_membase (code, ins->inst_basereg, ins->inst_offset);
2306                         break;
2307                 case OP_X86_INC_REG:
2308                         x86_inc_reg (code, ins->dreg);
2309                         break;
2310                 case OP_X86_DEC_MEMBASE:
2311                         x86_dec_membase (code, ins->inst_basereg, ins->inst_offset);
2312                         break;
2313                 case OP_X86_DEC_REG:
2314                         x86_dec_reg (code, ins->dreg);
2315                         break;
2316                 case OP_X86_MUL_MEMBASE:
2317                         x86_imul_reg_membase (code, ins->sreg1, ins->sreg2, ins->inst_offset);
2318                         break;
2319                 case CEE_BREAK:
2320                         x86_breakpoint (code);
2321                         break;
2322                 case OP_ADDCC:
2323                 case CEE_ADD:
2324                         x86_alu_reg_reg (code, X86_ADD, ins->sreg1, ins->sreg2);
2325                         break;
2326                 case OP_ADC:
2327                         x86_alu_reg_reg (code, X86_ADC, ins->sreg1, ins->sreg2);
2328                         break;
2329                 case OP_ADDCC_IMM:
2330                 case OP_ADD_IMM:
2331                         x86_alu_reg_imm (code, X86_ADD, ins->dreg, ins->inst_imm);
2332                         break;
2333                 case OP_ADC_IMM:
2334                         x86_alu_reg_imm (code, X86_ADC, ins->dreg, ins->inst_imm);
2335                         break;
2336                 case OP_SUBCC:
2337                 case CEE_SUB:
2338                         x86_alu_reg_reg (code, X86_SUB, ins->sreg1, ins->sreg2);
2339                         break;
2340                 case OP_SBB:
2341                         x86_alu_reg_reg (code, X86_SBB, ins->sreg1, ins->sreg2);
2342                         break;
2343                 case OP_SUBCC_IMM:
2344                 case OP_SUB_IMM:
2345                         x86_alu_reg_imm (code, X86_SUB, ins->dreg, ins->inst_imm);
2346                         break;
2347                 case OP_SBB_IMM:
2348                         x86_alu_reg_imm (code, X86_SBB, ins->dreg, ins->inst_imm);
2349                         break;
2350                 case CEE_AND:
2351                         x86_alu_reg_reg (code, X86_AND, ins->sreg1, ins->sreg2);
2352                         break;
2353                 case OP_AND_IMM:
2354                         x86_alu_reg_imm (code, X86_AND, ins->sreg1, ins->inst_imm);
2355                         break;
2356                 case CEE_DIV:
2357                         x86_cdq (code);
2358                         x86_div_reg (code, ins->sreg2, TRUE);
2359                         break;
2360                 case CEE_DIV_UN:
2361                         x86_alu_reg_reg (code, X86_XOR, X86_EDX, X86_EDX);
2362                         x86_div_reg (code, ins->sreg2, FALSE);
2363                         break;
2364                 case OP_DIV_IMM:
2365                         x86_mov_reg_imm (code, ins->sreg2, ins->inst_imm);
2366                         x86_cdq (code);
2367                         x86_div_reg (code, ins->sreg2, TRUE);
2368                         break;
2369                 case CEE_REM:
2370                         x86_cdq (code);
2371                         x86_div_reg (code, ins->sreg2, TRUE);
2372                         break;
2373                 case CEE_REM_UN:
2374                         x86_alu_reg_reg (code, X86_XOR, X86_EDX, X86_EDX);
2375                         x86_div_reg (code, ins->sreg2, FALSE);
2376                         break;
2377                 case OP_REM_IMM:
2378                         x86_mov_reg_imm (code, ins->sreg2, ins->inst_imm);
2379                         x86_cdq (code);
2380                         x86_div_reg (code, ins->sreg2, TRUE);
2381                         break;
2382                 case CEE_OR:
2383                         x86_alu_reg_reg (code, X86_OR, ins->sreg1, ins->sreg2);
2384                         break;
2385                 case OP_OR_IMM:
2386                         x86_alu_reg_imm (code, X86_OR, ins->sreg1, ins->inst_imm);
2387                         break;
2388                 case CEE_XOR:
2389                         x86_alu_reg_reg (code, X86_XOR, ins->sreg1, ins->sreg2);
2390                         break;
2391                 case OP_XOR_IMM:
2392                         x86_alu_reg_imm (code, X86_XOR, ins->sreg1, ins->inst_imm);
2393                         break;
2394                 case CEE_SHL:
2395                         g_assert (ins->sreg2 == X86_ECX);
2396                         x86_shift_reg (code, X86_SHL, ins->dreg);
2397                         break;
2398                 case CEE_SHR:
2399                         g_assert (ins->sreg2 == X86_ECX);
2400                         x86_shift_reg (code, X86_SAR, ins->dreg);
2401                         break;
2402                 case OP_SHR_IMM:
2403                         x86_shift_reg_imm (code, X86_SAR, ins->dreg, ins->inst_imm);
2404                         break;
2405                 case OP_SHR_UN_IMM:
2406                         x86_shift_reg_imm (code, X86_SHR, ins->dreg, ins->inst_imm);
2407                         break;
2408                 case CEE_SHR_UN:
2409                         g_assert (ins->sreg2 == X86_ECX);
2410                         x86_shift_reg (code, X86_SHR, ins->dreg);
2411                         break;
2412                 case OP_SHL_IMM:
2413                         x86_shift_reg_imm (code, X86_SHL, ins->dreg, ins->inst_imm);
2414                         break;
2415                 case OP_LSHL: {
2416                         guint8 *jump_to_end;
2417
2418                         /* handle shifts below 32 bits */
2419                         x86_shld_reg (code, ins->unused, ins->sreg1);
2420                         x86_shift_reg (code, X86_SHL, ins->sreg1);
2421
2422                         x86_test_reg_imm (code, X86_ECX, 32);
2423                         jump_to_end = code; x86_branch8 (code, X86_CC_EQ, 0, TRUE);
2424
2425                         /* handle shift over 32 bit */
2426                         x86_mov_reg_reg (code, ins->unused, ins->sreg1, 4);
2427                         x86_clear_reg (code, ins->sreg1);
2428                         
2429                         x86_patch (jump_to_end, code);
2430                         }
2431                         break;
2432                 case OP_LSHR: {
2433                         guint8 *jump_to_end;
2434
2435                         /* handle shifts below 32 bits */
2436                         x86_shrd_reg (code, ins->sreg1, ins->unused);
2437                         x86_shift_reg (code, X86_SAR, ins->unused);
2438
2439                         x86_test_reg_imm (code, X86_ECX, 32);
2440                         jump_to_end = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE);
2441
2442                         /* handle shifts over 31 bits */
2443                         x86_mov_reg_reg (code, ins->sreg1, ins->unused, 4);
2444                         x86_shift_reg_imm (code, X86_SAR, ins->unused, 31);
2445                         
2446                         x86_patch (jump_to_end, code);
2447                         }
2448                         break;
2449                 case OP_LSHR_UN: {
2450                         guint8 *jump_to_end;
2451
2452                         /* handle shifts below 32 bits */
2453                         x86_shrd_reg (code, ins->sreg1, ins->unused);
2454                         x86_shift_reg (code, X86_SHR, ins->unused);
2455
2456                         x86_test_reg_imm (code, X86_ECX, 32);
2457                         jump_to_end = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE);
2458
2459                         /* handle shifts over 31 bits */
2460                         x86_mov_reg_reg (code, ins->sreg1, ins->unused, 4);
2461                         x86_shift_reg_imm (code, X86_SHR, ins->unused, 31);
2462                         
2463                         x86_patch (jump_to_end, code);
2464                         }
2465                         break;
2466                 case OP_LSHL_IMM:
2467                         if (ins->inst_imm >= 32) {
2468                                 x86_mov_reg_reg (code, ins->unused, ins->sreg1, 4);
2469                                 x86_clear_reg (code, ins->sreg1);
2470                                 x86_shift_reg_imm (code, X86_SHL, ins->unused, ins->inst_imm - 32);
2471                         } else {
2472                                 x86_shld_reg_imm (code, ins->unused, ins->sreg1, ins->inst_imm);
2473                                 x86_shift_reg_imm (code, X86_SHL, ins->sreg1, ins->inst_imm);
2474                         }
2475                         break;
2476                 case OP_LSHR_IMM:
2477                         if (ins->inst_imm >= 32) {
2478                                 x86_mov_reg_reg (code, ins->sreg1, ins->unused,  4);
2479                                 x86_shift_reg_imm (code, X86_SAR, ins->unused, 0x1f);
2480                                 x86_shift_reg_imm (code, X86_SAR, ins->sreg1, ins->inst_imm - 32);
2481                         } else {
2482                                 x86_shrd_reg_imm (code, ins->sreg1, ins->unused, ins->inst_imm);
2483                                 x86_shift_reg_imm (code, X86_SAR, ins->unused, ins->inst_imm);
2484                         }
2485                         break;
2486                 case OP_LSHR_UN_IMM:
2487                         if (ins->inst_imm >= 32) {
2488                                 x86_mov_reg_reg (code, ins->sreg1, ins->unused, 4);
2489                                 x86_clear_reg (code, ins->unused);
2490                                 x86_shift_reg_imm (code, X86_SHR, ins->sreg1, ins->inst_imm - 32);
2491                         } else {
2492                                 x86_shrd_reg_imm (code, ins->sreg1, ins->unused, ins->inst_imm);
2493                                 x86_shift_reg_imm (code, X86_SHR, ins->unused, ins->inst_imm);
2494                         }
2495                         break;
2496                 case CEE_NOT:
2497                         x86_not_reg (code, ins->sreg1);
2498                         break;
2499                 case CEE_NEG:
2500                         x86_neg_reg (code, ins->sreg1);
2501                         break;
2502                 case OP_SEXT_I1:
2503                         x86_widen_reg (code, ins->dreg, ins->sreg1, TRUE, FALSE);
2504                         break;
2505                 case OP_SEXT_I2:
2506                         x86_widen_reg (code, ins->dreg, ins->sreg1, TRUE, TRUE);
2507                         break;
2508                 case CEE_MUL:
2509                         x86_imul_reg_reg (code, ins->sreg1, ins->sreg2);
2510                         break;
2511                 case OP_MUL_IMM:
2512                         x86_imul_reg_reg_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2513                         break;
2514                 case CEE_MUL_OVF:
2515                         x86_imul_reg_reg (code, ins->sreg1, ins->sreg2);
2516                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_O, FALSE, "OverflowException");
2517                         break;
2518                 case CEE_MUL_OVF_UN: {
2519                         /* the mul operation and the exception check should most likely be split */
2520                         int non_eax_reg, saved_eax = FALSE, saved_edx = FALSE;
2521                         /*g_assert (ins->sreg2 == X86_EAX);
2522                         g_assert (ins->dreg == X86_EAX);*/
2523                         if (ins->sreg2 == X86_EAX) {
2524                                 non_eax_reg = ins->sreg1;
2525                         } else if (ins->sreg1 == X86_EAX) {
2526                                 non_eax_reg = ins->sreg2;
2527                         } else {
2528                                 /* no need to save since we're going to store to it anyway */
2529                                 if (ins->dreg != X86_EAX) {
2530                                         saved_eax = TRUE;
2531                                         x86_push_reg (code, X86_EAX);
2532                                 }
2533                                 x86_mov_reg_reg (code, X86_EAX, ins->sreg1, 4);
2534                                 non_eax_reg = ins->sreg2;
2535                         }
2536                         if (ins->dreg == X86_EDX) {
2537                                 if (!saved_eax) {
2538                                         saved_eax = TRUE;
2539                                         x86_push_reg (code, X86_EAX);
2540                                 }
2541                         } else if (ins->dreg != X86_EAX) {
2542                                 saved_edx = TRUE;
2543                                 x86_push_reg (code, X86_EDX);
2544                         }
2545                         x86_mul_reg (code, non_eax_reg, FALSE);
2546                         /* save before the check since pop and mov don't change the flags */
2547                         if (ins->dreg != X86_EAX)
2548                                 x86_mov_reg_reg (code, ins->dreg, X86_EAX, 4);
2549                         if (saved_edx)
2550                                 x86_pop_reg (code, X86_EDX);
2551                         if (saved_eax)
2552                                 x86_pop_reg (code, X86_EAX);
2553                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_O, FALSE, "OverflowException");
2554                         break;
2555                 }
2556                 case OP_ICONST:
2557                         x86_mov_reg_imm (code, ins->dreg, ins->inst_c0);
2558                         break;
2559                 case OP_AOTCONST:
2560                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2561                         x86_mov_reg_imm (code, ins->dreg, 0);
2562                         break;
2563                 case CEE_CONV_I4:
2564                 case OP_MOVE:
2565                         x86_mov_reg_reg (code, ins->dreg, ins->sreg1, 4);
2566                         break;
2567                 case CEE_CONV_U4:
2568                         g_assert_not_reached ();
2569                 case CEE_JMP: {
2570                         /*
2571                          * Note: this 'frame destruction' logic is useful for tail calls, too.
2572                          * Keep in sync with the code in emit_epilog.
2573                          */
2574                         int pos = 0;
2575
2576                         /* FIXME: no tracing support... */
2577                         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
2578                                 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
2579                         /* reset offset to make max_len work */
2580                         offset = code - cfg->native_code;
2581
2582                         g_assert (!cfg->method->save_lmf);
2583
2584                         if (cfg->used_int_regs & (1 << X86_EBX))
2585                                 pos -= 4;
2586                         if (cfg->used_int_regs & (1 << X86_EDI))
2587                                 pos -= 4;
2588                         if (cfg->used_int_regs & (1 << X86_ESI))
2589                                 pos -= 4;
2590                         if (pos)
2591                                 x86_lea_membase (code, X86_ESP, X86_EBP, pos);
2592         
2593                         if (cfg->used_int_regs & (1 << X86_ESI))
2594                                 x86_pop_reg (code, X86_ESI);
2595                         if (cfg->used_int_regs & (1 << X86_EDI))
2596                                 x86_pop_reg (code, X86_EDI);
2597                         if (cfg->used_int_regs & (1 << X86_EBX))
2598                                 x86_pop_reg (code, X86_EBX);
2599         
2600                         /* restore ESP/EBP */
2601                         x86_leave (code);
2602                         offset = code - cfg->native_code;
2603                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2604                         x86_jump32 (code, 0);
2605                         break;
2606                 }
2607                 case OP_CHECK_THIS:
2608                         /* ensure ins->sreg1 is not NULL */
2609                         x86_alu_membase_imm (code, X86_CMP, ins->sreg1, 0, 0);
2610                         break;
2611                 case OP_ARGLIST: {
2612                         int hreg = ins->sreg1 == X86_EAX? X86_ECX: X86_EAX;
2613                         x86_push_reg (code, hreg);
2614                         x86_lea_membase (code, hreg, X86_EBP, cfg->sig_cookie);
2615                         x86_mov_membase_reg (code, ins->sreg1, 0, hreg, 4);
2616                         x86_pop_reg (code, hreg);
2617                         break;
2618                 }
2619                 case OP_FCALL:
2620                 case OP_LCALL:
2621                 case OP_VCALL:
2622                 case OP_VOIDCALL:
2623                 case CEE_CALL:
2624                         call = (MonoCallInst*)ins;
2625                         if (ins->flags & MONO_INST_HAS_METHOD)
2626                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2627                         else {
2628                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2629                         }
2630                         x86_call_code (code, 0);
2631                         if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature->call_convention))
2632                                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, call->stack_usage);
2633                         break;
2634                 case OP_FCALL_REG:
2635                 case OP_LCALL_REG:
2636                 case OP_VCALL_REG:
2637                 case OP_VOIDCALL_REG:
2638                 case OP_CALL_REG:
2639                         call = (MonoCallInst*)ins;
2640                         x86_call_reg (code, ins->sreg1);
2641                         if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature->call_convention))
2642                                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, call->stack_usage);
2643                         break;
2644                 case OP_FCALL_MEMBASE:
2645                 case OP_LCALL_MEMBASE:
2646                 case OP_VCALL_MEMBASE:
2647                 case OP_VOIDCALL_MEMBASE:
2648                 case OP_CALL_MEMBASE:
2649                         call = (MonoCallInst*)ins;
2650                         x86_call_membase (code, ins->sreg1, ins->inst_offset);
2651                         if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature->call_convention))
2652                                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, call->stack_usage);
2653                         break;
2654                 case OP_OUTARG:
2655                 case OP_X86_PUSH:
2656                         x86_push_reg (code, ins->sreg1);
2657                         break;
2658                 case OP_X86_PUSH_IMM:
2659                         x86_push_imm (code, ins->inst_imm);
2660                         break;
2661                 case OP_X86_PUSH_MEMBASE:
2662                         x86_push_membase (code, ins->inst_basereg, ins->inst_offset);
2663                         break;
2664                 case OP_X86_PUSH_OBJ: 
2665                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, ins->inst_imm);
2666                         x86_push_reg (code, X86_EDI);
2667                         x86_push_reg (code, X86_ESI);
2668                         x86_push_reg (code, X86_ECX);
2669                         if (ins->inst_offset)
2670                                 x86_lea_membase (code, X86_ESI, ins->inst_basereg, ins->inst_offset);
2671                         else
2672                                 x86_mov_reg_reg (code, X86_ESI, ins->inst_basereg, 4);
2673                         x86_lea_membase (code, X86_EDI, X86_ESP, 12);
2674                         x86_mov_reg_imm (code, X86_ECX, (ins->inst_imm >> 2));
2675                         x86_cld (code);
2676                         x86_prefix (code, X86_REP_PREFIX);
2677                         x86_movsd (code);
2678                         x86_pop_reg (code, X86_ECX);
2679                         x86_pop_reg (code, X86_ESI);
2680                         x86_pop_reg (code, X86_EDI);
2681                         break;
2682                 case OP_X86_LEA:
2683                         x86_lea_memindex (code, ins->dreg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->unused);
2684                         break;
2685                 case OP_X86_LEA_MEMBASE:
2686                         x86_lea_membase (code, ins->dreg, ins->sreg1, ins->inst_imm);
2687                         break;
2688                 case OP_X86_XCHG:
2689                         x86_xchg_reg_reg (code, ins->sreg1, ins->sreg2, 4);
2690                         break;
2691                 case OP_LOCALLOC:
2692                         /* keep alignment */
2693                         x86_alu_reg_imm (code, X86_ADD, ins->sreg1, MONO_ARCH_FRAME_ALIGNMENT - 1);
2694                         x86_alu_reg_imm (code, X86_AND, ins->sreg1, ~(MONO_ARCH_FRAME_ALIGNMENT - 1));
2695                         code = mono_emit_stack_alloc (code, ins);
2696                         x86_mov_reg_reg (code, ins->dreg, X86_ESP, 4);
2697                         break;
2698                 case CEE_RET:
2699                         x86_ret (code);
2700                         break;
2701                 case CEE_THROW: {
2702                         x86_push_reg (code, ins->sreg1);
2703                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2704                                              (gpointer)"mono_arch_throw_exception");
2705                         x86_call_code (code, 0);
2706                         break;
2707                 }
2708                 case OP_CALL_HANDLER: 
2709                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2710                         x86_call_imm (code, 0);
2711                         break;
2712                 case OP_LABEL:
2713                         ins->inst_c0 = code - cfg->native_code;
2714                         break;
2715                 case CEE_BR:
2716                         //g_print ("target: %p, next: %p, curr: %p, last: %p\n", ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
2717                         //if ((ins->inst_target_bb == bb->next_bb) && ins == bb->last_ins)
2718                         //break;
2719                         if (ins->flags & MONO_INST_BRLABEL) {
2720                                 if (ins->inst_i0->inst_c0) {
2721                                         x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
2722                                 } else {
2723                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2724                                         if ((cfg->opt & MONO_OPT_BRANCH) &&
2725                                             x86_is_imm8 (ins->inst_i0->inst_c1 - cpos))
2726                                                 x86_jump8 (code, 0);
2727                                         else 
2728                                                 x86_jump32 (code, 0);
2729                                 }
2730                         } else {
2731                                 if (ins->inst_target_bb->native_offset) {
2732                                         x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); 
2733                                 } else {
2734                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2735                                         if ((cfg->opt & MONO_OPT_BRANCH) &&
2736                                             x86_is_imm8 (ins->inst_target_bb->max_offset - cpos))
2737                                                 x86_jump8 (code, 0);
2738                                         else 
2739                                                 x86_jump32 (code, 0);
2740                                 } 
2741                         }
2742                         break;
2743                 case OP_BR_REG:
2744                         x86_jump_reg (code, ins->sreg1);
2745                         break;
2746                 case OP_CEQ:
2747                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
2748                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
2749                         break;
2750                 case OP_CLT:
2751                         x86_set_reg (code, X86_CC_LT, ins->dreg, TRUE);
2752                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
2753                         break;
2754                 case OP_CLT_UN:
2755                         x86_set_reg (code, X86_CC_LT, ins->dreg, FALSE);
2756                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
2757                         break;
2758                 case OP_CGT:
2759                         x86_set_reg (code, X86_CC_GT, ins->dreg, TRUE);
2760                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
2761                         break;
2762                 case OP_CGT_UN:
2763                         x86_set_reg (code, X86_CC_GT, ins->dreg, FALSE);
2764                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
2765                         break;
2766                 case OP_COND_EXC_EQ:
2767                 case OP_COND_EXC_NE_UN:
2768                 case OP_COND_EXC_LT:
2769                 case OP_COND_EXC_LT_UN:
2770                 case OP_COND_EXC_GT:
2771                 case OP_COND_EXC_GT_UN:
2772                 case OP_COND_EXC_GE:
2773                 case OP_COND_EXC_GE_UN:
2774                 case OP_COND_EXC_LE:
2775                 case OP_COND_EXC_LE_UN:
2776                 case OP_COND_EXC_OV:
2777                 case OP_COND_EXC_NO:
2778                 case OP_COND_EXC_C:
2779                 case OP_COND_EXC_NC:
2780                         EMIT_COND_SYSTEM_EXCEPTION (branch_cc_table [ins->opcode - OP_COND_EXC_EQ], 
2781                                                     (ins->opcode < OP_COND_EXC_NE_UN), ins->inst_p1);
2782                         break;
2783                 case CEE_BEQ:
2784                 case CEE_BNE_UN:
2785                 case CEE_BLT:
2786                 case CEE_BLT_UN:
2787                 case CEE_BGT:
2788                 case CEE_BGT_UN:
2789                 case CEE_BGE:
2790                 case CEE_BGE_UN:
2791                 case CEE_BLE:
2792                 case CEE_BLE_UN:
2793                         EMIT_COND_BRANCH (ins, branch_cc_table [ins->opcode - CEE_BEQ], (ins->opcode < CEE_BNE_UN));
2794                         break;
2795
2796                 /* floating point opcodes */
2797                 case OP_R8CONST: {
2798                         double d = *(double *)ins->inst_p0;
2799
2800                         if ((d == 0.0) && (mono_signbit (d) == 0)) {
2801                                 x86_fldz (code);
2802                         } else if (d == 1.0) {
2803                                 x86_fld1 (code);
2804                         } else {
2805                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R8, ins->inst_p0);
2806                                 x86_fld (code, NULL, TRUE);
2807                         }
2808                         break;
2809                 }
2810                 case OP_R4CONST: {
2811                         float f = *(float *)ins->inst_p0;
2812
2813                         if ((f == 0.0) && (mono_signbit (f) == 0)) {
2814                                 x86_fldz (code);
2815                         } else if (f == 1.0) {
2816                                 x86_fld1 (code);
2817                         } else {
2818                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R4, ins->inst_p0);
2819                                 x86_fld (code, NULL, FALSE);
2820                         }
2821                         break;
2822                 }
2823                 case OP_STORER8_MEMBASE_REG:
2824                         x86_fst_membase (code, ins->inst_destbasereg, ins->inst_offset, TRUE, TRUE);
2825                         break;
2826                 case OP_LOADR8_SPILL_MEMBASE:
2827                         x86_fld_membase (code, ins->inst_basereg, ins->inst_offset, TRUE);
2828                         x86_fxch (code, 1);
2829                         break;
2830                 case OP_LOADR8_MEMBASE:
2831                         x86_fld_membase (code, ins->inst_basereg, ins->inst_offset, TRUE);
2832                         break;
2833                 case OP_STORER4_MEMBASE_REG:
2834                         x86_fst_membase (code, ins->inst_destbasereg, ins->inst_offset, FALSE, TRUE);
2835                         break;
2836                 case OP_LOADR4_MEMBASE:
2837                         x86_fld_membase (code, ins->inst_basereg, ins->inst_offset, FALSE);
2838                         break;
2839                 case CEE_CONV_R4: /* FIXME: change precision */
2840                 case CEE_CONV_R8:
2841                         x86_push_reg (code, ins->sreg1);
2842                         x86_fild_membase (code, X86_ESP, 0, FALSE);
2843                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
2844                         break;
2845                 case OP_X86_FP_LOAD_I8:
2846                         x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, TRUE);
2847                         break;
2848                 case OP_X86_FP_LOAD_I4:
2849                         x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, FALSE);
2850                         break;
2851                 case OP_FCONV_TO_I1:
2852                         code = emit_float_to_int (cfg, code, ins->dreg, 1, TRUE);
2853                         break;
2854                 case OP_FCONV_TO_U1:
2855                         code = emit_float_to_int (cfg, code, ins->dreg, 1, FALSE);
2856                         break;
2857                 case OP_FCONV_TO_I2:
2858                         code = emit_float_to_int (cfg, code, ins->dreg, 2, TRUE);
2859                         break;
2860                 case OP_FCONV_TO_U2:
2861                         code = emit_float_to_int (cfg, code, ins->dreg, 2, FALSE);
2862                         break;
2863                 case OP_FCONV_TO_I4:
2864                 case OP_FCONV_TO_I:
2865                         code = emit_float_to_int (cfg, code, ins->dreg, 4, TRUE);
2866                         break;
2867                 case OP_FCONV_TO_I8:
2868                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 4);
2869                         x86_fnstcw_membase(code, X86_ESP, 0);
2870                         x86_mov_reg_membase (code, ins->dreg, X86_ESP, 0, 2);
2871                         x86_alu_reg_imm (code, X86_OR, ins->dreg, 0xc00);
2872                         x86_mov_membase_reg (code, X86_ESP, 2, ins->dreg, 2);
2873                         x86_fldcw_membase (code, X86_ESP, 2);
2874                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
2875                         x86_fist_pop_membase (code, X86_ESP, 0, TRUE);
2876                         x86_pop_reg (code, ins->dreg);
2877                         x86_pop_reg (code, ins->unused);
2878                         x86_fldcw_membase (code, X86_ESP, 0);
2879                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
2880                         break;
2881                 case OP_LCONV_TO_R_UN: { 
2882                         static guint8 mn[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x40 };
2883                         guint8 *br;
2884
2885                         /* load 64bit integer to FP stack */
2886                         x86_push_imm (code, 0);
2887                         x86_push_reg (code, ins->sreg2);
2888                         x86_push_reg (code, ins->sreg1);
2889                         x86_fild_membase (code, X86_ESP, 0, TRUE);
2890                         /* store as 80bit FP value */
2891                         x86_fst80_membase (code, X86_ESP, 0);
2892                         
2893                         /* test if lreg is negative */
2894                         x86_test_reg_reg (code, ins->sreg2, ins->sreg2);
2895                         br = code; x86_branch8 (code, X86_CC_GEZ, 0, TRUE);
2896         
2897                         /* add correction constant mn */
2898                         x86_fld80_mem (code, mn);
2899                         x86_fld80_membase (code, X86_ESP, 0);
2900                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
2901                         x86_fst80_membase (code, X86_ESP, 0);
2902
2903                         x86_patch (br, code);
2904
2905                         x86_fld80_membase (code, X86_ESP, 0);
2906                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
2907
2908                         break;
2909                 }
2910                 case OP_LCONV_TO_OVF_I: {
2911                         guint8 *br [3], *label [1];
2912
2913                         /* 
2914                          * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
2915                          */
2916                         x86_test_reg_reg (code, ins->sreg1, ins->sreg1);
2917
2918                         /* If the low word top bit is set, see if we are negative */
2919                         br [0] = code; x86_branch8 (code, X86_CC_LT, 0, TRUE);
2920                         /* We are not negative (no top bit set, check for our top word to be zero */
2921                         x86_test_reg_reg (code, ins->sreg2, ins->sreg2);
2922                         br [1] = code; x86_branch8 (code, X86_CC_EQ, 0, TRUE);
2923                         label [0] = code;
2924
2925                         /* throw exception */
2926                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC, "OverflowException");
2927                         x86_jump32 (code, 0);
2928         
2929                         x86_patch (br [0], code);
2930                         /* our top bit is set, check that top word is 0xfffffff */
2931                         x86_alu_reg_imm (code, X86_CMP, ins->sreg2, 0xffffffff);
2932                 
2933                         x86_patch (br [1], code);
2934                         /* nope, emit exception */
2935                         br [2] = code; x86_branch8 (code, X86_CC_NE, 0, TRUE);
2936                         x86_patch (br [2], label [0]);
2937
2938                         if (ins->dreg != ins->sreg1)
2939                                 x86_mov_reg_reg (code, ins->dreg, ins->sreg1, 4);
2940                         break;
2941                 }
2942                 case OP_FADD:
2943                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
2944                         break;
2945                 case OP_FSUB:
2946                         x86_fp_op_reg (code, X86_FSUB, 1, TRUE);
2947                         break;          
2948                 case OP_FMUL:
2949                         x86_fp_op_reg (code, X86_FMUL, 1, TRUE);
2950                         break;          
2951                 case OP_FDIV:
2952                         x86_fp_op_reg (code, X86_FDIV, 1, TRUE);
2953                         break;          
2954                 case OP_FNEG:
2955                         x86_fchs (code);
2956                         break;          
2957                 case OP_SIN:
2958                         x86_fsin (code);
2959                         x86_fldz (code);
2960                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
2961                         break;          
2962                 case OP_COS:
2963                         x86_fcos (code);
2964                         x86_fldz (code);
2965                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
2966                         break;          
2967                 case OP_ABS:
2968                         x86_fabs (code);
2969                         break;          
2970                 case OP_TAN: {
2971                         /* 
2972                          * it really doesn't make sense to inline all this code,
2973                          * it's here just to show that things may not be as simple 
2974                          * as they appear.
2975                          */
2976                         guchar *check_pos, *end_tan, *pop_jump;
2977                         x86_push_reg (code, X86_EAX);
2978                         x86_fptan (code);
2979                         x86_fnstsw (code);
2980                         x86_test_reg_imm (code, X86_EAX, X86_FP_C2);
2981                         check_pos = code;
2982                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
2983                         x86_fstp (code, 0); /* pop the 1.0 */
2984                         end_tan = code;
2985                         x86_jump8 (code, 0);
2986                         x86_fldpi (code);
2987                         x86_fp_op (code, X86_FADD, 0);
2988                         x86_fxch (code, 1);
2989                         x86_fprem1 (code);
2990                         x86_fstsw (code);
2991                         x86_test_reg_imm (code, X86_EAX, X86_FP_C2);
2992                         pop_jump = code;
2993                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
2994                         x86_fstp (code, 1);
2995                         x86_fptan (code);
2996                         x86_patch (pop_jump, code);
2997                         x86_fstp (code, 0); /* pop the 1.0 */
2998                         x86_patch (check_pos, code);
2999                         x86_patch (end_tan, code);
3000                         x86_fldz (code);
3001                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3002                         x86_pop_reg (code, X86_EAX);
3003                         break;
3004                 }
3005                 case OP_ATAN:
3006                         x86_fld1 (code);
3007                         x86_fpatan (code);
3008                         x86_fldz (code);
3009                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3010                         break;          
3011                 case OP_SQRT:
3012                         x86_fsqrt (code);
3013                         break;          
3014                 case OP_X86_FPOP:
3015                         x86_fstp (code, 0);
3016                         break;          
3017                 case OP_FREM: {
3018                         guint8 *l1, *l2;
3019
3020                         x86_push_reg (code, X86_EAX);
3021                         /* we need to exchange ST(0) with ST(1) */
3022                         x86_fxch (code, 1);
3023
3024                         /* this requires a loop, because fprem somtimes 
3025                          * returns a partial remainder */
3026                         l1 = code;
3027                         /* looks like MS is using fprem instead of the IEEE compatible fprem1 */
3028                         /* x86_fprem1 (code); */
3029                         x86_fprem (code);
3030                         x86_fnstsw (code);
3031                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_C2);
3032                         l2 = code + 2;
3033                         x86_branch8 (code, X86_CC_NE, l1 - l2, FALSE);
3034
3035                         /* pop result */
3036                         x86_fstp (code, 1);
3037
3038                         x86_pop_reg (code, X86_EAX);
3039                         break;
3040                 }
3041                 case OP_FCOMPARE:
3042                         if (cfg->opt & MONO_OPT_FCMOV) {
3043                                 x86_fcomip (code, 1);
3044                                 x86_fstp (code, 0);
3045                                 break;
3046                         }
3047                         /* this overwrites EAX */
3048                         EMIT_FPCOMPARE(code);
3049                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3050                         break;
3051                 case OP_FCEQ:
3052                         if (cfg->opt & MONO_OPT_FCMOV) {
3053                                 /* zeroing the register at the start results in 
3054                                  * shorter and faster code (we can also remove the widening op)
3055                                  */
3056                                 guchar *unordered_check;
3057                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
3058                                 x86_fcomip (code, 1);
3059                                 x86_fstp (code, 0);
3060                                 unordered_check = code;
3061                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
3062                                 x86_set_reg (code, X86_CC_EQ, ins->dreg, FALSE);
3063                                 x86_patch (unordered_check, code);
3064                                 break;
3065                         }
3066                         if (ins->dreg != X86_EAX) 
3067                                 x86_push_reg (code, X86_EAX);
3068
3069                         EMIT_FPCOMPARE(code);
3070                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3071                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0x4000);
3072                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
3073                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3074
3075                         if (ins->dreg != X86_EAX) 
3076                                 x86_pop_reg (code, X86_EAX);
3077                         break;
3078                 case OP_FCLT:
3079                 case OP_FCLT_UN:
3080                         if (cfg->opt & MONO_OPT_FCMOV) {
3081                                 /* zeroing the register at the start results in 
3082                                  * shorter and faster code (we can also remove the widening op)
3083                                  */
3084                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
3085                                 x86_fcomip (code, 1);
3086                                 x86_fstp (code, 0);
3087                                 if (ins->opcode == OP_FCLT_UN) {
3088                                         guchar *unordered_check = code;
3089                                         guchar *jump_to_end;
3090                                         x86_branch8 (code, X86_CC_P, 0, FALSE);
3091                                         x86_set_reg (code, X86_CC_GT, ins->dreg, FALSE);
3092                                         jump_to_end = code;
3093                                         x86_jump8 (code, 0);
3094                                         x86_patch (unordered_check, code);
3095                                         x86_inc_reg (code, ins->dreg);
3096                                         x86_patch (jump_to_end, code);
3097                                 } else {
3098                                         x86_set_reg (code, X86_CC_GT, ins->dreg, FALSE);
3099                                 }
3100                                 break;
3101                         }
3102                         if (ins->dreg != X86_EAX) 
3103                                 x86_push_reg (code, X86_EAX);
3104
3105                         EMIT_FPCOMPARE(code);
3106                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3107                         if (ins->opcode == OP_FCLT_UN) {
3108                                 guchar *is_not_zero_check, *end_jump;
3109                                 is_not_zero_check = code;
3110                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3111                                 end_jump = code;
3112                                 x86_jump8 (code, 0);
3113                                 x86_patch (is_not_zero_check, code);
3114                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3115
3116                                 x86_patch (end_jump, code);
3117                         }
3118                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
3119                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3120
3121                         if (ins->dreg != X86_EAX) 
3122                                 x86_pop_reg (code, X86_EAX);
3123                         break;
3124                 case OP_FCGT:
3125                 case OP_FCGT_UN:
3126                         if (cfg->opt & MONO_OPT_FCMOV) {
3127                                 /* zeroing the register at the start results in 
3128                                  * shorter and faster code (we can also remove the widening op)
3129                                  */
3130                                 guchar *unordered_check;
3131                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
3132                                 x86_fcomip (code, 1);
3133                                 x86_fstp (code, 0);
3134                                 if (ins->opcode == OP_FCGT) {
3135                                         unordered_check = code;
3136                                         x86_branch8 (code, X86_CC_P, 0, FALSE);
3137                                         x86_set_reg (code, X86_CC_LT, ins->dreg, FALSE);
3138                                         x86_patch (unordered_check, code);
3139                                 } else {
3140                                         x86_set_reg (code, X86_CC_LT, ins->dreg, FALSE);
3141                                 }
3142                                 break;
3143                         }
3144                         if (ins->dreg != X86_EAX) 
3145                                 x86_push_reg (code, X86_EAX);
3146
3147                         EMIT_FPCOMPARE(code);
3148                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3149                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3150                         if (ins->opcode == OP_FCGT_UN) {
3151                                 guchar *is_not_zero_check, *end_jump;
3152                                 is_not_zero_check = code;
3153                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3154                                 end_jump = code;
3155                                 x86_jump8 (code, 0);
3156                                 x86_patch (is_not_zero_check, code);
3157                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3158
3159                                 x86_patch (end_jump, code);
3160                         }
3161                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
3162                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3163
3164                         if (ins->dreg != X86_EAX) 
3165                                 x86_pop_reg (code, X86_EAX);
3166                         break;
3167                 case OP_FBEQ:
3168                         if (cfg->opt & MONO_OPT_FCMOV) {
3169                                 guchar *jump = code;
3170                                 x86_branch8 (code, X86_CC_P, 0, TRUE);
3171                                 EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3172                                 x86_patch (jump, code);
3173                                 break;
3174                         }
3175                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0x4000);
3176                         EMIT_COND_BRANCH (ins, X86_CC_EQ, TRUE);
3177                         break;
3178                 case OP_FBNE_UN:
3179                         /* Branch if C013 != 100 */
3180                         if (cfg->opt & MONO_OPT_FCMOV) {
3181                                 /* branch if !ZF or (PF|CF) */
3182                                 EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3183                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
3184                                 EMIT_COND_BRANCH (ins, X86_CC_B, FALSE);
3185                                 break;
3186                         }
3187                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C3);
3188                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3189                         break;
3190                 case OP_FBLT:
3191                         if (cfg->opt & MONO_OPT_FCMOV) {
3192                                 EMIT_COND_BRANCH (ins, X86_CC_GT, FALSE);
3193                                 break;
3194                         }
3195                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3196                         break;
3197                 case OP_FBLT_UN:
3198                         if (cfg->opt & MONO_OPT_FCMOV) {
3199                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
3200                                 EMIT_COND_BRANCH (ins, X86_CC_GT, FALSE);
3201                                 break;
3202                         }
3203                         if (ins->opcode == OP_FBLT_UN) {
3204                                 guchar *is_not_zero_check, *end_jump;
3205                                 is_not_zero_check = code;
3206                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3207                                 end_jump = code;
3208                                 x86_jump8 (code, 0);
3209                                 x86_patch (is_not_zero_check, code);
3210                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3211
3212                                 x86_patch (end_jump, code);
3213                         }
3214                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3215                         break;
3216                 case OP_FBGT:
3217                 case OP_FBGT_UN:
3218                         if (cfg->opt & MONO_OPT_FCMOV) {
3219                                 EMIT_COND_BRANCH (ins, X86_CC_LT, FALSE);
3220                                 break;
3221                         }
3222                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3223                         if (ins->opcode == OP_FBGT_UN) {
3224                                 guchar *is_not_zero_check, *end_jump;
3225                                 is_not_zero_check = code;
3226                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3227                                 end_jump = code;
3228                                 x86_jump8 (code, 0);
3229                                 x86_patch (is_not_zero_check, code);
3230                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3231
3232                                 x86_patch (end_jump, code);
3233                         }
3234                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3235                         break;
3236                 case OP_FBGE:
3237                         /* Branch if C013 == 100 or 001 */
3238                         if (cfg->opt & MONO_OPT_FCMOV) {
3239                                 guchar *br1;
3240
3241                                 /* skip branch if C1=1 */
3242                                 br1 = code;
3243                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
3244                                 /* branch if (C0 | C3) = 1 */
3245                                 EMIT_COND_BRANCH (ins, X86_CC_BE, FALSE);
3246                                 x86_patch (br1, code);
3247                                 break;
3248                         }
3249                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3250                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3251                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C3);
3252                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3253                         break;
3254                 case OP_FBGE_UN:
3255                         /* Branch if C013 == 000 */
3256                         if (cfg->opt & MONO_OPT_FCMOV) {
3257                                 EMIT_COND_BRANCH (ins, X86_CC_LE, FALSE);
3258                                 break;
3259                         }
3260                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3261                         break;
3262                 case OP_FBLE:
3263                         /* Branch if C013=000 or 100 */
3264                         if (cfg->opt & MONO_OPT_FCMOV) {
3265                                 guchar *br1;
3266
3267                                 /* skip branch if C1=1 */
3268                                 br1 = code;
3269                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
3270                                 /* branch if C0=0 */
3271                                 EMIT_COND_BRANCH (ins, X86_CC_NB, FALSE);
3272                                 x86_patch (br1, code);
3273                                 break;
3274                         }
3275                         x86_alu_reg_imm (code, X86_AND, X86_EAX, (X86_FP_C0|X86_FP_C1));
3276                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0);
3277                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3278                         break;
3279                 case OP_FBLE_UN:
3280                         /* Branch if C013 != 001 */
3281                         if (cfg->opt & MONO_OPT_FCMOV) {
3282                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
3283                                 EMIT_COND_BRANCH (ins, X86_CC_GE, FALSE);
3284                                 break;
3285                         }
3286                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3287                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3288                         break;
3289                 case CEE_CKFINITE: {
3290                         x86_push_reg (code, X86_EAX);
3291                         x86_fxam (code);
3292                         x86_fnstsw (code);
3293                         x86_alu_reg_imm (code, X86_AND, X86_EAX, 0x4100);
3294                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3295                         x86_pop_reg (code, X86_EAX);
3296                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "ArithmeticException");
3297                         break;
3298                 }
3299                 default:
3300                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3301                         g_assert_not_reached ();
3302                 }
3303
3304                 if ((code - cfg->native_code - offset) > max_len) {
3305                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3306                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3307                         g_assert_not_reached ();
3308                 }
3309                
3310                 cpos += max_len;
3311
3312                 last_ins = ins;
3313                 last_offset = offset;
3314                 
3315                 ins = ins->next;
3316         }
3317
3318         cfg->code_len = code - cfg->native_code;
3319 }
3320
3321 void
3322 mono_arch_register_lowlevel_calls (void)
3323 {
3324 }
3325
3326 void
3327 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3328 {
3329         MonoJumpInfo *patch_info;
3330
3331         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3332                 unsigned char *ip = patch_info->ip.i + code;
3333                 const unsigned char *target;
3334
3335                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3336
3337                 switch (patch_info->type) {
3338                 case MONO_PATCH_INFO_IP:
3339                         *((gconstpointer *)(ip)) = target;
3340                         continue;
3341                 case MONO_PATCH_INFO_METHOD_REL:
3342                         *((gconstpointer *)(ip)) = target;
3343                         continue;
3344                 case MONO_PATCH_INFO_SWITCH: {
3345                         *((gconstpointer *)(ip + 2)) = target;
3346                         /* we put into the table the absolute address, no need for x86_patch in this case */
3347                         continue;
3348                 }
3349                 case MONO_PATCH_INFO_IID:
3350                         *((guint32 *)(ip + 1)) = (guint32)target;
3351                         continue;                       
3352                 case MONO_PATCH_INFO_CLASS_INIT: {
3353                         guint8 *code = ip;
3354                         /* Might already been changed to a nop */
3355                         x86_call_imm (code, 0);
3356                         break;
3357                 }
3358                 case MONO_PATCH_INFO_R4:
3359                 case MONO_PATCH_INFO_R8:
3360                         *((gconstpointer *)(ip + 2)) = target;
3361                         continue;
3362                 case MONO_PATCH_INFO_METHODCONST:
3363                 case MONO_PATCH_INFO_CLASS:
3364                 case MONO_PATCH_INFO_IMAGE:
3365                 case MONO_PATCH_INFO_FIELD:
3366                 case MONO_PATCH_INFO_VTABLE:
3367                 case MONO_PATCH_INFO_SFLDA:
3368                 case MONO_PATCH_INFO_EXC_NAME:
3369                 case MONO_PATCH_INFO_LDSTR:
3370                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3371                 case MONO_PATCH_INFO_LDTOKEN:
3372                         *((gconstpointer *)(ip + 1)) = target;
3373                         continue;
3374                 default:
3375                         break;
3376                 }
3377                 x86_patch (ip, target);
3378         }
3379 }
3380
3381 int
3382 mono_arch_max_epilog_size (MonoCompile *cfg)
3383 {
3384         int exc_count = 0, max_epilog_size = 16;
3385         MonoJumpInfo *patch_info;
3386         
3387         if (cfg->method->save_lmf)
3388                 max_epilog_size += 128;
3389         
3390         if (mono_jit_trace_calls != NULL)
3391                 max_epilog_size += 50;
3392
3393         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3394                 max_epilog_size += 50;
3395
3396         /* count the number of exception infos */
3397      
3398         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3399                 if (patch_info->type == MONO_PATCH_INFO_EXC)
3400                         exc_count++;
3401         }
3402
3403         /* 
3404          * make sure we have enough space for exceptions
3405          * 16 is the size of two push_imm instructions and a call
3406          */
3407         max_epilog_size += exc_count*16;
3408
3409         return max_epilog_size;
3410 }
3411
3412 guint8 *
3413 mono_arch_emit_prolog (MonoCompile *cfg)
3414 {
3415         MonoMethod *method = cfg->method;
3416         MonoBasicBlock *bb;
3417         MonoMethodSignature *sig;
3418         MonoInst *inst;
3419         int alloc_size, pos, max_offset, i;
3420         guint8 *code;
3421
3422         cfg->code_size =  MAX (((MonoMethodNormal *)method)->header->code_size * 4, 256);
3423         code = cfg->native_code = g_malloc (cfg->code_size);
3424
3425         x86_push_reg (code, X86_EBP);
3426         x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
3427
3428         alloc_size = - cfg->stack_offset;
3429         pos = 0;
3430
3431         if (method->save_lmf) {
3432                 pos += sizeof (MonoLMF);
3433
3434                 /* save the current IP */
3435                 mono_add_patch_info (cfg, code + 1 - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3436                 x86_push_imm (code, 0);
3437
3438                 /* save all caller saved regs */
3439                 x86_push_reg (code, X86_EBP);
3440                 x86_push_reg (code, X86_ESI);
3441                 x86_push_reg (code, X86_EDI);
3442                 x86_push_reg (code, X86_EBX);
3443
3444                 /* save method info */
3445                 x86_push_imm (code, method);
3446
3447                 /* get the address of lmf for the current thread */
3448                 /* 
3449                  * This is performance critical so we try to use some tricks to make
3450                  * it fast.
3451                  */
3452                 if (lmf_tls_offset != -1) {
3453                         /* Load lmf quicky using the GS register */
3454                         x86_prefix (code, X86_GS_PREFIX);
3455                         x86_mov_reg_mem (code, X86_EAX, 0, 4);
3456                         x86_mov_reg_membase (code, X86_EAX, X86_EAX, lmf_tls_offset, 4);
3457                 }
3458                 else {
3459                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3460                                                                  (gpointer)"mono_get_lmf_addr");
3461                         x86_call_code (code, 0);
3462                 }
3463
3464                 /* push lmf */
3465                 x86_push_reg (code, X86_EAX); 
3466                 /* push *lfm (previous_lmf) */
3467                 x86_push_membase (code, X86_EAX, 0);
3468                 /* *(lmf) = ESP */
3469                 x86_mov_membase_reg (code, X86_EAX, 0, X86_ESP, 4);
3470         } else {
3471
3472                 if (cfg->used_int_regs & (1 << X86_EBX)) {
3473                         x86_push_reg (code, X86_EBX);
3474                         pos += 4;
3475                 }
3476
3477                 if (cfg->used_int_regs & (1 << X86_EDI)) {
3478                         x86_push_reg (code, X86_EDI);
3479                         pos += 4;
3480                 }
3481
3482                 if (cfg->used_int_regs & (1 << X86_ESI)) {
3483                         x86_push_reg (code, X86_ESI);
3484                         pos += 4;
3485                 }
3486         }
3487
3488         alloc_size -= pos;
3489
3490         if (alloc_size) {
3491                 /* See mono_emit_stack_alloc */
3492 #ifdef PLATFORM_WIN32
3493                 guint32 remaining_size = alloc_size;
3494                 while (remaining_size >= 0x1000) {
3495                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x1000);
3496                         x86_test_membase_reg (code, X86_ESP, 0, X86_ESP);
3497                         remaining_size -= 0x1000;
3498                 }
3499                 if (remaining_size)
3500                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, remaining_size);
3501 #else
3502                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, alloc_size);
3503 #endif
3504         }
3505
3506         /* compute max_offset in order to use short forward jumps */
3507         max_offset = 0;
3508         if (cfg->opt & MONO_OPT_BRANCH) {
3509                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3510                         MonoInst *ins = bb->code;
3511                         bb->max_offset = max_offset;
3512
3513                         if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3514                                 max_offset += 6;
3515                         /* max alignment for loops */
3516                         if ((cfg->opt & MONO_OPT_LOOP) && bb_is_loop_start (bb))
3517                                 max_offset += LOOP_ALIGNMENT;
3518
3519                         while (ins) {
3520                                 if (ins->opcode == OP_LABEL)
3521                                         ins->inst_c1 = max_offset;
3522                                 
3523                                 max_offset += ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
3524                                 ins = ins->next;
3525                         }
3526                 }
3527         }
3528
3529         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3530                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3531
3532         /* load arguments allocated to register from the stack */
3533         sig = method->signature;
3534         pos = 0;
3535
3536         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3537                 inst = cfg->varinfo [pos];
3538                 if (inst->opcode == OP_REGVAR) {
3539                         x86_mov_reg_membase (code, inst->dreg, X86_EBP, inst->inst_offset, 4);
3540                         if (cfg->verbose_level > 2)
3541                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3542                 }
3543                 pos++;
3544         }
3545
3546         cfg->code_len = code - cfg->native_code;
3547
3548         return code;
3549 }
3550
3551 void
3552 mono_arch_emit_epilog (MonoCompile *cfg)
3553 {
3554         MonoJumpInfo *patch_info;
3555         MonoMethod *method = cfg->method;
3556         MonoMethodSignature *sig = method->signature;
3557         int pos;
3558         guint32 stack_to_pop;
3559         guint8 *code;
3560
3561         code = cfg->native_code + cfg->code_len;
3562
3563         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3564                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3565
3566         /* the code restoring the registers must be kept in sync with CEE_JMP */
3567         pos = 0;
3568         
3569         if (method->save_lmf) {
3570                 gint32 prev_lmf_reg;
3571
3572                 /* Find a spare register */
3573                 switch (sig->ret->type) {
3574                 case MONO_TYPE_I8:
3575                 case MONO_TYPE_U8:
3576                         prev_lmf_reg = X86_EDI;
3577                         cfg->used_int_regs |= (1 << X86_EDI);
3578                         break;
3579                 default:
3580                         prev_lmf_reg = X86_EDX;
3581                         break;
3582                 }
3583
3584                 /* reg = previous_lmf */
3585                 x86_mov_reg_membase (code, prev_lmf_reg, X86_EBP, -32, 4);
3586
3587                 /* ecx = lmf */
3588                 x86_mov_reg_membase (code, X86_ECX, X86_EBP, -28, 4);
3589
3590                 /* *(lmf) = previous_lmf */
3591                 x86_mov_membase_reg (code, X86_ECX, 0, prev_lmf_reg, 4);
3592
3593                 /* restore caller saved regs */
3594                 if (cfg->used_int_regs & (1 << X86_EBX)) {
3595                         x86_mov_reg_membase (code, X86_EBX, X86_EBP, -20, 4);
3596                 }
3597
3598                 if (cfg->used_int_regs & (1 << X86_EDI)) {
3599                         x86_mov_reg_membase (code, X86_EDI, X86_EBP, -16, 4);
3600                 }
3601                 if (cfg->used_int_regs & (1 << X86_ESI)) {
3602                         x86_mov_reg_membase (code, X86_ESI, X86_EBP, -12, 4);
3603                 }
3604
3605                 /* EBP is restored by LEAVE */
3606         } else {
3607                 if (cfg->used_int_regs & (1 << X86_EBX)) {
3608                         pos -= 4;
3609                 }
3610                 if (cfg->used_int_regs & (1 << X86_EDI)) {
3611                         pos -= 4;
3612                 }
3613                 if (cfg->used_int_regs & (1 << X86_ESI)) {
3614                         pos -= 4;
3615                 }
3616
3617                 if (pos)
3618                         x86_lea_membase (code, X86_ESP, X86_EBP, pos);
3619
3620                 if (cfg->used_int_regs & (1 << X86_ESI)) {
3621                         x86_pop_reg (code, X86_ESI);
3622                 }
3623                 if (cfg->used_int_regs & (1 << X86_EDI)) {
3624                         x86_pop_reg (code, X86_EDI);
3625                 }
3626                 if (cfg->used_int_regs & (1 << X86_EBX)) {
3627                         x86_pop_reg (code, X86_EBX);
3628                 }
3629         }
3630
3631         x86_leave (code);
3632
3633         if (CALLCONV_IS_STDCALL (sig->call_convention)) {
3634                 MonoJitArgumentInfo *arg_info = alloca (sizeof (MonoJitArgumentInfo) * (sig->param_count + 1));
3635
3636                 stack_to_pop = mono_arch_get_argument_info (sig, sig->param_count, arg_info);
3637         } else if (MONO_TYPE_ISSTRUCT (cfg->method->signature->ret))
3638                 stack_to_pop = 4;
3639         else
3640                 stack_to_pop = 0;
3641
3642         if (stack_to_pop)
3643                 x86_ret_imm (code, stack_to_pop);
3644         else
3645                 x86_ret (code);
3646
3647         /* add code to raise exceptions */
3648         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3649                 switch (patch_info->type) {
3650                 case MONO_PATCH_INFO_EXC:
3651                         x86_patch (patch_info->ip.i + cfg->native_code, code);
3652                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);
3653                         x86_push_imm (code, patch_info->data.target);
3654                         mono_add_patch_info (cfg, code + 1 - cfg->native_code, MONO_PATCH_INFO_METHOD_REL, (gpointer)patch_info->ip.i);
3655                         x86_push_imm (code, patch_info->ip.i + cfg->native_code);
3656                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3657                         patch_info->data.name = "mono_arch_throw_exception_by_name";
3658                         patch_info->ip.i = code - cfg->native_code;
3659                         x86_jump_code (code, 0);
3660                         break;
3661                 default:
3662                         /* do nothing */
3663                         break;
3664                 }
3665         }
3666
3667         cfg->code_len = code - cfg->native_code;
3668
3669         g_assert (cfg->code_len < cfg->code_size);
3670
3671 }
3672
3673 void
3674 mono_arch_flush_icache (guint8 *code, gint size)
3675 {
3676         /* not needed */
3677 }
3678
3679 void
3680 mono_arch_flush_register_windows (void)
3681 {
3682 }
3683
3684 /*
3685  * Support for fast access to the thread-local lmf structure using the GS
3686  * segment register on NPTL + kernel 2.6.x.
3687  */
3688
3689 static gboolean tls_offset_inited = FALSE;
3690
3691 void
3692 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3693 {
3694 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3695         pthread_t self = pthread_self();
3696         pthread_attr_t attr;
3697         void *staddr = NULL;
3698         size_t stsize = 0;
3699         struct sigaltstack sa;
3700 #endif
3701
3702         if (!tls_offset_inited) {
3703                 guint8 *code;
3704
3705                 tls_offset_inited = TRUE;
3706
3707                 code = (guint8*)mono_get_lmf_addr;
3708
3709                 if (getenv ("MONO_NPTL")) {
3710                         /* 
3711                          * Determine the offset of mono_lfm_addr inside the TLS structures
3712                          * by disassembling the function above.
3713                          */
3714
3715                         /* This is generated by gcc 3.3.2 */
3716                         if ((code [0] == 0x55) && (code [1] == 0x89) && (code [2] == 0xe5) &&
3717                                 (code [3] == 0x65) && (code [4] == 0xa1) && (code [5] == 0x00) &&
3718                                 (code [6] == 0x00) && (code [7] == 0x00) && (code [8] == 0x00) &&
3719                                 (code [9] == 0x8b) && (code [10] == 0x80)) {
3720                                 lmf_tls_offset = *(int*)&(code [11]);
3721                         }
3722                         else
3723                                 /* This is generated by gcc-3.4 */
3724                                 if ((code [0] == 0x55) && (code [1] == 0x89) && (code [2] == 0xe5) &&
3725                                         (code [3] == 0x65) && (code [4] == 0xa1)) {
3726                                         lmf_tls_offset = *(int*)&(code [5]);
3727                                 }
3728                 }
3729         }               
3730
3731 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3732
3733         /* Determine stack boundaries */
3734         if (!mono_running_on_valgrind ()) {
3735 #ifdef HAVE_PTHREAD_GETATTR_NP
3736                 pthread_getattr_np( self, &attr );
3737 #else
3738 #ifdef HAVE_PTHREAD_ATTR_GET_NP
3739                 pthread_attr_get_np( self, &attr );
3740 #elif defined(sun)
3741                 pthread_attr_init( &attr );
3742                 pthread_attr_getstacksize( &attr, &stsize );
3743 #else
3744 #error "Not implemented"
3745 #endif
3746 #endif
3747 #ifndef sun
3748                 pthread_attr_getstack( &attr, &staddr, &stsize );
3749 #endif
3750         }
3751
3752         /* 
3753          * staddr seems to be wrong for the main thread, so we keep the value in
3754          * tls->end_of_stack
3755          */
3756         tls->stack_size = stsize;
3757
3758         /* Setup an alternate signal stack */
3759         tls->signal_stack = g_malloc (SIGNAL_STACK_SIZE);
3760         tls->signal_stack_size = SIGNAL_STACK_SIZE;
3761
3762         sa.ss_sp = tls->signal_stack;
3763         sa.ss_size = SIGNAL_STACK_SIZE;
3764         sa.ss_flags = SS_ONSTACK;
3765         sigaltstack (&sa, NULL);
3766 #endif
3767 }
3768
3769 void
3770 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3771 {
3772 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3773         struct sigaltstack sa;
3774
3775         sa.ss_sp = tls->signal_stack;
3776         sa.ss_size = SIGNAL_STACK_SIZE;
3777         sa.ss_flags = SS_DISABLE;
3778         sigaltstack  (&sa, NULL);
3779
3780         if (tls->signal_stack)
3781                 g_free (tls->signal_stack);
3782 #endif
3783 }
3784
3785 void
3786 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3787 {
3788
3789         /* add the this argument */
3790         if (this_reg != -1) {
3791                 MonoInst *this;
3792                 MONO_INST_NEW (cfg, this, OP_OUTARG);
3793                 this->type = this_type;
3794                 this->sreg1 = this_reg;
3795                 mono_bblock_add_inst (cfg->cbb, this);
3796         }
3797
3798         if (vt_reg != -1) {
3799                 MonoInst *vtarg;
3800                 MONO_INST_NEW (cfg, vtarg, OP_OUTARG);
3801                 vtarg->type = STACK_MP;
3802                 vtarg->sreg1 = vt_reg;
3803                 mono_bblock_add_inst (cfg->cbb, vtarg);
3804         }
3805 }
3806
3807
3808 gint
3809 mono_arch_get_opcode_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3810 {
3811         if (cmethod->klass == mono_defaults.math_class) {
3812                 if (strcmp (cmethod->name, "Sin") == 0)
3813                         return OP_SIN;
3814                 else if (strcmp (cmethod->name, "Cos") == 0)
3815                         return OP_COS;
3816                 else if (strcmp (cmethod->name, "Tan") == 0)
3817                         return OP_TAN;
3818                 else if (strcmp (cmethod->name, "Atan") == 0)
3819                         return OP_ATAN;
3820                 else if (strcmp (cmethod->name, "Sqrt") == 0)
3821                         return OP_SQRT;
3822                 else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8)
3823                         return OP_ABS;
3824 #if 0
3825                 /* OP_FREM is not IEEE compatible */
3826                 else if (strcmp (cmethod->name, "IEEERemainder") == 0)
3827                         return OP_FREM;
3828 #endif
3829                 else
3830                         return -1;
3831         } else {
3832                 return -1;
3833         }
3834         return -1;
3835 }
3836
3837
3838 gboolean
3839 mono_arch_print_tree (MonoInst *tree, int arity)
3840 {
3841         return 0;
3842 }