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