This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[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
2550                 switch (ins->opcode) {
2551                 case OP_STOREI1_MEMBASE_IMM:
2552                         EMIT_STORE_MEMBASE_IMM (ins, stb);
2553                         break;
2554                 case OP_STOREI2_MEMBASE_IMM:
2555                         EMIT_STORE_MEMBASE_IMM (ins, sth);
2556                         break;
2557                 case OP_STORE_MEMBASE_IMM:
2558                 case OP_STOREI4_MEMBASE_IMM:
2559                         EMIT_STORE_MEMBASE_IMM (ins, st);
2560                         break;
2561                 case OP_STOREI8_MEMBASE_IMM:
2562                         /* Only generated by peephole opts */
2563                         g_assert ((ins->inst_offset % 8) == 0);
2564                         g_assert (ins->inst_imm == 0);
2565                         EMIT_STORE_MEMBASE_IMM (ins, stx);
2566                         break;
2567                 case OP_STOREI1_MEMBASE_REG:
2568                         EMIT_STORE_MEMBASE_REG (ins, stb);
2569                         break;
2570                 case OP_STOREI2_MEMBASE_REG:
2571                         EMIT_STORE_MEMBASE_REG (ins, sth);
2572                         break;
2573                 case OP_STORE_MEMBASE_REG:
2574                 case OP_STOREI4_MEMBASE_REG:
2575                         EMIT_STORE_MEMBASE_REG (ins, st);
2576                         break;
2577                 case OP_STOREI8_MEMBASE_REG:
2578                         /* Only used by OP_MEMSET */
2579                         EMIT_STORE_MEMBASE_REG (ins, std);
2580                         break;
2581                 case CEE_LDIND_I:
2582                 case CEE_LDIND_I4:
2583                 case CEE_LDIND_U4:
2584                         sparc_ld (code, ins->inst_p0, sparc_g0, ins->dreg);
2585                         break;
2586                 /* The cast IS BAD (maybe).  But it needs to be done... */
2587                 case OP_LOADU4_MEM:
2588                         sparc_set (code, (guint)ins->inst_p0, ins->dreg);
2589                         sparc_ld (code, ins->dreg, sparc_g0, ins->dreg);
2590                         break;
2591                 case OP_LOAD_MEMBASE:
2592                 case OP_LOADI4_MEMBASE:
2593                 case OP_LOADU4_MEMBASE:
2594                         EMIT_LOAD_MEMBASE (ins, ld);
2595                         break;
2596                 case OP_LOADU1_MEMBASE:
2597                         EMIT_LOAD_MEMBASE (ins, ldub);
2598                         break;
2599                 case OP_LOADI1_MEMBASE:
2600                         EMIT_LOAD_MEMBASE (ins, ldsb);
2601                         break;
2602                 case OP_LOADU2_MEMBASE:
2603                         EMIT_LOAD_MEMBASE (ins, lduh);
2604                         break;
2605                 case OP_LOADI2_MEMBASE:
2606                         EMIT_LOAD_MEMBASE (ins, ldsh);
2607                         break;
2608                 case CEE_CONV_I1:
2609                         sparc_sll_imm (code, ins->sreg1, 24, sparc_o7);
2610                         sparc_sra_imm (code, sparc_o7, 24, ins->dreg);
2611                         break;
2612                 case CEE_CONV_I2:
2613                         sparc_sll_imm (code, ins->sreg1, 16, sparc_o7);
2614                         sparc_sra_imm (code, sparc_o7, 16, ins->dreg);
2615                         break;
2616                 /* GCC does this one differently.  Don't ask me WHY. */
2617                 case CEE_CONV_U1:
2618                         sparc_and_imm (code, FALSE, ins->sreg1, 0xff, ins->dreg);
2619                         break;
2620                 case CEE_CONV_U2:
2621                         sparc_sll_imm (code, ins->sreg1, 16, sparc_o7);
2622                         sparc_srl_imm (code, sparc_o7, 16, ins->dreg);
2623                         break;
2624                 case OP_COMPARE:
2625                         sparc_cmp (code, ins->sreg1, ins->sreg2);
2626                         break;
2627                 case OP_COMPARE_IMM:
2628                         if (sparc_is_imm13 (ins->inst_imm))
2629                                 sparc_cmp_imm (code, ins->sreg1, ins->inst_imm);
2630                         else {
2631                                 sparc_set (code, ins->inst_imm, sparc_o7);
2632                                 sparc_cmp (code, ins->sreg1, sparc_o7);
2633                         }
2634                         break;
2635                 case OP_X86_TEST_NULL:
2636                         sparc_cmp_imm (code, ins->sreg1, 0);
2637                         break;
2638                 case CEE_BREAK:
2639                         /*
2640                          * gdb does not like encountering 'ta 1' in the debugged code. So 
2641                          * instead of emitting a trap, we emit a call a C function and place a 
2642                          * breakpoint there.
2643                          */
2644                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, mono_sparc_break);
2645                         sparc_call_simple (code, 0);
2646                         sparc_nop (code);
2647                         break;
2648                 case OP_ADDCC:
2649                         sparc_add (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
2650                         break;
2651                 case CEE_ADD:
2652                         sparc_add (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2653                         break;
2654                 case OP_ADD_IMM:
2655                         /* according to inssel-long32.brg, this should set cc */
2656                         EMIT_ALU_IMM (ins, add, TRUE);
2657                         break;
2658                 case OP_ADC:
2659                         /* according to inssel-long32.brg, this should set cc */
2660                         sparc_addx (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
2661                         break;
2662                 case OP_ADC_IMM:
2663                         EMIT_ALU_IMM (ins, addx, TRUE);
2664                         break;
2665                 case OP_SUBCC:
2666                         sparc_sub (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
2667                         break;
2668                 case CEE_SUB:
2669                         sparc_sub (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2670                         break;
2671                 case OP_SUB_IMM:
2672                         /* according to inssel-long32.brg, this should set cc */
2673                         EMIT_ALU_IMM (ins, sub, TRUE);
2674                         break;
2675                 case OP_SBB:
2676                         /* according to inssel-long32.brg, this should set cc */
2677                         sparc_subx (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
2678                         break;
2679                 case OP_SBB_IMM:
2680                         EMIT_ALU_IMM (ins, subx, TRUE);
2681                         break;
2682                 case CEE_AND:
2683                         sparc_and (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2684                         break;
2685                 case OP_AND_IMM:
2686                         EMIT_ALU_IMM (ins, and, FALSE);
2687                         break;
2688                 case CEE_DIV:
2689                         /* Sign extend sreg1 into %y */
2690                         sparc_sra_imm (code, ins->sreg1, 31, sparc_o7);
2691                         sparc_wry (code, sparc_o7, sparc_g0);
2692                         sparc_sdiv (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
2693                         EMIT_COND_SYSTEM_EXCEPTION (code, sparc_boverflow, "ArithmeticException");
2694                         break;
2695                 case CEE_DIV_UN:
2696                         sparc_wry (code, sparc_g0, sparc_g0);
2697                         sparc_udiv (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2698                         break;
2699                 case OP_DIV_IMM: {
2700                         int i, imm;
2701
2702                         /* Transform division into a shift */
2703                         for (i = 1; i < 30; ++i) {
2704                                 imm = (1 << i);
2705                                 if (ins->inst_imm == imm)
2706                                         break;
2707                         }
2708                         if (i < 30) {
2709                                 if (i == 1) {
2710                                         /* gcc 2.95.3 */
2711                                         sparc_srl_imm (code, ins->sreg1, 31, sparc_o7);
2712                                         sparc_add (code, FALSE, ins->sreg1, sparc_o7, ins->dreg);
2713                                         sparc_sra_imm (code, ins->dreg, 1, ins->dreg);
2714                                 }
2715                                 else {
2716                                         /* http://compilers.iecc.com/comparch/article/93-04-079 */
2717                                         sparc_sra_imm (code, ins->sreg1, 31, sparc_o7);
2718                                         sparc_srl_imm (code, sparc_o7, 32 - i, sparc_o7);
2719                                         sparc_add (code, FALSE, ins->sreg1, sparc_o7, ins->dreg);
2720                                         sparc_sra_imm (code, ins->dreg, i, ins->dreg);
2721                                 }
2722                         }
2723                         else {
2724                                 /* Sign extend sreg1 into %y */
2725                                 sparc_sra_imm (code, ins->sreg1, 31, sparc_o7);
2726                                 sparc_wry (code, sparc_o7, sparc_g0);
2727                                 EMIT_ALU_IMM (ins, sdiv, TRUE);
2728                                 EMIT_COND_SYSTEM_EXCEPTION (code, sparc_boverflow, "ArithmeticException");
2729                         }
2730                         break;
2731                 }
2732                 case CEE_REM:
2733                         /* Sign extend sreg1 into %y */
2734                         sparc_sra_imm (code, ins->sreg1, 31, sparc_o7);
2735                         sparc_wry (code, sparc_o7, sparc_g0);
2736                         sparc_sdiv (code, TRUE, ins->sreg1, ins->sreg2, sparc_o7);
2737                         EMIT_COND_SYSTEM_EXCEPTION (code, sparc_boverflow, "ArithmeticException");
2738                         sparc_smul (code, FALSE, ins->sreg2, sparc_o7, sparc_o7);
2739                         sparc_sub (code, FALSE, ins->sreg1, sparc_o7, ins->dreg);
2740                         break;
2741                 case CEE_REM_UN:
2742                         sparc_wry (code, sparc_g0, sparc_g0);
2743                         sparc_udiv (code, FALSE, ins->sreg1, ins->sreg2, sparc_o7);
2744                         sparc_umul (code, FALSE, ins->sreg2, sparc_o7, sparc_o7);
2745                         sparc_sub (code, FALSE, ins->sreg1, sparc_o7, ins->dreg);
2746                         break;
2747                 case OP_REM_IMM:
2748                         /* Sign extend sreg1 into %y */
2749                         sparc_sra_imm (code, ins->sreg1, 31, sparc_o7);
2750                         sparc_wry (code, sparc_o7, sparc_g0);
2751                         if (!sparc_is_imm13 (ins->inst_imm)) {
2752                                 sparc_set (code, ins->inst_imm, sparc_g1);
2753                                 sparc_sdiv (code, TRUE, ins->sreg1, sparc_g1, sparc_o7);
2754                                 EMIT_COND_SYSTEM_EXCEPTION (code, sparc_boverflow, "ArithmeticException");
2755                                 sparc_smul (code, FALSE, sparc_o7, sparc_g1, sparc_o7);
2756                         }
2757                         else {
2758                                 sparc_sdiv_imm (code, TRUE, ins->sreg1, ins->inst_imm, sparc_o7);
2759                                 EMIT_COND_SYSTEM_EXCEPTION (code, sparc_boverflow, "ArithmeticException");
2760                                 sparc_smul_imm (code, FALSE, sparc_o7, ins->inst_imm, sparc_o7);
2761                         }
2762                         sparc_sub (code, FALSE, ins->sreg1, sparc_o7, ins->dreg);
2763                         break;
2764                 case CEE_OR:
2765                         sparc_or (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2766                         break;
2767                 case OP_OR_IMM:
2768                         EMIT_ALU_IMM (ins, or, FALSE);
2769                         break;
2770                 case CEE_XOR:
2771                         sparc_xor (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2772                         break;
2773                 case OP_XOR_IMM:
2774                         EMIT_ALU_IMM (ins, xor, FALSE);
2775                         break;
2776                 case CEE_SHL:
2777                         sparc_sll (code, ins->sreg1, ins->sreg2, ins->dreg);
2778                         break;
2779                 case OP_SHL_IMM:
2780                         if (sparc_is_imm13 (ins->inst_imm))
2781                                 sparc_sll_imm (code, ins->sreg1, ins->inst_imm, ins->dreg);
2782                         else {
2783                                 sparc_set (code, ins->inst_imm, sparc_o7);
2784                                 sparc_sll (code, ins->sreg1, sparc_o7, ins->dreg);
2785                         }
2786                         break;
2787                 case CEE_SHR:
2788                         sparc_sra (code, ins->sreg1, ins->sreg2, ins->dreg);
2789                         break;
2790                 case OP_SHR_IMM:
2791                         if (sparc_is_imm13 (ins->inst_imm))
2792                                 sparc_sra_imm (code, ins->sreg1, ins->inst_imm, ins->dreg);
2793                         else {
2794                                 sparc_set (code, ins->inst_imm, sparc_o7);
2795                                 sparc_sra (code, ins->sreg1, sparc_o7, ins->dreg);
2796                         }
2797                         break;
2798                 case OP_SHR_UN_IMM:
2799                         if (sparc_is_imm13 (ins->inst_imm))
2800                                 sparc_srl_imm (code, ins->sreg1, ins->inst_imm, ins->dreg);
2801                         else {
2802                                 sparc_set (code, ins->inst_imm, sparc_o7);
2803                                 sparc_srl (code, ins->sreg1, sparc_o7, ins->dreg);
2804                         }
2805                         break;
2806                 case CEE_SHR_UN:
2807                         sparc_srl (code, ins->sreg1, ins->sreg2, ins->dreg);
2808                         break;
2809                 case CEE_NOT:
2810                         /* can't use sparc_not */
2811                         sparc_xnor (code, FALSE, ins->sreg1, sparc_g0, ins->dreg);
2812                         break;
2813                 case CEE_NEG:
2814                         /* can't use sparc_neg */
2815                         sparc_sub (code, FALSE, sparc_g0, ins->sreg1, ins->dreg);
2816                         break;
2817                 case CEE_MUL:
2818                         sparc_smul (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2819                         break;
2820                 case OP_MUL_IMM: {
2821                         int i, imm;
2822
2823                         /* Transform multiplication into a shift */
2824                         for (i = 1; i < 30; ++i) {
2825                                 imm = (1 << i);
2826                                 if (ins->inst_imm == imm)
2827                                         break;
2828                         }
2829                         if (i < 30)
2830                                 sparc_sll_imm (code, ins->sreg1, i, ins->dreg);
2831                         else
2832                                 EMIT_ALU_IMM (ins, smul, FALSE);
2833                         break;
2834                 }
2835                 case CEE_MUL_OVF:
2836                         sparc_smul (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
2837                         sparc_rdy (code, sparc_g1);
2838                         sparc_sra_imm (code, ins->dreg, 31, sparc_o7);
2839                         sparc_cmp (code, sparc_g1, sparc_o7);
2840                         EMIT_COND_SYSTEM_EXCEPTION (ins, sparc_bne, "OverflowException");
2841                         break;
2842                 case CEE_MUL_OVF_UN:
2843                         sparc_umul (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
2844                         sparc_rdy (code, sparc_o7);
2845                         sparc_cmp (code, sparc_o7, sparc_g0);
2846                         EMIT_COND_SYSTEM_EXCEPTION (ins, sparc_bne, "OverflowException");
2847                         break;
2848                 case OP_ICONST:
2849                 case OP_SETREGIMM:
2850                         sparc_set (code, ins->inst_c0, ins->dreg);
2851                         break;
2852                 case OP_AOTCONST:
2853                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2854                         sparc_set (code, 0xffffff, ins->dreg);
2855                         break;
2856                 case CEE_CONV_I4:
2857                 case CEE_CONV_U4:
2858                 case OP_MOVE:
2859                 case OP_SETREG:
2860                         if (ins->sreg1 != ins->dreg)
2861                                 sparc_mov_reg_reg (code, ins->sreg1, ins->dreg);
2862                         break;
2863                 case CEE_JMP:
2864                         if (cfg->method->save_lmf)
2865                                 NOT_IMPLEMENTED;
2866
2867                         code = emit_load_volatile_arguments (cfg, code);
2868                         mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2869                         sparc_set (code, 0xffffff, sparc_o7);
2870                         sparc_jmpl (code, sparc_o7, sparc_g0, sparc_g0);
2871                         /* Restore parent frame in delay slot */
2872                         sparc_restore_imm (code, sparc_g0, 0, sparc_g0);
2873                         break;
2874                 case OP_CHECK_THIS:
2875                         /* ensure ins->sreg1 is not NULL */
2876                         sparc_ld_imm (code, ins->sreg1, 0, sparc_g0);
2877                         break;
2878                 case OP_ARGLIST:
2879                         sparc_add_imm (code, FALSE, sparc_fp, cfg->sig_cookie, sparc_o7);
2880                         sparc_st_imm (code, sparc_o7, ins->sreg1, 0);
2881                         break;
2882                 case OP_FCALL:
2883                 case OP_LCALL:
2884                 case OP_VCALL:
2885                 case OP_VOIDCALL:
2886                 case CEE_CALL:
2887                         call = (MonoCallInst*)ins;
2888                         g_assert (!call->virtual);
2889                         code = emit_save_sp_to_lmf (cfg, code);
2890                         if (ins->flags & MONO_INST_HAS_METHOD)
2891                                 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_METHOD, call->method);
2892                         else
2893                                 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_ABS, call->fptr);
2894                         sparc_call_simple (code, 0);
2895                         sparc_nop (code);
2896
2897                         code = emit_vret_token (ins, code);
2898                         code = emit_move_return_value (ins, code);
2899                         break;
2900                 case OP_FCALL_REG:
2901                 case OP_LCALL_REG:
2902                 case OP_VCALL_REG:
2903                 case OP_VOIDCALL_REG:
2904                 case OP_CALL_REG:
2905                         call = (MonoCallInst*)ins;
2906                         code = emit_save_sp_to_lmf (cfg, code);
2907                         sparc_jmpl (code, ins->sreg1, sparc_g0, sparc_callsite);
2908                         /*
2909                          * We emit a special kind of nop in the delay slot to tell the 
2910                          * trampoline code that this is a virtual call, thus an unbox
2911                          * trampoline might need to be called.
2912                          */
2913                         if (call->virtual)
2914                                 sparc_or_imm (code, FALSE, sparc_g0, 0xca, sparc_g0);
2915                         else
2916                                 sparc_nop (code);
2917
2918                         code = emit_vret_token (ins, code);
2919                         code = emit_move_return_value (ins, code);
2920                         break;
2921                 case OP_FCALL_MEMBASE:
2922                 case OP_LCALL_MEMBASE:
2923                 case OP_VCALL_MEMBASE:
2924                 case OP_VOIDCALL_MEMBASE:
2925                 case OP_CALL_MEMBASE:
2926                         call = (MonoCallInst*)ins;
2927                         g_assert (sparc_is_imm13 (ins->inst_offset));
2928                         code = emit_save_sp_to_lmf (cfg, code);
2929                         sparc_ld_imm (code, ins->inst_basereg, ins->inst_offset, sparc_o7);
2930                         sparc_jmpl (code, sparc_o7, sparc_g0, sparc_callsite);
2931                         if (call->virtual)
2932                                 sparc_or_imm (code, FALSE, sparc_g0, 0xca, sparc_g0);
2933                         else
2934                                 sparc_nop (code);
2935
2936                         code = emit_vret_token (ins, code);
2937                         code = emit_move_return_value (ins, code);
2938                         break;
2939                 case OP_SETFRET:
2940                         if (cfg->method->signature->ret->type == MONO_TYPE_R4)
2941                                 sparc_fdtos (code, ins->sreg1, sparc_f0);
2942                         else {
2943                                 sparc_fmovs (code, ins->sreg1, ins->dreg);
2944                                 sparc_fmovs (code, ins->sreg1 + 1, ins->dreg + 1);
2945                         }
2946                         break;
2947                 case OP_OUTARG:
2948                         g_assert_not_reached ();
2949                         break;
2950                 case OP_LOCALLOC:
2951                         /* Keep alignment */
2952                         sparc_add_imm (code, FALSE, ins->sreg1, MONO_ARCH_FRAME_ALIGNMENT - 1, ins->dreg);
2953                         sparc_set (code, ~(MONO_ARCH_FRAME_ALIGNMENT - 1), sparc_o7);
2954                         sparc_and (code, FALSE, ins->dreg, sparc_o7, ins->dreg);
2955                         sparc_sub (code, FALSE, sparc_sp, ins->dreg, ins->dreg);
2956                         /* Keep %sp valid at all times */
2957                         sparc_mov_reg_reg (code, ins->dreg, sparc_sp);
2958                         g_assert (sparc_is_imm13 (cfg->arch.localloc_offset));
2959                         sparc_add_imm (code, FALSE, ins->dreg, cfg->arch.localloc_offset, ins->dreg);
2960                         break;
2961                 case OP_SPARC_LOCALLOC_IMM: {
2962                         guint32 offset = ins->inst_c0;
2963                         offset = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
2964                         if (sparc_is_imm13 (offset))
2965                                 sparc_sub_imm (code, FALSE, sparc_sp, offset, sparc_sp);
2966                         else {
2967                                 sparc_set (code, offset, sparc_o7);
2968                                 sparc_sub (code, FALSE, sparc_sp, sparc_o7, sparc_sp);
2969                         }
2970                         sparc_mov_reg_reg (code, sparc_sp, ins->dreg);
2971                         g_assert (sparc_is_imm13 (cfg->arch.localloc_offset));
2972                         sparc_add_imm (code, FALSE, ins->dreg, cfg->arch.localloc_offset, ins->dreg);
2973                         break;
2974                 }
2975                 case CEE_RET:
2976                         /* The return is done in the epilog */
2977                         g_assert_not_reached ();
2978                         break;
2979                 case CEE_THROW:
2980                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_INTERNAL_METHOD, 
2981                                              (gpointer)"mono_arch_throw_exception");
2982                         sparc_call_simple (code, 0);
2983                         /* Delay slot */
2984                         sparc_mov_reg_reg (code, ins->sreg1, sparc_o0);
2985                         break;
2986                 case OP_START_HANDLER: {
2987                         /*
2988                          * The START_HANDLER instruction marks the beginning of a handler 
2989                          * block. It is called using a call instruction, so %o7 contains 
2990                          * the return address. Since the handler executes in the same stack
2991              * frame as the method itself, we can't use save/restore to save 
2992                          * the return address. Instead, we save it into a dedicated 
2993                          * variable.
2994                          */
2995                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
2996                         if (!sparc_is_imm13 (spvar->inst_offset)) {
2997                                 sparc_set (code, spvar->inst_offset, sparc_g0);
2998                                 sparc_st (code, sparc_o7, spvar->inst_basereg, sparc_g0);
2999                         }
3000                         else
3001                                 sparc_st_imm (code, sparc_o7, spvar->inst_basereg, spvar->inst_offset);
3002                         break;
3003                 }
3004                 case OP_ENDFILTER: {
3005                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3006                         if (!sparc_is_imm13 (spvar->inst_offset)) {
3007                                 sparc_set (code, spvar->inst_offset, sparc_g0);
3008                                 sparc_ld (code, spvar->inst_basereg, sparc_g0, sparc_o7);
3009                         }
3010                         else
3011                                 sparc_ld_imm (code, spvar->inst_basereg, spvar->inst_offset, sparc_o7);
3012                         sparc_jmpl_imm (code, sparc_o7, 8, sparc_g0);
3013                         /* Delay slot */
3014                         sparc_mov_reg_reg (code, ins->sreg1, sparc_o0);
3015                         break;
3016                 }
3017                 case CEE_ENDFINALLY: {
3018                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3019                         if (!sparc_is_imm13 (spvar->inst_offset)) {
3020                                 sparc_set (code, spvar->inst_offset, sparc_g0);
3021                                 sparc_ld (code, spvar->inst_basereg, sparc_g0, sparc_o7);
3022                         }
3023                         else
3024                                 sparc_ld_imm (code, spvar->inst_basereg, spvar->inst_offset, sparc_o7);
3025                         sparc_jmpl_imm (code, sparc_o7, 8, sparc_g0);
3026                         sparc_nop (code);
3027                         break;
3028                 }
3029                 case OP_CALL_HANDLER: 
3030                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3031                         sparc_call_simple (code, 0);
3032                         sparc_nop (code);
3033                         break;
3034                 case OP_LABEL:
3035                         ins->inst_c0 = (guint8*)code - cfg->native_code;
3036                         break;
3037                 case CEE_BR:
3038                         //g_print ("target: %p, next: %p, curr: %p, last: %p\n", ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
3039                         if ((ins->inst_target_bb == bb->next_bb) && ins == bb->last_ins)
3040                                 break;
3041                         if (ins->flags & MONO_INST_BRLABEL) {
3042                                 if (ins->inst_i0->inst_c0) {
3043                                         gint32 disp = (ins->inst_i0->inst_c0 - ((guint8*)code - cfg->native_code)) >> 2;
3044                                         g_assert (sparc_is_imm22 (disp));
3045                                         sparc_branch (code, 1, sparc_ba, disp);
3046                                 } else {
3047                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3048                                         sparc_branch (code, 1, sparc_ba, 0);
3049                                 }
3050                         } else {
3051                                 if (ins->inst_target_bb->native_offset) {
3052                                         gint32 disp = (ins->inst_target_bb->native_offset - ((guint8*)code - cfg->native_code)) >> 2;
3053                                         g_assert (sparc_is_imm22 (disp));
3054                                         sparc_branch (code, 1, sparc_ba, disp);
3055                                 } else {
3056                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3057                                         sparc_branch (code, 1, sparc_ba, 0);
3058                                 } 
3059                         }
3060                         sparc_nop (code);
3061                         break;
3062                 case OP_BR_REG:
3063                         sparc_jmp (code, ins->sreg1, sparc_g0);
3064                         sparc_nop (code);
3065                         break;
3066                 case OP_CEQ:
3067                 case OP_CLT:
3068                 case OP_CLT_UN:
3069                 case OP_CGT:
3070                 case OP_CGT_UN:
3071                         //if (cfg->opt & MONO_OPT_CMOV) {
3072                         if (0) {
3073                                 sparc_clr_reg (code, ins->dreg);
3074                                 sparc_movcc_imm (code, sparc_icc, opcode_to_sparc_cond (ins->opcode), 1, ins->dreg);
3075                         }
3076                         else {
3077                                 sparc_clr_reg (code, ins->dreg);
3078                                 sparc_branch (code, 1, opcode_to_sparc_cond (ins->opcode), 2);
3079                                 /* delay slot */
3080                                 sparc_set (code, 1, ins->dreg);
3081                         }
3082                         break;
3083                 case OP_COND_EXC_EQ:
3084                 case OP_COND_EXC_NE_UN:
3085                 case OP_COND_EXC_LT:
3086                 case OP_COND_EXC_LT_UN:
3087                 case OP_COND_EXC_GT:
3088                 case OP_COND_EXC_GT_UN:
3089                 case OP_COND_EXC_GE:
3090                 case OP_COND_EXC_GE_UN:
3091                 case OP_COND_EXC_LE:
3092                 case OP_COND_EXC_LE_UN:
3093                 case OP_COND_EXC_OV:
3094                 case OP_COND_EXC_NO:
3095                 case OP_COND_EXC_C:
3096                 case OP_COND_EXC_NC:
3097                         EMIT_COND_SYSTEM_EXCEPTION (ins, opcode_to_sparc_cond (ins->opcode), ins->inst_p1);
3098                         break;
3099                 case CEE_BEQ:
3100                 case CEE_BNE_UN:
3101                 case CEE_BLT:
3102                 case CEE_BLT_UN:
3103                 case CEE_BGT:
3104                 case CEE_BGT_UN:
3105                 case CEE_BGE:
3106                 case CEE_BGE_UN:
3107                 case CEE_BLE:
3108                 case CEE_BLE_UN: {
3109                         if (sparcv9)
3110                                 EMIT_COND_BRANCH_PREDICTED (ins, opcode_to_sparc_cond (ins->opcode), 1, 1);
3111                         else
3112                                 EMIT_COND_BRANCH (ins, opcode_to_sparc_cond (ins->opcode), 1, 1);
3113                         break;
3114                 }
3115                 case OP_SPARC_BRZ:
3116                         /* We misuse the macro arguments */
3117                         EMIT_COND_BRANCH_BPR (ins, brz, 1, 1, 1);
3118                         break;
3119                 case OP_SPARC_BRLEZ:
3120                         EMIT_COND_BRANCH_BPR (ins, brlez, 1, 1, 1);
3121                         break;
3122                 case OP_SPARC_BRLZ:
3123                         EMIT_COND_BRANCH_BPR (ins, brlz, 1, 1, 1);
3124                         break;
3125                 case OP_SPARC_BRNZ:
3126                         EMIT_COND_BRANCH_BPR (ins, brnz, 1, 1, 1);
3127                         break;
3128                 case OP_SPARC_BRGZ:
3129                         EMIT_COND_BRANCH_BPR (ins, brgz, 1, 1, 1);
3130                         break;
3131                 case OP_SPARC_BRGEZ:
3132                         EMIT_COND_BRANCH_BPR (ins, brgez, 1, 1, 1);
3133                         break;
3134
3135                 /* floating point opcodes */
3136                 case OP_R8CONST:
3137                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R8, ins->inst_p0);
3138                         sparc_sethi (code, 0, sparc_o7);
3139                         sparc_lddf_imm (code, sparc_o7, 0, ins->dreg);
3140                         break;
3141                 case OP_R4CONST:
3142                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R4, ins->inst_p0);
3143                         sparc_sethi (code, 0, sparc_o7);
3144                         sparc_ldf_imm (code, sparc_o7, 0, ins->dreg);
3145
3146                         /* Extend to double */
3147                         sparc_fstod (code, ins->dreg, ins->dreg);
3148                         break;
3149                 case OP_STORER8_MEMBASE_REG:
3150                         if (!sparc_is_imm13 (ins->inst_offset + 4)) {
3151                                 sparc_set (code, ins->inst_offset, sparc_o7);
3152                                 if (ins->inst_offset % 8) {
3153                                         /* Misaligned */
3154                                         sparc_add (code, FALSE, ins->inst_destbasereg, sparc_o7, sparc_o7);
3155                                         sparc_stf (code, ins->sreg1, sparc_o7, sparc_g0);
3156                                         sparc_stf_imm (code, ins->sreg1 + 1, sparc_o7, 4);
3157                                 } else
3158                                         sparc_stdf (code, ins->sreg1, ins->inst_destbasereg, sparc_o7);
3159                         }
3160                         else {
3161                                 if (ins->inst_offset % 8) {
3162                                         /* Misaligned */
3163                                         sparc_stf_imm (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3164                                         sparc_stf_imm (code, ins->sreg1 + 1, ins->inst_destbasereg, ins->inst_offset + 4);
3165                                 } else
3166                                         sparc_stdf_imm (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3167                         }
3168                         break;
3169                 case OP_LOADR8_MEMBASE:
3170                         g_assert ((ins->inst_offset % 8) == 0);
3171                         EMIT_LOAD_MEMBASE (ins, lddf);
3172                         break;
3173                 case OP_STORER4_MEMBASE_REG:
3174                         /* This requires a double->single conversion */
3175                         sparc_fdtos (code, ins->sreg1, sparc_f0);
3176                         if (!sparc_is_imm13 (ins->inst_offset)) {
3177                                 sparc_set (code, ins->inst_offset, sparc_o7);
3178                                 sparc_stf (code, sparc_f0, ins->inst_destbasereg, sparc_o7);
3179                         }
3180                         else
3181                                 sparc_stf_imm (code, sparc_f0, ins->inst_destbasereg, ins->inst_offset);
3182                         break;
3183                 case OP_LOADR4_MEMBASE:
3184                         EMIT_LOAD_MEMBASE (ins, ldf);
3185                         /* Extend to double */
3186                         sparc_fstod (code, ins->dreg, ins->dreg);
3187                         break;
3188                 case OP_FMOVE:
3189                         sparc_fmovs (code, ins->sreg1, ins->dreg);
3190                         sparc_fmovs (code, ins->sreg1 + 1, ins->dreg + 1);
3191                         break;
3192                 case CEE_CONV_R4: {
3193                         guint32 offset = mono_spillvar_offset_float (cfg, 0);
3194                         if (!sparc_is_imm13 (offset))
3195                                 NOT_IMPLEMENTED;
3196                         sparc_st_imm (code, ins->sreg1, sparc_sp, offset);
3197                         sparc_ldf_imm (code, sparc_sp, offset, sparc_f0);
3198                         sparc_fitos (code, sparc_f0, sparc_f0);
3199                         sparc_fstod (code, sparc_f0, ins->dreg);
3200                         break;
3201                 }
3202                 case CEE_CONV_R8: {
3203                         guint32 offset = mono_spillvar_offset_float (cfg, 0);
3204                         if (!sparc_is_imm13 (offset))
3205                                 NOT_IMPLEMENTED;
3206                         sparc_st_imm (code, ins->sreg1, sparc_sp, offset);
3207                         sparc_ldf_imm (code, sparc_sp, offset, sparc_f0);
3208                         sparc_fitod (code, sparc_f0, ins->dreg);
3209                         break;
3210                 }
3211                 case OP_FCONV_TO_I1:
3212                 case OP_FCONV_TO_U1:
3213                 case OP_FCONV_TO_I2:
3214                 case OP_FCONV_TO_U2:
3215                 case OP_FCONV_TO_I4:
3216                 case OP_FCONV_TO_I:
3217                 case OP_FCONV_TO_U4:
3218                 case OP_FCONV_TO_U: {
3219                         guint32 offset = mono_spillvar_offset_float (cfg, 0);
3220                         if (!sparc_is_imm13 (offset))
3221                                 NOT_IMPLEMENTED;
3222                         /* FIXME: Is having the same code for all of these ok ? */
3223                         sparc_fdtoi (code, ins->sreg1, sparc_f0);
3224                         sparc_stdf_imm (code, sparc_f0, sparc_sp, offset);
3225                         sparc_ld_imm (code, sparc_sp, offset, ins->dreg);
3226                         break;
3227                 }
3228                 case OP_FCONV_TO_I8:
3229                 case OP_FCONV_TO_U8:
3230                         /* Emulated */
3231                         g_assert_not_reached ();
3232                         break;
3233                 case CEE_CONV_R_UN:
3234                         /* Emulated */
3235                         g_assert_not_reached ();
3236                         break;
3237                 case OP_LCONV_TO_R_UN: { 
3238                         /* Emulated */
3239                         g_assert_not_reached ();
3240                         break;
3241                 }
3242                 case OP_LCONV_TO_OVF_I: {
3243                         guint32 *br [3], *label [1];
3244
3245                         /* 
3246                          * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
3247                          */
3248                         sparc_cmp_imm (code, ins->sreg1, 0);
3249                         br [0] = code; 
3250                         sparc_branch (code, 1, sparc_bneg, 0);
3251                         sparc_nop (code);
3252
3253                         /* positive */
3254                         /* ms word must be 0 */
3255                         sparc_cmp_imm (code, ins->sreg2, 0);
3256                         br [1] = code;
3257                         sparc_branch (code, 1, sparc_be, 0);
3258                         sparc_nop (code);
3259
3260                         label [0] = code;
3261
3262                         EMIT_COND_SYSTEM_EXCEPTION (ins, sparc_ba, "OverflowException");
3263
3264                         /* negative */
3265                         sparc_patch (br [0], code);
3266
3267                         /* ms word must 0xfffffff */
3268                         sparc_cmp_imm (code, ins->sreg2, -1);
3269                         br [2] = code;
3270                         sparc_branch (code, 1, sparc_bne, 0);
3271                         sparc_patch (br [2], label [0]);
3272
3273                         /* Ok */
3274                         sparc_patch (br [1], code);
3275                         if (ins->sreg1 != ins->dreg)
3276                                 sparc_mov_reg_reg (code, ins->sreg1, ins->dreg);
3277                         break;
3278                 }
3279                 case OP_FADD:
3280                         sparc_faddd (code, ins->sreg1, ins->sreg2, ins->dreg);
3281                         break;
3282                 case OP_FSUB:
3283                         sparc_fsubd (code, ins->sreg1, ins->sreg2, ins->dreg);
3284                         break;          
3285                 case OP_FMUL:
3286                         sparc_fmuld (code, ins->sreg1, ins->sreg2, ins->dreg);
3287                         break;          
3288                 case OP_FDIV:
3289                         sparc_fdivd (code, ins->sreg1, ins->sreg2, ins->dreg);
3290                         break;          
3291                 case OP_FNEG:
3292                         sparc_fnegs (code, ins->sreg1, ins->dreg);
3293                         break;          
3294                 case OP_FREM:
3295                         sparc_fdivd (code, ins->sreg1, ins->sreg2, sparc_f0);
3296                         sparc_fmuld (code, ins->sreg2, sparc_f0, sparc_f0);
3297                         sparc_fsubd (code, ins->sreg1, sparc_f0, ins->dreg);
3298                         break;
3299                 case OP_FCOMPARE:
3300                         sparc_fcmpd (code, ins->sreg1, ins->sreg2);
3301                         break;
3302                 case OP_FCEQ:
3303                 case OP_FCLT:
3304                 case OP_FCLT_UN:
3305                 case OP_FCGT:
3306                 case OP_FCGT_UN:
3307                         sparc_fcmpd (code, ins->sreg1, ins->sreg2);
3308                         sparc_clr_reg (code, ins->dreg);
3309                         switch (ins->opcode) {
3310                         case OP_FCLT_UN:
3311                         case OP_FCGT_UN:
3312                                 sparc_fbranch (code, 1, opcode_to_sparc_cond (ins->opcode), 4);
3313                                 /* delay slot */
3314                                 sparc_set (code, 1, ins->dreg);
3315                                 sparc_fbranch (code, 1, sparc_fbu, 2);
3316                                 /* delay slot */
3317                                 sparc_set (code, 1, ins->dreg);
3318                                 break;
3319                         default:
3320                                 sparc_fbranch (code, 1, opcode_to_sparc_cond (ins->opcode), 2);
3321                                 /* delay slot */
3322                                 sparc_set (code, 1, ins->dreg);                         
3323                         }
3324                         break;
3325                 case OP_FBEQ:
3326                 case OP_FBLT:
3327                 case OP_FBGT:
3328                         EMIT_FLOAT_COND_BRANCH (ins, opcode_to_sparc_cond (ins->opcode), 1, 1);
3329                         break;
3330                 case OP_FBGE: {
3331                         /* clt.un + brfalse */
3332                         guint32 *p = code;
3333                         sparc_fbranch (code, 1, sparc_fbul, 0);
3334                         /* delay slot */
3335                         sparc_nop (code);
3336                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fba, 1, 1);
3337                         sparc_patch ((guint8*)p, (guint8*)code);
3338                         break;
3339                 }
3340                 case OP_FBLE: {
3341                         /* cgt.un + brfalse */
3342                         guint32 *p = code;
3343                         sparc_fbranch (code, 1, sparc_fbug, 0);
3344                         /* delay slot */
3345                         sparc_nop (code);
3346                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fba, 1, 1);
3347                         sparc_patch ((guint8*)p, (guint8*)code);
3348                         break;
3349                 }
3350                 case OP_FBNE_UN:
3351                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbne, 1, 1);
3352                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbu, 1, 1);
3353                         break;
3354                 case OP_FBLT_UN:
3355                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbl, 1, 1);
3356                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbu, 1, 1);
3357                         break;
3358                 case OP_FBGT_UN:
3359                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbg, 1, 1);
3360                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbu, 1, 1);
3361                         break;
3362                 case OP_FBGE_UN:
3363                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbge, 1, 1);
3364                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbu, 1, 1);
3365                         break;
3366                 case OP_FBLE_UN:
3367                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fble, 1, 1);
3368                         EMIT_FLOAT_COND_BRANCH (ins, sparc_fbu, 1, 1);
3369                         break;
3370                 case CEE_CKFINITE: {
3371                         guint32 offset = mono_spillvar_offset_float (cfg, 0);
3372                         if (!sparc_is_imm13 (offset))
3373                                 NOT_IMPLEMENTED;
3374                         sparc_stdf_imm (code, ins->sreg1, sparc_sp, offset);
3375                         sparc_lduh_imm (code, sparc_sp, offset, sparc_o7);
3376                         sparc_srl_imm (code, sparc_o7, 4, sparc_o7);
3377                         sparc_and_imm (code, FALSE, sparc_o7, 2047, sparc_o7);
3378                         sparc_cmp_imm (code, sparc_o7, 2047);
3379                         EMIT_COND_SYSTEM_EXCEPTION (ins, sparc_be, "ArithmeticException");
3380                         sparc_fmovs (code, ins->sreg1, ins->dreg);
3381                         sparc_fmovs (code, ins->sreg1 + 1, ins->dreg + 1);
3382                         break;
3383                 }
3384                 default:
3385 #ifdef __GNUC__
3386                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3387 #else
3388                         g_warning ("%s:%d: unknown opcode %s\n", __FILE__, __LINE__, mono_inst_name (ins->opcode));
3389 #endif
3390                         g_assert_not_reached ();
3391                 }
3392
3393                 if ((((guint8*)code) - code_start) > max_len) {
3394                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3395                                    mono_inst_name (ins->opcode), max_len, ((guint8*)code) - code_start);
3396                         g_assert_not_reached ();
3397                 }
3398                
3399                 cpos += max_len;
3400
3401                 last_ins = ins;
3402                 
3403                 ins = ins->next;
3404         }
3405
3406         cfg->code_len = (guint8*)code - cfg->native_code;
3407 }
3408
3409 void
3410 mono_arch_register_lowlevel_calls (void)
3411 {
3412         mono_register_jit_icall (mono_sparc_break, "mono_sparc_break", NULL, TRUE);
3413         mono_register_jit_icall (mono_arch_get_lmf_addr, "mono_arch_get_lmf_addr", NULL, TRUE);
3414 }
3415
3416 void
3417 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3418 {
3419         MonoJumpInfo *patch_info;
3420
3421         /* FIXME: Move part of this to arch independent code */
3422         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3423                 unsigned char *ip = patch_info->ip.i + code;
3424                 const unsigned char *target = NULL;
3425
3426                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3427
3428                 switch (patch_info->type) {
3429                 case MONO_PATCH_INFO_CLASS_INIT: {
3430                         unsigned char *ip2 = ip;
3431                         /* Might already been changed to a nop */
3432                         sparc_call_simple (ip2, 0);
3433                         break;
3434                 }
3435                 case MONO_PATCH_INFO_R4: {
3436                         float *f = g_new0 (float, 1);
3437                         *f = *(float*)patch_info->data.target;
3438                         target = f;
3439                         break;
3440                 }
3441                 case MONO_PATCH_INFO_R8: {
3442                         double *d = g_new0 (double, 1);
3443                         *d = *(double*)patch_info->data.target;
3444                         target = d;                     
3445                         break;
3446                 }
3447                 default:
3448                         break;
3449                 }
3450                 sparc_patch (ip, target);
3451         }
3452 }
3453
3454 /*
3455  * Allow tracing to work with this interface (with an optional argument)
3456  */
3457
3458 /*
3459  * This may be needed on some archs or for debugging support.
3460  */
3461 void
3462 mono_arch_instrument_mem_needs (MonoMethod *method, int *stack, int *code)
3463 {
3464         /* no stack room needed now (may be needed for FASTCALL-trace support) */
3465         *stack = 0;
3466         /* split prolog-epilog requirements? */
3467         *code = 256; /* max bytes needed: check this number */
3468 }
3469
3470 void*
3471 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
3472 {
3473         int stack, code_size;
3474         guint32 *code = (guint32*)p;
3475
3476         /* Save registers to stack */
3477         sparc_st_imm (code, sparc_i0, sparc_fp, 68);
3478         sparc_st_imm (code, sparc_i1, sparc_fp, 72);
3479         sparc_st_imm (code, sparc_i2, sparc_fp, 76);
3480         sparc_st_imm (code, sparc_i3, sparc_fp, 80);
3481         sparc_st_imm (code, sparc_i4, sparc_fp, 84);
3482         sparc_st_imm (code, sparc_i5, sparc_fp, 88);
3483
3484         sparc_set (code, cfg->method, sparc_o0);
3485         sparc_mov_reg_reg (code, sparc_fp, sparc_o1);
3486
3487         mono_add_patch_info (cfg, (guint8*)code-cfg->native_code, MONO_PATCH_INFO_ABS, func);
3488         sparc_sethi (code, 0, sparc_o7);
3489         sparc_jmpl_imm (code, sparc_o7, 0, sparc_callsite);
3490         sparc_nop (code);
3491
3492         mono_arch_instrument_mem_needs (cfg->method, &stack, &code_size);
3493
3494         g_assert ((code - (guint32*)p) <= (code_size * 4));
3495
3496         return code;
3497 }
3498
3499 enum {
3500         SAVE_NONE,
3501         SAVE_STRUCT,
3502         SAVE_ONE,
3503         SAVE_TWO,
3504         SAVE_FP
3505 };
3506
3507 void*
3508 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
3509 {
3510         guchar *code = p;
3511         int save_mode = SAVE_NONE;
3512         MonoMethod *method = cfg->method;
3513         int rtype = method->signature->ret->type;
3514         
3515 handle_enum:
3516         switch (rtype) {
3517         case MONO_TYPE_VOID:
3518                 /* special case string .ctor icall */
3519                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
3520                         save_mode = SAVE_ONE;
3521                 else
3522                         save_mode = SAVE_NONE;
3523                 break;
3524         case MONO_TYPE_I8:
3525         case MONO_TYPE_U8:
3526                 save_mode = SAVE_TWO;
3527                 break;
3528         case MONO_TYPE_R4:
3529         case MONO_TYPE_R8:
3530                 save_mode = SAVE_FP;
3531                 break;
3532         case MONO_TYPE_VALUETYPE:
3533                 if (method->signature->ret->data.klass->enumtype) {
3534                         rtype = method->signature->ret->data.klass->enum_basetype->type;
3535                         goto handle_enum;
3536                 }
3537                 save_mode = SAVE_STRUCT;
3538                 break;
3539         default:
3540                 save_mode = SAVE_ONE;
3541                 break;
3542         }
3543
3544         /* Save the result to the stack and also put it into the output registers */
3545
3546         switch (save_mode) {
3547         case SAVE_TWO:
3548                 sparc_st_imm (code, sparc_i0, sparc_fp, 68);
3549                 sparc_st_imm (code, sparc_i0, sparc_fp, 72);
3550                 sparc_mov_reg_reg (code, sparc_i0, sparc_o1);
3551                 sparc_mov_reg_reg (code, sparc_i1, sparc_o2);
3552                 break;
3553         case SAVE_ONE:
3554                 sparc_st_imm (code, sparc_i0, sparc_fp, 68);
3555                 sparc_mov_reg_reg (code, sparc_i0, sparc_o1);
3556                 break;
3557         case SAVE_FP:
3558                 sparc_stdf_imm (code, sparc_f0, sparc_fp, 72);
3559                 sparc_ld_imm (code, sparc_fp, 72, sparc_o1);
3560                 sparc_ld_imm (code, sparc_fp, 72, sparc_o2);
3561                 break;
3562         case SAVE_STRUCT:
3563                 sparc_ld_imm (code, sparc_fp, 64, sparc_o1);
3564                 break;
3565         case SAVE_NONE:
3566         default:
3567                 break;
3568         }
3569
3570         sparc_set (code, cfg->method, sparc_o0);
3571
3572         mono_add_patch_info (cfg, (guint8*)code-cfg->native_code, MONO_PATCH_INFO_ABS, func);
3573         sparc_sethi (code, 0, sparc_o7);
3574         sparc_jmpl_imm (code, sparc_o7, 0, sparc_callsite);
3575         sparc_nop (code);
3576
3577         /* Restore result */
3578
3579         switch (save_mode) {
3580         case SAVE_TWO:
3581                 sparc_ld_imm (code, sparc_fp, 68, sparc_i0);
3582                 sparc_ld_imm (code, sparc_fp, 72, sparc_i0);
3583                 break;
3584         case SAVE_ONE:
3585                 sparc_ld_imm (code, sparc_fp, 68, sparc_i0);
3586                 break;
3587         case SAVE_FP:
3588                 sparc_lddf_imm (code, sparc_fp, 72, sparc_f0);
3589                 break;
3590         case SAVE_NONE:
3591         default:
3592                 break;
3593         }
3594
3595         return code;
3596 }
3597
3598 int
3599 mono_arch_max_epilog_size (MonoCompile *cfg)
3600 {
3601         int exc_count = 0, max_epilog_size = 16 + 20*4;
3602         MonoJumpInfo *patch_info;
3603         
3604         if (cfg->method->save_lmf)
3605                 max_epilog_size += 128;
3606         
3607         if (mono_jit_trace_calls != NULL)
3608                 max_epilog_size += 50;
3609
3610         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3611                 max_epilog_size += 50;
3612
3613         /* count the number of exception infos */
3614      
3615         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3616                 if (patch_info->type == MONO_PATCH_INFO_EXC)
3617                         exc_count++;
3618         }
3619
3620         /* 
3621          * make sure we have enough space for exceptions
3622          */
3623         max_epilog_size += exc_count * 24;
3624
3625         return max_epilog_size;
3626 }
3627
3628 guint8 *
3629 mono_arch_emit_prolog (MonoCompile *cfg)
3630 {
3631         MonoMethod *method = cfg->method;
3632         MonoMethodSignature *sig;
3633         MonoInst *inst;
3634         guint8 *code;
3635         CallInfo *cinfo;
3636         guint32 i, offset;
3637
3638         cfg->code_size = 256;
3639         code = cfg->native_code = g_malloc (cfg->code_size);
3640
3641         /* FIXME: Generate intermediate code instead */
3642
3643         offset = cfg->stack_offset;
3644         offset += 64; /* register save area */
3645         offset += 4; /* struct/union return pointer */
3646
3647         /* add parameter area size for called functions */
3648         if (cfg->param_area < 24)
3649                 /* Reserve space for the first 6 arguments even if it is unused */
3650                 offset += 24;
3651         else
3652                 offset += cfg->param_area;
3653         
3654         /* align the stack size to 8 bytes */
3655         offset = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
3656
3657         /*
3658          * localloc'd memory is stored between the local variables (whose
3659          * size is given by cfg->stack_offset), and between the space reserved
3660          * by the ABI.
3661          */
3662         cfg->arch.localloc_offset = offset - cfg->stack_offset;
3663
3664         cfg->stack_offset = offset;
3665
3666         if (!sparc_is_imm13 (- cfg->stack_offset)) {
3667                 /* Can't use sparc_o7 here, since we're still in the caller's frame */
3668                 sparc_set (code, (- cfg->stack_offset), sparc_g1);
3669                 sparc_save (code, sparc_sp, sparc_g1, sparc_sp);
3670         }
3671         else
3672                 sparc_save_imm (code, sparc_sp, - cfg->stack_offset, sparc_sp);
3673
3674         if (strstr (cfg->method->name, "test_marshal_struct")) {
3675                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_ABS, mono_sparc_break);
3676                 sparc_call_simple (code, 0);
3677                 sparc_nop (code);
3678         }
3679
3680         sig = method->signature;
3681
3682         cinfo = get_call_info (sig, FALSE);
3683
3684         /* Keep in sync with emit_load_volatile_arguments */
3685         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3686                 ArgInfo *ainfo = cinfo->args + i;
3687                 guint32 stack_offset;
3688                 MonoType *arg_type;
3689                 inst = cfg->varinfo [i];
3690
3691                 if (sig->hasthis && (i == 0))
3692                         arg_type = mono_defaults.object_class;
3693                 else
3694                         arg_type = sig->params [i - sig->hasthis];
3695
3696                 stack_offset = ainfo->offset + 68;
3697
3698                 /* Save the split arguments so they will reside entirely on the stack */
3699                 if (ainfo->storage == ArgInSplitRegStack) {
3700                         /* Save the register to the stack */
3701                         g_assert (inst->opcode == OP_REGOFFSET);
3702                         if (!sparc_is_imm13 (stack_offset))
3703                                 NOT_IMPLEMENTED;
3704                         sparc_st_imm (code, sparc_i5, inst->inst_basereg, stack_offset);
3705                 }
3706
3707                 if (!arg_type->byref && (arg_type->type == MONO_TYPE_R8)) {
3708                         /* Save the argument to a dword aligned stack location */
3709                         /*
3710                          * stack_offset contains the offset of the argument on the stack.
3711                          * inst->inst_offset contains the dword aligned offset where the value 
3712                          * should be stored.
3713                          */
3714                         if (ainfo->storage == ArgInIRegPair) {
3715                                 if (!sparc_is_imm13 (inst->inst_offset + 4))
3716                                         NOT_IMPLEMENTED;
3717                                 sparc_st_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, inst->inst_offset);
3718                                 sparc_st_imm (code, sparc_i0 + ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
3719                         }
3720                         else
3721                                 if (ainfo->storage == ArgInSplitRegStack) {
3722                                         if (stack_offset != inst->inst_offset) {
3723                                                 /* stack_offset is not dword aligned, so we need to make a copy */
3724                                                 sparc_st_imm (code, sparc_i5, inst->inst_basereg, inst->inst_offset);
3725                                                 sparc_ld_imm (code, sparc_fp, stack_offset + 4, sparc_o7);
3726                                                 sparc_st_imm (code, sparc_o7, inst->inst_basereg, inst->inst_offset + 4);
3727                                         }
3728                                 }
3729                         else
3730                                 if (ainfo->storage == ArgOnStackPair) {
3731                                         if (stack_offset != inst->inst_offset) {
3732                                                 /* stack_offset is not dword aligned, so we need to make a copy */
3733                                                 sparc_ld_imm (code, sparc_fp, stack_offset, sparc_o7);
3734                                                 sparc_st_imm (code, sparc_o7, inst->inst_basereg, inst->inst_offset);
3735                                                 sparc_ld_imm (code, sparc_fp, stack_offset + 4, sparc_o7);
3736                                                 sparc_st_imm (code, sparc_o7, inst->inst_basereg, inst->inst_offset + 4);
3737                                         }
3738                                 }
3739                         else
3740                                 g_assert_not_reached ();
3741                 }
3742                 else
3743                         if ((ainfo->storage == ArgInIReg) && (inst->opcode != OP_REGVAR)) {
3744                                 /* Argument in register, but need to be saved to stack */
3745                                 if (!sparc_is_imm13 (stack_offset))
3746                                         NOT_IMPLEMENTED;
3747                                 if (stack_offset & 0x1)
3748                                         sparc_stb_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, stack_offset);
3749                                 else
3750                                         if (stack_offset & 0x2)
3751                                                 sparc_sth_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, stack_offset);
3752                                 else
3753                                         sparc_st_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, stack_offset);
3754                         }
3755                 else
3756                         if ((ainfo->storage == ArgInIRegPair) && (inst->opcode != OP_REGVAR)) {
3757                                 /* Argument in regpair, but need to be saved to stack */
3758                                 if (!sparc_is_imm13 (inst->inst_offset + 4))
3759                                         NOT_IMPLEMENTED;
3760                                 sparc_st_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, inst->inst_offset);
3761                                 sparc_st_imm (code, sparc_i0 + ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);                              
3762                         }
3763
3764                 if ((ainfo->storage == ArgInSplitRegStack) || (ainfo->storage == ArgOnStack))
3765                         if (inst->opcode == OP_REGVAR)
3766                                 /* FIXME: Load the argument into memory */
3767                                 NOT_IMPLEMENTED;
3768         }
3769
3770         g_free (cinfo);
3771
3772         if (cfg->method->save_lmf) {
3773                 gint32 lmf_offset = - cfg->arch.lmf_offset;
3774
3775                 /* Save ip */
3776                 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3777                 sparc_set (code, 0xfffffff, sparc_o7);
3778                 sparc_st_imm (code, sparc_o7, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ip));
3779                 /* Save sp */
3780                 sparc_st_imm (code, sparc_sp, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, sp));
3781                 /* Save fp */
3782                 sparc_st_imm (code, sparc_fp, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebp));
3783                 /* Save method */
3784                 /* FIXME: add a relocation for this */
3785                 sparc_set (code, cfg->method, sparc_o7);
3786                 sparc_st_imm (code, sparc_o7, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, method));
3787
3788                 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3789                                                          (gpointer)"mono_arch_get_lmf_addr");           
3790                 sparc_call_simple (code, 0);
3791                 sparc_nop (code);
3792
3793                 code = (guint32*)mono_sparc_emit_save_lmf ((guint32*)code, lmf_offset);
3794         }
3795
3796         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3797                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3798
3799         cfg->code_len = code - cfg->native_code;
3800
3801         g_assert (cfg->code_len <= cfg->code_size);
3802
3803         return code;
3804 }
3805
3806 void
3807 mono_arch_emit_epilog (MonoCompile *cfg)
3808 {
3809         MonoJumpInfo *patch_info;
3810         MonoMethod *method = cfg->method;
3811         guint8 *code;
3812
3813         code = cfg->native_code + cfg->code_len;
3814
3815         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3816                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3817
3818         if (cfg->method->save_lmf) {
3819                 gint32 lmf_offset = - cfg->arch.lmf_offset;
3820
3821                 code = mono_sparc_emit_restore_lmf (code, lmf_offset);
3822         }
3823
3824         /* 
3825          * The sparc ABI requires that calls to functions which return a structure
3826          * return to %i7+12
3827          */
3828         if (cfg->method->signature->pinvoke && MONO_TYPE_ISSTRUCT(cfg->method->signature->ret))
3829                 sparc_jmpl_imm (code, sparc_i7, 12, sparc_g0);
3830         else
3831                 sparc_ret (code);
3832         sparc_restore_imm (code, sparc_g0, 0, sparc_g0);
3833
3834         /* add code to raise exceptions */
3835         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3836                 switch (patch_info->type) {
3837                 case MONO_PATCH_INFO_EXC:
3838                         sparc_patch (cfg->native_code + patch_info->ip.i, code);
3839                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);
3840                         sparc_set (code, 0xffffff, sparc_o0);
3841                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_METHOD_REL, (gpointer)patch_info->ip.i);
3842                         sparc_set (code, 0xffffff, sparc_o1);
3843                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3844                         patch_info->data.name = "mono_arch_throw_exception_by_name";
3845                         patch_info->ip.i = code - cfg->native_code;
3846                         sparc_call_simple (code, 0);
3847                         sparc_nop (code);
3848                         break;
3849                 default:
3850                         /* do nothing */
3851                         break;
3852                 }
3853         }
3854
3855         cfg->code_len = code - cfg->native_code;
3856
3857         g_assert (cfg->code_len < cfg->code_size);
3858
3859 }
3860
3861 gboolean lmf_addr_key_inited = FALSE;
3862
3863 #ifdef MONO_SPARC_THR_TLS
3864 thread_key_t lmf_addr_key;
3865 #else
3866 pthread_key_t lmf_addr_key;
3867 #endif
3868
3869 gpointer
3870 mono_arch_get_lmf_addr (void)
3871 {
3872         /* This is perf critical so we bypass the IO layer */
3873         /* The thr_... functions seem to be somewhat faster */
3874 #ifdef MONO_SPARC_THR_TLS
3875         gpointer res;
3876         thr_getspecific (lmf_addr_key, &res);
3877         return res;
3878 #else
3879         return pthread_getspecific (lmf_addr_key);
3880 #endif
3881 }
3882
3883 void
3884 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3885 {
3886 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3887 #ifdef __linux__
3888         struct sigaltstack sa;
3889 #else
3890         stack_t         sigstk;
3891 #endif
3892  
3893         printf ("SIGALT!\n");
3894         /* Setup an alternate signal stack */
3895         tls->signal_stack = g_malloc (SIGNAL_STACK_SIZE);
3896         tls->signal_stack_size = SIGNAL_STACK_SIZE;
3897
3898 #ifdef __linux__
3899         sa.ss_sp = tls->signal_stack;
3900         sa.ss_size = SIGNAL_STACK_SIZE;
3901         sa.ss_flags = 0;
3902         g_assert (sigaltstack (&sa, NULL) == 0);
3903 #else
3904         sigstk.ss_sp = tls->signal_stack;
3905         sigstk.ss_size = SIGNAL_STACK_SIZE;
3906         sigstk.ss_flags = 0;
3907         g_assert (sigaltstack (&sigstk, NULL) == 0);
3908 #endif
3909 #endif
3910
3911         if (!lmf_addr_key_inited) {
3912                 int res;
3913
3914                 lmf_addr_key_inited = TRUE;
3915
3916 #ifdef MONO_SPARC_THR_TLS
3917                 res = thr_keycreate (&lmf_addr_key, NULL);
3918 #else
3919                 res = pthread_key_create (&lmf_addr_key, NULL);
3920 #endif
3921                 g_assert (res == 0);
3922
3923         }
3924
3925 #ifdef MONO_SPARC_THR_TLS
3926         thr_setspecific (lmf_addr_key, &tls->lmf);
3927 #else
3928         pthread_setspecific (lmf_addr_key, &tls->lmf);
3929 #endif
3930 }
3931
3932 void
3933 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3934 {
3935 }
3936
3937 void
3938 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3939 {
3940         /* add the this argument */
3941         if (this_reg != -1) {
3942                 MonoInst *this;
3943                 MONO_INST_NEW (cfg, this, OP_SETREG);
3944                 this->type = this_type;
3945                 this->sreg1 = this_reg;
3946                 this->dreg = sparc_o0;
3947                 mono_bblock_add_inst (cfg->cbb, this);
3948         }
3949
3950         if (vt_reg != -1) {
3951                 /* Set the 'struct/union return pointer' location on the stack */
3952                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, sparc_sp, 64, vt_reg);
3953         }
3954 }
3955
3956
3957 gint
3958 mono_arch_get_opcode_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3959 {
3960         return -1;
3961 }
3962
3963 /*
3964  * mono_arch_get_argument_info:
3965  * @csig:  a method signature
3966  * @param_count: the number of parameters to consider
3967  * @arg_info: an array to store the result infos
3968  *
3969  * Gathers information on parameters such as size, alignment and
3970  * padding. arg_info should be large enought to hold param_count + 1 entries. 
3971  *
3972  * Returns the size of the activation frame.
3973  */
3974 int
3975 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
3976 {
3977         int k, align;
3978         CallInfo *cinfo;
3979         ArgInfo *ainfo;
3980
3981         cinfo = get_call_info (csig, FALSE);
3982
3983         if (csig->hasthis) {
3984                 ainfo = &cinfo->args [0];
3985                 arg_info [0].offset = 68 + ainfo->offset;
3986         }
3987
3988         for (k = 0; k < param_count; k++) {
3989                 ainfo = &cinfo->args [k + csig->hasthis];
3990
3991                 arg_info [k + 1].offset = 68 + ainfo->offset;
3992                 arg_info [k + 1].size = mono_type_size (csig->params [k], &align);
3993         }
3994
3995         g_free (cinfo);
3996
3997         /* FIXME: */
3998         return 0;
3999 }
4000
4001 gboolean
4002 mono_arch_print_tree (MonoInst *tree, int arity)
4003 {
4004         return 0;
4005 }