2004-11-03 Sebastien Pouliot <sebastien@ximian.com>
[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 #include <pthread.h>
18 #include <unistd.h>
19
20 #ifndef __linux__
21 #include <sys/systeminfo.h>
22 #include <thread.h>
23 #endif
24
25 #include <mono/metadata/appdomain.h>
26 #include <mono/metadata/debug-helpers.h>
27 #include <mono/utils/mono-math.h>
28
29 #include "mini-sparc.h"
30 #include "inssel.h"
31 #include "trace.h"
32 #include "cpu-sparc.h"
33
34 /*
35  * Sparc V9 means two things:
36  * - the instruction set
37  * - the ABI
38  *
39  * V9 instructions are only usable if the underlying processor is 64 bit. Most Sparc 
40  * processors in use are 64 bit processors. The V9 ABI is only usable if the 
41  * mono executable is a 64 bit executable. So it would make sense to use the 64 bit
42  * instructions without using the 64 bit ABI.
43  */
44
45 /*
46  * Register usage:
47  * - %i0..%i<n> hold the incoming arguments, these are never written by JITted 
48  * code. Unused input registers are used for global register allocation.
49  * - %l0..%l7 is used for local register allocation
50  * - %o0..%o6 is used for outgoing arguments
51  * - %o7 and %g1 is used as scratch registers in opcodes
52  * - all floating point registers are used for local register allocation except %f0. 
53  *   Only double precision registers are used.
54  */
55
56 /*
57  * Alignment:
58  * - doubles and longs must be stored in dword aligned locations
59  */
60
61 /*
62  * The following things are not implemented or do not work:
63  *  - some fp arithmetic corner cases
64  * The following tests in mono/mini are expected to fail:
65  *  - test_0_simple_double_casts
66  *      This test casts (guint64)-1 to double and then back to guint64 again.
67  *    Under x86, it returns 0, while under sparc it returns -1.
68  *
69  * In addition to this, the runtime requires the truncl function, or its 
70  * solaris counterpart, aintl, to do some double->int conversions. If this 
71  * function is not available, it is emulated somewhat, but the results can be
72  * strange.
73  */
74
75 /*
76  * Possible optimizations:
77  * - delay slot scheduling
78  * - allocate large constants to registers
79  * - use %o registers for local allocation
80  * - implement unwinding through native frames
81  * - add more mul/div/rem optimizations
82  */
83
84 #if SPARCV9
85 #error "Sparc V9 support not yet implemented."
86 #endif
87
88 #ifndef __linux__
89 #define MONO_SPARC_THR_TLS 1
90 #endif
91
92 #define NOT_IMPLEMENTED g_assert_not_reached ();
93
94 #define ALIGN_TO(val,align) (((val) + ((align) - 1)) & ~((align) - 1))
95
96 #define SIGNAL_STACK_SIZE (64 * 1024)
97
98 /* Whenever the CPU supports v9 instructions */
99 gboolean sparcv9 = FALSE;
100
101 static gpointer mono_arch_get_lmf_addr (void);
102
103 static int
104 mono_spillvar_offset_float (MonoCompile *cfg, int spillvar);
105
106 const char*
107 mono_arch_regname (int reg) {
108         static const char * rnames[] = {
109                 "sparc_g0", "sparc_g1", "sparc_g2", "sparc_g3", "sparc_g4",
110                 "sparc_g5", "sparc_g6", "sparc_g7", "sparc_o0", "sparc_o1",
111                 "sparc_o2", "sparc_o3", "sparc_o4", "sparc_o5", "sparc_sp",
112                 "sparc_call", "sparc_l0", "sparc_l1", "sparc_l2", "sparc_l3",
113                 "sparc_l4", "sparc_l5", "sparc_l6", "sparc_l7", "sparc_i0",
114                 "sparc_i1", "sparc_i2", "sparc_i3", "sparc_i4", "sparc_i5",
115                 "sparc_fp", "sparc_retadr"
116         };
117         if (reg >= 0 && reg < 32)
118                 return rnames [reg];
119         return "unknown";
120 }
121
122 /*
123  * Initialize the cpu to execute managed code.
124  */
125 void
126 mono_arch_cpu_init (void)
127 {
128 }
129
130 /*
131  * This function returns the optimizations supported on this cpu.
132  */
133 guint32
134 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
135 {
136         char buf [1024];
137         guint32 opts = 0;
138
139         *exclude_mask = 0;
140
141 #ifndef __linux__
142         if (!sysinfo (SI_ISALIST, buf, 1024))
143                 g_assert_not_reached ();
144 #else
145         /* From glibc.  If the getpagesize is 8192, we're on sparc64, which
146          * (in)directly implies that we're a v9 or better.
147          * Improvements to this are greatly accepted...
148          * Also, we don't differentiate between v7 and v8.  I sense SIGILL
149          * sniffing in my future.  
150          */
151         if (getpagesize() == 8192)
152                 strcpy (buf, "sparcv9");
153         else
154                 strcpy (buf, "sparcv8");
155 #endif
156
157         /* 
158          * On some processors, the cmov instructions are even slower than the
159          * normal ones...
160          */
161         if (strstr (buf, "sparcv9")) {
162                 opts |= MONO_OPT_CMOV | MONO_OPT_FCMOV;
163                 sparcv9 = TRUE;
164         }
165         else
166                 *exclude_mask |= MONO_OPT_CMOV | MONO_OPT_FCMOV;
167
168         return opts;
169 }
170
171 static void
172 mono_sparc_break (void)
173 {
174 }
175
176 #ifdef __GNUC__
177 #define flushi(addr)    __asm__ __volatile__ ("iflush %0"::"r"(addr):"memory")
178 #else /* assume Sun's compiler */
179 static void flushi(void *addr)
180 {
181     asm("flush %i0");
182 }
183 #endif
184
185 void
186 mono_arch_flush_icache (guint8 *code, gint size)
187 {
188 #ifndef __linux__
189         /* Hopefully this is optimized based on the actual CPU */
190         sync_instruction_memory (code, size);
191 #else
192         guint64 *p = (guint64*)code;
193         guint64 *end = (guint64*)(code + ((size + 8) /8));
194
195         /* 
196          * FIXME: Flushing code in dword chunks in _slow_.
197          */
198         while (p < end)
199 #ifdef __GNUC__
200                 __asm__ __volatile__ ("iflush %0"::"r"(p++));
201 #else
202                         flushi (p ++);
203 #endif
204 #endif
205 }
206
207 /*
208  * mono_sparc_flushw:
209  *
210  * Flush all register windows to memory. Every register window is saved to
211  * a 16 word area on the stack pointed to by its %sp register.
212  */
213 void
214 mono_sparc_flushw (void)
215 {
216         static guint32 start [64];
217         static int inited = 0;
218         guint32 *code;
219         static void (*flushw) (void);
220
221         if (!inited) {
222                 code = start;
223
224                 sparc_save_imm (code, sparc_sp, -160, sparc_sp);
225                 sparc_flushw (code);
226                 sparc_ret (code);
227                 sparc_restore_simple (code);
228
229                 g_assert ((code - start) < 64);
230
231                 flushw = (gpointer)start;
232
233                 inited = 1;
234         }
235
236         flushw ();
237 }
238
239 void
240 mono_arch_flush_register_windows (void)
241 {
242         mono_sparc_flushw ();
243 }
244
245 gboolean 
246 mono_sparc_is_v9 (void) {
247         return sparcv9;
248 }
249
250 typedef enum {
251         ArgInIReg,
252         ArgInIRegPair,
253         ArgInSplitRegStack,
254         ArgInFReg,
255         ArgInFRegPair,
256         ArgOnStack,
257         ArgOnStackPair
258 } ArgStorage;
259
260 typedef struct {
261         gint16 offset;
262         /* This needs to be offset by %i0 or %o0 depending on caller/callee */
263         gint8  reg;
264         ArgStorage storage;
265         guint32 vt_offset; /* for valuetypes */
266 } ArgInfo;
267
268 typedef struct {
269         int nargs;
270         guint32 stack_usage;
271         guint32 reg_usage;
272         ArgInfo ret;
273         ArgInfo sig_cookie;
274         ArgInfo args [1];
275 } CallInfo;
276
277 #define DEBUG(a)
278
279 /* %o0..%o5 */
280 #define PARAM_REGS 6
281
282 static void inline
283 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo, gboolean pair)
284 {
285         ainfo->offset = *stack_size;
286
287         if (!pair) {
288                 if (*gr >= PARAM_REGS) {
289                         ainfo->storage = ArgOnStack;
290                 }
291                 else {
292                         ainfo->storage = ArgInIReg;
293                         ainfo->reg = *gr;
294                         (*gr) ++;
295                 }
296
297                 /* Allways reserve stack space for parameters passed in registers */
298                 (*stack_size) += 4;
299         }
300         else {
301                 if (*gr < PARAM_REGS - 1) {
302                         /* A pair of registers */
303                         ainfo->storage = ArgInIRegPair;
304                         ainfo->reg = *gr;
305                         (*gr) += 2;
306                 }
307                 else if (*gr >= PARAM_REGS) {
308                         /* A pair of stack locations */
309                         ainfo->storage = ArgOnStackPair;
310                         ainfo->offset = *stack_size;
311                 }
312                 else {
313                         ainfo->storage = ArgInSplitRegStack;
314                         ainfo->reg = *gr;
315                         ainfo->offset = *stack_size;
316                         (*gr) ++;
317                 }
318
319                 (*stack_size) += 8;
320         }
321 }
322
323 /*
324  * get_call_info:
325  *
326  *  Obtain information about a call according to the calling convention.
327  * See the "System V ABI, Sparc Processor Supplement" Sparc V8 version document for
328  * more information.
329  */
330 static CallInfo*
331 get_call_info (MonoMethodSignature *sig, gboolean is_pinvoke)
332 {
333         guint32 i, gr, simpletype;
334         int n = sig->hasthis + sig->param_count;
335         guint32 stack_size = 0;
336         CallInfo *cinfo;
337
338         cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
339
340         gr = 0;
341
342         /* this */
343         if (sig->hasthis)
344                 add_general (&gr, &stack_size, cinfo->args + 0, FALSE);
345
346         for (i = 0; i < sig->param_count; ++i) {
347                 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
348
349                 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
350                         /* Emit the signature cookie just before the implicit arguments */
351                         add_general (&gr, &stack_size, &cinfo->sig_cookie, FALSE);
352                         /* Prevent implicit arguments from being passed in registers */
353                         gr = PARAM_REGS;
354                 }
355
356                 DEBUG(printf("param %d: ", i));
357                 if (sig->params [i]->byref) {
358                         DEBUG(printf("byref\n"));
359                         
360                         add_general (&gr, &stack_size, ainfo, FALSE);
361                         continue;
362                 }
363                 simpletype = sig->params [i]->type;
364         enum_calc_size:
365                 switch (simpletype) {
366                 case MONO_TYPE_BOOLEAN:
367                 case MONO_TYPE_I1:
368                 case MONO_TYPE_U1:
369                         add_general (&gr, &stack_size, ainfo, FALSE);
370                         /* the value is in the ls byte */
371                         ainfo->offset += 3;
372                         break;
373                 case MONO_TYPE_I2:
374                 case MONO_TYPE_U2:
375                 case MONO_TYPE_CHAR:
376                         add_general (&gr, &stack_size, ainfo, FALSE);
377                         /* the value is in the ls word */
378                         ainfo->offset += 2;
379                         break;
380                 case MONO_TYPE_I4:
381                 case MONO_TYPE_U4:
382                 case MONO_TYPE_I:
383                 case MONO_TYPE_U:
384                 case MONO_TYPE_PTR:
385                 case MONO_TYPE_CLASS:
386                 case MONO_TYPE_OBJECT:
387                 case MONO_TYPE_STRING:
388                 case MONO_TYPE_SZARRAY:
389                 case MONO_TYPE_ARRAY:
390                         add_general (&gr, &stack_size, ainfo, FALSE);
391                         break;
392                 case MONO_TYPE_VALUETYPE:
393                         if (sig->params [i]->data.klass->enumtype) {
394                                 simpletype = sig->params [i]->data.klass->enum_basetype->type;
395                                 goto enum_calc_size;
396                         }
397
398                         add_general (&gr, &stack_size, ainfo, FALSE);
399                         break;
400                 case MONO_TYPE_TYPEDBYREF:
401                         add_general (&gr, &stack_size, ainfo, FALSE);
402                         break;
403                 case MONO_TYPE_U8:
404                 case MONO_TYPE_I8:
405                         add_general (&gr, &stack_size, ainfo, TRUE);
406                         break;
407                 case MONO_TYPE_R4:
408                         /* single precision values are passed in integer registers */
409                         add_general (&gr, &stack_size, ainfo, FALSE);
410                         break;
411                 case MONO_TYPE_R8:
412                         /* double precision values are passed in a pair of registers */
413                         add_general (&gr, &stack_size, ainfo, TRUE);
414                         break;
415                 default:
416                         g_assert_not_reached ();
417                 }
418         }
419
420         /* return value */
421         {
422                 simpletype = sig->ret->type;
423 enum_retvalue:
424                 switch (simpletype) {
425                 case MONO_TYPE_BOOLEAN:
426                 case MONO_TYPE_I1:
427                 case MONO_TYPE_U1:
428                 case MONO_TYPE_I2:
429                 case MONO_TYPE_U2:
430                 case MONO_TYPE_CHAR:
431                 case MONO_TYPE_I4:
432                 case MONO_TYPE_U4:
433                 case MONO_TYPE_I:
434                 case MONO_TYPE_U:
435                 case MONO_TYPE_PTR:
436                 case MONO_TYPE_CLASS:
437                 case MONO_TYPE_OBJECT:
438                 case MONO_TYPE_SZARRAY:
439                 case MONO_TYPE_ARRAY:
440                 case MONO_TYPE_STRING:
441                         cinfo->ret.storage = ArgInIReg;
442                         cinfo->ret.reg = sparc_i0;
443                         if (gr < 1)
444                                 gr = 1;
445                         break;
446                 case MONO_TYPE_U8:
447                 case MONO_TYPE_I8:
448                         cinfo->ret.storage = ArgInIRegPair;
449                         cinfo->ret.reg = sparc_i0;
450                         if (gr < 2)
451                                 gr = 2;
452                         break;
453                 case MONO_TYPE_R4:
454                 case MONO_TYPE_R8:
455                         cinfo->ret.storage = ArgInFReg;
456                         cinfo->ret.reg = sparc_f0;
457                         break;
458                 case MONO_TYPE_VALUETYPE:
459                         if (sig->ret->data.klass->enumtype) {
460                                 simpletype = sig->ret->data.klass->enum_basetype->type;
461                                 goto enum_retvalue;
462                         }
463                         cinfo->ret.storage = ArgOnStack;
464                         break;
465                 case MONO_TYPE_TYPEDBYREF:
466                         cinfo->ret.storage = ArgOnStack;
467                         break;
468                 case MONO_TYPE_VOID:
469                         break;
470                 default:
471                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
472                 }
473         }
474
475         cinfo->stack_usage = stack_size;
476         cinfo->reg_usage = gr;
477         return cinfo;
478 }
479
480 static gboolean
481 is_regsize_var (MonoType *t) {
482         if (t->byref)
483                 return TRUE;
484         switch (t->type) {
485         case MONO_TYPE_BOOLEAN:
486         case MONO_TYPE_CHAR:
487         case MONO_TYPE_I1:
488         case MONO_TYPE_U1:
489         case MONO_TYPE_I2:
490         case MONO_TYPE_U2:
491         case MONO_TYPE_I4:
492         case MONO_TYPE_U4:
493         case MONO_TYPE_I:
494         case MONO_TYPE_U:
495                 return TRUE;
496         case MONO_TYPE_OBJECT:
497         case MONO_TYPE_STRING:
498         case MONO_TYPE_CLASS:
499         case MONO_TYPE_SZARRAY:
500         case MONO_TYPE_ARRAY:
501                 return TRUE;
502         case MONO_TYPE_VALUETYPE:
503                 if (t->data.klass->enumtype)
504                         return is_regsize_var (t->data.klass->enum_basetype);
505                 return FALSE;
506         }
507         return FALSE;
508 }
509
510 GList *
511 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
512 {
513         GList *vars = NULL;
514         int i;
515
516         /* 
517          * FIXME: If an argument is allocated to a register, then load it from the
518          * stack in the prolog.
519          */
520
521         for (i = 0; i < cfg->num_varinfo; i++) {
522                 MonoInst *ins = cfg->varinfo [i];
523                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
524
525                 /* unused vars */
526                 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
527                         continue;
528
529                 /* FIXME: Make arguments on stack allocateable to registers */
530                 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode == OP_REGVAR) || (ins->opcode == OP_ARG))
531                         continue;
532
533                 /* we can only allocate 32 bit values */
534                 if (is_regsize_var (ins->inst_vtype)) {
535                         g_assert (MONO_VARINFO (cfg, i)->reg == -1);
536                         g_assert (i == vmv->idx);
537
538                         vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
539                 }
540         }
541
542         return vars;
543 }
544
545 GList *
546 mono_arch_get_global_int_regs (MonoCompile *cfg)
547 {
548         GList *regs = NULL;
549         int i;
550         MonoMethodSignature *sig;
551         CallInfo *cinfo;
552
553         sig = cfg->method->signature;
554
555         cinfo = get_call_info (sig, FALSE);
556
557         /* Use unused input registers */
558         for (i = cinfo->reg_usage; i < 6; ++i)
559                 regs = g_list_prepend (regs, GUINT_TO_POINTER (sparc_i0 + i));
560
561         /* Use %l0..%l3 as global registers */
562         for (i = 16; i < 20; ++i)
563                 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
564
565         g_free (cinfo);
566
567         return regs;
568 }
569
570 /*
571  * mono_arch_regalloc_cost:
572  *
573  *  Return the cost, in number of memory references, of the action of 
574  * allocating the variable VMV into a register during global register
575  * allocation.
576  */
577 guint32
578 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
579 {
580         return 0;
581 }
582
583 /*
584  * Set var information according to the calling convention. sparc version.
585  * The locals var stuff should most likely be split in another method.
586  */
587 void
588 mono_arch_allocate_vars (MonoCompile *m)
589 {
590         MonoMethodSignature *sig;
591         MonoMethodHeader *header;
592         MonoInst *inst;
593         int i, offset, size, align, curinst;
594         CallInfo *cinfo;
595
596         header = ((MonoMethodNormal *)m->method)->header;
597
598         sig = m->method->signature;
599
600         cinfo = get_call_info (sig, FALSE);
601
602         if (sig->ret->type != MONO_TYPE_VOID) {
603                 switch (cinfo->ret.storage) {
604                 case ArgInIReg:
605                 case ArgInFReg:
606                 case ArgInIRegPair:
607                         m->ret->opcode = OP_REGVAR;
608                         m->ret->inst_c0 = cinfo->ret.reg;
609                         break;
610                 case ArgOnStack:
611                         /* valuetypes */
612                         m->ret->opcode = OP_REGOFFSET;
613                         m->ret->inst_basereg = sparc_fp;
614                         m->ret->inst_offset = 64;
615                         break;
616                 default:
617                         NOT_IMPLEMENTED;
618                 }
619         }
620
621         /*
622          * We use the Sparc V8 calling conventions for managed code as well.
623          * FIXME: Use something more optimized.
624          */
625
626         /* Locals are allocated backwards from %fp */
627         m->frame_reg = sparc_fp;
628         offset = 0;
629
630         /* 
631          * Reserve a stack slot for holding information used during exception 
632          * handling.
633          */
634         if (header->num_clauses)
635                 offset += 8;
636
637         if (m->method->save_lmf) {
638                 offset += sizeof (MonoLMF);
639                 m->arch.lmf_offset = offset;
640         }
641
642         curinst = m->locals_start;
643         for (i = curinst; i < m->num_varinfo; ++i) {
644                 inst = m->varinfo [i];
645
646                 if (inst->opcode == OP_REGVAR) {
647                         //g_print ("allocating local %d to %s\n", i, mono_arch_regname (inst->dreg));
648                         continue;
649                 }
650
651                 /* inst->unused indicates native sized value types, this is used by the
652                 * pinvoke wrappers when they call functions returning structure */
653                 if (inst->unused && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
654                         size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
655                 else
656                         size = mono_type_stack_size (inst->inst_vtype, &align);
657
658                 /* 
659                  * This is needed since structures containing doubles must be doubleword 
660          * aligned.
661                  * FIXME: Do this only if needed.
662                  */
663                 if (MONO_TYPE_ISSTRUCT (inst->inst_vtype))
664                         align = 8;
665
666                 /*
667                  * variables are accessed as negative offsets from %fp, so increase
668                  * the offset before assigning it to a variable
669                  */
670                 offset += size;
671
672                 offset += align - 1;
673                 offset &= ~(align - 1);
674                 inst->opcode = OP_REGOFFSET;
675                 inst->inst_basereg = sparc_fp;
676                 inst->inst_offset = -offset;
677
678                 //g_print ("allocating local %d to [%s - %d]\n", i, mono_arch_regname (inst->inst_basereg), - inst->inst_offset);
679         }
680
681         if (sig->call_convention == MONO_CALL_VARARG) {
682                 m->sig_cookie = cinfo->sig_cookie.offset + 68;
683         }
684
685         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
686                 inst = m->varinfo [i];
687                 if (inst->opcode != OP_REGVAR) {
688                         ArgInfo *ainfo = &cinfo->args [i];
689                         gboolean inreg = TRUE;
690                         MonoType *arg_type;
691
692                         if (sig->hasthis && (i == 0))
693                                 arg_type = &mono_defaults.object_class->byval_arg;
694                         else
695                                 arg_type = sig->params [i - sig->hasthis];
696
697                         if (!arg_type->byref && ((arg_type->type == MONO_TYPE_R4) 
698                                                                          || (arg_type->type == MONO_TYPE_R8)))
699                                 /*
700                                  * Since float arguments are passed in integer registers, we need to
701                                  * save them to the stack in the prolog.
702                                  */
703                                 inreg = FALSE;
704
705                         /* FIXME: Allocate volatile arguments to registers */
706                         if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
707                                 inreg = FALSE;
708
709                         if (MONO_TYPE_ISSTRUCT (arg_type))
710                                 /* FIXME: this isn't needed */
711                                 inreg = FALSE;
712
713                         switch (ainfo->storage) {
714                         case ArgInIReg:
715                         case ArgInIRegPair:
716                                 if (inreg) {
717                                         inst->opcode = OP_REGVAR;
718                                         inst->dreg = sparc_i0 + ainfo->reg;
719                                         break;
720                                 }
721                                 else {
722                                         /* Fall through */
723                                 }
724                         case ArgOnStack:
725                         case ArgOnStackPair:
726                         case ArgInSplitRegStack:
727                                 /* Split arguments are saved to the stack in the prolog */
728                                 inst->opcode = OP_REGOFFSET;
729                                 /* in parent frame */
730                                 inst->inst_basereg = sparc_fp;
731                                 inst->inst_offset = ainfo->offset + 68;
732
733                                 if (!arg_type->byref && (arg_type->type == MONO_TYPE_R8)) {
734                                         /* 
735                                          * It is very hard to load doubles from non-doubleword aligned
736                                          * memory locations. So if the offset is misaligned, we copy the
737                                          * argument to a stack location in the prolog.
738                                          */
739                                         if (inst->inst_offset % 8) {
740                                                 inst->inst_basereg = sparc_fp;
741                                                 offset += 8;
742                                                 align = 8;
743                                                 offset += align - 1;
744                                                 offset &= ~(align - 1);
745                                                 inst->inst_offset = -offset;
746
747                                         }
748                                 }
749                                 break;
750                         default:
751                                 NOT_IMPLEMENTED;
752                         }
753
754                         if (MONO_TYPE_ISSTRUCT (arg_type)) {
755                                 /* Add a level of indirection */
756                                 /*
757                                  * It would be easier to add OP_LDIND_I here, but ldind_i instructions
758                                  * are destructively modified in a lot of places in inssel.brg.
759                                  */
760                                 MonoInst *indir;
761                                 MONO_INST_NEW (m, indir, 0);
762                                 *indir = *inst;
763                                 inst->opcode = OP_SPARC_INARG_VT;
764                                 inst->inst_left = indir;
765                         }
766                 }
767         }
768
769         /* 
770          * spillvars are stored between the normal locals and the storage reserved
771          * by the ABI.
772          */
773
774         m->stack_offset = offset;
775
776         /* Add a properly aligned dword for use by int<->float conversion opcodes */
777         m->spill_count ++;
778         mono_spillvar_offset_float (m, 0);
779
780         g_free (cinfo);
781 }
782
783 /* 
784  * take the arguments and generate the arch-specific
785  * instructions to properly call the function in call.
786  * This includes pushing, moving arguments to the right register
787  * etc.
788  */
789 MonoCallInst*
790 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
791         MonoInst *arg, *in;
792         MonoMethodSignature *sig;
793         int i, n;
794         CallInfo *cinfo;
795         ArgInfo *ainfo;
796         guint32 extra_space = 0;
797
798         sig = call->signature;
799         n = sig->param_count + sig->hasthis;
800         
801         cinfo = get_call_info (sig, sig->pinvoke);
802
803         for (i = 0; i < n; ++i) {
804                 ainfo = cinfo->args + i;
805                 if (is_virtual && i == 0) {
806                         /* the argument will be attached to the call instruction */
807                         in = call->args [i];
808                 } else {
809                         if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
810                                 /* FIXME: Test varargs with 0 implicit args */
811                                 /* FIXME: Test interaction with hasthis */
812                                 /* Emit the signature cookie just before the first implicit argument */
813                                 MonoInst *sig_arg;
814                                 /* FIXME: Add support for signature tokens to AOT */
815                                 cfg->disable_aot = TRUE;
816                                 /* We allways pass the signature on the stack for simplicity */
817                                 MONO_INST_NEW (cfg, arg, OP_SPARC_OUTARG_MEM);
818                                 arg->inst_basereg = sparc_sp;
819                                 arg->inst_imm = 68 + cinfo->sig_cookie.offset;
820                                 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
821                                 sig_arg->inst_p0 = call->signature;
822                                 arg->inst_left = sig_arg;
823                                 arg->type = STACK_PTR;
824                                 /* prepend, so they get reversed */
825                                 arg->next = call->out_args;
826                                 call->out_args = arg;
827                         }
828
829                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
830                         in = call->args [i];
831                         arg->cil_code = in->cil_code;
832                         arg->inst_left = in;
833                         arg->type = in->type;
834                         /* prepend, we'll need to reverse them later */
835                         arg->next = call->out_args;
836                         call->out_args = arg;
837
838                         if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(sig->params [i - sig->hasthis]))) {
839                                 MonoInst *inst;
840                                 gint align;
841                                 guint32 offset, pad;
842                                 guint32 size;
843                                 
844                                 if (sig->params [i - sig->hasthis]->type == MONO_TYPE_TYPEDBYREF) {
845                                         size = sizeof (MonoTypedRef);
846                                         align = 4;
847                                 }
848                                 else
849                                 if (sig->pinvoke)
850                                         size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
851                                 else
852                                         size = mono_type_stack_size (&in->klass->byval_arg, &align);
853
854                                 /* 
855                                  * We use OP_OUTARG_VT to copy the valuetype to a stack location, then
856                                  * use the normal OUTARG opcodes to pass the address of the location to
857                                  * the callee.
858                                  */
859                                 MONO_INST_NEW (cfg, inst, OP_OUTARG_VT);
860                                 inst->inst_left = in;
861
862                                 /* The first 6 argument locations are reserved */
863                                 if (cinfo->stack_usage < 24)
864                                         cinfo->stack_usage = 24;
865
866                                 offset = ALIGN_TO (68 + cinfo->stack_usage, align);
867                                 pad = offset - (68 + cinfo->stack_usage);
868
869                                 inst->inst_c1 = offset;
870                                 inst->unused = size;
871                                 arg->inst_left = inst;
872
873                                 cinfo->stack_usage += size;
874                                 cinfo->stack_usage += pad;
875                         }
876
877                         switch (ainfo->storage) {
878                         case ArgInIReg:
879                         case ArgInFReg:
880                         case ArgInIRegPair:
881                                 if (ainfo->storage == ArgInIRegPair)
882                                         arg->opcode = OP_SPARC_OUTARG_REGPAIR;
883                                 arg->unused = sparc_o0 + ainfo->reg;
884                                 /* outgoing arguments begin at sp+68 */
885                                 arg->inst_basereg = sparc_sp;
886                                 arg->inst_imm = 68 + ainfo->offset;
887                                 call->used_iregs |= 1 << ainfo->reg;
888
889                                 if ((i >= sig->hasthis) && (sig->params [i - sig->hasthis]->type == MONO_TYPE_R8)) {
890                                         /*
891                                          * The OUTARG (freg) implementation needs an extra dword to store
892                                          * the temporary value.
893                                          */
894                                         extra_space += 8;
895                                 }
896                                 break;
897                         case ArgOnStack:
898                                 arg->opcode = OP_SPARC_OUTARG_MEM;
899                                 arg->inst_basereg = sparc_sp;
900                                 arg->inst_imm = 68 + ainfo->offset;
901                                 break;
902                         case ArgOnStackPair:
903                                 arg->opcode = OP_SPARC_OUTARG_MEMPAIR;
904                                 arg->inst_basereg = sparc_sp;
905                                 arg->inst_imm = 68 + ainfo->offset;
906                                 break;
907                         case ArgInSplitRegStack:
908                                 arg->opcode = OP_SPARC_OUTARG_SPLIT_REG_STACK;
909                                 arg->unused = sparc_o0 + ainfo->reg;
910                                 arg->inst_basereg = sparc_sp;
911                                 arg->inst_imm = 68 + ainfo->offset;
912                                 call->used_iregs |= 1 << ainfo->reg;
913                                 break;
914                         default:
915                                 NOT_IMPLEMENTED;
916                         }
917                 }
918         }
919
920         /*
921          * Reverse the call->out_args list.
922          */
923         {
924                 MonoInst *prev = NULL, *list = call->out_args, *next;
925                 while (list) {
926                         next = list->next;
927                         list->next = prev;
928                         prev = list;
929                         list = next;
930                 }
931                 call->out_args = prev;
932         }
933         call->stack_usage = cinfo->stack_usage + extra_space;
934         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
935         cfg->flags |= MONO_CFG_HAS_CALLS;
936
937         g_free (cinfo);
938         return call;
939 }
940
941 /* Map opcode to the sparc condition codes */
942 static inline SparcCond
943 opcode_to_sparc_cond (int opcode)
944 {
945         switch (opcode) {
946         case OP_FBGE:
947                 return sparc_fbge;
948         case OP_FBLE:
949                 return sparc_fble;
950         case OP_FBEQ:
951         case OP_FCEQ:
952                 return sparc_fbe;
953         case OP_FBLT:
954         case OP_FCLT:
955         case OP_FCLT_UN:
956                 return sparc_fbl;
957         case OP_FBGT:
958         case OP_FCGT:
959         case OP_FCGT_UN:
960                 return sparc_fbg;
961         case CEE_BEQ:
962         case OP_CEQ:
963         case OP_COND_EXC_EQ:
964                 return sparc_be;
965         case CEE_BNE_UN:
966         case OP_COND_EXC_NE_UN:
967                 return sparc_bne;
968         case CEE_BLT:
969         case OP_CLT:
970         case OP_COND_EXC_LT:
971                 return sparc_bl;
972         case CEE_BLT_UN:
973         case OP_CLT_UN:
974         case OP_COND_EXC_LT_UN:
975                 return sparc_blu;
976         case CEE_BGT:
977         case OP_CGT:
978         case OP_COND_EXC_GT:
979                 return sparc_bg;
980         case CEE_BGT_UN:
981         case OP_CGT_UN:
982         case OP_COND_EXC_GT_UN:
983                 return sparc_bgu;
984         case CEE_BGE:
985         case OP_COND_EXC_GE:
986                 return sparc_bge;
987         case CEE_BGE_UN:
988         case OP_COND_EXC_GE_UN:
989                 return sparc_beu;
990         case CEE_BLE:
991         case OP_COND_EXC_LE:
992                 return sparc_ble;
993         case CEE_BLE_UN:
994         case OP_COND_EXC_LE_UN:
995                 return sparc_bleu;
996         case OP_COND_EXC_OV:
997                 return sparc_bvs;
998         case OP_COND_EXC_C:
999                 return sparc_bcs;
1000
1001         case OP_COND_EXC_NO:
1002         case OP_COND_EXC_NC:
1003                 NOT_IMPLEMENTED;
1004         default:
1005                 g_assert_not_reached ();
1006                 return sparc_be;
1007         }
1008 }
1009
1010 #define COMPUTE_DISP(ins) \
1011 if (ins->flags & MONO_INST_BRLABEL) { \
1012         if (ins->inst_i0->inst_c0) \
1013            disp = (ins->inst_i0->inst_c0 - ((guint8*)code - cfg->native_code)) >> 2; \
1014         else { \
1015             disp = 0; \
1016                 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1017         } \
1018 } else { \
1019         if (ins->inst_true_bb->native_offset) \
1020            disp = (ins->inst_true_bb->native_offset - ((guint8*)code - cfg->native_code)) >> 2; \
1021         else { \
1022             disp = 0; \
1023                 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1024         } \
1025 }
1026
1027 #define EMIT_COND_BRANCH_GENERAL(ins,bop,cond,annul,filldelay) \
1028     do { \
1029         gint32 disp; \
1030         COMPUTE_DISP(ins); \
1031         g_assert (sparc_is_imm22 (disp)); \
1032         sparc_ ## bop (code, (annul), cond, disp); \
1033         if (filldelay) sparc_nop (code); \
1034     } while (0)
1035
1036 #define EMIT_COND_BRANCH(ins,cond,annul,filldelay) EMIT_COND_BRANCH_GENERAL((ins),branch,(cond),annul,filldelay)
1037 #define EMIT_FLOAT_COND_BRANCH(ins,cond,annul,filldelay) EMIT_COND_BRANCH_GENERAL((ins),fbranch,(cond),annul,filldelay)
1038
1039 #define EMIT_COND_BRANCH_PREDICTED(ins,cond,annul,filldelay) \
1040     do { \
1041             gint32 disp; \
1042         guint32 predict; \
1043         COMPUTE_DISP(ins); \
1044         predict = (disp != 0) ? 1 : 0; \
1045         g_assert (sparc_is_imm19 (disp)); \
1046                 sparc_branchp (code, (annul), (cond), sparc_icc_short, (predict), disp); \
1047         if (filldelay) sparc_nop (code); \
1048     } while (0)
1049
1050 #define EMIT_COND_BRANCH_BPR(ins,bop,predict,annul,filldelay) \
1051     do { \
1052             gint32 disp; \
1053         COMPUTE_DISP(ins); \
1054                 g_assert (sparc_is_imm22 (disp)); \
1055                 sparc_ ## bop (code, (annul), (predict), ins->sreg2, disp); \
1056         if (filldelay) sparc_nop (code); \
1057     } while (0)
1058
1059 /* emit an exception if condition is fail */
1060 /*
1061  * We put the exception throwing code out-of-line, at the end of the method
1062  */
1063 #define EMIT_COND_SYSTEM_EXCEPTION(ins,cond,sexc_name) do {     \
1064                 mono_add_patch_info (cfg, (guint8*)(code) - (cfg)->native_code,   \
1065                                     MONO_PATCH_INFO_EXC, sexc_name);  \
1066         if (sparcv9) { \
1067            sparc_branchp (code, 0, (cond), sparc_icc_short, 0, 0); \
1068         } \
1069         else { \
1070                         sparc_branch (code, 1, cond, 0);     \
1071         } \
1072         sparc_nop (code);     \
1073         } while (0); 
1074
1075 #define EMIT_ALU_IMM(ins,op,setcc) do { \
1076                         if (sparc_is_imm13 ((ins)->inst_imm)) \
1077                                 sparc_ ## op ## _imm (code, (setcc), (ins)->sreg1, ins->inst_imm, (ins)->dreg); \
1078                         else { \
1079                                 sparc_set (code, ins->inst_imm, sparc_o7); \
1080                                 sparc_ ## op (code, (setcc), (ins)->sreg1, sparc_o7, (ins)->dreg); \
1081                         } \
1082 } while (0);
1083
1084 #define EMIT_LOAD_MEMBASE(ins,op) do { \
1085                         if (sparc_is_imm13 (ins->inst_offset)) \
1086                                 sparc_ ## op ## _imm (code, ins->inst_basereg, ins->inst_offset, ins->dreg); \
1087                         else { \
1088                                 sparc_set (code, ins->inst_offset, sparc_o7); \
1089                                 sparc_ ## op (code, ins->inst_basereg, sparc_o7, ins->dreg); \
1090                         } \
1091 } while (0);
1092
1093 /* max len = 5 */
1094 #define EMIT_STORE_MEMBASE_IMM(ins,op) do { \
1095                         guint32 sreg; \
1096                         if (ins->inst_imm == 0) \
1097                                 sreg = sparc_g0; \
1098                         else { \
1099                                 sparc_set (code, ins->inst_imm, sparc_o7); \
1100                                 sreg = sparc_o7; \
1101                         } \
1102                         if (!sparc_is_imm13 (ins->inst_offset)) { \
1103                                 sparc_set (code, ins->inst_offset, sparc_g1); \
1104                                 sparc_ ## op (code, sreg, ins->inst_destbasereg, sparc_g1); \
1105                         } \
1106                         else \
1107                                 sparc_ ## op ## _imm (code, sreg, ins->inst_destbasereg, ins->inst_offset); \
1108                                                                                                                                                                                  } while (0);
1109
1110 #define EMIT_STORE_MEMBASE_REG(ins,op) do { \
1111                         if (!sparc_is_imm13 (ins->inst_offset)) { \
1112                                 sparc_set (code, ins->inst_offset, sparc_o7); \
1113                                 sparc_ ## op (code, ins->sreg1, ins->inst_destbasereg, sparc_o7); \
1114                         } \
1115                                   else \
1116                                 sparc_ ## op ## _imm (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset); \
1117                                                                                                                                                                                  } while (0);
1118
1119 static void
1120 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1121 {
1122         MonoInst *ins, *last_ins = NULL;
1123         ins = bb->code;
1124
1125         while (ins) {
1126
1127                 switch (ins->opcode) {
1128                 case OP_MUL_IMM: 
1129                         /* remove unnecessary multiplication with 1 */
1130                         if (ins->inst_imm == 1) {
1131                                 if (ins->dreg != ins->sreg1) {
1132                                         ins->opcode = OP_MOVE;
1133                                 } else {
1134                                         last_ins->next = ins->next;                             
1135                                         ins = ins->next;                                
1136                                         continue;
1137                                 }
1138                         }
1139                         break;
1140                 case OP_LOAD_MEMBASE:
1141                 case OP_LOADI4_MEMBASE:
1142                         /* 
1143                          * OP_STORE_MEMBASE_REG reg, offset(basereg) 
1144                          * OP_LOAD_MEMBASE offset(basereg), reg
1145                          */
1146                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG 
1147                                          || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1148                             ins->inst_basereg == last_ins->inst_destbasereg &&
1149                             ins->inst_offset == last_ins->inst_offset) {
1150                                 if (ins->dreg == last_ins->sreg1) {
1151                                         last_ins->next = ins->next;                             
1152                                         ins = ins->next;                                
1153                                         continue;
1154                                 } else {
1155                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1156                                         ins->opcode = OP_MOVE;
1157                                         ins->sreg1 = last_ins->sreg1;
1158                                 }
1159
1160                         /* 
1161                          * Note: reg1 must be different from the basereg in the second load
1162                          * OP_LOAD_MEMBASE offset(basereg), reg1
1163                          * OP_LOAD_MEMBASE offset(basereg), reg2
1164                          * -->
1165                          * OP_LOAD_MEMBASE offset(basereg), reg1
1166                          * OP_MOVE reg1, reg2
1167                          */
1168                         } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1169                                            || last_ins->opcode == OP_LOAD_MEMBASE) &&
1170                               ins->inst_basereg != last_ins->dreg &&
1171                               ins->inst_basereg == last_ins->inst_basereg &&
1172                               ins->inst_offset == last_ins->inst_offset) {
1173
1174                                 if (ins->dreg == last_ins->dreg) {
1175                                         last_ins->next = ins->next;                             
1176                                         ins = ins->next;                                
1177                                         continue;
1178                                 } else {
1179                                         ins->opcode = OP_MOVE;
1180                                         ins->sreg1 = last_ins->dreg;
1181                                 }
1182
1183                                 //g_assert_not_reached ();
1184
1185 #if 0
1186                         /* 
1187                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1188                          * OP_LOAD_MEMBASE offset(basereg), reg
1189                          * -->
1190                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1191                          * OP_ICONST reg, imm
1192                          */
1193                         } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1194                                                 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1195                                    ins->inst_basereg == last_ins->inst_destbasereg &&
1196                                    ins->inst_offset == last_ins->inst_offset) {
1197                                 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1198                                 ins->opcode = OP_ICONST;
1199                                 ins->inst_c0 = last_ins->inst_imm;
1200                                 g_assert_not_reached (); // check this rule
1201 #endif
1202                         }
1203                         break;
1204                 case OP_LOADU1_MEMBASE:
1205                 case OP_LOADI1_MEMBASE:
1206                         if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1207                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1208                                         ins->inst_offset == last_ins->inst_offset) {
1209                                 if (ins->dreg == last_ins->sreg1) {
1210                                         last_ins->next = ins->next;                             
1211                                         ins = ins->next;                                
1212                                         continue;
1213                                 } else {
1214                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1215                                         ins->opcode = OP_MOVE;
1216                                         ins->sreg1 = last_ins->sreg1;
1217                                 }
1218                         }
1219                         break;
1220                 case OP_LOADU2_MEMBASE:
1221                 case OP_LOADI2_MEMBASE:
1222                         if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1223                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1224                                         ins->inst_offset == last_ins->inst_offset) {
1225                                 if (ins->dreg == last_ins->sreg1) {
1226                                         last_ins->next = ins->next;                             
1227                                         ins = ins->next;                                
1228                                         continue;
1229                                 } else {
1230                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1231                                         ins->opcode = OP_MOVE;
1232                                         ins->sreg1 = last_ins->sreg1;
1233                                 }
1234                         }
1235                         break;
1236                 case OP_STOREI4_MEMBASE_IMM:
1237                         /* Convert pairs of 0 stores to a dword 0 store */
1238                         /* Used when initializing temporaries */
1239                         /* We know sparc_fp is dword aligned */
1240                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM) &&
1241                                 (ins->inst_destbasereg == last_ins->inst_destbasereg) && 
1242                                 (ins->inst_destbasereg == sparc_fp) &&
1243                                 (ins->inst_offset < 0) &&
1244                                 ((ins->inst_offset % 8) == 0) &&
1245                                 ((ins->inst_offset == last_ins->inst_offset - 4)) &&
1246                                 (ins->inst_imm == 0) &&
1247                                 (last_ins->inst_imm == 0)) {
1248                                 if (sparcv9) {
1249                                         last_ins->opcode = OP_STOREI8_MEMBASE_IMM;
1250                                         last_ins->inst_offset = ins->inst_offset;
1251                                         last_ins->next = ins->next;                             
1252                                         ins = ins->next;
1253                                         continue;
1254                                 }
1255                         }
1256                         break;
1257                 case CEE_BEQ:
1258                 case CEE_BNE_UN:
1259                 case CEE_BLT:
1260                 case CEE_BGT:
1261                 case CEE_BGE:
1262                 case CEE_BLE:
1263                         /*
1264                          * Convert compare with zero+branch to BRcc
1265                          */
1266                         /* 
1267                          * This only works in 64 bit mode, since it examines all 64
1268                          * bits of the register.
1269                          */
1270                         if (0 && sparcv9 && last_ins && 
1271                                 (last_ins->opcode == OP_COMPARE_IMM) &&
1272                                 (last_ins->inst_imm == 0)) {
1273                                 MonoInst *next = ins->next;
1274                                 switch (ins->opcode) {
1275                                 case CEE_BEQ:
1276                                         ins->opcode = OP_SPARC_BRZ;
1277                                         break;
1278                                 case CEE_BNE_UN:
1279                                         ins->opcode = OP_SPARC_BRNZ;
1280                                         break;
1281                                 case CEE_BLT:
1282                                         ins->opcode = OP_SPARC_BRLZ;
1283                                         break;
1284                                 case CEE_BGT:
1285                                         ins->opcode = OP_SPARC_BRGZ;
1286                                         break;
1287                                 case CEE_BGE:
1288                                         ins->opcode = OP_SPARC_BRGEZ;
1289                                         break;
1290                                 case CEE_BLE:
1291                                         ins->opcode = OP_SPARC_BRLEZ;
1292                                         break;
1293                                 default:
1294                                         g_assert_not_reached ();
1295                                 }
1296                                 ins->sreg2 = last_ins->sreg1;
1297                                 *last_ins = *ins;
1298                                 last_ins->next = next;
1299                                 ins = next;
1300                                 continue;
1301                         }
1302                         break;
1303                 case CEE_CONV_I4:
1304                 case CEE_CONV_U4:
1305                 case OP_MOVE:
1306                         /* 
1307                          * OP_MOVE reg, reg 
1308                          */
1309                         if (ins->dreg == ins->sreg1) {
1310                                 if (last_ins)
1311                                         last_ins->next = ins->next;                             
1312                                 ins = ins->next;
1313                                 continue;
1314                         }
1315                         /* 
1316                          * OP_MOVE sreg, dreg 
1317                          * OP_MOVE dreg, sreg
1318                          */
1319                         if (last_ins && last_ins->opcode == OP_MOVE &&
1320                             ins->sreg1 == last_ins->dreg &&
1321                             ins->dreg == last_ins->sreg1) {
1322                                 last_ins->next = ins->next;                             
1323                                 ins = ins->next;                                
1324                                 continue;
1325                         }
1326                         break;
1327                 }
1328                 last_ins = ins;
1329                 ins = ins->next;
1330         }
1331         bb->last_ins = last_ins;
1332 }
1333
1334 /* Parameters used by the register allocator */
1335
1336 /* Use %l4..%l7 as local registers */
1337 #define ARCH_CALLER_REGS (0xf0<<16)
1338 /* Use %f2..%f30 as the double precision floating point local registers */
1339 #define ARCH_CALLER_FREGS (0x55555554)
1340
1341 #undef DEBUG
1342 #define DEBUG(a) if (cfg->verbose_level > 1) a
1343 //#define DEBUG(a)
1344 #define reg_is_freeable(r) ((1 << (r)) & ARCH_CALLER_REGS)
1345 #define freg_is_freeable(r) (((1) << (r)) & ARCH_CALLER_FREGS)
1346
1347 typedef struct {
1348         int born_in;
1349         int killed_in;
1350         int last_use;
1351         int prev_use;
1352 } RegTrack;
1353
1354 static const char*const * ins_spec = sparc_desc;
1355
1356 static void
1357 print_ins (int i, MonoInst *ins)
1358 {
1359         const char *spec = ins_spec [ins->opcode];
1360         g_print ("\t%-2d %s", i, mono_inst_name (ins->opcode));
1361         if (spec [MONO_INST_DEST]) {
1362                 if (ins->dreg >= MONO_MAX_IREGS)
1363                         g_print (" R%d <-", ins->dreg);
1364                 else
1365                         if (spec [MONO_INST_DEST] == 'b')
1366                                 g_print (" [%s + 0x%x] <-", mono_arch_regname (ins->dreg), ins->inst_offset);
1367                 else
1368                         g_print (" %s <-", mono_arch_regname (ins->dreg));
1369         }
1370         if (spec [MONO_INST_SRC1]) {
1371                 if (ins->sreg1 >= MONO_MAX_IREGS)
1372                         g_print (" R%d", ins->sreg1);
1373                 else
1374                         if (spec [MONO_INST_SRC1] == 'b')
1375                                 g_print (" [%s + 0x%x]", mono_arch_regname (ins->sreg1), ins->inst_offset);
1376                 else
1377                         g_print (" %s", mono_arch_regname (ins->sreg1));
1378         }
1379         if (spec [MONO_INST_SRC2]) {
1380                 if (ins->sreg2 >= MONO_MAX_IREGS)
1381                         g_print (" R%d", ins->sreg2);
1382                 else
1383                         g_print (" %s", mono_arch_regname (ins->sreg2));
1384         }
1385         if (spec [MONO_INST_CLOB])
1386                 g_print (" clobbers: %c", spec [MONO_INST_CLOB]);
1387         g_print ("\n");
1388 }
1389
1390 static void
1391 print_regtrack (RegTrack *t, int num)
1392 {
1393         int i;
1394         char buf [32];
1395         const char *r;
1396         
1397         for (i = 0; i < num; ++i) {
1398                 if (!t [i].born_in)
1399                         continue;
1400                 if (i >= MONO_MAX_IREGS) {
1401                         g_snprintf (buf, sizeof(buf), "R%d", i);
1402                         r = buf;
1403                 } else
1404                         r = mono_arch_regname (i);
1405                 g_print ("liveness: %s [%d - %d]\n", r, t [i].born_in, t[i].last_use);
1406         }
1407 }
1408
1409 typedef struct InstList InstList;
1410
1411 struct InstList {
1412         InstList *prev;
1413         InstList *next;
1414         MonoInst *data;
1415 };
1416
1417 static inline InstList*
1418 inst_list_prepend (MonoMemPool *pool, InstList *list, MonoInst *data)
1419 {
1420         InstList *item = mono_mempool_alloc (pool, sizeof (InstList));
1421         item->data = data;
1422         item->prev = NULL;
1423         item->next = list;
1424         if (list)
1425                 list->prev = item;
1426         return item;
1427 }
1428
1429 #define STACK_OFFSETS_POSITIVE
1430
1431 /*
1432  * returns the offset used by spillvar. It allocates a new
1433  * spill variable if necessary.
1434  */
1435 static int
1436 mono_spillvar_offset (MonoCompile *cfg, int spillvar)
1437 {
1438         MonoSpillInfo **si, *info;
1439         int i = 0;
1440
1441         si = &cfg->spill_info; 
1442         
1443         while (i <= spillvar) {
1444
1445                 if (!*si) {
1446                         *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
1447                         info->next = NULL;
1448                         cfg->stack_offset += sizeof (gpointer);
1449                         info->offset = - cfg->stack_offset;
1450                 }
1451
1452                 if (i == spillvar)
1453                         return (*si)->offset;
1454
1455                 i++;
1456                 si = &(*si)->next;
1457         }
1458
1459         g_assert_not_reached ();
1460         return 0;
1461 }
1462
1463 static int
1464 mono_spillvar_offset_float (MonoCompile *cfg, int spillvar)
1465 {
1466         MonoSpillInfo **si, *info;
1467         int i = 0;
1468
1469         si = &cfg->spill_info_float; 
1470         
1471         while (i <= spillvar) {
1472
1473                 if (!*si) {
1474                         *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
1475                         info->next = NULL;
1476                         cfg->stack_offset += sizeof (double);
1477                         cfg->stack_offset = ALIGN_TO (cfg->stack_offset, 8);
1478                         info->offset = - cfg->stack_offset;
1479                 }
1480
1481                 if (i == spillvar)
1482                         return (*si)->offset;
1483
1484                 i++;
1485                 si = &(*si)->next;
1486         }
1487
1488         g_assert_not_reached ();
1489         return 0;
1490 }
1491
1492 /*
1493  * Force the spilling of the variable in the symbolic register 'reg'.
1494  */
1495 static int
1496 get_register_force_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, int reg)
1497 {
1498         MonoInst *load;
1499         int i, sel, spill;
1500         
1501         sel = cfg->rs->iassign [reg];
1502         /*i = cfg->rs->isymbolic [sel];
1503         g_assert (i == reg);*/
1504         i = reg;
1505         spill = ++cfg->spill_count;
1506         cfg->rs->iassign [i] = -spill - 1;
1507         mono_regstate_free_int (cfg->rs, sel);
1508         /* we need to create a spill var and insert a load to sel after the current instruction */
1509         MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE);
1510         load->dreg = sel;
1511         load->inst_basereg = cfg->frame_reg;
1512         load->inst_offset = mono_spillvar_offset (cfg, spill);
1513         if (item->prev) {
1514                 while (ins->next != item->prev->data)
1515                         ins = ins->next;
1516         }
1517         load->next = ins->next;
1518         ins->next = load;
1519         DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel)));
1520         i = mono_regstate_alloc_int (cfg->rs, 1 << sel);
1521         g_assert (i == sel);
1522
1523         return sel;
1524 }
1525
1526 static int
1527 get_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, guint32 regmask, int reg)
1528 {
1529         MonoInst *load;
1530         int i, sel, spill;
1531
1532         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));
1533         /* exclude the registers in the current instruction */
1534         if (reg != ins->sreg1 && (reg_is_freeable (ins->sreg1) || (ins->sreg1 >= MONO_MAX_IREGS && cfg->rs->iassign [ins->sreg1] >= 0))) {
1535                 if (ins->sreg1 >= MONO_MAX_IREGS)
1536                         regmask &= ~ (1 << cfg->rs->iassign [ins->sreg1]);
1537                 else
1538                         regmask &= ~ (1 << ins->sreg1);
1539                 DEBUG (g_print ("excluding sreg1 %s\n", mono_arch_regname (ins->sreg1)));
1540         }
1541         if (reg != ins->sreg2 && (reg_is_freeable (ins->sreg2) || (ins->sreg2 >= MONO_MAX_IREGS && cfg->rs->iassign [ins->sreg2] >= 0))) {
1542                 if (ins->sreg2 >= MONO_MAX_IREGS)
1543                         regmask &= ~ (1 << cfg->rs->iassign [ins->sreg2]);
1544                 else
1545                         regmask &= ~ (1 << ins->sreg2);
1546                 DEBUG (g_print ("excluding sreg2 %s %d\n", mono_arch_regname (ins->sreg2), ins->sreg2));
1547         }
1548         if (reg != ins->dreg && reg_is_freeable (ins->dreg)) {
1549                 regmask &= ~ (1 << ins->dreg);
1550                 DEBUG (g_print ("excluding dreg %s\n", mono_arch_regname (ins->dreg)));
1551         }
1552
1553         DEBUG (g_print ("available regmask: 0x%08x\n", regmask));
1554         g_assert (regmask); /* need at least a register we can free */
1555         sel = -1;
1556         /* we should track prev_use and spill the register that's farther */
1557         for (i = 0; i < MONO_MAX_IREGS; ++i) {
1558                 if (regmask & (1 << i)) {
1559                         sel = i;
1560                         DEBUG (g_print ("selected register %s has assignment %d\n", mono_arch_regname (sel), cfg->rs->iassign [sel]));
1561                         break;
1562                 }
1563         }
1564         i = cfg->rs->isymbolic [sel];
1565         spill = ++cfg->spill_count;
1566         cfg->rs->iassign [i] = -spill - 1;
1567         mono_regstate_free_int (cfg->rs, sel);
1568         /* we need to create a spill var and insert a load to sel after the current instruction */
1569         MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE);
1570         load->dreg = sel;
1571         load->inst_basereg = cfg->frame_reg;
1572         load->inst_offset = mono_spillvar_offset (cfg, spill);
1573         if (item->prev) {
1574                 while (ins->next != item->prev->data)
1575                         ins = ins->next;
1576         }
1577         load->next = ins->next;
1578         ins->next = load;
1579         DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel)));
1580         i = mono_regstate_alloc_int (cfg->rs, 1 << sel);
1581         g_assert (i == sel);
1582         
1583         return sel;
1584 }
1585
1586 static int
1587 get_float_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, guint32 regmask, int reg)
1588 {
1589         MonoInst *load;
1590         int i, sel, spill;
1591
1592         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));
1593         /* exclude the registers in the current instruction */
1594         if (reg != ins->sreg1 && (freg_is_freeable (ins->sreg1) || (ins->sreg1 >= MONO_MAX_FREGS && cfg->rs->fassign [ins->sreg1] >= 0))) {
1595                 if (ins->sreg1 >= MONO_MAX_FREGS)
1596                         regmask &= ~ (1 << cfg->rs->fassign [ins->sreg1]);
1597                 else
1598                         regmask &= ~ (1 << ins->sreg1);
1599                 DEBUG (g_print ("excluding sreg1 %s\n", mono_arch_regname (ins->sreg1)));
1600         }
1601         if (reg != ins->sreg2 && (freg_is_freeable (ins->sreg2) || (ins->sreg2 >= MONO_MAX_FREGS && cfg->rs->fassign [ins->sreg2] >= 0))) {
1602                 if (ins->sreg2 >= MONO_MAX_FREGS)
1603                         regmask &= ~ (1 << cfg->rs->fassign [ins->sreg2]);
1604                 else
1605                         regmask &= ~ (1 << ins->sreg2);
1606                 DEBUG (g_print ("excluding sreg2 %s %d\n", mono_arch_regname (ins->sreg2), ins->sreg2));
1607         }
1608         if (reg != ins->dreg && freg_is_freeable (ins->dreg)) {
1609                 regmask &= ~ (1 << ins->dreg);
1610                 DEBUG (g_print ("excluding dreg %s\n", mono_arch_regname (ins->dreg)));
1611         }
1612
1613         DEBUG (g_print ("available regmask: 0x%08x\n", regmask));
1614         g_assert (regmask); /* need at least a register we can free */
1615         sel = -1;
1616         /* we should track prev_use and spill the register that's farther */
1617         for (i = 0; i < MONO_MAX_FREGS; ++i) {
1618                 if (regmask & (1 << i)) {
1619                         sel = i;
1620                         DEBUG (g_print ("selected register %s has assignment %d\n", mono_arch_regname (sel), cfg->rs->fassign [sel]));
1621                         break;
1622                 }
1623         }
1624         i = cfg->rs->fsymbolic [sel];
1625         spill = ++cfg->spill_count;
1626         cfg->rs->fassign [i] = -spill - 1;
1627         mono_regstate_free_float(cfg->rs, sel);
1628         /* we need to create a spill var and insert a load to sel after the current instruction */
1629         MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
1630         load->dreg = sel;
1631         load->inst_basereg = cfg->frame_reg;
1632         load->inst_offset = mono_spillvar_offset_float (cfg, spill);
1633         if (item->prev) {
1634                 while (ins->next != item->prev->data)
1635                         ins = ins->next;
1636         }
1637         load->next = ins->next;
1638         ins->next = load;
1639         DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel)));
1640         i = mono_regstate_alloc_float (cfg->rs, 1 << sel);
1641         g_assert (i == sel);
1642         
1643         return sel;
1644 }
1645
1646 static MonoInst*
1647 create_copy_ins (MonoCompile *cfg, int dest, int src, MonoInst *ins)
1648 {
1649         MonoInst *copy;
1650         MONO_INST_NEW (cfg, copy, OP_MOVE);
1651         copy->dreg = dest;
1652         copy->sreg1 = src;
1653         if (ins) {
1654                 copy->next = ins->next;
1655                 ins->next = copy;
1656         }
1657         DEBUG (g_print ("\tforced copy from %s to %s\n", mono_arch_regname (src), mono_arch_regname (dest)));
1658         return copy;
1659 }
1660
1661 static MonoInst*
1662 create_copy_ins_float (MonoCompile *cfg, int dest, int src, MonoInst *ins)
1663 {
1664         MonoInst *copy;
1665         MONO_INST_NEW (cfg, copy, OP_FMOVE);
1666         copy->dreg = dest;
1667         copy->sreg1 = src;
1668         if (ins) {
1669                 copy->next = ins->next;
1670                 ins->next = copy;
1671         }
1672         DEBUG (g_print ("\tforced copy from %s to %s\n", mono_arch_regname (src), mono_arch_regname (dest)));
1673         return copy;
1674 }
1675
1676 static MonoInst*
1677 create_spilled_store (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins)
1678 {
1679         MonoInst *store;
1680         MONO_INST_NEW (cfg, store, OP_STORE_MEMBASE_REG);
1681         store->sreg1 = reg;
1682         store->inst_destbasereg = cfg->frame_reg;
1683         store->inst_offset = mono_spillvar_offset (cfg, spill);
1684         if (ins) {
1685                 store->next = ins->next;
1686                 ins->next = store;
1687         }
1688         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)));
1689         return store;
1690 }
1691
1692 static MonoInst*
1693 create_spilled_store_float (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins)
1694 {
1695         MonoInst *store;
1696         MONO_INST_NEW (cfg, store, OP_STORER8_MEMBASE_REG);
1697         store->sreg1 = reg;
1698         store->inst_destbasereg = cfg->frame_reg;
1699         store->inst_offset = mono_spillvar_offset_float (cfg, spill);
1700         if (ins) {
1701                 store->next = ins->next;
1702                 ins->next = store;
1703         }
1704         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)));
1705         return store;
1706 }
1707
1708 static void
1709 insert_before_ins (MonoInst *ins, InstList *item, MonoInst* to_insert)
1710 {
1711         MonoInst *prev;
1712         g_assert (item->next);
1713         prev = item->next->data;
1714
1715         while (prev->next != ins)
1716                 prev = prev->next;
1717         to_insert->next = ins;
1718         prev->next = to_insert;
1719         /* 
1720          * needed otherwise in the next instruction we can add an ins to the 
1721          * end and that would get past this instruction.
1722          */
1723         item->data = to_insert; 
1724 }
1725
1726 static int
1727 alloc_int_reg (MonoCompile *cfg, InstList *curinst, MonoInst *ins, int sym_reg, guint32 allow_mask)
1728 {
1729         int val = cfg->rs->iassign [sym_reg];
1730         if (val < 0) {
1731                 int spill = 0;
1732                 if (val < -1) {
1733                         /* the register gets spilled after this inst */
1734                         spill = -val -1;
1735                 }
1736                 val = mono_regstate_alloc_int (cfg->rs, allow_mask);
1737                 if (val < 0)
1738                         val = get_register_spilling (cfg, curinst, ins, allow_mask, sym_reg);
1739                 cfg->rs->iassign [sym_reg] = val;
1740                 /* add option to store before the instruction for src registers */
1741                 if (spill)
1742                         create_spilled_store (cfg, spill, val, sym_reg, ins);
1743         }
1744         cfg->rs->isymbolic [val] = sym_reg;
1745         return val;
1746 }
1747
1748 /* FIXME: Strange loads from the stack in basic-float.cs:test_2_rem */
1749
1750 /*
1751  * Local register allocation.
1752  * We first scan the list of instructions and we save the liveness info of
1753  * each register (when the register is first used, when it's value is set etc.).
1754  * We also reverse the list of instructions (in the InstList list) because assigning
1755  * registers backwards allows for more tricks to be used.
1756  */
1757 void
1758 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1759 {
1760         MonoInst *ins;
1761         MonoRegState *rs = cfg->rs;
1762         int i, val;
1763         RegTrack *reginfo, *reginfof;
1764         RegTrack *reginfo1, *reginfo2, *reginfod;
1765         InstList *tmp, *reversed = NULL;
1766         const char *spec;
1767         guint32 src1_mask, src2_mask, dest_mask;
1768         guint32 cur_iregs, cur_fregs;
1769
1770         /* FIXME: Use caller saved regs and %i1-%2 for allocation */
1771
1772         if (!bb->code)
1773                 return;
1774         rs->next_vireg = bb->max_ireg;
1775         rs->next_vfreg = bb->max_freg;
1776         mono_regstate_assign (rs);
1777         reginfo = mono_mempool_alloc0 (cfg->mempool, sizeof (RegTrack) * rs->next_vireg);
1778         reginfof = mono_mempool_alloc0 (cfg->mempool, sizeof (RegTrack) * rs->next_vfreg);
1779         rs->ifree_mask = ARCH_CALLER_REGS;
1780         rs->ffree_mask = ARCH_CALLER_FREGS;
1781
1782         ins = bb->code;
1783         i = 1;
1784         DEBUG (g_print ("LOCAL regalloc: basic block: %d\n", bb->block_num));
1785         /* forward pass on the instructions to collect register liveness info */
1786         while (ins) {
1787                 spec = ins_spec [ins->opcode];
1788                 if (!spec) {
1789                         mono_print_tree_nl (ins);
1790                         g_assert (spec);
1791                 }
1792                 DEBUG (print_ins (i, ins));
1793
1794                 if (spec [MONO_INST_SRC1]) {
1795                         if (spec [MONO_INST_SRC1] == 'f')
1796                                 reginfo1 = reginfof;
1797                         else
1798                                 reginfo1 = reginfo;
1799                         reginfo1 [ins->sreg1].prev_use = reginfo1 [ins->sreg1].last_use;
1800                         reginfo1 [ins->sreg1].last_use = i;
1801                 } else {
1802                         ins->sreg1 = -1;
1803                 }
1804                 if (spec [MONO_INST_SRC2]) {
1805                         if (spec [MONO_INST_SRC2] == 'f')
1806                                 reginfo2 = reginfof;
1807                         else
1808                                 reginfo2 = reginfo;
1809                         reginfo2 [ins->sreg2].prev_use = reginfo2 [ins->sreg2].last_use;
1810                         reginfo2 [ins->sreg2].last_use = i;
1811                 } else {
1812                         ins->sreg2 = -1;
1813                 }
1814                 if (spec [MONO_INST_DEST]) {
1815                         if (spec [MONO_INST_DEST] == 'f')
1816                                 reginfod = reginfof;
1817                         else
1818                                 reginfod = reginfo;
1819                         if (spec [MONO_INST_DEST] != 'b') /* it's not just a base register */
1820                                 reginfod [ins->dreg].killed_in = i;
1821                         reginfod [ins->dreg].prev_use = reginfod [ins->dreg].last_use;
1822                         reginfod [ins->dreg].last_use = i;
1823                         if (reginfod [ins->dreg].born_in == 0 || reginfod [ins->dreg].born_in > i)
1824                                 reginfod [ins->dreg].born_in = i;
1825                         if (spec [MONO_INST_DEST] == 'l') {
1826                                 /* result in eax:edx, the virtual register is allocated sequentially */
1827                                 reginfod [ins->dreg + 1].prev_use = reginfod [ins->dreg + 1].last_use;
1828                                 reginfod [ins->dreg + 1].last_use = i;
1829                                 if (reginfod [ins->dreg + 1].born_in == 0 || reginfod [ins->dreg + 1].born_in > i)
1830                                         reginfod [ins->dreg + 1].born_in = i;
1831                         }
1832                 } else {
1833                         ins->dreg = -1;
1834                 }
1835                 reversed = inst_list_prepend (cfg->mempool, reversed, ins);
1836                 ++i;
1837                 ins = ins->next;
1838         }
1839
1840         cur_iregs = ARCH_CALLER_REGS;
1841         cur_fregs = ARCH_CALLER_FREGS;
1842
1843         DEBUG (print_regtrack (reginfo, rs->next_vireg));
1844         DEBUG (print_regtrack (reginfof, rs->next_vfreg));
1845         tmp = reversed;
1846         while (tmp) {
1847                 int prev_dreg, prev_sreg1, prev_sreg2;
1848                 --i;
1849                 ins = tmp->data;
1850                 spec = ins_spec [ins->opcode];
1851                 DEBUG (g_print ("processing:"));
1852                 DEBUG (print_ins (i, ins));
1853
1854                 /* make the register available for allocation: FIXME add fp reg */
1855                 if (ins->opcode == OP_SETREG || ins->opcode == OP_SETREGIMM) {
1856                         /* Dont free register which can't be allocated */
1857                         if (reg_is_freeable (ins->dreg)) {
1858                                 cur_iregs |= 1 << ins->dreg;
1859                                 DEBUG (g_print ("adding %d to cur_iregs\n", ins->dreg));
1860                         }
1861                 } else if (ins->opcode == OP_SETFREG) {
1862                         if (freg_is_freeable (ins->dreg)) {
1863                                 cur_fregs |= 1 << ins->dreg;
1864                                 DEBUG (g_print ("adding %d to cur_fregs\n", ins->dreg));
1865                         }
1866                 } else if (spec [MONO_INST_CLOB] == 'c') {
1867                         MonoCallInst *cinst = (MonoCallInst*)ins;
1868                         DEBUG (g_print ("excluding regs 0x%x from cur_iregs (0x%x)\n", cinst->used_iregs, cur_iregs));
1869                         cur_iregs &= ~cinst->used_iregs;
1870                         cur_fregs &= ~cinst->used_fregs;
1871                         DEBUG (g_print ("available cur_iregs: 0x%x\n", cur_iregs));
1872                         /* registers used by the calling convention are excluded from 
1873                          * allocation: they will be selectively enabled when they are 
1874                          * assigned by the special SETREG opcodes.
1875                          */
1876                 }
1877                 dest_mask = src1_mask = src2_mask = cur_iregs;
1878
1879                 /*
1880                  * DEST
1881                  */
1882                 /* update for use with FP regs... */
1883                 if (spec [MONO_INST_DEST] == 'f') {
1884                         if (ins->dreg >= MONO_MAX_FREGS) {
1885                                 val = rs->fassign [ins->dreg];
1886                                 prev_dreg = ins->dreg;
1887                                 if (val < 0) {
1888                                         int spill = 0;
1889                                         if (val < -1) {
1890                                                 /* the register gets spilled after this inst */
1891                                                 spill = -val -1;
1892                                         }
1893                                         dest_mask = cur_fregs;
1894                                         val = mono_regstate_alloc_float (rs, dest_mask);
1895                                         if (val < 0)
1896                                                 val = get_float_register_spilling (cfg, tmp, ins, dest_mask, ins->dreg);
1897                                         rs->fassign [ins->dreg] = val;
1898                                         if (spill)
1899                                                 create_spilled_store_float (cfg, spill, val, prev_dreg, ins);
1900                                 }
1901                                 DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_arch_regname (val), ins->dreg));
1902                                 rs->fsymbolic [val] = prev_dreg;
1903                                 ins->dreg = val;
1904                         } else {
1905                                 prev_dreg = -1;
1906                         }
1907                         if (freg_is_freeable (ins->dreg) && prev_dreg >= 0 && (reginfo [prev_dreg].born_in >= i || !(cur_fregs & (1 << ins->dreg)))) {
1908                                 DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins->dreg), prev_dreg, reginfo [prev_dreg].born_in));
1909                                 mono_regstate_free_float (rs, ins->dreg);
1910                         }
1911                 } else if (ins->dreg >= MONO_MAX_IREGS) {
1912                         val = rs->iassign [ins->dreg];
1913                         prev_dreg = ins->dreg;
1914                         if (val < 0) {
1915                                 int spill = 0;
1916                                 if (val < -1) {
1917                                         /* the register gets spilled after this inst */
1918                                         spill = -val -1;
1919                                 }
1920                                 val = mono_regstate_alloc_int (rs, dest_mask);
1921                                 if (val < 0)
1922                                         val = get_register_spilling (cfg, tmp, ins, dest_mask, ins->dreg);
1923                                 rs->iassign [ins->dreg] = val;
1924                                 if (spill)
1925                                         create_spilled_store (cfg, spill, val, prev_dreg, ins);
1926                         }
1927                         DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_arch_regname (val), ins->dreg));
1928                         rs->isymbolic [val] = prev_dreg;
1929                         ins->dreg = val;
1930                         if (spec [MONO_INST_DEST] == 'l') {
1931                                 int hreg = prev_dreg + 1;
1932                                 val = rs->iassign [hreg];
1933                                 if (val < 0) {
1934                                         int spill = 0;
1935                                         if (val < -1) {
1936                                                 /* the register gets spilled after this inst */
1937                                                 spill = -val -1;
1938                                         }
1939                                         /* The second register must be a pair of the first */
1940                                         dest_mask = 1 << (rs->iassign [prev_dreg] + 1);
1941                                         val = mono_regstate_alloc_int (rs, dest_mask);
1942                                         if (val < 0)
1943                                                 val = get_register_spilling (cfg, tmp, ins, dest_mask, hreg);
1944                                         rs->iassign [hreg] = val;
1945                                         if (spill)
1946                                                 create_spilled_store (cfg, spill, val, hreg, ins);
1947                                 }
1948                                 else {
1949                                         /* The second register must be a pair of the first */
1950                                         if (val != rs->iassign [prev_dreg] + 1) {
1951                                                 dest_mask = 1 << (rs->iassign [prev_dreg] + 1);
1952
1953                                                 val = mono_regstate_alloc_int (rs, dest_mask);
1954                                                 if (val < 0)
1955                                                         val = get_register_spilling (cfg, tmp, ins, dest_mask, hreg);
1956
1957                                                 create_copy_ins (cfg, rs->iassign [hreg], val, ins);
1958
1959                                                 rs->iassign [hreg] = val;
1960                                         }
1961                                 }                                       
1962
1963                                 DEBUG (g_print ("\tassigned hreg %s to dest R%d\n", mono_arch_regname (val), hreg));
1964                                 rs->isymbolic [val] = hreg;
1965
1966                                 if (reg_is_freeable (val) && hreg >= 0 && (reginfo [hreg].born_in >= i && !(cur_iregs & (1 << val)))) {
1967                                         DEBUG (g_print ("\tfreeable %s (R%d)\n", mono_arch_regname (val), hreg));
1968                                         mono_regstate_free_int (rs, val);
1969                                 }
1970                         }
1971                 } else {
1972                         prev_dreg = -1;
1973                 }
1974                 if (spec [MONO_INST_DEST] != 'f' && reg_is_freeable (ins->dreg) && prev_dreg >= 0 && (reginfo [prev_dreg].born_in >= i)) {
1975                         DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins->dreg), prev_dreg, reginfo [prev_dreg].born_in));
1976                         mono_regstate_free_int (rs, ins->dreg);
1977                 }
1978
1979                 /**
1980                  * SRC1
1981                  */
1982                 if (spec [MONO_INST_SRC1] == 'f') {
1983                         if (ins->sreg1 >= MONO_MAX_FREGS) {
1984                                 val = rs->fassign [ins->sreg1];
1985                                 prev_sreg1 = ins->sreg1;
1986                                 if (val < 0) {
1987                                         int spill = 0;
1988                                         if (val < -1) {
1989                                                 /* the register gets spilled after this inst */
1990                                                 spill = -val -1;
1991                                         }
1992                                         //g_assert (val == -1); /* source cannot be spilled */
1993                                         src1_mask = cur_fregs;
1994                                         val = mono_regstate_alloc_float (rs, src1_mask);
1995                                         if (val < 0)
1996                                                 val = get_float_register_spilling (cfg, tmp, ins, src1_mask, ins->sreg1);
1997                                         rs->fassign [ins->sreg1] = val;
1998                                         DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1));
1999                                         if (spill) {
2000                                                 MonoInst *store = create_spilled_store_float (cfg, spill, val, prev_sreg1, NULL);
2001                                                 insert_before_ins (ins, tmp, store);
2002                                         }
2003                                 }
2004                                 rs->fsymbolic [val] = prev_sreg1;
2005                                 ins->sreg1 = val;
2006                         } else {
2007                                 prev_sreg1 = -1;
2008                         }
2009                 } else if (ins->sreg1 >= MONO_MAX_IREGS) {
2010                         val = rs->iassign [ins->sreg1];
2011                         prev_sreg1 = ins->sreg1;
2012                         if (val < 0) {
2013                                 int spill = 0;
2014                                 if (val < -1) {
2015                                         /* the register gets spilled after this inst */
2016                                         spill = -val -1;
2017                                 }
2018                                 if (0 && (ins->opcode == OP_MOVE) && reg_is_freeable (ins->dreg)) {
2019                                         /* 
2020                                          * small optimization: the dest register is already allocated
2021                                          * but the src one is not: we can simply assign the same register
2022                                          * here and peephole will get rid of the instruction later.
2023                                          * This optimization may interfere with the clobbering handling:
2024                                          * it removes a mov operation that will be added again to handle clobbering.
2025                                          * There are also some other issues that should with make testjit.
2026                                          */
2027                                         mono_regstate_alloc_int (rs, 1 << ins->dreg);
2028                                         val = rs->iassign [ins->sreg1] = ins->dreg;
2029                                         //g_assert (val >= 0);
2030                                         DEBUG (g_print ("\tfast assigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1));
2031                                 } else {
2032                                         //g_assert (val == -1); /* source cannot be spilled */
2033                                         val = mono_regstate_alloc_int (rs, src1_mask);
2034                                         if (val < 0)
2035                                                 val = get_register_spilling (cfg, tmp, ins, src1_mask, ins->sreg1);
2036                                         rs->iassign [ins->sreg1] = val;
2037                                         DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1));
2038                                 }
2039                                 if (spill) {
2040                                         MonoInst *store = create_spilled_store (cfg, spill, val, prev_sreg1, NULL);
2041                                         insert_before_ins (ins, tmp, store);
2042                                 }
2043                         }
2044                         rs->isymbolic [val] = prev_sreg1;
2045                         ins->sreg1 = val;
2046                 } else {
2047                         prev_sreg1 = -1;
2048                 }
2049
2050                 /*
2051                  * SRC2
2052                  */
2053                 if (spec [MONO_INST_SRC2] == 'f') {
2054                         if (ins->sreg2 >= MONO_MAX_FREGS) {
2055                                 val = rs->fassign [ins->sreg2];
2056                                 prev_sreg2 = ins->sreg2;
2057                                 if (val < 0) {
2058                                         int spill = 0;
2059                                         if (val < -1) {
2060                                                 /* the register gets spilled after this inst */
2061                                                 spill = -val -1;
2062                                         }
2063                                         src2_mask = cur_fregs;
2064                                         val = mono_regstate_alloc_float (rs, src2_mask);
2065                                         if (val < 0)
2066                                                 val = get_float_register_spilling (cfg, tmp, ins, src2_mask, ins->sreg2);
2067                                         rs->fassign [ins->sreg2] = val;
2068                                         DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val), ins->sreg2));
2069                                         if (spill)
2070                                                 create_spilled_store_float (cfg, spill, val, prev_sreg2, ins);
2071                                 }
2072                                 rs->fsymbolic [val] = prev_sreg2;
2073                                 ins->sreg2 = val;
2074                         } else {
2075                                 prev_sreg2 = -1;
2076                         }
2077                 } else if (ins->sreg2 >= MONO_MAX_IREGS) {
2078                         val = rs->iassign [ins->sreg2];
2079                         prev_sreg2 = ins->sreg2;
2080                         if (val < 0) {
2081                                 int spill = 0;
2082                                 if (val < -1) {
2083                                         /* the register gets spilled after this inst */
2084                                         spill = -val -1;
2085                                 }
2086                                 val = mono_regstate_alloc_int (rs, src2_mask);
2087                                 if (val < 0)
2088                                         val = get_register_spilling (cfg, tmp, ins, src2_mask, ins->sreg2);
2089                                 rs->iassign [ins->sreg2] = val;
2090                                 DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val), ins->sreg2));
2091                                 if (spill)
2092                                         create_spilled_store (cfg, spill, val, prev_sreg2, ins);
2093                         }
2094                         rs->isymbolic [val] = prev_sreg2;
2095                         ins->sreg2 = val;
2096                 } else {
2097                         prev_sreg2 = -1;
2098                 }
2099
2100                 if (spec [MONO_INST_CLOB] == 'c') {
2101                         int j, s;
2102                         guint32 clob_mask = ARCH_CALLER_REGS;
2103                         for (j = 0; j < MONO_MAX_IREGS; ++j) {
2104                                 s = 1 << j;
2105                                 if ((clob_mask & s) && !(rs->ifree_mask & s) && j != ins->sreg1) {
2106                                         //g_warning ("register %s busy at call site\n", mono_arch_regname (j));
2107                                 }
2108                         }
2109                 }
2110                 /*if (reg_is_freeable (ins->sreg1) && prev_sreg1 >= 0 && reginfo [prev_sreg1].born_in >= i) {
2111                         DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg1)));
2112                         mono_regstate_free_int (rs, ins->sreg1);
2113                 }
2114                 if (reg_is_freeable (ins->sreg2) && prev_sreg2 >= 0 && reginfo [prev_sreg2].born_in >= i) {
2115                         DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg2)));
2116                         mono_regstate_free_int (rs, ins->sreg2);
2117                 }*/
2118                 
2119                 //DEBUG (print_ins (i, ins));
2120
2121                 tmp = tmp->next;
2122         }
2123 }
2124
2125 static void
2126 sparc_patch (guint8 *code, const guint8 *target)
2127 {
2128         guint32 ins = *(guint32*)code;
2129         guint32 op = ins >> 30;
2130         guint32 op2 = (ins >> 22) & 0x7;
2131         guint32 rd = (ins >> 25) & 0x1f;
2132         gint32 disp = (target - code) >> 2;
2133
2134 //      g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2135
2136         if ((op == 0) && (op2 == 2)) {
2137                 if (!sparc_is_imm22 (disp))
2138                         NOT_IMPLEMENTED;
2139                 /* Bicc */
2140                 *(guint32*)code = ((ins >> 22) << 22) | (disp & 0x3fffff);
2141         }
2142         else if ((op == 0) && (op2 == 1)) {
2143                 if (!sparc_is_imm19 (disp))
2144                         NOT_IMPLEMENTED;
2145                 /* BPcc */
2146                 *(guint32*)code = ((ins >> 19) << 19) | (disp & 0x7ffff);
2147         }
2148         else if ((op == 0) && (op2 == 3)) {
2149                 if (!sparc_is_imm16 (disp))
2150                         NOT_IMPLEMENTED;
2151                 /* BPr */
2152                 *(guint32*)code &= ~(0x180000 | 0x3fff);
2153                 *(guint32*)code |= ((disp << 21) & (0x180000)) | (disp & 0x3fff);
2154         }
2155         else if ((op == 0) && (op2 == 6)) {
2156                 if (!sparc_is_imm22 (disp))
2157                         NOT_IMPLEMENTED;
2158                 /* FBicc */
2159                 *(guint32*)code = ((ins >> 22) << 22) | (disp & 0x3fffff);
2160         }
2161         else if ((op == 0) && (op2 == 4)) {
2162                 guint32 ins2 = *(guint32*)(code + 4);
2163
2164                 if (((ins2 >> 30) == 2) && (((ins2 >> 19) & 0x3f) == 2)) {
2165                         /* sethi followed by or */
2166                         guint32 *p = (guint32*)code;
2167                         sparc_set (p, target, rd);
2168                         while (p <= (code + 4))
2169                                 sparc_nop (p);
2170                 }
2171                 else if (ins2 == 0x01000000) {
2172                         /* sethi followed by nop */
2173                         guint32 *p = (guint32*)code;
2174                         sparc_set (p, target, rd);
2175                         while (p <= (code + 4))
2176                                 sparc_nop (p);
2177                 }
2178                 else if ((sparc_inst_op (ins2) == 3) && (sparc_inst_imm (ins2))) {
2179                         /* sethi followed by load/store */
2180                         guint32 t = (guint32)target;
2181                         *(guint32*)code &= ~(0x3fffff);
2182                         *(guint32*)code |= (t >> 10);
2183                         *(guint32*)(code + 4) &= ~(0x3ff);
2184                         *(guint32*)(code + 4) |= (t & 0x3ff);
2185                 }
2186                 else if ((sparc_inst_op (ins2) == 2) && (sparc_inst_op3 (ins2) == 0x38) && 
2187                                  (sparc_inst_imm (ins2))) {
2188                         /* sethi followed by jmpl */
2189                         guint32 t = (guint32)target;
2190                         *(guint32*)code &= ~(0x3fffff);
2191                         *(guint32*)code |= (t >> 10);
2192                         *(guint32*)(code + 4) &= ~(0x3ff);
2193                         *(guint32*)(code + 4) |= (t & 0x3ff);
2194                 }
2195                 else
2196                         NOT_IMPLEMENTED;
2197         }
2198         else if (op == 01) {
2199                 sparc_call_simple (code, target - code);
2200         }
2201         else if ((op == 2) && (sparc_inst_op3 (ins) == 0x2) && sparc_inst_imm (ins)) {
2202                 /* mov imm, reg */
2203                 g_assert (sparc_is_imm13 (target));
2204                 *(guint32*)code &= ~(0x1fff);
2205                 *(guint32*)code |= (guint32)target;
2206         }
2207         else
2208                 NOT_IMPLEMENTED;
2209
2210 //      g_print ("patched with 0x%08x\n", ins);
2211 }
2212
2213 /*
2214  * mono_sparc_emit_save_lmf:
2215  *
2216  *  Emit the code neccesary to push a new entry onto the lmf stack. Used by
2217  * trampolines as well.
2218  */
2219 guint32*
2220 mono_sparc_emit_save_lmf (guint32 *code, guint32 lmf_offset)
2221 {
2222         /* Save lmf_addr */
2223         sparc_st_imm (code, sparc_o0, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr));
2224         /* Save previous_lmf */
2225         sparc_ld (code, sparc_o0, sparc_g0, sparc_o7);
2226         sparc_st_imm (code, sparc_o7, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf));
2227         /* Set new lmf */
2228         sparc_add_imm (code, FALSE, sparc_fp, lmf_offset, sparc_o7);
2229         sparc_st (code, sparc_o7, sparc_o0, sparc_g0);
2230
2231         return code;
2232 }
2233
2234 guint32*
2235 mono_sparc_emit_restore_lmf (guint32 *code, guint32 lmf_offset)
2236 {
2237         /* Load previous_lmf */
2238         sparc_ld_imm (code, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), sparc_l0);
2239         /* Load lmf_addr */
2240         sparc_ld_imm (code, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), sparc_l1);
2241         /* *(lmf) = previous_lmf */
2242         sparc_st (code, sparc_l0, sparc_l1, sparc_g0);
2243         return code;
2244 }
2245
2246 static guint32*
2247 emit_save_sp_to_lmf (MonoCompile *cfg, guint32 *code)
2248 {
2249         /*
2250          * Since register windows are saved to the current value of %sp, we need to
2251          * set the sp field in the lmf before the call, not in the prolog.
2252          */
2253         if (cfg->method->save_lmf) {
2254                 gint32 lmf_offset = - cfg->arch.lmf_offset;
2255
2256                 /* Save sp */
2257                 sparc_st_imm (code, sparc_sp, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, sp));
2258         }
2259
2260         return code;
2261 }
2262
2263 static guint32*
2264 emit_vret_token (MonoInst *ins, guint32 *code)
2265 {
2266         MonoCallInst *call = (MonoCallInst*)ins;
2267         guint32 size;
2268
2269         /* 
2270          * The sparc ABI requires that calls to functions which return a structure
2271          * contain an additional unimpl instruction which is checked by the callee.
2272          */
2273         if (call->signature->pinvoke && MONO_TYPE_ISSTRUCT(call->signature->ret)) {
2274                 if (call->signature->ret->type == MONO_TYPE_TYPEDBYREF)
2275                         size = mono_type_stack_size (call->signature->ret, NULL);
2276                 else
2277                         size = mono_class_native_size (call->signature->ret->data.klass, NULL);
2278                 sparc_unimp (code, size & 0xfff);
2279         }
2280
2281         return code;
2282 }
2283
2284 static guint32*
2285 emit_move_return_value (MonoInst *ins, guint32 *code)
2286 {
2287         /* Move return value to the target register */
2288         /* FIXME: do this in the local reg allocator */
2289         switch (ins->opcode) {
2290         case OP_VOIDCALL:
2291         case OP_VOIDCALL_REG:
2292         case OP_VOIDCALL_MEMBASE:
2293                 break;
2294         case CEE_CALL:
2295         case OP_CALL_REG:
2296         case OP_CALL_MEMBASE:
2297                 sparc_mov_reg_reg (code, sparc_o0, ins->dreg);
2298                 break;
2299         case OP_LCALL:
2300         case OP_LCALL_REG:
2301         case OP_LCALL_MEMBASE:
2302                 /* 
2303                  * ins->dreg is the least significant reg due to the lreg: LCALL rule
2304                  * in inssel.brg.
2305                  */
2306                 sparc_mov_reg_reg (code, sparc_o0, ins->dreg + 1);
2307                 sparc_mov_reg_reg (code, sparc_o1, ins->dreg);
2308                 break;
2309         case OP_FCALL:
2310         case OP_FCALL_REG:
2311         case OP_FCALL_MEMBASE:
2312                 sparc_fmovs (code, sparc_f0, ins->dreg);
2313                 if (((MonoCallInst*)ins)->signature->ret->type == MONO_TYPE_R4)
2314                         sparc_fstod (code, ins->dreg, ins->dreg);
2315                 else
2316                         sparc_fmovs (code, sparc_f1, ins->dreg + 1);
2317                 break;
2318         case OP_VCALL:
2319         case OP_VCALL_REG:
2320         case OP_VCALL_MEMBASE:
2321                 break;
2322         default:
2323                 NOT_IMPLEMENTED;
2324         }
2325
2326         return code;
2327 }
2328
2329 /*
2330  * emit_load_volatile_arguments:
2331  *
2332  *  Load volatile arguments from the stack to the original input registers.
2333  * Required before a tail call.
2334  */
2335 static guint32*
2336 emit_load_volatile_arguments (MonoCompile *cfg, guint32 *code)
2337 {
2338         MonoMethod *method = cfg->method;
2339         MonoMethodSignature *sig;
2340         MonoInst *inst;
2341         CallInfo *cinfo;
2342         guint32 i, ireg;
2343
2344         /* FIXME: Generate intermediate code instead */
2345
2346         sig = method->signature;
2347
2348         cinfo = get_call_info (sig, FALSE);
2349         
2350         /* This is the opposite of the code in emit_prolog */
2351
2352         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2353                 ArgInfo *ainfo = cinfo->args + i;
2354                 guint32 stack_offset;
2355                 MonoType *arg_type;
2356                 inst = cfg->varinfo [i];
2357
2358                 if (sig->hasthis && (i == 0))
2359                         arg_type = mono_defaults.object_class;
2360                 else
2361                         arg_type = sig->params [i - sig->hasthis];
2362
2363                 stack_offset = ainfo->offset + 68;
2364                 ireg = sparc_i0 + ainfo->reg;
2365
2366                 if (ainfo->storage == ArgInSplitRegStack) {
2367                         g_assert (inst->opcode == OP_REGOFFSET);
2368                         if (!sparc_is_imm13 (stack_offset))
2369                                 NOT_IMPLEMENTED;
2370                         sparc_st_imm (code, inst->inst_basereg, stack_offset, sparc_i5);
2371                 }
2372
2373                 if (!arg_type->byref && (arg_type->type == MONO_TYPE_R8)) {
2374                         if (ainfo->storage == ArgInIRegPair) {
2375                                 if (!sparc_is_imm13 (inst->inst_offset + 4))
2376                                         NOT_IMPLEMENTED;
2377                                 sparc_ld_imm (code, inst->inst_basereg, inst->inst_offset, ireg);
2378                                 sparc_ld_imm (code, inst->inst_basereg, inst->inst_offset + 4, ireg + 1);
2379                         }
2380                         else
2381                                 if (ainfo->storage == ArgInSplitRegStack) {
2382                                         if (stack_offset != inst->inst_offset) {
2383                                                 sparc_ld_imm (code, inst->inst_basereg, inst->inst_offset, sparc_i5);
2384                                                 sparc_ld_imm (code, inst->inst_basereg, inst->inst_offset + 4, sparc_o7);
2385                                                 sparc_st_imm (code, sparc_o7, sparc_fp, stack_offset + 4);
2386
2387                                         }
2388                                 }
2389                         else
2390                                 if (ainfo->storage == ArgOnStackPair) {
2391                                         if (stack_offset != inst->inst_offset) {
2392                                                 /* stack_offset is not dword aligned, so we need to make a copy */
2393                                                 sparc_ld_imm (code, inst->inst_basereg, inst->inst_offset, sparc_o7);
2394                                                 sparc_st_imm (code, sparc_o7, sparc_fp, stack_offset);
2395
2396                                                 sparc_ld_imm (code, inst->inst_basereg, inst->inst_offset + 4, sparc_o7);
2397                                                 sparc_st_imm (code, sparc_o7, sparc_fp, stack_offset + 4);
2398
2399                                         }
2400                                 }
2401                         else
2402                                 g_assert_not_reached ();
2403                 }
2404                 else
2405                         if ((ainfo->storage == ArgInIReg) && (inst->opcode != OP_REGVAR)) {
2406                                 /* Argument in register, but need to be saved to stack */
2407                                 if (!sparc_is_imm13 (stack_offset))
2408                                         NOT_IMPLEMENTED;
2409                                 if (stack_offset & 0x1)
2410                                         /* FIXME: Is this ldsb or ldub ? */
2411                                         sparc_ldsb_imm (code, inst->inst_basereg, stack_offset, ireg);
2412                                 else
2413                                         if (stack_offset & 0x2)
2414                                                 sparc_ldsh_imm (code, inst->inst_basereg, stack_offset, ireg);
2415                                 else
2416                                         sparc_ld_imm (code, inst->inst_basereg, stack_offset, ireg);
2417                         }
2418                 else
2419                         if ((ainfo->storage == ArgInIRegPair) && (inst->opcode != OP_REGVAR)) {
2420                                 /* Argument in regpair, but need to be saved to stack */
2421                                 if (!sparc_is_imm13 (inst->inst_offset + 4))
2422                                         NOT_IMPLEMENTED;
2423                                 sparc_ld_imm (code, inst->inst_basereg, inst->inst_offset, ireg);
2424                                 sparc_st_imm (code, inst->inst_basereg, inst->inst_offset + 4, ireg + 1);
2425                         }
2426
2427                 if ((ainfo->storage == ArgInSplitRegStack) || (ainfo->storage == ArgOnStack))
2428                         if (inst->opcode == OP_REGVAR)
2429                                 /* FIXME: Load the argument into memory */
2430                                 NOT_IMPLEMENTED;
2431         }
2432
2433         g_free (cinfo);
2434
2435         return code;
2436 }
2437
2438 /*
2439  * mono_sparc_is_virtual_call:
2440  *
2441  *  Determine whenever the instruction at CODE is a virtual call.
2442  */
2443 gboolean 
2444 mono_sparc_is_virtual_call (guint32 *code)
2445 {
2446         guint32 buf[1];
2447         guint32 *p;
2448
2449         p = buf;
2450
2451         if ((sparc_inst_op (*code) == 0x2) && (sparc_inst_op3 (*code) == 0x38)) {
2452                 /*
2453                  * Register indirect call. If it is a virtual call, then the 
2454                  * instruction in the delay slot is a special kind of nop.
2455                  */
2456
2457                 /* Construct special nop */
2458                 sparc_or_imm (p, FALSE, sparc_g0, 0xca, sparc_g0);
2459                 p --;
2460
2461                 if (code [1] == p [0])
2462                         return TRUE;
2463         }
2464
2465         return FALSE;
2466 }
2467
2468 /*
2469  * mono_sparc_get_vcall_slot_addr:
2470  *
2471  *  Determine the vtable slot used by a virtual call.
2472  */
2473 gpointer*
2474 mono_sparc_get_vcall_slot_addr (guint32 *code, guint32 *fp)
2475 {
2476         guint32 ins = code [0];
2477         guint32 prev_ins = code [-1];
2478
2479         mono_sparc_flushw ();
2480
2481         if ((sparc_inst_op (ins) == 0x2) && (sparc_inst_op3 (ins) == 0x38)) {
2482                 if ((sparc_inst_op (prev_ins) == 0x3) && (sparc_inst_op3 (prev_ins) == 0)) {
2483                         /* ld [r1 + CONST ], r2; call r2 */
2484                         guint32 base = sparc_inst_rs1 (prev_ins);
2485                         guint32 disp = sparc_inst_imm13 (prev_ins);
2486                         guint32 base_val;
2487
2488                         g_assert (sparc_inst_rd (prev_ins) == sparc_inst_rs1 (ins));
2489
2490                         g_assert ((base >= sparc_o0) && (base <= sparc_i7));
2491                         
2492                         base_val = fp [base - 16];
2493
2494                         return (gpointer)((guint8*)base_val + disp);
2495                 }
2496                 else
2497                         g_assert_not_reached ();
2498         }
2499         else
2500                 g_assert_not_reached ();
2501
2502         return FALSE;
2503 }
2504
2505 /*
2506  * Some conventions used in the following code.
2507  * 2) The only scratch registers we have are o7 and g1.  We try to
2508  * stick to o7 when we can, and use g1 when necessary.
2509  */
2510
2511 void
2512 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2513 {
2514         MonoInst *ins;
2515         MonoCallInst *call;
2516         guint offset;
2517         guint32 *code = (guint32*)(cfg->native_code + cfg->code_len);
2518         MonoInst *last_ins = NULL;
2519         int max_len, cpos;
2520
2521         if (cfg->opt & MONO_OPT_PEEPHOLE)
2522                 peephole_pass (cfg, bb);
2523
2524         if (cfg->verbose_level > 2)
2525                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2526
2527         cpos = bb->max_offset;
2528
2529         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2530                 NOT_IMPLEMENTED;
2531         }
2532
2533         ins = bb->code;
2534         while (ins) {
2535                 guint8* code_start;
2536
2537                 offset = (guint8*)code - cfg->native_code;
2538
2539                 max_len = ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
2540
2541                 if (offset > (cfg->code_size - max_len - 16)) {
2542                         cfg->code_size *= 2;
2543                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2544                         code = (guint32*)(cfg->native_code + offset);
2545                 }
2546                 code_start = (guint8*)code;
2547                 //      if (ins->cil_code)
2548                 //              g_print ("cil code\n");
2549                 mono_debug_record_line_number (cfg, ins, offset);
2550
2551                 switch (ins->opcode) {
2552                 case OP_STOREI1_MEMBASE_IMM:
2553                         EMIT_STORE_MEMBASE_IMM (ins, stb);
2554                         break;
2555                 case OP_STOREI2_MEMBASE_IMM:
2556                         EMIT_STORE_MEMBASE_IMM (ins, sth);
2557                         break;
2558                 case OP_STORE_MEMBASE_IMM:
2559                 case OP_STOREI4_MEMBASE_IMM:
2560                         EMIT_STORE_MEMBASE_IMM (ins, st);
2561                         break;
2562                 case OP_STOREI8_MEMBASE_IMM:
2563                         /* Only generated by peephole opts */
2564                         g_assert ((ins->inst_offset % 8) == 0);
2565                         g_assert (ins->inst_imm == 0);
2566                         EMIT_STORE_MEMBASE_IMM (ins, stx);
2567                         break;
2568                 case OP_STOREI1_MEMBASE_REG:
2569                         EMIT_STORE_MEMBASE_REG (ins, stb);
2570                         break;
2571                 case OP_STOREI2_MEMBASE_REG:
2572                         EMIT_STORE_MEMBASE_REG (ins, sth);
2573                         break;
2574                 case OP_STORE_MEMBASE_REG:
2575                 case OP_STOREI4_MEMBASE_REG:
2576                         EMIT_STORE_MEMBASE_REG (ins, st);
2577                         break;
2578                 case OP_STOREI8_MEMBASE_REG:
2579                         /* Only used by OP_MEMSET */
2580                         EMIT_STORE_MEMBASE_REG (ins, std);
2581                         break;
2582                 case CEE_LDIND_I:
2583                 case CEE_LDIND_I4:
2584                 case CEE_LDIND_U4:
2585                         sparc_ld (code, ins->inst_p0, sparc_g0, ins->dreg);
2586                         break;
2587                 /* The cast IS BAD (maybe).  But it needs to be done... */
2588                 case OP_LOADU4_MEM:
2589                         sparc_set (code, (guint)ins->inst_p0, ins->dreg);
2590                         sparc_ld (code, ins->dreg, sparc_g0, ins->dreg);
2591                         break;
2592                 case OP_LOAD_MEMBASE:
2593                 case OP_LOADI4_MEMBASE:
2594                 case OP_LOADU4_MEMBASE:
2595                         EMIT_LOAD_MEMBASE (ins, ld);
2596                         break;
2597                 case OP_LOADU1_MEMBASE:
2598                         EMIT_LOAD_MEMBASE (ins, ldub);
2599                         break;
2600                 case OP_LOADI1_MEMBASE:
2601                         EMIT_LOAD_MEMBASE (ins, ldsb);
2602                         break;
2603                 case OP_LOADU2_MEMBASE:
2604                         EMIT_LOAD_MEMBASE (ins, lduh);
2605                         break;
2606                 case OP_LOADI2_MEMBASE:
2607                         EMIT_LOAD_MEMBASE (ins, ldsh);
2608                         break;
2609                 case CEE_CONV_I1:
2610                         sparc_sll_imm (code, ins->sreg1, 24, sparc_o7);
2611                         sparc_sra_imm (code, sparc_o7, 24, ins->dreg);
2612                         break;
2613                 case CEE_CONV_I2:
2614                         sparc_sll_imm (code, ins->sreg1, 16, sparc_o7);
2615                         sparc_sra_imm (code, sparc_o7, 16, ins->dreg);
2616                         break;
2617                 /* GCC does this one differently.  Don't ask me WHY. */
2618                 case CEE_CONV_U1:
2619                         sparc_and_imm (code, FALSE, ins->sreg1, 0xff, ins->dreg);
2620                         break;
2621                 case CEE_CONV_U2:
2622                         sparc_sll_imm (code, ins->sreg1, 16, sparc_o7);
2623                         sparc_srl_imm (code, sparc_o7, 16, ins->dreg);
2624                         break;
2625                 case OP_COMPARE:
2626                         sparc_cmp (code, ins->sreg1, ins->sreg2);
2627                         break;
2628                 case OP_COMPARE_IMM:
2629                         if (sparc_is_imm13 (ins->inst_imm))
2630                                 sparc_cmp_imm (code, ins->sreg1, ins->inst_imm);
2631                         else {
2632                                 sparc_set (code, ins->inst_imm, sparc_o7);
2633                                 sparc_cmp (code, ins->sreg1, sparc_o7);
2634                         }
2635                         break;
2636                 case OP_X86_TEST_NULL:
2637                         sparc_cmp_imm (code, ins->sreg1, 0);
2638                         break;
2639                 case CEE_BREAK:
2640                         /*
2641                          * gdb does not like encountering 'ta 1' in the debugged code. So 
2642                          * instead of emitting a trap, we emit a call a C function and place a 
2643                          * breakpoint there.
2644                          */
2645                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, mono_sparc_break);
2646                         sparc_call_simple (code, 0);
2647                         sparc_nop (code);
2648                         break;
2649                 case OP_ADDCC:
2650                         sparc_add (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
2651                         break;
2652                 case CEE_ADD:
2653                         sparc_add (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2654                         break;
2655                 case OP_ADDCC_IMM:
2656                 case OP_ADD_IMM:
2657                         /* according to inssel-long32.brg, this should set cc */
2658                         EMIT_ALU_IMM (ins, add, TRUE);
2659                         break;
2660                 case OP_ADC:
2661                         /* according to inssel-long32.brg, this should set cc */
2662                         sparc_addx (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
2663                         break;
2664                 case OP_ADC_IMM:
2665                         EMIT_ALU_IMM (ins, addx, TRUE);
2666                         break;
2667                 case OP_SUBCC:
2668                         sparc_sub (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
2669                         break;
2670                 case CEE_SUB:
2671                         sparc_sub (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2672                         break;
2673                 case OP_SUBCC_IMM:
2674                 case OP_SUB_IMM:
2675                         /* according to inssel-long32.brg, this should set cc */
2676                         EMIT_ALU_IMM (ins, sub, TRUE);
2677                         break;
2678                 case OP_SBB:
2679                         /* according to inssel-long32.brg, this should set cc */
2680                         sparc_subx (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
2681                         break;
2682                 case OP_SBB_IMM:
2683                         EMIT_ALU_IMM (ins, subx, TRUE);
2684                         break;
2685                 case CEE_AND:
2686                         sparc_and (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2687                         break;
2688                 case OP_AND_IMM:
2689                         EMIT_ALU_IMM (ins, and, FALSE);
2690                         break;
2691                 case CEE_DIV:
2692                         /* Sign extend sreg1 into %y */
2693                         sparc_sra_imm (code, ins->sreg1, 31, sparc_o7);
2694                         sparc_wry (code, sparc_o7, sparc_g0);
2695                         sparc_sdiv (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
2696                         EMIT_COND_SYSTEM_EXCEPTION (code, sparc_boverflow, "ArithmeticException");
2697                         break;
2698                 case CEE_DIV_UN:
2699                         sparc_wry (code, sparc_g0, sparc_g0);
2700                         sparc_udiv (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2701                         break;
2702                 case OP_DIV_IMM: {
2703                         int i, imm;
2704
2705                         /* Transform division into a shift */
2706                         for (i = 1; i < 30; ++i) {
2707                                 imm = (1 << i);
2708                                 if (ins->inst_imm == imm)
2709                                         break;
2710                         }
2711                         if (i < 30) {
2712                                 if (i == 1) {
2713                                         /* gcc 2.95.3 */
2714                                         sparc_srl_imm (code, ins->sreg1, 31, sparc_o7);
2715                                         sparc_add (code, FALSE, ins->sreg1, sparc_o7, ins->dreg);
2716                                         sparc_sra_imm (code, ins->dreg, 1, ins->dreg);
2717                                 }
2718                                 else {
2719                                         /* http://compilers.iecc.com/comparch/article/93-04-079 */
2720                                         sparc_sra_imm (code, ins->sreg1, 31, sparc_o7);
2721                                         sparc_srl_imm (code, sparc_o7, 32 - i, sparc_o7);
2722                                         sparc_add (code, FALSE, ins->sreg1, sparc_o7, ins->dreg);
2723                                         sparc_sra_imm (code, ins->dreg, i, ins->dreg);
2724                                 }
2725                         }
2726                         else {
2727                                 /* Sign extend sreg1 into %y */
2728                                 sparc_sra_imm (code, ins->sreg1, 31, sparc_o7);
2729                                 sparc_wry (code, sparc_o7, sparc_g0);
2730                                 EMIT_ALU_IMM (ins, sdiv, TRUE);
2731                                 EMIT_COND_SYSTEM_EXCEPTION (code, sparc_boverflow, "ArithmeticException");
2732                         }
2733                         break;
2734                 }
2735                 case CEE_REM:
2736                         /* Sign extend sreg1 into %y */
2737                         sparc_sra_imm (code, ins->sreg1, 31, sparc_o7);
2738                         sparc_wry (code, sparc_o7, sparc_g0);
2739                         sparc_sdiv (code, TRUE, ins->sreg1, ins->sreg2, sparc_o7);
2740                         EMIT_COND_SYSTEM_EXCEPTION (code, sparc_boverflow, "ArithmeticException");
2741                         sparc_smul (code, FALSE, ins->sreg2, sparc_o7, sparc_o7);
2742                         sparc_sub (code, FALSE, ins->sreg1, sparc_o7, ins->dreg);
2743                         break;
2744                 case CEE_REM_UN:
2745                         sparc_wry (code, sparc_g0, sparc_g0);
2746                         sparc_udiv (code, FALSE, ins->sreg1, ins->sreg2, sparc_o7);
2747                         sparc_umul (code, FALSE, ins->sreg2, sparc_o7, sparc_o7);
2748                         sparc_sub (code, FALSE, ins->sreg1, sparc_o7, ins->dreg);
2749                         break;
2750                 case OP_REM_IMM:
2751                         /* Sign extend sreg1 into %y */
2752                         sparc_sra_imm (code, ins->sreg1, 31, sparc_o7);
2753                         sparc_wry (code, sparc_o7, sparc_g0);
2754                         if (!sparc_is_imm13 (ins->inst_imm)) {
2755                                 sparc_set (code, ins->inst_imm, sparc_g1);
2756                                 sparc_sdiv (code, TRUE, ins->sreg1, sparc_g1, sparc_o7);
2757                                 EMIT_COND_SYSTEM_EXCEPTION (code, sparc_boverflow, "ArithmeticException");
2758                                 sparc_smul (code, FALSE, sparc_o7, sparc_g1, sparc_o7);
2759                         }
2760                         else {
2761                                 sparc_sdiv_imm (code, TRUE, ins->sreg1, ins->inst_imm, sparc_o7);
2762                                 EMIT_COND_SYSTEM_EXCEPTION (code, sparc_boverflow, "ArithmeticException");
2763                                 sparc_smul_imm (code, FALSE, sparc_o7, ins->inst_imm, sparc_o7);
2764                         }
2765                         sparc_sub (code, FALSE, ins->sreg1, sparc_o7, ins->dreg);
2766                         break;
2767                 case CEE_OR:
2768                         sparc_or (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2769                         break;
2770                 case OP_OR_IMM:
2771                         EMIT_ALU_IMM (ins, or, FALSE);
2772                         break;
2773                 case CEE_XOR:
2774                         sparc_xor (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2775                         break;
2776                 case OP_XOR_IMM:
2777                         EMIT_ALU_IMM (ins, xor, FALSE);
2778                         break;
2779                 case CEE_SHL:
2780                         sparc_sll (code, ins->sreg1, ins->sreg2, ins->dreg);
2781                         break;
2782                 case OP_SHL_IMM:
2783                         if (sparc_is_imm13 (ins->inst_imm))
2784                                 sparc_sll_imm (code, ins->sreg1, ins->inst_imm, ins->dreg);
2785                         else {
2786                                 sparc_set (code, ins->inst_imm, sparc_o7);
2787                                 sparc_sll (code, ins->sreg1, sparc_o7, ins->dreg);
2788                         }
2789                         break;
2790                 case CEE_SHR:
2791                         sparc_sra (code, ins->sreg1, ins->sreg2, ins->dreg);
2792                         break;
2793                 case OP_SHR_IMM:
2794                         if (sparc_is_imm13 (ins->inst_imm))
2795                                 sparc_sra_imm (code, ins->sreg1, ins->inst_imm, ins->dreg);
2796                         else {
2797                                 sparc_set (code, ins->inst_imm, sparc_o7);
2798                                 sparc_sra (code, ins->sreg1, sparc_o7, ins->dreg);
2799                         }
2800                         break;
2801                 case OP_SHR_UN_IMM:
2802                         if (sparc_is_imm13 (ins->inst_imm))
2803                                 sparc_srl_imm (code, ins->sreg1, ins->inst_imm, ins->dreg);
2804                         else {
2805                                 sparc_set (code, ins->inst_imm, sparc_o7);
2806                                 sparc_srl (code, ins->sreg1, sparc_o7, ins->dreg);
2807                         }
2808                         break;
2809                 case CEE_SHR_UN:
2810                         sparc_srl (code, ins->sreg1, ins->sreg2, ins->dreg);
2811                         break;
2812                 case CEE_NOT:
2813                         /* can't use sparc_not */
2814                         sparc_xnor (code, FALSE, ins->sreg1, sparc_g0, ins->dreg);
2815                         break;
2816                 case CEE_NEG:
2817                         /* can't use sparc_neg */
2818                         sparc_sub (code, FALSE, sparc_g0, ins->sreg1, ins->dreg);
2819                         break;
2820                 case CEE_MUL:
2821                         sparc_smul (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2822                         break;
2823                 case OP_MUL_IMM: {
2824                         int i, imm;
2825
2826                         /* Transform multiplication into a shift */
2827                         for (i = 1; i < 30; ++i) {
2828                                 imm = (1 << i);
2829                                 if (ins->inst_imm == imm)
2830                                         break;
2831                         }
2832                         if (i < 30)
2833                                 sparc_sll_imm (code, ins->sreg1, i, ins->dreg);
2834                         else
2835                                 EMIT_ALU_IMM (ins, smul, FALSE);
2836                         break;
2837                 }
2838                 case CEE_MUL_OVF:
2839                         sparc_smul (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
2840                         sparc_rdy (code, sparc_g1);
2841                         sparc_sra_imm (code, ins->dreg, 31, sparc_o7);
2842                         sparc_cmp (code, sparc_g1, sparc_o7);
2843                         EMIT_COND_SYSTEM_EXCEPTION (ins, sparc_bne, "OverflowException");
2844                         break;
2845                 case CEE_MUL_OVF_UN:
2846                         sparc_umul (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
2847                         sparc_rdy (code, sparc_o7);
2848                         sparc_cmp (code, sparc_o7, sparc_g0);
2849                         EMIT_COND_SYSTEM_EXCEPTION (ins, sparc_bne, "OverflowException");
2850                         break;
2851                 case OP_ICONST:
2852                 case OP_SETREGIMM:
2853                         sparc_set (code, ins->inst_c0, ins->dreg);
2854                         break;
2855                 case OP_AOTCONST:
2856                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2857                         sparc_set (code, 0xffffff, ins->dreg);
2858                         break;
2859                 case CEE_CONV_I4:
2860                 case CEE_CONV_U4:
2861                 case OP_MOVE:
2862                 case OP_SETREG:
2863                         if (ins->sreg1 != ins->dreg)
2864                                 sparc_mov_reg_reg (code, ins->sreg1, ins->dreg);
2865                         break;
2866                 case CEE_JMP:
2867                         if (cfg->method->save_lmf)
2868                                 NOT_IMPLEMENTED;
2869
2870                         code = emit_load_volatile_arguments (cfg, code);
2871                         mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2872                         sparc_set (code, 0xffffff, sparc_o7);
2873                         sparc_jmpl (code, sparc_o7, sparc_g0, sparc_g0);
2874                         /* Restore parent frame in delay slot */
2875                         sparc_restore_imm (code, sparc_g0, 0, sparc_g0);
2876                         break;
2877                 case OP_CHECK_THIS:
2878                         /* ensure ins->sreg1 is not NULL */
2879                         sparc_ld_imm (code, ins->sreg1, 0, sparc_g0);
2880                         break;
2881                 case OP_ARGLIST:
2882                         sparc_add_imm (code, FALSE, sparc_fp, cfg->sig_cookie, sparc_o7);
2883                         sparc_st_imm (code, sparc_o7, ins->sreg1, 0);
2884                         break;
2885                 case OP_FCALL:
2886                 case OP_LCALL:
2887                 case OP_VCALL:
2888                 case OP_VOIDCALL:
2889                 case CEE_CALL:
2890                         call = (MonoCallInst*)ins;
2891                         g_assert (!call->virtual);
2892                         code = emit_save_sp_to_lmf (cfg, code);
2893                         if (ins->flags & MONO_INST_HAS_METHOD)
2894                                 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_METHOD, call->method);
2895                         else
2896                                 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_ABS, call->fptr);
2897                         sparc_call_simple (code, 0);
2898                         sparc_nop (code);
2899
2900                         code = emit_vret_token (ins, code);
2901                         code = emit_move_return_value (ins, code);
2902                         break;
2903                 case OP_FCALL_REG:
2904                 case OP_LCALL_REG:
2905                 case OP_VCALL_REG:
2906                 case OP_VOIDCALL_REG:
2907                 case OP_CALL_REG:
2908                         call = (MonoCallInst*)ins;
2909                         code = emit_save_sp_to_lmf (cfg, code);
2910                         sparc_jmpl (code, ins->sreg1, sparc_g0, sparc_callsite);
2911                         /*
2912                          * We emit a special kind of nop in the delay slot to tell the 
2913                          * trampoline code that this is a virtual call, thus an unbox
2914                          * trampoline might need to be called.
2915                          */
2916                         if (call->virtual)
2917                                 sparc_or_imm (code, FALSE, sparc_g0, 0xca, sparc_g0);
2918                         else
2919                                 sparc_nop (code);
2920
2921                         code = emit_vret_token (ins, code);
2922                         code = emit_move_return_value (ins, code);
2923                         break;
2924                 case OP_FCALL_MEMBASE:
2925                 case OP_LCALL_MEMBASE:
2926                 case OP_VCALL_MEMBASE:
2927                 case OP_VOIDCALL_MEMBASE:
2928                 case OP_CALL_MEMBASE:
2929                         call = (MonoCallInst*)ins;
2930                         g_assert (sparc_is_imm13 (ins->inst_offset));
2931                         code = emit_save_sp_to_lmf (cfg, code);
2932                         sparc_ld_imm (code, ins->inst_basereg, ins->inst_offset, sparc_o7);
2933                         sparc_jmpl (code, sparc_o7, sparc_g0, sparc_callsite);
2934                         if (call->virtual)
2935                                 sparc_or_imm (code, FALSE, sparc_g0, 0xca, sparc_g0);
2936                         else
2937                                 sparc_nop (code);
2938
2939                         code = emit_vret_token (ins, code);
2940                         code = emit_move_return_value (ins, code);
2941                         break;
2942                 case OP_SETFRET:
2943                         if (cfg->method->signature->ret->type == MONO_TYPE_R4)
2944                                 sparc_fdtos (code, ins->sreg1, sparc_f0);
2945                         else {
2946                                 sparc_fmovs (code, ins->sreg1, ins->dreg);
2947                                 sparc_fmovs (code, ins->sreg1 + 1, ins->dreg + 1);
2948                         }
2949                         break;
2950                 case OP_OUTARG:
2951                         g_assert_not_reached ();
2952                         break;
2953                 case OP_LOCALLOC:
2954                         /* Keep alignment */
2955                         sparc_add_imm (code, FALSE, ins->sreg1, MONO_ARCH_FRAME_ALIGNMENT - 1, ins->dreg);
2956                         sparc_set (code, ~(MONO_ARCH_FRAME_ALIGNMENT - 1), sparc_o7);
2957                         sparc_and (code, FALSE, ins->dreg, sparc_o7, ins->dreg);
2958                         sparc_sub (code, FALSE, sparc_sp, ins->dreg, ins->dreg);
2959                         /* Keep %sp valid at all times */
2960                         sparc_mov_reg_reg (code, ins->dreg, sparc_sp);
2961                         g_assert (sparc_is_imm13 (cfg->arch.localloc_offset));
2962                         sparc_add_imm (code, FALSE, ins->dreg, cfg->arch.localloc_offset, ins->dreg);
2963                         break;
2964                 case OP_SPARC_LOCALLOC_IMM: {
2965                         guint32 offset = ins->inst_c0;
2966                         offset = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
2967                         if (sparc_is_imm13 (offset))
2968                                 sparc_sub_imm (code, FALSE, sparc_sp, offset, sparc_sp);
2969                         else {
2970                                 sparc_set (code, offset, sparc_o7);
2971                                 sparc_sub (code, FALSE, sparc_sp, sparc_o7, sparc_sp);
2972                         }
2973                         sparc_mov_reg_reg (code, sparc_sp, ins->dreg);
2974                         g_assert (sparc_is_imm13 (cfg->arch.localloc_offset));
2975                         sparc_add_imm (code, FALSE, ins->dreg, cfg->arch.localloc_offset, ins->dreg);
2976                         break;
2977                 }
2978                 case CEE_RET:
2979                         /* The return is done in the epilog */
2980                         g_assert_not_reached ();
2981                         break;
2982                 case CEE_THROW:
2983                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_INTERNAL_METHOD, 
2984                                              (gpointer)"mono_arch_throw_exception");
2985                         sparc_call_simple (code, 0);
2986                         /* Delay slot */
2987                         sparc_mov_reg_reg (code, ins->sreg1, sparc_o0);
2988                         break;
2989                 case OP_START_HANDLER: {
2990                         /*
2991                          * The START_HANDLER instruction marks the beginning of a handler 
2992                          * block. It is called using a call instruction, so %o7 contains 
2993                          * the return address. Since the handler executes in the same stack
2994              * frame as the method itself, we can't use save/restore to save 
2995                          * the return address. Instead, we save it into a dedicated 
2996                          * variable.
2997                          */
2998                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
2999                         if (!sparc_is_imm13 (spvar->inst_offset)) {
3000                                 sparc_set (code, spvar->inst_offset, sparc_g0);
3001                                 sparc_st (code, sparc_o7, spvar->inst_basereg, sparc_g0);
3002                         }
3003                         else
3004                                 sparc_st_imm (code, sparc_o7, spvar->inst_basereg, spvar->inst_offset);
3005                         break;
3006                 }
3007                 case OP_ENDFILTER: {
3008                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3009                         if (!sparc_is_imm13 (spvar->inst_offset)) {
3010                                 sparc_set (code, spvar->inst_offset, sparc_g0);
3011                                 sparc_ld (code, spvar->inst_basereg, sparc_g0, sparc_o7);
3012                         }
3013                         else
3014                                 sparc_ld_imm (code, spvar->inst_basereg, spvar->inst_offset, sparc_o7);
3015                         sparc_jmpl_imm (code, sparc_o7, 8, sparc_g0);
3016                         /* Delay slot */
3017                         sparc_mov_reg_reg (code, ins->sreg1, sparc_o0);
3018                         break;
3019                 }
3020                 case CEE_ENDFINALLY: {
3021                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3022                         if (!sparc_is_imm13 (spvar->inst_offset)) {
3023                                 sparc_set (code, spvar->inst_offset, sparc_g0);
3024                                 sparc_ld (code, spvar->inst_basereg, sparc_g0, sparc_o7);
3025                         }
3026                         else
3027                                 sparc_ld_imm (code, spvar->inst_basereg, spvar->inst_offset, sparc_o7);
3028                         sparc_jmpl_imm (code, sparc_o7, 8, sparc_g0);
3029                         sparc_nop (code);
3030                         break;
3031                 }
3032                 case OP_CALL_HANDLER: 
3033                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3034                         sparc_call_simple (code, 0);
3035                         sparc_nop (code);
3036                         break;
3037                 case OP_LABEL:
3038                         ins->inst_c0 = (guint8*)code - cfg->native_code;
3039                         break;
3040                 case CEE_BR:
3041                         //g_print ("target: %p, next: %p, curr: %p, last: %p\n", ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
3042                         if ((ins->inst_target_bb == bb->next_bb) && ins == bb->last_ins)
3043                                 break;
3044                         if (ins->flags & MONO_INST_BRLABEL) {
3045                                 if (ins->inst_i0->inst_c0) {
3046                                         gint32 disp = (ins->inst_i0->inst_c0 - ((guint8*)code - cfg->native_code)) >> 2;
3047                                         g_assert (sparc_is_imm22 (disp));
3048                                         sparc_branch (code, 1, sparc_ba, disp);
3049                                 } else {
3050                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3051                                         sparc_branch (code, 1, sparc_ba, 0);
3052                                 }
3053                         } else {
3054                                 if (ins->inst_target_bb->native_offset) {
3055                                         gint32 disp = (ins->inst_target_bb->native_offset - ((guint8*)code - cfg->native_code)) >> 2;
3056                                         g_assert (sparc_is_imm22 (disp));
3057                                         sparc_branch (code, 1, sparc_ba, disp);
3058                                 } else {
3059                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3060                                         sparc_branch (code, 1, sparc_ba, 0);
3061                                 } 
3062                         }
3063                         sparc_nop (code);
3064                         break;
3065                 case OP_BR_REG:
3066                         sparc_jmp (code, ins->sreg1, sparc_g0);
3067                         sparc_nop (code);
3068                         break;
3069                 case OP_CEQ:
3070                 case OP_CLT:
3071                 case OP_CLT_UN:
3072                 case OP_CGT:
3073                 case OP_CGT_UN:
3074                         //if (cfg->opt & MONO_OPT_CMOV) {
3075                         if (0) {
3076                                 sparc_clr_reg (code, ins->dreg);
3077                                 sparc_movcc_imm (code, sparc_icc, opcode_to_sparc_cond (ins->opcode), 1, ins->dreg);
3078                         }
3079                         else {
3080                                 sparc_clr_reg (code, ins->dreg);
3081                                 sparc_branch (code, 1, opcode_to_sparc_cond (ins->opcode), 2);
3082                                 /* delay slot */
3083                                 sparc_set (code, 1, ins->dreg);
3084                         }
3085                         break;
3086                 case OP_COND_EXC_EQ:
3087                 case OP_COND_EXC_NE_UN:
3088                 case OP_COND_EXC_LT:
3089                 case OP_COND_EXC_LT_UN:
3090                 case OP_COND_EXC_GT:
3091                 case OP_COND_EXC_GT_UN:
3092                 case OP_COND_EXC_GE:
3093                 case OP_COND_EXC_GE_UN:
3094                 case OP_COND_EXC_LE:
3095                 case OP_COND_EXC_LE_UN:
3096                 case OP_COND_EXC_OV:
3097                 case OP_COND_EXC_NO:
3098                 case OP_COND_EXC_C:
3099                 case OP_COND_EXC_NC:
3100                         EMIT_COND_SYSTEM_EXCEPTION (ins, opcode_to_sparc_cond (ins->opcode), ins->inst_p1);
3101                         break;
3102                 case CEE_BEQ:
3103                 case CEE_BNE_UN:
3104                 case CEE_BLT:
3105                 case CEE_BLT_UN:
3106                 case CEE_BGT:
3107                 case CEE_BGT_UN:
3108                 case CEE_BGE:
3109                 case CEE_BGE_UN:
3110                 case CEE_BLE:
3111                 case CEE_BLE_UN: {
3112                         if (sparcv9)
3113                                 EMIT_COND_BRANCH_PREDICTED (ins, opcode_to_sparc_cond (ins->opcode), 1, 1);
3114                         else
3115                                 EMIT_COND_BRANCH (ins, opcode_to_sparc_cond (ins->opcode), 1, 1);
3116                         break;
3117                 }
3118                 case OP_SPARC_BRZ:
3119                         /* We misuse the macro arguments */
3120                         EMIT_COND_BRANCH_BPR (ins, brz, 1, 1, 1);
3121                         break;
3122                 case OP_SPARC_BRLEZ:
3123                         EMIT_COND_BRANCH_BPR (ins, brlez, 1, 1, 1);
3124                         break;
3125                 case OP_SPARC_BRLZ:
3126                         EMIT_COND_BRANCH_BPR (ins, brlz, 1, 1, 1);
3127                         break;
3128                 case OP_SPARC_BRNZ:
3129                         EMIT_COND_BRANCH_BPR (ins, brnz, 1, 1, 1);
3130                         break;
3131                 case OP_SPARC_BRGZ:
3132                         EMIT_COND_BRANCH_BPR (ins, brgz, 1, 1, 1);
3133                         break;
3134                 case OP_SPARC_BRGEZ:
3135                         EMIT_COND_BRANCH_BPR (ins, brgez, 1, 1, 1);
3136                         break;
3137
3138                 /* floating point opcodes */
3139                 case OP_R8CONST:
3140                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R8, ins->inst_p0);
3141                         sparc_sethi (code, 0, sparc_o7);
3142                         sparc_lddf_imm (code, sparc_o7, 0, ins->dreg);
3143                         break;
3144                 case OP_R4CONST:
3145                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R4, ins->inst_p0);
3146                         sparc_sethi (code, 0, sparc_o7);
3147                         sparc_ldf_imm (code, sparc_o7, 0, ins->dreg);
3148
3149                         /* Extend to double */
3150                         sparc_fstod (code, ins->dreg, ins->dreg);
3151                         break;
3152                 case OP_STORER8_MEMBASE_REG:
3153                         if (!sparc_is_imm13 (ins->inst_offset + 4)) {
3154                                 sparc_set (code, ins->inst_offset, sparc_o7);
3155                                 if (ins->inst_offset % 8) {
3156                                         /* Misaligned */
3157                                         sparc_add (code, FALSE, ins->inst_destbasereg, sparc_o7, sparc_o7);
3158                                         sparc_stf (code, ins->sreg1, sparc_o7, sparc_g0);
3159                                         sparc_stf_imm (code, ins->sreg1 + 1, sparc_o7, 4);
3160                                 } else
3161                                         sparc_stdf (code, ins->sreg1, ins->inst_destbasereg, sparc_o7);
3162                         }
3163                         else {
3164                                 if (ins->inst_offset % 8) {
3165                                         /* Misaligned */
3166                                         sparc_stf_imm (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3167                                         sparc_stf_imm (code, ins->sreg1 + 1, ins->inst_destbasereg, ins->inst_offset + 4);
3168                                 } else
3169                                         sparc_stdf_imm (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3170                         }
3171                         break;
3172                 case OP_LOADR8_MEMBASE:
3173                         g_assert ((ins->inst_offset % 8) == 0);
3174                         EMIT_LOAD_MEMBASE (ins, lddf);
3175                         break;
3176                 case OP_STORER4_MEMBASE_REG:
3177                         /* This requires a double->single conversion */
3178                         sparc_fdtos (code, ins->sreg1, sparc_f0);
3179                         if (!sparc_is_imm13 (ins->inst_offset)) {
3180                                 sparc_set (code, ins->inst_offset, sparc_o7);
3181                                 sparc_stf (code, sparc_f0, ins->inst_destbasereg, sparc_o7);
3182                         }
3183                         else
3184                                 sparc_stf_imm (code, sparc_f0, ins->inst_destbasereg, ins->inst_offset);
3185                         break;
3186                 case OP_LOADR4_MEMBASE:
3187                         EMIT_LOAD_MEMBASE (ins, ldf);
3188                         /* Extend to double */
3189                         sparc_fstod (code, ins->dreg, ins->dreg);
3190                         break;
3191                 case OP_FMOVE:
3192                         sparc_fmovs (code, ins->sreg1, ins->dreg);
3193                         sparc_fmovs (code, ins->sreg1 + 1, ins->dreg + 1);
3194                         break;
3195                 case CEE_CONV_R4: {
3196                         guint32 offset = mono_spillvar_offset_float (cfg, 0);
3197                         if (!sparc_is_imm13 (offset))
3198                                 NOT_IMPLEMENTED;
3199                         sparc_st_imm (code, ins->sreg1, sparc_sp, offset);
3200                         sparc_ldf_imm (code, sparc_sp, offset, sparc_f0);
3201                         sparc_fitos (code, sparc_f0, sparc_f0);
3202                         sparc_fstod (code, sparc_f0, ins->dreg);
3203                         break;
3204                 }
3205                 case CEE_CONV_R8: {
3206                         guint32 offset = mono_spillvar_offset_float (cfg, 0);
3207                         if (!sparc_is_imm13 (offset))
3208                                 NOT_IMPLEMENTED;
3209                         sparc_st_imm (code, ins->sreg1, sparc_sp, offset);
3210                         sparc_ldf_imm (code, sparc_sp, offset, sparc_f0);
3211                         sparc_fitod (code, sparc_f0, ins->dreg);
3212                         break;
3213                 }
3214                 case OP_FCONV_TO_I1:
3215                 case OP_FCONV_TO_U1:
3216                 case OP_FCONV_TO_I2:
3217                 case OP_FCONV_TO_U2:
3218                 case OP_FCONV_TO_I4:
3219                 case OP_FCONV_TO_I:
3220                 case OP_FCONV_TO_U4:
3221                 case OP_FCONV_TO_U: {
3222                         guint32 offset = mono_spillvar_offset_float (cfg, 0);
3223                         if (!sparc_is_imm13 (offset))
3224                                 NOT_IMPLEMENTED;
3225                         /* FIXME: Is having the same code for all of these ok ? */
3226                         sparc_fdtoi (code, ins->sreg1, sparc_f0);
3227                         sparc_stdf_imm (code, sparc_f0, sparc_sp, offset);
3228                         sparc_ld_imm (code, sparc_sp, offset, ins->dreg);
3229                         break;
3230                 }
3231                 case OP_FCONV_TO_I8:
3232                 case OP_FCONV_TO_U8:
3233                         /* Emulated */
3234                         g_assert_not_reached ();
3235                         break;
3236                 case CEE_CONV_R_UN:
3237                         /* Emulated */
3238                         g_assert_not_reached ();
3239                         break;
3240                 case OP_LCONV_TO_R_UN: { 
3241                         /* Emulated */
3242                         g_assert_not_reached ();
3243                         break;
3244                 }
3245                 case OP_LCONV_TO_OVF_I: {
3246                         guint32 *br [3], *label [1];
3247
3248                         /* 
3249                          * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
3250                          */
3251                         sparc_cmp_imm (code, ins->sreg1, 0);
3252                         br [0] = code; 
3253                         sparc_branch (code, 1, sparc_bneg, 0);
3254                         sparc_nop (code);
3255
3256                         /* positive */
3257                         /* ms word must be 0 */
3258                         sparc_cmp_imm (code, ins->sreg2, 0);
3259                         br [1] = code;
3260                         sparc_branch (code, 1, sparc_be, 0);
3261                         sparc_nop (code);
3262
3263                         label [0] = code;
3264
3265                         EMIT_COND_SYSTEM_EXCEPTION (ins, sparc_ba, "OverflowException");
3266
3267                         /* negative */
3268                         sparc_patch (br [0], code);
3269
3270                         /* ms word must 0xfffffff */
3271                         sparc_cmp_imm (code, ins->sreg2, -1);
3272                         br [2] = code;
3273                         sparc_branch (code, 1, sparc_bne, 0);
3274                         sparc_patch (br [2], label [0]);
3275
3276                         /* Ok */
3277                         sparc_patch (br [1], code);
3278                         if (ins->sreg1 != ins->dreg)
3279                                 sparc_mov_reg_reg (code, ins->sreg1, ins->dreg);
3280                         break;
3281                 }
3282                 case OP_FADD:
3283                         sparc_faddd (code, ins->sreg1, ins->sreg2, ins->dreg);
3284                         break;
3285                 case OP_FSUB:
3286                         sparc_fsubd (code, ins->sreg1, ins->sreg2, ins->dreg);
3287                         break;          
3288                 case OP_FMUL:
3289                         sparc_fmuld (code, ins->sreg1, ins->sreg2, ins->dreg);
3290                         break;          
3291                 case OP_FDIV:
3292                         sparc_fdivd (code, ins->sreg1, ins->sreg2, ins->dreg);
3293                         break;          
3294                 case OP_FNEG:
3295                         sparc_fnegs (code, ins->sreg1, ins->dreg);
3296                         break;          
3297                 case OP_FREM:
3298                         sparc_fdivd (code, ins->sreg1, ins->sreg2, sparc_f0);
3299                         sparc_fmuld (code, ins->sreg2, sparc_f0, sparc_f0);
3300                         sparc_fsubd (code, ins->sreg1, sparc_f0, ins->dreg);
3301                         break;
3302                 case OP_FCOMPARE:
3303                         sparc_fcmpd (code, ins->sreg1, ins->sreg2);
3304                         break;
3305                 case OP_FCEQ:
3306                 case OP_FCLT:
3307                 case OP_FCLT_UN:
3308                 case OP_FCGT:
3309                 case OP_FCGT_UN:
3310                         sparc_fcmpd (code, ins->sreg1, ins->sreg2);
3311                         sparc_clr_reg (code, ins->dreg);
3312                         switch (ins->opcode) {
3313                         case OP_FCLT_UN:
3314                         case OP_FCGT_UN:
3315                                 sparc_fbranch (code, 1, opcode_to_sparc_cond (ins->opcode), 4);
3316                                 /* delay slot */
3317                                 sparc_set (code, 1, ins->dreg);
3318                                 sparc_fbranch (code, 1, sparc_fbu, 2);
3319                                 /* delay slot */
3320                                 sparc_set (code, 1, ins->dreg);
3321                                 break;
3322                         default:
3323                                 sparc_fbranch (code, 1, opcode_to_sparc_cond (ins->opcode), 2);
3324                                 /* delay slot */
3325                                 sparc_set (code, 1, ins->dreg);                         
3326                         }
3327                         break;
3328                 case OP_FBEQ:
3329                 case OP_FBLT:
3330                 case OP_FBGT:
3331                         EMIT_FLOAT_COND_BRANCH (ins, opcode_to_sparc_cond (ins->opcode), 1, 1);
3332                         break;
3333                 case OP_FBGE: {
3334                         /* clt.un + brfalse */
3335                         guint32 *p = code;
3336                         sparc_fbranch (code, 1, sparc_fbul, 0);
3337                         /* delay slot */
3338                         sparc_nop (code);
3339                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fba, 1, 1);
3340                         sparc_patch ((guint8*)p, (guint8*)code);
3341                         break;
3342                 }
3343                 case OP_FBLE: {
3344                         /* cgt.un + brfalse */
3345                         guint32 *p = code;
3346                         sparc_fbranch (code, 1, sparc_fbug, 0);
3347                         /* delay slot */
3348                         sparc_nop (code);
3349                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fba, 1, 1);
3350                         sparc_patch ((guint8*)p, (guint8*)code);
3351                         break;
3352                 }
3353                 case OP_FBNE_UN:
3354                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbne, 1, 1);
3355                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbu, 1, 1);
3356                         break;
3357                 case OP_FBLT_UN:
3358                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbl, 1, 1);
3359                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbu, 1, 1);
3360                         break;
3361                 case OP_FBGT_UN:
3362                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbg, 1, 1);
3363                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbu, 1, 1);
3364                         break;
3365                 case OP_FBGE_UN:
3366                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbge, 1, 1);
3367                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbu, 1, 1);
3368                         break;
3369                 case OP_FBLE_UN:
3370                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fble, 1, 1);
3371                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbu, 1, 1);
3372                         break;
3373                 case CEE_CKFINITE: {
3374                         guint32 offset = mono_spillvar_offset_float (cfg, 0);
3375                         if (!sparc_is_imm13 (offset))
3376                                 NOT_IMPLEMENTED;
3377                         sparc_stdf_imm (code, ins->sreg1, sparc_sp, offset);
3378                         sparc_lduh_imm (code, sparc_sp, offset, sparc_o7);
3379                         sparc_srl_imm (code, sparc_o7, 4, sparc_o7);
3380                         sparc_and_imm (code, FALSE, sparc_o7, 2047, sparc_o7);
3381                         sparc_cmp_imm (code, sparc_o7, 2047);
3382                         EMIT_COND_SYSTEM_EXCEPTION (ins, sparc_be, "ArithmeticException");
3383                         sparc_fmovs (code, ins->sreg1, ins->dreg);
3384                         sparc_fmovs (code, ins->sreg1 + 1, ins->dreg + 1);
3385                         break;
3386                 }
3387                 default:
3388 #ifdef __GNUC__
3389                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3390 #else
3391                         g_warning ("%s:%d: unknown opcode %s\n", __FILE__, __LINE__, mono_inst_name (ins->opcode));
3392 #endif
3393                         g_assert_not_reached ();
3394                 }
3395
3396                 if ((((guint8*)code) - code_start) > max_len) {
3397                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3398                                    mono_inst_name (ins->opcode), max_len, ((guint8*)code) - code_start);
3399                         g_assert_not_reached ();
3400                 }
3401                
3402                 cpos += max_len;
3403
3404                 last_ins = ins;
3405                 
3406                 ins = ins->next;
3407         }
3408
3409         cfg->code_len = (guint8*)code - cfg->native_code;
3410 }
3411
3412 void
3413 mono_arch_register_lowlevel_calls (void)
3414 {
3415         mono_register_jit_icall (mono_sparc_break, "mono_sparc_break", NULL, TRUE);
3416         mono_register_jit_icall (mono_arch_get_lmf_addr, "mono_arch_get_lmf_addr", NULL, TRUE);
3417 }
3418
3419 void
3420 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3421 {
3422         MonoJumpInfo *patch_info;
3423
3424         /* FIXME: Move part of this to arch independent code */
3425         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3426                 unsigned char *ip = patch_info->ip.i + code;
3427                 const unsigned char *target = NULL;
3428
3429                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3430
3431                 switch (patch_info->type) {
3432                 case MONO_PATCH_INFO_CLASS_INIT: {
3433                         unsigned char *ip2 = ip;
3434                         /* Might already been changed to a nop */
3435                         sparc_call_simple (ip2, 0);
3436                         break;
3437                 }
3438                 case MONO_PATCH_INFO_R4: {
3439                         float *f = g_new0 (float, 1);
3440                         *f = *(float*)patch_info->data.target;
3441                         target = f;
3442                         break;
3443                 }
3444                 case MONO_PATCH_INFO_R8: {
3445                         double *d = g_new0 (double, 1);
3446                         *d = *(double*)patch_info->data.target;
3447                         target = d;                     
3448                         break;
3449                 }
3450                 default:
3451                         break;
3452                 }
3453                 sparc_patch (ip, target);
3454         }
3455 }
3456
3457 /*
3458  * Allow tracing to work with this interface (with an optional argument)
3459  */
3460
3461 /*
3462  * This may be needed on some archs or for debugging support.
3463  */
3464 void
3465 mono_arch_instrument_mem_needs (MonoMethod *method, int *stack, int *code)
3466 {
3467         /* no stack room needed now (may be needed for FASTCALL-trace support) */
3468         *stack = 0;
3469         /* split prolog-epilog requirements? */
3470         *code = 256; /* max bytes needed: check this number */
3471 }
3472
3473 void*
3474 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
3475 {
3476         int stack, code_size;
3477         guint32 *code = (guint32*)p;
3478
3479         /* Save registers to stack */
3480         sparc_st_imm (code, sparc_i0, sparc_fp, 68);
3481         sparc_st_imm (code, sparc_i1, sparc_fp, 72);
3482         sparc_st_imm (code, sparc_i2, sparc_fp, 76);
3483         sparc_st_imm (code, sparc_i3, sparc_fp, 80);
3484         sparc_st_imm (code, sparc_i4, sparc_fp, 84);
3485         sparc_st_imm (code, sparc_i5, sparc_fp, 88);
3486
3487         sparc_set (code, cfg->method, sparc_o0);
3488         sparc_mov_reg_reg (code, sparc_fp, sparc_o1);
3489
3490         mono_add_patch_info (cfg, (guint8*)code-cfg->native_code, MONO_PATCH_INFO_ABS, func);
3491         sparc_sethi (code, 0, sparc_o7);
3492         sparc_jmpl_imm (code, sparc_o7, 0, sparc_callsite);
3493         sparc_nop (code);
3494
3495         mono_arch_instrument_mem_needs (cfg->method, &stack, &code_size);
3496
3497         g_assert ((code - (guint32*)p) <= (code_size * 4));
3498
3499         return code;
3500 }
3501
3502 enum {
3503         SAVE_NONE,
3504         SAVE_STRUCT,
3505         SAVE_ONE,
3506         SAVE_TWO,
3507         SAVE_FP
3508 };
3509
3510 void*
3511 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
3512 {
3513         guchar *code = p;
3514         int save_mode = SAVE_NONE;
3515         MonoMethod *method = cfg->method;
3516         int rtype = method->signature->ret->type;
3517         
3518 handle_enum:
3519         switch (rtype) {
3520         case MONO_TYPE_VOID:
3521                 /* special case string .ctor icall */
3522                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
3523                         save_mode = SAVE_ONE;
3524                 else
3525                         save_mode = SAVE_NONE;
3526                 break;
3527         case MONO_TYPE_I8:
3528         case MONO_TYPE_U8:
3529                 save_mode = SAVE_TWO;
3530                 break;
3531         case MONO_TYPE_R4:
3532         case MONO_TYPE_R8:
3533                 save_mode = SAVE_FP;
3534                 break;
3535         case MONO_TYPE_VALUETYPE:
3536                 if (method->signature->ret->data.klass->enumtype) {
3537                         rtype = method->signature->ret->data.klass->enum_basetype->type;
3538                         goto handle_enum;
3539                 }
3540                 save_mode = SAVE_STRUCT;
3541                 break;
3542         default:
3543                 save_mode = SAVE_ONE;
3544                 break;
3545         }
3546
3547         /* Save the result to the stack and also put it into the output registers */
3548
3549         switch (save_mode) {
3550         case SAVE_TWO:
3551                 sparc_st_imm (code, sparc_i0, sparc_fp, 68);
3552                 sparc_st_imm (code, sparc_i0, sparc_fp, 72);
3553                 sparc_mov_reg_reg (code, sparc_i0, sparc_o1);
3554                 sparc_mov_reg_reg (code, sparc_i1, sparc_o2);
3555                 break;
3556         case SAVE_ONE:
3557                 sparc_st_imm (code, sparc_i0, sparc_fp, 68);
3558                 sparc_mov_reg_reg (code, sparc_i0, sparc_o1);
3559                 break;
3560         case SAVE_FP:
3561                 sparc_stdf_imm (code, sparc_f0, sparc_fp, 72);
3562                 sparc_ld_imm (code, sparc_fp, 72, sparc_o1);
3563                 sparc_ld_imm (code, sparc_fp, 72, sparc_o2);
3564                 break;
3565         case SAVE_STRUCT:
3566                 sparc_ld_imm (code, sparc_fp, 64, sparc_o1);
3567                 break;
3568         case SAVE_NONE:
3569         default:
3570                 break;
3571         }
3572
3573         sparc_set (code, cfg->method, sparc_o0);
3574
3575         mono_add_patch_info (cfg, (guint8*)code-cfg->native_code, MONO_PATCH_INFO_ABS, func);
3576         sparc_sethi (code, 0, sparc_o7);
3577         sparc_jmpl_imm (code, sparc_o7, 0, sparc_callsite);
3578         sparc_nop (code);
3579
3580         /* Restore result */
3581
3582         switch (save_mode) {
3583         case SAVE_TWO:
3584                 sparc_ld_imm (code, sparc_fp, 68, sparc_i0);
3585                 sparc_ld_imm (code, sparc_fp, 72, sparc_i0);
3586                 break;
3587         case SAVE_ONE:
3588                 sparc_ld_imm (code, sparc_fp, 68, sparc_i0);
3589                 break;
3590         case SAVE_FP:
3591                 sparc_lddf_imm (code, sparc_fp, 72, sparc_f0);
3592                 break;
3593         case SAVE_NONE:
3594         default:
3595                 break;
3596         }
3597
3598         return code;
3599 }
3600
3601 int
3602 mono_arch_max_epilog_size (MonoCompile *cfg)
3603 {
3604         int exc_count = 0, max_epilog_size = 16 + 20*4;
3605         MonoJumpInfo *patch_info;
3606         
3607         if (cfg->method->save_lmf)
3608                 max_epilog_size += 128;
3609         
3610         if (mono_jit_trace_calls != NULL)
3611                 max_epilog_size += 50;
3612
3613         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3614                 max_epilog_size += 50;
3615
3616         /* count the number of exception infos */
3617      
3618         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3619                 if (patch_info->type == MONO_PATCH_INFO_EXC)
3620                         exc_count++;
3621         }
3622
3623         /* 
3624          * make sure we have enough space for exceptions
3625          */
3626         max_epilog_size += exc_count * 24;
3627
3628         return max_epilog_size;
3629 }
3630
3631 guint8 *
3632 mono_arch_emit_prolog (MonoCompile *cfg)
3633 {
3634         MonoMethod *method = cfg->method;
3635         MonoMethodSignature *sig;
3636         MonoInst *inst;
3637         guint8 *code;
3638         CallInfo *cinfo;
3639         guint32 i, offset;
3640
3641         cfg->code_size = 256;
3642         code = cfg->native_code = g_malloc (cfg->code_size);
3643
3644         /* FIXME: Generate intermediate code instead */
3645
3646         offset = cfg->stack_offset;
3647         offset += 64; /* register save area */
3648         offset += 4; /* struct/union return pointer */
3649
3650         /* add parameter area size for called functions */
3651         if (cfg->param_area < 24)
3652                 /* Reserve space for the first 6 arguments even if it is unused */
3653                 offset += 24;
3654         else
3655                 offset += cfg->param_area;
3656         
3657         /* align the stack size to 8 bytes */
3658         offset = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
3659
3660         /*
3661          * localloc'd memory is stored between the local variables (whose
3662          * size is given by cfg->stack_offset), and between the space reserved
3663          * by the ABI.
3664          */
3665         cfg->arch.localloc_offset = offset - cfg->stack_offset;
3666
3667         cfg->stack_offset = offset;
3668
3669         if (!sparc_is_imm13 (- cfg->stack_offset)) {
3670                 /* Can't use sparc_o7 here, since we're still in the caller's frame */
3671                 sparc_set (code, (- cfg->stack_offset), sparc_g1);
3672                 sparc_save (code, sparc_sp, sparc_g1, sparc_sp);
3673         }
3674         else
3675                 sparc_save_imm (code, sparc_sp, - cfg->stack_offset, sparc_sp);
3676
3677         if (strstr (cfg->method->name, "test_marshal_struct")) {
3678                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_ABS, mono_sparc_break);
3679                 sparc_call_simple (code, 0);
3680                 sparc_nop (code);
3681         }
3682
3683         sig = method->signature;
3684
3685         cinfo = get_call_info (sig, FALSE);
3686
3687         /* Keep in sync with emit_load_volatile_arguments */
3688         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3689                 ArgInfo *ainfo = cinfo->args + i;
3690                 guint32 stack_offset;
3691                 MonoType *arg_type;
3692                 inst = cfg->varinfo [i];
3693
3694                 if (sig->hasthis && (i == 0))
3695                         arg_type = mono_defaults.object_class;
3696                 else
3697                         arg_type = sig->params [i - sig->hasthis];
3698
3699                 stack_offset = ainfo->offset + 68;
3700
3701                 /* Save the split arguments so they will reside entirely on the stack */
3702                 if (ainfo->storage == ArgInSplitRegStack) {
3703                         /* Save the register to the stack */
3704                         g_assert (inst->opcode == OP_REGOFFSET);
3705                         if (!sparc_is_imm13 (stack_offset))
3706                                 NOT_IMPLEMENTED;
3707                         sparc_st_imm (code, sparc_i5, inst->inst_basereg, stack_offset);
3708                 }
3709
3710                 if (!arg_type->byref && (arg_type->type == MONO_TYPE_R8)) {
3711                         /* Save the argument to a dword aligned stack location */
3712                         /*
3713                          * stack_offset contains the offset of the argument on the stack.
3714                          * inst->inst_offset contains the dword aligned offset where the value 
3715                          * should be stored.
3716                          */
3717                         if (ainfo->storage == ArgInIRegPair) {
3718                                 if (!sparc_is_imm13 (inst->inst_offset + 4))
3719                                         NOT_IMPLEMENTED;
3720                                 sparc_st_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, inst->inst_offset);
3721                                 sparc_st_imm (code, sparc_i0 + ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
3722                         }
3723                         else
3724                                 if (ainfo->storage == ArgInSplitRegStack) {
3725                                         if (stack_offset != inst->inst_offset) {
3726                                                 /* stack_offset is not dword aligned, so we need to make a copy */
3727                                                 sparc_st_imm (code, sparc_i5, inst->inst_basereg, inst->inst_offset);
3728                                                 sparc_ld_imm (code, sparc_fp, stack_offset + 4, sparc_o7);
3729                                                 sparc_st_imm (code, sparc_o7, inst->inst_basereg, inst->inst_offset + 4);
3730                                         }
3731                                 }
3732                         else
3733                                 if (ainfo->storage == ArgOnStackPair) {
3734                                         if (stack_offset != inst->inst_offset) {
3735                                                 /* stack_offset is not dword aligned, so we need to make a copy */
3736                                                 sparc_ld_imm (code, sparc_fp, stack_offset, sparc_o7);
3737                                                 sparc_st_imm (code, sparc_o7, inst->inst_basereg, inst->inst_offset);
3738                                                 sparc_ld_imm (code, sparc_fp, stack_offset + 4, sparc_o7);
3739                                                 sparc_st_imm (code, sparc_o7, inst->inst_basereg, inst->inst_offset + 4);
3740                                         }
3741                                 }
3742                         else
3743                                 g_assert_not_reached ();
3744                 }
3745                 else
3746                         if ((ainfo->storage == ArgInIReg) && (inst->opcode != OP_REGVAR)) {
3747                                 /* Argument in register, but need to be saved to stack */
3748                                 if (!sparc_is_imm13 (stack_offset))
3749                                         NOT_IMPLEMENTED;
3750                                 if (stack_offset & 0x1)
3751                                         sparc_stb_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, stack_offset);
3752                                 else
3753                                         if (stack_offset & 0x2)
3754                                                 sparc_sth_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, stack_offset);
3755                                 else
3756                                         sparc_st_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, stack_offset);
3757                         }
3758                 else
3759                         if ((ainfo->storage == ArgInIRegPair) && (inst->opcode != OP_REGVAR)) {
3760                                 /* Argument in regpair, but need to be saved to stack */
3761                                 if (!sparc_is_imm13 (inst->inst_offset + 4))
3762                                         NOT_IMPLEMENTED;
3763                                 sparc_st_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, inst->inst_offset);
3764                                 sparc_st_imm (code, sparc_i0 + ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);                              
3765                         }
3766
3767                 if ((ainfo->storage == ArgInSplitRegStack) || (ainfo->storage == ArgOnStack))
3768                         if (inst->opcode == OP_REGVAR)
3769                                 /* FIXME: Load the argument into memory */
3770                                 NOT_IMPLEMENTED;
3771         }
3772
3773         g_free (cinfo);
3774
3775         if (cfg->method->save_lmf) {
3776                 gint32 lmf_offset = - cfg->arch.lmf_offset;
3777
3778                 /* Save ip */
3779                 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3780                 sparc_set (code, 0xfffffff, sparc_o7);
3781                 sparc_st_imm (code, sparc_o7, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ip));
3782                 /* Save sp */
3783                 sparc_st_imm (code, sparc_sp, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, sp));
3784                 /* Save fp */
3785                 sparc_st_imm (code, sparc_fp, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebp));
3786                 /* Save method */
3787                 /* FIXME: add a relocation for this */
3788                 sparc_set (code, cfg->method, sparc_o7);
3789                 sparc_st_imm (code, sparc_o7, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, method));
3790
3791                 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3792                                                          (gpointer)"mono_arch_get_lmf_addr");           
3793                 sparc_call_simple (code, 0);
3794                 sparc_nop (code);
3795
3796                 code = (guint32*)mono_sparc_emit_save_lmf ((guint32*)code, lmf_offset);
3797         }
3798
3799         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3800                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3801
3802         cfg->code_len = code - cfg->native_code;
3803
3804         g_assert (cfg->code_len <= cfg->code_size);
3805
3806         return code;
3807 }
3808
3809 void
3810 mono_arch_emit_epilog (MonoCompile *cfg)
3811 {
3812         MonoJumpInfo *patch_info;
3813         MonoMethod *method = cfg->method;
3814         guint8 *code;
3815
3816         code = cfg->native_code + cfg->code_len;
3817
3818         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3819                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3820
3821         if (cfg->method->save_lmf) {
3822                 gint32 lmf_offset = - cfg->arch.lmf_offset;
3823
3824                 code = mono_sparc_emit_restore_lmf (code, lmf_offset);
3825         }
3826
3827         /* 
3828          * The sparc ABI requires that calls to functions which return a structure
3829          * return to %i7+12
3830          */
3831         if (cfg->method->signature->pinvoke && MONO_TYPE_ISSTRUCT(cfg->method->signature->ret))
3832                 sparc_jmpl_imm (code, sparc_i7, 12, sparc_g0);
3833         else
3834                 sparc_ret (code);
3835         sparc_restore_imm (code, sparc_g0, 0, sparc_g0);
3836
3837         /* add code to raise exceptions */
3838         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3839                 switch (patch_info->type) {
3840                 case MONO_PATCH_INFO_EXC:
3841                         sparc_patch (cfg->native_code + patch_info->ip.i, code);
3842                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);
3843                         sparc_set (code, 0xffffff, sparc_o0);
3844                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_METHOD_REL, (gpointer)patch_info->ip.i);
3845                         sparc_set (code, 0xffffff, sparc_o1);
3846                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3847                         patch_info->data.name = "mono_arch_throw_exception_by_name";
3848                         patch_info->ip.i = code - cfg->native_code;
3849                         sparc_call_simple (code, 0);
3850                         sparc_nop (code);
3851                         break;
3852                 default:
3853                         /* do nothing */
3854                         break;
3855                 }
3856         }
3857
3858         cfg->code_len = code - cfg->native_code;
3859
3860         g_assert (cfg->code_len < cfg->code_size);
3861
3862 }
3863
3864 gboolean lmf_addr_key_inited = FALSE;
3865
3866 #ifdef MONO_SPARC_THR_TLS
3867 thread_key_t lmf_addr_key;
3868 #else
3869 pthread_key_t lmf_addr_key;
3870 #endif
3871
3872 gpointer
3873 mono_arch_get_lmf_addr (void)
3874 {
3875         /* This is perf critical so we bypass the IO layer */
3876         /* The thr_... functions seem to be somewhat faster */
3877 #ifdef MONO_SPARC_THR_TLS
3878         gpointer res;
3879         thr_getspecific (lmf_addr_key, &res);
3880         return res;
3881 #else
3882         return pthread_getspecific (lmf_addr_key);
3883 #endif
3884 }
3885
3886 void
3887 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3888 {
3889 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3890 #ifdef __linux__
3891         struct sigaltstack sa;
3892 #else
3893         stack_t         sigstk;
3894 #endif
3895  
3896         printf ("SIGALT!\n");
3897         /* Setup an alternate signal stack */
3898         tls->signal_stack = g_malloc (SIGNAL_STACK_SIZE);
3899         tls->signal_stack_size = SIGNAL_STACK_SIZE;
3900
3901 #ifdef __linux__
3902         sa.ss_sp = tls->signal_stack;
3903         sa.ss_size = SIGNAL_STACK_SIZE;
3904         sa.ss_flags = 0;
3905         g_assert (sigaltstack (&sa, NULL) == 0);
3906 #else
3907         sigstk.ss_sp = tls->signal_stack;
3908         sigstk.ss_size = SIGNAL_STACK_SIZE;
3909         sigstk.ss_flags = 0;
3910         g_assert (sigaltstack (&sigstk, NULL) == 0);
3911 #endif
3912 #endif
3913
3914         if (!lmf_addr_key_inited) {
3915                 int res;
3916
3917                 lmf_addr_key_inited = TRUE;
3918
3919 #ifdef MONO_SPARC_THR_TLS
3920                 res = thr_keycreate (&lmf_addr_key, NULL);
3921 #else
3922                 res = pthread_key_create (&lmf_addr_key, NULL);
3923 #endif
3924                 g_assert (res == 0);
3925
3926         }
3927
3928 #ifdef MONO_SPARC_THR_TLS
3929         thr_setspecific (lmf_addr_key, &tls->lmf);
3930 #else
3931         pthread_setspecific (lmf_addr_key, &tls->lmf);
3932 #endif
3933 }
3934
3935 void
3936 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3937 {
3938 }
3939
3940 void
3941 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3942 {
3943         /* add the this argument */
3944         if (this_reg != -1) {
3945                 MonoInst *this;
3946                 MONO_INST_NEW (cfg, this, OP_SETREG);
3947                 this->type = this_type;
3948                 this->sreg1 = this_reg;
3949                 this->dreg = sparc_o0;
3950                 mono_bblock_add_inst (cfg->cbb, this);
3951         }
3952
3953         if (vt_reg != -1) {
3954                 /* Set the 'struct/union return pointer' location on the stack */
3955                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, sparc_sp, 64, vt_reg);
3956         }
3957 }
3958
3959
3960 gint
3961 mono_arch_get_opcode_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3962 {
3963         return -1;
3964 }
3965
3966 /*
3967  * mono_arch_get_argument_info:
3968  * @csig:  a method signature
3969  * @param_count: the number of parameters to consider
3970  * @arg_info: an array to store the result infos
3971  *
3972  * Gathers information on parameters such as size, alignment and
3973  * padding. arg_info should be large enought to hold param_count + 1 entries. 
3974  *
3975  * Returns the size of the activation frame.
3976  */
3977 int
3978 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
3979 {
3980         int k, align;
3981         CallInfo *cinfo;
3982         ArgInfo *ainfo;
3983
3984         cinfo = get_call_info (csig, FALSE);
3985
3986         if (csig->hasthis) {
3987                 ainfo = &cinfo->args [0];
3988                 arg_info [0].offset = 68 + ainfo->offset;
3989         }
3990
3991         for (k = 0; k < param_count; k++) {
3992                 ainfo = &cinfo->args [k + csig->hasthis];
3993
3994                 arg_info [k + 1].offset = 68 + ainfo->offset;
3995                 arg_info [k + 1].size = mono_type_size (csig->params [k], &align);
3996         }
3997
3998         g_free (cinfo);
3999
4000         /* FIXME: */
4001         return 0;
4002 }
4003
4004 gboolean
4005 mono_arch_print_tree (MonoInst *tree, int arity)
4006 {
4007         return 0;
4008 }