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