2 * mini-mips.c: MIPS backend for the Mono code generator
5 * Mark Mason (mason@broadcom.com)
7 * Based on mini-ppc.c by
8 * Paolo Molaro (lupus@ximian.com)
9 * Dietmar Maurer (dietmar@ximian.com)
12 * (C) 2003 Ximian, Inc.
16 #include <asm/cachectl.h>
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/debug-helpers.h>
21 #include "mini-mips.h"
26 #define SAVE_FP_REGS 0
27 #define SAVE_ALL_REGS 0
28 #define EXTRA_STACK_SPACE 0 /* suppresses some s-reg corruption issues */
29 #define LONG_BRANCH 1 /* needed for yyparse in mcs */
32 #define ALWAYS_USE_FP 1
33 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
42 int mono_exc_esp_offset = 0;
43 static int tls_mode = TLS_MODE_DETECT;
44 static int lmf_pthread_key = -1;
45 static int monothread_key = -1;
46 static int monodomain_key = -1;
49 #define DEBUG(a) if (cfg->verbose_level > 1) a
55 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
57 code = mips_emit_exc_by_name (code, exc_name); \
58 cfg->bb_exit->max_offset += 16; \
62 #define emit_linuxthreads_tls(code,dreg,key) do {\
64 off1 = offsets_from_pthread_key ((key), &off2); \
65 ppc_lwz ((code), (dreg), off1, ppc_r2); \
66 ppc_lwz ((code), (dreg), off2, (dreg)); \
70 #define emit_tls_access(code,dreg,key) do { \
72 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
73 default: g_assert_not_reached (); \
77 typedef struct InstList InstList;
95 guint16 vtsize; /* in param area */
97 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
98 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
115 void patch_lui_addiu(guint32 *ip, guint32 val);
116 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
119 mono_arch_flush_icache (guint8 *code, gint size)
121 /* Linux/MIPS specific */
122 cacheflush (code, size, BCACHE);
126 mono_arch_flush_register_windows (void)
131 mips_emit_exc_by_name(guint8 *code, const char *name)
135 mips_load_const (code, mips_a0, name);
136 addr = (guint32) mono_arch_get_throw_exception_by_name ();
137 mips_load_const (code, mips_t9, addr);
138 mips_jalr (code, mips_t9, mips_ra);
145 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
151 /* Invert test and emit branch around jump */
154 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
158 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
162 mips_bltz (code, ins->sreg1, br_offset);
166 mips_blez (code, ins->sreg1, br_offset);
170 mips_bgtz (code, ins->sreg1, br_offset);
174 mips_bgez (code, ins->sreg1, br_offset);
178 g_assert_not_reached ();
180 if (ins->flags & MONO_INST_BRLABEL)
181 mono_add_patch_info (cfg, code - cfg->native_code,
182 MONO_PATCH_INFO_LABEL, ins->inst_i0);
184 mono_add_patch_info (cfg, code - cfg->native_code,
185 MONO_PATCH_INFO_BB, ins->inst_true_bb);
186 mips_lui (code, mips_at, mips_zero, 0);
187 mips_addiu (code, mips_at, mips_at, 0);
188 mips_jr (code, mips_at);
191 if (ins->flags & MONO_INST_BRLABEL)
192 mono_add_patch_info (cfg, code - cfg->native_code,
193 MONO_PATCH_INFO_LABEL, ins->inst_i0);
195 mono_add_patch_info (cfg, code - cfg->native_code,
196 MONO_PATCH_INFO_BB, ins->inst_true_bb);
199 mips_beq (code, ins->sreg1, ins->sreg2, 0);
203 mips_bne (code, ins->sreg1, ins->sreg2, 0);
207 mips_bgez (code, ins->sreg1, 0);
211 mips_bgtz (code, ins->sreg1, 0);
215 mips_blez (code, ins->sreg1, 0);
219 mips_bltz (code, ins->sreg1, 0);
223 g_assert_not_reached ();
229 /* XXX - big-endian dependent? */
231 patch_lui_addiu(guint32 *ip, guint32 val)
233 guint16 *__lui_addiu = (guint16*)(void *)(ip);
236 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
237 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
240 if (((guint32)(val)) & (1 << 15))
241 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
243 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
244 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
245 mono_arch_flush_icache ((guint8 *)ip, 8);
250 mips_patch (guint32 *code, guint32 target)
253 guint32 op = ins >> 26;
254 guint32 diff, offset;
256 g_assert (trap_target != target);
257 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
259 case 0x00: /* jr ra */
260 if (ins == 0x3e00008)
262 g_assert_not_reached ();
266 g_assert (!(target & 0x03));
267 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
268 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
270 mono_arch_flush_icache ((guint8 *)code, 4);
272 case 0x01: /* BLTZ */
275 case 0x06: /* BLEZ */
276 case 0x07: /* BGTZ */
277 case 0x11: /* bc1t */
278 diff = target - (guint32)(code + 1);
279 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
280 g_assert (!(diff & 0x03));
281 offset = ((gint32)diff) >> 2;
282 g_assert (((int)offset) == ((int)(short)offset));
283 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
285 mono_arch_flush_icache ((guint8 *)code, 4);
287 case 0x0f: /* LUI / ADDIU pair */
288 patch_lui_addiu (code, target);
289 mono_arch_flush_icache ((guint8 *)code, 8);
293 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
294 g_assert_not_reached ();
299 offsets_from_pthread_key (guint32 key, int *offset2)
303 *offset2 = idx2 * sizeof (gpointer);
304 return 284 + idx1 * sizeof (gpointer);
308 mono_arch_regname (int reg) {
309 static const char * rnames[] = {
310 "zero", "at", "v0", "v1",
311 "a0", "a1", "a2", "a3",
312 "t0", "t1", "t2", "t3",
313 "t4", "t5", "t6", "t7",
314 "s0", "s1", "s2", "s3",
315 "s4", "s5", "s6", "s7",
316 "t8", "t9", "k0", "k1",
317 "gp", "sp", "fp", "ra"
319 if (reg >= 0 && reg < 32)
325 mono_arch_fregname (int reg) {
326 static const char * rnames[] = {
327 "f0", "f1", "f2", "f3",
328 "f4", "f5", "f6", "f7",
329 "f8", "f9", "f10", "f11",
330 "f12", "f13", "f14", "f15",
331 "f16", "f17", "f18", "f19",
332 "f20", "f21", "f22", "f23",
333 "f24", "f25", "f26", "f27",
334 "f28", "f29", "f30", "f31"
336 if (reg >= 0 && reg < 32)
341 /* this function overwrites at */
343 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
345 /* XXX write a loop, not an unrolled loop */
347 mips_lw (code, mips_at, sreg, soffset);
348 mips_sw (code, mips_at, dreg, doffset);
357 * mono_arch_get_argument_info:
358 * @csig: a method signature
359 * @param_count: the number of parameters to consider
360 * @arg_info: an array to store the result infos
362 * Gathers information on parameters such as size, alignment and
363 * padding. arg_info should be large enought to hold param_count + 1 entries.
365 * Returns the size of the activation frame.
368 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
370 int k, frame_size = 0;
371 guint32 size, align, pad;
374 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
375 frame_size += sizeof (gpointer);
379 arg_info [0].offset = offset;
382 frame_size += sizeof (gpointer);
386 arg_info [0].size = frame_size;
388 for (k = 0; k < param_count; k++) {
391 size = mono_type_native_stack_size (csig->params [k], &align);
393 size = mini_type_stack_size (NULL, csig->params [k], &align);
395 /* ignore alignment for now */
398 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
399 arg_info [k].pad = pad;
401 arg_info [k + 1].pad = 0;
402 arg_info [k + 1].size = size;
404 arg_info [k + 1].offset = offset;
408 align = MONO_ARCH_FRAME_ALIGNMENT;
409 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
410 arg_info [k].pad = pad;
416 * Initialize the cpu to execute managed code.
419 mono_arch_cpu_init (void)
424 * Initialize architecture specific code.
427 mono_arch_init (void)
432 * Cleanup architecture specific code.
435 mono_arch_cleanup (void)
440 * This function returns the optimizations supported on this cpu.
443 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
447 /* no mips-specific optimizations yet */
453 is_regsize_var (MonoType *t) {
456 t = mono_type_get_underlying_type (t);
463 case MONO_TYPE_FNPTR:
465 case MONO_TYPE_OBJECT:
466 case MONO_TYPE_STRING:
467 case MONO_TYPE_CLASS:
468 case MONO_TYPE_SZARRAY:
469 case MONO_TYPE_ARRAY:
471 case MONO_TYPE_GENERICINST:
472 if (!mono_type_generic_inst_is_valuetype (t))
475 case MONO_TYPE_VALUETYPE:
482 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
487 for (i = 0; i < cfg->num_varinfo; i++) {
488 MonoInst *ins = cfg->varinfo [i];
489 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
492 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
495 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
498 /* we can only allocate 32 bit values */
499 if (is_regsize_var (ins->inst_vtype)) {
500 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
501 g_assert (i == vmv->idx);
502 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
510 mono_arch_get_global_int_regs (MonoCompile *cfg)
514 regs = g_list_prepend (regs, (gpointer)mips_s0);
515 regs = g_list_prepend (regs, (gpointer)mips_s1);
516 regs = g_list_prepend (regs, (gpointer)mips_s2);
517 regs = g_list_prepend (regs, (gpointer)mips_s3);
518 regs = g_list_prepend (regs, (gpointer)mips_s4);
519 regs = g_list_prepend (regs, (gpointer)mips_s5);
520 regs = g_list_prepend (regs, (gpointer)mips_s6);
521 regs = g_list_prepend (regs, (gpointer)mips_s7);
527 * mono_arch_regalloc_cost:
529 * Return the cost, in number of memory references, of the action of
530 * allocating the variable VMV into a register during global register
534 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
541 args_onto_stack (CallInfo *info)
543 g_assert(!info->on_stack);
544 g_assert(info->stack_size <= MIPS_STACK_PARAM_OFFSET);
545 info->on_stack = TRUE;
546 info->stack_size = MIPS_STACK_PARAM_OFFSET;
550 * O32 calling convention version
554 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
555 /* First, see if we need to drop onto the stack */
556 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
557 args_onto_stack (info);
559 /* Now, place the argument */
560 if (info->on_stack) {
561 ainfo->regtype = RegTypeBase;
562 ainfo->reg = mips_sp; /* in the caller */
563 ainfo->offset = info->stack_size;
566 ainfo->regtype = RegTypeGeneral;
567 ainfo->reg = info->gr;
569 info->gr_passed = TRUE;
571 info->stack_size += 4;
575 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
576 /* First, see if we need to drop onto the stack */
577 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
578 args_onto_stack (info);
580 /* Now, place the argument */
581 if (info->on_stack) {
582 g_assert(info->stack_size % 4 == 0);
583 info->stack_size += (info->stack_size % 8);
585 ainfo->regtype = RegTypeBase;
586 ainfo->reg = mips_sp; /* in the caller */
587 ainfo->offset = info->stack_size;
590 // info->gr must be a0 or a2
591 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
592 g_assert(info->gr <= MIPS_LAST_ARG_REG);
594 ainfo->regtype = RegTypeGeneral;
595 ainfo->reg = info->gr;
597 info->gr_passed = TRUE;
599 info->stack_size += 8;
603 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
604 /* First, see if we need to drop onto the stack */
605 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
606 args_onto_stack (info);
608 /* Now, place the argument */
609 if (info->on_stack) {
610 ainfo->regtype = RegTypeBase;
611 ainfo->reg = mips_sp; /* in the caller */
612 ainfo->offset = info->stack_size;
615 /* Only use FP regs for args if no int args passed yet */
616 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
617 ainfo->regtype = RegTypeFP;
618 ainfo->reg = info->fr;
619 /* Even though it's a single-precision float, it takes up two FP regs */
621 /* FP and GP slots do not overlap */
625 /* Passing single-precision float arg in a GP register
626 * such as: func (0, 1.0, 2, 3);
627 * In this case, only one 'gr' register is consumed.
629 ainfo->regtype = RegTypeGeneral;
630 ainfo->reg = info->gr;
633 info->gr_passed = TRUE;
636 info->stack_size += 4;
640 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
641 /* First, see if we need to drop onto the stack */
642 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
643 args_onto_stack (info);
645 /* Now, place the argument */
646 if (info->on_stack) {
647 g_assert(info->stack_size % 4 == 0);
648 info->stack_size += (info->stack_size % 8);
650 ainfo->regtype = RegTypeBase;
651 ainfo->reg = mips_sp; /* in the caller */
652 ainfo->offset = info->stack_size;
655 /* Only use FP regs for args if no int args passed yet */
656 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
657 ainfo->regtype = RegTypeFP;
658 ainfo->reg = info->fr;
660 /* FP and GP slots do not overlap */
664 // info->gr must be a0 or a2
665 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
666 g_assert(info->gr <= MIPS_LAST_ARG_REG);
668 ainfo->regtype = RegTypeGeneral;
669 ainfo->reg = info->gr;
671 info->gr_passed = TRUE;
674 info->stack_size += 8;
678 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
681 int n = sig->hasthis + sig->param_count;
683 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
685 cinfo->fr = MIPS_FIRST_FPARG_REG;
686 cinfo->gr = MIPS_FIRST_ARG_REG;
687 cinfo->stack_size = 0;
689 DEBUG(printf("calculate_sizes\n"));
691 /* handle returning a struct */
692 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
693 cinfo->struct_ret = cinfo->gr;
694 add_int32_arg (cinfo, &cinfo->ret);
699 add_int32_arg (cinfo, cinfo->args + n);
702 DEBUG(printf("params: %d\n", sig->param_count));
703 for (i = 0; i < sig->param_count; ++i) {
704 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
705 /* Prevent implicit arguments and sig_cookie from
706 being passed in registers */
707 args_onto_stack (cinfo);
708 /* Emit the signature cookie just before the implicit arguments */
709 add_int32_arg (cinfo, &cinfo->sig_cookie);
711 DEBUG(printf("param %d: ", i));
712 if (sig->params [i]->byref) {
713 DEBUG(printf("byref\n"));
714 add_int32_arg (cinfo, &cinfo->args[n]);
718 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
719 switch (simpletype) {
720 case MONO_TYPE_BOOLEAN:
723 DEBUG(printf("1 byte\n"));
724 cinfo->args [n].size = 1;
725 add_int32_arg (cinfo, &cinfo->args[n]);
731 DEBUG(printf("2 bytes\n"));
732 cinfo->args [n].size = 2;
733 add_int32_arg (cinfo, &cinfo->args[n]);
738 DEBUG(printf("4 bytes\n"));
739 cinfo->args [n].size = 4;
740 add_int32_arg (cinfo, &cinfo->args[n]);
746 case MONO_TYPE_FNPTR:
747 case MONO_TYPE_CLASS:
748 case MONO_TYPE_OBJECT:
749 case MONO_TYPE_STRING:
750 case MONO_TYPE_SZARRAY:
751 case MONO_TYPE_ARRAY:
752 cinfo->args [n].size = sizeof (gpointer);
753 add_int32_arg (cinfo, &cinfo->args[n]);
756 case MONO_TYPE_GENERICINST:
757 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
758 cinfo->args [n].size = sizeof (gpointer);
759 add_int32_arg (cinfo, &cinfo->args[n]);
764 case MONO_TYPE_VALUETYPE: {
767 int has_offset = FALSE;
769 gint size, alignment;
772 klass = mono_class_from_mono_type (sig->params [i]);
774 size = mono_class_native_size (klass, NULL);
776 size = mono_class_value_size (klass, NULL);
777 alignment = mono_class_min_align (klass);
778 #if MIPS_PASS_STRUCTS_BY_VALUE
779 /* Need to do alignment if struct contains long or double */
781 if (cinfo->stack_size & (alignment - 1)) {
782 add_int32_arg (cinfo, &dummy_arg);
784 g_assert (!(cinfo->stack_size & (alignment - 1)));
788 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
789 mono_class_native_size (sig->params [i]->data.klass, NULL),
790 cinfo->stack_size, alignment);
792 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
793 g_assert(cinfo->args [n].size == 0);
794 g_assert(cinfo->args [n].vtsize == 0);
795 for (j = 0; j < nwords; ++j) {
797 add_int32_arg (cinfo, &cinfo->args [n]);
801 add_int32_arg (cinfo, &dummy_arg);
802 if (!has_offset && cinfo->on_stack) {
803 cinfo->args [n].offset = dummy_arg.offset;
808 cinfo->args [n].vtsize += 1;
810 cinfo->args [n].size += 1;
812 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
813 cinfo->args [n].regtype = RegTypeStructByVal;
815 add_int32_arg (cinfo, &cinfo->args[n]);
816 cinfo->args [n].regtype = RegTypeStructByAddr;
821 case MONO_TYPE_TYPEDBYREF: {
822 /* keep in sync or merge with the valuetype case */
823 #if MIPS_PASS_STRUCTS_BY_VALUE
825 int size = sizeof (MonoTypedRef);
826 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
827 cinfo->args [n].regtype = RegTypeStructByVal;
828 if (!cinfo->on_stack && cinfo->gr <= MIPS_LAST_ARG_REG) {
829 int rest = MIPS_LAST_ARG_REG - cinfo->gr + 1;
830 int n_in_regs = rest >= nwords? nwords: rest;
831 cinfo->args [n].size = n_in_regs;
832 cinfo->args [n].vtsize = nwords - n_in_regs;
833 cinfo->args [n].reg = cinfo->gr;
834 cinfo->gr += n_in_regs;
835 cinfo->gr_passed = TRUE;
837 cinfo->args [n].size = 0;
838 cinfo->args [n].vtsize = nwords;
840 if (cinfo->args [n].vtsize > 0) {
841 if (!cinfo->on_stack)
842 args_onto_stack (cinfo);
843 g_assert(cinfo->on_stack);
844 cinfo->args [n].offset = cinfo->stack_size;
845 g_print ("offset for arg %d at %d\n", n, cinfo->args [n].offset);
846 cinfo->stack_size += cinfo->args [n].vtsize * sizeof (gpointer);
850 add_int32_arg (cinfo, &cinfo->args[n]);
851 cinfo->args [n].regtype = RegTypeStructByAddr;
858 DEBUG(printf("8 bytes\n"));
859 cinfo->args [n].size = 8;
860 add_int64_arg (cinfo, &cinfo->args[n]);
864 DEBUG(printf("R4\n"));
865 cinfo->args [n].size = 4;
866 add_float32_arg (cinfo, &cinfo->args[n]);
870 DEBUG(printf("R8\n"));
871 cinfo->args [n].size = 8;
872 add_float64_arg (cinfo, &cinfo->args[n]);
876 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
881 simpletype = mono_type_get_underlying_type (sig->ret)->type;
882 switch (simpletype) {
883 case MONO_TYPE_BOOLEAN:
894 case MONO_TYPE_FNPTR:
895 case MONO_TYPE_CLASS:
896 case MONO_TYPE_OBJECT:
897 case MONO_TYPE_SZARRAY:
898 case MONO_TYPE_ARRAY:
899 case MONO_TYPE_STRING:
900 cinfo->ret.reg = mips_v0;
904 cinfo->ret.reg = mips_v0;
908 cinfo->ret.reg = mips_f0;
909 cinfo->ret.regtype = RegTypeFP;
911 case MONO_TYPE_GENERICINST:
912 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
913 cinfo->ret.reg = mips_v0;
917 case MONO_TYPE_VALUETYPE:
919 case MONO_TYPE_TYPEDBYREF:
923 g_error ("Can't handle as return value 0x%x", sig->ret->type);
927 /* align stack size to 16 */
928 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
930 cinfo->stack_usage = cinfo->stack_size;
936 * Set var information according to the calling convention. mips version.
937 * The locals var stuff should most likely be split in another method.
940 mono_arch_allocate_vars (MonoCompile *cfg)
942 MonoMethodSignature *sig;
943 MonoMethodHeader *header;
945 int i, offset, size, align, curinst;
946 int frame_reg = mips_sp;
947 guint32 iregs_to_save = 0;
948 guint32 fregs_to_restore;
950 cfg->flags |= MONO_CFG_HAS_SPILLUP;
952 /* allow room for the vararg method args: void* and long/double */
953 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
954 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
956 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
957 * call convs needs to be handled this way.
959 if (cfg->flags & MONO_CFG_HAS_VARARGS)
960 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
962 /* gtk-sharp and other broken code will dllimport vararg functions even with
963 * non-varargs signatures. Since there is little hope people will get this right
964 * we assume they won't.
966 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
967 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
969 /* a0-a3 always present */
970 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
972 header = mono_method_get_header (cfg->method);
974 sig = mono_method_signature (cfg->method);
977 * We use the frame register also for any method that has
978 * exception clauses. This way, when the handlers are called,
979 * the code will reference local variables using the frame reg instead of
980 * the stack pointer: if we had to restore the stack pointer, we'd
981 * corrupt the method frames that are already on the stack (since
982 * filters get called before stack unwinding happens) when the filter
983 * code would call any method (this also applies to finally etc.).
986 if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses || ALWAYS_USE_FP)
988 cfg->frame_reg = frame_reg;
989 if (frame_reg != mips_sp) {
990 cfg->used_int_regs |= 1 << frame_reg;
995 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
996 /* FIXME: handle long and FP values */
997 switch (mono_type_get_underlying_type (sig->ret)->type) {
1001 cfg->ret->opcode = OP_REGVAR;
1002 cfg->ret->inst_c0 = mips_v0;
1006 /* Space for outgoing parameters, including a0-a3 */
1007 offset += cfg->param_area;
1009 /* allow room to save the return value (if it's a struct) */
1010 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1013 if (sig->call_convention == MONO_CALL_VARARG) {
1014 cfg->sig_cookie = MIPS_STACK_PARAM_OFFSET;
1017 /* Now handle the local variables */
1019 curinst = cfg->locals_start;
1020 for (i = curinst; i < cfg->num_varinfo; ++i) {
1021 inst = cfg->varinfo [i];
1022 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1025 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1026 * pinvoke wrappers when they call functions returning structure
1028 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1029 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
1031 size = mono_type_size (inst->inst_vtype, &align);
1033 offset += align - 1;
1034 offset &= ~(align - 1);
1035 inst->inst_offset = offset;
1036 inst->opcode = OP_REGOFFSET;
1037 inst->inst_basereg = frame_reg;
1039 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1042 /* Space for LMF (if needed) */
1044 if (cfg->method->save_lmf) {
1045 /* align the offset to 16 bytes */
1046 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1047 cfg->arch.lmf_offset = offset;
1048 offset += sizeof (MonoLMF);
1052 #if EXTRA_STACK_SPACE
1053 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1054 * args or return vals. Extra stack space avoids this in a lot of cases.
1058 /* Space for saved registers */
1059 cfg->arch.iregs_offset = offset;
1061 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
1063 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1065 if (iregs_to_save) {
1066 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1067 if (iregs_to_save & (1 << i)) {
1068 offset += sizeof (gulong);
1073 #if EXTRA_STACK_SPACE
1074 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1075 * args or return vals. Extra stack space avoids this in a lot of cases.
1080 /* saved float registers */
1082 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1083 if (fregs_to_restore) {
1084 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1085 if (fregs_to_restore & (1 << i)) {
1086 offset += sizeof (double);
1092 /* Now add space for saving the ra */
1096 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1097 cfg->stack_offset = offset;
1100 * Now allocate stack slots for the int arg regs (a0 - a3)
1101 * On MIPS o32, these are just above the incoming stack pointer
1102 * Even if the arg has been assigned to a regvar, it gets a stack slot
1105 /* Return struct-by-value results in a hidden first argument */
1106 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1107 cfg->vret_addr->opcode = OP_REGOFFSET;
1108 cfg->vret_addr->inst_c0 = mips_a0;
1109 cfg->vret_addr->inst_offset = offset;
1110 cfg->vret_addr->inst_basereg = frame_reg;
1114 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1115 inst = cfg->args [i];
1116 if (inst->opcode != OP_REGVAR) {
1119 if (sig->hasthis && (i == 0))
1120 arg_type = &mono_defaults.object_class->byval_arg;
1122 arg_type = sig->params [i - sig->hasthis];
1124 inst->opcode = OP_REGOFFSET;
1125 size = mono_type_size (arg_type, &align);
1131 inst->inst_basereg = frame_reg;
1132 offset = (offset + align - 1) & ~(align - 1);
1133 inst->inst_offset = offset;
1135 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1136 cfg->sig_cookie += size;
1137 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1140 /* Even a0-a3 get stack slots */
1141 size = sizeof (gpointer);
1142 align = sizeof (gpointer);
1143 inst->inst_basereg = frame_reg;
1144 offset = (offset + align - 1) & ~(align - 1);
1145 inst->inst_offset = offset;
1147 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1148 cfg->sig_cookie += size;
1149 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1155 mono_arch_create_vars (MonoCompile *cfg)
1157 MonoMethodSignature *sig;
1159 sig = mono_method_signature (cfg->method);
1161 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1162 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1163 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1164 printf ("vret_addr = ");
1165 mono_print_ins (cfg->vret_addr);
1170 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1171 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1175 * take the arguments and generate the arch-specific
1176 * instructions to properly call the function in call.
1177 * This includes pushing, moving arguments to the right register
1179 * Issue: who does the spilling if needed, and when?
1182 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
1184 MonoMethodSignature *sig;
1189 sig = call->signature;
1190 n = sig->param_count + sig->hasthis;
1192 cinfo = calculate_sizes (sig, sig->pinvoke);
1193 if (cinfo->struct_ret)
1194 call->used_iregs |= 1 << cinfo->struct_ret;
1196 for (i = 0; i < n; ++i) {
1197 ainfo = cinfo->args + i;
1198 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1200 cfg->disable_aot = TRUE;
1202 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1203 sig_arg->inst_p0 = call->signature;
1205 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1206 arg->inst_imm = cinfo->sig_cookie.offset;
1207 arg->inst_left = sig_arg;
1209 /* prepend, so they get reversed */
1210 arg->next = call->out_args;
1211 call->out_args = arg;
1213 if (is_virtual && i == 0) {
1214 /* the argument will be attached to the call instrucion */
1215 in = call->args [i];
1216 call->used_iregs |= 1 << ainfo->reg;
1218 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1219 in = call->args [i];
1220 arg->cil_code = in->cil_code;
1221 arg->inst_left = in;
1222 arg->inst_call = call;
1223 arg->type = in->type;
1224 /* prepend, we'll need to reverse them later */
1225 arg->next = call->out_args;
1226 call->out_args = arg;
1227 if (ainfo->regtype == RegTypeGeneral) {
1228 arg->backend.reg3 = ainfo->reg;
1229 call->used_iregs |= 1 << ainfo->reg;
1230 if (arg->type == STACK_I8)
1231 call->used_iregs |= 1 << (ainfo->reg + 1);
1232 } else if (ainfo->regtype == RegTypeStructByAddr) {
1233 /* FIXME: where is the data allocated? */
1234 arg->backend.reg3 = ainfo->reg;
1235 call->used_iregs |= 1 << ainfo->reg;
1236 } else if (ainfo->regtype == RegTypeStructByVal) {
1238 MonoMIPSArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMIPSArgInfo));
1239 /* mark the used regs */
1240 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1241 call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1243 arg->opcode = OP_OUTARG_VT;
1244 ai->reg = ainfo->reg;
1245 ai->size = ainfo->size;
1246 ai->vtsize = ainfo->vtsize;
1247 ai->offset = ainfo->offset;
1248 arg->backend.data = ai;
1250 g_printf ("OUTARG_VT reg=%d size=%d vtsize=%d offset=%d\n",
1251 ai->reg, ai->size, ai->vtsize, ai->offset);
1253 } else if (ainfo->regtype == RegTypeBase) {
1254 MonoMIPSArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMIPSArgInfo));
1255 g_assert(ainfo->reg == mips_sp);
1256 arg->opcode = OP_OUTARG_MEMBASE;
1257 ai->reg = ainfo->reg;
1258 ai->size = ainfo->size;
1259 ai->offset = ainfo->offset;
1260 arg->backend.data = ai;
1261 } else if (ainfo->regtype == RegTypeFP) {
1262 arg->opcode = OP_OUTARG_R8;
1263 arg->backend.reg3 = ainfo->reg;
1264 call->used_fregs |= 1 << ainfo->reg;
1265 if (ainfo->size == 4) {
1266 arg->opcode = OP_OUTARG_R4;
1267 /* we reduce the precision */
1269 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1270 conv->inst_left = arg->inst_left;
1271 arg->inst_left = conv;*/
1274 g_assert_not_reached ();
1279 * Reverse the call->out_args list.
1282 MonoInst *prev = NULL, *list = call->out_args, *next;
1289 call->out_args = prev;
1291 call->stack_usage = cinfo->stack_usage;
1292 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1293 cfg->param_area = MAX (cfg->param_area, 16); /* a0-a3 always present */
1294 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1295 cfg->flags |= MONO_CFG_HAS_CALLS;
1297 * should set more info in call, such as the stack space
1298 * used by the args that needs to be added back to esp
1306 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1311 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1313 MonoInst *ins, *n, *last_ins = NULL;
1316 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1317 MonoInst *last_ins = mono_inst_list_prev (&ins->node, &bb->ins_list);
1319 switch (ins->opcode) {
1321 /* remove unnecessary multiplication with 1 */
1322 if (ins->inst_imm == 1) {
1323 if (ins->dreg != ins->sreg1) {
1324 ins->opcode = OP_MOVE;
1326 MONO_DELETE_INS (bb, ins);
1330 int power2 = mono_is_power_of_two (ins->inst_imm);
1332 ins->opcode = OP_SHL_IMM;
1333 ins->inst_imm = power2;
1337 case OP_LOAD_MEMBASE:
1338 case OP_LOADI4_MEMBASE:
1340 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1341 * OP_LOAD_MEMBASE offset(basereg), reg
1343 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1344 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1345 ins->inst_basereg == last_ins->inst_destbasereg &&
1346 ins->inst_offset == last_ins->inst_offset) {
1347 if (ins->dreg == last_ins->sreg1) {
1348 MONO_DELETE_INS (bb, ins);
1351 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1352 ins->opcode = OP_MOVE;
1353 ins->sreg1 = last_ins->sreg1;
1358 * Note: reg1 must be different from the basereg in the second load
1359 * OP_LOAD_MEMBASE offset(basereg), reg1
1360 * OP_LOAD_MEMBASE offset(basereg), reg2
1362 * OP_LOAD_MEMBASE offset(basereg), reg1
1363 * OP_MOVE reg1, reg2
1365 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1366 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1367 ins->inst_basereg != last_ins->dreg &&
1368 ins->inst_basereg == last_ins->inst_basereg &&
1369 ins->inst_offset == last_ins->inst_offset) {
1371 if (ins->dreg == last_ins->dreg) {
1372 MONO_DELETE_INS (bb, ins);
1375 ins->opcode = OP_MOVE;
1376 ins->sreg1 = last_ins->dreg;
1379 //g_assert_not_reached ();
1384 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1385 * OP_LOAD_MEMBASE offset(basereg), reg
1387 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1388 * OP_ICONST reg, imm
1390 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1391 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1392 ins->inst_basereg == last_ins->inst_destbasereg &&
1393 ins->inst_offset == last_ins->inst_offset) {
1394 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1395 ins->opcode = OP_ICONST;
1396 ins->inst_c0 = last_ins->inst_imm;
1397 g_assert_not_reached (); // check this rule
1402 case OP_LOADU1_MEMBASE:
1403 case OP_LOADI1_MEMBASE:
1404 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1405 ins->inst_basereg == last_ins->inst_destbasereg &&
1406 ins->inst_offset == last_ins->inst_offset) {
1407 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? CEE_CONV_I1 : CEE_CONV_U1;
1408 ins->sreg1 = last_ins->sreg1;
1411 case OP_LOADU2_MEMBASE:
1412 case OP_LOADI2_MEMBASE:
1413 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1414 ins->inst_basereg == last_ins->inst_destbasereg &&
1415 ins->inst_offset == last_ins->inst_offset) {
1416 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? CEE_CONV_I2 : CEE_CONV_U2;
1417 ins->sreg1 = last_ins->sreg1;
1423 ins->opcode = OP_MOVE;
1427 if (ins->dreg == ins->sreg1) {
1428 MONO_DELETE_INS (bb, ins);
1432 * OP_MOVE sreg, dreg
1433 * OP_MOVE dreg, sreg
1435 if (last_ins && last_ins->opcode == OP_MOVE &&
1436 ins->sreg1 == last_ins->dreg &&
1437 ins->dreg == last_ins->sreg1) {
1438 MONO_DELETE_INS (bb, ins);
1446 bb->last_ins = last_ins;
1449 static inline InstList*
1450 inst_list_prepend (MonoMemPool *pool, InstList *list, MonoInst *data)
1452 InstList *item = mono_mempool_alloc (pool, sizeof (InstList));
1462 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1466 bb->code = to_insert;
1467 to_insert->next = ins;
1469 to_insert->next = ins->next;
1470 ins->next = to_insert;
1474 #define NEW_INS(cfg,dest,op) do { \
1475 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1476 (dest)->opcode = (op); \
1477 insert_after_ins (bb, last_ins, (dest)); \
1481 map_to_reg_reg_op (int op)
1490 case OP_COMPARE_IMM:
1506 case OP_LOAD_MEMBASE:
1507 return OP_LOAD_MEMINDEX;
1508 case OP_LOADI4_MEMBASE:
1509 return OP_LOADI4_MEMINDEX;
1510 case OP_LOADU4_MEMBASE:
1511 return OP_LOADU4_MEMINDEX;
1512 case OP_LOADU1_MEMBASE:
1513 return OP_LOADU1_MEMINDEX;
1514 case OP_LOADI2_MEMBASE:
1515 return OP_LOADI2_MEMINDEX;
1516 case OP_LOADU2_MEMBASE:
1517 return OP_LOADU2_MEMINDEX;
1518 case OP_LOADI1_MEMBASE:
1519 return OP_LOADI1_MEMINDEX;
1520 case OP_LOADR4_MEMBASE:
1521 return OP_LOADR4_MEMINDEX;
1522 case OP_LOADR8_MEMBASE:
1523 return OP_LOADR8_MEMINDEX;
1524 case OP_STOREI1_MEMBASE_REG:
1525 return OP_STOREI1_MEMINDEX;
1526 case OP_STOREI2_MEMBASE_REG:
1527 return OP_STOREI2_MEMINDEX;
1528 case OP_STOREI4_MEMBASE_REG:
1529 return OP_STOREI4_MEMINDEX;
1530 case OP_STORE_MEMBASE_REG:
1531 return OP_STORE_MEMINDEX;
1532 case OP_STORER4_MEMBASE_REG:
1533 return OP_STORER4_MEMINDEX;
1534 case OP_STORER8_MEMBASE_REG:
1535 return OP_STORER8_MEMINDEX;
1536 case OP_STORE_MEMBASE_IMM:
1537 return OP_STORE_MEMBASE_REG;
1538 case OP_STOREI1_MEMBASE_IMM:
1539 return OP_STOREI1_MEMBASE_REG;
1540 case OP_STOREI2_MEMBASE_IMM:
1541 return OP_STOREI2_MEMBASE_REG;
1542 case OP_STOREI4_MEMBASE_IMM:
1543 return OP_STOREI4_MEMBASE_REG;
1545 g_assert_not_reached ();
1549 * Remove from the instruction list the instructions that can't be
1550 * represented with very simple instructions with no register
1554 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1556 MonoInst *ins, *next, *temp, *last_ins = NULL;
1559 /* setup the virtual reg allocator */
1560 if (bb->max_vreg > cfg->rs->next_vreg)
1561 cfg->rs->next_vreg = bb->max_vreg;
1563 MONO_BB_FOR_EACH_INS (bb, ins) {
1565 switch (ins->opcode) {
1568 if (!mips_is_imm16 (ins->inst_imm)) {
1569 NEW_INS (cfg, temp, OP_ICONST);
1570 temp->inst_c0 = ins->inst_imm;
1571 temp->dreg = mono_regstate_next_int (cfg->rs);
1572 ins->sreg2 = temp->dreg;
1573 ins->opcode = map_to_reg_reg_op (ins->opcode);
1578 if (!mips_is_imm16 (-ins->inst_imm)) {
1579 NEW_INS (cfg, temp, OP_ICONST);
1580 temp->inst_c0 = ins->inst_imm;
1581 temp->dreg = mono_regstate_next_int (cfg->rs);
1582 ins->sreg2 = temp->dreg;
1583 ins->opcode = map_to_reg_reg_op (ins->opcode);
1591 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
1592 NEW_INS (cfg, temp, OP_ICONST);
1593 temp->inst_c0 = ins->inst_imm;
1594 temp->dreg = mono_regstate_next_int (cfg->rs);
1595 ins->sreg2 = temp->dreg;
1596 ins->opcode = map_to_reg_reg_op (ins->opcode);
1604 NEW_INS (cfg, temp, OP_ICONST);
1605 temp->inst_c0 = ins->inst_imm;
1606 temp->dreg = mono_regstate_next_int (cfg->rs);
1607 ins->sreg2 = temp->dreg;
1608 ins->opcode = map_to_reg_reg_op (ins->opcode);
1612 case OP_COMPARE_IMM:
1613 if (compare_opcode_is_unsigned (ins->next->opcode)) {
1614 if (!ppc_is_uimm16 (ins->inst_imm)) {
1615 NEW_INS (cfg, temp, OP_ICONST);
1616 temp->inst_c0 = ins->inst_imm;
1617 temp->dreg = mono_regstate_next_int (cfg->rs);
1618 ins->sreg2 = temp->dreg;
1619 ins->opcode = map_to_reg_reg_op (ins->opcode);
1622 if (!ppc_is_imm16 (ins->inst_imm)) {
1623 NEW_INS (cfg, temp, OP_ICONST);
1624 temp->inst_c0 = ins->inst_imm;
1625 temp->dreg = mono_regstate_next_int (cfg->rs);
1626 ins->sreg2 = temp->dreg;
1627 ins->opcode = map_to_reg_reg_op (ins->opcode);
1634 if (ins->inst_imm == 1) {
1635 ins->opcode = OP_MOVE;
1638 if (ins->inst_imm == 0) {
1639 ins->opcode = OP_ICONST;
1643 imm = mono_is_power_of_two (ins->inst_imm);
1645 ins->opcode = OP_SHL_IMM;
1646 ins->inst_imm = imm;
1649 if (!ppc_is_imm16 (ins->inst_imm)) {
1650 NEW_INS (cfg, temp, OP_ICONST);
1651 temp->inst_c0 = ins->inst_imm;
1652 temp->dreg = mono_regstate_next_int (cfg->rs);
1653 ins->sreg2 = temp->dreg;
1654 ins->opcode = map_to_reg_reg_op (ins->opcode);
1659 case OP_LOAD_MEMBASE:
1660 case OP_LOADI4_MEMBASE:
1661 case OP_LOADU4_MEMBASE:
1662 case OP_LOADI2_MEMBASE:
1663 case OP_LOADU2_MEMBASE:
1664 case OP_LOADI1_MEMBASE:
1665 case OP_LOADU1_MEMBASE:
1666 case OP_LOADR4_MEMBASE:
1667 case OP_LOADR8_MEMBASE:
1668 case OP_STORE_MEMBASE_REG:
1669 case OP_STOREI4_MEMBASE_REG:
1670 case OP_STOREI2_MEMBASE_REG:
1671 case OP_STOREI1_MEMBASE_REG:
1672 case OP_STORER4_MEMBASE_REG:
1673 case OP_STORER8_MEMBASE_REG:
1674 /* we can do two things: load the immed in a register
1675 * and use an indexed load, or see if the immed can be
1676 * represented as an ad_imm + a load with a smaller offset
1677 * that fits. We just do the first for now, optimize later.
1679 if (ppc_is_imm16 (ins->inst_offset))
1681 NEW_INS (cfg, temp, OP_ICONST);
1682 temp->inst_c0 = ins->inst_offset;
1683 temp->dreg = mono_regstate_next_int (cfg->rs);
1684 ins->sreg2 = temp->dreg;
1685 ins->opcode = map_to_reg_reg_op (ins->opcode);
1688 case OP_STORE_MEMBASE_IMM:
1689 case OP_STOREI1_MEMBASE_IMM:
1690 case OP_STOREI2_MEMBASE_IMM:
1691 case OP_STOREI4_MEMBASE_IMM:
1692 if (!ins->inst_imm) {
1693 ins->sreg1 = mips_zero;
1694 ins->opcode = map_to_reg_reg_op (ins->opcode);
1697 NEW_INS (cfg, temp, OP_ICONST);
1698 temp->inst_c0 = ins->inst_imm;
1699 temp->dreg = mono_regstate_next_int (cfg->rs);
1700 ins->sreg1 = temp->dreg;
1701 ins->opcode = map_to_reg_reg_op (ins->opcode);
1703 goto loop_start; /* make it handle the possibly big ins->inst_offset */
1709 bb->last_ins = last_ins;
1710 bb->max_vreg = cfg->rs->next_vreg;
1714 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
1716 /* sreg is a float, dreg is an integer reg. mips_at is used a scratch */
1718 mips_truncwd (code, mips_ftemp, sreg);
1720 mips_cvtwd (code, mips_ftemp, sreg);
1722 mips_mfc1 (code, dreg, mips_ftemp);
1725 mips_andi (code, dreg, dreg, 0xff);
1726 else if (size == 2) {
1727 mips_sll (code, dreg, dreg, 16);
1728 mips_srl (code, dreg, dreg, 16);
1732 mips_sll (code, dreg, dreg, 24);
1733 mips_sra (code, dreg, dreg, 24);
1735 else if (size == 2) {
1736 mips_sll (code, dreg, dreg, 16);
1737 mips_sra (code, dreg, dreg, 16);
1744 * emit_load_volatile_arguments:
1746 * Load volatile arguments from the stack to the original input registers.
1747 * Required before a tail call.
1750 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
1752 MonoMethod *method = cfg->method;
1753 MonoMethodSignature *sig;
1758 sig = mono_method_signature (method);
1759 cinfo = calculate_sizes (sig, sig->pinvoke);
1760 if (cinfo->struct_ret) {
1761 ArgInfo *ainfo = &cinfo->ret;
1762 inst = cfg->vret_addr;
1763 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1766 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1767 ArgInfo *ainfo = cinfo->args + i;
1768 inst = cfg->args [i];
1769 if (inst->opcode == OP_REGVAR) {
1770 if (ainfo->regtype == RegTypeGeneral)
1771 mips_move (code, ainfo->reg, inst->dreg);
1772 else if (ainfo->regtype == RegTypeFP)
1773 g_assert_not_reached();
1774 else if (ainfo->regtype == RegTypeBase) {
1777 g_assert_not_reached ();
1779 if (ainfo->regtype == RegTypeGeneral) {
1780 g_assert (mips_is_imm16 (inst->inst_offset));
1781 switch (ainfo->size) {
1783 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1786 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1790 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1793 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1794 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
1797 g_assert_not_reached ();
1800 } else if (ainfo->regtype == RegTypeBase) {
1802 } else if (ainfo->regtype == RegTypeFP) {
1803 g_assert (mips_is_imm16 (inst->inst_offset));
1804 if (ainfo->size == 8)
1805 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1806 else if (ainfo->size == 4)
1807 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1809 g_assert_not_reached ();
1810 } else if (ainfo->regtype == RegTypeStructByVal) {
1812 int doffset = inst->inst_offset;
1814 g_assert (mips_is_imm16 (inst->inst_offset));
1815 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
1816 for (i = 0; i < ainfo->size; ++i) {
1817 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
1818 doffset += sizeof (gpointer);
1820 } else if (ainfo->regtype == RegTypeStructByAddr) {
1821 g_assert (mips_is_imm16 (inst->inst_offset));
1822 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1824 g_assert_not_reached ();
1834 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
1839 guint8 *code = cfg->native_code + cfg->code_len;
1840 MonoInst *last_ins = NULL;
1841 guint last_offset = 0;
1845 /* we don't align basic blocks of loops on mips */
1847 if (cfg->verbose_level > 2)
1848 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
1850 cpos = bb->max_offset;
1853 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
1854 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
1855 g_assert (!mono_compile_aot);
1858 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
1859 /* this is not thread save, but good enough */
1860 /* fixme: howto handle overflows? */
1861 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
1862 mips_lw (code, mips_temp, mips_at, 0);
1863 mips_addiu (code, mips_temp, mips_temp, 1);
1864 mips_sw (code, mips_temp, mips_at, 0);
1867 MONO_BB_FOR_EACH_INS (bb, ins) {
1868 offset = code - cfg->native_code;
1870 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
1872 if (offset > (cfg->code_size - max_len - 16)) {
1873 cfg->code_size *= 2;
1874 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1875 code = cfg->native_code + offset;
1877 mono_debug_record_line_number (cfg, ins, offset);
1878 if (cfg->verbose_level > 2) {
1879 g_print (" @ 0x%x\t", offset);
1880 mono_print_ins_index (ins_cnt++, ins);
1883 switch (ins->opcode) {
1885 g_assert_not_reached();
1887 emit_tls_access (code, ins->dreg, ins->inst_offset);
1891 mips_mult (code, ins->sreg1, ins->sreg2);
1892 mips_mflo (code, ins->dreg);
1893 mips_mfhi (code, ins->dreg+1);
1896 mips_multu (code, ins->sreg1, ins->sreg2);
1897 mips_mflo (code, ins->dreg);
1898 mips_mfhi (code, ins->dreg+1);
1900 case OP_MEMORY_BARRIER:
1905 case OP_STOREI1_MEMBASE_IMM:
1906 mips_load_const (code, mips_temp, ins->inst_imm);
1907 if (mips_is_imm16 (ins->inst_offset)) {
1908 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
1910 mips_load_const (code, mips_at, ins->inst_offset);
1911 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
1914 case OP_STOREI2_MEMBASE_IMM:
1915 mips_load_const (code, mips_temp, ins->inst_imm);
1916 if (mips_is_imm16 (ins->inst_offset)) {
1917 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
1919 mips_load_const (code, mips_at, ins->inst_offset);
1920 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
1923 case OP_STORE_MEMBASE_IMM:
1924 case OP_STOREI4_MEMBASE_IMM:
1925 mips_load_const (code, mips_temp, ins->inst_imm);
1926 if (mips_is_imm16 (ins->inst_offset)) {
1927 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
1929 mips_load_const (code, mips_at, ins->inst_offset);
1930 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
1933 case OP_STOREI1_MEMBASE_REG:
1934 if (mips_is_imm16 (ins->inst_offset)) {
1935 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1937 mips_load_const (code, mips_at, ins->inst_offset);
1938 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
1939 mips_sb (code, ins->sreg1, mips_at, 0);
1942 case OP_STOREI2_MEMBASE_REG:
1943 if (mips_is_imm16 (ins->inst_offset)) {
1944 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1946 mips_load_const (code, mips_at, ins->inst_offset);
1947 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
1948 mips_sh (code, ins->sreg1, mips_at, 0);
1951 case OP_STORE_MEMBASE_REG:
1952 case OP_STOREI4_MEMBASE_REG:
1953 if (mips_is_imm16 (ins->inst_offset)) {
1954 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1956 mips_load_const (code, mips_at, ins->inst_offset);
1957 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
1958 mips_sw (code, ins->sreg1, mips_at, 0);
1962 g_assert_not_reached ();
1963 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
1964 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
1966 case OP_LOAD_MEMBASE:
1967 case OP_LOADI4_MEMBASE:
1968 case OP_LOADU4_MEMBASE:
1969 if (mips_is_imm16 (ins->inst_offset)) {
1970 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1972 mips_load_const (code, mips_at, ins->inst_offset);
1973 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1974 mips_lw (code, ins->dreg, mips_at, 0);
1977 case OP_LOADI1_MEMBASE:
1978 if (mips_is_imm16 (ins->inst_offset)) {
1979 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1981 mips_load_const (code, mips_at, ins->inst_offset);
1982 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1983 mips_lb (code, ins->dreg, mips_at, 0);
1986 case OP_LOADU1_MEMBASE:
1987 if (mips_is_imm16 (ins->inst_offset)) {
1988 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1990 mips_load_const (code, mips_at, ins->inst_offset);
1991 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1992 mips_lbu (code, ins->dreg, mips_at, 0);
1995 case OP_LOADI2_MEMBASE:
1996 if (mips_is_imm16 (ins->inst_offset)) {
1997 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1999 mips_load_const (code, mips_at, ins->inst_offset);
2000 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2001 mips_lh (code, ins->dreg, mips_at, 0);
2004 case OP_LOADU2_MEMBASE:
2005 if (mips_is_imm16 (ins->inst_offset)) {
2006 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2008 mips_load_const (code, mips_at, ins->inst_offset);
2009 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2010 mips_lhu (code, ins->dreg, mips_at, 0);
2014 mips_sll (code, mips_at, ins->sreg1, 24);
2015 mips_sra (code, ins->dreg, mips_at, 24);
2018 mips_sll (code, mips_at, ins->sreg1, 16);
2019 mips_sra (code, ins->dreg, mips_at, 16);
2022 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
2025 mips_sll (code, mips_at, ins->sreg1, 16);
2026 mips_srl (code, ins->dreg, mips_at, 16);
2029 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
2032 g_assert (mips_is_imm16 (ins->inst_imm));
2033 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
2036 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
2039 g_assert (mips_is_imm16 (ins->inst_imm));
2040 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
2042 case OP_COMPARE_IMM:
2043 g_assert_not_reached ();
2046 g_assert_not_reached ();
2049 mips_break (code, 0xfd);
2052 g_assert_not_reached ();
2055 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
2058 g_assert_not_reached ();
2061 g_assert_not_reached ();
2064 if (mips_is_imm16 (ins->inst_imm)) {
2065 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
2067 mips_load_const (code, mips_at, ins->inst_imm);
2068 mips_addu (code, ins->dreg, ins->sreg1, mips_at);
2072 g_assert_not_reached ();
2075 /* rewritten in .brg file */
2076 g_assert_not_reached ();
2078 case CEE_ADD_OVF_UN:
2079 /* rewritten in .brg file */
2080 g_assert_not_reached ();
2083 /* rewritten in .brg file */
2084 g_assert_not_reached ();
2086 case CEE_SUB_OVF_UN:
2087 /* rewritten in .brg file */
2088 g_assert_not_reached ();
2090 case OP_ADD_OVF_CARRY:
2091 /* rewritten in .brg file */
2092 g_assert_not_reached ();
2094 case OP_ADD_OVF_UN_CARRY:
2095 /* rewritten in .brg file */
2096 g_assert_not_reached ();
2098 case OP_SUB_OVF_CARRY:
2099 /* rewritten in .brg file */
2100 g_assert_not_reached ();
2102 case OP_SUB_OVF_UN_CARRY:
2103 /* rewritten in .brg file */
2104 g_assert_not_reached ();
2107 /* rewritten in .brg file */
2108 g_assert_not_reached ();
2111 /* rewritten in .brg file */
2112 g_assert_not_reached ();
2115 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
2118 g_assert_not_reached ();
2121 // we add the negated value
2122 if (mips_is_imm16 (-ins->inst_imm))
2123 mips_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2125 mips_load_const (code, mips_at, ins->inst_imm);
2126 mips_subu (code, ins->dreg, ins->sreg1, mips_at);
2130 g_assert_not_reached ();
2133 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2136 if (mips_is_imm16 (ins->inst_imm)) {
2137 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2139 mips_load_const (code, mips_at, ins->inst_imm);
2140 mips_and (code, ins->dreg, ins->sreg1, mips_at);
2145 guint32 *divisor_is_m1;
2146 guint32 *divisor_is_zero;
2149 mips_addiu (code, mips_at, mips_zero, 0xffff);
2150 divisor_is_m1 = (guint32 *)code;
2151 mips_bne (code, ins->sreg2, mips_at, 0);
2154 /* Divide by -1 -- throw exception */
2155 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
2157 mips_patch (divisor_is_m1, (guint32)code);
2159 /* Put divide in branch delay slot (NOT YET) */
2160 divisor_is_zero = (guint32 *)code;
2161 mips_bne (code, ins->sreg2, mips_zero, 0);
2164 /* Divide by zero -- throw exception */
2165 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2167 mips_patch (divisor_is_zero, (guint32)code);
2168 mips_div (code, ins->sreg1, ins->sreg2);
2169 if (ins->opcode == CEE_DIV)
2170 mips_mflo (code, ins->dreg);
2172 mips_mfhi (code, ins->dreg);
2176 guint32 *divisor_is_zero = (guint32 *)(void *)code;
2178 /* Put divide in branch delay slot (NOT YET) */
2179 mips_bne (code, ins->sreg2, mips_zero, 0);
2182 /* Divide by zero -- throw exception */
2183 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2185 mips_patch (divisor_is_zero, (guint32)code);
2186 mips_divu (code, ins->sreg1, ins->sreg2);
2187 mips_mflo (code, ins->dreg);
2191 g_assert_not_reached ();
2193 ppc_load (code, ppc_r11, ins->inst_imm);
2194 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
2195 ppc_mfspr (code, ppc_r0, ppc_xer);
2196 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2197 /* FIXME: use OverflowException for 0x80000000/-1 */
2198 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2200 g_assert_not_reached();
2203 guint32 *divisor_is_zero = (guint32 *)(void *)code;
2205 /* Put divide in branch delay slot (NOT YET) */
2206 mips_bne (code, ins->sreg2, mips_zero, 0);
2209 /* Divide by zero -- throw exception */
2210 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2212 mips_patch (divisor_is_zero, (guint32)code);
2213 mips_divu (code, ins->sreg1, ins->sreg2);
2214 mips_mfhi (code, ins->dreg);
2218 g_assert_not_reached ();
2220 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2223 if (mips_is_imm16 (ins->inst_imm)) {
2224 mips_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2226 mips_load_const (code, mips_at, ins->inst_imm);
2227 mips_or (code, ins->dreg, ins->sreg1, mips_at);
2231 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2234 /* unsigned 16-bit immediate */
2235 if ((ins->inst_imm & 0xffff) == ins->inst_imm) {
2236 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
2238 mips_load_const (code, mips_at, ins->inst_imm);
2239 mips_xor (code, ins->dreg, ins->sreg1, mips_at);
2243 g_assert (mips_is_imm16 (ins->inst_imm));
2244 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
2247 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
2250 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2253 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
2256 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2259 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2262 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
2265 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
2268 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
2272 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
2274 mips_mult (code, ins->sreg1, ins->sreg2);
2275 mips_mflo (code, ins->dreg);
2281 mips_load_const (code, mips_at, ins->inst_imm);
2283 mips_mul (code, ins->dreg, ins->sreg1, mips_at);
2285 mips_mult (code, ins->sreg1, mips_at);
2286 mips_mflo (code, ins->dreg);
2293 mips_mult (code, ins->sreg1, ins->sreg2);
2294 mips_mflo (code, ins->dreg);
2295 mips_mfhi (code, mips_at);
2298 mips_sra (code, mips_temp, ins->dreg, 31);
2299 patch = (guint32 *)(void *)code;
2300 mips_beq (code, mips_temp, mips_at, 0);
2302 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
2303 mips_patch (patch, (guint32)code);
2306 case CEE_MUL_OVF_UN:
2308 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
2310 mips_mult (code, ins->sreg1, ins->sreg2);
2311 mips_mflo (code, ins->dreg);
2312 mips_mfhi (code, mips_at);
2316 /* XXX - Throw exception if we overflowed */
2319 mips_load_const (code, ins->dreg, ins->inst_c0);
2322 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2323 mips_load (code, ins->dreg, 0);
2327 mips_mtc1 (code, ins->dreg, ins->sreg1);
2330 mips_mfc1 (code, ins->dreg, ins->sreg1);
2333 mips_dmtc1 (code, ins->dreg, ins->sreg1);
2336 mips_dmfc1 (code, ins->dreg, ins->sreg1);
2342 if (ins->dreg != ins->sreg1)
2343 mips_move (code, ins->dreg, ins->sreg1);
2346 /* Get sreg1 into v1, sreg2 into v0 */
2348 if (ins->sreg1 == mips_v0) {
2349 if (ins->sreg1 != mips_at)
2350 mips_move (code, mips_at, ins->sreg1);
2351 if (ins->sreg2 != mips_v0)
2352 mips_move (code, mips_v0, ins->sreg2);
2353 mips_move (code, mips_v1, mips_at);
2356 if (ins->sreg2 != mips_v0)
2357 mips_move (code, mips_v0, ins->sreg2);
2358 if (ins->sreg1 != mips_v1)
2359 mips_move (code, mips_v1, ins->sreg1);
2363 if (ins->dreg != ins->sreg1) {
2364 mips_fmovd (code, ins->dreg, ins->sreg1);
2368 /* Convert from double to float and leave it there */
2369 mips_cvtsd (code, ins->dreg, ins->sreg1);
2371 case OP_FCONV_TO_R4:
2372 /* Convert from double to float and back again */
2373 mips_cvtsd (code, ins->dreg, ins->sreg1);
2374 mips_cvtds (code, ins->dreg, ins->dreg);
2377 code = emit_load_volatile_arguments(cfg, code);
2380 * Pop our stack, then jump to specified method (tail-call)
2381 * Keep in sync with mono_arch_emit_epilog
2383 code = mono_arch_emit_epilog_sub (cfg, code);
2385 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
2386 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2388 mips_lui (code, mips_t9, mips_zero, 0);
2389 mips_addiu (code, mips_t9, mips_t9, 0);
2390 mips_jr (code, mips_t9);
2393 mips_beq (code, mips_zero, mips_zero, 0);
2398 /* ensure ins->sreg1 is not NULL */
2399 mips_lw (code, mips_zero, ins->sreg1, 0);
2402 if (mips_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2403 mips_addiu (code, mips_at, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2405 mips_load_const (code, mips_at, cfg->sig_cookie + cfg->stack_usage);
2406 mips_addu (code, mips_at, cfg->frame_reg, mips_at);
2408 mips_sw (code, mips_at, ins->sreg1, 0);
2419 case OP_VOIDCALL_REG:
2421 case OP_FCALL_MEMBASE:
2422 case OP_LCALL_MEMBASE:
2423 case OP_VCALL_MEMBASE:
2424 case OP_VOIDCALL_MEMBASE:
2425 case OP_CALL_MEMBASE:
2426 call = (MonoCallInst*)ins;
2427 switch (ins->opcode) {
2433 if (ins->flags & MONO_INST_HAS_METHOD)
2434 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2436 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2437 mips_lui (code, mips_t9, mips_zero, 0);
2438 mips_addiu (code, mips_t9, mips_t9, 0);
2443 case OP_VOIDCALL_REG:
2445 mips_move (code, mips_t9, ins->sreg1);
2447 case OP_FCALL_MEMBASE:
2448 case OP_LCALL_MEMBASE:
2449 case OP_VCALL_MEMBASE:
2450 case OP_VOIDCALL_MEMBASE:
2451 case OP_CALL_MEMBASE:
2452 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
2455 mips_jalr (code, mips_t9, mips_ra);
2457 if ((ins->opcode == OP_FCALL ||
2458 ins->opcode == OP_FCALL_REG) &&
2459 call->signature->ret->type == MONO_TYPE_R4) {
2460 mips_cvtds (code, mips_f0, mips_f0);
2464 g_assert_not_reached ();
2467 int area_offset = cfg->param_area;
2469 /* Round up ins->sreg1, mips_at ends up holding size */
2470 mips_addiu (code, mips_at, ins->sreg1, 31);
2471 mips_andi (code, mips_at, mips_at, ~31);
2473 mips_subu (code, mips_sp, mips_sp, mips_at);
2474 mips_addiu (code, ins->dreg, mips_sp, area_offset);
2476 if (ins->flags & MONO_INST_INIT) {
2477 mips_move (code, mips_temp, ins->dreg);
2478 mips_sb (code, mips_zero, mips_temp, 0);
2479 mips_addiu (code, mips_at, mips_at, -1);
2480 mips_bne (code, mips_at, mips_zero, -4);
2481 mips_addiu (code, mips_temp, mips_temp, 1);
2486 gpointer addr = mono_arch_get_throw_exception();
2487 mips_move (code, mips_a0, ins->sreg1);
2488 mips_load_const (code, mips_t9, addr);
2489 mips_jalr (code, mips_t9, mips_ra);
2491 mips_break (code, 0xfc);
2495 gpointer addr = mono_arch_get_rethrow_exception();
2496 mips_move (code, mips_a0, ins->sreg1);
2497 mips_load_const (code, mips_t9, addr);
2498 mips_jalr (code, mips_t9, mips_ra);
2500 mips_break (code, 0xfb);
2503 case OP_START_HANDLER:
2505 * The START_HANDLER instruction marks the beginning of a handler
2506 * block. It is called using a call instruction, so mips_ra contains
2507 * the return address. Since the handler executes in the same stack
2508 * frame as the method itself, we can't use save/restore to save
2509 * the return address. Instead, we save it into a dedicated
2512 if (mips_is_imm16 (ins->inst_left->inst_offset)) {
2513 mips_sw (code, mips_ra, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2515 mips_load_const (code, mips_at, ins->inst_left->inst_offset);
2516 mips_add (code, mips_at, mips_at, ins->inst_left->inst_basereg);
2517 mips_sw (code, mips_ra, mips_at, 0);
2521 if (ins->sreg1 != mips_v0)
2522 mips_move (code, mips_v0, ins->sreg1);
2523 if (mips_is_imm16 (ins->inst_left->inst_offset)) {
2524 mips_lw (code, mips_ra, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2526 mips_load_const (code, mips_at, ins->inst_left->inst_offset);
2527 mips_addu (code, mips_at, mips_at, ins->inst_left->inst_basereg);
2528 mips_lw (code, mips_ra, mips_at, 0);
2530 mips_jr (code, mips_ra);
2534 mips_lw (code, mips_t9, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2535 mips_jalr (code, mips_t9, mips_ra);
2538 case OP_CALL_HANDLER:
2539 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2540 mips_lui (code, mips_t9, mips_zero, 0);
2541 mips_addiu (code, mips_t9, mips_t9, 0);
2542 mips_jalr (code, mips_t9, mips_ra);
2546 ins->inst_c0 = code - cfg->native_code;
2549 if (ins->flags & MONO_INST_BRLABEL) {
2550 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2552 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2555 mips_lui (code, mips_at, mips_zero, 0);
2556 mips_addiu (code, mips_at, mips_at, 0);
2557 mips_jr (code, mips_at);
2560 mips_beq (code, mips_zero, mips_zero, 0);
2565 mips_jr (code, ins->sreg1);
2571 max_len += 4 * GPOINTER_TO_INT (ins->klass);
2572 if (offset > (cfg->code_size - max_len - 16)) {
2573 cfg->code_size += max_len;
2574 cfg->code_size *= 2;
2575 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2576 code = cfg->native_code + offset;
2578 g_assert (ins->sreg1 != -1);
2579 mips_sll (code, mips_at, ins->sreg1, 2);
2580 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
2581 mips_move (code, mips_t8, mips_ra);
2582 mips_bgezal (code, mips_zero, 1); /* bal */
2584 mips_addu (code, mips_t9, mips_ra, mips_at);
2585 /* Table is 16 or 20 bytes from target of bal above */
2586 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
2587 mips_move (code, mips_ra, mips_t8);
2588 mips_lw (code, mips_t9, mips_t9, 20);
2591 mips_lw (code, mips_t9, mips_t9, 16);
2592 mips_jalr (code, mips_t9, mips_t8);
2594 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
2595 mips_emit32 (code, 0xfefefefe);
2599 mips_addiu (code, ins->dreg, mips_zero, 1);
2600 mips_beq (code, mips_at, mips_zero, 2);
2602 mips_move (code, ins->dreg, mips_zero);
2606 mips_addiu (code, ins->dreg, mips_zero, 1);
2607 mips_bltz (code, mips_at, 2);
2609 mips_move (code, ins->dreg, mips_zero);
2613 mips_addiu (code, ins->dreg, mips_zero, 1);
2614 mips_bgtz (code, mips_at, 2);
2616 mips_move (code, ins->dreg, mips_zero);
2619 case OP_COND_EXC_EQ:
2620 case OP_COND_EXC_GE:
2621 case OP_COND_EXC_GT:
2622 case OP_COND_EXC_LE:
2623 case OP_COND_EXC_LT:
2624 case OP_COND_EXC_NE_UN:
2625 case OP_COND_EXC_GE_UN:
2626 case OP_COND_EXC_GT_UN:
2627 case OP_COND_EXC_LE_UN:
2628 case OP_COND_EXC_LT_UN:
2630 case OP_COND_EXC_OV:
2631 case OP_COND_EXC_NO:
2633 case OP_COND_EXC_NC:
2635 case OP_COND_EXC_IEQ:
2636 case OP_COND_EXC_IGE:
2637 case OP_COND_EXC_IGT:
2638 case OP_COND_EXC_ILE:
2639 case OP_COND_EXC_ILT:
2640 case OP_COND_EXC_INE_UN:
2641 case OP_COND_EXC_IGE_UN:
2642 case OP_COND_EXC_IGT_UN:
2643 case OP_COND_EXC_ILE_UN:
2644 case OP_COND_EXC_ILT_UN:
2646 case OP_COND_EXC_IOV:
2647 case OP_COND_EXC_INO:
2648 case OP_COND_EXC_IC:
2649 case OP_COND_EXC_INC:
2650 /* Should be re-mapped to OP_MIPS_B* by *.inssel-mips.brg */
2651 g_warning ("unsupported conditional exception %s\n", mono_inst_name (ins->opcode));
2652 g_assert_not_reached ();
2655 case OP_MIPS_COND_EXC_EQ:
2656 case OP_MIPS_COND_EXC_GE:
2657 case OP_MIPS_COND_EXC_GT:
2658 case OP_MIPS_COND_EXC_LE:
2659 case OP_MIPS_COND_EXC_LT:
2660 case OP_MIPS_COND_EXC_NE_UN:
2661 case OP_MIPS_COND_EXC_GE_UN:
2662 case OP_MIPS_COND_EXC_GT_UN:
2663 case OP_MIPS_COND_EXC_LE_UN:
2664 case OP_MIPS_COND_EXC_LT_UN:
2666 case OP_MIPS_COND_EXC_OV:
2667 case OP_MIPS_COND_EXC_NO:
2668 case OP_MIPS_COND_EXC_C:
2669 case OP_MIPS_COND_EXC_NC:
2671 case OP_MIPS_COND_EXC_IEQ:
2672 case OP_MIPS_COND_EXC_IGE:
2673 case OP_MIPS_COND_EXC_IGT:
2674 case OP_MIPS_COND_EXC_ILE:
2675 case OP_MIPS_COND_EXC_ILT:
2676 case OP_MIPS_COND_EXC_INE_UN:
2677 case OP_MIPS_COND_EXC_IGE_UN:
2678 case OP_MIPS_COND_EXC_IGT_UN:
2679 case OP_MIPS_COND_EXC_ILE_UN:
2680 case OP_MIPS_COND_EXC_ILT_UN:
2682 case OP_MIPS_COND_EXC_IOV:
2683 case OP_MIPS_COND_EXC_INO:
2684 case OP_MIPS_COND_EXC_IC:
2685 case OP_MIPS_COND_EXC_INC: {
2689 /* If the condition is true, raise the exception */
2691 /* need to reverse test to skip around exception raising */
2693 /* For the moment, branch around a branch to avoid reversing
2696 /* Remember, an unpatched branch to 0 branches to the delay slot */
2697 throw = (guint32 *)(void *)code;
2698 switch (ins->opcode) {
2699 case OP_MIPS_COND_EXC_EQ:
2700 mips_beq (code, ins->sreg1, ins->sreg2, 0);
2703 case OP_MIPS_COND_EXC_NE_UN:
2704 mips_bne (code, ins->sreg1, ins->sreg2, 0);
2708 /* Not yet implemented */
2709 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
2710 g_assert_not_reached ();
2712 skip = (guint32 *)(void *)code;
2713 mips_beq (code, mips_zero, mips_zero, 0);
2715 mips_patch (throw, (guint32)code);
2716 code = mips_emit_exc_by_name (code, ins->inst_p1);
2717 mips_patch (skip, (guint32)code);
2718 cfg->bb_exit->max_offset += 24;
2731 /* Should be re-mapped to OP_MIPS_B* by *.inssel-mips.brg */
2732 g_warning ("unsupported conditional set %s\n", mono_inst_name (ins->opcode));
2733 g_assert_not_reached ();
2741 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
2744 /* floating point opcodes */
2746 if (((guint32)ins->inst_p0) & (1 << 15))
2747 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
2749 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
2750 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
2753 if (((guint32)ins->inst_p0) & (1 << 15))
2754 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
2756 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
2757 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
2758 mips_cvtds (code, ins->dreg, ins->dreg);
2760 case OP_STORER8_MEMBASE_REG:
2761 if (mips_is_imm16 (ins->inst_offset)) {
2763 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2765 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset+4);
2766 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset);
2769 mips_load_const (code, mips_at, ins->inst_offset);
2770 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
2771 mips_swc1 (code, ins->sreg1, mips_at, 4);
2772 mips_swc1 (code, ins->sreg1+1, mips_at, 0);
2775 case OP_LOADR8_MEMBASE:
2776 if (mips_is_imm16 (ins->inst_offset)) {
2778 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2780 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset+4);
2781 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset);
2784 mips_load_const (code, mips_at, ins->inst_offset);
2785 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2786 mips_lwc1 (code, ins->dreg, mips_at, 4);
2787 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
2790 case OP_STORER4_MEMBASE_REG:
2791 /* XXX Need to convert ins->sreg1 to single-precision first */
2792 mips_cvtsd (code, mips_ftemp, ins->sreg1);
2793 if (mips_is_imm16 (ins->inst_offset)) {
2794 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
2796 mips_load_const (code, mips_at, ins->inst_offset);
2797 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
2798 mips_swc1 (code, mips_ftemp, mips_at, 0);
2802 if (mips_is_imm16 (ins->inst_offset)) {
2803 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2805 mips_load_const (code, mips_at, ins->inst_offset);
2806 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2807 mips_lwc1 (code, ins->dreg, mips_at, 0);
2810 case OP_LOADR4_MEMBASE:
2811 if (mips_is_imm16 (ins->inst_offset)) {
2812 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2814 mips_load_const (code, mips_at, ins->inst_offset);
2815 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2816 mips_lwc1 (code, ins->dreg, mips_at, 0);
2818 /* Convert to double precision in place */
2819 mips_cvtds (code, ins->dreg, ins->dreg);
2821 case CEE_CONV_R_UN: {
2822 static const guint64 adjust_val = 0x41F0000000000000ULL;
2824 /* convert unsigned int to double */
2825 mips_mtc1 (code, mips_ftemp, ins->sreg1);
2826 mips_bgez (code, ins->sreg1, 5);
2827 mips_cvtdw (code, ins->dreg, mips_ftemp);
2829 mips_load (code, mips_at, (guint32) &adjust_val);
2830 mips_ldc1 (code, mips_ftemp, mips_at, 0);
2831 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
2832 /* target is here */
2836 mips_mtc1 (code, mips_ftemp, ins->sreg1);
2837 mips_cvtsw (code, ins->dreg, mips_ftemp);
2838 mips_cvtds (code, ins->dreg, ins->dreg);
2841 mips_mtc1 (code, mips_ftemp, ins->sreg1);
2842 mips_cvtdw (code, ins->dreg, mips_ftemp);
2844 case OP_FCONV_TO_I1:
2845 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2847 case OP_FCONV_TO_U1:
2848 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2850 case OP_FCONV_TO_I2:
2851 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
2853 case OP_FCONV_TO_U2:
2854 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
2856 case OP_FCONV_TO_I4:
2858 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
2860 case OP_FCONV_TO_U4:
2862 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
2864 case OP_FCONV_TO_I8:
2865 case OP_FCONV_TO_U8:
2866 g_assert_not_reached ();
2867 /* Implemented as helper calls */
2869 case OP_LCONV_TO_R_UN:
2870 g_assert_not_reached ();
2871 /* Implemented as helper calls */
2873 case OP_LCONV_TO_OVF_I:
2874 g_assert_not_reached ();
2875 /* split up by brg file */
2878 mips_fsqrtd (code, ins->dreg, ins->sreg1);
2881 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
2884 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
2887 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
2890 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
2893 mips_fnegd (code, ins->dreg, ins->sreg1);
2897 g_assert_not_reached ();
2900 g_assert_not_reached();
2903 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
2904 mips_addiu (code, ins->dreg, mips_zero, 1);
2905 mips_fbtrue (code, 2);
2907 mips_move (code, ins->dreg, mips_zero);
2910 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
2911 mips_addiu (code, ins->dreg, mips_zero, 1);
2912 mips_fbtrue (code, 2);
2914 mips_move (code, ins->dreg, mips_zero);
2917 /* Less than, or Unordered */
2918 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
2919 mips_addiu (code, ins->dreg, mips_zero, 1);
2920 mips_fbtrue (code, 2);
2922 mips_move (code, ins->dreg, mips_zero);
2925 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
2926 mips_move (code, ins->dreg, mips_zero);
2927 mips_fbtrue (code, 2);
2929 mips_addiu (code, ins->dreg, mips_zero, 1);
2932 /* Greater than, or Unordered */
2933 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
2934 mips_move (code, ins->dreg, mips_zero);
2935 mips_fbtrue (code, 2);
2937 mips_addiu (code, ins->dreg, mips_zero, 1);
2940 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
2942 if (ins->flags & MONO_INST_BRLABEL)
2943 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2945 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2946 mips_fbtrue (code, 0);
2950 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
2952 if (ins->flags & MONO_INST_BRLABEL)
2953 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2955 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2956 mips_fbfalse (code, 0);
2960 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
2962 if (ins->flags & MONO_INST_BRLABEL)
2963 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2965 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2966 mips_fbtrue (code, 0);
2970 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
2972 if (ins->flags & MONO_INST_BRLABEL)
2973 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2975 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2976 mips_fbtrue (code, 0);
2980 mips_fcmpd (code, MIPS_FPU_LE, ins->sreg1, ins->sreg2);
2982 if (ins->flags & MONO_INST_BRLABEL)
2983 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2985 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2986 mips_fbfalse (code, 0);
2990 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
2992 if (ins->flags & MONO_INST_BRLABEL)
2993 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2995 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2996 mips_fbfalse (code, 0);
3000 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
3002 if (ins->flags & MONO_INST_BRLABEL)
3003 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3005 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3006 mips_fbfalse (code, 0);
3010 mips_fcmpd (code, MIPS_FPU_OLT, ins->sreg1, ins->sreg2);
3012 if (ins->flags & MONO_INST_BRLABEL)
3013 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3015 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3016 mips_fbfalse (code, 0);
3020 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
3022 if (ins->flags & MONO_INST_BRLABEL)
3023 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3025 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3026 mips_fbtrue (code, 0);
3030 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
3032 if (ins->flags & MONO_INST_BRLABEL)
3033 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3035 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3036 mips_fbtrue (code, 0);
3040 g_assert_not_reached();
3042 ppc_stfd (code, ins->sreg1, -8, ppc_sp);
3043 ppc_lwz (code, ppc_r11, -8, ppc_sp);
3044 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 1, 31);
3045 ppc_addis (code, ppc_r11, ppc_r11, -32752);
3046 ppc_rlwinmd (code, ppc_r11, ppc_r11, 1, 31, 31);
3047 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3052 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3053 g_assert_not_reached ();
3056 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3057 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3058 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3059 g_assert_not_reached ();
3065 last_offset = offset;
3068 cfg->code_len = code - cfg->native_code;
3072 mono_arch_register_lowlevel_calls (void)
3077 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3079 MonoJumpInfo *patch_info;
3081 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3082 unsigned char *ip = patch_info->ip.i + code;
3083 const unsigned char *target;
3085 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3087 switch (patch_info->type) {
3088 case MONO_PATCH_INFO_IP:
3089 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
3091 case MONO_PATCH_INFO_SWITCH: {
3092 /* jt is the inlined jump table, 7 or 9 instructions after ip
3093 * In the normal case we store the absolute addresses.
3094 * otherwise the displacements.
3097 gpointer *table = (gpointer *)patch_info->data.table->table;
3098 gpointer *jt = ((gpointer*)(void *)ip) + 7;
3099 if (1 /* || !(cfg->->flags & MONO_CFG_HAS_CALLS) */)
3101 for (i = 0; i < patch_info->data.table->table_size; i++) {
3102 jt [i] = code + (int)table [i];
3106 case MONO_PATCH_INFO_METHODCONST:
3107 case MONO_PATCH_INFO_CLASS:
3108 case MONO_PATCH_INFO_IMAGE:
3109 case MONO_PATCH_INFO_FIELD:
3110 case MONO_PATCH_INFO_VTABLE:
3111 case MONO_PATCH_INFO_IID:
3112 case MONO_PATCH_INFO_SFLDA:
3113 case MONO_PATCH_INFO_LDSTR:
3114 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3115 case MONO_PATCH_INFO_LDTOKEN:
3116 case MONO_PATCH_INFO_R4:
3117 case MONO_PATCH_INFO_R8:
3118 /* from OP_AOTCONST : lui + addiu */
3119 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
3122 case MONO_PATCH_INFO_EXC_NAME:
3123 g_assert_not_reached ();
3124 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
3127 case MONO_PATCH_INFO_NONE:
3128 /* everything is dealt with at epilog output time */
3133 mips_patch ((guint32 *)(void *)ip, (guint32)target);
3139 mono_trace_lmf_prolog (MonoLMF *new_lmf)
3145 mono_trace_lmf_epilog (MonoLMF *old_lmf)
3150 * Allow tracing to work with this interface (with an optional argument)
3152 * This code is expected to be inserted just after the 'real' prolog code,
3153 * and before the first basic block. We need to allocate a 2nd, temporary
3154 * stack frame so that we can preserve f12-f15 as well as a0-a3.
3158 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
3161 int fp_stack_offset = 0;
3167 mips_sw (code, mips_a0, mips_sp, cfg->stack_offset + 0);
3168 mips_sw (code, mips_a1, mips_sp, cfg->stack_offset + 4);
3169 mips_sw (code, mips_a2, mips_sp, cfg->stack_offset + 8);
3170 mips_sw (code, mips_a3, mips_sp, cfg->stack_offset + 12);
3173 fp_stack_offset = MIPS_STACK_PARAM_OFFSET;
3174 mips_addiu (code, mips_sp, mips_sp, -64);
3175 mips_swc1 (code, mips_f12, mips_sp, fp_stack_offset + 16);
3176 mips_swc1 (code, mips_f13, mips_sp, fp_stack_offset + 20);
3177 mips_swc1 (code, mips_f14, mips_sp, fp_stack_offset + 24);
3178 mips_swc1 (code, mips_f15, mips_sp, fp_stack_offset + 28);
3180 mips_fmovs (code, mips_f22, mips_f12);
3181 mips_fmovs (code, mips_f23, mips_f13);
3182 mips_fmovs (code, mips_f24, mips_f14);
3183 mips_fmovs (code, mips_f25, mips_f15);
3186 mips_load_const (code, mips_a0, cfg->method);
3187 mips_addiu (code, mips_a1, mips_sp, cfg->stack_offset + fp_stack_offset);
3188 mips_load_const (code, mips_t9, func);
3189 mips_jalr (code, mips_t9, mips_ra);
3192 mips_lw (code, mips_a0, mips_sp, cfg->stack_offset + 0);
3193 mips_lw (code, mips_a1, mips_sp, cfg->stack_offset + 4);
3194 mips_lw (code, mips_a2, mips_sp, cfg->stack_offset + 8);
3195 mips_lw (code, mips_a3, mips_sp, cfg->stack_offset + 12);
3198 mips_lwc1 (code, mips_f12, mips_sp, fp_stack_offset + 16);
3199 mips_lwc1 (code, mips_f13, mips_sp, fp_stack_offset + 20);
3200 mips_lwc1 (code, mips_f14, mips_sp, fp_stack_offset + 24);
3201 mips_lwc1 (code, mips_f15, mips_sp, fp_stack_offset + 28);
3202 mips_addiu (code, mips_sp, mips_sp, 64);
3204 mips_fmovs (code, mips_f12, mips_f22);
3205 mips_fmovs (code, mips_f13, mips_f23);
3206 mips_fmovs (code, mips_f14, mips_f24);
3207 mips_fmovs (code, mips_f15, mips_f25);
3217 * Stack frame layout:
3219 * ------------------- sp + cfg->stack_usage + cfg->param_area
3220 * param area incoming
3221 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
3223 * ------------------- sp + cfg->stack_usage
3225 * ------------------- sp + cfg->stack_usage-4
3227 * ------------------- sp +
3228 * MonoLMF structure optional
3229 * ------------------- sp + cfg->arch.lmf_offset
3230 * saved registers s0-s8
3231 * ------------------- sp + cfg->arch.iregs_offset
3233 * ------------------- sp + cfg->param_area
3234 * param area outgoing
3235 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
3237 * ------------------- sp
3241 mono_arch_emit_prolog (MonoCompile *cfg)
3243 MonoMethod *method = cfg->method;
3244 MonoMethodSignature *sig;
3246 int alloc_size, pos, i;
3250 guint32 iregs_to_save = 0;
3252 guint32 fregs_to_save = 0;
3255 /* lmf_offset is the offset of the LMF from our stack pointer. */
3256 guint32 lmf_offset = cfg->arch.lmf_offset;
3259 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3263 cfg->flags |= MONO_CFG_HAS_CALLS;
3265 sig = mono_method_signature (method);
3266 cfg->code_size = 768 + sig->param_count * 20;
3267 code = cfg->native_code = g_malloc (cfg->code_size);
3269 /* re-align cfg->stack_offset if needed (due to var spilling in mini-codegen.c) */
3270 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
3272 /* stack_offset should not be changed here. */
3273 alloc_size = cfg->stack_offset;
3274 cfg->stack_usage = alloc_size;
3277 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
3279 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
3283 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
3285 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
3286 fregs_to_save |= (fregs_to_save << 1);
3290 if (mips_is_imm16 (-alloc_size)) {
3291 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
3293 mips_load_const (code, mips_at, -alloc_size);
3294 mips_addu (code, mips_sp, mips_sp, mips_at);
3298 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
3299 mips_sw (code, mips_ra, mips_sp, alloc_size + MIPS_RET_ADDR_OFFSET);
3301 /* XXX - optimize this later to not save all regs if LMF constructed */
3303 if (iregs_to_save) {
3304 /* save used registers in own stack frame (at pos) */
3305 pos = cfg->arch.iregs_offset;
3306 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
3307 if (iregs_to_save & (1 << i)) {
3308 g_assert (pos < cfg->stack_usage - 4);
3309 mips_sw (code, i, mips_sp, pos);
3310 pos += sizeof (gulong);
3315 if (method->save_lmf) {
3316 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
3317 mips_sw (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]));
3323 /* Save float registers */
3324 if (fregs_to_save) {
3325 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
3326 if (fregs_to_save & (1 << i)) {
3327 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
3328 mips_swc1 (code, i, mips_sp, pos);
3329 pos += sizeof (gulong);
3334 if (method->save_lmf) {
3335 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
3336 mips_swc1 (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]));
3341 if (cfg->frame_reg != mips_sp) {
3342 mips_move (code, cfg->frame_reg, mips_sp);
3344 if (method->save_lmf)
3345 mips_sw (code, cfg->frame_reg, mips_sp,
3346 lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]));
3350 /* Do instrumentation before assigning regvars to registers. Because they may be assigned
3351 * to the t* registers, which would be clobbered by the instrumentation calls.
3354 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3357 /* load arguments allocated to register from the stack */
3360 cinfo = calculate_sizes (sig, sig->pinvoke);
3362 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3363 ArgInfo *ainfo = &cinfo->ret;
3364 inst = cfg->vret_addr;
3365 if (inst->opcode == OP_REGVAR)
3366 mips_move (code, inst->dreg, ainfo->reg);
3367 else if (mips_is_imm16 (inst->inst_offset)) {
3368 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3370 mips_load_const (code, mips_at, inst->inst_offset);
3371 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
3372 mips_sw (code, ainfo->reg, mips_at, 0);
3375 /* Keep this in sync with emit_load_volatile_arguments */
3376 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3377 ArgInfo *ainfo = cinfo->args + i;
3378 inst = cfg->args [pos];
3380 if (cfg->verbose_level > 2)
3381 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3382 if (inst->opcode == OP_REGVAR) {
3383 /* Argument ends up in a register */
3384 if (ainfo->regtype == RegTypeGeneral)
3385 mips_move (code, inst->dreg, ainfo->reg);
3386 else if (ainfo->regtype == RegTypeFP) {
3387 g_assert_not_reached();
3389 ppc_fmr (code, inst->dreg, ainfo->reg);
3392 else if (ainfo->regtype == RegTypeBase) {
3393 mips_lw (code, inst->dreg, mips_sp, cfg->stack_usage + ainfo->offset);
3395 g_assert_not_reached ();
3397 if (cfg->verbose_level > 2)
3398 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3400 /* Argument ends up on the stack */
3401 if (ainfo->regtype == RegTypeGeneral) {
3402 /* Incoming parameters should be above this frame */
3403 g_assert (inst->inst_offset >= alloc_size);
3404 g_assert (mips_is_imm16 (inst->inst_offset));
3405 switch (ainfo->size) {
3407 mips_sb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3410 mips_sh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3414 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3417 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3418 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
3421 g_assert_not_reached ();
3424 } else if (ainfo->regtype == RegTypeBase) {
3426 * Argument comes in on the stack, and ends up on the stack
3427 * 1 and 2 byte args are passed as 32-bit quantities, but used as
3428 * 8 and 16 bit quantities. Shorten them in place.
3430 g_assert (mips_is_imm16 (inst->inst_offset));
3431 switch (ainfo->size) {
3433 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
3434 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
3437 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
3438 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
3445 g_assert_not_reached ();
3447 } else if (ainfo->regtype == RegTypeFP) {
3448 g_assert (mips_is_imm16 (inst->inst_offset));
3449 if (ainfo->size == 8) {
3451 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3453 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
3454 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
3457 else if (ainfo->size == 4)
3458 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3460 g_assert_not_reached ();
3461 } else if (ainfo->regtype == RegTypeStructByVal) {
3463 int doffset = inst->inst_offset;
3465 g_assert (mips_is_imm16 (inst->inst_offset));
3466 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3467 /* Push the argument registers into their stack slots */
3468 for (i = 0; i < ainfo->size; ++i) {
3469 mips_sw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3470 doffset += sizeof (gpointer);
3472 } else if (ainfo->regtype == RegTypeStructByAddr) {
3473 g_assert (mips_is_imm16 (inst->inst_offset));
3474 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3475 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
3477 g_assert_not_reached ();
3482 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
3483 mips_load_const (code, mips_a0, cfg->domain);
3484 mips_load_const (code, mips_t9, (gpointer)mono_jit_thread_attach);
3485 mips_jalr (code, mips_t9, mips_ra);
3490 if (method->save_lmf) {
3491 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
3492 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
3494 if (lmf_pthread_key != -1) {
3495 g_assert_not_reached();
3497 emit_tls_access (code, mips_temp, lmf_pthread_key);
3499 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
3500 mips_addiu (code, mips_a0, mips_temp, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3503 mips_addiu (code, mips_a0, mips_sp, lmf_offset);
3504 mips_load_const (code, mips_t9, (gpointer)mono_trace_lmf_prolog);
3505 mips_jalr (code, mips_t9, mips_ra);
3508 /* This can/will clobber the a0-a3 registers */
3509 mips_load_const (code, mips_t9, (gpointer)mono_get_lmf_addr);
3510 mips_jalr (code, mips_t9, mips_ra);
3514 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
3515 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
3516 /* new_lmf->previous_lmf = *lmf_addr */
3517 mips_lw (code, mips_at, mips_v0, 0);
3518 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
3519 /* *(lmf_addr) = sp + lmf_offset */
3520 mips_addiu (code, mips_at, mips_sp, lmf_offset);
3521 mips_sw (code, mips_at, mips_v0, 0);
3523 /* save method info */
3524 mips_load_const (code, mips_at, method);
3525 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
3526 mips_sw (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
3528 /* save the current IP */
3529 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3530 mips_load_const (code, mips_at, 0x01010101);
3531 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
3535 cfg->code_len = code - cfg->native_code;
3536 g_assert (cfg->code_len < cfg->code_size);
3551 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
3554 int save_mode = SAVE_NONE;
3556 MonoMethod *method = cfg->method;
3557 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
3558 int save_offset = MIPS_STACK_PARAM_OFFSET;
3560 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
3562 offset = code - cfg->native_code;
3563 /* we need about 16 instructions */
3564 if (offset > (cfg->code_size - 16 * 4)) {
3565 cfg->code_size *= 2;
3566 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3567 code = cfg->native_code + offset;
3572 case MONO_TYPE_VOID:
3573 /* special case string .ctor icall */
3574 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
3575 save_mode = SAVE_ONE;
3577 save_mode = SAVE_NONE;
3581 save_mode = SAVE_TWO;
3585 save_mode = SAVE_FP;
3587 case MONO_TYPE_VALUETYPE:
3588 save_mode = SAVE_STRUCT;
3591 save_mode = SAVE_ONE;
3595 mips_addiu (code, mips_sp, mips_sp, -32);
3596 switch (save_mode) {
3598 mips_sw (code, mips_v0, mips_sp, save_offset);
3599 mips_sw (code, mips_v1, mips_sp, save_offset + 4);
3600 if (enable_arguments) {
3601 mips_move (code, mips_a1, mips_v0);
3602 mips_move (code, mips_a2, mips_v1);
3606 mips_sw (code, mips_v0, mips_sp, save_offset);
3607 if (enable_arguments) {
3608 mips_move (code, mips_a1, mips_v0);
3612 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
3613 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
3614 mips_lw (code, mips_a0, mips_sp, save_offset);
3615 mips_lw (code, mips_a1, mips_sp, save_offset+4);
3622 mips_load_const (code, mips_a0, cfg->method);
3623 mips_load_const (code, mips_t9, func);
3624 mips_jalr (code, mips_t9, mips_ra);
3627 switch (save_mode) {
3629 mips_lw (code, mips_v0, mips_sp, save_offset);
3630 mips_lw (code, mips_v1, mips_sp, save_offset + 4);
3633 mips_lw (code, mips_v0, mips_sp, save_offset);
3636 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
3643 mips_addiu (code, mips_sp, mips_sp, 32);
3650 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
3652 MonoMethod *method = cfg->method;
3654 int max_epilog_size = 16 + 20*4;
3655 guint32 iregs_to_restore;
3657 guint32 fregs_to_restore;
3661 if (cfg->method->save_lmf)
3662 max_epilog_size += 128;
3665 if (mono_jit_trace_calls != NULL)
3666 max_epilog_size += 50;
3668 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3669 max_epilog_size += 50;
3672 pos = code - cfg->native_code;
3673 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3674 cfg->code_size *= 2;
3675 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3676 mono_jit_stats.code_reallocs++;
3680 * Keep in sync with OP_JMP
3683 code = cfg->native_code + pos;
3685 code = cfg->native_code + cfg->code_len;
3687 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3688 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3690 pos = cfg->arch.iregs_offset;
3691 if (cfg->frame_reg != mips_sp) {
3692 mips_move (code, mips_sp, cfg->frame_reg);
3695 iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
3697 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
3699 if (iregs_to_restore) {
3700 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
3701 if (iregs_to_restore & (1 << i)) {
3702 mips_lw (code, i, mips_sp, pos);
3703 pos += sizeof (gulong);
3710 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
3712 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
3713 fregs_to_restore |= (fregs_to_restore << 1);
3715 if (fregs_to_restore) {
3716 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
3717 if (fregs_to_restore & (1 << i)) {
3718 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
3719 mips_lwc1 (code, i, mips_sp, pos);
3720 pos += sizeof (gulong);
3726 /* Unlink the LMF if necessary */
3727 if (method->save_lmf) {
3728 int lmf_offset = cfg->arch.lmf_offset;
3730 /* t0 = current_lmf->previous_lmf */
3731 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
3733 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
3734 /* (*lmf_addr) = previous_lmf */
3735 mips_sw (code, mips_temp, mips_t1, 0);
3739 /* Restore the fp */
3740 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
3742 /* Correct the stack pointer */
3743 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
3744 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage + MIPS_RET_ADDR_OFFSET);
3745 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage);
3747 /* Caller will emit either return or tail-call sequence */
3749 cfg->code_len = code - cfg->native_code;
3751 g_assert (cfg->code_len < cfg->code_size);
3756 mono_arch_emit_epilog (MonoCompile *cfg)
3760 code = mono_arch_emit_epilog_sub (cfg, NULL);
3762 mips_jr (code, mips_ra);
3765 cfg->code_len = code - cfg->native_code;
3767 g_assert (cfg->code_len < cfg->code_size);
3770 /* remove once throw_exception_by_name is eliminated */
3772 exception_id_by_name (const char *name)
3774 if (strcmp (name, "IndexOutOfRangeException") == 0)
3775 return MONO_EXC_INDEX_OUT_OF_RANGE;
3776 if (strcmp (name, "OverflowException") == 0)
3777 return MONO_EXC_OVERFLOW;
3778 if (strcmp (name, "ArithmeticException") == 0)
3779 return MONO_EXC_ARITHMETIC;
3780 if (strcmp (name, "DivideByZeroException") == 0)
3781 return MONO_EXC_DIVIDE_BY_ZERO;
3782 if (strcmp (name, "InvalidCastException") == 0)
3783 return MONO_EXC_INVALID_CAST;
3784 if (strcmp (name, "NullReferenceException") == 0)
3785 return MONO_EXC_NULL_REF;
3786 if (strcmp (name, "ArrayTypeMismatchException") == 0)
3787 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3788 g_error ("Unknown intrinsic exception %s\n", name);
3793 mono_arch_emit_exceptions (MonoCompile *cfg)
3796 MonoJumpInfo *patch_info;
3799 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3800 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3801 int max_epilog_size = 50;
3803 /* count the number of exception infos */
3806 * make sure we have enough space for exceptions
3807 * 24 is the simulated call to throw_exception_by_name
3809 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3811 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3812 i = exception_id_by_name (patch_info->data.target);
3813 g_assert (i < MONO_EXC_INTRINS_NUM);
3814 if (!exc_throw_found [i]) {
3815 max_epilog_size += 12;
3816 exc_throw_found [i] = TRUE;
3822 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3823 cfg->code_size *= 2;
3824 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3825 mono_jit_stats.code_reallocs++;
3828 code = cfg->native_code + cfg->code_len;
3830 /* add code to raise exceptions */
3831 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3832 switch (patch_info->type) {
3833 case MONO_PATCH_INFO_EXC: {
3835 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
3837 i = exception_id_by_name (patch_info->data.target);
3838 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
3839 if (!exc_throw_pos [i]) {
3842 exc_throw_pos [i] = code;
3843 //g_print ("exc: writing stub at %p\n", code);
3844 mips_load_const (code, mips_a0, patch_info->data.target);
3845 addr = (guint32) mono_arch_get_throw_exception_by_name ();
3846 mips_load_const (code, mips_t9, addr);
3847 mips_jr (code, mips_t9);
3850 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
3852 /* Turn into a Relative patch, pointing at code stub */
3853 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
3854 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
3856 g_assert_not_reached();
3866 cfg->code_len = code - cfg->native_code;
3868 g_assert (cfg->code_len < cfg->code_size);
3873 * Thread local storage support
3876 setup_tls_access (void)
3879 //guint32 *ins, *code;
3881 if (tls_mode == TLS_MODE_FAILED)
3884 if (g_getenv ("MONO_NO_TLS")) {
3885 tls_mode = TLS_MODE_FAILED;
3889 if (tls_mode == TLS_MODE_DETECT) {
3891 tls_mode = TLS_MODE_FAILED;
3895 ins = (guint32*)pthread_getspecific;
3896 /* uncond branch to the real method */
3897 if ((*ins >> 26) == 18) {
3899 val = (*ins & ~3) << 6;
3903 ins = (guint32*)val;
3905 ins = (guint32*) ((char*)ins + val);
3908 code = &cmplwi_1023;
3909 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
3911 ppc_li (code, ppc_r4, 0x48);
3914 if (*ins == cmplwi_1023) {
3915 int found_lwz_284 = 0;
3916 for (ptk = 0; ptk < 20; ++ptk) {
3918 if (!*ins || *ins == blr_ins)
3920 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
3925 if (!found_lwz_284) {
3926 tls_mode = TLS_MODE_FAILED;
3929 tls_mode = TLS_MODE_LTHREADS;
3930 } else if (*ins == li_0x48) {
3932 /* uncond branch to the real method */
3933 if ((*ins >> 26) == 18) {
3935 val = (*ins & ~3) << 6;
3939 ins = (guint32*)val;
3941 ins = (guint32*) ((char*)ins + val);
3944 ppc_li (code, ppc_r0, 0x7FF2);
3945 if (ins [1] == val) {
3946 /* Darwin on G4, implement */
3947 tls_mode = TLS_MODE_FAILED;
3951 ppc_mfspr (code, ppc_r3, 104);
3952 if (ins [1] != val) {
3953 tls_mode = TLS_MODE_FAILED;
3956 tls_mode = TLS_MODE_DARWIN_G5;
3959 tls_mode = TLS_MODE_FAILED;
3963 tls_mode = TLS_MODE_FAILED;
3968 if (monodomain_key == -1) {
3969 ptk = mono_domain_get_tls_key ();
3971 ptk = mono_pthread_key_for_tls (ptk);
3973 monodomain_key = ptk;
3977 if (lmf_pthread_key == -1) {
3978 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
3980 /*g_print ("MonoLMF at: %d\n", ptk);*/
3981 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
3982 init_tls_failed = 1;
3985 lmf_pthread_key = ptk;
3988 if (monothread_key == -1) {
3989 ptk = mono_thread_get_tls_key ();
3991 ptk = mono_pthread_key_for_tls (ptk);
3993 monothread_key = ptk;
3994 /*g_print ("thread inited: %d\n", ptk);*/
3997 /*g_print ("thread not inited yet %d\n", ptk);*/
4003 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4005 setup_tls_access ();
4009 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4014 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4016 int this_dreg = mips_a0;
4019 this_dreg = mips_a1;
4021 /* add the this argument */
4022 if (this_reg != -1) {
4024 MONO_INST_NEW (cfg, this, OP_MOVE);
4025 this->type = this_type;
4026 this->sreg1 = this_reg;
4027 this->dreg = mono_regstate_next_int (cfg->rs);
4028 mono_bblock_add_inst (cfg->cbb, this);
4029 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
4034 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4035 vtarg->type = STACK_MP;
4036 vtarg->sreg1 = vt_reg;
4037 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4038 mono_bblock_add_inst (cfg->cbb, vtarg);
4039 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
4044 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4046 MonoInst *ins = NULL;
4052 mono_arch_print_tree (MonoInst *tree, int arity)
4057 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4061 setup_tls_access ();
4062 if (monodomain_key == -1)
4065 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4066 ins->inst_offset = monodomain_key;
4071 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4075 setup_tls_access ();
4076 if (monothread_key == -1)
4079 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4080 ins->inst_offset = monothread_key;
4085 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4087 /* FIXME: implement */
4088 g_assert_not_reached ();