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