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