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