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