* StringTest.cs: Added test for Concat when one of the arguments is an
[mono.git] / mono / mini / mini-sparc.c
1 /*
2  * mini-sparc.c: Sparc backend for the Mono code generator
3  *
4  * Authors:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * Modified for SPARC:
9  *   Christopher Taylor (ct@gentoo.org)
10  *   Mark Crichton (crichton@gimp.org)
11  *   Zoltan Varga (vargaz@freemail.hu)
12  *
13  * (C) 2003 Ximian, Inc.
14  */
15 #include "mini.h"
16 #include <string.h>
17
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/debug-helpers.h>
20 #include <mono/utils/mono-math.h>
21
22 #include "mini-sparc.h"
23 #include "inssel.h"
24 #include "trace.h"
25 #include "cpu-sparc.h"
26
27 /*
28  * Sparc V9 means two things:
29  * - the instruction set
30  * - the ABI
31  *
32  * V9 instructions are only usable if the underlying processor is 64 bit. Most Sparc 
33  * processors in use are 64 bit processors. The V9 ABI is only usable if the 
34  * mono executable is a 64 bit executable. So it would make sense to use the 64 bit
35  * instructions without using the 64 bit ABI.
36  */
37
38 /*
39  * Register usage:
40  * - %i0..%i7 hold the incoming arguments, these are never written by JITted code
41  * - %l0..%l7 is used for local register allocation
42  * - %o0..%o6 is used for outgoing arguments
43  * - %o7 and %g1 is used as scratch registers in opcodes
44  * - all floating point registers are used for local register allocation except %f0. 
45  *   Only double precision registers are used.
46  */
47
48 /*
49  * Alignment:
50  * - doubles and longs must be stored in dword aligned locations
51  */
52
53 #if SPARCV9
54 #error "Sparc V9 support not yet implemented."
55 #endif
56
57 int mono_exc_esp_offset = 0;
58
59 #define NOT_IMPLEMENTED g_assert_not_reached ();
60
61 #define ALIGN_TO(val,align) (((val) + ((align) - 1)) & ~((align) - 1))
62
63 const char*
64 mono_arch_regname (int reg) {
65         static const char * rnames[] = {
66                 "sparc_g0", "sparc_g1", "sparc_g2", "sparc_g3", "sparc_g4",
67                 "sparc_g5", "sparc_g6", "sparc_g7", "sparc_o0", "sparc_o1",
68                 "sparc_o2", "sparc_o3", "sparc_o4", "sparc_o5", "sparc_sp",
69                 "sparc_call", "sparc_l0", "sparc_l1", "sparc_l2", "sparc_l3",
70                 "sparc_l4", "sparc_l5", "sparc_l6", "sparc_l7", "sparc_i0",
71                 "sparc_i1", "sparc_i2", "sparc_i3", "sparc_i4", "sparc_i5",
72                 "sparc_fp", "sparc_retadr"
73         };
74         if (reg >= 0 && reg < 32)
75                 return rnames [reg];
76         return "unknown";
77 }
78
79 /*
80  * Initialize the cpu to execute managed code.
81  */
82 void
83 mono_arch_cpu_init (void)
84 {
85 }
86
87 /*
88  * This function returns the optimizations supported on this cpu.
89  */
90 guint32
91 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
92 {
93         guint32 opts = 0;
94         *exclude_mask = 0;
95         return opts;
96 }
97
98 static void
99 mono_sparc_break (void)
100 {
101 }
102
103 static gboolean
104 is_regsize_var (MonoType *t) {
105         if (t->byref)
106                 return TRUE;
107         switch (t->type) {
108         case MONO_TYPE_BOOLEAN:
109         case MONO_TYPE_CHAR:
110         case MONO_TYPE_I1:
111         case MONO_TYPE_U1:
112         case MONO_TYPE_I2:
113         case MONO_TYPE_U2:
114         case MONO_TYPE_I4:
115         case MONO_TYPE_U4:
116         case MONO_TYPE_I:
117         case MONO_TYPE_U:
118                 return TRUE;
119         case MONO_TYPE_OBJECT:
120         case MONO_TYPE_STRING:
121         case MONO_TYPE_CLASS:
122         case MONO_TYPE_SZARRAY:
123         case MONO_TYPE_ARRAY:
124                 return TRUE;
125         case MONO_TYPE_VALUETYPE:
126                 if (t->data.klass->enumtype)
127                         return is_regsize_var (t->data.klass->enum_basetype);
128                 return FALSE;
129         }
130         return FALSE;
131 }
132
133 GList *
134 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
135 {
136         GList *vars = NULL;
137         int i;
138
139         /* 
140          * FIXME: If an argument is allocated to a register, then load it from the
141          * stack in the prolog.
142          */
143
144         for (i = 0; i < cfg->num_varinfo; i++) {
145                 MonoInst *ins = cfg->varinfo [i];
146                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
147
148                 /* unused vars */
149                 if (vmv->range.first_use.abs_pos > vmv->range.last_use.abs_pos)
150                         continue;
151
152                 /* FIXME: Make arguments on stack allocateable to registers */
153                 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL))
154                         continue;
155
156                 /* we can only allocate 32 bit values */
157                 if (is_regsize_var (ins->inst_vtype)) {
158                         g_assert (MONO_VARINFO (cfg, i)->reg == -1);
159                         g_assert (i == vmv->idx);
160                         vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
161                 }
162         }
163
164         return vars;
165 }
166
167 GList *
168 mono_arch_get_global_int_regs (MonoCompile *cfg)
169 {
170         GList *regs = NULL;
171         int i;
172
173         /* FIXME: Use unused input registers for global allocation */
174
175         /* Use %l0..%l3 as global registers */
176
177         for (i = 16; i < 20; ++i)
178                 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
179
180         return regs;
181 }
182
183 /*
184  * mono_arch_regalloc_cost:
185  *
186  *  Return the cost, in number of memory references, of the action of 
187  * allocating the variable VMV into a register during global register
188  * allocation.
189  */
190 guint32
191 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
192 {
193         return 0;
194 }
195
196 #ifdef __GNUC__
197 #define flushi(addr)    __asm__ __volatile__ ("flush %0"::"r"(addr):"memory")
198 #else /* assume Sun's compiler */
199 static void flushi(void *addr)
200 {
201     asm("flush %i0");
202 }
203 #endif
204
205 void
206 mono_arch_flush_icache (guint8 *code, gint size)
207 {
208         /* 
209          * FIXME: This might not work on older machines, but flushing code in dword
210          * chunks in _slow_.
211          */
212            
213         flushi (code);
214
215         /*
216         for (i = 0; i < (size/8); i++)
217                 flushi(code + (i*8));
218         */
219 }
220
221 typedef enum {
222         ArgInIReg,
223         ArgInIRegPair,
224         ArgInSplitRegStack,
225         ArgInFReg,
226         ArgInFRegPair,
227         ArgOnStack,
228         ArgOnStackPair
229 } ArgStorage;
230
231 typedef struct {
232         gint16 offset;
233         /* This needs to be offset by %i0 or %o0 depending on caller/callee */
234         gint8  reg;
235         ArgStorage storage;
236         guint32 vt_offset; /* for valuetypes */
237 } ArgInfo;
238
239 typedef struct {
240         int nargs;
241         guint32 stack_usage;
242         ArgInfo ret;
243         ArgInfo args [1];
244 } CallInfo;
245
246 #define DEBUG(a)
247
248 /* %o0..%o5 */
249 #define PARAM_REGS 6
250
251 static void inline
252 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo, gboolean pair)
253 {
254         ainfo->offset = *stack_size;
255
256         if (!pair) {
257                 if (*gr >= PARAM_REGS) {
258                         ainfo->storage = ArgOnStack;
259                 }
260                 else {
261                         ainfo->storage = ArgInIReg;
262                         ainfo->reg = *gr;
263                         (*gr) ++;
264                 }
265
266                 /* Allways reserve stack space for parameters passed in registers */
267                 (*stack_size) += 4;
268         }
269         else {
270                 if (*gr < PARAM_REGS - 1) {
271                         /* A pair of registers */
272                         ainfo->storage = ArgInIRegPair;
273                         ainfo->reg = *gr;
274                         (*gr) += 2;
275                 }
276                 else if (*gr >= PARAM_REGS) {
277                         /* A pair of stack locations */
278                         ainfo->storage = ArgOnStackPair;
279                         ainfo->offset = *stack_size;
280                 }
281                 else {
282                         ainfo->storage = ArgInSplitRegStack;
283                         ainfo->reg = *gr;
284                         ainfo->offset = *stack_size;
285                         (*gr) ++;
286                 }
287
288                 (*stack_size) += 8;
289         }
290 }
291
292 /*
293  * get_call_info:
294  *
295  *  Obtain information about a call according to the calling convention.
296  * See the "System V ABI, Sparc Processor Supplement" Sparc V8 version document for
297  * more information.
298  */
299 static CallInfo*
300 get_call_info (MonoMethodSignature *sig, gboolean is_pinvoke)
301 {
302         guint32 i, gr, simpletype;
303         int n = sig->hasthis + sig->param_count;
304         guint32 stack_size = 0;
305         CallInfo *cinfo;
306
307         cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
308
309         gr = 0;
310
311         /* this */
312         if (sig->hasthis)
313                 add_general (&gr, &stack_size, cinfo->args + 0, FALSE);
314
315         for (i = 0; i < sig->param_count; ++i) {
316                 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
317
318                 DEBUG(printf("param %d: ", i));
319                 if (sig->params [i]->byref) {
320                         DEBUG(printf("byref\n"));
321                         
322                         add_general (&gr, &stack_size, ainfo, FALSE);
323                         continue;
324                 }
325                 simpletype = sig->params [i]->type;
326         enum_calc_size:
327                 switch (simpletype) {
328                 case MONO_TYPE_BOOLEAN:
329                 case MONO_TYPE_CHAR:
330                 case MONO_TYPE_I1:
331                 case MONO_TYPE_U1:
332                         add_general (&gr, &stack_size, ainfo, FALSE);
333                         /* the value is in the ls byte */
334                         ainfo->offset += 3;
335                         break;
336                 case MONO_TYPE_I2:
337                 case MONO_TYPE_U2:
338                         add_general (&gr, &stack_size, ainfo, FALSE);
339                         /* the value is in the ls word */
340                         ainfo->offset += 2;
341                         break;
342                 case MONO_TYPE_I4:
343                 case MONO_TYPE_U4:
344                 case MONO_TYPE_I:
345                 case MONO_TYPE_U:
346                 case MONO_TYPE_PTR:
347                 case MONO_TYPE_CLASS:
348                 case MONO_TYPE_OBJECT:
349                 case MONO_TYPE_STRING:
350                 case MONO_TYPE_SZARRAY:
351                 case MONO_TYPE_ARRAY:
352                         add_general (&gr, &stack_size, ainfo, FALSE);
353                         break;
354                 case MONO_TYPE_VALUETYPE: {
355                         if (sig->params [i]->data.klass->enumtype) {
356                                 simpletype = sig->params [i]->data.klass->enum_basetype->type;
357                                 goto enum_calc_size;
358                         }
359
360                         add_general (&gr, &stack_size, ainfo, FALSE);
361                         break;
362                 }
363                 case MONO_TYPE_U8:
364                 case MONO_TYPE_I8:
365                         add_general (&gr, &stack_size, ainfo, TRUE);
366                         break;
367                 case MONO_TYPE_R4:
368                         /* single precision values are passed in integer registers */
369                         add_general (&gr, &stack_size, ainfo, FALSE);
370                         break;
371                 case MONO_TYPE_R8:
372                         /* double precision values are passed in a pair of registers */
373                         add_general (&gr, &stack_size, ainfo, TRUE);
374                         break;
375                 default:
376                         g_assert_not_reached ();
377                 }
378         }
379
380         /* return value */
381         {
382                 simpletype = sig->ret->type;
383 enum_retvalue:
384                 switch (simpletype) {
385                 case MONO_TYPE_BOOLEAN:
386                 case MONO_TYPE_I1:
387                 case MONO_TYPE_U1:
388                 case MONO_TYPE_I2:
389                 case MONO_TYPE_U2:
390                 case MONO_TYPE_CHAR:
391                 case MONO_TYPE_I4:
392                 case MONO_TYPE_U4:
393                 case MONO_TYPE_I:
394                 case MONO_TYPE_U:
395                 case MONO_TYPE_PTR:
396                 case MONO_TYPE_CLASS:
397                 case MONO_TYPE_OBJECT:
398                 case MONO_TYPE_SZARRAY:
399                 case MONO_TYPE_ARRAY:
400                 case MONO_TYPE_STRING:
401                         cinfo->ret.storage = ArgInIReg;
402                         cinfo->ret.reg = sparc_i0;
403                         break;
404                 case MONO_TYPE_U8:
405                 case MONO_TYPE_I8:
406                         cinfo->ret.storage = ArgInIRegPair;
407                         cinfo->ret.reg = sparc_i0;
408                         break;
409                 case MONO_TYPE_R4:
410                 case MONO_TYPE_R8:
411                         cinfo->ret.storage = ArgInFReg;
412                         cinfo->ret.reg = sparc_f0;
413                         break;
414                 case MONO_TYPE_VALUETYPE:
415                         if (sig->ret->data.klass->enumtype) {
416                                 simpletype = sig->ret->data.klass->enum_basetype->type;
417                                 goto enum_retvalue;
418                         }
419                         cinfo->ret.storage = ArgOnStack;
420                         break;
421                 case MONO_TYPE_VOID:
422                         break;
423                 default:
424                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
425                 }
426         }
427
428         cinfo->stack_usage = stack_size;
429         return cinfo;
430 }
431
432 /*
433  * Set var information according to the calling convention. sparc version.
434  * The locals var stuff should most likely be split in another method.
435  */
436 void
437 mono_arch_allocate_vars (MonoCompile *m)
438 {
439         MonoMethodSignature *sig;
440         MonoMethodHeader *header;
441         MonoInst *inst;
442         int i, offset, size, align, curinst;
443         int frame_reg = sparc_sp;
444         CallInfo *cinfo;
445  
446         m->frame_reg = frame_reg;
447
448         header = ((MonoMethodNormal *)m->method)->header;
449
450         sig = m->method->signature;
451
452         cinfo = get_call_info (sig, FALSE);
453
454         if (sig->ret->type != MONO_TYPE_VOID) {
455                 switch (cinfo->ret.storage) {
456                 case ArgInIReg:
457                 case ArgInFReg:
458                 case ArgInIRegPair:
459                         m->ret->opcode = OP_REGVAR;
460                         m->ret->inst_c0 = cinfo->ret.reg;
461                         break;
462                 case ArgOnStack:
463                         /* valuetypes */
464                         m->ret->opcode = OP_REGOFFSET;
465                         m->ret->inst_basereg = sparc_fp;
466                         m->ret->inst_offset = 64;
467                         break;
468                 default:
469                         NOT_IMPLEMENTED;
470                 }
471         }
472
473         /*
474          * We use the Sparc V8 calling conventions for managed code as well.
475          * FIXME: Use something more optimized.
476          */
477
478         offset = 64; /* register save area */
479         offset += 4; /* struct/union return pointer */
480
481         /* add parameter area size for called functions */
482         if (m->param_area < 24)
483                 /* Reserve space for the first 6 arguments even if it is unused */
484                 offset += 24;
485         else
486                 offset += m->param_area;
487         
488         curinst = m->locals_start;
489         for (i = curinst; i < m->num_varinfo; ++i) {
490                 inst = m->varinfo [i];
491
492                 if (inst->opcode == OP_REGVAR)
493                         continue;
494
495                 /* inst->unused indicates native sized value types, this is used by the
496                 * pinvoke wrappers when they call functions returning structure */
497                 if (inst->unused && MONO_TYPE_ISSTRUCT (inst->inst_vtype))
498                         size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
499                 else
500                         size = mono_type_stack_size (inst->inst_vtype, &align);
501
502                 /* 
503                  * This is needed since structures containing doubles must be doubleword 
504          * aligned.
505                  * FIXME: Do this only if needed.
506                  */
507                 if (MONO_TYPE_ISSTRUCT (inst->inst_vtype))
508                         align = 8;
509
510                 offset += align - 1;
511                 offset &= ~(align - 1);
512                 inst->inst_offset = offset;
513                 inst->opcode = OP_REGOFFSET;
514                 inst->inst_basereg = frame_reg;
515                 offset += size;
516                 //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
517         }
518
519         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
520                 inst = m->varinfo [i];
521                 if (inst->opcode != OP_REGVAR) {
522                         ArgInfo *ainfo = &cinfo->args [i];
523                         gboolean inreg = TRUE;
524                         MonoType *arg_type;
525
526                         if (sig->hasthis && (i == 0))
527                                 arg_type = mono_defaults.object_class;
528                         else
529                                 arg_type = sig->params [i - sig->hasthis];
530
531                         if ((arg_type->type == MONO_TYPE_R4) 
532                                 || (arg_type->type == MONO_TYPE_R8))
533                                 /*
534                                  * Since float arguments are passed in integer registers, we need to
535                                  * save them to the stack in the prolog.
536                                  */
537                                 inreg = FALSE;
538
539                         if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
540                                 inreg = FALSE;
541
542                         if (MONO_TYPE_ISSTRUCT (arg_type))
543                                 /* FIXME: this isn't needed */
544                                 inreg = FALSE;
545
546                         switch (ainfo->storage) {
547                         case ArgInIReg:
548                         case ArgInIRegPair:
549                                 if (inreg) {
550                                         inst->opcode = OP_REGVAR;
551                                         inst->dreg = sparc_i0 + ainfo->reg;
552                                         break;
553                                 }
554                                 else {
555                                         /* Fall through */
556                                 }
557                         case ArgOnStack:
558                         case ArgOnStackPair:
559                         case ArgInSplitRegStack:
560                                 /* Split arguments are saved to the stack in the prolog */
561                                 inst->opcode = OP_REGOFFSET;
562                                 /* in parent frame */
563                                 inst->inst_basereg = sparc_fp;
564                                 inst->inst_offset = ainfo->offset + 68;
565
566                                 if (arg_type->type == MONO_TYPE_R8) {
567                                         /* 
568                                          * It is very hard to load doubles from non-doubleword aligned
569                                          * memory locations. So if the offset is misaligned, we copy the
570                                          * argument to a stack location in the prolog.
571                                          */
572                                         if (inst->inst_offset % 8) {
573                                                 inst->inst_basereg = sparc_sp;
574                                                 align = 8;
575                                                 offset += align - 1;
576                                                 offset &= ~(align - 1);
577                                                 inst->inst_offset = offset;
578                                                 offset += 8;
579                                         }
580                                 }
581                                 break;
582                         default:
583                                 NOT_IMPLEMENTED;
584                         }
585
586                         if (MONO_TYPE_ISSTRUCT (arg_type)) {
587                                 /* Add a level of indirection */
588                                 /*
589                                  * It would be easier to add OP_LDIND_I here, but ldind_i instructions
590                                  * are destructively modified in a lot of places in inssel.brg.
591                                  */
592                                 MonoInst *indir;
593                                 MONO_INST_NEW (m, indir, 0);
594                                 *indir = *inst;
595                                 inst->opcode = OP_SPARC_INARG_VT;
596                                 inst->inst_left = indir;
597                         }
598                 }
599         }
600
601         /* align the stack size to 8 bytes */
602         offset += 8 - 1;
603         offset &= ~(8 - 1);
604
605         /* Add a properly aligned dword for use by int<->float conversion opcodes */
606         offset += 8;
607
608         m->stack_offset = offset;
609
610         g_free (cinfo);
611 }
612
613 /* 
614  * take the arguments and generate the arch-specific
615  * instructions to properly call the function in call.
616  * This includes pushing, moving arguments to the right register
617  * etc.
618  */
619 MonoCallInst*
620 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
621         MonoInst *arg, *in;
622         MonoMethodSignature *sig;
623         int i, n;
624         CallInfo *cinfo;
625         ArgInfo *ainfo;
626         guint32 extra_space = 0;
627
628         sig = call->signature;
629         n = sig->param_count + sig->hasthis;
630         
631         cinfo = get_call_info (sig, sig->pinvoke);
632
633         for (i = 0; i < n; ++i) {
634                 ainfo = cinfo->args + i;
635                 if (is_virtual && i == 0) {
636                         /* the argument will be attached to the call instruction */
637                         in = call->args [i];
638                 } else {
639                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
640                         in = call->args [i];
641                         arg->cil_code = in->cil_code;
642                         arg->inst_left = in;
643                         arg->type = in->type;
644                         /* prepend, we'll need to reverse them later */
645                         arg->next = call->out_args;
646                         call->out_args = arg;
647
648                         if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(sig->params [i - sig->hasthis]))) {
649                                 MonoInst *inst;
650                                 gint align;
651                                 guint32 offset, pad;
652                                 guint32 size = mono_type_stack_size (&in->klass->byval_arg, &align);
653
654                                 /* 
655                                  * We use OP_OUTARG_VT to copy the valuetype to a stack location, then
656                                  * use the normal OUTARG opcodes to pass the address of the location to
657                                  * the callee.
658                                  */
659                                 MONO_INST_NEW (cfg, inst, OP_OUTARG_VT);
660                                 inst->inst_left = in;
661
662                                 /* The first 6 argument locations are reserved */
663                                 if (cinfo->stack_usage < 24)
664                                         cinfo->stack_usage = 24;
665
666                                 offset = ALIGN_TO (68 + cinfo->stack_usage, align);
667                                 pad = offset - (68 + cinfo->stack_usage);
668
669                                 inst->inst_c1 = offset;
670                                 inst->unused = size;
671                                 arg->inst_left = inst;
672
673                                 cinfo->stack_usage += size;
674                                 cinfo->stack_usage += pad;
675                         }
676
677                         switch (ainfo->storage) {
678                         case ArgInIReg:
679                         case ArgInFReg:
680                         case ArgInIRegPair:
681                                 if (ainfo->storage == ArgInIRegPair)
682                                         arg->opcode = OP_SPARC_OUTARG_REGPAIR;
683                                 arg->unused = sparc_o0 + ainfo->reg;
684                                 /* outgoing arguments begin at sp+68 */
685                                 arg->inst_basereg = sparc_sp;
686                                 arg->inst_imm = 68 + ainfo->offset;
687                                 call->used_iregs |= 1 << ainfo->reg;
688
689                                 if ((i >= sig->hasthis) && (sig->params [i - sig->hasthis]->type == MONO_TYPE_R8)) {
690                                         /*
691                                          * The OUTARG (freg) implementation needs an extra dword to store
692                                          * the temporary value.
693                                          */
694                                         extra_space += 8;
695                                 }
696                                 break;
697                         case ArgOnStack:
698                                 arg->opcode = OP_SPARC_OUTARG_MEM;
699                                 arg->inst_basereg = sparc_sp;
700                                 arg->inst_imm = 68 + ainfo->offset;
701                                 break;
702                         case ArgOnStackPair:
703                                 arg->opcode = OP_SPARC_OUTARG_MEMPAIR;
704                                 arg->inst_basereg = sparc_sp;
705                                 arg->inst_imm = 68 + ainfo->offset;
706                                 break;
707                         case ArgInSplitRegStack:
708                                 arg->opcode = OP_SPARC_OUTARG_SPLIT_REG_STACK;
709                                 arg->unused = sparc_o0 + ainfo->reg;
710                                 arg->inst_basereg = sparc_sp;
711                                 arg->inst_imm = 68 + ainfo->offset;
712                                 call->used_iregs |= 1 << ainfo->reg;
713                                 break;
714                         default:
715                                 NOT_IMPLEMENTED;
716                         }
717                 }
718         }
719
720         /*
721          * Reverse the call->out_args list.
722          */
723         {
724                 MonoInst *prev = NULL, *list = call->out_args, *next;
725                 while (list) {
726                         next = list->next;
727                         list->next = prev;
728                         prev = list;
729                         list = next;
730                 }
731                 call->out_args = prev;
732         }
733         call->stack_usage = cinfo->stack_usage + extra_space;
734         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
735         cfg->flags |= MONO_CFG_HAS_CALLS;
736
737         g_free (cinfo);
738         return call;
739 }
740
741 /* Map opcode to the sparc condition codes */
742 static inline SparcCond
743 opcode_to_sparc_cond (int opcode)
744 {
745         switch (opcode) {
746
747         case OP_FBGE:
748                 return sparc_fbge;
749         case OP_FBLE:
750                 return sparc_fble;
751         case OP_FBEQ:
752         case OP_FCEQ:
753                 return sparc_fbe;
754         case OP_FBLT:
755         case OP_FCLT:
756         case OP_FCLT_UN:
757                 return sparc_fbl;
758         case OP_FBGT:
759         case OP_FCGT:
760         case OP_FCGT_UN:
761                 return sparc_fbg;
762         case CEE_BEQ:
763         case OP_CEQ:
764                 return sparc_be;
765         case CEE_BNE_UN:
766                 return sparc_bne;
767         case CEE_BLT:
768         case OP_CLT:
769                 return sparc_bl;
770         case CEE_BLT_UN:
771         case OP_CLT_UN:
772                 return sparc_blu;
773         case CEE_BGT:
774         case OP_CGT:
775                 return sparc_bg;
776         case CEE_BGT_UN:
777         case OP_CGT_UN:
778                 return sparc_bgu;
779         case CEE_BGE:
780                 return sparc_bge;
781         case CEE_BGE_UN:
782                 return sparc_beu;
783         case CEE_BLE:
784                 return sparc_ble;
785         case CEE_BLE_UN:
786                 return sparc_bleu;
787         default:
788                 g_assert_not_reached ();
789                 return sparc_be;
790         }
791 }
792
793 #define EMIT_COND_BRANCH_GENERAL(ins,bop,cond) \
794 if (ins->flags & MONO_INST_BRLABEL) { \
795         if (ins->inst_i0->inst_c0) { \
796            gint32 disp = (ins->inst_i0->inst_c0 - ((guint8*)code - cfg->native_code)) >> 2; \
797            g_assert (sparc_is_imm22 (disp)); \
798            sparc_ ## bop (code, 1, cond, disp); \
799         } else { \
800                 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
801             sparc_ ## bop (code, 1, cond, 0); \
802         } \
803                 sparc_nop (code); \
804 } else { \
805         if (ins->inst_true_bb->native_offset) { \
806            gint32 disp = (ins->inst_true_bb->native_offset - ((guint8*)code - cfg->native_code)) >> 2; \
807            g_assert (sparc_is_imm22 (disp)); \
808            sparc_ ## bop (code, 1, cond, disp); \
809         } else { \
810                 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
811             sparc_ ## bop (code, 1, cond, 0); \
812         } \
813                 sparc_nop (code); \
814 }
815
816 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_GENERAL((ins),branch,(cond))
817
818 #define EMIT_FLOAT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_GENERAL((ins),fbranch,(cond))
819
820 #define EMIT_ALU_IMM(ins,op,setcc) do { \
821                         if (sparc_is_imm13 ((ins)->inst_imm)) \
822                                 sparc_ ## op ## _imm (code, (setcc), (ins)->sreg1, ins->inst_imm, (ins)->dreg); \
823                         else { \
824                                 sparc_set (code, ins->inst_imm, sparc_o7); \
825                                 sparc_ ## op (code, (setcc), (ins)->sreg1, sparc_o7, (ins)->dreg); \
826                         } \
827 } while (0);
828
829 #define EMIT_LOAD_MEMBASE(ins,op) do { \
830                         if (sparc_is_imm13 (ins->inst_offset)) \
831                                 sparc_ ## op ## _imm (code, ins->inst_basereg, ins->inst_offset, ins->dreg); \
832                         else { \
833                                 sparc_set (code, ins->inst_offset, sparc_o7); \
834                                 sparc_ ## op (code, ins->inst_basereg, sparc_o7, ins->dreg); \
835                         } \
836 } while (0);
837
838 /* max len = 5 */
839 #define EMIT_STORE_MEMBASE_IMM(ins,op) do { \
840                         guint32 sreg; \
841                         if (ins->inst_imm == 0) \
842                                 sreg = sparc_g0; \
843                         else { \
844                                 sparc_set (code, ins->inst_imm, sparc_o7); \
845                                 sreg = sparc_o7; \
846                         } \
847                         if (!sparc_is_imm13 (ins->inst_offset)) { \
848                                 sparc_set (code, ins->inst_offset, sparc_g1); \
849                                 sparc_ ## op (code, sreg, ins->inst_destbasereg, sparc_g1); \
850                         } \
851                         else \
852                                 sparc_ ## op ## _imm (code, sreg, ins->inst_destbasereg, ins->inst_offset); \
853                                                                                                                                                                                  } while (0);
854
855 #define EMIT_STORE_MEMBASE_REG(ins,op) do { \
856                         if (!sparc_is_imm13 (ins->inst_offset)) { \
857                                 sparc_set (code, ins->inst_offset, sparc_o7); \
858                                 sparc_ ## op (code, ins->sreg1, ins->inst_destbasereg, sparc_o7); \
859                         } \
860                                   else \
861                                 sparc_ ## op ## _imm (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset); \
862                                                                                                                                                                                  } while (0);
863
864
865 /* emit an exception if condition is fail */
866 #define EMIT_COND_SYSTEM_EXCEPTION(cond,signed,exc_name)            \
867         do {                                                        \
868                 mono_add_patch_info (cfg, code - cfg->native_code,   \
869                                     MONO_PATCH_INFO_EXC, exc_name);  \
870                 x86_branch32 (code, cond, 0, signed);               \
871         } while (0); 
872
873 #define EMIT_FPCOMPARE(code) do { \
874         x86_fcompp (code); \
875         x86_fnstsw (code); \
876         x86_alu_reg_imm (code, X86_AND, X86_EAX, 0x4500); \
877 } while (0); 
878
879 static void
880 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
881 {
882         MonoInst *ins, *last_ins = NULL;
883         ins = bb->code;
884
885         /* short circuit this for now */
886         return;
887
888         while (ins) {
889
890                 switch (ins->opcode) {
891                 case OP_MUL_IMM: 
892                         /* remove unnecessary multiplication with 1 */
893                         if (ins->inst_imm == 1) {
894                                 if (ins->dreg != ins->sreg1) {
895                                         ins->opcode = OP_MOVE;
896                                 } else {
897                                         last_ins->next = ins->next;                             
898                                         ins = ins->next;                                
899                                         continue;
900                                 }
901                         }
902                         break;
903                 case OP_LOAD_MEMBASE:
904                 case OP_LOADI4_MEMBASE:
905                         /* 
906                          * OP_STORE_MEMBASE_REG reg, offset(basereg) 
907                          * OP_LOAD_MEMBASE offset(basereg), reg
908                          */
909                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG 
910                                          || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
911                             ins->inst_basereg == last_ins->inst_destbasereg &&
912                             ins->inst_offset == last_ins->inst_offset) {
913                                 if (ins->dreg == last_ins->sreg1) {
914                                         last_ins->next = ins->next;                             
915                                         ins = ins->next;                                
916                                         continue;
917                                 } else {
918                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
919                                         ins->opcode = OP_MOVE;
920                                         ins->sreg1 = last_ins->sreg1;
921                                 }
922
923                         /* 
924                          * Note: reg1 must be different from the basereg in the second load
925                          * OP_LOAD_MEMBASE offset(basereg), reg1
926                          * OP_LOAD_MEMBASE offset(basereg), reg2
927                          * -->
928                          * OP_LOAD_MEMBASE offset(basereg), reg1
929                          * OP_MOVE reg1, reg2
930                          */
931                         } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
932                                            || last_ins->opcode == OP_LOAD_MEMBASE) &&
933                               ins->inst_basereg != last_ins->dreg &&
934                               ins->inst_basereg == last_ins->inst_basereg &&
935                               ins->inst_offset == last_ins->inst_offset) {
936
937                                 if (ins->dreg == last_ins->dreg) {
938                                         last_ins->next = ins->next;                             
939                                         ins = ins->next;                                
940                                         continue;
941                                 } else {
942                                         ins->opcode = OP_MOVE;
943                                         ins->sreg1 = last_ins->dreg;
944                                 }
945
946                                 //g_assert_not_reached ();
947
948 #if 0
949                         /* 
950                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
951                          * OP_LOAD_MEMBASE offset(basereg), reg
952                          * -->
953                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
954                          * OP_ICONST reg, imm
955                          */
956                         } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
957                                                 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
958                                    ins->inst_basereg == last_ins->inst_destbasereg &&
959                                    ins->inst_offset == last_ins->inst_offset) {
960                                 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
961                                 ins->opcode = OP_ICONST;
962                                 ins->inst_c0 = last_ins->inst_imm;
963                                 g_assert_not_reached (); // check this rule
964 #endif
965                         }
966                         break;
967                 case OP_LOADU1_MEMBASE:
968                 case OP_LOADI1_MEMBASE:
969                         if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
970                                         ins->inst_basereg == last_ins->inst_destbasereg &&
971                                         ins->inst_offset == last_ins->inst_offset) {
972                                 if (ins->dreg == last_ins->sreg1) {
973                                         last_ins->next = ins->next;                             
974                                         ins = ins->next;                                
975                                         continue;
976                                 } else {
977                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
978                                         ins->opcode = OP_MOVE;
979                                         ins->sreg1 = last_ins->sreg1;
980                                 }
981                         }
982                         break;
983                 case OP_LOADU2_MEMBASE:
984                 case OP_LOADI2_MEMBASE:
985                         if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
986                                         ins->inst_basereg == last_ins->inst_destbasereg &&
987                                         ins->inst_offset == last_ins->inst_offset) {
988                                 if (ins->dreg == last_ins->sreg1) {
989                                         last_ins->next = ins->next;                             
990                                         ins = ins->next;                                
991                                         continue;
992                                 } else {
993                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
994                                         ins->opcode = OP_MOVE;
995                                         ins->sreg1 = last_ins->sreg1;
996                                 }
997                         }
998                         break;
999                 case CEE_CONV_I4:
1000                 case CEE_CONV_U4:
1001                 case OP_MOVE:
1002                         /* 
1003                          * OP_MOVE reg, reg 
1004                          */
1005                         if (ins->dreg == ins->sreg1) {
1006                                 if (last_ins)
1007                                         last_ins->next = ins->next;                             
1008                                 ins = ins->next;
1009                                 continue;
1010                         }
1011                         /* 
1012                          * OP_MOVE sreg, dreg 
1013                          * OP_MOVE dreg, sreg
1014                          */
1015                         if (last_ins && last_ins->opcode == OP_MOVE &&
1016                             ins->sreg1 == last_ins->dreg &&
1017                             ins->dreg == last_ins->sreg1) {
1018                                 last_ins->next = ins->next;                             
1019                                 ins = ins->next;                                
1020                                 continue;
1021                         }
1022                         break;
1023                 }
1024                 last_ins = ins;
1025                 ins = ins->next;
1026         }
1027         bb->last_ins = last_ins;
1028 }
1029
1030 #undef DEBUG
1031 #define DEBUG(a) if (cfg->verbose_level > 1) a
1032 //#define DEBUG(a)
1033 #define reg_is_freeable(r) (TRUE)
1034 #define freg_is_freeable(r) (TRUE)
1035
1036 typedef struct {
1037         int born_in;
1038         int killed_in;
1039         int last_use;
1040         int prev_use;
1041 } RegTrack;
1042
1043 static const char*const * ins_spec = sparc_desc;
1044
1045 static void
1046 print_ins (int i, MonoInst *ins)
1047 {
1048         const char *spec = ins_spec [ins->opcode];
1049         g_print ("\t%-2d %s", i, mono_inst_name (ins->opcode));
1050         if (spec [MONO_INST_DEST]) {
1051                 if (ins->dreg >= MONO_MAX_IREGS)
1052                         g_print (" R%d <-", ins->dreg);
1053                 else
1054                         if (spec [MONO_INST_DEST] == 'b')
1055                                 g_print (" [%s + 0x%x] <-", mono_arch_regname (ins->dreg), ins->inst_offset);
1056                 else
1057                         g_print (" %s <-", mono_arch_regname (ins->dreg));
1058         }
1059         if (spec [MONO_INST_SRC1]) {
1060                 if (ins->sreg1 >= MONO_MAX_IREGS)
1061                         g_print (" R%d", ins->sreg1);
1062                 else
1063                         if (spec [MONO_INST_SRC1] == 'b')
1064                                 g_print (" [%s + 0x%x]", mono_arch_regname (ins->sreg1), ins->inst_offset);
1065                 else
1066                         g_print (" %s", mono_arch_regname (ins->sreg1));
1067         }
1068         if (spec [MONO_INST_SRC2]) {
1069                 if (ins->sreg2 >= MONO_MAX_IREGS)
1070                         g_print (" R%d", ins->sreg2);
1071                 else
1072                         g_print (" %s", mono_arch_regname (ins->sreg2));
1073         }
1074         if (spec [MONO_INST_CLOB])
1075                 g_print (" clobbers: %c", spec [MONO_INST_CLOB]);
1076         g_print ("\n");
1077 }
1078
1079 static void
1080 print_regtrack (RegTrack *t, int num)
1081 {
1082         int i;
1083         char buf [32];
1084         const char *r;
1085         
1086         for (i = 0; i < num; ++i) {
1087                 if (!t [i].born_in)
1088                         continue;
1089                 if (i >= MONO_MAX_IREGS) {
1090                         g_snprintf (buf, sizeof(buf), "R%d", i);
1091                         r = buf;
1092                 } else
1093                         r = mono_arch_regname (i);
1094                 g_print ("liveness: %s [%d - %d]\n", r, t [i].born_in, t[i].last_use);
1095         }
1096 }
1097
1098 typedef struct InstList InstList;
1099
1100 struct InstList {
1101         InstList *prev;
1102         InstList *next;
1103         MonoInst *data;
1104 };
1105
1106 static inline InstList*
1107 inst_list_prepend (MonoMemPool *pool, InstList *list, MonoInst *data)
1108 {
1109         InstList *item = mono_mempool_alloc (pool, sizeof (InstList));
1110         item->data = data;
1111         item->prev = NULL;
1112         item->next = list;
1113         if (list)
1114                 list->prev = item;
1115         return item;
1116 }
1117
1118 #define STACK_OFFSETS_POSITIVE
1119
1120 /*
1121  * returns the offset used by spillvar. It allocates a new
1122  * spill variable if necessary. Likely incorrect for sparc.
1123  */
1124 static int
1125 mono_spillvar_offset (MonoCompile *cfg, int spillvar)
1126 {
1127         MonoSpillInfo **si, *info;
1128         int i = 0;
1129
1130         si = &cfg->spill_info; 
1131         
1132         while (i <= spillvar) {
1133
1134                 if (!*si) {
1135                         *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
1136                         info->next = NULL;
1137 #ifdef STACK_OFFSETS_POSITIVE
1138                         cfg->stack_offset += sizeof (gpointer);
1139 #else
1140                         cfg->stack_offset -= sizeof (gpointer);
1141 #endif
1142                         info->offset = cfg->stack_offset;
1143                 }
1144
1145                 if (i == spillvar)
1146                         return (*si)->offset;
1147
1148                 i++;
1149                 si = &(*si)->next;
1150         }
1151
1152         g_assert_not_reached ();
1153         return 0;
1154 }
1155
1156 static int
1157 mono_spillvar_offset_float (MonoCompile *cfg, int spillvar)
1158 {
1159         MonoSpillInfo **si, *info;
1160         int i = 0;
1161
1162         si = &cfg->spill_info_float; 
1163         
1164         while (i <= spillvar) {
1165
1166                 if (!*si) {
1167                         *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
1168                         info->next = NULL;
1169                         cfg->stack_offset += 7;
1170                         cfg->stack_offset &= ~7;
1171                         info->offset = cfg->stack_offset;
1172                         cfg->stack_offset += sizeof (double);
1173                 }
1174
1175                 if (i == spillvar)
1176                         return (*si)->offset;
1177
1178                 i++;
1179                 si = &(*si)->next;
1180         }
1181
1182         g_assert_not_reached ();
1183         return 0;
1184 }
1185
1186 /*
1187  * Force the spilling of the variable in the symbolic register 'reg'.
1188  */
1189 static int
1190 get_register_force_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, int reg)
1191 {
1192         MonoInst *load;
1193         int i, sel, spill;
1194         
1195         sel = cfg->rs->iassign [reg];
1196         /*i = cfg->rs->isymbolic [sel];
1197         g_assert (i == reg);*/
1198         i = reg;
1199         spill = ++cfg->spill_count;
1200         cfg->rs->iassign [i] = -spill - 1;
1201         mono_regstate_free_int (cfg->rs, sel);
1202         /* we need to create a spill var and insert a load to sel after the current instruction */
1203         MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE);
1204         load->dreg = sel;
1205         load->inst_basereg = cfg->frame_reg;
1206         load->inst_offset = mono_spillvar_offset (cfg, spill);
1207         if (item->prev) {
1208                 while (ins->next != item->prev->data)
1209                         ins = ins->next;
1210         }
1211         load->next = ins->next;
1212         ins->next = load;
1213         DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel)));
1214         i = mono_regstate_alloc_int (cfg->rs, 1 << sel);
1215         g_assert (i == sel);
1216
1217         return sel;
1218 }
1219
1220 static int
1221 get_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, guint32 regmask, int reg)
1222 {
1223         MonoInst *load;
1224         int i, sel, spill;
1225
1226         DEBUG (g_print ("start regmask to assign R%d: 0x%08x (R%d <- R%d R%d)\n", reg, regmask, ins->dreg, ins->sreg1, ins->sreg2));
1227         /* exclude the registers in the current instruction */
1228         if (reg != ins->sreg1 && (reg_is_freeable (ins->sreg1) || (ins->sreg1 >= MONO_MAX_IREGS && cfg->rs->iassign [ins->sreg1] >= 0))) {
1229                 if (ins->sreg1 >= MONO_MAX_IREGS)
1230                         regmask &= ~ (1 << cfg->rs->iassign [ins->sreg1]);
1231                 else
1232                         regmask &= ~ (1 << ins->sreg1);
1233                 DEBUG (g_print ("excluding sreg1 %s\n", mono_arch_regname (ins->sreg1)));
1234         }
1235         if (reg != ins->sreg2 && (reg_is_freeable (ins->sreg2) || (ins->sreg2 >= MONO_MAX_IREGS && cfg->rs->iassign [ins->sreg2] >= 0))) {
1236                 if (ins->sreg2 >= MONO_MAX_IREGS)
1237                         regmask &= ~ (1 << cfg->rs->iassign [ins->sreg2]);
1238                 else
1239                         regmask &= ~ (1 << ins->sreg2);
1240                 DEBUG (g_print ("excluding sreg2 %s %d\n", mono_arch_regname (ins->sreg2), ins->sreg2));
1241         }
1242         if (reg != ins->dreg && reg_is_freeable (ins->dreg)) {
1243                 regmask &= ~ (1 << ins->dreg);
1244                 DEBUG (g_print ("excluding dreg %s\n", mono_arch_regname (ins->dreg)));
1245         }
1246
1247         DEBUG (g_print ("available regmask: 0x%08x\n", regmask));
1248         g_assert (regmask); /* need at least a register we can free */
1249         sel = -1;
1250         /* we should track prev_use and spill the register that's farther */
1251         for (i = 0; i < MONO_MAX_IREGS; ++i) {
1252                 if (regmask & (1 << i)) {
1253                         sel = i;
1254                         DEBUG (g_print ("selected register %s has assignment %d\n", mono_arch_regname (sel), cfg->rs->iassign [sel]));
1255                         break;
1256                 }
1257         }
1258         i = cfg->rs->isymbolic [sel];
1259         spill = ++cfg->spill_count;
1260         cfg->rs->iassign [i] = -spill - 1;
1261         mono_regstate_free_int (cfg->rs, sel);
1262         /* we need to create a spill var and insert a load to sel after the current instruction */
1263         MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE);
1264         load->dreg = sel;
1265         load->inst_basereg = cfg->frame_reg;
1266         load->inst_offset = mono_spillvar_offset (cfg, spill);
1267         if (item->prev) {
1268                 while (ins->next != item->prev->data)
1269                         ins = ins->next;
1270         }
1271         load->next = ins->next;
1272         ins->next = load;
1273         DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel)));
1274         i = mono_regstate_alloc_int (cfg->rs, 1 << sel);
1275         g_assert (i == sel);
1276         
1277         return sel;
1278 }
1279
1280 static int
1281 get_float_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, guint32 regmask, int reg)
1282 {
1283         MonoInst *load;
1284         int i, sel, spill;
1285
1286         DEBUG (g_print ("start regmask to assign R%d: 0x%08x (R%d <- R%d R%d)\n", reg, regmask, ins->dreg, ins->sreg1, ins->sreg2));
1287         /* exclude the registers in the current instruction */
1288         if (reg != ins->sreg1 && (freg_is_freeable (ins->sreg1) || (ins->sreg1 >= MONO_MAX_FREGS && cfg->rs->fassign [ins->sreg1] >= 0))) {
1289                 if (ins->sreg1 >= MONO_MAX_FREGS)
1290                         regmask &= ~ (1 << cfg->rs->fassign [ins->sreg1]);
1291                 else
1292                         regmask &= ~ (1 << ins->sreg1);
1293                 DEBUG (g_print ("excluding sreg1 %s\n", mono_arch_regname (ins->sreg1)));
1294         }
1295         if (reg != ins->sreg2 && (freg_is_freeable (ins->sreg2) || (ins->sreg2 >= MONO_MAX_FREGS && cfg->rs->fassign [ins->sreg2] >= 0))) {
1296                 if (ins->sreg2 >= MONO_MAX_FREGS)
1297                         regmask &= ~ (1 << cfg->rs->fassign [ins->sreg2]);
1298                 else
1299                         regmask &= ~ (1 << ins->sreg2);
1300                 DEBUG (g_print ("excluding sreg2 %s %d\n", mono_arch_regname (ins->sreg2), ins->sreg2));
1301         }
1302         if (reg != ins->dreg && freg_is_freeable (ins->dreg)) {
1303                 regmask &= ~ (1 << ins->dreg);
1304                 DEBUG (g_print ("excluding dreg %s\n", mono_arch_regname (ins->dreg)));
1305         }
1306
1307         DEBUG (g_print ("available regmask: 0x%08x\n", regmask));
1308         g_assert (regmask); /* need at least a register we can free */
1309         sel = -1;
1310         /* we should track prev_use and spill the register that's farther */
1311         for (i = 0; i < MONO_MAX_FREGS; ++i) {
1312                 if (regmask & (1 << i)) {
1313                         sel = i;
1314                         DEBUG (g_print ("selected register %s has assignment %d\n", mono_arch_regname (sel), cfg->rs->fassign [sel]));
1315                         break;
1316                 }
1317         }
1318         i = cfg->rs->fsymbolic [sel];
1319         spill = ++cfg->spill_count;
1320         cfg->rs->fassign [i] = -spill - 1;
1321         mono_regstate_free_float(cfg->rs, sel);
1322         /* we need to create a spill var and insert a load to sel after the current instruction */
1323         MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
1324         load->dreg = sel;
1325         load->inst_basereg = cfg->frame_reg;
1326         load->inst_offset = mono_spillvar_offset_float (cfg, spill);
1327         if (item->prev) {
1328                 while (ins->next != item->prev->data)
1329                         ins = ins->next;
1330         }
1331         load->next = ins->next;
1332         ins->next = load;
1333         DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel)));
1334         i = mono_regstate_alloc_float (cfg->rs, 1 << sel);
1335         g_assert (i == sel);
1336         
1337         return sel;
1338 }
1339
1340 static MonoInst*
1341 create_copy_ins (MonoCompile *cfg, int dest, int src, MonoInst *ins)
1342 {
1343         MonoInst *copy;
1344         MONO_INST_NEW (cfg, copy, OP_MOVE);
1345         copy->dreg = dest;
1346         copy->sreg1 = src;
1347         if (ins) {
1348                 copy->next = ins->next;
1349                 ins->next = copy;
1350         }
1351         DEBUG (g_print ("\tforced copy from %s to %s\n", mono_arch_regname (src), mono_arch_regname (dest)));
1352         return copy;
1353 }
1354
1355 static MonoInst*
1356 create_copy_ins_float (MonoCompile *cfg, int dest, int src, MonoInst *ins)
1357 {
1358         MonoInst *copy;
1359         MONO_INST_NEW (cfg, copy, OP_FMOVE);
1360         copy->dreg = dest;
1361         copy->sreg1 = src;
1362         if (ins) {
1363                 copy->next = ins->next;
1364                 ins->next = copy;
1365         }
1366         DEBUG (g_print ("\tforced copy from %s to %s\n", mono_arch_regname (src), mono_arch_regname (dest)));
1367         return copy;
1368 }
1369
1370 static MonoInst*
1371 create_spilled_store (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins)
1372 {
1373         MonoInst *store;
1374         MONO_INST_NEW (cfg, store, OP_STORE_MEMBASE_REG);
1375         store->sreg1 = reg;
1376         store->inst_destbasereg = cfg->frame_reg;
1377         store->inst_offset = mono_spillvar_offset (cfg, spill);
1378         if (ins) {
1379                 store->next = ins->next;
1380                 ins->next = store;
1381         }
1382         DEBUG (g_print ("SPILLED STORE (%d at 0x%08x(%%sp)) R%d (from %s)\n", spill, store->inst_offset, prev_reg, mono_arch_regname (reg)));
1383         return store;
1384 }
1385
1386 static MonoInst*
1387 create_spilled_store_float (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins)
1388 {
1389         MonoInst *store;
1390         MONO_INST_NEW (cfg, store, OP_STORER8_MEMBASE_REG);
1391         store->sreg1 = reg;
1392         store->inst_destbasereg = cfg->frame_reg;
1393         store->inst_offset = mono_spillvar_offset_float (cfg, spill);
1394         if (ins) {
1395                 store->next = ins->next;
1396                 ins->next = store;
1397         }
1398         DEBUG (g_print ("SPILLED STORE (%d at 0x%08x(%%sp)) R%d (from %s)\n", spill, store->inst_offset, prev_reg, mono_arch_regname (reg)));
1399         return store;
1400 }
1401
1402 static void
1403 insert_before_ins (MonoInst *ins, InstList *item, MonoInst* to_insert)
1404 {
1405         MonoInst *prev;
1406         g_assert (item->next);
1407         prev = item->next->data;
1408
1409         while (prev->next != ins)
1410                 prev = prev->next;
1411         to_insert->next = ins;
1412         prev->next = to_insert;
1413         /* 
1414          * needed otherwise in the next instruction we can add an ins to the 
1415          * end and that would get past this instruction.
1416          */
1417         item->data = to_insert; 
1418 }
1419
1420 static int
1421 alloc_int_reg (MonoCompile *cfg, InstList *curinst, MonoInst *ins, int sym_reg, guint32 allow_mask)
1422 {
1423         int val = cfg->rs->iassign [sym_reg];
1424         if (val < 0) {
1425                 int spill = 0;
1426                 if (val < -1) {
1427                         /* the register gets spilled after this inst */
1428                         spill = -val -1;
1429                 }
1430                 val = mono_regstate_alloc_int (cfg->rs, allow_mask);
1431                 if (val < 0)
1432                         val = get_register_spilling (cfg, curinst, ins, allow_mask, sym_reg);
1433                 cfg->rs->iassign [sym_reg] = val;
1434                 /* add option to store before the instruction for src registers */
1435                 if (spill)
1436                         create_spilled_store (cfg, spill, val, sym_reg, ins);
1437         }
1438         cfg->rs->isymbolic [val] = sym_reg;
1439         return val;
1440 }
1441
1442 /* Parameters used by the register allocator */
1443
1444 /* Use %l4..%l7 as local registers */
1445 #define ARCH_CALLER_REGS (0xf0<<16)
1446 /* Use %f2..%f30 as the double precision floating point local registers */
1447 #define ARCH_CALLER_FREGS (0x55555554)
1448
1449 /* FIXME: Strange loads from the stack in basic-float.cs:test_2_rem */
1450
1451 /*
1452  * Local register allocation.
1453  * We first scan the list of instructions and we save the liveness info of
1454  * each register (when the register is first used, when it's value is set etc.).
1455  * We also reverse the list of instructions (in the InstList list) because assigning
1456  * registers backwards allows for more tricks to be used.
1457  */
1458 void
1459 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1460 {
1461         MonoInst *ins;
1462         MonoRegState *rs = cfg->rs;
1463         int i, val;
1464         RegTrack *reginfo, *reginfof;
1465         RegTrack *reginfo1, *reginfo2, *reginfod;
1466         InstList *tmp, *reversed = NULL;
1467         const char *spec;
1468         guint32 src1_mask, src2_mask, dest_mask;
1469         guint32 cur_iregs, cur_fregs;
1470
1471         /* FIXME: clobbering */
1472
1473         if (!bb->code)
1474                 return;
1475         rs->next_vireg = bb->max_ireg;
1476         rs->next_vfreg = bb->max_freg;
1477         mono_regstate_assign (rs);
1478         reginfo = mono_mempool_alloc0 (cfg->mempool, sizeof (RegTrack) * rs->next_vireg);
1479         reginfof = mono_mempool_alloc0 (cfg->mempool, sizeof (RegTrack) * rs->next_vfreg);
1480         rs->ifree_mask = ARCH_CALLER_REGS;
1481         rs->ffree_mask = ARCH_CALLER_FREGS;
1482
1483         ins = bb->code;
1484         i = 1;
1485         DEBUG (g_print ("LOCAL regalloc: basic block: %d\n", bb->block_num));
1486         /* forward pass on the instructions to collect register liveness info */
1487         while (ins) {
1488                 spec = ins_spec [ins->opcode];
1489                 g_assert (spec);
1490                 DEBUG (print_ins (i, ins));
1491
1492                 if (spec [MONO_INST_SRC1]) {
1493                         if (spec [MONO_INST_SRC1] == 'f')
1494                                 reginfo1 = reginfof;
1495                         else
1496                                 reginfo1 = reginfo;
1497                         reginfo1 [ins->sreg1].prev_use = reginfo1 [ins->sreg1].last_use;
1498                         reginfo1 [ins->sreg1].last_use = i;
1499                 } else {
1500                         ins->sreg1 = -1;
1501                 }
1502                 if (spec [MONO_INST_SRC2]) {
1503                         if (spec [MONO_INST_SRC2] == 'f')
1504                                 reginfo2 = reginfof;
1505                         else
1506                                 reginfo2 = reginfo;
1507                         reginfo2 [ins->sreg2].prev_use = reginfo2 [ins->sreg2].last_use;
1508                         reginfo2 [ins->sreg2].last_use = i;
1509                 } else {
1510                         ins->sreg2 = -1;
1511                 }
1512                 if (spec [MONO_INST_DEST]) {
1513                         if (spec [MONO_INST_DEST] == 'f')
1514                                 reginfod = reginfof;
1515                         else
1516                                 reginfod = reginfo;
1517                         if (spec [MONO_INST_DEST] != 'b') /* it's not just a base register */
1518                                 reginfod [ins->dreg].killed_in = i;
1519                         reginfod [ins->dreg].prev_use = reginfod [ins->dreg].last_use;
1520                         reginfod [ins->dreg].last_use = i;
1521                         if (reginfod [ins->dreg].born_in == 0 || reginfod [ins->dreg].born_in > i)
1522                                 reginfod [ins->dreg].born_in = i;
1523                         if (spec [MONO_INST_DEST] == 'l') {
1524                                 /* result in eax:edx, the virtual register is allocated sequentially */
1525                                 reginfod [ins->dreg + 1].prev_use = reginfod [ins->dreg + 1].last_use;
1526                                 reginfod [ins->dreg + 1].last_use = i;
1527                                 if (reginfod [ins->dreg + 1].born_in == 0 || reginfod [ins->dreg + 1].born_in > i)
1528                                         reginfod [ins->dreg + 1].born_in = i;
1529                         }
1530                 } else {
1531                         ins->dreg = -1;
1532                 }
1533                 reversed = inst_list_prepend (cfg->mempool, reversed, ins);
1534                 ++i;
1535                 ins = ins->next;
1536         }
1537
1538         cur_iregs = ARCH_CALLER_REGS;
1539         cur_fregs = ARCH_CALLER_FREGS;
1540
1541         DEBUG (print_regtrack (reginfo, rs->next_vireg));
1542         DEBUG (print_regtrack (reginfof, rs->next_vfreg));
1543         tmp = reversed;
1544         while (tmp) {
1545                 int prev_dreg, prev_sreg1, prev_sreg2;
1546                 --i;
1547                 ins = tmp->data;
1548                 spec = ins_spec [ins->opcode];
1549                 DEBUG (g_print ("processing:"));
1550                 DEBUG (print_ins (i, ins));
1551
1552                 /* make the register available for allocation: FIXME add fp reg */
1553                 if (ins->opcode == OP_SETREG || ins->opcode == OP_SETREGIMM) {
1554                         /* Dont free register which can't be allocated */
1555                         if ((ins->dreg << 1) | ARCH_CALLER_REGS) {
1556                                 cur_iregs |= 1 << ins->dreg;
1557                                 DEBUG (g_print ("adding %d to cur_iregs\n", ins->dreg));
1558                         }
1559                 } else if (ins->opcode == OP_SETFREG) {
1560                         if ((ins->dreg << 1) | ARCH_CALLER_FREGS) {
1561                                 cur_fregs |= 1 << ins->dreg;
1562                                 DEBUG (g_print ("adding %d to cur_fregs\n", ins->dreg));
1563                         }
1564                 } else if (spec [MONO_INST_CLOB] == 'c') {
1565                         MonoCallInst *cinst = (MonoCallInst*)ins;
1566                         DEBUG (g_print ("excluding regs 0x%x from cur_iregs (0x%x)\n", cinst->used_iregs, cur_iregs));
1567                         cur_iregs &= ~cinst->used_iregs;
1568                         cur_fregs &= ~cinst->used_fregs;
1569                         DEBUG (g_print ("available cur_iregs: 0x%x\n", cur_iregs));
1570                         /* registers used by the calling convention are excluded from 
1571                          * allocation: they will be selectively enabled when they are 
1572                          * assigned by the special SETREG opcodes.
1573                          */
1574                 }
1575                 dest_mask = src1_mask = src2_mask = cur_iregs;
1576
1577                 /*
1578                  * DEST
1579                  */
1580                 /* update for use with FP regs... */
1581                 if (spec [MONO_INST_DEST] == 'f') {
1582                         if (ins->dreg >= MONO_MAX_FREGS) {
1583                                 val = rs->fassign [ins->dreg];
1584                                 prev_dreg = ins->dreg;
1585                                 if (val < 0) {
1586                                         int spill = 0;
1587                                         if (val < -1) {
1588                                                 /* the register gets spilled after this inst */
1589                                                 spill = -val -1;
1590                                         }
1591                                         dest_mask = cur_fregs;
1592                                         val = mono_regstate_alloc_float (rs, dest_mask);
1593                                         if (val < 0)
1594                                                 val = get_float_register_spilling (cfg, tmp, ins, dest_mask, ins->dreg);
1595                                         rs->fassign [ins->dreg] = val;
1596                                         if (spill)
1597                                                 create_spilled_store_float (cfg, spill, val, prev_dreg, ins);
1598                                 }
1599                                 DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_arch_regname (val), ins->dreg));
1600                                 rs->fsymbolic [val] = prev_dreg;
1601                                 ins->dreg = val;
1602                         } else {
1603                                 prev_dreg = -1;
1604                         }
1605                         if (freg_is_freeable (ins->dreg) && prev_dreg >= 0 && (reginfo [prev_dreg].born_in >= i || !(cur_fregs & (1 << ins->dreg)))) {
1606                                 DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins->dreg), prev_dreg, reginfo [prev_dreg].born_in));
1607                                 mono_regstate_free_float (rs, ins->dreg);
1608                         }
1609                 } else if (ins->dreg >= MONO_MAX_IREGS) {
1610                         val = rs->iassign [ins->dreg];
1611                         prev_dreg = ins->dreg;
1612                         if (val < 0) {
1613                                 int spill = 0;
1614                                 if (val < -1) {
1615                                         /* the register gets spilled after this inst */
1616                                         spill = -val -1;
1617                                 }
1618                                 val = mono_regstate_alloc_int (rs, dest_mask);
1619                                 if (val < 0)
1620                                         val = get_register_spilling (cfg, tmp, ins, dest_mask, ins->dreg);
1621                                 rs->iassign [ins->dreg] = val;
1622                                 if (spill)
1623                                         create_spilled_store (cfg, spill, val, prev_dreg, ins);
1624                         }
1625                         DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_arch_regname (val), ins->dreg));
1626                         rs->isymbolic [val] = prev_dreg;
1627                         ins->dreg = val;
1628                         if (spec [MONO_INST_DEST] == 'l') {
1629                                 int hreg = prev_dreg + 1;
1630                                 val = rs->iassign [hreg];
1631                                 if (val < 0) {
1632                                         int spill = 0;
1633                                         if (val < -1) {
1634                                                 /* the register gets spilled after this inst */
1635                                                 spill = -val -1;
1636                                         }
1637                                         /* The second register must be a pair of the first */
1638                                         dest_mask = 1 << (rs->iassign [prev_dreg] + 1);
1639                                         val = mono_regstate_alloc_int (rs, dest_mask);
1640                                         if (val < 0)
1641                                                 val = get_register_spilling (cfg, tmp, ins, dest_mask, hreg);
1642                                         rs->iassign [hreg] = val;
1643                                         if (spill)
1644                                                 create_spilled_store (cfg, spill, val, hreg, ins);
1645                                 }
1646                                 else {
1647                                         /* The second register must be a pair of the first */
1648                                         if (val != rs->iassign [prev_dreg] + 1) {
1649                                                 dest_mask = 1 << (rs->iassign [prev_dreg] + 1);
1650
1651                                                 val = mono_regstate_alloc_int (rs, dest_mask);
1652                                                 if (val < 0)
1653                                                         val = get_register_spilling (cfg, tmp, ins, dest_mask, hreg);
1654
1655                                                 create_copy_ins (cfg, rs->iassign [hreg], val, ins);
1656
1657                                                 rs->iassign [hreg] = val;
1658                                         }
1659                                 }                                       
1660
1661                                 DEBUG (g_print ("\tassigned hreg %s to dest R%d\n", mono_arch_regname (val), hreg));
1662                                 rs->isymbolic [val] = hreg;
1663
1664                                 if (reg_is_freeable (val) && hreg >= 0 && (reginfo [hreg].born_in >= i && !(cur_iregs & (1 << val)))) {
1665                                         DEBUG (g_print ("\tfreeable %s (R%d)\n", mono_arch_regname (val), hreg));
1666                                         mono_regstate_free_int (rs, val);
1667                                 }
1668                         }
1669                 } else {
1670                         prev_dreg = -1;
1671                 }
1672                 if (spec [MONO_INST_DEST] != 'f' && reg_is_freeable (ins->dreg) && prev_dreg >= 0 && (reginfo [prev_dreg].born_in >= i)) {
1673                         DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins->dreg), prev_dreg, reginfo [prev_dreg].born_in));
1674                         mono_regstate_free_int (rs, ins->dreg);
1675                 }
1676
1677                 /**
1678                  * SRC1
1679                  */
1680                 if (spec [MONO_INST_SRC1] == 'f') {
1681                         if (ins->sreg1 >= MONO_MAX_FREGS) {
1682                                 val = rs->fassign [ins->sreg1];
1683                                 prev_sreg1 = ins->sreg1;
1684                                 if (val < 0) {
1685                                         int spill = 0;
1686                                         if (val < -1) {
1687                                                 /* the register gets spilled after this inst */
1688                                                 spill = -val -1;
1689                                         }
1690                                         //g_assert (val == -1); /* source cannot be spilled */
1691                                         src1_mask = cur_fregs;
1692                                         val = mono_regstate_alloc_float (rs, src1_mask);
1693                                         if (val < 0)
1694                                                 val = get_float_register_spilling (cfg, tmp, ins, src1_mask, ins->sreg1);
1695                                         rs->fassign [ins->sreg1] = val;
1696                                         DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1));
1697                                         if (spill) {
1698                                                 MonoInst *store = create_spilled_store_float (cfg, spill, val, prev_sreg1, NULL);
1699                                                 insert_before_ins (ins, tmp, store);
1700                                         }
1701                                 }
1702                                 rs->fsymbolic [val] = prev_sreg1;
1703                                 ins->sreg1 = val;
1704                         } else {
1705                                 prev_sreg1 = -1;
1706                         }
1707                 } else if (ins->sreg1 >= MONO_MAX_IREGS) {
1708                         val = rs->iassign [ins->sreg1];
1709                         prev_sreg1 = ins->sreg1;
1710                         if (val < 0) {
1711                                 int spill = 0;
1712                                 if (val < -1) {
1713                                         /* the register gets spilled after this inst */
1714                                         spill = -val -1;
1715                                 }
1716                                 if (0 && ins->opcode == OP_MOVE) {
1717                                         /* 
1718                                          * small optimization: the dest register is already allocated
1719                                          * but the src one is not: we can simply assign the same register
1720                                          * here and peephole will get rid of the instruction later.
1721                                          * This optimization may interfere with the clobbering handling:
1722                                          * it removes a mov operation that will be added again to handle clobbering.
1723                                          * There are also some other issues that should with make testjit.
1724                                          */
1725                                         mono_regstate_alloc_int (rs, 1 << ins->dreg);
1726                                         val = rs->iassign [ins->sreg1] = ins->dreg;
1727                                         //g_assert (val >= 0);
1728                                         DEBUG (g_print ("\tfast assigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1));
1729                                 } else {
1730                                         //g_assert (val == -1); /* source cannot be spilled */
1731                                         val = mono_regstate_alloc_int (rs, src1_mask);
1732                                         if (val < 0)
1733                                                 val = get_register_spilling (cfg, tmp, ins, src1_mask, ins->sreg1);
1734                                         rs->iassign [ins->sreg1] = val;
1735                                         DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1));
1736                                 }
1737                                 if (spill) {
1738                                         MonoInst *store = create_spilled_store (cfg, spill, val, prev_sreg1, NULL);
1739                                         insert_before_ins (ins, tmp, store);
1740                                 }
1741                         }
1742                         rs->isymbolic [val] = prev_sreg1;
1743                         ins->sreg1 = val;
1744                 } else {
1745                         prev_sreg1 = -1;
1746                 }
1747
1748                 /*
1749                  * SRC2
1750                  */
1751                 if (spec [MONO_INST_SRC2] == 'f') {
1752                         if (ins->sreg2 >= MONO_MAX_FREGS) {
1753                                 val = rs->fassign [ins->sreg2];
1754                                 prev_sreg2 = ins->sreg2;
1755                                 if (val < 0) {
1756                                         int spill = 0;
1757                                         if (val < -1) {
1758                                                 /* the register gets spilled after this inst */
1759                                                 spill = -val -1;
1760                                         }
1761                                         src2_mask = cur_fregs;
1762                                         val = mono_regstate_alloc_float (rs, src2_mask);
1763                                         if (val < 0)
1764                                                 val = get_float_register_spilling (cfg, tmp, ins, src2_mask, ins->sreg2);
1765                                         rs->fassign [ins->sreg2] = val;
1766                                         DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val), ins->sreg2));
1767                                         if (spill)
1768                                                 create_spilled_store_float (cfg, spill, val, prev_sreg2, ins);
1769                                 }
1770                                 rs->fsymbolic [val] = prev_sreg2;
1771                                 ins->sreg2 = val;
1772                         } else {
1773                                 prev_sreg2 = -1;
1774                         }
1775                 } else if (ins->sreg2 >= MONO_MAX_IREGS) {
1776                         val = rs->iassign [ins->sreg2];
1777                         prev_sreg2 = ins->sreg2;
1778                         if (val < 0) {
1779                                 int spill = 0;
1780                                 if (val < -1) {
1781                                         /* the register gets spilled after this inst */
1782                                         spill = -val -1;
1783                                 }
1784                                 val = mono_regstate_alloc_int (rs, src2_mask);
1785                                 if (val < 0)
1786                                         val = get_register_spilling (cfg, tmp, ins, src2_mask, ins->sreg2);
1787                                 rs->iassign [ins->sreg2] = val;
1788                                 DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val), ins->sreg2));
1789                                 if (spill)
1790                                         create_spilled_store (cfg, spill, val, prev_sreg2, ins);
1791                         }
1792                         rs->isymbolic [val] = prev_sreg2;
1793                         ins->sreg2 = val;
1794                 } else {
1795                         prev_sreg2 = -1;
1796                 }
1797
1798                 if (spec [MONO_INST_CLOB] == 'c') {
1799                         int j, s;
1800                         guint32 clob_mask = ARCH_CALLER_REGS;
1801                         for (j = 0; j < MONO_MAX_IREGS; ++j) {
1802                                 s = 1 << j;
1803                                 if ((clob_mask & s) && !(rs->ifree_mask & s) && j != ins->sreg1) {
1804                                         //g_warning ("register %s busy at call site\n", mono_arch_regname (j));
1805                                 }
1806                         }
1807                 }
1808                 /*if (reg_is_freeable (ins->sreg1) && prev_sreg1 >= 0 && reginfo [prev_sreg1].born_in >= i) {
1809                         DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg1)));
1810                         mono_regstate_free_int (rs, ins->sreg1);
1811                 }
1812                 if (reg_is_freeable (ins->sreg2) && prev_sreg2 >= 0 && reginfo [prev_sreg2].born_in >= i) {
1813                         DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg2)));
1814                         mono_regstate_free_int (rs, ins->sreg2);
1815                 }*/
1816                 
1817                 //DEBUG (print_ins (i, ins));
1818
1819                 tmp = tmp->next;
1820         }
1821 }
1822
1823 static guchar*
1824 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int size, gboolean is_signed)
1825 {
1826         return code;
1827 }
1828
1829 static unsigned char*
1830 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
1831 {
1832         NOT_IMPLEMENTED;
1833         return code;
1834 }
1835
1836 static void
1837 sparc_patch (guint8 *code, guint8 *target)
1838 {
1839         guint32 ins = *(guint32*)code;
1840         guint32 op = ins >> 30;
1841         guint32 op2 = (ins >> 22) & 0x7;
1842         guint32 rd = (ins >> 25) & 0x1f;
1843         gint32 disp = (target - code) >> 2;
1844
1845 //      g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
1846
1847         if ((op == 0) && (op2 == 2)) {
1848                 if (!sparc_is_imm22 (disp))
1849                         NOT_IMPLEMENTED;
1850                 /* Bicc */
1851                 *(guint32*)code = ((ins >> 22) << 22) | disp;
1852         }
1853         else if ((op == 0) && (op2 == 6)) {
1854                 if (!sparc_is_imm22 (disp))
1855                         NOT_IMPLEMENTED;
1856                 /* FBicc */
1857                 *(guint32*)code = ((ins >> 22) << 22) | disp;
1858         }
1859         else if ((op == 0) && (op2 == 4)) {
1860                 guint32 ins2 = *(guint32*)(code + 4);
1861
1862                 if (((ins2 >> 30) == 2) && (((ins2 >> 19) & 0x3f) == 2)) {
1863                         /* sethi followed by or */
1864                         guint32 *p = (guint32*)code;
1865                         sparc_set (p, target, rd);
1866                         while (p < (code + 4))
1867                                 sparc_nop (p);
1868                 }
1869                 else if ((sparc_inst_op (ins2) == 3) && (sparc_inst_imm (ins2))) {
1870                         /* sethi followed by load/store */
1871                         guint32 t = (guint32)target;
1872                         *(guint32*)code = ins | (t >> 10);
1873                         *(guint32*)(code + 4) = ins2 | (t & 0x3ff);
1874                 }
1875                 else if ((sparc_inst_op (ins2) == 2) && (sparc_inst_op3 (ins2) == 0x38) && 
1876                                  (sparc_inst_imm (ins2))) {
1877                         /* sethi followed by jmpl */
1878                         guint32 t = (guint32)target;
1879                         *(guint32*)code = ins | (t >> 10);
1880                         *(guint32*)(code + 4) = ins2 | (t & 0x3ff);
1881                 }
1882                 else
1883                         NOT_IMPLEMENTED;
1884         }
1885         else if (op == 01) {
1886                 sparc_call_simple (code, target - code);
1887         }
1888         else
1889                 NOT_IMPLEMENTED;
1890
1891 //      g_print ("patched with 0x%08x\n", ins);
1892 }
1893
1894 static guint32*
1895 emit_move_return_value (MonoInst *ins, guint32 *code)
1896 {
1897         /* Move return value to the target register */
1898         /* FIXME: do this in the local reg allocator */
1899         switch (ins->opcode) {
1900         case OP_VOIDCALL:
1901         case OP_VOIDCALL_REG:
1902         case OP_VOIDCALL_MEMBASE:
1903                 break;
1904         case CEE_CALL:
1905         case OP_CALL_REG:
1906         case OP_CALL_MEMBASE:
1907                 sparc_mov_reg_reg (code, sparc_o0, ins->dreg);
1908                 break;
1909         case OP_LCALL:
1910         case OP_LCALL_REG:
1911         case OP_LCALL_MEMBASE:
1912                 /* 
1913                  * ins->dreg is the least significant reg due to the lreg: LCALL rule
1914                  * in inssel.brg.
1915                  */
1916                 sparc_mov_reg_reg (code, sparc_o0, ins->dreg + 1);
1917                 sparc_mov_reg_reg (code, sparc_o1, ins->dreg);
1918                 break;
1919         case OP_FCALL:
1920         case OP_FCALL_REG:
1921         case OP_FCALL_MEMBASE:
1922                 sparc_fmovs (code, sparc_f0, ins->dreg);
1923                 sparc_fmovs (code, sparc_f1, ins->dreg + 1);
1924                 break;
1925         case OP_VCALL:
1926         case OP_VCALL_REG:
1927         case OP_VCALL_MEMBASE:
1928                 break;
1929         default:
1930                 NOT_IMPLEMENTED;
1931         }
1932
1933         return code;
1934 }
1935
1936 /*
1937  * mono_sparc_is_virtual_call:
1938  *
1939  *  Determine whenever the instruction at CODE is a virtual call.
1940  */
1941 gboolean 
1942 mono_sparc_is_virtual_call (guint32 *code)
1943 {
1944         guint32 buf[1];
1945         guint32 *p;
1946
1947         p = buf;
1948
1949         if ((sparc_inst_op (*code) == 0x2) && (sparc_inst_op3 (*code) == 0x38)) {
1950                 /*
1951                  * Register indirect call. If it is a virtual call, then the 
1952                  * instruction in the delay slot is a special kind of nop.
1953                  */
1954
1955                 /* Construct special nop */
1956                 sparc_or_imm (p, FALSE, sparc_g0, 0xca, sparc_g0);
1957                 p --;
1958
1959                 if (code [1] == p [0])
1960                         return TRUE;
1961         }
1962
1963         return FALSE;
1964 }
1965
1966 /*
1967  * Some conventions used in the following code.
1968  * 2) The only scratch registers we have are o7 and g1.  We try to
1969  * stick to o7 when we can, and use g1 when necessary.
1970  */
1971
1972 void
1973 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
1974 {
1975         MonoInst *ins;
1976         MonoCallInst *call;
1977         guint offset;
1978         guint32 *code = (guint32*)(cfg->native_code + cfg->code_len);
1979         MonoInst *last_ins = NULL;
1980         guint last_offset = 0;
1981         int max_len, cpos;
1982
1983         GC_malloc (240);
1984
1985         if (cfg->opt & MONO_OPT_PEEPHOLE)
1986                 peephole_pass (cfg, bb);
1987
1988         if (cfg->verbose_level > 2)
1989                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
1990
1991         cpos = bb->max_offset;
1992
1993         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
1994                 NOT_IMPLEMENTED;
1995         }
1996
1997         ins = bb->code;
1998         while (ins) {
1999                 offset = (guint8*)code - cfg->native_code;
2000
2001                 max_len = ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
2002
2003                 if (offset > (cfg->code_size - max_len - 16)) {
2004                         cfg->code_size *= 2;
2005                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2006                         code = (guint32*)(cfg->native_code + offset);
2007                 }
2008                 //      if (ins->cil_code)
2009                 //              g_print ("cil code\n");
2010
2011                 switch (ins->opcode) {
2012                 case OP_STOREI1_MEMBASE_IMM:
2013                         EMIT_STORE_MEMBASE_IMM (ins, stb);
2014                         break;
2015                 case OP_STOREI2_MEMBASE_IMM:
2016                         EMIT_STORE_MEMBASE_IMM (ins, sth);
2017                         break;
2018                 case OP_STORE_MEMBASE_IMM:
2019                 case OP_STOREI4_MEMBASE_IMM:
2020                         EMIT_STORE_MEMBASE_IMM (ins, st);
2021                         break;
2022                 case OP_STOREI1_MEMBASE_REG:
2023                         EMIT_STORE_MEMBASE_REG (ins, stb);
2024                         break;
2025                 case OP_STOREI2_MEMBASE_REG:
2026                         EMIT_STORE_MEMBASE_REG (ins, sth);
2027                         break;
2028                 case OP_STORE_MEMBASE_REG:
2029                 case OP_STOREI4_MEMBASE_REG:
2030                         EMIT_STORE_MEMBASE_REG (ins, st);
2031                         break;
2032                 case OP_STOREI8_MEMBASE_REG:
2033                         /* Only used by OP_MEMSET */
2034                         EMIT_STORE_MEMBASE_REG (ins, std);
2035                         break;
2036                 case CEE_LDIND_I:
2037                 case CEE_LDIND_I4:
2038                 case CEE_LDIND_U4:
2039                         sparc_ld (code, ins->inst_p0, sparc_g0, ins->dreg);
2040                         break;
2041                 /* The cast IS BAD (maybe).  But it needs to be done... */
2042                 case OP_LOADU4_MEM:
2043                         sparc_set (code, (guint)ins->inst_p0, ins->dreg);
2044                         sparc_ld (code, ins->dreg, sparc_g0, ins->dreg);
2045                         break;
2046                 case OP_LOAD_MEMBASE:
2047                 case OP_LOADI4_MEMBASE:
2048                 case OP_LOADU4_MEMBASE:
2049                         EMIT_LOAD_MEMBASE (ins, ld);
2050                         break;
2051                 case OP_LOADU1_MEMBASE:
2052                         EMIT_LOAD_MEMBASE (ins, ldub);
2053                         break;
2054                 case OP_LOADI1_MEMBASE:
2055                         EMIT_LOAD_MEMBASE (ins, ldsb);
2056                         break;
2057                 case OP_LOADU2_MEMBASE:
2058                         EMIT_LOAD_MEMBASE (ins, lduh);
2059                         break;
2060                 case OP_LOADI2_MEMBASE:
2061                         EMIT_LOAD_MEMBASE (ins, ldsh);
2062                         break;
2063                 case CEE_CONV_I1:
2064                         sparc_sll_imm (code, ins->sreg1, 24, sparc_o7);
2065                         sparc_sra_imm (code, sparc_o7, 24, ins->dreg);
2066                         break;
2067                 case CEE_CONV_I2:
2068                         sparc_sll_imm (code, ins->sreg1, 16, sparc_o7);
2069                         sparc_sra_imm (code, sparc_o7, 16, ins->dreg);
2070                         break;
2071                 /* GCC does this one differently.  Don't ask me WHY. */
2072                 case CEE_CONV_U1:
2073                         sparc_and_imm (code, FALSE, ins->sreg1, 0xff, ins->dreg);
2074                         break;
2075                 case CEE_CONV_U2:
2076                         sparc_sll_imm (code, ins->sreg1, 16, sparc_o7);
2077                         sparc_srl_imm (code, sparc_o7, 16, ins->dreg);
2078                         break;
2079                 case OP_COMPARE:
2080                         sparc_cmp (code, ins->sreg1, ins->sreg2);
2081                         break;
2082                 case OP_COMPARE_IMM:
2083                         if (sparc_is_imm13 (ins->inst_imm))
2084                                 sparc_cmp_imm (code, ins->sreg1, ins->inst_imm);
2085                         else {
2086                                 sparc_set (code, ins->inst_imm, sparc_o7);
2087                                 sparc_cmp (code, ins->sreg1, sparc_o7);
2088                         }
2089                         break;
2090                 case OP_X86_TEST_NULL:
2091                         sparc_cmp_imm (code, ins->sreg1, 0);
2092                         break;
2093                 case CEE_BREAK:
2094                         /*
2095                          * gdb does not like encountering 'ta 1' in the debugged code. So 
2096                          * instead of emitting a trap, we emit a call a C function and place a 
2097                          * breakpoint there.
2098                          */
2099                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, mono_sparc_break);
2100                         sparc_call_simple (code, 0);
2101                         sparc_nop (code);
2102                         break;
2103                 case OP_ADDCC:
2104                         sparc_add (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
2105                         break;
2106                 case CEE_ADD:
2107                         sparc_add (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2108                         break;
2109                 case OP_ADC:
2110                         sparc_addx (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2111                         break;
2112                 case OP_ADD_IMM:
2113                         EMIT_ALU_IMM (ins, add, FALSE);
2114                         break;
2115                 case OP_ADC_IMM:
2116                         EMIT_ALU_IMM (ins, addx, FALSE);
2117                         break;
2118                 case OP_SUBCC:
2119                         sparc_sub (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
2120                         break;
2121                 case CEE_SUB:
2122                         sparc_sub (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2123                         break;
2124                 case OP_SBB:
2125                         sparc_subx (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2126                         break;
2127                 case OP_SUB_IMM:
2128                         // we add the negated value
2129                         if (sparc_is_imm13 (- ins->inst_imm))
2130                                 sparc_add_imm (code, FALSE, ins->sreg1, -ins->inst_imm, ins->dreg);
2131                         else {
2132                                 sparc_set (code, - ins->inst_imm, sparc_o7);
2133                                 sparc_add (code, FALSE, ins->sreg1, sparc_o7, ins->dreg);
2134                         }
2135                         break;
2136                 case OP_SBB_IMM:
2137                         EMIT_ALU_IMM (ins, subx, FALSE);
2138                         break;
2139                 case CEE_AND:
2140                         sparc_and (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2141                         break;
2142                 case OP_AND_IMM:
2143                         EMIT_ALU_IMM (ins, and, FALSE);
2144                         break;
2145                 case CEE_DIV:
2146                         /* Sign extend sreg1 into %y */
2147                         sparc_sra_imm (code, ins->sreg1, 31, sparc_o7);
2148                         sparc_wry (code, sparc_o7, sparc_g0);
2149                         sparc_sdiv (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2150                         break;
2151                 case CEE_DIV_UN:
2152                         sparc_wry (code, sparc_g0, sparc_g0);
2153                         sparc_udiv (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2154                         break;
2155                 case OP_DIV_IMM:
2156                         /* Sign extend sreg1 into %y */
2157                         sparc_sra_imm (code, ins->sreg1, 31, sparc_o7);
2158                         sparc_wry (code, sparc_o7, sparc_g0);
2159                         EMIT_ALU_IMM (ins, sdiv, FALSE);
2160                         break;
2161                 case CEE_REM:
2162                         /* Sign extend sreg1 into %y */
2163                         sparc_sra_imm (code, ins->sreg1, 31, sparc_o7);
2164                         sparc_wry (code, sparc_o7, sparc_g0);
2165                         sparc_sdiv (code, FALSE, ins->sreg1, ins->sreg2, sparc_o7);
2166                         sparc_smul (code, FALSE, ins->sreg2, sparc_o7, sparc_o7);
2167                         sparc_sub (code, FALSE, ins->sreg1, sparc_o7, ins->dreg);
2168                         break;
2169                 case CEE_REM_UN:
2170                         sparc_wry (code, sparc_g0, sparc_g0);
2171                         sparc_udiv (code, FALSE, ins->sreg1, ins->sreg2, sparc_o7);
2172                         sparc_umul (code, FALSE, ins->sreg2, sparc_o7, sparc_o7);
2173                         sparc_sub (code, FALSE, ins->sreg1, sparc_o7, ins->dreg);
2174                         break;
2175                 case OP_REM_IMM:
2176                         /* Sign extend sreg1 into %y */
2177                         sparc_sra_imm (code, ins->sreg1, 31, sparc_o7);
2178                         sparc_wry (code, sparc_o7, sparc_g0);
2179                         if (!sparc_is_imm13 (ins->inst_imm)) {
2180                                 sparc_set (code, ins->inst_imm, sparc_g1);
2181                                 sparc_sdiv (code, FALSE, ins->sreg1, sparc_g1, sparc_o7);
2182                                 sparc_smul (code, FALSE, sparc_o7, sparc_g1, sparc_o7);
2183                         }
2184                         else {
2185                                 sparc_sdiv_imm (code, FALSE, ins->sreg1, ins->inst_imm, sparc_o7);
2186                                 sparc_smul_imm (code, FALSE, sparc_o7, ins->inst_imm, sparc_o7);
2187                         }
2188                         sparc_sub (code, FALSE, ins->sreg1, sparc_o7, ins->dreg);
2189                         break;
2190                 case CEE_OR:
2191                         sparc_or (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2192                         break;
2193                 case OP_OR_IMM:
2194                         EMIT_ALU_IMM (ins, or, FALSE);
2195                         break;
2196                 case CEE_XOR:
2197                         sparc_xor (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2198                         break;
2199                 case OP_XOR_IMM:
2200                         EMIT_ALU_IMM (ins, xor, FALSE);
2201                         break;
2202                 case CEE_SHL:
2203                         sparc_sll (code, ins->sreg1, ins->sreg2, ins->dreg);
2204                         break;
2205                 case OP_SHL_IMM:
2206                         if (sparc_is_imm13 (ins->inst_imm))
2207                                 sparc_sll_imm (code, ins->sreg1, ins->inst_imm, ins->dreg);
2208                         else {
2209                                 sparc_set (code, ins->inst_imm, sparc_o7);
2210                                 sparc_sll (code, ins->sreg1, sparc_o7, ins->dreg);
2211                         }
2212                         break;
2213                 case CEE_SHR:
2214                         sparc_sra (code, ins->sreg1, ins->sreg2, ins->dreg);
2215                         break;
2216                 case OP_SHR_IMM:
2217                         if (sparc_is_imm13 (ins->inst_imm))
2218                                 sparc_sra_imm (code, ins->sreg1, ins->inst_imm, ins->dreg);
2219                         else {
2220                                 sparc_set (code, ins->inst_imm, sparc_o7);
2221                                 sparc_sra (code, ins->sreg1, sparc_o7, ins->dreg);
2222                         }
2223                         break;
2224                 case OP_SHR_UN_IMM:
2225                         if (sparc_is_imm13 (ins->inst_imm))
2226                                 sparc_srl_imm (code, ins->sreg1, ins->inst_imm, ins->dreg);
2227                         else {
2228                                 sparc_set (code, ins->inst_imm, sparc_o7);
2229                                 sparc_srl (code, ins->sreg1, sparc_o7, ins->dreg);
2230                         }
2231                         break;
2232                 case CEE_SHR_UN:
2233                         sparc_srl (code, ins->sreg1, ins->sreg2, ins->dreg);
2234                         break;
2235                 case CEE_NOT:
2236                         /* can't use sparc_not */
2237                         sparc_xnor (code, FALSE, ins->sreg1, sparc_g0, ins->dreg);
2238                         break;
2239                 case CEE_NEG:
2240                         /* can't use sparc_neg */
2241                         sparc_sub (code, FALSE, sparc_g0, ins->sreg1, ins->dreg);
2242                         break;
2243                 case CEE_MUL:
2244                         sparc_smul (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2245                         break;
2246                 case OP_MUL_IMM:
2247                         EMIT_ALU_IMM (ins, smul, FALSE);
2248                         break;
2249                 case CEE_MUL_OVF:
2250                         /* FIXME: */
2251                         sparc_smul (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2252                         break;
2253                 case CEE_MUL_OVF_UN:
2254                         /* FIXME: */
2255                         sparc_umul (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2256                         break;
2257                 case OP_ICONST:
2258                 case OP_SETREGIMM:
2259                         sparc_set (code, ins->inst_c0, ins->dreg);
2260                         break;
2261                 case CEE_CONV_I4:
2262                 case CEE_CONV_U4:
2263                 case OP_MOVE:
2264                 case OP_SETREG:
2265                         if (ins->sreg1 != ins->dreg)
2266                                 sparc_mov_reg_reg (code, ins->sreg1, ins->dreg);
2267                         break;
2268                 case CEE_JMP:
2269                         g_assert_not_reached ();
2270                         break;
2271                 case OP_CHECK_THIS:
2272                         /* ensure ins->sreg1 is not NULL */
2273                         sparc_ld_imm (code, ins->sreg1, 0, sparc_g0);
2274                         break;
2275                 case OP_FCALL:
2276                 case OP_LCALL:
2277                 case OP_VCALL:
2278                 case OP_VOIDCALL:
2279                 case CEE_CALL:
2280                         call = (MonoCallInst*)ins;
2281                         g_assert (!call->virtual);
2282                         if (ins->flags & MONO_INST_HAS_METHOD)
2283                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2284                         else
2285                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2286                         sparc_call_simple (code, 0);
2287                         sparc_nop (code);
2288
2289                         code = emit_move_return_value (ins, code);
2290                         break;
2291                 case OP_FCALL_REG:
2292                 case OP_LCALL_REG:
2293                 case OP_VCALL_REG:
2294                 case OP_VOIDCALL_REG:
2295                 case OP_CALL_REG:
2296                         call = (MonoCallInst*)ins;
2297                         sparc_jmpl (code, ins->sreg1, sparc_g0, sparc_callsite);
2298                         /*
2299                          * We emit a special kind of nop in the delay slot to tell the 
2300                          * trampoline code that this is a virtual call, thus an unbox
2301                          * trampoline might need to be called.
2302                          */
2303                         if (call->virtual)
2304                                 sparc_or_imm (code, FALSE, sparc_g0, 0xca, sparc_g0);
2305                         else
2306                                 sparc_nop (code);
2307
2308                         code = emit_move_return_value (ins, code);
2309                         break;
2310                 case OP_FCALL_MEMBASE:
2311                 case OP_LCALL_MEMBASE:
2312                 case OP_VCALL_MEMBASE:
2313                 case OP_VOIDCALL_MEMBASE:
2314                 case OP_CALL_MEMBASE:
2315                         call = (MonoCallInst*)ins;
2316                         g_assert (sparc_is_imm13 (ins->inst_offset));
2317
2318                         sparc_ld_imm (code, ins->inst_basereg, ins->inst_offset, sparc_o7);
2319                         sparc_jmpl (code, sparc_o7, sparc_g0, sparc_callsite);
2320                         if (call->virtual)
2321                                 sparc_or_imm (code, FALSE, sparc_g0, 0xca, sparc_g0);
2322                         else
2323                                 sparc_nop (code);
2324
2325                         code = emit_move_return_value (ins, code);
2326                         break;
2327                 case OP_OUTARG:
2328                         g_assert_not_reached ();
2329                         break;
2330                 case OP_LOCALLOC:
2331                         NOT_IMPLEMENTED;
2332                         break;
2333                 case CEE_RET:
2334                         /* The return is done in the epilog */
2335                         g_assert_not_reached ();
2336                         break;
2337                 case CEE_THROW: {
2338                         sparc_unimp (code, 0);
2339                         /* FIXME: */
2340                         break;
2341                 }
2342                 case OP_ENDFILTER:
2343                         /* FIXME: */
2344                         break;
2345                 case CEE_ENDFINALLY:
2346                         /* FIXME: */
2347                         break;
2348                 case OP_CALL_HANDLER: 
2349                         /* FIXME: */
2350                         break;
2351                 case OP_LABEL:
2352                         ins->inst_c0 = (guint8*)code - cfg->native_code;
2353                         break;
2354                 case CEE_BR:
2355                         //g_print ("target: %p, next: %p, curr: %p, last: %p\n", ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
2356                         if ((ins->inst_target_bb == bb->next_bb) && ins == bb->last_ins)
2357                                 break;
2358                         if (ins->flags & MONO_INST_BRLABEL) {
2359                                 if (ins->inst_i0->inst_c0) {
2360                                         gint32 disp = (ins->inst_i0->inst_c0 - ((guint8*)code - cfg->native_code)) >> 2;
2361                                         g_assert (sparc_is_imm22 (disp));
2362                                         sparc_branch (code, 1, sparc_ba, disp);
2363                                 } else {
2364                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2365                                         sparc_branch (code, 1, sparc_ba, 0);
2366                                 }
2367                         } else {
2368                                 if (ins->inst_target_bb->native_offset) {
2369                                         gint32 disp = (ins->inst_target_bb->native_offset - ((guint8*)code - cfg->native_code)) >> 2;
2370                                         g_assert (sparc_is_imm22 (disp));
2371                                         sparc_branch (code, 1, sparc_ba, disp);
2372                                 } else {
2373                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2374                                         sparc_branch (code, 1, sparc_ba, 0);
2375                                 } 
2376                         }
2377                         sparc_nop (code);
2378                         break;
2379                 case OP_BR_REG:
2380                         sparc_jmp (code, ins->sreg1, sparc_g0);
2381                         sparc_nop (code);
2382                         break;
2383                 case OP_CEQ:
2384                 case OP_CLT:
2385                 case OP_CLT_UN:
2386                 case OP_CGT:
2387                 case OP_CGT_UN:
2388                         sparc_clr_reg (code, ins->dreg);
2389                         sparc_branch (code, 1, opcode_to_sparc_cond (ins->opcode), 2);
2390                         /* delay slot */
2391                         sparc_set (code, 1, ins->dreg);
2392                         break;
2393                 case OP_COND_EXC_EQ:
2394                 case OP_COND_EXC_NE_UN:
2395                 case OP_COND_EXC_LT:
2396                 case OP_COND_EXC_LT_UN:
2397                 case OP_COND_EXC_GT:
2398                 case OP_COND_EXC_GT_UN:
2399                 case OP_COND_EXC_GE:
2400                 case OP_COND_EXC_GE_UN:
2401                 case OP_COND_EXC_LE:
2402                 case OP_COND_EXC_LE_UN:
2403                 case OP_COND_EXC_OV:
2404                 case OP_COND_EXC_NO:
2405                 case OP_COND_EXC_C:
2406                 case OP_COND_EXC_NC:
2407                         /* FIXME: */
2408                         //EMIT_COND_SYSTEM_EXCEPTION (branch_cc_table [ins->opcode - OP_COND_EXC_EQ], 
2409                         //                          (ins->opcode < OP_COND_EXC_NE_UN), ins->inst_p1);
2410                         break;
2411                 case CEE_BEQ:
2412                 case CEE_BNE_UN:
2413                 case CEE_BLT:
2414                 case CEE_BLT_UN:
2415                 case CEE_BGT:
2416                 case CEE_BGT_UN:
2417                 case CEE_BGE:
2418                 case CEE_BGE_UN:
2419                 case CEE_BLE:
2420                 case CEE_BLE_UN:
2421                         EMIT_COND_BRANCH (ins, opcode_to_sparc_cond (ins->opcode));
2422                         break;
2423
2424                 /* floating point opcodes */
2425                 case OP_R8CONST: {
2426                         double d = *(double*)ins->inst_p0;
2427
2428                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R8, ins->inst_p0);
2429                         sparc_sethi (code, 0, sparc_o7);
2430                         sparc_lddf_imm (code, sparc_o7, 0, ins->dreg);
2431                         break;
2432                 }
2433                 case OP_R4CONST: {
2434                         float f = *(float*)ins->inst_p0;
2435
2436                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R4, ins->inst_p0);
2437                         sparc_sethi (code, 0, sparc_o7);
2438                         sparc_ldf_imm (code, sparc_o7, 0, ins->dreg);
2439
2440                         /* Extend to double */
2441                         sparc_fstod (code, ins->dreg, ins->dreg);
2442                         break;
2443                 }
2444                 case OP_STORER8_MEMBASE_REG:
2445                         if (!sparc_is_imm13 (ins->inst_offset + 4)) {
2446                                 sparc_set (code, ins->inst_offset, sparc_o7);
2447                                 if (ins->inst_offset % 8) {
2448                                         /* Misaligned */
2449                                         sparc_add (code, FALSE, ins->inst_destbasereg, sparc_o7, sparc_o7);
2450                                         sparc_stf (code, ins->sreg1, sparc_o7, sparc_g0);
2451                                         sparc_stf_imm (code, ins->sreg1 + 1, sparc_o7, 4);
2452                                 } else
2453                                         sparc_stdf (code, ins->sreg1, ins->inst_destbasereg, sparc_o7);
2454                         }
2455                         else {
2456                                 if (ins->inst_offset % 8) {
2457                                         /* Misaligned */
2458                                         sparc_stf_imm (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2459                                         sparc_stf_imm (code, ins->sreg1 + 1, ins->inst_destbasereg, ins->inst_offset + 4);
2460                                 } else
2461                                         sparc_stdf_imm (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2462                         }
2463                         break;
2464                 case OP_LOADR8_MEMBASE:
2465                         g_assert ((ins->inst_offset % 8) == 0);
2466                         EMIT_LOAD_MEMBASE (ins, lddf);
2467                         break;
2468                 case OP_STORER4_MEMBASE_REG:
2469                         /* This requires a double->single conversion */
2470                         sparc_fdtos (code, ins->sreg1, sparc_f0);
2471                         if (!sparc_is_imm13 (ins->inst_offset)) {
2472                                 sparc_set (code, ins->inst_offset, sparc_o7);
2473                                 sparc_stf (code, sparc_f0, ins->inst_destbasereg, sparc_o7);
2474                         }
2475                         else
2476                                 sparc_stf_imm (code, sparc_f0, ins->inst_destbasereg, ins->inst_offset);
2477                         break;
2478                 case OP_LOADR4_MEMBASE:
2479                         EMIT_LOAD_MEMBASE (ins, ldf);
2480                         /* Extend to double */
2481                         sparc_fstod (code, ins->dreg, ins->dreg);
2482                         break;
2483                 case OP_FMOVE:
2484                         sparc_fmovs (code, ins->sreg1, ins->dreg);
2485                         sparc_fmovs (code, ins->sreg1 + 1, ins->dreg + 1);
2486                         break;
2487                 case CEE_CONV_R4:
2488                         g_assert (sparc_is_imm13 (cfg->stack_offset));
2489                         sparc_st_imm (code, ins->sreg1, sparc_sp, cfg->stack_offset - 8);
2490                         sparc_ldf_imm (code, sparc_sp, cfg->stack_offset - 8, sparc_f0);
2491                         sparc_fitos (code, sparc_f0, sparc_f0);
2492                         sparc_fstod (code, sparc_f0, ins->dreg);
2493                         break;
2494                 case CEE_CONV_R8:
2495                         g_assert (sparc_is_imm13 (cfg->stack_offset));
2496                         sparc_st_imm (code, ins->sreg1, sparc_sp, cfg->stack_offset - 8);
2497                         sparc_ldf_imm (code, sparc_sp, cfg->stack_offset - 8, sparc_f0);
2498                         sparc_fitod (code, sparc_f0, ins->dreg);
2499                         break;
2500                 case OP_FCONV_TO_I1:
2501                         NOT_IMPLEMENTED;
2502                         break;
2503                 case OP_FCONV_TO_U1:
2504                         NOT_IMPLEMENTED;
2505                         break;
2506                 case OP_FCONV_TO_I2:
2507                         NOT_IMPLEMENTED;
2508                         break;
2509                 case OP_FCONV_TO_U2:
2510                         NOT_IMPLEMENTED;
2511                         break;
2512                 case OP_FCONV_TO_I4:
2513                 case OP_FCONV_TO_I:
2514                         sparc_fdtoi (code, ins->sreg1, sparc_f0);
2515                         sparc_stdf_imm (code, sparc_f0, sparc_sp, cfg->stack_offset - 8);
2516                         sparc_ld_imm (code, sparc_sp, cfg->stack_offset - 8, ins->dreg);
2517                         break;
2518                 case OP_FCONV_TO_U4:
2519                 case OP_FCONV_TO_U:
2520                         NOT_IMPLEMENTED;
2521                         break;
2522                 case OP_FCONV_TO_I8:
2523                 case OP_FCONV_TO_U8:
2524                         NOT_IMPLEMENTED;
2525                         break;
2526                 case OP_LCONV_TO_R_UN: { 
2527                         NOT_IMPLEMENTED;
2528                         break;
2529                 }
2530                 case OP_LCONV_TO_OVF_I: {
2531                         guint32 *br [3], *label [1];
2532
2533                         /* 
2534                          * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
2535                          */
2536                         sparc_cmp_imm (code, ins->sreg1, 0);
2537                         br [0] = code; 
2538                         sparc_branch (code, 1, sparc_bneg, 0);
2539                         sparc_nop (code);
2540
2541                         /* positive */
2542                         /* ms word must be 0 */
2543                         sparc_cmp_imm (code, ins->sreg2, 0);
2544                         br [1] = code;
2545                         sparc_branch (code, 1, sparc_be, 0);
2546                         sparc_nop (code);
2547
2548                         label [0] = code;
2549                         /* FIXME: throw exception */
2550
2551                         /* negative */
2552                         sparc_patch (br [0], code);
2553
2554                         /* ms word must 0xfffffff */
2555                         sparc_cmp_imm (code, ins->sreg2, -1);
2556                         sparc_branch (code, 1, sparc_bne, label [0]);
2557
2558                         /* Ok */
2559                         sparc_patch (br [1], code);
2560                         if (ins->sreg1 != ins->dreg)
2561                                 sparc_mov_reg_reg (code, ins->sreg1, ins->dreg);
2562                         break;
2563                 }
2564                 case OP_FADD:
2565                         sparc_faddd (code, ins->sreg1, ins->sreg2, ins->dreg);
2566                         break;
2567                 case OP_FSUB:
2568                         sparc_fsubd (code, ins->sreg1, ins->sreg2, ins->dreg);
2569                         break;          
2570                 case OP_FMUL:
2571                         sparc_fmuld (code, ins->sreg1, ins->sreg2, ins->dreg);
2572                         break;          
2573                 case OP_FDIV:
2574                         sparc_fdivd (code, ins->sreg1, ins->sreg2, ins->dreg);
2575                         break;          
2576                 case OP_FNEG:
2577                         sparc_fnegs (code, ins->sreg1, ins->dreg);
2578                         break;          
2579                 case OP_FREM:
2580                         sparc_fdivd (code, ins->sreg1, ins->sreg2, sparc_f0);
2581                         sparc_fmuld (code, ins->sreg2, sparc_f0, sparc_f0);
2582                         sparc_fsubd (code, ins->sreg1, sparc_f0, ins->dreg);
2583                         break;
2584                 case OP_FCOMPARE:
2585                         sparc_fcmpd (code, ins->sreg1, ins->sreg2);
2586                         break;
2587                 case OP_FCEQ:
2588                 case OP_FCLT:
2589                 case OP_FCLT_UN:
2590                 case OP_FCGT:
2591                 case OP_FCGT_UN:
2592                         sparc_fcmpd (code, ins->sreg1, ins->sreg2);
2593                         sparc_clr_reg (code, ins->dreg);
2594                         switch (ins->opcode) {
2595                         case OP_FCLT_UN:
2596                         case OP_FCGT_UN:
2597                                 sparc_fbranch (code, 1, opcode_to_sparc_cond (ins->opcode), 4);
2598                                 /* delay slot */
2599                                 sparc_set (code, 1, ins->dreg);
2600                                 sparc_fbranch (code, 1, sparc_fbu, 2);
2601                                 /* delay slot */
2602                                 sparc_set (code, 1, ins->dreg);
2603                                 break;
2604                         default:
2605                                 sparc_fbranch (code, 1, opcode_to_sparc_cond (ins->opcode), 2);
2606                                 /* delay slot */
2607                                 sparc_set (code, 1, ins->dreg);                         
2608                         }
2609                         break;
2610                 case OP_FBEQ:
2611                 case OP_FBLT:
2612                 case OP_FBGT:
2613                         EMIT_FLOAT_COND_BRANCH (ins, opcode_to_sparc_cond (ins->opcode));
2614                         break;
2615                 case OP_FBGE: {
2616                         /* clt.un + brfalse */
2617                         guint32 *p = code;
2618                         sparc_fbranch (code, 1, sparc_fbul, 0);
2619                         /* delay slot */
2620                         sparc_nop (code);
2621                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fba);
2622                         sparc_patch ((guint8*)p, (guint8*)code);
2623                         break;
2624                 }
2625                 case OP_FBLE: {
2626                         /* cgt.un + brfalse */
2627                         guint32 *p = code;
2628                         sparc_fbranch (code, 1, sparc_fbug, 0);
2629                         /* delay slot */
2630                         sparc_nop (code);
2631                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fba);
2632                         sparc_patch ((guint8*)p, (guint8*)code);
2633                         break;
2634                 }
2635                 case OP_FBNE_UN:
2636                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbne);
2637                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbu);
2638                         break;
2639                 case OP_FBLT_UN:
2640                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbl);
2641                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbu);
2642                         break;
2643                 case OP_FBGT_UN:
2644                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbg);
2645                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbu);
2646                         break;
2647                 case OP_FBGE_UN:
2648                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbge);
2649                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbu);
2650                         break;
2651                 case OP_FBLE_UN:
2652                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fble);
2653                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbu);
2654                         break;
2655                 case CEE_CKFINITE: {
2656                         NOT_IMPLEMENTED;
2657                         break;
2658                 }
2659                 default:
2660 #ifdef __GNUC__
2661                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
2662 #else
2663                         g_warning ("%s:%d: unknown opcode %s\n", __FILE__, __LINE__, mono_inst_name (ins->opcode));
2664 #endif
2665                         g_assert_not_reached ();
2666                 }
2667
2668                 if ((cfg->opt & MONO_OPT_BRANCH) && (((guint8*)code - cfg->native_code - offset) > max_len)) {
2669                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
2670                                    mono_inst_name (ins->opcode), max_len, (guint8*)code - cfg->native_code - offset);
2671                         g_assert_not_reached ();
2672                 }
2673                
2674                 cpos += max_len;
2675
2676                 last_ins = ins;
2677                 last_offset = offset;
2678                 
2679                 ins = ins->next;
2680         }
2681
2682         cfg->code_len = (guint8*)code - cfg->native_code;
2683 }
2684
2685 void
2686 mono_arch_register_lowlevel_calls (void)
2687 {
2688         mono_register_jit_icall (mono_sparc_break, "mono_sparc_break", NULL, TRUE);
2689 }
2690
2691 void
2692 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
2693 {
2694         MonoJumpInfo *patch_info;
2695
2696         /* FIXME: Move part of this to arch independent code */
2697         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
2698                 unsigned char *ip = patch_info->ip.i + code;
2699                 const unsigned char *target = NULL;
2700
2701                 switch (patch_info->type) {
2702                 case MONO_PATCH_INFO_BB:
2703                         target = patch_info->data.bb->native_offset + code;
2704                         break;
2705                 case MONO_PATCH_INFO_ABS:
2706                         target = patch_info->data.target;
2707                         break;
2708                 case MONO_PATCH_INFO_LABEL:
2709                         target = patch_info->data.inst->inst_c0 + code;
2710                         break;
2711                 case MONO_PATCH_INFO_IP:
2712                         *((gpointer *)(ip)) = ip;
2713                         continue;
2714                 case MONO_PATCH_INFO_METHOD_REL:
2715                         NOT_IMPLEMENTED;
2716                         *((gpointer *)(ip)) = code + patch_info->data.offset;
2717                         continue;
2718                 case MONO_PATCH_INFO_INTERNAL_METHOD: {
2719                         MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
2720                         if (!mi) {
2721                                 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
2722                                 g_assert_not_reached ();
2723                         }
2724                         target = mono_icall_get_wrapper (mi);
2725                         break;
2726                 }
2727                 case MONO_PATCH_INFO_METHOD_JUMP: {
2728                         GSList *list;
2729
2730                         /* get the trampoline to the method from the domain */
2731                         target = mono_arch_create_jump_trampoline (patch_info->data.method);
2732                         if (!domain->jump_target_hash)
2733                                 domain->jump_target_hash = g_hash_table_new (NULL, NULL);
2734                         list = g_hash_table_lookup (domain->jump_target_hash, patch_info->data.method);
2735                         list = g_slist_prepend (list, ip);
2736                         g_hash_table_insert (domain->jump_target_hash, patch_info->data.method, list);
2737                         break;
2738                 }
2739                 case MONO_PATCH_INFO_METHOD:
2740                         if (patch_info->data.method == method) {
2741                                 target = code;
2742                         } else
2743                                 /* get the trampoline to the method from the domain */
2744                                 target = mono_arch_create_jit_trampoline (patch_info->data.method);
2745                         break;
2746                 case MONO_PATCH_INFO_SWITCH: {
2747                         guint32 *p = (guint32*)ip;
2748                         gpointer *jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->table_size);
2749                         int i;
2750
2751                         target = jump_table;
2752
2753                         for (i = 0; i < patch_info->table_size; i++) {
2754                                 jump_table [i] = code + (int)patch_info->data.table [i];
2755                         }
2756                         break;
2757                 }
2758                 case MONO_PATCH_INFO_METHODCONST:
2759                 case MONO_PATCH_INFO_CLASS:
2760                 case MONO_PATCH_INFO_IMAGE:
2761                 case MONO_PATCH_INFO_FIELD:
2762                         NOT_IMPLEMENTED;
2763                         *((gconstpointer *)(ip + 1)) = patch_info->data.target;
2764                         continue;
2765                 case MONO_PATCH_INFO_IID:
2766                         NOT_IMPLEMENTED;
2767                         mono_class_init (patch_info->data.klass);
2768                         *((guint32 *)(ip + 1)) = patch_info->data.klass->interface_id;
2769                         continue;                       
2770                 case MONO_PATCH_INFO_VTABLE:
2771                         NOT_IMPLEMENTED;
2772                         *((gconstpointer *)(ip + 1)) = mono_class_vtable (domain, patch_info->data.klass);
2773                         continue;
2774                 case MONO_PATCH_INFO_CLASS_INIT: {
2775                         /* Might already been changed to a nop */
2776                         target = mono_create_class_init_trampoline (mono_class_vtable (domain, patch_info->data.klass));
2777                         break;
2778                 }
2779                 case MONO_PATCH_INFO_SFLDA: {
2780                         MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
2781                         if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && mono_class_needs_cctor_run (vtable->klass, method))
2782                                 /* Done by the generated code */
2783                                 ;
2784                         else {
2785                                 if (run_cctors)
2786                                         mono_runtime_class_init (vtable);
2787                         }
2788                         NOT_IMPLEMENTED;
2789                         *((gconstpointer *)(ip + 1)) = 
2790                                 (char*)vtable->data + patch_info->data.field->offset;
2791                         continue;
2792                 }
2793                 case MONO_PATCH_INFO_R4: {
2794                         float *f = g_new0 (float, 1);
2795                         *f = *(float*)patch_info->data.target;
2796                         target = f;
2797                         break;
2798                 }
2799                 case MONO_PATCH_INFO_R8: {
2800                         double *d = g_new0 (double, 1);
2801                         *d = *(double*)patch_info->data.target;
2802                         target = d;                     
2803                         break;
2804                 }
2805                 case MONO_PATCH_INFO_EXC_NAME:
2806                         NOT_IMPLEMENTED;
2807                         *((gconstpointer *)(ip + 1)) = patch_info->data.name;
2808                         continue;
2809                 case MONO_PATCH_INFO_LDSTR:
2810                         NOT_IMPLEMENTED;
2811                         *((gconstpointer *)(ip + 1)) = 
2812                                 mono_ldstr (domain, patch_info->data.token->image, 
2813                                                         mono_metadata_token_index (patch_info->data.token->token));
2814                         continue;
2815                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
2816                         gpointer handle;
2817                         MonoClass *handle_class;
2818
2819                         handle = mono_ldtoken (patch_info->data.token->image, 
2820                                                                    patch_info->data.token->token, &handle_class);
2821                         mono_class_init (handle_class);
2822                         mono_class_init (mono_class_from_mono_type (handle));
2823
2824                         NOT_IMPLEMENTED;
2825                         *((gconstpointer *)(ip + 1)) = 
2826                                 mono_type_get_object (domain, handle);
2827                         continue;
2828                 }
2829                 case MONO_PATCH_INFO_LDTOKEN: {
2830                         gpointer handle;
2831                         MonoClass *handle_class;
2832
2833                         handle = mono_ldtoken (patch_info->data.token->image,
2834                                                                    patch_info->data.token->token, &handle_class);
2835                         mono_class_init (handle_class);
2836
2837                         NOT_IMPLEMENTED;
2838                         *((gconstpointer *)(ip + 1)) = handle;
2839                         continue;
2840                 }
2841                 default:
2842                         g_assert_not_reached ();
2843                 }
2844                 sparc_patch (ip, target);
2845         }
2846 }
2847
2848 /*
2849  * Allow tracing to work with this interface (with an optional argument)
2850  */
2851
2852 /*
2853  * This may be needed on some archs or for debugging support.
2854  */
2855 void
2856 mono_arch_instrument_mem_needs (MonoMethod *method, int *stack, int *code)
2857 {
2858         /* no stack room needed now (may be needed for FASTCALL-trace support) */
2859         *stack = 0;
2860         /* split prolog-epilog requirements? */
2861         *code = 256; /* max bytes needed: check this number */
2862 }
2863
2864 void*
2865 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
2866 {
2867         int stack, code_size;
2868         guint32 *code = (guint32*)p;
2869
2870         /* Save registers to stack */
2871         sparc_st_imm (code, sparc_i0, sparc_fp, 68);
2872         sparc_st_imm (code, sparc_i1, sparc_fp, 72);
2873         sparc_st_imm (code, sparc_i2, sparc_fp, 76);
2874         sparc_st_imm (code, sparc_i3, sparc_fp, 80);
2875         sparc_st_imm (code, sparc_i4, sparc_fp, 84);
2876
2877         sparc_set (code, cfg->method, sparc_o0);
2878         sparc_mov_reg_reg (code, sparc_fp, sparc_o1);
2879
2880         mono_add_patch_info (cfg, (guint8*)code-cfg->native_code, MONO_PATCH_INFO_ABS, func);
2881         sparc_sethi (code, 0, sparc_o7);
2882         sparc_jmpl_imm (code, sparc_o7, 0, sparc_callsite);
2883         sparc_nop (code);
2884
2885         mono_arch_instrument_mem_needs (cfg->method, &stack, &code_size);
2886
2887         g_assert ((code - (guint32*)p) <= (code_size * 4));
2888
2889         return code;
2890 }
2891
2892 enum {
2893         SAVE_NONE,
2894         SAVE_STRUCT,
2895         SAVE_ONE,
2896         SAVE_TWO,
2897         SAVE_FP
2898 };
2899
2900 void*
2901 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
2902 {
2903         guchar *code = p;
2904         int arg_size = 0, save_mode = SAVE_NONE;
2905         MonoMethod *method = cfg->method;
2906         int rtype = method->signature->ret->type;
2907         
2908 handle_enum:
2909         switch (rtype) {
2910         case MONO_TYPE_VOID:
2911                 /* special case string .ctor icall */
2912                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
2913                         save_mode = SAVE_ONE;
2914                 else
2915                         save_mode = SAVE_NONE;
2916                 break;
2917         case MONO_TYPE_I8:
2918         case MONO_TYPE_U8:
2919                 save_mode = SAVE_TWO;
2920                 break;
2921         case MONO_TYPE_R4:
2922         case MONO_TYPE_R8:
2923                 save_mode = SAVE_FP;
2924                 break;
2925         case MONO_TYPE_VALUETYPE:
2926                 if (method->signature->ret->data.klass->enumtype) {
2927                         rtype = method->signature->ret->data.klass->enum_basetype->type;
2928                         goto handle_enum;
2929                 }
2930                 save_mode = SAVE_STRUCT;
2931                 break;
2932         default:
2933                 save_mode = SAVE_ONE;
2934                 break;
2935         }
2936
2937         /* Save the result to the stack and also put it into the output registers */
2938
2939         switch (save_mode) {
2940         case SAVE_TWO:
2941                 sparc_st_imm (code, sparc_i0, sparc_fp, 68);
2942                 sparc_st_imm (code, sparc_i0, sparc_fp, 72);
2943                 sparc_mov_reg_reg (code, sparc_i0, sparc_o1);
2944                 sparc_mov_reg_reg (code, sparc_i1, sparc_o2);
2945                 break;
2946         case SAVE_ONE:
2947                 sparc_st_imm (code, sparc_i0, sparc_fp, 68);
2948                 sparc_mov_reg_reg (code, sparc_i0, sparc_o1);
2949                 break;
2950         case SAVE_FP:
2951                 sparc_stdf (code, sparc_f0, sparc_fp, 72);
2952                 sparc_ld_imm (code, sparc_fp, 72, sparc_o1);
2953                 sparc_ld_imm (code, sparc_fp, 72, sparc_o2);
2954                 break;
2955         case SAVE_STRUCT:
2956                 sparc_ld_imm (code, sparc_fp, 64, sparc_o1);
2957                 break;
2958         case SAVE_NONE:
2959         default:
2960                 break;
2961         }
2962
2963         sparc_set (code, cfg->method, sparc_o0);
2964
2965         mono_add_patch_info (cfg, (guint8*)code-cfg->native_code, MONO_PATCH_INFO_ABS, func);
2966         sparc_sethi (code, 0, sparc_o7);
2967         sparc_jmpl_imm (code, sparc_o7, 0, sparc_callsite);
2968         sparc_nop (code);
2969
2970         /* Restore result */
2971
2972         switch (save_mode) {
2973         case SAVE_TWO:
2974                 sparc_ld_imm (code, sparc_fp, 68, sparc_i0);
2975                 sparc_ld_imm (code, sparc_fp, 72, sparc_i0);
2976                 break;
2977         case SAVE_ONE:
2978                 sparc_ld_imm (code, sparc_fp, 68, sparc_i0);
2979                 break;
2980         case SAVE_FP:
2981                 sparc_lddf_imm (code, sparc_fp, 72, sparc_f0);
2982                 break;
2983         case SAVE_NONE:
2984         default:
2985                 break;
2986         }
2987
2988         return code;
2989 }
2990
2991 int
2992 mono_arch_max_epilog_size (MonoCompile *cfg)
2993 {
2994         int exc_count = 0, max_epilog_size = 16 + 20*4;
2995         MonoJumpInfo *patch_info;
2996         
2997         if (cfg->method->save_lmf)
2998                 max_epilog_size += 128;
2999         
3000         if (mono_jit_trace_calls != NULL)
3001                 max_epilog_size += 50;
3002
3003         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3004                 max_epilog_size += 50;
3005
3006         /* count the number of exception infos */
3007      
3008         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3009                 if (patch_info->type == MONO_PATCH_INFO_EXC)
3010                         exc_count++;
3011         }
3012
3013         /* 
3014          * make sure we have enough space for exceptions
3015          * 16 is the size of two push_imm instructions and a call
3016          */
3017         max_epilog_size += exc_count*16;
3018
3019         return max_epilog_size;
3020 }
3021
3022 guint8 *
3023 mono_arch_emit_prolog (MonoCompile *cfg)
3024 {
3025         MonoMethod *method = cfg->method;
3026         MonoBasicBlock *bb;
3027         MonoMethodSignature *sig;
3028         MonoInst *inst;
3029         int alloc_size, pos, max_offset, i;
3030         guint8 *code;
3031         CallInfo *cinfo;
3032
3033         cfg->code_size = 256;
3034         code = cfg->native_code = g_malloc (cfg->code_size);
3035
3036         /* 
3037          * Align stack_offset. It is aligned at the end of allocate_vars, but
3038          * spillvars may make in unaligned.
3039          */
3040         cfg->stack_offset += (MONO_ARCH_FRAME_ALIGNMENT - 1);
3041         cfg->stack_offset &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
3042
3043         if (!sparc_is_imm13 (- cfg->stack_offset)) {
3044                 /* Can't use sparc_o7 here, since we're still in the caller's frame */
3045                 sparc_set (code, (- cfg->stack_offset), sparc_g1);
3046                 sparc_save (code, sparc_sp, sparc_g1, sparc_sp);
3047         }
3048         else
3049                 sparc_save_imm (code, sparc_sp, - cfg->stack_offset, sparc_sp);
3050
3051         sig = method->signature;
3052         pos = 0;
3053         if (sig->hasthis)
3054                 pos ++;
3055
3056         cinfo = get_call_info (sig, FALSE);
3057
3058         for (i = 0; i < sig->param_count; ++i) {
3059                 ArgInfo *ainfo = cinfo->args + pos;
3060                 guint32 stack_offset;
3061                 inst = cfg->varinfo [pos];
3062
3063                 stack_offset = ainfo->offset + 68;
3064
3065                 /* Save the split arguments so they will reside entirely on the stack */
3066                 if (ainfo->storage == ArgInSplitRegStack) {
3067                         /* Save the register to the stack */
3068                         g_assert (inst->opcode == OP_REGOFFSET);
3069                         if (!sparc_is_imm13 (stack_offset))
3070                                 NOT_IMPLEMENTED;
3071                         sparc_st_imm (code, sparc_i5, inst->inst_basereg, stack_offset);
3072                 }
3073
3074                 if (sig->params [i]->type == MONO_TYPE_R8) {
3075                         /* Save the argument to a dword aligned stack location */
3076                         /*
3077                          * stack_offset contains the offset of the argument on the stack.
3078                          * inst->inst_offset contains the dword aligned offset where the value 
3079                          * should be stored.
3080                          */
3081                         if (ainfo->storage == ArgInIRegPair) {
3082                                 if (!sparc_is_imm13 (inst->inst_offset + 4))
3083                                         NOT_IMPLEMENTED;
3084                                 sparc_st_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, inst->inst_offset);
3085                                 sparc_st_imm (code, sparc_i0 + ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
3086                         }
3087                         else
3088                                 if (ainfo->storage == ArgInSplitRegStack) {
3089                                         if (stack_offset != inst->inst_offset) {
3090                                                 /* stack_offset is not dword aligned, so we need to make a copy */
3091                                                 sparc_st_imm (code, sparc_i5, inst->inst_basereg, inst->inst_offset);
3092                                                 sparc_ld_imm (code, sparc_fp, stack_offset + 4, sparc_o7);
3093                                                 sparc_st_imm (code, sparc_o7, inst->inst_basereg, inst->inst_offset + 4);
3094                                         }
3095                                 }
3096                         else
3097                                 if (ainfo->storage == ArgOnStackPair) {
3098                                         if (stack_offset != inst->inst_offset) {
3099                                                 /* stack_offset is not dword aligned, so we need to make a copy */
3100                                                 sparc_ld_imm (code, sparc_fp, stack_offset, sparc_o7);
3101                                                 sparc_st_imm (code, sparc_o7, inst->inst_basereg, inst->inst_offset);
3102                                                 sparc_ld_imm (code, sparc_fp, stack_offset + 4, sparc_o7);
3103                                                 sparc_st_imm (code, sparc_o7, inst->inst_basereg, inst->inst_offset + 4);
3104                                         }
3105                                 }
3106                         else
3107                                 g_assert_not_reached ();
3108                 }
3109                 else
3110                         if ((ainfo->storage == ArgInIReg) && (inst->opcode != OP_REGVAR)) {
3111                                 /* Argument in register, but need to be saved to stack */
3112                                 if (!sparc_is_imm13 (stack_offset))
3113                                         NOT_IMPLEMENTED;
3114                                 sparc_st_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, stack_offset);
3115                         }
3116                 else
3117                         if ((ainfo->storage == ArgInIRegPair) && (inst->opcode != OP_REGVAR)) {
3118                                 /* Argument in regpair, but need to be saved to stack */
3119                                 g_assert (((inst->inst_offset) % 8) == 0);
3120                                 if (!sparc_is_imm13 (inst->inst_offset + 4))
3121                                         NOT_IMPLEMENTED;
3122                                 sparc_st_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, inst->inst_offset);
3123                                 sparc_st_imm (code, sparc_i0 + ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);                              
3124                         }
3125
3126                 if ((ainfo->storage == ArgInSplitRegStack) || (ainfo->storage == ArgOnStack))
3127                         if (inst->opcode == OP_REGVAR)
3128                                 /* FIXME: Load the argument into memory */
3129                                 NOT_IMPLEMENTED;
3130
3131                 pos++;
3132         }
3133
3134         g_free (cinfo);
3135
3136         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3137                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3138
3139         cfg->code_len = code - cfg->native_code;
3140
3141         g_assert (cfg->code_len <= cfg->code_size);
3142
3143         return code;
3144 }
3145
3146 void
3147 mono_arch_emit_epilog (MonoCompile *cfg)
3148 {
3149         MonoJumpInfo *patch_info;
3150         MonoMethod *method = cfg->method;
3151         int pos, i;
3152         guint8 *code;
3153
3154         code = cfg->native_code + cfg->code_len;
3155
3156         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3157                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3158
3159         sparc_ret (code);
3160         sparc_restore_imm (code, sparc_g0, 0, sparc_g0);
3161
3162 #if 0
3163
3164         
3165         pos = 0;
3166         
3167         if (method->save_lmf) {
3168                 pos = -sizeof (MonoLMF);
3169         }
3170
3171         if (method->save_lmf) {
3172 #if 0
3173                 /* ebx = previous_lmf */
3174                 x86_pop_reg (code, X86_EBX);
3175                 /* edi = lmf */
3176                 x86_pop_reg (code, X86_EDI);
3177                 /* *(lmf) = previous_lmf */
3178                 x86_mov_membase_reg (code, X86_EDI, 0, X86_EBX, 4);
3179
3180                 /* discard method info */
3181                 x86_pop_reg (code, X86_ESI);
3182
3183                 /* restore caller saved regs */
3184                 x86_pop_reg (code, X86_EBP);
3185                 x86_pop_reg (code, X86_ESI);
3186                 x86_pop_reg (code, X86_EDI);
3187                 x86_pop_reg (code, X86_EBX);
3188 #endif
3189         }
3190
3191         if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3192                 //ppc_lwz (code, sparc_l0, cfg->stack_usage + 8, cfg->frame_reg);
3193                 //ppc_mtlr (code, sparc_l0);
3194         }
3195         //ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3196         for (i = 13; i < 32; ++i) {
3197                 if (cfg->used_int_regs & (1 << i)) {
3198                         pos += 4;
3199                         //ppc_lwz (code, i, -pos, cfg->frame_reg);
3200                 }
3201         }
3202         //ppc_blr (code);
3203
3204         /* add code to raise exceptions */
3205         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3206                 switch (patch_info->type) {
3207                 case MONO_PATCH_INFO_EXC:
3208                         /*x86_patch (patch_info->ip.i + cfg->native_code, code);
3209                         x86_push_imm (code, patch_info->data.target);
3210                         x86_push_imm (code, patch_info->ip.i + cfg->native_code);
3211                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3212                         patch_info->data.name = "throw_exception_by_name";
3213                         patch_info->ip.i = code - cfg->native_code;
3214                         x86_jump_code (code, 0);*/
3215                         break;
3216                 default:
3217                         /* do nothing */
3218                         break;
3219                 }
3220         }
3221 #endif
3222
3223         cfg->code_len = code - cfg->native_code;
3224
3225         g_assert (cfg->code_len < cfg->code_size);
3226
3227 }
3228
3229 void
3230 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3231 {
3232 }
3233
3234 void
3235 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3236 {
3237 }
3238
3239 void
3240 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3241 {
3242         /* add the this argument */
3243         if (this_reg != -1) {
3244                 MonoInst *this;
3245                 MONO_INST_NEW (cfg, this, OP_SETREG);
3246                 this->type = this_type;
3247                 this->sreg1 = this_reg;
3248                 this->dreg = sparc_o0;
3249                 mono_bblock_add_inst (cfg->cbb, this);
3250         }
3251
3252         if (vt_reg != -1) {
3253                 /* Set the 'struct/union return pointer' location on the stack */
3254                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, sparc_sp, 64, vt_reg);
3255         }
3256 }
3257
3258
3259 gint
3260 mono_arch_get_opcode_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3261 {
3262         return -1;
3263 }
3264
3265 /*
3266  * mono_arch_get_argument_info:
3267  * @csig:  a method signature
3268  * @param_count: the number of parameters to consider
3269  * @arg_info: an array to store the result infos
3270  *
3271  * Gathers information on parameters such as size, alignment and
3272  * padding. arg_info should be large enought to hold param_count + 1 entries. 
3273  *
3274  * Returns the size of the activation frame.
3275  */
3276 int
3277 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
3278 {
3279         int k, frame_size = 0;
3280         int size, align, pad;
3281         int offset = 8;
3282         CallInfo *cinfo;
3283         ArgInfo *ainfo;
3284
3285         cinfo = get_call_info (csig, FALSE);
3286
3287         if (csig->hasthis) {
3288                 ainfo = &cinfo->args [0];
3289                 arg_info [0].offset = 68 + ainfo->offset;
3290         }
3291
3292         for (k = 0; k < param_count; k++) {
3293                 ainfo = &cinfo->args [k + csig->hasthis];
3294
3295                 arg_info [k + 1].offset = 68 + ainfo->offset;
3296                 arg_info [k + 1].size = mono_type_size (csig->params [k], &align);
3297         }
3298
3299         g_free (cinfo);
3300
3301         /* FIXME: */
3302         return 0;
3303 }