2 * mini-sparc.c: Sparc backend for the Mono code generator
5 * Paolo Molaro (lupus@ximian.com)
6 * Dietmar Maurer (dietmar@ximian.com)
9 * Christopher Taylor (ct@gentoo.org)
10 * Mark Crichton (crichton@gimp.org)
11 * Zoltan Varga (vargaz@freemail.hu)
13 * (C) 2003 Ximian, Inc.
17 #include <sys/systeminfo.h>
19 #include <mono/metadata/appdomain.h>
20 #include <mono/metadata/debug-helpers.h>
21 #include <mono/utils/mono-math.h>
23 #include "mini-sparc.h"
26 #include "cpu-sparc.h"
29 * Sparc V9 means two things:
30 * - the instruction set
33 * V9 instructions are only usable if the underlying processor is 64 bit. Most Sparc
34 * processors in use are 64 bit processors. The V9 ABI is only usable if the
35 * mono executable is a 64 bit executable. So it would make sense to use the 64 bit
36 * instructions without using the 64 bit ABI.
41 * - %i0..%i<n> hold the incoming arguments, these are never written by JITted
42 * code. Unused input registers are used for global register allocation.
43 * - %l0..%l7 is used for local register allocation
44 * - %o0..%o6 is used for outgoing arguments
45 * - %o7 and %g1 is used as scratch registers in opcodes
46 * - all floating point registers are used for local register allocation except %f0.
47 * Only double precision registers are used.
52 * - doubles and longs must be stored in dword aligned locations
56 * The following things are not implemented or do not work:
57 * - some fp arithmetic corner cases
58 * The following tests in mono/mini are expected to fail:
59 * - test_0_simple_double_casts
60 * This test casts (guint64)-1 to double and then back to guint64 again.
61 * Under x86, it returns 0, while under sparc it returns -1.
63 * In addition to this, the runtime requires the truncl function, or its
64 * solaris counterpart, aintl, to do some double->int conversions. If this
65 * function is not available, it is emulated somewhat, but the results can be
70 * Possible optimizations:
71 * - delay slot scheduling
72 * - allocate large constants to registers
73 * - use %o registers for local allocation
74 * - implement unwinding through native frames
75 * - add more mul/div/rem optimizations
79 #error "Sparc V9 support not yet implemented."
82 #define NOT_IMPLEMENTED g_assert_not_reached ();
84 #define ALIGN_TO(val,align) (((val) + ((align) - 1)) & ~((align) - 1))
86 #define SIGNAL_STACK_SIZE (64 * 1024)
88 /* Whenever the CPU supports v9 instructions */
89 gboolean sparcv9 = FALSE;
92 mono_spillvar_offset_float (MonoCompile *cfg, int spillvar);
95 mono_arch_regname (int reg) {
96 static const char * rnames[] = {
97 "sparc_g0", "sparc_g1", "sparc_g2", "sparc_g3", "sparc_g4",
98 "sparc_g5", "sparc_g6", "sparc_g7", "sparc_o0", "sparc_o1",
99 "sparc_o2", "sparc_o3", "sparc_o4", "sparc_o5", "sparc_sp",
100 "sparc_call", "sparc_l0", "sparc_l1", "sparc_l2", "sparc_l3",
101 "sparc_l4", "sparc_l5", "sparc_l6", "sparc_l7", "sparc_i0",
102 "sparc_i1", "sparc_i2", "sparc_i3", "sparc_i4", "sparc_i5",
103 "sparc_fp", "sparc_retadr"
105 if (reg >= 0 && reg < 32)
111 * Initialize the cpu to execute managed code.
114 mono_arch_cpu_init (void)
119 * This function returns the optimizations supported on this cpu.
122 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
129 if (!sysinfo (SI_ISALIST, buf, 1024))
130 g_assert_not_reached ();
133 * On some processors, the cmov instructions are even slower than the
136 if (strstr (buf, "sparcv9")) {
137 opts |= MONO_OPT_CMOV | MONO_OPT_FCMOV;
141 *exclude_mask |= MONO_OPT_CMOV | MONO_OPT_FCMOV;
147 mono_sparc_break (void)
152 #define flushi(addr) __asm__ __volatile__ ("iflush %0"::"r"(addr):"memory")
153 #else /* assume Sun's compiler */
154 static void flushi(void *addr)
161 mono_arch_flush_icache (guint8 *code, gint size)
163 guint64 *p = (guint64*)code;
164 guint64 *end = (guint64*)(code + ((size + 8) /8));
167 * FIXME: Flushing code in dword chunks in _slow_.
172 __asm__ __volatile__ ("iflush %0"::"r"(p++));
181 * Flush all register windows to memory. Every register window is saved to
182 * a 16 word area on the stack pointed to by its %sp register.
185 mono_sparc_flushw (void)
187 static guint32 start [64];
188 static int inited = 0;
190 static void (*flushw) (void);
195 sparc_save_imm (code, sparc_sp, -160, sparc_sp);
198 sparc_restore_simple (code);
200 g_assert ((code - start) < 64);
202 flushw = (gpointer)start;
211 mono_arch_flush_register_windows (void)
213 mono_sparc_flushw ();
217 mono_sparc_is_v9 (void) {
233 /* This needs to be offset by %i0 or %o0 depending on caller/callee */
236 guint32 vt_offset; /* for valuetypes */
254 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo, gboolean pair)
256 ainfo->offset = *stack_size;
259 if (*gr >= PARAM_REGS) {
260 ainfo->storage = ArgOnStack;
263 ainfo->storage = ArgInIReg;
268 /* Allways reserve stack space for parameters passed in registers */
272 if (*gr < PARAM_REGS - 1) {
273 /* A pair of registers */
274 ainfo->storage = ArgInIRegPair;
278 else if (*gr >= PARAM_REGS) {
279 /* A pair of stack locations */
280 ainfo->storage = ArgOnStackPair;
281 ainfo->offset = *stack_size;
284 ainfo->storage = ArgInSplitRegStack;
286 ainfo->offset = *stack_size;
297 * Obtain information about a call according to the calling convention.
298 * See the "System V ABI, Sparc Processor Supplement" Sparc V8 version document for
302 get_call_info (MonoMethodSignature *sig, gboolean is_pinvoke)
304 guint32 i, gr, simpletype;
305 int n = sig->hasthis + sig->param_count;
306 guint32 stack_size = 0;
309 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
315 add_general (&gr, &stack_size, cinfo->args + 0, FALSE);
317 for (i = 0; i < sig->param_count; ++i) {
318 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
320 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
321 /* Emit the signature cookie just before the implicit arguments */
322 add_general (&gr, &stack_size, &cinfo->sig_cookie, FALSE);
323 /* Prevent implicit arguments from being passed in registers */
327 DEBUG(printf("param %d: ", i));
328 if (sig->params [i]->byref) {
329 DEBUG(printf("byref\n"));
331 add_general (&gr, &stack_size, ainfo, FALSE);
334 simpletype = sig->params [i]->type;
336 switch (simpletype) {
337 case MONO_TYPE_BOOLEAN:
340 add_general (&gr, &stack_size, ainfo, FALSE);
341 /* the value is in the ls byte */
347 add_general (&gr, &stack_size, ainfo, FALSE);
348 /* the value is in the ls word */
356 case MONO_TYPE_CLASS:
357 case MONO_TYPE_OBJECT:
358 case MONO_TYPE_STRING:
359 case MONO_TYPE_SZARRAY:
360 case MONO_TYPE_ARRAY:
361 add_general (&gr, &stack_size, ainfo, FALSE);
363 case MONO_TYPE_VALUETYPE:
364 if (sig->params [i]->data.klass->enumtype) {
365 simpletype = sig->params [i]->data.klass->enum_basetype->type;
369 add_general (&gr, &stack_size, ainfo, FALSE);
371 case MONO_TYPE_TYPEDBYREF:
372 add_general (&gr, &stack_size, ainfo, FALSE);
376 add_general (&gr, &stack_size, ainfo, TRUE);
379 /* single precision values are passed in integer registers */
380 add_general (&gr, &stack_size, ainfo, FALSE);
383 /* double precision values are passed in a pair of registers */
384 add_general (&gr, &stack_size, ainfo, TRUE);
387 g_assert_not_reached ();
393 simpletype = sig->ret->type;
395 switch (simpletype) {
396 case MONO_TYPE_BOOLEAN:
407 case MONO_TYPE_CLASS:
408 case MONO_TYPE_OBJECT:
409 case MONO_TYPE_SZARRAY:
410 case MONO_TYPE_ARRAY:
411 case MONO_TYPE_STRING:
412 cinfo->ret.storage = ArgInIReg;
413 cinfo->ret.reg = sparc_i0;
419 cinfo->ret.storage = ArgInIRegPair;
420 cinfo->ret.reg = sparc_i0;
426 cinfo->ret.storage = ArgInFReg;
427 cinfo->ret.reg = sparc_f0;
429 case MONO_TYPE_VALUETYPE:
430 if (sig->ret->data.klass->enumtype) {
431 simpletype = sig->ret->data.klass->enum_basetype->type;
434 cinfo->ret.storage = ArgOnStack;
436 case MONO_TYPE_TYPEDBYREF:
437 cinfo->ret.storage = ArgOnStack;
442 g_error ("Can't handle as return value 0x%x", sig->ret->type);
446 cinfo->stack_usage = stack_size;
447 cinfo->reg_usage = gr;
452 is_regsize_var (MonoType *t) {
456 case MONO_TYPE_BOOLEAN:
467 case MONO_TYPE_OBJECT:
468 case MONO_TYPE_STRING:
469 case MONO_TYPE_CLASS:
470 case MONO_TYPE_SZARRAY:
471 case MONO_TYPE_ARRAY:
473 case MONO_TYPE_VALUETYPE:
474 if (t->data.klass->enumtype)
475 return is_regsize_var (t->data.klass->enum_basetype);
482 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
488 * FIXME: If an argument is allocated to a register, then load it from the
489 * stack in the prolog.
492 for (i = 0; i < cfg->num_varinfo; i++) {
493 MonoInst *ins = cfg->varinfo [i];
494 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
497 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
500 /* FIXME: Make arguments on stack allocateable to registers */
501 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode == OP_REGVAR) || (ins->opcode == OP_ARG))
504 /* we can only allocate 32 bit values */
505 if (is_regsize_var (ins->inst_vtype)) {
506 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
507 g_assert (i == vmv->idx);
509 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
517 mono_arch_get_global_int_regs (MonoCompile *cfg)
521 MonoMethodSignature *sig;
524 sig = cfg->method->signature;
526 cinfo = get_call_info (sig, FALSE);
528 /* Use unused input registers */
529 for (i = cinfo->reg_usage; i < 6; ++i)
530 regs = g_list_prepend (regs, GUINT_TO_POINTER (sparc_i0 + i));
532 /* Use %l0..%l3 as global registers */
533 for (i = 16; i < 20; ++i)
534 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
542 * mono_arch_regalloc_cost:
544 * Return the cost, in number of memory references, of the action of
545 * allocating the variable VMV into a register during global register
549 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
555 * Set var information according to the calling convention. sparc version.
556 * The locals var stuff should most likely be split in another method.
559 mono_arch_allocate_vars (MonoCompile *m)
561 MonoMethodSignature *sig;
562 MonoMethodHeader *header;
564 int i, offset, size, align, curinst;
567 header = ((MonoMethodNormal *)m->method)->header;
569 sig = m->method->signature;
571 cinfo = get_call_info (sig, FALSE);
573 if (sig->ret->type != MONO_TYPE_VOID) {
574 switch (cinfo->ret.storage) {
578 m->ret->opcode = OP_REGVAR;
579 m->ret->inst_c0 = cinfo->ret.reg;
583 m->ret->opcode = OP_REGOFFSET;
584 m->ret->inst_basereg = sparc_fp;
585 m->ret->inst_offset = 64;
593 * We use the Sparc V8 calling conventions for managed code as well.
594 * FIXME: Use something more optimized.
597 /* Locals are allocated backwards from %fp */
598 m->frame_reg = sparc_fp;
602 * Reserve a stack slot for holding information used during exception
605 if (header->num_clauses)
608 if (m->method->save_lmf) {
609 offset += sizeof (MonoLMF);
610 m->arch.lmf_offset = offset;
613 curinst = m->locals_start;
614 for (i = curinst; i < m->num_varinfo; ++i) {
615 inst = m->varinfo [i];
617 if (inst->opcode == OP_REGVAR) {
618 //g_print ("allocating local %d to %s\n", i, mono_arch_regname (inst->dreg));
622 /* inst->unused indicates native sized value types, this is used by the
623 * pinvoke wrappers when they call functions returning structure */
624 if (inst->unused && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
625 size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
627 size = mono_type_stack_size (inst->inst_vtype, &align);
630 * This is needed since structures containing doubles must be doubleword
632 * FIXME: Do this only if needed.
634 if (MONO_TYPE_ISSTRUCT (inst->inst_vtype))
638 * variables are accessed as negative offsets from %fp, so increase
639 * the offset before assigning it to a variable
644 offset &= ~(align - 1);
645 inst->opcode = OP_REGOFFSET;
646 inst->inst_basereg = sparc_fp;
647 inst->inst_offset = -offset;
649 //g_print ("allocating local %d to [%s - %d]\n", i, mono_arch_regname (inst->inst_basereg), - inst->inst_offset);
652 if (sig->call_convention == MONO_CALL_VARARG) {
653 m->sig_cookie = cinfo->sig_cookie.offset + 68;
656 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
657 inst = m->varinfo [i];
658 if (inst->opcode != OP_REGVAR) {
659 ArgInfo *ainfo = &cinfo->args [i];
660 gboolean inreg = TRUE;
663 if (sig->hasthis && (i == 0))
664 arg_type = &mono_defaults.object_class->byval_arg;
666 arg_type = sig->params [i - sig->hasthis];
668 if (!arg_type->byref && ((arg_type->type == MONO_TYPE_R4)
669 || (arg_type->type == MONO_TYPE_R8)))
671 * Since float arguments are passed in integer registers, we need to
672 * save them to the stack in the prolog.
676 /* FIXME: Allocate volatile arguments to registers */
677 if (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))
680 if (MONO_TYPE_ISSTRUCT (arg_type))
681 /* FIXME: this isn't needed */
684 switch (ainfo->storage) {
688 inst->opcode = OP_REGVAR;
689 inst->dreg = sparc_i0 + ainfo->reg;
697 case ArgInSplitRegStack:
698 /* Split arguments are saved to the stack in the prolog */
699 inst->opcode = OP_REGOFFSET;
700 /* in parent frame */
701 inst->inst_basereg = sparc_fp;
702 inst->inst_offset = ainfo->offset + 68;
704 if (!arg_type->byref && (arg_type->type == MONO_TYPE_R8)) {
706 * It is very hard to load doubles from non-doubleword aligned
707 * memory locations. So if the offset is misaligned, we copy the
708 * argument to a stack location in the prolog.
710 if (inst->inst_offset % 8) {
711 inst->inst_basereg = sparc_fp;
715 offset &= ~(align - 1);
716 inst->inst_offset = -offset;
725 if (MONO_TYPE_ISSTRUCT (arg_type)) {
726 /* Add a level of indirection */
728 * It would be easier to add OP_LDIND_I here, but ldind_i instructions
729 * are destructively modified in a lot of places in inssel.brg.
732 MONO_INST_NEW (m, indir, 0);
734 inst->opcode = OP_SPARC_INARG_VT;
735 inst->inst_left = indir;
741 * spillvars are stored between the normal locals and the storage reserved
745 m->stack_offset = offset;
747 /* Add a properly aligned dword for use by int<->float conversion opcodes */
749 mono_spillvar_offset_float (m, 0);
755 * take the arguments and generate the arch-specific
756 * instructions to properly call the function in call.
757 * This includes pushing, moving arguments to the right register
761 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
763 MonoMethodSignature *sig;
767 guint32 extra_space = 0;
769 sig = call->signature;
770 n = sig->param_count + sig->hasthis;
772 cinfo = get_call_info (sig, sig->pinvoke);
774 for (i = 0; i < n; ++i) {
775 ainfo = cinfo->args + i;
776 if (is_virtual && i == 0) {
777 /* the argument will be attached to the call instruction */
780 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
781 /* FIXME: Test varargs with 0 implicit args */
782 /* FIXME: Test interaction with hasthis */
783 /* Emit the signature cookie just before the first implicit argument */
785 /* FIXME: Add support for signature tokens to AOT */
786 cfg->disable_aot = TRUE;
787 /* We allways pass the signature on the stack for simplicity */
788 MONO_INST_NEW (cfg, arg, OP_SPARC_OUTARG_MEM);
789 arg->inst_basereg = sparc_sp;
790 arg->inst_imm = 68 + cinfo->sig_cookie.offset;
791 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
792 sig_arg->inst_p0 = call->signature;
793 arg->inst_left = sig_arg;
794 arg->type = STACK_PTR;
795 /* prepend, so they get reversed */
796 arg->next = call->out_args;
797 call->out_args = arg;
800 MONO_INST_NEW (cfg, arg, OP_OUTARG);
802 arg->cil_code = in->cil_code;
804 arg->type = in->type;
805 /* prepend, we'll need to reverse them later */
806 arg->next = call->out_args;
807 call->out_args = arg;
809 if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(sig->params [i - sig->hasthis]))) {
815 if (sig->params [i - sig->hasthis]->type == MONO_TYPE_TYPEDBYREF) {
816 size = sizeof (MonoTypedRef);
821 size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
823 size = mono_type_stack_size (&in->klass->byval_arg, &align);
826 * We use OP_OUTARG_VT to copy the valuetype to a stack location, then
827 * use the normal OUTARG opcodes to pass the address of the location to
830 MONO_INST_NEW (cfg, inst, OP_OUTARG_VT);
831 inst->inst_left = in;
833 /* The first 6 argument locations are reserved */
834 if (cinfo->stack_usage < 24)
835 cinfo->stack_usage = 24;
837 offset = ALIGN_TO (68 + cinfo->stack_usage, align);
838 pad = offset - (68 + cinfo->stack_usage);
840 inst->inst_c1 = offset;
842 arg->inst_left = inst;
844 cinfo->stack_usage += size;
845 cinfo->stack_usage += pad;
848 switch (ainfo->storage) {
852 if (ainfo->storage == ArgInIRegPair)
853 arg->opcode = OP_SPARC_OUTARG_REGPAIR;
854 arg->unused = sparc_o0 + ainfo->reg;
855 /* outgoing arguments begin at sp+68 */
856 arg->inst_basereg = sparc_sp;
857 arg->inst_imm = 68 + ainfo->offset;
858 call->used_iregs |= 1 << ainfo->reg;
860 if ((i >= sig->hasthis) && (sig->params [i - sig->hasthis]->type == MONO_TYPE_R8)) {
862 * The OUTARG (freg) implementation needs an extra dword to store
863 * the temporary value.
869 arg->opcode = OP_SPARC_OUTARG_MEM;
870 arg->inst_basereg = sparc_sp;
871 arg->inst_imm = 68 + ainfo->offset;
874 arg->opcode = OP_SPARC_OUTARG_MEMPAIR;
875 arg->inst_basereg = sparc_sp;
876 arg->inst_imm = 68 + ainfo->offset;
878 case ArgInSplitRegStack:
879 arg->opcode = OP_SPARC_OUTARG_SPLIT_REG_STACK;
880 arg->unused = sparc_o0 + ainfo->reg;
881 arg->inst_basereg = sparc_sp;
882 arg->inst_imm = 68 + ainfo->offset;
883 call->used_iregs |= 1 << ainfo->reg;
892 * Reverse the call->out_args list.
895 MonoInst *prev = NULL, *list = call->out_args, *next;
902 call->out_args = prev;
904 call->stack_usage = cinfo->stack_usage + extra_space;
905 cfg->param_area = MAX (cfg->param_area, call->stack_usage);
906 cfg->flags |= MONO_CFG_HAS_CALLS;
912 /* Map opcode to the sparc condition codes */
913 static inline SparcCond
914 opcode_to_sparc_cond (int opcode)
937 case OP_COND_EXC_NE_UN:
945 case OP_COND_EXC_LT_UN:
953 case OP_COND_EXC_GT_UN:
959 case OP_COND_EXC_GE_UN:
965 case OP_COND_EXC_LE_UN:
976 g_assert_not_reached ();
981 #define COMPUTE_DISP(ins) \
982 if (ins->flags & MONO_INST_BRLABEL) { \
983 if (ins->inst_i0->inst_c0) \
984 disp = (ins->inst_i0->inst_c0 - ((guint8*)code - cfg->native_code)) >> 2; \
987 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
990 if (ins->inst_true_bb->native_offset) \
991 disp = (ins->inst_true_bb->native_offset - ((guint8*)code - cfg->native_code)) >> 2; \
994 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
998 #define EMIT_COND_BRANCH_GENERAL(ins,bop,cond,annul,filldelay) \
1001 COMPUTE_DISP(ins); \
1002 g_assert (sparc_is_imm22 (disp)); \
1003 sparc_ ## bop (code, (annul), cond, disp); \
1004 if (filldelay) sparc_nop (code); \
1007 #define EMIT_COND_BRANCH(ins,cond,annul,filldelay) EMIT_COND_BRANCH_GENERAL((ins),branch,(cond),annul,filldelay)
1008 #define EMIT_FLOAT_COND_BRANCH(ins,cond,annul,filldelay) EMIT_COND_BRANCH_GENERAL((ins),fbranch,(cond),annul,filldelay)
1010 #define EMIT_COND_BRANCH_PREDICTED(ins,cond,annul,filldelay) \
1014 COMPUTE_DISP(ins); \
1015 predict = (disp != 0) ? 1 : 0; \
1016 g_assert (sparc_is_imm19 (disp)); \
1017 sparc_branchp (code, (annul), (cond), sparc_icc_short, (predict), disp); \
1018 if (filldelay) sparc_nop (code); \
1021 #define EMIT_COND_BRANCH_BPR(ins,bop,predict,annul,filldelay) \
1024 COMPUTE_DISP(ins); \
1025 g_assert (sparc_is_imm22 (disp)); \
1026 sparc_ ## bop (code, (annul), (predict), ins->sreg2, disp); \
1027 if (filldelay) sparc_nop (code); \
1030 /* emit an exception if condition is fail */
1032 * We put the exception throwing code out-of-line, at the end of the method
1034 #define EMIT_COND_SYSTEM_EXCEPTION(ins,cond,sexc_name) do { \
1035 mono_add_patch_info (cfg, (guint8*)(code) - (cfg)->native_code, \
1036 MONO_PATCH_INFO_EXC, sexc_name); \
1038 sparc_branchp (code, 0, (cond), sparc_icc_short, 0, 0); \
1041 sparc_branch (code, 1, cond, 0); \
1046 #define EMIT_ALU_IMM(ins,op,setcc) do { \
1047 if (sparc_is_imm13 ((ins)->inst_imm)) \
1048 sparc_ ## op ## _imm (code, (setcc), (ins)->sreg1, ins->inst_imm, (ins)->dreg); \
1050 sparc_set (code, ins->inst_imm, sparc_o7); \
1051 sparc_ ## op (code, (setcc), (ins)->sreg1, sparc_o7, (ins)->dreg); \
1055 #define EMIT_LOAD_MEMBASE(ins,op) do { \
1056 if (sparc_is_imm13 (ins->inst_offset)) \
1057 sparc_ ## op ## _imm (code, ins->inst_basereg, ins->inst_offset, ins->dreg); \
1059 sparc_set (code, ins->inst_offset, sparc_o7); \
1060 sparc_ ## op (code, ins->inst_basereg, sparc_o7, ins->dreg); \
1065 #define EMIT_STORE_MEMBASE_IMM(ins,op) do { \
1067 if (ins->inst_imm == 0) \
1070 sparc_set (code, ins->inst_imm, sparc_o7); \
1073 if (!sparc_is_imm13 (ins->inst_offset)) { \
1074 sparc_set (code, ins->inst_offset, sparc_g1); \
1075 sparc_ ## op (code, sreg, ins->inst_destbasereg, sparc_g1); \
1078 sparc_ ## op ## _imm (code, sreg, ins->inst_destbasereg, ins->inst_offset); \
1081 #define EMIT_STORE_MEMBASE_REG(ins,op) do { \
1082 if (!sparc_is_imm13 (ins->inst_offset)) { \
1083 sparc_set (code, ins->inst_offset, sparc_o7); \
1084 sparc_ ## op (code, ins->sreg1, ins->inst_destbasereg, sparc_o7); \
1087 sparc_ ## op ## _imm (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset); \
1091 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1093 MonoInst *ins, *last_ins = NULL;
1098 switch (ins->opcode) {
1100 /* remove unnecessary multiplication with 1 */
1101 if (ins->inst_imm == 1) {
1102 if (ins->dreg != ins->sreg1) {
1103 ins->opcode = OP_MOVE;
1105 last_ins->next = ins->next;
1111 case OP_LOAD_MEMBASE:
1112 case OP_LOADI4_MEMBASE:
1114 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1115 * OP_LOAD_MEMBASE offset(basereg), reg
1117 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1118 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1119 ins->inst_basereg == last_ins->inst_destbasereg &&
1120 ins->inst_offset == last_ins->inst_offset) {
1121 if (ins->dreg == last_ins->sreg1) {
1122 last_ins->next = ins->next;
1126 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1127 ins->opcode = OP_MOVE;
1128 ins->sreg1 = last_ins->sreg1;
1132 * Note: reg1 must be different from the basereg in the second load
1133 * OP_LOAD_MEMBASE offset(basereg), reg1
1134 * OP_LOAD_MEMBASE offset(basereg), reg2
1136 * OP_LOAD_MEMBASE offset(basereg), reg1
1137 * OP_MOVE reg1, reg2
1139 } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1140 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1141 ins->inst_basereg != last_ins->dreg &&
1142 ins->inst_basereg == last_ins->inst_basereg &&
1143 ins->inst_offset == last_ins->inst_offset) {
1145 if (ins->dreg == last_ins->dreg) {
1146 last_ins->next = ins->next;
1150 ins->opcode = OP_MOVE;
1151 ins->sreg1 = last_ins->dreg;
1154 //g_assert_not_reached ();
1158 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1159 * OP_LOAD_MEMBASE offset(basereg), reg
1161 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1162 * OP_ICONST reg, imm
1164 } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1165 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1166 ins->inst_basereg == last_ins->inst_destbasereg &&
1167 ins->inst_offset == last_ins->inst_offset) {
1168 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1169 ins->opcode = OP_ICONST;
1170 ins->inst_c0 = last_ins->inst_imm;
1171 g_assert_not_reached (); // check this rule
1175 case OP_LOADU1_MEMBASE:
1176 case OP_LOADI1_MEMBASE:
1177 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1178 ins->inst_basereg == last_ins->inst_destbasereg &&
1179 ins->inst_offset == last_ins->inst_offset) {
1180 if (ins->dreg == last_ins->sreg1) {
1181 last_ins->next = ins->next;
1185 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1186 ins->opcode = OP_MOVE;
1187 ins->sreg1 = last_ins->sreg1;
1191 case OP_LOADU2_MEMBASE:
1192 case OP_LOADI2_MEMBASE:
1193 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1194 ins->inst_basereg == last_ins->inst_destbasereg &&
1195 ins->inst_offset == last_ins->inst_offset) {
1196 if (ins->dreg == last_ins->sreg1) {
1197 last_ins->next = ins->next;
1201 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1202 ins->opcode = OP_MOVE;
1203 ins->sreg1 = last_ins->sreg1;
1207 case OP_STOREI4_MEMBASE_IMM:
1208 /* Convert pairs of 0 stores to a dword 0 store */
1209 /* Used when initializing temporaries */
1210 /* We know sparc_fp is dword aligned */
1211 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM) &&
1212 (ins->inst_destbasereg == last_ins->inst_destbasereg) &&
1213 (ins->inst_destbasereg == sparc_fp) &&
1214 (ins->inst_offset < 0) &&
1215 ((ins->inst_offset % 8) == 0) &&
1216 ((ins->inst_offset == last_ins->inst_offset - 4)) &&
1217 (ins->inst_imm == 0) &&
1218 (last_ins->inst_imm == 0)) {
1220 last_ins->opcode = OP_STOREI8_MEMBASE_IMM;
1221 last_ins->inst_offset = ins->inst_offset;
1222 last_ins->next = ins->next;
1235 * Convert compare with zero+branch to BRcc
1238 * This only works in 64 bit mode, since it examines all 64
1239 * bits of the register.
1241 if (0 && sparcv9 && last_ins &&
1242 (last_ins->opcode == OP_COMPARE_IMM) &&
1243 (last_ins->inst_imm == 0)) {
1244 MonoInst *next = ins->next;
1245 switch (ins->opcode) {
1247 ins->opcode = OP_SPARC_BRZ;
1250 ins->opcode = OP_SPARC_BRNZ;
1253 ins->opcode = OP_SPARC_BRLZ;
1256 ins->opcode = OP_SPARC_BRGZ;
1259 ins->opcode = OP_SPARC_BRGEZ;
1262 ins->opcode = OP_SPARC_BRLEZ;
1265 g_assert_not_reached ();
1267 ins->sreg2 = last_ins->sreg1;
1269 last_ins->next = next;
1280 if (ins->dreg == ins->sreg1) {
1282 last_ins->next = ins->next;
1287 * OP_MOVE sreg, dreg
1288 * OP_MOVE dreg, sreg
1290 if (last_ins && last_ins->opcode == OP_MOVE &&
1291 ins->sreg1 == last_ins->dreg &&
1292 ins->dreg == last_ins->sreg1) {
1293 last_ins->next = ins->next;
1302 bb->last_ins = last_ins;
1305 /* Parameters used by the register allocator */
1307 /* Use %l4..%l7 as local registers */
1308 #define ARCH_CALLER_REGS (0xf0<<16)
1309 /* Use %f2..%f30 as the double precision floating point local registers */
1310 #define ARCH_CALLER_FREGS (0x55555554)
1313 #define DEBUG(a) if (cfg->verbose_level > 1) a
1315 #define reg_is_freeable(r) ((1 << (r)) & ARCH_CALLER_REGS)
1316 #define freg_is_freeable(r) (((1) << (r)) & ARCH_CALLER_FREGS)
1325 static const char*const * ins_spec = sparc_desc;
1328 print_ins (int i, MonoInst *ins)
1330 const char *spec = ins_spec [ins->opcode];
1331 g_print ("\t%-2d %s", i, mono_inst_name (ins->opcode));
1332 if (spec [MONO_INST_DEST]) {
1333 if (ins->dreg >= MONO_MAX_IREGS)
1334 g_print (" R%d <-", ins->dreg);
1336 if (spec [MONO_INST_DEST] == 'b')
1337 g_print (" [%s + 0x%x] <-", mono_arch_regname (ins->dreg), ins->inst_offset);
1339 g_print (" %s <-", mono_arch_regname (ins->dreg));
1341 if (spec [MONO_INST_SRC1]) {
1342 if (ins->sreg1 >= MONO_MAX_IREGS)
1343 g_print (" R%d", ins->sreg1);
1345 if (spec [MONO_INST_SRC1] == 'b')
1346 g_print (" [%s + 0x%x]", mono_arch_regname (ins->sreg1), ins->inst_offset);
1348 g_print (" %s", mono_arch_regname (ins->sreg1));
1350 if (spec [MONO_INST_SRC2]) {
1351 if (ins->sreg2 >= MONO_MAX_IREGS)
1352 g_print (" R%d", ins->sreg2);
1354 g_print (" %s", mono_arch_regname (ins->sreg2));
1356 if (spec [MONO_INST_CLOB])
1357 g_print (" clobbers: %c", spec [MONO_INST_CLOB]);
1362 print_regtrack (RegTrack *t, int num)
1368 for (i = 0; i < num; ++i) {
1371 if (i >= MONO_MAX_IREGS) {
1372 g_snprintf (buf, sizeof(buf), "R%d", i);
1375 r = mono_arch_regname (i);
1376 g_print ("liveness: %s [%d - %d]\n", r, t [i].born_in, t[i].last_use);
1380 typedef struct InstList InstList;
1388 static inline InstList*
1389 inst_list_prepend (MonoMemPool *pool, InstList *list, MonoInst *data)
1391 InstList *item = mono_mempool_alloc (pool, sizeof (InstList));
1400 #define STACK_OFFSETS_POSITIVE
1403 * returns the offset used by spillvar. It allocates a new
1404 * spill variable if necessary.
1407 mono_spillvar_offset (MonoCompile *cfg, int spillvar)
1409 MonoSpillInfo **si, *info;
1412 si = &cfg->spill_info;
1414 while (i <= spillvar) {
1417 *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
1419 cfg->stack_offset += sizeof (gpointer);
1420 info->offset = - cfg->stack_offset;
1424 return (*si)->offset;
1430 g_assert_not_reached ();
1435 mono_spillvar_offset_float (MonoCompile *cfg, int spillvar)
1437 MonoSpillInfo **si, *info;
1440 si = &cfg->spill_info_float;
1442 while (i <= spillvar) {
1445 *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
1447 cfg->stack_offset += sizeof (double);
1448 cfg->stack_offset = ALIGN_TO (cfg->stack_offset, 8);
1449 info->offset = - cfg->stack_offset;
1453 return (*si)->offset;
1459 g_assert_not_reached ();
1464 * Force the spilling of the variable in the symbolic register 'reg'.
1467 get_register_force_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, int reg)
1472 sel = cfg->rs->iassign [reg];
1473 /*i = cfg->rs->isymbolic [sel];
1474 g_assert (i == reg);*/
1476 spill = ++cfg->spill_count;
1477 cfg->rs->iassign [i] = -spill - 1;
1478 mono_regstate_free_int (cfg->rs, sel);
1479 /* we need to create a spill var and insert a load to sel after the current instruction */
1480 MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE);
1482 load->inst_basereg = cfg->frame_reg;
1483 load->inst_offset = mono_spillvar_offset (cfg, spill);
1485 while (ins->next != item->prev->data)
1488 load->next = ins->next;
1490 DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel)));
1491 i = mono_regstate_alloc_int (cfg->rs, 1 << sel);
1492 g_assert (i == sel);
1498 get_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, guint32 regmask, int reg)
1503 DEBUG (g_print ("start regmask to assign R%d: 0x%08x (R%d <- R%d R%d)\n", reg, regmask, ins->dreg, ins->sreg1, ins->sreg2));
1504 /* exclude the registers in the current instruction */
1505 if (reg != ins->sreg1 && (reg_is_freeable (ins->sreg1) || (ins->sreg1 >= MONO_MAX_IREGS && cfg->rs->iassign [ins->sreg1] >= 0))) {
1506 if (ins->sreg1 >= MONO_MAX_IREGS)
1507 regmask &= ~ (1 << cfg->rs->iassign [ins->sreg1]);
1509 regmask &= ~ (1 << ins->sreg1);
1510 DEBUG (g_print ("excluding sreg1 %s\n", mono_arch_regname (ins->sreg1)));
1512 if (reg != ins->sreg2 && (reg_is_freeable (ins->sreg2) || (ins->sreg2 >= MONO_MAX_IREGS && cfg->rs->iassign [ins->sreg2] >= 0))) {
1513 if (ins->sreg2 >= MONO_MAX_IREGS)
1514 regmask &= ~ (1 << cfg->rs->iassign [ins->sreg2]);
1516 regmask &= ~ (1 << ins->sreg2);
1517 DEBUG (g_print ("excluding sreg2 %s %d\n", mono_arch_regname (ins->sreg2), ins->sreg2));
1519 if (reg != ins->dreg && reg_is_freeable (ins->dreg)) {
1520 regmask &= ~ (1 << ins->dreg);
1521 DEBUG (g_print ("excluding dreg %s\n", mono_arch_regname (ins->dreg)));
1524 DEBUG (g_print ("available regmask: 0x%08x\n", regmask));
1525 g_assert (regmask); /* need at least a register we can free */
1527 /* we should track prev_use and spill the register that's farther */
1528 for (i = 0; i < MONO_MAX_IREGS; ++i) {
1529 if (regmask & (1 << i)) {
1531 DEBUG (g_print ("selected register %s has assignment %d\n", mono_arch_regname (sel), cfg->rs->iassign [sel]));
1535 i = cfg->rs->isymbolic [sel];
1536 spill = ++cfg->spill_count;
1537 cfg->rs->iassign [i] = -spill - 1;
1538 mono_regstate_free_int (cfg->rs, sel);
1539 /* we need to create a spill var and insert a load to sel after the current instruction */
1540 MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE);
1542 load->inst_basereg = cfg->frame_reg;
1543 load->inst_offset = mono_spillvar_offset (cfg, spill);
1545 while (ins->next != item->prev->data)
1548 load->next = ins->next;
1550 DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel)));
1551 i = mono_regstate_alloc_int (cfg->rs, 1 << sel);
1552 g_assert (i == sel);
1558 get_float_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, guint32 regmask, int reg)
1563 DEBUG (g_print ("start regmask to assign R%d: 0x%08x (R%d <- R%d R%d)\n", reg, regmask, ins->dreg, ins->sreg1, ins->sreg2));
1564 /* exclude the registers in the current instruction */
1565 if (reg != ins->sreg1 && (freg_is_freeable (ins->sreg1) || (ins->sreg1 >= MONO_MAX_FREGS && cfg->rs->fassign [ins->sreg1] >= 0))) {
1566 if (ins->sreg1 >= MONO_MAX_FREGS)
1567 regmask &= ~ (1 << cfg->rs->fassign [ins->sreg1]);
1569 regmask &= ~ (1 << ins->sreg1);
1570 DEBUG (g_print ("excluding sreg1 %s\n", mono_arch_regname (ins->sreg1)));
1572 if (reg != ins->sreg2 && (freg_is_freeable (ins->sreg2) || (ins->sreg2 >= MONO_MAX_FREGS && cfg->rs->fassign [ins->sreg2] >= 0))) {
1573 if (ins->sreg2 >= MONO_MAX_FREGS)
1574 regmask &= ~ (1 << cfg->rs->fassign [ins->sreg2]);
1576 regmask &= ~ (1 << ins->sreg2);
1577 DEBUG (g_print ("excluding sreg2 %s %d\n", mono_arch_regname (ins->sreg2), ins->sreg2));
1579 if (reg != ins->dreg && freg_is_freeable (ins->dreg)) {
1580 regmask &= ~ (1 << ins->dreg);
1581 DEBUG (g_print ("excluding dreg %s\n", mono_arch_regname (ins->dreg)));
1584 DEBUG (g_print ("available regmask: 0x%08x\n", regmask));
1585 g_assert (regmask); /* need at least a register we can free */
1587 /* we should track prev_use and spill the register that's farther */
1588 for (i = 0; i < MONO_MAX_FREGS; ++i) {
1589 if (regmask & (1 << i)) {
1591 DEBUG (g_print ("selected register %s has assignment %d\n", mono_arch_regname (sel), cfg->rs->fassign [sel]));
1595 i = cfg->rs->fsymbolic [sel];
1596 spill = ++cfg->spill_count;
1597 cfg->rs->fassign [i] = -spill - 1;
1598 mono_regstate_free_float(cfg->rs, sel);
1599 /* we need to create a spill var and insert a load to sel after the current instruction */
1600 MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
1602 load->inst_basereg = cfg->frame_reg;
1603 load->inst_offset = mono_spillvar_offset_float (cfg, spill);
1605 while (ins->next != item->prev->data)
1608 load->next = ins->next;
1610 DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel)));
1611 i = mono_regstate_alloc_float (cfg->rs, 1 << sel);
1612 g_assert (i == sel);
1618 create_copy_ins (MonoCompile *cfg, int dest, int src, MonoInst *ins)
1621 MONO_INST_NEW (cfg, copy, OP_MOVE);
1625 copy->next = ins->next;
1628 DEBUG (g_print ("\tforced copy from %s to %s\n", mono_arch_regname (src), mono_arch_regname (dest)));
1633 create_copy_ins_float (MonoCompile *cfg, int dest, int src, MonoInst *ins)
1636 MONO_INST_NEW (cfg, copy, OP_FMOVE);
1640 copy->next = ins->next;
1643 DEBUG (g_print ("\tforced copy from %s to %s\n", mono_arch_regname (src), mono_arch_regname (dest)));
1648 create_spilled_store (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins)
1651 MONO_INST_NEW (cfg, store, OP_STORE_MEMBASE_REG);
1653 store->inst_destbasereg = cfg->frame_reg;
1654 store->inst_offset = mono_spillvar_offset (cfg, spill);
1656 store->next = ins->next;
1659 DEBUG (g_print ("SPILLED STORE (%d at 0x%08x(%%sp)) R%d (from %s)\n", spill, store->inst_offset, prev_reg, mono_arch_regname (reg)));
1664 create_spilled_store_float (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins)
1667 MONO_INST_NEW (cfg, store, OP_STORER8_MEMBASE_REG);
1669 store->inst_destbasereg = cfg->frame_reg;
1670 store->inst_offset = mono_spillvar_offset_float (cfg, spill);
1672 store->next = ins->next;
1675 DEBUG (g_print ("SPILLED STORE (%d at 0x%08x(%%sp)) R%d (from %s)\n", spill, store->inst_offset, prev_reg, mono_arch_regname (reg)));
1680 insert_before_ins (MonoInst *ins, InstList *item, MonoInst* to_insert)
1683 g_assert (item->next);
1684 prev = item->next->data;
1686 while (prev->next != ins)
1688 to_insert->next = ins;
1689 prev->next = to_insert;
1691 * needed otherwise in the next instruction we can add an ins to the
1692 * end and that would get past this instruction.
1694 item->data = to_insert;
1698 alloc_int_reg (MonoCompile *cfg, InstList *curinst, MonoInst *ins, int sym_reg, guint32 allow_mask)
1700 int val = cfg->rs->iassign [sym_reg];
1704 /* the register gets spilled after this inst */
1707 val = mono_regstate_alloc_int (cfg->rs, allow_mask);
1709 val = get_register_spilling (cfg, curinst, ins, allow_mask, sym_reg);
1710 cfg->rs->iassign [sym_reg] = val;
1711 /* add option to store before the instruction for src registers */
1713 create_spilled_store (cfg, spill, val, sym_reg, ins);
1715 cfg->rs->isymbolic [val] = sym_reg;
1719 /* FIXME: Strange loads from the stack in basic-float.cs:test_2_rem */
1722 * Local register allocation.
1723 * We first scan the list of instructions and we save the liveness info of
1724 * each register (when the register is first used, when it's value is set etc.).
1725 * We also reverse the list of instructions (in the InstList list) because assigning
1726 * registers backwards allows for more tricks to be used.
1729 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1732 MonoRegState *rs = cfg->rs;
1734 RegTrack *reginfo, *reginfof;
1735 RegTrack *reginfo1, *reginfo2, *reginfod;
1736 InstList *tmp, *reversed = NULL;
1738 guint32 src1_mask, src2_mask, dest_mask;
1739 guint32 cur_iregs, cur_fregs;
1741 /* FIXME: Use caller saved regs and %i1-%2 for allocation */
1745 rs->next_vireg = bb->max_ireg;
1746 rs->next_vfreg = bb->max_freg;
1747 mono_regstate_assign (rs);
1748 reginfo = mono_mempool_alloc0 (cfg->mempool, sizeof (RegTrack) * rs->next_vireg);
1749 reginfof = mono_mempool_alloc0 (cfg->mempool, sizeof (RegTrack) * rs->next_vfreg);
1750 rs->ifree_mask = ARCH_CALLER_REGS;
1751 rs->ffree_mask = ARCH_CALLER_FREGS;
1755 DEBUG (g_print ("LOCAL regalloc: basic block: %d\n", bb->block_num));
1756 /* forward pass on the instructions to collect register liveness info */
1758 spec = ins_spec [ins->opcode];
1760 mono_print_tree_nl (ins);
1763 DEBUG (print_ins (i, ins));
1765 if (spec [MONO_INST_SRC1]) {
1766 if (spec [MONO_INST_SRC1] == 'f')
1767 reginfo1 = reginfof;
1770 reginfo1 [ins->sreg1].prev_use = reginfo1 [ins->sreg1].last_use;
1771 reginfo1 [ins->sreg1].last_use = i;
1775 if (spec [MONO_INST_SRC2]) {
1776 if (spec [MONO_INST_SRC2] == 'f')
1777 reginfo2 = reginfof;
1780 reginfo2 [ins->sreg2].prev_use = reginfo2 [ins->sreg2].last_use;
1781 reginfo2 [ins->sreg2].last_use = i;
1785 if (spec [MONO_INST_DEST]) {
1786 if (spec [MONO_INST_DEST] == 'f')
1787 reginfod = reginfof;
1790 if (spec [MONO_INST_DEST] != 'b') /* it's not just a base register */
1791 reginfod [ins->dreg].killed_in = i;
1792 reginfod [ins->dreg].prev_use = reginfod [ins->dreg].last_use;
1793 reginfod [ins->dreg].last_use = i;
1794 if (reginfod [ins->dreg].born_in == 0 || reginfod [ins->dreg].born_in > i)
1795 reginfod [ins->dreg].born_in = i;
1796 if (spec [MONO_INST_DEST] == 'l') {
1797 /* result in eax:edx, the virtual register is allocated sequentially */
1798 reginfod [ins->dreg + 1].prev_use = reginfod [ins->dreg + 1].last_use;
1799 reginfod [ins->dreg + 1].last_use = i;
1800 if (reginfod [ins->dreg + 1].born_in == 0 || reginfod [ins->dreg + 1].born_in > i)
1801 reginfod [ins->dreg + 1].born_in = i;
1806 reversed = inst_list_prepend (cfg->mempool, reversed, ins);
1811 cur_iregs = ARCH_CALLER_REGS;
1812 cur_fregs = ARCH_CALLER_FREGS;
1814 DEBUG (print_regtrack (reginfo, rs->next_vireg));
1815 DEBUG (print_regtrack (reginfof, rs->next_vfreg));
1818 int prev_dreg, prev_sreg1, prev_sreg2;
1821 spec = ins_spec [ins->opcode];
1822 DEBUG (g_print ("processing:"));
1823 DEBUG (print_ins (i, ins));
1825 /* make the register available for allocation: FIXME add fp reg */
1826 if (ins->opcode == OP_SETREG || ins->opcode == OP_SETREGIMM) {
1827 /* Dont free register which can't be allocated */
1828 if (reg_is_freeable (ins->dreg)) {
1829 cur_iregs |= 1 << ins->dreg;
1830 DEBUG (g_print ("adding %d to cur_iregs\n", ins->dreg));
1832 } else if (ins->opcode == OP_SETFREG) {
1833 if (freg_is_freeable (ins->dreg)) {
1834 cur_fregs |= 1 << ins->dreg;
1835 DEBUG (g_print ("adding %d to cur_fregs\n", ins->dreg));
1837 } else if (spec [MONO_INST_CLOB] == 'c') {
1838 MonoCallInst *cinst = (MonoCallInst*)ins;
1839 DEBUG (g_print ("excluding regs 0x%x from cur_iregs (0x%x)\n", cinst->used_iregs, cur_iregs));
1840 cur_iregs &= ~cinst->used_iregs;
1841 cur_fregs &= ~cinst->used_fregs;
1842 DEBUG (g_print ("available cur_iregs: 0x%x\n", cur_iregs));
1843 /* registers used by the calling convention are excluded from
1844 * allocation: they will be selectively enabled when they are
1845 * assigned by the special SETREG opcodes.
1848 dest_mask = src1_mask = src2_mask = cur_iregs;
1853 /* update for use with FP regs... */
1854 if (spec [MONO_INST_DEST] == 'f') {
1855 if (ins->dreg >= MONO_MAX_FREGS) {
1856 val = rs->fassign [ins->dreg];
1857 prev_dreg = ins->dreg;
1861 /* the register gets spilled after this inst */
1864 dest_mask = cur_fregs;
1865 val = mono_regstate_alloc_float (rs, dest_mask);
1867 val = get_float_register_spilling (cfg, tmp, ins, dest_mask, ins->dreg);
1868 rs->fassign [ins->dreg] = val;
1870 create_spilled_store_float (cfg, spill, val, prev_dreg, ins);
1872 DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_arch_regname (val), ins->dreg));
1873 rs->fsymbolic [val] = prev_dreg;
1878 if (freg_is_freeable (ins->dreg) && prev_dreg >= 0 && (reginfo [prev_dreg].born_in >= i || !(cur_fregs & (1 << ins->dreg)))) {
1879 DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins->dreg), prev_dreg, reginfo [prev_dreg].born_in));
1880 mono_regstate_free_float (rs, ins->dreg);
1882 } else if (ins->dreg >= MONO_MAX_IREGS) {
1883 val = rs->iassign [ins->dreg];
1884 prev_dreg = ins->dreg;
1888 /* the register gets spilled after this inst */
1891 val = mono_regstate_alloc_int (rs, dest_mask);
1893 val = get_register_spilling (cfg, tmp, ins, dest_mask, ins->dreg);
1894 rs->iassign [ins->dreg] = val;
1896 create_spilled_store (cfg, spill, val, prev_dreg, ins);
1898 DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_arch_regname (val), ins->dreg));
1899 rs->isymbolic [val] = prev_dreg;
1901 if (spec [MONO_INST_DEST] == 'l') {
1902 int hreg = prev_dreg + 1;
1903 val = rs->iassign [hreg];
1907 /* the register gets spilled after this inst */
1910 /* The second register must be a pair of the first */
1911 dest_mask = 1 << (rs->iassign [prev_dreg] + 1);
1912 val = mono_regstate_alloc_int (rs, dest_mask);
1914 val = get_register_spilling (cfg, tmp, ins, dest_mask, hreg);
1915 rs->iassign [hreg] = val;
1917 create_spilled_store (cfg, spill, val, hreg, ins);
1920 /* The second register must be a pair of the first */
1921 if (val != rs->iassign [prev_dreg] + 1) {
1922 dest_mask = 1 << (rs->iassign [prev_dreg] + 1);
1924 val = mono_regstate_alloc_int (rs, dest_mask);
1926 val = get_register_spilling (cfg, tmp, ins, dest_mask, hreg);
1928 create_copy_ins (cfg, rs->iassign [hreg], val, ins);
1930 rs->iassign [hreg] = val;
1934 DEBUG (g_print ("\tassigned hreg %s to dest R%d\n", mono_arch_regname (val), hreg));
1935 rs->isymbolic [val] = hreg;
1937 if (reg_is_freeable (val) && hreg >= 0 && (reginfo [hreg].born_in >= i && !(cur_iregs & (1 << val)))) {
1938 DEBUG (g_print ("\tfreeable %s (R%d)\n", mono_arch_regname (val), hreg));
1939 mono_regstate_free_int (rs, val);
1945 if (spec [MONO_INST_DEST] != 'f' && reg_is_freeable (ins->dreg) && prev_dreg >= 0 && (reginfo [prev_dreg].born_in >= i)) {
1946 DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins->dreg), prev_dreg, reginfo [prev_dreg].born_in));
1947 mono_regstate_free_int (rs, ins->dreg);
1953 if (spec [MONO_INST_SRC1] == 'f') {
1954 if (ins->sreg1 >= MONO_MAX_FREGS) {
1955 val = rs->fassign [ins->sreg1];
1956 prev_sreg1 = ins->sreg1;
1960 /* the register gets spilled after this inst */
1963 //g_assert (val == -1); /* source cannot be spilled */
1964 src1_mask = cur_fregs;
1965 val = mono_regstate_alloc_float (rs, src1_mask);
1967 val = get_float_register_spilling (cfg, tmp, ins, src1_mask, ins->sreg1);
1968 rs->fassign [ins->sreg1] = val;
1969 DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1));
1971 MonoInst *store = create_spilled_store_float (cfg, spill, val, prev_sreg1, NULL);
1972 insert_before_ins (ins, tmp, store);
1975 rs->fsymbolic [val] = prev_sreg1;
1980 } else if (ins->sreg1 >= MONO_MAX_IREGS) {
1981 val = rs->iassign [ins->sreg1];
1982 prev_sreg1 = ins->sreg1;
1986 /* the register gets spilled after this inst */
1989 if (0 && (ins->opcode == OP_MOVE) && reg_is_freeable (ins->dreg)) {
1991 * small optimization: the dest register is already allocated
1992 * but the src one is not: we can simply assign the same register
1993 * here and peephole will get rid of the instruction later.
1994 * This optimization may interfere with the clobbering handling:
1995 * it removes a mov operation that will be added again to handle clobbering.
1996 * There are also some other issues that should with make testjit.
1998 mono_regstate_alloc_int (rs, 1 << ins->dreg);
1999 val = rs->iassign [ins->sreg1] = ins->dreg;
2000 //g_assert (val >= 0);
2001 DEBUG (g_print ("\tfast assigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1));
2003 //g_assert (val == -1); /* source cannot be spilled */
2004 val = mono_regstate_alloc_int (rs, src1_mask);
2006 val = get_register_spilling (cfg, tmp, ins, src1_mask, ins->sreg1);
2007 rs->iassign [ins->sreg1] = val;
2008 DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1));
2011 MonoInst *store = create_spilled_store (cfg, spill, val, prev_sreg1, NULL);
2012 insert_before_ins (ins, tmp, store);
2015 rs->isymbolic [val] = prev_sreg1;
2024 if (spec [MONO_INST_SRC2] == 'f') {
2025 if (ins->sreg2 >= MONO_MAX_FREGS) {
2026 val = rs->fassign [ins->sreg2];
2027 prev_sreg2 = ins->sreg2;
2031 /* the register gets spilled after this inst */
2034 src2_mask = cur_fregs;
2035 val = mono_regstate_alloc_float (rs, src2_mask);
2037 val = get_float_register_spilling (cfg, tmp, ins, src2_mask, ins->sreg2);
2038 rs->fassign [ins->sreg2] = val;
2039 DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val), ins->sreg2));
2041 create_spilled_store_float (cfg, spill, val, prev_sreg2, ins);
2043 rs->fsymbolic [val] = prev_sreg2;
2048 } else if (ins->sreg2 >= MONO_MAX_IREGS) {
2049 val = rs->iassign [ins->sreg2];
2050 prev_sreg2 = ins->sreg2;
2054 /* the register gets spilled after this inst */
2057 val = mono_regstate_alloc_int (rs, src2_mask);
2059 val = get_register_spilling (cfg, tmp, ins, src2_mask, ins->sreg2);
2060 rs->iassign [ins->sreg2] = val;
2061 DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val), ins->sreg2));
2063 create_spilled_store (cfg, spill, val, prev_sreg2, ins);
2065 rs->isymbolic [val] = prev_sreg2;
2071 if (spec [MONO_INST_CLOB] == 'c') {
2073 guint32 clob_mask = ARCH_CALLER_REGS;
2074 for (j = 0; j < MONO_MAX_IREGS; ++j) {
2076 if ((clob_mask & s) && !(rs->ifree_mask & s) && j != ins->sreg1) {
2077 //g_warning ("register %s busy at call site\n", mono_arch_regname (j));
2081 /*if (reg_is_freeable (ins->sreg1) && prev_sreg1 >= 0 && reginfo [prev_sreg1].born_in >= i) {
2082 DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg1)));
2083 mono_regstate_free_int (rs, ins->sreg1);
2085 if (reg_is_freeable (ins->sreg2) && prev_sreg2 >= 0 && reginfo [prev_sreg2].born_in >= i) {
2086 DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg2)));
2087 mono_regstate_free_int (rs, ins->sreg2);
2090 //DEBUG (print_ins (i, ins));
2097 sparc_patch (guint8 *code, const guint8 *target)
2099 guint32 ins = *(guint32*)code;
2100 guint32 op = ins >> 30;
2101 guint32 op2 = (ins >> 22) & 0x7;
2102 guint32 rd = (ins >> 25) & 0x1f;
2103 gint32 disp = (target - code) >> 2;
2105 // g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2107 if ((op == 0) && (op2 == 2)) {
2108 if (!sparc_is_imm22 (disp))
2111 *(guint32*)code = ((ins >> 22) << 22) | (disp & 0x3fffff);
2113 else if ((op == 0) && (op2 == 1)) {
2114 if (!sparc_is_imm19 (disp))
2117 *(guint32*)code = ((ins >> 19) << 19) | (disp & 0x7ffff);
2119 else if ((op == 0) && (op2 == 3)) {
2120 if (!sparc_is_imm16 (disp))
2123 *(guint32*)code &= ~(0x180000 | 0x3fff);
2124 *(guint32*)code |= ((disp << 21) & (0x180000)) | (disp & 0x3fff);
2126 else if ((op == 0) && (op2 == 6)) {
2127 if (!sparc_is_imm22 (disp))
2130 *(guint32*)code = ((ins >> 22) << 22) | (disp & 0x3fffff);
2132 else if ((op == 0) && (op2 == 4)) {
2133 guint32 ins2 = *(guint32*)(code + 4);
2135 if (((ins2 >> 30) == 2) && (((ins2 >> 19) & 0x3f) == 2)) {
2136 /* sethi followed by or */
2137 guint32 *p = (guint32*)code;
2138 sparc_set (p, target, rd);
2139 while (p <= (code + 4))
2142 else if (ins2 == 0x01000000) {
2143 /* sethi followed by nop */
2144 guint32 *p = (guint32*)code;
2145 sparc_set (p, target, rd);
2146 while (p <= (code + 4))
2149 else if ((sparc_inst_op (ins2) == 3) && (sparc_inst_imm (ins2))) {
2150 /* sethi followed by load/store */
2151 guint32 t = (guint32)target;
2152 *(guint32*)code &= ~(0x3fffff);
2153 *(guint32*)code |= (t >> 10);
2154 *(guint32*)(code + 4) &= ~(0x3ff);
2155 *(guint32*)(code + 4) |= (t & 0x3ff);
2157 else if ((sparc_inst_op (ins2) == 2) && (sparc_inst_op3 (ins2) == 0x38) &&
2158 (sparc_inst_imm (ins2))) {
2159 /* sethi followed by jmpl */
2160 guint32 t = (guint32)target;
2161 *(guint32*)code &= ~(0x3fffff);
2162 *(guint32*)code |= (t >> 10);
2163 *(guint32*)(code + 4) &= ~(0x3ff);
2164 *(guint32*)(code + 4) |= (t & 0x3ff);
2169 else if (op == 01) {
2170 sparc_call_simple (code, target - code);
2172 else if ((op == 2) && (sparc_inst_op3 (ins) == 0x2) && sparc_inst_imm (ins)) {
2174 g_assert (sparc_is_imm13 (target));
2175 *(guint32*)code &= ~(0x1fff);
2176 *(guint32*)code |= (guint32)target;
2181 // g_print ("patched with 0x%08x\n", ins);
2185 * mono_sparc_emit_save_lmf:
2187 * Emit the code neccesary to push a new entry onto the lmf stack. Used by
2188 * trampolines as well.
2191 mono_sparc_emit_save_lmf (guint32 *code, guint32 lmf_offset)
2194 sparc_st_imm (code, sparc_o0, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr));
2195 /* Save previous_lmf */
2196 sparc_ld (code, sparc_o0, sparc_g0, sparc_o7);
2197 sparc_st_imm (code, sparc_o7, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf));
2199 sparc_add_imm (code, FALSE, sparc_fp, lmf_offset, sparc_o7);
2200 sparc_st (code, sparc_o7, sparc_o0, sparc_g0);
2206 mono_sparc_emit_restore_lmf (guint32 *code, guint32 lmf_offset)
2208 /* Load previous_lmf */
2209 sparc_ld_imm (code, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), sparc_l0);
2211 sparc_ld_imm (code, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), sparc_l1);
2212 /* *(lmf) = previous_lmf */
2213 sparc_st (code, sparc_l0, sparc_l1, sparc_g0);
2218 emit_save_sp_to_lmf (MonoCompile *cfg, guint32 *code)
2221 * Since register windows are saved to the current value of %sp, we need to
2222 * set the sp field in the lmf before the call, not in the prolog.
2224 if (cfg->method->save_lmf) {
2225 gint32 lmf_offset = - cfg->arch.lmf_offset;
2228 sparc_st_imm (code, sparc_sp, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, sp));
2235 emit_vret_token (MonoInst *ins, guint32 *code)
2237 MonoCallInst *call = (MonoCallInst*)ins;
2241 * The sparc ABI requires that calls to functions which return a structure
2242 * contain an additional unimpl instruction which is checked by the callee.
2244 if (call->signature->pinvoke && MONO_TYPE_ISSTRUCT(call->signature->ret)) {
2245 if (call->signature->ret->type == MONO_TYPE_TYPEDBYREF)
2246 size = mono_type_stack_size (call->signature->ret, NULL);
2248 size = mono_class_native_size (call->signature->ret->data.klass, NULL);
2249 sparc_unimp (code, size & 0xfff);
2256 emit_move_return_value (MonoInst *ins, guint32 *code)
2258 /* Move return value to the target register */
2259 /* FIXME: do this in the local reg allocator */
2260 switch (ins->opcode) {
2262 case OP_VOIDCALL_REG:
2263 case OP_VOIDCALL_MEMBASE:
2267 case OP_CALL_MEMBASE:
2268 sparc_mov_reg_reg (code, sparc_o0, ins->dreg);
2272 case OP_LCALL_MEMBASE:
2274 * ins->dreg is the least significant reg due to the lreg: LCALL rule
2277 sparc_mov_reg_reg (code, sparc_o0, ins->dreg + 1);
2278 sparc_mov_reg_reg (code, sparc_o1, ins->dreg);
2282 case OP_FCALL_MEMBASE:
2283 sparc_fmovs (code, sparc_f0, ins->dreg);
2284 if (((MonoCallInst*)ins)->signature->ret->type == MONO_TYPE_R4)
2285 sparc_fstod (code, ins->dreg, ins->dreg);
2287 sparc_fmovs (code, sparc_f1, ins->dreg + 1);
2291 case OP_VCALL_MEMBASE:
2301 * emit_load_volatile_arguments:
2303 * Load volatile arguments from the stack to the original input registers.
2304 * Required before a tail call.
2307 emit_load_volatile_arguments (MonoCompile *cfg, guint32 *code)
2309 MonoMethod *method = cfg->method;
2310 MonoMethodSignature *sig;
2315 /* FIXME: Generate intermediate code instead */
2317 sig = method->signature;
2319 cinfo = get_call_info (sig, FALSE);
2321 /* This is the opposite of the code in emit_prolog */
2323 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2324 ArgInfo *ainfo = cinfo->args + i;
2325 guint32 stack_offset;
2327 inst = cfg->varinfo [i];
2329 if (sig->hasthis && (i == 0))
2330 arg_type = mono_defaults.object_class;
2332 arg_type = sig->params [i - sig->hasthis];
2334 stack_offset = ainfo->offset + 68;
2335 ireg = sparc_i0 + ainfo->reg;
2337 if (ainfo->storage == ArgInSplitRegStack) {
2338 g_assert (inst->opcode == OP_REGOFFSET);
2339 if (!sparc_is_imm13 (stack_offset))
2341 sparc_st_imm (code, inst->inst_basereg, stack_offset, sparc_i5);
2344 if (!arg_type->byref && (arg_type->type == MONO_TYPE_R8)) {
2345 if (ainfo->storage == ArgInIRegPair) {
2346 if (!sparc_is_imm13 (inst->inst_offset + 4))
2348 sparc_ld_imm (code, inst->inst_basereg, inst->inst_offset, ireg);
2349 sparc_ld_imm (code, inst->inst_basereg, inst->inst_offset + 4, ireg + 1);
2352 if (ainfo->storage == ArgInSplitRegStack) {
2353 if (stack_offset != inst->inst_offset) {
2354 sparc_ld_imm (code, inst->inst_basereg, inst->inst_offset, sparc_i5);
2355 sparc_ld_imm (code, inst->inst_basereg, inst->inst_offset + 4, sparc_o7);
2356 sparc_st_imm (code, sparc_o7, sparc_fp, stack_offset + 4);
2361 if (ainfo->storage == ArgOnStackPair) {
2362 if (stack_offset != inst->inst_offset) {
2363 /* stack_offset is not dword aligned, so we need to make a copy */
2364 sparc_ld_imm (code, inst->inst_basereg, inst->inst_offset, sparc_o7);
2365 sparc_st_imm (code, sparc_o7, sparc_fp, stack_offset);
2367 sparc_ld_imm (code, inst->inst_basereg, inst->inst_offset + 4, sparc_o7);
2368 sparc_st_imm (code, sparc_o7, sparc_fp, stack_offset + 4);
2373 g_assert_not_reached ();
2376 if ((ainfo->storage == ArgInIReg) && (inst->opcode != OP_REGVAR)) {
2377 /* Argument in register, but need to be saved to stack */
2378 if (!sparc_is_imm13 (stack_offset))
2380 if (stack_offset & 0x1)
2381 /* FIXME: Is this ldsb or ldub ? */
2382 sparc_ldsb_imm (code, inst->inst_basereg, stack_offset, ireg);
2384 if (stack_offset & 0x2)
2385 sparc_ldsh_imm (code, inst->inst_basereg, stack_offset, ireg);
2387 sparc_ld_imm (code, inst->inst_basereg, stack_offset, ireg);
2390 if ((ainfo->storage == ArgInIRegPair) && (inst->opcode != OP_REGVAR)) {
2391 /* Argument in regpair, but need to be saved to stack */
2392 if (!sparc_is_imm13 (inst->inst_offset + 4))
2394 sparc_ld_imm (code, inst->inst_basereg, inst->inst_offset, ireg);
2395 sparc_st_imm (code, inst->inst_basereg, inst->inst_offset + 4, ireg + 1);
2398 if ((ainfo->storage == ArgInSplitRegStack) || (ainfo->storage == ArgOnStack))
2399 if (inst->opcode == OP_REGVAR)
2400 /* FIXME: Load the argument into memory */
2410 * mono_sparc_is_virtual_call:
2412 * Determine whenever the instruction at CODE is a virtual call.
2415 mono_sparc_is_virtual_call (guint32 *code)
2422 if ((sparc_inst_op (*code) == 0x2) && (sparc_inst_op3 (*code) == 0x38)) {
2424 * Register indirect call. If it is a virtual call, then the
2425 * instruction in the delay slot is a special kind of nop.
2428 /* Construct special nop */
2429 sparc_or_imm (p, FALSE, sparc_g0, 0xca, sparc_g0);
2432 if (code [1] == p [0])
2440 * mono_sparc_get_vcall_slot_addr:
2442 * Determine the vtable slot used by a virtual call.
2445 mono_sparc_get_vcall_slot_addr (guint32 *code, guint32 *fp)
2447 guint32 ins = code [0];
2448 guint32 prev_ins = code [-1];
2450 mono_sparc_flushw ();
2452 if ((sparc_inst_op (ins) == 0x2) && (sparc_inst_op3 (ins) == 0x38)) {
2453 if ((sparc_inst_op (prev_ins) == 0x3) && (sparc_inst_op3 (prev_ins) == 0)) {
2454 /* ld [r1 + CONST ], r2; call r2 */
2455 guint32 base = sparc_inst_rs1 (prev_ins);
2456 guint32 disp = sparc_inst_imm13 (prev_ins);
2459 g_assert (sparc_inst_rd (prev_ins) == sparc_inst_rs1 (ins));
2461 g_assert ((base >= sparc_o0) && (base <= sparc_i7));
2463 base_val = fp [base - 16];
2465 return (gpointer)((guint8*)base_val + disp);
2468 g_assert_not_reached ();
2471 g_assert_not_reached ();
2477 * Some conventions used in the following code.
2478 * 2) The only scratch registers we have are o7 and g1. We try to
2479 * stick to o7 when we can, and use g1 when necessary.
2483 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2488 guint32 *code = (guint32*)(cfg->native_code + cfg->code_len);
2489 MonoInst *last_ins = NULL;
2492 if (cfg->opt & MONO_OPT_PEEPHOLE)
2493 peephole_pass (cfg, bb);
2495 if (cfg->verbose_level > 2)
2496 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2498 cpos = bb->max_offset;
2500 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2508 offset = (guint8*)code - cfg->native_code;
2510 max_len = ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
2512 if (offset > (cfg->code_size - max_len - 16)) {
2513 cfg->code_size *= 2;
2514 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2515 code = (guint32*)(cfg->native_code + offset);
2517 code_start = (guint8*)code;
2518 // if (ins->cil_code)
2519 // g_print ("cil code\n");
2521 switch (ins->opcode) {
2522 case OP_STOREI1_MEMBASE_IMM:
2523 EMIT_STORE_MEMBASE_IMM (ins, stb);
2525 case OP_STOREI2_MEMBASE_IMM:
2526 EMIT_STORE_MEMBASE_IMM (ins, sth);
2528 case OP_STORE_MEMBASE_IMM:
2529 case OP_STOREI4_MEMBASE_IMM:
2530 EMIT_STORE_MEMBASE_IMM (ins, st);
2532 case OP_STOREI8_MEMBASE_IMM:
2533 /* Only generated by peephole opts */
2534 g_assert ((ins->inst_offset % 8) == 0);
2535 g_assert (ins->inst_imm == 0);
2536 EMIT_STORE_MEMBASE_IMM (ins, stx);
2538 case OP_STOREI1_MEMBASE_REG:
2539 EMIT_STORE_MEMBASE_REG (ins, stb);
2541 case OP_STOREI2_MEMBASE_REG:
2542 EMIT_STORE_MEMBASE_REG (ins, sth);
2544 case OP_STORE_MEMBASE_REG:
2545 case OP_STOREI4_MEMBASE_REG:
2546 EMIT_STORE_MEMBASE_REG (ins, st);
2548 case OP_STOREI8_MEMBASE_REG:
2549 /* Only used by OP_MEMSET */
2550 EMIT_STORE_MEMBASE_REG (ins, std);
2555 sparc_ld (code, ins->inst_p0, sparc_g0, ins->dreg);
2557 /* The cast IS BAD (maybe). But it needs to be done... */
2559 sparc_set (code, (guint)ins->inst_p0, ins->dreg);
2560 sparc_ld (code, ins->dreg, sparc_g0, ins->dreg);
2562 case OP_LOAD_MEMBASE:
2563 case OP_LOADI4_MEMBASE:
2564 case OP_LOADU4_MEMBASE:
2565 EMIT_LOAD_MEMBASE (ins, ld);
2567 case OP_LOADU1_MEMBASE:
2568 EMIT_LOAD_MEMBASE (ins, ldub);
2570 case OP_LOADI1_MEMBASE:
2571 EMIT_LOAD_MEMBASE (ins, ldsb);
2573 case OP_LOADU2_MEMBASE:
2574 EMIT_LOAD_MEMBASE (ins, lduh);
2576 case OP_LOADI2_MEMBASE:
2577 EMIT_LOAD_MEMBASE (ins, ldsh);
2580 sparc_sll_imm (code, ins->sreg1, 24, sparc_o7);
2581 sparc_sra_imm (code, sparc_o7, 24, ins->dreg);
2584 sparc_sll_imm (code, ins->sreg1, 16, sparc_o7);
2585 sparc_sra_imm (code, sparc_o7, 16, ins->dreg);
2587 /* GCC does this one differently. Don't ask me WHY. */
2589 sparc_and_imm (code, FALSE, ins->sreg1, 0xff, ins->dreg);
2592 sparc_sll_imm (code, ins->sreg1, 16, sparc_o7);
2593 sparc_srl_imm (code, sparc_o7, 16, ins->dreg);
2596 sparc_cmp (code, ins->sreg1, ins->sreg2);
2598 case OP_COMPARE_IMM:
2599 if (sparc_is_imm13 (ins->inst_imm))
2600 sparc_cmp_imm (code, ins->sreg1, ins->inst_imm);
2602 sparc_set (code, ins->inst_imm, sparc_o7);
2603 sparc_cmp (code, ins->sreg1, sparc_o7);
2606 case OP_X86_TEST_NULL:
2607 sparc_cmp_imm (code, ins->sreg1, 0);
2611 * gdb does not like encountering 'ta 1' in the debugged code. So
2612 * instead of emitting a trap, we emit a call a C function and place a
2615 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, mono_sparc_break);
2616 sparc_call_simple (code, 0);
2620 sparc_add (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
2623 sparc_add (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2626 EMIT_ALU_IMM (ins, add, FALSE);
2629 /* according to inssel-long32.brg, this should set cc */
2630 sparc_addx (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
2633 EMIT_ALU_IMM (ins, addx, TRUE);
2636 sparc_sub (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
2639 sparc_sub (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2642 // we add the negated value
2643 if (sparc_is_imm13 (- ins->inst_imm))
2644 sparc_add_imm (code, FALSE, ins->sreg1, -ins->inst_imm, ins->dreg);
2646 sparc_set (code, - ins->inst_imm, sparc_o7);
2647 sparc_add (code, FALSE, ins->sreg1, sparc_o7, ins->dreg);
2651 /* according to inssel-long32.brg, this should set cc */
2652 sparc_subx (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
2655 EMIT_ALU_IMM (ins, subx, TRUE);
2658 sparc_and (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2661 EMIT_ALU_IMM (ins, and, FALSE);
2664 /* Sign extend sreg1 into %y */
2665 sparc_sra_imm (code, ins->sreg1, 31, sparc_o7);
2666 sparc_wry (code, sparc_o7, sparc_g0);
2667 sparc_sdiv (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2670 sparc_wry (code, sparc_g0, sparc_g0);
2671 sparc_udiv (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2676 /* Transform division into a shift */
2677 for (i = 1; i < 30; ++i) {
2679 if (ins->inst_imm == imm)
2685 sparc_srl_imm (code, ins->sreg1, 31, sparc_o7);
2686 sparc_add (code, FALSE, ins->sreg1, sparc_o7, ins->dreg);
2687 sparc_sra_imm (code, ins->dreg, 1, ins->dreg);
2690 /* http://compilers.iecc.com/comparch/article/93-04-079 */
2691 sparc_sra_imm (code, ins->sreg1, 31, sparc_o7);
2692 sparc_srl_imm (code, sparc_o7, 32 - i, sparc_o7);
2693 sparc_add (code, FALSE, ins->sreg1, sparc_o7, ins->dreg);
2694 sparc_sra_imm (code, ins->dreg, i, ins->dreg);
2698 /* Sign extend sreg1 into %y */
2699 sparc_sra_imm (code, ins->sreg1, 31, sparc_o7);
2700 sparc_wry (code, sparc_o7, sparc_g0);
2701 EMIT_ALU_IMM (ins, sdiv, FALSE);
2706 /* Sign extend sreg1 into %y */
2707 sparc_sra_imm (code, ins->sreg1, 31, sparc_o7);
2708 sparc_wry (code, sparc_o7, sparc_g0);
2709 sparc_sdiv (code, FALSE, ins->sreg1, ins->sreg2, sparc_o7);
2710 sparc_smul (code, FALSE, ins->sreg2, sparc_o7, sparc_o7);
2711 sparc_sub (code, FALSE, ins->sreg1, sparc_o7, ins->dreg);
2714 sparc_wry (code, sparc_g0, sparc_g0);
2715 sparc_udiv (code, FALSE, ins->sreg1, ins->sreg2, sparc_o7);
2716 sparc_umul (code, FALSE, ins->sreg2, sparc_o7, sparc_o7);
2717 sparc_sub (code, FALSE, ins->sreg1, sparc_o7, ins->dreg);
2720 /* Sign extend sreg1 into %y */
2721 sparc_sra_imm (code, ins->sreg1, 31, sparc_o7);
2722 sparc_wry (code, sparc_o7, sparc_g0);
2723 if (!sparc_is_imm13 (ins->inst_imm)) {
2724 sparc_set (code, ins->inst_imm, sparc_g1);
2725 sparc_sdiv (code, FALSE, ins->sreg1, sparc_g1, sparc_o7);
2726 sparc_smul (code, FALSE, sparc_o7, sparc_g1, sparc_o7);
2729 sparc_sdiv_imm (code, FALSE, ins->sreg1, ins->inst_imm, sparc_o7);
2730 sparc_smul_imm (code, FALSE, sparc_o7, ins->inst_imm, sparc_o7);
2732 sparc_sub (code, FALSE, ins->sreg1, sparc_o7, ins->dreg);
2735 sparc_or (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2738 EMIT_ALU_IMM (ins, or, FALSE);
2741 sparc_xor (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2744 EMIT_ALU_IMM (ins, xor, FALSE);
2747 sparc_sll (code, ins->sreg1, ins->sreg2, ins->dreg);
2750 if (sparc_is_imm13 (ins->inst_imm))
2751 sparc_sll_imm (code, ins->sreg1, ins->inst_imm, ins->dreg);
2753 sparc_set (code, ins->inst_imm, sparc_o7);
2754 sparc_sll (code, ins->sreg1, sparc_o7, ins->dreg);
2758 sparc_sra (code, ins->sreg1, ins->sreg2, ins->dreg);
2761 if (sparc_is_imm13 (ins->inst_imm))
2762 sparc_sra_imm (code, ins->sreg1, ins->inst_imm, ins->dreg);
2764 sparc_set (code, ins->inst_imm, sparc_o7);
2765 sparc_sra (code, ins->sreg1, sparc_o7, ins->dreg);
2769 if (sparc_is_imm13 (ins->inst_imm))
2770 sparc_srl_imm (code, ins->sreg1, ins->inst_imm, ins->dreg);
2772 sparc_set (code, ins->inst_imm, sparc_o7);
2773 sparc_srl (code, ins->sreg1, sparc_o7, ins->dreg);
2777 sparc_srl (code, ins->sreg1, ins->sreg2, ins->dreg);
2780 /* can't use sparc_not */
2781 sparc_xnor (code, FALSE, ins->sreg1, sparc_g0, ins->dreg);
2784 /* can't use sparc_neg */
2785 sparc_sub (code, FALSE, sparc_g0, ins->sreg1, ins->dreg);
2788 sparc_smul (code, FALSE, ins->sreg1, ins->sreg2, ins->dreg);
2793 /* Transform multiplication into a shift */
2794 for (i = 1; i < 30; ++i) {
2796 if (ins->inst_imm == imm)
2800 sparc_sll_imm (code, ins->sreg1, i, ins->dreg);
2802 EMIT_ALU_IMM (ins, smul, FALSE);
2806 sparc_smul (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
2807 sparc_rdy (code, sparc_g1);
2808 sparc_sra_imm (code, ins->dreg, 31, sparc_o7);
2809 sparc_cmp (code, sparc_g1, sparc_o7);
2810 EMIT_COND_SYSTEM_EXCEPTION (ins, sparc_bne, "OverflowException");
2812 case CEE_MUL_OVF_UN:
2813 sparc_umul (code, TRUE, ins->sreg1, ins->sreg2, ins->dreg);
2814 sparc_rdy (code, sparc_o7);
2815 sparc_cmp (code, sparc_o7, sparc_g0);
2816 EMIT_COND_SYSTEM_EXCEPTION (ins, sparc_bne, "OverflowException");
2820 sparc_set (code, ins->inst_c0, ins->dreg);
2823 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2824 sparc_set (code, 0xffffff, ins->dreg);
2830 if (ins->sreg1 != ins->dreg)
2831 sparc_mov_reg_reg (code, ins->sreg1, ins->dreg);
2834 if (cfg->method->save_lmf)
2837 code = emit_load_volatile_arguments (cfg, code);
2838 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2839 sparc_set (code, 0xffffff, sparc_o7);
2840 sparc_jmpl (code, sparc_o7, sparc_g0, sparc_g0);
2841 /* Restore parent frame in delay slot */
2842 sparc_restore_imm (code, sparc_g0, 0, sparc_g0);
2845 /* ensure ins->sreg1 is not NULL */
2846 sparc_ld_imm (code, ins->sreg1, 0, sparc_g0);
2849 sparc_add_imm (code, FALSE, sparc_fp, cfg->sig_cookie, sparc_o7);
2850 sparc_st_imm (code, sparc_o7, ins->sreg1, 0);
2857 call = (MonoCallInst*)ins;
2858 g_assert (!call->virtual);
2859 code = emit_save_sp_to_lmf (cfg, code);
2860 if (ins->flags & MONO_INST_HAS_METHOD)
2861 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_METHOD, call->method);
2863 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_ABS, call->fptr);
2864 sparc_call_simple (code, 0);
2867 code = emit_vret_token (ins, code);
2868 code = emit_move_return_value (ins, code);
2873 case OP_VOIDCALL_REG:
2875 call = (MonoCallInst*)ins;
2876 code = emit_save_sp_to_lmf (cfg, code);
2877 sparc_jmpl (code, ins->sreg1, sparc_g0, sparc_callsite);
2879 * We emit a special kind of nop in the delay slot to tell the
2880 * trampoline code that this is a virtual call, thus an unbox
2881 * trampoline might need to be called.
2884 sparc_or_imm (code, FALSE, sparc_g0, 0xca, sparc_g0);
2888 code = emit_vret_token (ins, code);
2889 code = emit_move_return_value (ins, code);
2891 case OP_FCALL_MEMBASE:
2892 case OP_LCALL_MEMBASE:
2893 case OP_VCALL_MEMBASE:
2894 case OP_VOIDCALL_MEMBASE:
2895 case OP_CALL_MEMBASE:
2896 call = (MonoCallInst*)ins;
2897 g_assert (sparc_is_imm13 (ins->inst_offset));
2898 code = emit_save_sp_to_lmf (cfg, code);
2899 sparc_ld_imm (code, ins->inst_basereg, ins->inst_offset, sparc_o7);
2900 sparc_jmpl (code, sparc_o7, sparc_g0, sparc_callsite);
2902 sparc_or_imm (code, FALSE, sparc_g0, 0xca, sparc_g0);
2906 code = emit_vret_token (ins, code);
2907 code = emit_move_return_value (ins, code);
2910 if (cfg->method->signature->ret->type == MONO_TYPE_R4)
2911 sparc_fdtos (code, ins->sreg1, sparc_f0);
2913 sparc_fmovs (code, ins->sreg1, ins->dreg);
2914 sparc_fmovs (code, ins->sreg1 + 1, ins->dreg + 1);
2918 g_assert_not_reached ();
2921 /* Keep alignment */
2922 sparc_add_imm (code, FALSE, ins->sreg1, MONO_ARCH_FRAME_ALIGNMENT - 1, ins->dreg);
2923 sparc_set (code, ~(MONO_ARCH_FRAME_ALIGNMENT - 1), sparc_o7);
2924 sparc_and (code, FALSE, ins->dreg, sparc_o7, ins->dreg);
2925 sparc_sub (code, FALSE, sparc_sp, ins->dreg, ins->dreg);
2926 /* Keep %sp valid at all times */
2927 sparc_mov_reg_reg (code, ins->dreg, sparc_sp);
2928 g_assert (sparc_is_imm13 (cfg->arch.localloc_offset));
2929 sparc_add_imm (code, FALSE, ins->dreg, cfg->arch.localloc_offset, ins->dreg);
2931 case OP_SPARC_LOCALLOC_IMM: {
2932 guint32 offset = ins->inst_c0;
2933 offset = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
2934 if (sparc_is_imm13 (offset))
2935 sparc_sub_imm (code, FALSE, sparc_sp, offset, sparc_sp);
2937 sparc_set (code, offset, sparc_o7);
2938 sparc_sub (code, FALSE, sparc_sp, sparc_o7, sparc_sp);
2940 sparc_mov_reg_reg (code, sparc_sp, ins->dreg);
2941 g_assert (sparc_is_imm13 (cfg->arch.localloc_offset));
2942 sparc_add_imm (code, FALSE, ins->dreg, cfg->arch.localloc_offset, ins->dreg);
2946 /* The return is done in the epilog */
2947 g_assert_not_reached ();
2950 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_INTERNAL_METHOD,
2951 (gpointer)"mono_arch_throw_exception");
2952 sparc_call_simple (code, 0);
2954 sparc_mov_reg_reg (code, ins->sreg1, sparc_o0);
2956 case OP_START_HANDLER: {
2958 * The START_HANDLER instruction marks the beginning of a handler
2959 * block. It is called using a call instruction, so %o7 contains
2960 * the return address. Since the handler executes in the same stack
2961 * frame as the method itself, we can't use save/restore to save
2962 * the return address. Instead, we save it into a dedicated
2965 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
2966 if (!sparc_is_imm13 (spvar->inst_offset)) {
2967 sparc_set (code, spvar->inst_offset, sparc_g0);
2968 sparc_st (code, sparc_o7, spvar->inst_basereg, sparc_g0);
2971 sparc_st_imm (code, sparc_o7, spvar->inst_basereg, spvar->inst_offset);
2974 case OP_ENDFILTER: {
2975 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
2976 if (!sparc_is_imm13 (spvar->inst_offset)) {
2977 sparc_set (code, spvar->inst_offset, sparc_g0);
2978 sparc_ld (code, spvar->inst_basereg, sparc_g0, sparc_o7);
2981 sparc_ld_imm (code, spvar->inst_basereg, spvar->inst_offset, sparc_o7);
2982 sparc_jmpl_imm (code, sparc_o7, 8, sparc_g0);
2984 sparc_mov_reg_reg (code, ins->sreg1, sparc_o0);
2987 case CEE_ENDFINALLY: {
2988 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
2989 if (!sparc_is_imm13 (spvar->inst_offset)) {
2990 sparc_set (code, spvar->inst_offset, sparc_g0);
2991 sparc_ld (code, spvar->inst_basereg, sparc_g0, sparc_o7);
2994 sparc_ld_imm (code, spvar->inst_basereg, spvar->inst_offset, sparc_o7);
2995 sparc_jmpl_imm (code, sparc_o7, 8, sparc_g0);
2999 case OP_CALL_HANDLER:
3000 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3001 sparc_call_simple (code, 0);
3005 ins->inst_c0 = (guint8*)code - cfg->native_code;
3008 //g_print ("target: %p, next: %p, curr: %p, last: %p\n", ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
3009 if ((ins->inst_target_bb == bb->next_bb) && ins == bb->last_ins)
3011 if (ins->flags & MONO_INST_BRLABEL) {
3012 if (ins->inst_i0->inst_c0) {
3013 gint32 disp = (ins->inst_i0->inst_c0 - ((guint8*)code - cfg->native_code)) >> 2;
3014 g_assert (sparc_is_imm22 (disp));
3015 sparc_branch (code, 1, sparc_ba, disp);
3017 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3018 sparc_branch (code, 1, sparc_ba, 0);
3021 if (ins->inst_target_bb->native_offset) {
3022 gint32 disp = (ins->inst_target_bb->native_offset - ((guint8*)code - cfg->native_code)) >> 2;
3023 g_assert (sparc_is_imm22 (disp));
3024 sparc_branch (code, 1, sparc_ba, disp);
3026 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3027 sparc_branch (code, 1, sparc_ba, 0);
3033 sparc_jmp (code, ins->sreg1, sparc_g0);
3041 //if (cfg->opt & MONO_OPT_CMOV) {
3043 sparc_clr_reg (code, ins->dreg);
3044 sparc_movcc_imm (code, sparc_icc, opcode_to_sparc_cond (ins->opcode), 1, ins->dreg);
3047 sparc_clr_reg (code, ins->dreg);
3048 sparc_branch (code, 1, opcode_to_sparc_cond (ins->opcode), 2);
3050 sparc_set (code, 1, ins->dreg);
3053 case OP_COND_EXC_EQ:
3054 case OP_COND_EXC_NE_UN:
3055 case OP_COND_EXC_LT:
3056 case OP_COND_EXC_LT_UN:
3057 case OP_COND_EXC_GT:
3058 case OP_COND_EXC_GT_UN:
3059 case OP_COND_EXC_GE:
3060 case OP_COND_EXC_GE_UN:
3061 case OP_COND_EXC_LE:
3062 case OP_COND_EXC_LE_UN:
3063 case OP_COND_EXC_OV:
3064 case OP_COND_EXC_NO:
3066 case OP_COND_EXC_NC:
3067 EMIT_COND_SYSTEM_EXCEPTION (ins, opcode_to_sparc_cond (ins->opcode), ins->inst_p1);
3080 EMIT_COND_BRANCH_PREDICTED (ins, opcode_to_sparc_cond (ins->opcode), 1, 1);
3082 EMIT_COND_BRANCH (ins, opcode_to_sparc_cond (ins->opcode), 1, 1);
3086 /* We misuse the macro arguments */
3087 EMIT_COND_BRANCH_BPR (ins, brz, 1, 1, 1);
3089 case OP_SPARC_BRLEZ:
3090 EMIT_COND_BRANCH_BPR (ins, brlez, 1, 1, 1);
3093 EMIT_COND_BRANCH_BPR (ins, brlz, 1, 1, 1);
3096 EMIT_COND_BRANCH_BPR (ins, brnz, 1, 1, 1);
3099 EMIT_COND_BRANCH_BPR (ins, brgz, 1, 1, 1);
3101 case OP_SPARC_BRGEZ:
3102 EMIT_COND_BRANCH_BPR (ins, brgez, 1, 1, 1);
3105 /* floating point opcodes */
3107 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R8, ins->inst_p0);
3108 sparc_sethi (code, 0, sparc_o7);
3109 sparc_lddf_imm (code, sparc_o7, 0, ins->dreg);
3112 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_R4, ins->inst_p0);
3113 sparc_sethi (code, 0, sparc_o7);
3114 sparc_ldf_imm (code, sparc_o7, 0, ins->dreg);
3116 /* Extend to double */
3117 sparc_fstod (code, ins->dreg, ins->dreg);
3119 case OP_STORER8_MEMBASE_REG:
3120 if (!sparc_is_imm13 (ins->inst_offset + 4)) {
3121 sparc_set (code, ins->inst_offset, sparc_o7);
3122 if (ins->inst_offset % 8) {
3124 sparc_add (code, FALSE, ins->inst_destbasereg, sparc_o7, sparc_o7);
3125 sparc_stf (code, ins->sreg1, sparc_o7, sparc_g0);
3126 sparc_stf_imm (code, ins->sreg1 + 1, sparc_o7, 4);
3128 sparc_stdf (code, ins->sreg1, ins->inst_destbasereg, sparc_o7);
3131 if (ins->inst_offset % 8) {
3133 sparc_stf_imm (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3134 sparc_stf_imm (code, ins->sreg1 + 1, ins->inst_destbasereg, ins->inst_offset + 4);
3136 sparc_stdf_imm (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3139 case OP_LOADR8_MEMBASE:
3140 g_assert ((ins->inst_offset % 8) == 0);
3141 EMIT_LOAD_MEMBASE (ins, lddf);
3143 case OP_STORER4_MEMBASE_REG:
3144 /* This requires a double->single conversion */
3145 sparc_fdtos (code, ins->sreg1, sparc_f0);
3146 if (!sparc_is_imm13 (ins->inst_offset)) {
3147 sparc_set (code, ins->inst_offset, sparc_o7);
3148 sparc_stf (code, sparc_f0, ins->inst_destbasereg, sparc_o7);
3151 sparc_stf_imm (code, sparc_f0, ins->inst_destbasereg, ins->inst_offset);
3153 case OP_LOADR4_MEMBASE:
3154 EMIT_LOAD_MEMBASE (ins, ldf);
3155 /* Extend to double */
3156 sparc_fstod (code, ins->dreg, ins->dreg);
3159 sparc_fmovs (code, ins->sreg1, ins->dreg);
3160 sparc_fmovs (code, ins->sreg1 + 1, ins->dreg + 1);
3163 guint32 offset = mono_spillvar_offset_float (cfg, 0);
3164 if (!sparc_is_imm13 (offset))
3166 sparc_st_imm (code, ins->sreg1, sparc_sp, offset);
3167 sparc_ldf_imm (code, sparc_sp, offset, sparc_f0);
3168 sparc_fitos (code, sparc_f0, sparc_f0);
3169 sparc_fstod (code, sparc_f0, ins->dreg);
3173 guint32 offset = mono_spillvar_offset_float (cfg, 0);
3174 if (!sparc_is_imm13 (offset))
3176 sparc_st_imm (code, ins->sreg1, sparc_sp, offset);
3177 sparc_ldf_imm (code, sparc_sp, offset, sparc_f0);
3178 sparc_fitod (code, sparc_f0, ins->dreg);
3181 case OP_FCONV_TO_I1:
3182 case OP_FCONV_TO_U1:
3183 case OP_FCONV_TO_I2:
3184 case OP_FCONV_TO_U2:
3185 case OP_FCONV_TO_I4:
3187 case OP_FCONV_TO_U4:
3188 case OP_FCONV_TO_U: {
3189 guint32 offset = mono_spillvar_offset_float (cfg, 0);
3190 if (!sparc_is_imm13 (offset))
3192 /* FIXME: Is having the same code for all of these ok ? */
3193 sparc_fdtoi (code, ins->sreg1, sparc_f0);
3194 sparc_stdf_imm (code, sparc_f0, sparc_sp, offset);
3195 sparc_ld_imm (code, sparc_sp, offset, ins->dreg);
3198 case OP_FCONV_TO_I8:
3199 case OP_FCONV_TO_U8:
3201 g_assert_not_reached ();
3205 g_assert_not_reached ();
3207 case OP_LCONV_TO_R_UN: {
3209 g_assert_not_reached ();
3212 case OP_LCONV_TO_OVF_I: {
3213 guint32 *br [3], *label [1];
3216 * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
3218 sparc_cmp_imm (code, ins->sreg1, 0);
3220 sparc_branch (code, 1, sparc_bneg, 0);
3224 /* ms word must be 0 */
3225 sparc_cmp_imm (code, ins->sreg2, 0);
3227 sparc_branch (code, 1, sparc_be, 0);
3232 EMIT_COND_SYSTEM_EXCEPTION (ins, sparc_ba, "OverflowException");
3235 sparc_patch (br [0], code);
3237 /* ms word must 0xfffffff */
3238 sparc_cmp_imm (code, ins->sreg2, -1);
3240 sparc_branch (code, 1, sparc_bne, 0);
3241 sparc_patch (br [2], label [0]);
3244 sparc_patch (br [1], code);
3245 if (ins->sreg1 != ins->dreg)
3246 sparc_mov_reg_reg (code, ins->sreg1, ins->dreg);
3250 sparc_faddd (code, ins->sreg1, ins->sreg2, ins->dreg);
3253 sparc_fsubd (code, ins->sreg1, ins->sreg2, ins->dreg);
3256 sparc_fmuld (code, ins->sreg1, ins->sreg2, ins->dreg);
3259 sparc_fdivd (code, ins->sreg1, ins->sreg2, ins->dreg);
3262 sparc_fnegs (code, ins->sreg1, ins->dreg);
3265 sparc_fdivd (code, ins->sreg1, ins->sreg2, sparc_f0);
3266 sparc_fmuld (code, ins->sreg2, sparc_f0, sparc_f0);
3267 sparc_fsubd (code, ins->sreg1, sparc_f0, ins->dreg);
3270 sparc_fcmpd (code, ins->sreg1, ins->sreg2);
3277 sparc_fcmpd (code, ins->sreg1, ins->sreg2);
3278 sparc_clr_reg (code, ins->dreg);
3279 switch (ins->opcode) {
3282 sparc_fbranch (code, 1, opcode_to_sparc_cond (ins->opcode), 4);
3284 sparc_set (code, 1, ins->dreg);
3285 sparc_fbranch (code, 1, sparc_fbu, 2);
3287 sparc_set (code, 1, ins->dreg);
3290 sparc_fbranch (code, 1, opcode_to_sparc_cond (ins->opcode), 2);
3292 sparc_set (code, 1, ins->dreg);
3298 EMIT_FLOAT_COND_BRANCH (ins, opcode_to_sparc_cond (ins->opcode), 1, 1);
3301 /* clt.un + brfalse */
3303 sparc_fbranch (code, 1, sparc_fbul, 0);
3306 EMIT_FLOAT_COND_BRANCH (ins, sparc_fba, 1, 1);
3307 sparc_patch ((guint8*)p, (guint8*)code);
3311 /* cgt.un + brfalse */
3313 sparc_fbranch (code, 1, sparc_fbug, 0);
3316 EMIT_FLOAT_COND_BRANCH (ins, sparc_fba, 1, 1);
3317 sparc_patch ((guint8*)p, (guint8*)code);
3321 EMIT_FLOAT_COND_BRANCH (ins, sparc_fbne, 1, 1);
3322 EMIT_FLOAT_COND_BRANCH (ins, sparc_fbu, 1, 1);
3325 EMIT_FLOAT_COND_BRANCH (ins, sparc_fbl, 1, 1);
3326 EMIT_FLOAT_COND_BRANCH (ins, sparc_fbu, 1, 1);
3329 EMIT_FLOAT_COND_BRANCH (ins, sparc_fbg, 1, 1);
3330 EMIT_FLOAT_COND_BRANCH (ins, sparc_fbu, 1, 1);
3333 EMIT_FLOAT_COND_BRANCH (ins, sparc_fbge, 1, 1);
3334 EMIT_FLOAT_COND_BRANCH (ins, sparc_fbu, 1, 1);
3337 EMIT_FLOAT_COND_BRANCH (ins, sparc_fble, 1, 1);
3338 EMIT_FLOAT_COND_BRANCH (ins, sparc_fbu, 1, 1);
3340 case CEE_CKFINITE: {
3341 guint32 offset = mono_spillvar_offset_float (cfg, 0);
3342 if (!sparc_is_imm13 (offset))
3344 sparc_stdf_imm (code, ins->sreg1, sparc_sp, offset);
3345 sparc_lduh_imm (code, sparc_sp, offset, sparc_o7);
3346 sparc_srl_imm (code, sparc_o7, 4, sparc_o7);
3347 sparc_and_imm (code, FALSE, sparc_o7, 2047, sparc_o7);
3348 sparc_cmp_imm (code, sparc_o7, 2047);
3349 EMIT_COND_SYSTEM_EXCEPTION (ins, sparc_be, "ArithmeticException");
3350 sparc_fmovs (code, ins->sreg1, ins->dreg);
3351 sparc_fmovs (code, ins->sreg1 + 1, ins->dreg + 1);
3356 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3358 g_warning ("%s:%d: unknown opcode %s\n", __FILE__, __LINE__, mono_inst_name (ins->opcode));
3360 g_assert_not_reached ();
3363 if ((((guint8*)code) - code_start) > max_len) {
3364 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3365 mono_inst_name (ins->opcode), max_len, ((guint8*)code) - code_start);
3366 g_assert_not_reached ();
3376 cfg->code_len = (guint8*)code - cfg->native_code;
3380 mono_arch_register_lowlevel_calls (void)
3382 mono_register_jit_icall (mono_sparc_break, "mono_sparc_break", NULL, TRUE);
3386 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3388 MonoJumpInfo *patch_info;
3390 /* FIXME: Move part of this to arch independent code */
3391 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3392 unsigned char *ip = patch_info->ip.i + code;
3393 const unsigned char *target = NULL;
3395 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3397 switch (patch_info->type) {
3398 case MONO_PATCH_INFO_CLASS_INIT: {
3399 unsigned char *ip2 = ip;
3400 /* Might already been changed to a nop */
3401 sparc_call_simple (ip2, 0);
3404 case MONO_PATCH_INFO_R4: {
3405 float *f = g_new0 (float, 1);
3406 *f = *(float*)patch_info->data.target;
3410 case MONO_PATCH_INFO_R8: {
3411 double *d = g_new0 (double, 1);
3412 *d = *(double*)patch_info->data.target;
3419 sparc_patch (ip, target);
3424 * Allow tracing to work with this interface (with an optional argument)
3428 * This may be needed on some archs or for debugging support.
3431 mono_arch_instrument_mem_needs (MonoMethod *method, int *stack, int *code)
3433 /* no stack room needed now (may be needed for FASTCALL-trace support) */
3435 /* split prolog-epilog requirements? */
3436 *code = 256; /* max bytes needed: check this number */
3440 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
3442 int stack, code_size;
3443 guint32 *code = (guint32*)p;
3445 /* Save registers to stack */
3446 sparc_st_imm (code, sparc_i0, sparc_fp, 68);
3447 sparc_st_imm (code, sparc_i1, sparc_fp, 72);
3448 sparc_st_imm (code, sparc_i2, sparc_fp, 76);
3449 sparc_st_imm (code, sparc_i3, sparc_fp, 80);
3450 sparc_st_imm (code, sparc_i4, sparc_fp, 84);
3451 sparc_st_imm (code, sparc_i5, sparc_fp, 88);
3453 sparc_set (code, cfg->method, sparc_o0);
3454 sparc_mov_reg_reg (code, sparc_fp, sparc_o1);
3456 mono_add_patch_info (cfg, (guint8*)code-cfg->native_code, MONO_PATCH_INFO_ABS, func);
3457 sparc_sethi (code, 0, sparc_o7);
3458 sparc_jmpl_imm (code, sparc_o7, 0, sparc_callsite);
3461 mono_arch_instrument_mem_needs (cfg->method, &stack, &code_size);
3463 g_assert ((code - (guint32*)p) <= (code_size * 4));
3477 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
3480 int save_mode = SAVE_NONE;
3481 MonoMethod *method = cfg->method;
3482 int rtype = method->signature->ret->type;
3486 case MONO_TYPE_VOID:
3487 /* special case string .ctor icall */
3488 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
3489 save_mode = SAVE_ONE;
3491 save_mode = SAVE_NONE;
3495 save_mode = SAVE_TWO;
3499 save_mode = SAVE_FP;
3501 case MONO_TYPE_VALUETYPE:
3502 if (method->signature->ret->data.klass->enumtype) {
3503 rtype = method->signature->ret->data.klass->enum_basetype->type;
3506 save_mode = SAVE_STRUCT;
3509 save_mode = SAVE_ONE;
3513 /* Save the result to the stack and also put it into the output registers */
3515 switch (save_mode) {
3517 sparc_st_imm (code, sparc_i0, sparc_fp, 68);
3518 sparc_st_imm (code, sparc_i0, sparc_fp, 72);
3519 sparc_mov_reg_reg (code, sparc_i0, sparc_o1);
3520 sparc_mov_reg_reg (code, sparc_i1, sparc_o2);
3523 sparc_st_imm (code, sparc_i0, sparc_fp, 68);
3524 sparc_mov_reg_reg (code, sparc_i0, sparc_o1);
3527 sparc_stdf_imm (code, sparc_f0, sparc_fp, 72);
3528 sparc_ld_imm (code, sparc_fp, 72, sparc_o1);
3529 sparc_ld_imm (code, sparc_fp, 72, sparc_o2);
3532 sparc_ld_imm (code, sparc_fp, 64, sparc_o1);
3539 sparc_set (code, cfg->method, sparc_o0);
3541 mono_add_patch_info (cfg, (guint8*)code-cfg->native_code, MONO_PATCH_INFO_ABS, func);
3542 sparc_sethi (code, 0, sparc_o7);
3543 sparc_jmpl_imm (code, sparc_o7, 0, sparc_callsite);
3546 /* Restore result */
3548 switch (save_mode) {
3550 sparc_ld_imm (code, sparc_fp, 68, sparc_i0);
3551 sparc_ld_imm (code, sparc_fp, 72, sparc_i0);
3554 sparc_ld_imm (code, sparc_fp, 68, sparc_i0);
3557 sparc_lddf_imm (code, sparc_fp, 72, sparc_f0);
3568 mono_arch_max_epilog_size (MonoCompile *cfg)
3570 int exc_count = 0, max_epilog_size = 16 + 20*4;
3571 MonoJumpInfo *patch_info;
3573 if (cfg->method->save_lmf)
3574 max_epilog_size += 128;
3576 if (mono_jit_trace_calls != NULL)
3577 max_epilog_size += 50;
3579 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3580 max_epilog_size += 50;
3582 /* count the number of exception infos */
3584 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3585 if (patch_info->type == MONO_PATCH_INFO_EXC)
3590 * make sure we have enough space for exceptions
3592 max_epilog_size += exc_count * 24;
3594 return max_epilog_size;
3598 mono_arch_emit_prolog (MonoCompile *cfg)
3600 MonoMethod *method = cfg->method;
3601 MonoMethodSignature *sig;
3607 cfg->code_size = 256;
3608 code = cfg->native_code = g_malloc (cfg->code_size);
3610 /* FIXME: Generate intermediate code instead */
3612 offset = cfg->stack_offset;
3613 offset += 64; /* register save area */
3614 offset += 4; /* struct/union return pointer */
3616 /* add parameter area size for called functions */
3617 if (cfg->param_area < 24)
3618 /* Reserve space for the first 6 arguments even if it is unused */
3621 offset += cfg->param_area;
3623 /* align the stack size to 8 bytes */
3624 offset = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
3627 * localloc'd memory is stored between the local variables (whose
3628 * size is given by cfg->stack_offset), and between the space reserved
3631 cfg->arch.localloc_offset = offset - cfg->stack_offset;
3633 cfg->stack_offset = offset;
3635 if (!sparc_is_imm13 (- cfg->stack_offset)) {
3636 /* Can't use sparc_o7 here, since we're still in the caller's frame */
3637 sparc_set (code, (- cfg->stack_offset), sparc_g1);
3638 sparc_save (code, sparc_sp, sparc_g1, sparc_sp);
3641 sparc_save_imm (code, sparc_sp, - cfg->stack_offset, sparc_sp);
3643 if (strstr (cfg->method->name, "test_marshal_struct")) {
3644 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_ABS, mono_sparc_break);
3645 sparc_call_simple (code, 0);
3649 sig = method->signature;
3651 cinfo = get_call_info (sig, FALSE);
3653 /* Keep in sync with emit_load_volatile_arguments */
3654 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3655 ArgInfo *ainfo = cinfo->args + i;
3656 guint32 stack_offset;
3658 inst = cfg->varinfo [i];
3660 if (sig->hasthis && (i == 0))
3661 arg_type = mono_defaults.object_class;
3663 arg_type = sig->params [i - sig->hasthis];
3665 stack_offset = ainfo->offset + 68;
3667 /* Save the split arguments so they will reside entirely on the stack */
3668 if (ainfo->storage == ArgInSplitRegStack) {
3669 /* Save the register to the stack */
3670 g_assert (inst->opcode == OP_REGOFFSET);
3671 if (!sparc_is_imm13 (stack_offset))
3673 sparc_st_imm (code, sparc_i5, inst->inst_basereg, stack_offset);
3676 if (!arg_type->byref && (arg_type->type == MONO_TYPE_R8)) {
3677 /* Save the argument to a dword aligned stack location */
3679 * stack_offset contains the offset of the argument on the stack.
3680 * inst->inst_offset contains the dword aligned offset where the value
3683 if (ainfo->storage == ArgInIRegPair) {
3684 if (!sparc_is_imm13 (inst->inst_offset + 4))
3686 sparc_st_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, inst->inst_offset);
3687 sparc_st_imm (code, sparc_i0 + ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
3690 if (ainfo->storage == ArgInSplitRegStack) {
3691 if (stack_offset != inst->inst_offset) {
3692 /* stack_offset is not dword aligned, so we need to make a copy */
3693 sparc_st_imm (code, sparc_i5, inst->inst_basereg, inst->inst_offset);
3694 sparc_ld_imm (code, sparc_fp, stack_offset + 4, sparc_o7);
3695 sparc_st_imm (code, sparc_o7, inst->inst_basereg, inst->inst_offset + 4);
3699 if (ainfo->storage == ArgOnStackPair) {
3700 if (stack_offset != inst->inst_offset) {
3701 /* stack_offset is not dword aligned, so we need to make a copy */
3702 sparc_ld_imm (code, sparc_fp, stack_offset, sparc_o7);
3703 sparc_st_imm (code, sparc_o7, inst->inst_basereg, inst->inst_offset);
3704 sparc_ld_imm (code, sparc_fp, stack_offset + 4, sparc_o7);
3705 sparc_st_imm (code, sparc_o7, inst->inst_basereg, inst->inst_offset + 4);
3709 g_assert_not_reached ();
3712 if ((ainfo->storage == ArgInIReg) && (inst->opcode != OP_REGVAR)) {
3713 /* Argument in register, but need to be saved to stack */
3714 if (!sparc_is_imm13 (stack_offset))
3716 if (stack_offset & 0x1)
3717 sparc_stb_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, stack_offset);
3719 if (stack_offset & 0x2)
3720 sparc_sth_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, stack_offset);
3722 sparc_st_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, stack_offset);
3725 if ((ainfo->storage == ArgInIRegPair) && (inst->opcode != OP_REGVAR)) {
3726 /* Argument in regpair, but need to be saved to stack */
3727 if (!sparc_is_imm13 (inst->inst_offset + 4))
3729 sparc_st_imm (code, sparc_i0 + ainfo->reg, inst->inst_basereg, inst->inst_offset);
3730 sparc_st_imm (code, sparc_i0 + ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
3733 if ((ainfo->storage == ArgInSplitRegStack) || (ainfo->storage == ArgOnStack))
3734 if (inst->opcode == OP_REGVAR)
3735 /* FIXME: Load the argument into memory */
3741 if (cfg->method->save_lmf) {
3742 gint32 lmf_offset = - cfg->arch.lmf_offset;
3745 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3746 sparc_set (code, 0xfffffff, sparc_o7);
3747 sparc_st_imm (code, sparc_o7, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ip));
3749 sparc_st_imm (code, sparc_sp, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, sp));
3751 sparc_st_imm (code, sparc_fp, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebp));
3753 /* FIXME: add a relocation for this */
3754 sparc_set (code, cfg->method, sparc_o7);
3755 sparc_st_imm (code, sparc_o7, sparc_fp, lmf_offset + G_STRUCT_OFFSET (MonoLMF, method));
3757 mono_add_patch_info (cfg, (guint8*)code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3758 (gpointer)"mono_get_lmf_addr");
3759 sparc_call_simple (code, 0);
3762 code = (guint32*)mono_sparc_emit_save_lmf ((guint32*)code, lmf_offset);
3765 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3766 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3768 cfg->code_len = code - cfg->native_code;
3770 g_assert (cfg->code_len <= cfg->code_size);
3776 mono_arch_emit_epilog (MonoCompile *cfg)
3778 MonoJumpInfo *patch_info;
3779 MonoMethod *method = cfg->method;
3782 code = cfg->native_code + cfg->code_len;
3784 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3785 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3787 if (cfg->method->save_lmf) {
3788 gint32 lmf_offset = - cfg->arch.lmf_offset;
3790 code = mono_sparc_emit_restore_lmf (code, lmf_offset);
3794 * The sparc ABI requires that calls to functions which return a structure
3797 if (cfg->method->signature->pinvoke && MONO_TYPE_ISSTRUCT(cfg->method->signature->ret))
3798 sparc_jmpl_imm (code, sparc_i7, 12, sparc_g0);
3801 sparc_restore_imm (code, sparc_g0, 0, sparc_g0);
3803 /* add code to raise exceptions */
3804 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3805 switch (patch_info->type) {
3806 case MONO_PATCH_INFO_EXC:
3807 sparc_patch (cfg->native_code + patch_info->ip.i, code);
3808 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);
3809 sparc_set (code, 0xffffff, sparc_o0);
3810 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_METHOD_REL, (gpointer)patch_info->ip.i);
3811 sparc_set (code, 0xffffff, sparc_o1);
3812 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3813 patch_info->data.name = "mono_arch_throw_exception_by_name";
3814 patch_info->ip.i = code - cfg->native_code;
3815 sparc_call_simple (code, 0);
3824 cfg->code_len = code - cfg->native_code;
3826 g_assert (cfg->code_len < cfg->code_size);
3831 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3833 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
3834 struct sigaltstack sa;
3836 printf ("SIGALT!\n");
3837 /* Setup an alternate signal stack */
3838 tls->signal_stack = g_malloc (SIGNAL_STACK_SIZE * 100);
3839 tls->signal_stack_size = SIGNAL_STACK_SIZE;
3841 sa.ss_sp = tls->signal_stack;
3842 sa.ss_size = SIGNAL_STACK_SIZE * 100;
3844 g_assert (sigaltstack (&sa, NULL) == 0);
3849 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3854 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3856 /* add the this argument */
3857 if (this_reg != -1) {
3859 MONO_INST_NEW (cfg, this, OP_SETREG);
3860 this->type = this_type;
3861 this->sreg1 = this_reg;
3862 this->dreg = sparc_o0;
3863 mono_bblock_add_inst (cfg->cbb, this);
3867 /* Set the 'struct/union return pointer' location on the stack */
3868 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, sparc_sp, 64, vt_reg);
3874 mono_arch_get_opcode_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3880 * mono_arch_get_argument_info:
3881 * @csig: a method signature
3882 * @param_count: the number of parameters to consider
3883 * @arg_info: an array to store the result infos
3885 * Gathers information on parameters such as size, alignment and
3886 * padding. arg_info should be large enought to hold param_count + 1 entries.
3888 * Returns the size of the activation frame.
3891 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
3897 cinfo = get_call_info (csig, FALSE);
3899 if (csig->hasthis) {
3900 ainfo = &cinfo->args [0];
3901 arg_info [0].offset = 68 + ainfo->offset;
3904 for (k = 0; k < param_count; k++) {
3905 ainfo = &cinfo->args [k + csig->hasthis];
3907 arg_info [k + 1].offset = 68 + ainfo->offset;
3908 arg_info [k + 1].size = mono_type_size (csig->params [k], &align);
3918 mono_arch_print_tree (MonoInst *tree, int arity)