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