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 #error "The mips backend has not been ported to linear IR."
28 #define SAVE_FP_REGS 0
29 #define SAVE_ALL_REGS 0
30 #define EXTRA_STACK_SPACE 0 /* suppresses some s-reg corruption issues */
31 #define LONG_BRANCH 1 /* needed for yyparse in mcs */
34 #define ALWAYS_USE_FP 1
35 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
44 int mono_exc_esp_offset = 0;
45 static int tls_mode = TLS_MODE_DETECT;
46 static int lmf_pthread_key = -1;
47 static int monothread_key = -1;
48 static int monodomain_key = -1;
51 #define DEBUG(a) if (cfg->verbose_level > 1) a
57 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
59 code = mips_emit_exc_by_name (code, exc_name); \
60 cfg->bb_exit->max_offset += 16; \
64 #define emit_linuxthreads_tls(code,dreg,key) do {\
66 off1 = offsets_from_pthread_key ((key), &off2); \
67 ppc_lwz ((code), (dreg), off1, ppc_r2); \
68 ppc_lwz ((code), (dreg), off2, (dreg)); \
72 #define emit_tls_access(code,dreg,key) do { \
74 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
75 default: g_assert_not_reached (); \
79 typedef struct InstList InstList;
97 guint16 vtsize; /* in param area */
99 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
100 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
117 void patch_lui_addiu(guint32 *ip, guint32 val);
118 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
121 mono_arch_flush_icache (guint8 *code, gint size)
123 /* Linux/MIPS specific */
124 cacheflush (code, size, BCACHE);
128 mono_arch_flush_register_windows (void)
133 mono_arch_is_inst_imm (gint64 imm)
139 mips_emit_exc_by_name(guint8 *code, const char *name)
143 mips_load_const (code, mips_a0, name);
144 addr = (guint32) mono_arch_get_throw_exception_by_name ();
145 mips_load_const (code, mips_t9, addr);
146 mips_jalr (code, mips_t9, mips_ra);
153 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
159 /* Invert test and emit branch around jump */
162 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
166 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
170 mips_bltz (code, ins->sreg1, br_offset);
174 mips_blez (code, ins->sreg1, br_offset);
178 mips_bgtz (code, ins->sreg1, br_offset);
182 mips_bgez (code, ins->sreg1, br_offset);
186 g_assert_not_reached ();
188 if (ins->flags & MONO_INST_BRLABEL)
189 mono_add_patch_info (cfg, code - cfg->native_code,
190 MONO_PATCH_INFO_LABEL, ins->inst_i0);
192 mono_add_patch_info (cfg, code - cfg->native_code,
193 MONO_PATCH_INFO_BB, ins->inst_true_bb);
194 mips_lui (code, mips_at, mips_zero, 0);
195 mips_addiu (code, mips_at, mips_at, 0);
196 mips_jr (code, mips_at);
199 if (ins->flags & MONO_INST_BRLABEL)
200 mono_add_patch_info (cfg, code - cfg->native_code,
201 MONO_PATCH_INFO_LABEL, ins->inst_i0);
203 mono_add_patch_info (cfg, code - cfg->native_code,
204 MONO_PATCH_INFO_BB, ins->inst_true_bb);
207 mips_beq (code, ins->sreg1, ins->sreg2, 0);
211 mips_bne (code, ins->sreg1, ins->sreg2, 0);
215 mips_bgez (code, ins->sreg1, 0);
219 mips_bgtz (code, ins->sreg1, 0);
223 mips_blez (code, ins->sreg1, 0);
227 mips_bltz (code, ins->sreg1, 0);
231 g_assert_not_reached ();
237 /* XXX - big-endian dependent? */
239 patch_lui_addiu(guint32 *ip, guint32 val)
241 guint16 *__lui_addiu = (guint16*)(void *)(ip);
244 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
245 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
248 if (((guint32)(val)) & (1 << 15))
249 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
251 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
252 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
253 mono_arch_flush_icache ((guint8 *)ip, 8);
258 mips_patch (guint32 *code, guint32 target)
261 guint32 op = ins >> 26;
262 guint32 diff, offset;
264 g_assert (trap_target != target);
265 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
267 case 0x00: /* jr ra */
268 if (ins == 0x3e00008)
270 g_assert_not_reached ();
274 g_assert (!(target & 0x03));
275 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
276 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
278 mono_arch_flush_icache ((guint8 *)code, 4);
280 case 0x01: /* BLTZ */
283 case 0x06: /* BLEZ */
284 case 0x07: /* BGTZ */
285 case 0x11: /* bc1t */
286 diff = target - (guint32)(code + 1);
287 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
288 g_assert (!(diff & 0x03));
289 offset = ((gint32)diff) >> 2;
290 g_assert (((int)offset) == ((int)(short)offset));
291 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
293 mono_arch_flush_icache ((guint8 *)code, 4);
295 case 0x0f: /* LUI / ADDIU pair */
296 patch_lui_addiu (code, target);
297 mono_arch_flush_icache ((guint8 *)code, 8);
301 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
302 g_assert_not_reached ();
307 offsets_from_pthread_key (guint32 key, int *offset2)
311 *offset2 = idx2 * sizeof (gpointer);
312 return 284 + idx1 * sizeof (gpointer);
316 mono_arch_regname (int reg) {
317 static const char * rnames[] = {
318 "zero", "at", "v0", "v1",
319 "a0", "a1", "a2", "a3",
320 "t0", "t1", "t2", "t3",
321 "t4", "t5", "t6", "t7",
322 "s0", "s1", "s2", "s3",
323 "s4", "s5", "s6", "s7",
324 "t8", "t9", "k0", "k1",
325 "gp", "sp", "fp", "ra"
327 if (reg >= 0 && reg < 32)
333 mono_arch_fregname (int reg) {
334 static const char * rnames[] = {
335 "f0", "f1", "f2", "f3",
336 "f4", "f5", "f6", "f7",
337 "f8", "f9", "f10", "f11",
338 "f12", "f13", "f14", "f15",
339 "f16", "f17", "f18", "f19",
340 "f20", "f21", "f22", "f23",
341 "f24", "f25", "f26", "f27",
342 "f28", "f29", "f30", "f31"
344 if (reg >= 0 && reg < 32)
349 /* this function overwrites at */
351 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
353 /* XXX write a loop, not an unrolled loop */
355 mips_lw (code, mips_at, sreg, soffset);
356 mips_sw (code, mips_at, dreg, doffset);
365 * mono_arch_get_argument_info:
366 * @csig: a method signature
367 * @param_count: the number of parameters to consider
368 * @arg_info: an array to store the result infos
370 * Gathers information on parameters such as size, alignment and
371 * padding. arg_info should be large enought to hold param_count + 1 entries.
373 * Returns the size of the activation frame.
376 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
378 int k, frame_size = 0;
379 guint32 size, align, pad;
382 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
383 frame_size += sizeof (gpointer);
387 arg_info [0].offset = offset;
390 frame_size += sizeof (gpointer);
394 arg_info [0].size = frame_size;
396 for (k = 0; k < param_count; k++) {
397 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
399 /* ignore alignment for now */
402 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
403 arg_info [k].pad = pad;
405 arg_info [k + 1].pad = 0;
406 arg_info [k + 1].size = size;
408 arg_info [k + 1].offset = offset;
412 align = MONO_ARCH_FRAME_ALIGNMENT;
413 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
414 arg_info [k].pad = pad;
420 * Initialize the cpu to execute managed code.
423 mono_arch_cpu_init (void)
428 * Initialize architecture specific code.
431 mono_arch_init (void)
436 * Cleanup architecture specific code.
439 mono_arch_cleanup (void)
444 * This function returns the optimizations supported on this cpu.
447 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
451 /* no mips-specific optimizations yet */
457 is_regsize_var (MonoType *t) {
460 t = mono_type_get_underlying_type (t);
467 case MONO_TYPE_FNPTR:
469 case MONO_TYPE_OBJECT:
470 case MONO_TYPE_STRING:
471 case MONO_TYPE_CLASS:
472 case MONO_TYPE_SZARRAY:
473 case MONO_TYPE_ARRAY:
475 case MONO_TYPE_GENERICINST:
476 if (!mono_type_generic_inst_is_valuetype (t))
479 case MONO_TYPE_VALUETYPE:
486 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
491 for (i = 0; i < cfg->num_varinfo; i++) {
492 MonoInst *ins = cfg->varinfo [i];
493 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
496 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
499 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
502 /* we can only allocate 32 bit values */
503 if (is_regsize_var (ins->inst_vtype)) {
504 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
505 g_assert (i == vmv->idx);
506 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
514 mono_arch_get_global_int_regs (MonoCompile *cfg)
518 regs = g_list_prepend (regs, (gpointer)mips_s0);
519 regs = g_list_prepend (regs, (gpointer)mips_s1);
520 regs = g_list_prepend (regs, (gpointer)mips_s2);
521 regs = g_list_prepend (regs, (gpointer)mips_s3);
522 regs = g_list_prepend (regs, (gpointer)mips_s4);
523 regs = g_list_prepend (regs, (gpointer)mips_s5);
524 regs = g_list_prepend (regs, (gpointer)mips_s6);
525 regs = g_list_prepend (regs, (gpointer)mips_s7);
531 * mono_arch_regalloc_cost:
533 * Return the cost, in number of memory references, of the action of
534 * allocating the variable VMV into a register during global register
538 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
545 args_onto_stack (CallInfo *info)
547 g_assert(!info->on_stack);
548 g_assert(info->stack_size <= MIPS_STACK_PARAM_OFFSET);
549 info->on_stack = TRUE;
550 info->stack_size = MIPS_STACK_PARAM_OFFSET;
554 * O32 calling convention version
558 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
559 /* First, see if we need to drop onto the stack */
560 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
561 args_onto_stack (info);
563 /* Now, place the argument */
564 if (info->on_stack) {
565 ainfo->regtype = RegTypeBase;
566 ainfo->reg = mips_sp; /* in the caller */
567 ainfo->offset = info->stack_size;
570 ainfo->regtype = RegTypeGeneral;
571 ainfo->reg = info->gr;
573 info->gr_passed = TRUE;
575 info->stack_size += 4;
579 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
580 /* First, see if we need to drop onto the stack */
581 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
582 args_onto_stack (info);
584 /* Now, place the argument */
585 if (info->on_stack) {
586 g_assert(info->stack_size % 4 == 0);
587 info->stack_size += (info->stack_size % 8);
589 ainfo->regtype = RegTypeBase;
590 ainfo->reg = mips_sp; /* in the caller */
591 ainfo->offset = info->stack_size;
594 // info->gr must be a0 or a2
595 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
596 g_assert(info->gr <= MIPS_LAST_ARG_REG);
598 ainfo->regtype = RegTypeGeneral;
599 ainfo->reg = info->gr;
601 info->gr_passed = TRUE;
603 info->stack_size += 8;
607 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
608 /* First, see if we need to drop onto the stack */
609 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
610 args_onto_stack (info);
612 /* Now, place the argument */
613 if (info->on_stack) {
614 ainfo->regtype = RegTypeBase;
615 ainfo->reg = mips_sp; /* in the caller */
616 ainfo->offset = info->stack_size;
619 /* Only use FP regs for args if no int args passed yet */
620 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
621 ainfo->regtype = RegTypeFP;
622 ainfo->reg = info->fr;
623 /* Even though it's a single-precision float, it takes up two FP regs */
625 /* FP and GP slots do not overlap */
629 /* Passing single-precision float arg in a GP register
630 * such as: func (0, 1.0, 2, 3);
631 * In this case, only one 'gr' register is consumed.
633 ainfo->regtype = RegTypeGeneral;
634 ainfo->reg = info->gr;
637 info->gr_passed = TRUE;
640 info->stack_size += 4;
644 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
645 /* First, see if we need to drop onto the stack */
646 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
647 args_onto_stack (info);
649 /* Now, place the argument */
650 if (info->on_stack) {
651 g_assert(info->stack_size % 4 == 0);
652 info->stack_size += (info->stack_size % 8);
654 ainfo->regtype = RegTypeBase;
655 ainfo->reg = mips_sp; /* in the caller */
656 ainfo->offset = info->stack_size;
659 /* Only use FP regs for args if no int args passed yet */
660 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
661 ainfo->regtype = RegTypeFP;
662 ainfo->reg = info->fr;
664 /* FP and GP slots do not overlap */
668 // info->gr must be a0 or a2
669 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
670 g_assert(info->gr <= MIPS_LAST_ARG_REG);
672 ainfo->regtype = RegTypeGeneral;
673 ainfo->reg = info->gr;
675 info->gr_passed = TRUE;
678 info->stack_size += 8;
682 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
685 int n = sig->hasthis + sig->param_count;
687 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
689 cinfo->fr = MIPS_FIRST_FPARG_REG;
690 cinfo->gr = MIPS_FIRST_ARG_REG;
691 cinfo->stack_size = 0;
693 DEBUG(printf("calculate_sizes\n"));
695 /* handle returning a struct */
696 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
697 cinfo->struct_ret = cinfo->gr;
698 add_int32_arg (cinfo, &cinfo->ret);
703 add_int32_arg (cinfo, cinfo->args + n);
706 DEBUG(printf("params: %d\n", sig->param_count));
707 for (i = 0; i < sig->param_count; ++i) {
708 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
709 /* Prevent implicit arguments and sig_cookie from
710 being passed in registers */
711 args_onto_stack (cinfo);
712 /* Emit the signature cookie just before the implicit arguments */
713 add_int32_arg (cinfo, &cinfo->sig_cookie);
715 DEBUG(printf("param %d: ", i));
716 if (sig->params [i]->byref) {
717 DEBUG(printf("byref\n"));
718 add_int32_arg (cinfo, &cinfo->args[n]);
722 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
723 switch (simpletype) {
724 case MONO_TYPE_BOOLEAN:
727 DEBUG(printf("1 byte\n"));
728 cinfo->args [n].size = 1;
729 add_int32_arg (cinfo, &cinfo->args[n]);
735 DEBUG(printf("2 bytes\n"));
736 cinfo->args [n].size = 2;
737 add_int32_arg (cinfo, &cinfo->args[n]);
742 DEBUG(printf("4 bytes\n"));
743 cinfo->args [n].size = 4;
744 add_int32_arg (cinfo, &cinfo->args[n]);
750 case MONO_TYPE_FNPTR:
751 case MONO_TYPE_CLASS:
752 case MONO_TYPE_OBJECT:
753 case MONO_TYPE_STRING:
754 case MONO_TYPE_SZARRAY:
755 case MONO_TYPE_ARRAY:
756 cinfo->args [n].size = sizeof (gpointer);
757 add_int32_arg (cinfo, &cinfo->args[n]);
760 case MONO_TYPE_GENERICINST:
761 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
762 cinfo->args [n].size = sizeof (gpointer);
763 add_int32_arg (cinfo, &cinfo->args[n]);
768 case MONO_TYPE_VALUETYPE: {
771 int has_offset = FALSE;
773 gint size, alignment;
776 klass = mono_class_from_mono_type (sig->params [i]);
778 size = mono_class_native_size (klass, NULL);
780 size = mono_class_value_size (klass, NULL);
781 alignment = mono_class_min_align (klass);
782 #if MIPS_PASS_STRUCTS_BY_VALUE
783 /* Need to do alignment if struct contains long or double */
785 if (cinfo->stack_size & (alignment - 1)) {
786 add_int32_arg (cinfo, &dummy_arg);
788 g_assert (!(cinfo->stack_size & (alignment - 1)));
792 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
793 mono_class_native_size (sig->params [i]->data.klass, NULL),
794 cinfo->stack_size, alignment);
796 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
797 g_assert(cinfo->args [n].size == 0);
798 g_assert(cinfo->args [n].vtsize == 0);
799 for (j = 0; j < nwords; ++j) {
801 add_int32_arg (cinfo, &cinfo->args [n]);
805 add_int32_arg (cinfo, &dummy_arg);
806 if (!has_offset && cinfo->on_stack) {
807 cinfo->args [n].offset = dummy_arg.offset;
812 cinfo->args [n].vtsize += 1;
814 cinfo->args [n].size += 1;
816 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
817 cinfo->args [n].regtype = RegTypeStructByVal;
819 add_int32_arg (cinfo, &cinfo->args[n]);
820 cinfo->args [n].regtype = RegTypeStructByAddr;
825 case MONO_TYPE_TYPEDBYREF: {
826 /* keep in sync or merge with the valuetype case */
827 #if MIPS_PASS_STRUCTS_BY_VALUE
829 int size = sizeof (MonoTypedRef);
830 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
831 cinfo->args [n].regtype = RegTypeStructByVal;
832 if (!cinfo->on_stack && cinfo->gr <= MIPS_LAST_ARG_REG) {
833 int rest = MIPS_LAST_ARG_REG - cinfo->gr + 1;
834 int n_in_regs = rest >= nwords? nwords: rest;
835 cinfo->args [n].size = n_in_regs;
836 cinfo->args [n].vtsize = nwords - n_in_regs;
837 cinfo->args [n].reg = cinfo->gr;
838 cinfo->gr += n_in_regs;
839 cinfo->gr_passed = TRUE;
841 cinfo->args [n].size = 0;
842 cinfo->args [n].vtsize = nwords;
844 if (cinfo->args [n].vtsize > 0) {
845 if (!cinfo->on_stack)
846 args_onto_stack (cinfo);
847 g_assert(cinfo->on_stack);
848 cinfo->args [n].offset = cinfo->stack_size;
849 g_print ("offset for arg %d at %d\n", n, cinfo->args [n].offset);
850 cinfo->stack_size += cinfo->args [n].vtsize * sizeof (gpointer);
854 add_int32_arg (cinfo, &cinfo->args[n]);
855 cinfo->args [n].regtype = RegTypeStructByAddr;
862 DEBUG(printf("8 bytes\n"));
863 cinfo->args [n].size = 8;
864 add_int64_arg (cinfo, &cinfo->args[n]);
868 DEBUG(printf("R4\n"));
869 cinfo->args [n].size = 4;
870 add_float32_arg (cinfo, &cinfo->args[n]);
874 DEBUG(printf("R8\n"));
875 cinfo->args [n].size = 8;
876 add_float64_arg (cinfo, &cinfo->args[n]);
880 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
885 simpletype = mono_type_get_underlying_type (sig->ret)->type;
886 switch (simpletype) {
887 case MONO_TYPE_BOOLEAN:
898 case MONO_TYPE_FNPTR:
899 case MONO_TYPE_CLASS:
900 case MONO_TYPE_OBJECT:
901 case MONO_TYPE_SZARRAY:
902 case MONO_TYPE_ARRAY:
903 case MONO_TYPE_STRING:
904 cinfo->ret.reg = mips_v0;
908 cinfo->ret.reg = mips_v0;
912 cinfo->ret.reg = mips_f0;
913 cinfo->ret.regtype = RegTypeFP;
915 case MONO_TYPE_GENERICINST:
916 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
917 cinfo->ret.reg = mips_v0;
921 case MONO_TYPE_VALUETYPE:
923 case MONO_TYPE_TYPEDBYREF:
927 g_error ("Can't handle as return value 0x%x", sig->ret->type);
931 /* align stack size to 16 */
932 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
934 cinfo->stack_usage = cinfo->stack_size;
940 * Set var information according to the calling convention. mips version.
941 * The locals var stuff should most likely be split in another method.
944 mono_arch_allocate_vars (MonoCompile *cfg)
946 MonoMethodSignature *sig;
947 MonoMethodHeader *header;
949 int i, offset, size, align, curinst;
950 int frame_reg = mips_sp;
951 guint32 iregs_to_save = 0;
952 guint32 fregs_to_restore;
954 cfg->flags |= MONO_CFG_HAS_SPILLUP;
956 /* allow room for the vararg method args: void* and long/double */
957 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
958 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
960 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
961 * call convs needs to be handled this way.
963 if (cfg->flags & MONO_CFG_HAS_VARARGS)
964 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
966 /* gtk-sharp and other broken code will dllimport vararg functions even with
967 * non-varargs signatures. Since there is little hope people will get this right
968 * we assume they won't.
970 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
971 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
973 /* a0-a3 always present */
974 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
976 header = mono_method_get_header (cfg->method);
978 sig = mono_method_signature (cfg->method);
981 * We use the frame register also for any method that has
982 * exception clauses. This way, when the handlers are called,
983 * the code will reference local variables using the frame reg instead of
984 * the stack pointer: if we had to restore the stack pointer, we'd
985 * corrupt the method frames that are already on the stack (since
986 * filters get called before stack unwinding happens) when the filter
987 * code would call any method (this also applies to finally etc.).
990 if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses || ALWAYS_USE_FP)
992 cfg->frame_reg = frame_reg;
993 if (frame_reg != mips_sp) {
994 cfg->used_int_regs |= 1 << frame_reg;
999 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1000 /* FIXME: handle long and FP values */
1001 switch (mono_type_get_underlying_type (sig->ret)->type) {
1002 case MONO_TYPE_VOID:
1005 cfg->ret->opcode = OP_REGVAR;
1006 cfg->ret->inst_c0 = mips_v0;
1010 /* Space for outgoing parameters, including a0-a3 */
1011 offset += cfg->param_area;
1013 /* allow room to save the return value (if it's a struct) */
1014 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1017 if (sig->call_convention == MONO_CALL_VARARG) {
1018 cfg->sig_cookie = MIPS_STACK_PARAM_OFFSET;
1021 /* Now handle the local variables */
1023 curinst = cfg->locals_start;
1024 for (i = curinst; i < cfg->num_varinfo; ++i) {
1025 inst = cfg->varinfo [i];
1026 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1029 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1030 * pinvoke wrappers when they call functions returning structure
1032 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1033 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
1035 size = mono_type_size (inst->inst_vtype, &align);
1037 offset += align - 1;
1038 offset &= ~(align - 1);
1039 inst->inst_offset = offset;
1040 inst->opcode = OP_REGOFFSET;
1041 inst->inst_basereg = frame_reg;
1043 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1046 /* Space for LMF (if needed) */
1048 if (cfg->method->save_lmf) {
1049 /* align the offset to 16 bytes */
1050 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1051 cfg->arch.lmf_offset = offset;
1052 offset += sizeof (MonoLMF);
1056 #if EXTRA_STACK_SPACE
1057 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1058 * args or return vals. Extra stack space avoids this in a lot of cases.
1062 /* Space for saved registers */
1063 cfg->arch.iregs_offset = offset;
1065 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
1067 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1069 if (iregs_to_save) {
1070 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1071 if (iregs_to_save & (1 << i)) {
1072 offset += sizeof (gulong);
1077 #if EXTRA_STACK_SPACE
1078 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1079 * args or return vals. Extra stack space avoids this in a lot of cases.
1084 /* saved float registers */
1086 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1087 if (fregs_to_restore) {
1088 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1089 if (fregs_to_restore & (1 << i)) {
1090 offset += sizeof (double);
1096 /* Now add space for saving the ra */
1100 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1101 cfg->stack_offset = offset;
1104 * Now allocate stack slots for the int arg regs (a0 - a3)
1105 * On MIPS o32, these are just above the incoming stack pointer
1106 * Even if the arg has been assigned to a regvar, it gets a stack slot
1109 /* Return struct-by-value results in a hidden first argument */
1110 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1111 cfg->vret_addr->opcode = OP_REGOFFSET;
1112 cfg->vret_addr->inst_c0 = mips_a0;
1113 cfg->vret_addr->inst_offset = offset;
1114 cfg->vret_addr->inst_basereg = frame_reg;
1118 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1119 inst = cfg->args [i];
1120 if (inst->opcode != OP_REGVAR) {
1123 if (sig->hasthis && (i == 0))
1124 arg_type = &mono_defaults.object_class->byval_arg;
1126 arg_type = sig->params [i - sig->hasthis];
1128 inst->opcode = OP_REGOFFSET;
1129 size = mono_type_size (arg_type, &align);
1135 inst->inst_basereg = frame_reg;
1136 offset = (offset + align - 1) & ~(align - 1);
1137 inst->inst_offset = offset;
1139 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1140 cfg->sig_cookie += size;
1141 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1144 /* Even a0-a3 get stack slots */
1145 size = sizeof (gpointer);
1146 align = sizeof (gpointer);
1147 inst->inst_basereg = frame_reg;
1148 offset = (offset + align - 1) & ~(align - 1);
1149 inst->inst_offset = offset;
1151 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1152 cfg->sig_cookie += size;
1153 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1159 mono_arch_create_vars (MonoCompile *cfg)
1161 MonoMethodSignature *sig;
1163 sig = mono_method_signature (cfg->method);
1165 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1166 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1167 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1168 printf ("vret_addr = ");
1169 mono_print_ins (cfg->vret_addr);
1174 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1175 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1179 * take the arguments and generate the arch-specific
1180 * instructions to properly call the function in call.
1181 * This includes pushing, moving arguments to the right register
1183 * Issue: who does the spilling if needed, and when?
1186 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
1188 MonoMethodSignature *sig;
1193 sig = call->signature;
1194 n = sig->param_count + sig->hasthis;
1196 cinfo = calculate_sizes (sig, sig->pinvoke);
1197 if (cinfo->struct_ret)
1198 call->used_iregs |= 1 << cinfo->struct_ret;
1200 for (i = 0; i < n; ++i) {
1201 ainfo = cinfo->args + i;
1202 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1204 cfg->disable_aot = TRUE;
1206 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1207 sig_arg->inst_p0 = call->signature;
1209 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1210 arg->inst_imm = cinfo->sig_cookie.offset;
1211 arg->inst_left = sig_arg;
1213 /* prepend, so they get reversed */
1214 arg->next = call->out_args;
1215 call->out_args = arg;
1217 if (is_virtual && i == 0) {
1218 /* the argument will be attached to the call instrucion */
1219 in = call->args [i];
1220 call->used_iregs |= 1 << ainfo->reg;
1222 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1223 in = call->args [i];
1224 arg->cil_code = in->cil_code;
1225 arg->inst_left = in;
1226 arg->inst_call = call;
1227 arg->type = in->type;
1228 /* prepend, we'll need to reverse them later */
1229 arg->next = call->out_args;
1230 call->out_args = arg;
1231 if (ainfo->regtype == RegTypeGeneral) {
1232 arg->backend.reg3 = ainfo->reg;
1233 call->used_iregs |= 1 << ainfo->reg;
1234 if (arg->type == STACK_I8)
1235 call->used_iregs |= 1 << (ainfo->reg + 1);
1236 } else if (ainfo->regtype == RegTypeStructByAddr) {
1237 /* FIXME: where is the data allocated? */
1238 arg->backend.reg3 = ainfo->reg;
1239 call->used_iregs |= 1 << ainfo->reg;
1240 } else if (ainfo->regtype == RegTypeStructByVal) {
1242 MonoMIPSArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMIPSArgInfo));
1243 /* mark the used regs */
1244 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1245 call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1247 arg->opcode = OP_OUTARG_VT;
1248 ai->reg = ainfo->reg;
1249 ai->size = ainfo->size;
1250 ai->vtsize = ainfo->vtsize;
1251 ai->offset = ainfo->offset;
1252 arg->backend.data = ai;
1254 g_printf ("OUTARG_VT reg=%d size=%d vtsize=%d offset=%d\n",
1255 ai->reg, ai->size, ai->vtsize, ai->offset);
1257 } else if (ainfo->regtype == RegTypeBase) {
1258 MonoMIPSArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMIPSArgInfo));
1259 g_assert(ainfo->reg == mips_sp);
1260 arg->opcode = OP_OUTARG_MEMBASE;
1261 ai->reg = ainfo->reg;
1262 ai->size = ainfo->size;
1263 ai->offset = ainfo->offset;
1264 arg->backend.data = ai;
1265 } else if (ainfo->regtype == RegTypeFP) {
1266 arg->opcode = OP_OUTARG_R8;
1267 arg->backend.reg3 = ainfo->reg;
1268 call->used_fregs |= 1 << ainfo->reg;
1269 if (ainfo->size == 4) {
1270 arg->opcode = OP_OUTARG_R4;
1271 /* we reduce the precision */
1273 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1274 conv->inst_left = arg->inst_left;
1275 arg->inst_left = conv;*/
1278 g_assert_not_reached ();
1283 * Reverse the call->out_args list.
1286 MonoInst *prev = NULL, *list = call->out_args, *next;
1293 call->out_args = prev;
1295 call->stack_usage = cinfo->stack_usage;
1296 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1297 cfg->param_area = MAX (cfg->param_area, 16); /* a0-a3 always present */
1298 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1299 cfg->flags |= MONO_CFG_HAS_CALLS;
1301 * should set more info in call, such as the stack space
1302 * used by the args that needs to be added back to esp
1310 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1316 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1322 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1328 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1333 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1335 MonoInst *ins, *n, *last_ins = NULL;
1338 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1339 MonoInst *last_ins = ins->prev;
1341 switch (ins->opcode) {
1343 /* remove unnecessary multiplication with 1 */
1344 if (ins->inst_imm == 1) {
1345 if (ins->dreg != ins->sreg1) {
1346 ins->opcode = OP_MOVE;
1348 MONO_DELETE_INS (bb, ins);
1352 int power2 = mono_is_power_of_two (ins->inst_imm);
1354 ins->opcode = OP_SHL_IMM;
1355 ins->inst_imm = power2;
1359 case OP_LOAD_MEMBASE:
1360 case OP_LOADI4_MEMBASE:
1362 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1363 * OP_LOAD_MEMBASE offset(basereg), reg
1365 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1366 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1367 ins->inst_basereg == last_ins->inst_destbasereg &&
1368 ins->inst_offset == last_ins->inst_offset) {
1369 if (ins->dreg == last_ins->sreg1) {
1370 MONO_DELETE_INS (bb, ins);
1373 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1374 ins->opcode = OP_MOVE;
1375 ins->sreg1 = last_ins->sreg1;
1380 * Note: reg1 must be different from the basereg in the second load
1381 * OP_LOAD_MEMBASE offset(basereg), reg1
1382 * OP_LOAD_MEMBASE offset(basereg), reg2
1384 * OP_LOAD_MEMBASE offset(basereg), reg1
1385 * OP_MOVE reg1, reg2
1387 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1388 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1389 ins->inst_basereg != last_ins->dreg &&
1390 ins->inst_basereg == last_ins->inst_basereg &&
1391 ins->inst_offset == last_ins->inst_offset) {
1393 if (ins->dreg == last_ins->dreg) {
1394 MONO_DELETE_INS (bb, ins);
1397 ins->opcode = OP_MOVE;
1398 ins->sreg1 = last_ins->dreg;
1401 //g_assert_not_reached ();
1406 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1407 * OP_LOAD_MEMBASE offset(basereg), reg
1409 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1410 * OP_ICONST reg, imm
1412 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1413 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1414 ins->inst_basereg == last_ins->inst_destbasereg &&
1415 ins->inst_offset == last_ins->inst_offset) {
1416 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1417 ins->opcode = OP_ICONST;
1418 ins->inst_c0 = last_ins->inst_imm;
1419 g_assert_not_reached (); // check this rule
1424 case OP_LOADU1_MEMBASE:
1425 case OP_LOADI1_MEMBASE:
1426 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1427 ins->inst_basereg == last_ins->inst_destbasereg &&
1428 ins->inst_offset == last_ins->inst_offset) {
1429 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? CEE_CONV_I1 : CEE_CONV_U1;
1430 ins->sreg1 = last_ins->sreg1;
1433 case OP_LOADU2_MEMBASE:
1434 case OP_LOADI2_MEMBASE:
1435 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1436 ins->inst_basereg == last_ins->inst_destbasereg &&
1437 ins->inst_offset == last_ins->inst_offset) {
1438 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? CEE_CONV_I2 : CEE_CONV_U2;
1439 ins->sreg1 = last_ins->sreg1;
1445 ins->opcode = OP_MOVE;
1449 if (ins->dreg == ins->sreg1) {
1450 MONO_DELETE_INS (bb, ins);
1454 * OP_MOVE sreg, dreg
1455 * OP_MOVE dreg, sreg
1457 if (last_ins && last_ins->opcode == OP_MOVE &&
1458 ins->sreg1 == last_ins->dreg &&
1459 ins->dreg == last_ins->sreg1) {
1460 MONO_DELETE_INS (bb, ins);
1468 bb->last_ins = last_ins;
1471 static inline InstList*
1472 inst_list_prepend (MonoMemPool *pool, InstList *list, MonoInst *data)
1474 InstList *item = mono_mempool_alloc (pool, sizeof (InstList));
1484 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1488 bb->code = to_insert;
1489 to_insert->next = ins;
1491 to_insert->next = ins->next;
1492 ins->next = to_insert;
1496 #define NEW_INS(cfg,dest,op) do { \
1497 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1498 (dest)->opcode = (op); \
1499 insert_after_ins (bb, last_ins, (dest)); \
1503 map_to_reg_reg_op (int op)
1512 case OP_COMPARE_IMM:
1528 case OP_LOAD_MEMBASE:
1529 return OP_LOAD_MEMINDEX;
1530 case OP_LOADI4_MEMBASE:
1531 return OP_LOADI4_MEMINDEX;
1532 case OP_LOADU4_MEMBASE:
1533 return OP_LOADU4_MEMINDEX;
1534 case OP_LOADU1_MEMBASE:
1535 return OP_LOADU1_MEMINDEX;
1536 case OP_LOADI2_MEMBASE:
1537 return OP_LOADI2_MEMINDEX;
1538 case OP_LOADU2_MEMBASE:
1539 return OP_LOADU2_MEMINDEX;
1540 case OP_LOADI1_MEMBASE:
1541 return OP_LOADI1_MEMINDEX;
1542 case OP_LOADR4_MEMBASE:
1543 return OP_LOADR4_MEMINDEX;
1544 case OP_LOADR8_MEMBASE:
1545 return OP_LOADR8_MEMINDEX;
1546 case OP_STOREI1_MEMBASE_REG:
1547 return OP_STOREI1_MEMINDEX;
1548 case OP_STOREI2_MEMBASE_REG:
1549 return OP_STOREI2_MEMINDEX;
1550 case OP_STOREI4_MEMBASE_REG:
1551 return OP_STOREI4_MEMINDEX;
1552 case OP_STORE_MEMBASE_REG:
1553 return OP_STORE_MEMINDEX;
1554 case OP_STORER4_MEMBASE_REG:
1555 return OP_STORER4_MEMINDEX;
1556 case OP_STORER8_MEMBASE_REG:
1557 return OP_STORER8_MEMINDEX;
1558 case OP_STORE_MEMBASE_IMM:
1559 return OP_STORE_MEMBASE_REG;
1560 case OP_STOREI1_MEMBASE_IMM:
1561 return OP_STOREI1_MEMBASE_REG;
1562 case OP_STOREI2_MEMBASE_IMM:
1563 return OP_STOREI2_MEMBASE_REG;
1564 case OP_STOREI4_MEMBASE_IMM:
1565 return OP_STOREI4_MEMBASE_REG;
1567 g_assert_not_reached ();
1571 * Remove from the instruction list the instructions that can't be
1572 * represented with very simple instructions with no register
1576 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1578 MonoInst *ins, *next, *temp, *last_ins = NULL;
1581 /* setup the virtual reg allocator */
1582 if (bb->max_vreg > cfg->rs->next_vreg)
1583 cfg->rs->next_vreg = bb->max_vreg;
1585 MONO_BB_FOR_EACH_INS (bb, ins) {
1587 switch (ins->opcode) {
1590 if (!mips_is_imm16 (ins->inst_imm)) {
1591 NEW_INS (cfg, temp, OP_ICONST);
1592 temp->inst_c0 = ins->inst_imm;
1593 temp->dreg = mono_regstate_next_int (cfg->rs);
1594 ins->sreg2 = temp->dreg;
1595 ins->opcode = map_to_reg_reg_op (ins->opcode);
1600 if (!mips_is_imm16 (-ins->inst_imm)) {
1601 NEW_INS (cfg, temp, OP_ICONST);
1602 temp->inst_c0 = ins->inst_imm;
1603 temp->dreg = mono_regstate_next_int (cfg->rs);
1604 ins->sreg2 = temp->dreg;
1605 ins->opcode = map_to_reg_reg_op (ins->opcode);
1613 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
1614 NEW_INS (cfg, temp, OP_ICONST);
1615 temp->inst_c0 = ins->inst_imm;
1616 temp->dreg = mono_regstate_next_int (cfg->rs);
1617 ins->sreg2 = temp->dreg;
1618 ins->opcode = map_to_reg_reg_op (ins->opcode);
1626 NEW_INS (cfg, temp, OP_ICONST);
1627 temp->inst_c0 = ins->inst_imm;
1628 temp->dreg = mono_regstate_next_int (cfg->rs);
1629 ins->sreg2 = temp->dreg;
1630 ins->opcode = map_to_reg_reg_op (ins->opcode);
1634 case OP_COMPARE_IMM:
1635 if (compare_opcode_is_unsigned (ins->next->opcode)) {
1636 if (!ppc_is_uimm16 (ins->inst_imm)) {
1637 NEW_INS (cfg, temp, OP_ICONST);
1638 temp->inst_c0 = ins->inst_imm;
1639 temp->dreg = mono_regstate_next_int (cfg->rs);
1640 ins->sreg2 = temp->dreg;
1641 ins->opcode = map_to_reg_reg_op (ins->opcode);
1644 if (!ppc_is_imm16 (ins->inst_imm)) {
1645 NEW_INS (cfg, temp, OP_ICONST);
1646 temp->inst_c0 = ins->inst_imm;
1647 temp->dreg = mono_regstate_next_int (cfg->rs);
1648 ins->sreg2 = temp->dreg;
1649 ins->opcode = map_to_reg_reg_op (ins->opcode);
1656 if (ins->inst_imm == 1) {
1657 ins->opcode = OP_MOVE;
1660 if (ins->inst_imm == 0) {
1661 ins->opcode = OP_ICONST;
1665 imm = mono_is_power_of_two (ins->inst_imm);
1667 ins->opcode = OP_SHL_IMM;
1668 ins->inst_imm = imm;
1671 if (!ppc_is_imm16 (ins->inst_imm)) {
1672 NEW_INS (cfg, temp, OP_ICONST);
1673 temp->inst_c0 = ins->inst_imm;
1674 temp->dreg = mono_regstate_next_int (cfg->rs);
1675 ins->sreg2 = temp->dreg;
1676 ins->opcode = map_to_reg_reg_op (ins->opcode);
1681 case OP_LOAD_MEMBASE:
1682 case OP_LOADI4_MEMBASE:
1683 case OP_LOADU4_MEMBASE:
1684 case OP_LOADI2_MEMBASE:
1685 case OP_LOADU2_MEMBASE:
1686 case OP_LOADI1_MEMBASE:
1687 case OP_LOADU1_MEMBASE:
1688 case OP_LOADR4_MEMBASE:
1689 case OP_LOADR8_MEMBASE:
1690 case OP_STORE_MEMBASE_REG:
1691 case OP_STOREI4_MEMBASE_REG:
1692 case OP_STOREI2_MEMBASE_REG:
1693 case OP_STOREI1_MEMBASE_REG:
1694 case OP_STORER4_MEMBASE_REG:
1695 case OP_STORER8_MEMBASE_REG:
1696 /* we can do two things: load the immed in a register
1697 * and use an indexed load, or see if the immed can be
1698 * represented as an ad_imm + a load with a smaller offset
1699 * that fits. We just do the first for now, optimize later.
1701 if (ppc_is_imm16 (ins->inst_offset))
1703 NEW_INS (cfg, temp, OP_ICONST);
1704 temp->inst_c0 = ins->inst_offset;
1705 temp->dreg = mono_regstate_next_int (cfg->rs);
1706 ins->sreg2 = temp->dreg;
1707 ins->opcode = map_to_reg_reg_op (ins->opcode);
1710 case OP_STORE_MEMBASE_IMM:
1711 case OP_STOREI1_MEMBASE_IMM:
1712 case OP_STOREI2_MEMBASE_IMM:
1713 case OP_STOREI4_MEMBASE_IMM:
1714 if (!ins->inst_imm) {
1715 ins->sreg1 = mips_zero;
1716 ins->opcode = map_to_reg_reg_op (ins->opcode);
1719 NEW_INS (cfg, temp, OP_ICONST);
1720 temp->inst_c0 = ins->inst_imm;
1721 temp->dreg = mono_regstate_next_int (cfg->rs);
1722 ins->sreg1 = temp->dreg;
1723 ins->opcode = map_to_reg_reg_op (ins->opcode);
1725 goto loop_start; /* make it handle the possibly big ins->inst_offset */
1731 bb->last_ins = last_ins;
1732 bb->max_vreg = cfg->rs->next_vreg;
1736 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
1738 /* sreg is a float, dreg is an integer reg. mips_at is used a scratch */
1740 mips_truncwd (code, mips_ftemp, sreg);
1742 mips_cvtwd (code, mips_ftemp, sreg);
1744 mips_mfc1 (code, dreg, mips_ftemp);
1747 mips_andi (code, dreg, dreg, 0xff);
1748 else if (size == 2) {
1749 mips_sll (code, dreg, dreg, 16);
1750 mips_srl (code, dreg, dreg, 16);
1754 mips_sll (code, dreg, dreg, 24);
1755 mips_sra (code, dreg, dreg, 24);
1757 else if (size == 2) {
1758 mips_sll (code, dreg, dreg, 16);
1759 mips_sra (code, dreg, dreg, 16);
1766 * emit_load_volatile_arguments:
1768 * Load volatile arguments from the stack to the original input registers.
1769 * Required before a tail call.
1772 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
1774 MonoMethod *method = cfg->method;
1775 MonoMethodSignature *sig;
1780 sig = mono_method_signature (method);
1781 cinfo = calculate_sizes (sig, sig->pinvoke);
1782 if (cinfo->struct_ret) {
1783 ArgInfo *ainfo = &cinfo->ret;
1784 inst = cfg->vret_addr;
1785 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1788 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1789 ArgInfo *ainfo = cinfo->args + i;
1790 inst = cfg->args [i];
1791 if (inst->opcode == OP_REGVAR) {
1792 if (ainfo->regtype == RegTypeGeneral)
1793 mips_move (code, ainfo->reg, inst->dreg);
1794 else if (ainfo->regtype == RegTypeFP)
1795 g_assert_not_reached();
1796 else if (ainfo->regtype == RegTypeBase) {
1799 g_assert_not_reached ();
1801 if (ainfo->regtype == RegTypeGeneral) {
1802 g_assert (mips_is_imm16 (inst->inst_offset));
1803 switch (ainfo->size) {
1805 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1808 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1812 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1815 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1816 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
1819 g_assert_not_reached ();
1822 } else if (ainfo->regtype == RegTypeBase) {
1824 } else if (ainfo->regtype == RegTypeFP) {
1825 g_assert (mips_is_imm16 (inst->inst_offset));
1826 if (ainfo->size == 8)
1827 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1828 else if (ainfo->size == 4)
1829 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1831 g_assert_not_reached ();
1832 } else if (ainfo->regtype == RegTypeStructByVal) {
1834 int doffset = inst->inst_offset;
1836 g_assert (mips_is_imm16 (inst->inst_offset));
1837 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
1838 for (i = 0; i < ainfo->size; ++i) {
1839 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
1840 doffset += sizeof (gpointer);
1842 } else if (ainfo->regtype == RegTypeStructByAddr) {
1843 g_assert (mips_is_imm16 (inst->inst_offset));
1844 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1846 g_assert_not_reached ();
1856 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
1861 guint8 *code = cfg->native_code + cfg->code_len;
1862 MonoInst *last_ins = NULL;
1863 guint last_offset = 0;
1867 /* we don't align basic blocks of loops on mips */
1869 if (cfg->verbose_level > 2)
1870 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
1872 cpos = bb->max_offset;
1875 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
1876 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
1877 g_assert (!mono_compile_aot);
1880 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
1881 /* this is not thread save, but good enough */
1882 /* fixme: howto handle overflows? */
1883 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
1884 mips_lw (code, mips_temp, mips_at, 0);
1885 mips_addiu (code, mips_temp, mips_temp, 1);
1886 mips_sw (code, mips_temp, mips_at, 0);
1889 MONO_BB_FOR_EACH_INS (bb, ins) {
1890 offset = code - cfg->native_code;
1892 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
1894 if (offset > (cfg->code_size - max_len - 16)) {
1895 cfg->code_size *= 2;
1896 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1897 code = cfg->native_code + offset;
1899 mono_debug_record_line_number (cfg, ins, offset);
1900 if (cfg->verbose_level > 2) {
1901 g_print (" @ 0x%x\t", offset);
1902 mono_print_ins_index (ins_cnt++, ins);
1905 switch (ins->opcode) {
1907 g_assert_not_reached();
1909 emit_tls_access (code, ins->dreg, ins->inst_offset);
1913 mips_mult (code, ins->sreg1, ins->sreg2);
1914 mips_mflo (code, ins->dreg);
1915 mips_mfhi (code, ins->dreg+1);
1918 mips_multu (code, ins->sreg1, ins->sreg2);
1919 mips_mflo (code, ins->dreg);
1920 mips_mfhi (code, ins->dreg+1);
1922 case OP_RELAXED_NOP:
1924 case OP_MEMORY_BARRIER:
1929 case OP_STOREI1_MEMBASE_IMM:
1930 mips_load_const (code, mips_temp, ins->inst_imm);
1931 if (mips_is_imm16 (ins->inst_offset)) {
1932 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
1934 mips_load_const (code, mips_at, ins->inst_offset);
1935 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
1938 case OP_STOREI2_MEMBASE_IMM:
1939 mips_load_const (code, mips_temp, ins->inst_imm);
1940 if (mips_is_imm16 (ins->inst_offset)) {
1941 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
1943 mips_load_const (code, mips_at, ins->inst_offset);
1944 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
1947 case OP_STORE_MEMBASE_IMM:
1948 case OP_STOREI4_MEMBASE_IMM:
1949 mips_load_const (code, mips_temp, ins->inst_imm);
1950 if (mips_is_imm16 (ins->inst_offset)) {
1951 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
1953 mips_load_const (code, mips_at, ins->inst_offset);
1954 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
1957 case OP_STOREI1_MEMBASE_REG:
1958 if (mips_is_imm16 (ins->inst_offset)) {
1959 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1961 mips_load_const (code, mips_at, ins->inst_offset);
1962 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
1963 mips_sb (code, ins->sreg1, mips_at, 0);
1966 case OP_STOREI2_MEMBASE_REG:
1967 if (mips_is_imm16 (ins->inst_offset)) {
1968 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1970 mips_load_const (code, mips_at, ins->inst_offset);
1971 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
1972 mips_sh (code, ins->sreg1, mips_at, 0);
1975 case OP_STORE_MEMBASE_REG:
1976 case OP_STOREI4_MEMBASE_REG:
1977 if (mips_is_imm16 (ins->inst_offset)) {
1978 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1980 mips_load_const (code, mips_at, ins->inst_offset);
1981 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
1982 mips_sw (code, ins->sreg1, mips_at, 0);
1986 g_assert_not_reached ();
1987 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
1988 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
1990 case OP_LOAD_MEMBASE:
1991 case OP_LOADI4_MEMBASE:
1992 case OP_LOADU4_MEMBASE:
1993 if (mips_is_imm16 (ins->inst_offset)) {
1994 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1996 mips_load_const (code, mips_at, ins->inst_offset);
1997 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1998 mips_lw (code, ins->dreg, mips_at, 0);
2001 case OP_LOADI1_MEMBASE:
2002 if (mips_is_imm16 (ins->inst_offset)) {
2003 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2005 mips_load_const (code, mips_at, ins->inst_offset);
2006 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2007 mips_lb (code, ins->dreg, mips_at, 0);
2010 case OP_LOADU1_MEMBASE:
2011 if (mips_is_imm16 (ins->inst_offset)) {
2012 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2014 mips_load_const (code, mips_at, ins->inst_offset);
2015 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2016 mips_lbu (code, ins->dreg, mips_at, 0);
2019 case OP_LOADI2_MEMBASE:
2020 if (mips_is_imm16 (ins->inst_offset)) {
2021 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2023 mips_load_const (code, mips_at, ins->inst_offset);
2024 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2025 mips_lh (code, ins->dreg, mips_at, 0);
2028 case OP_LOADU2_MEMBASE:
2029 if (mips_is_imm16 (ins->inst_offset)) {
2030 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2032 mips_load_const (code, mips_at, ins->inst_offset);
2033 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2034 mips_lhu (code, ins->dreg, mips_at, 0);
2038 mips_sll (code, mips_at, ins->sreg1, 24);
2039 mips_sra (code, ins->dreg, mips_at, 24);
2042 mips_sll (code, mips_at, ins->sreg1, 16);
2043 mips_sra (code, ins->dreg, mips_at, 16);
2046 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
2049 mips_sll (code, mips_at, ins->sreg1, 16);
2050 mips_srl (code, ins->dreg, mips_at, 16);
2053 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
2056 g_assert (mips_is_imm16 (ins->inst_imm));
2057 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
2060 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
2063 g_assert (mips_is_imm16 (ins->inst_imm));
2064 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
2066 case OP_COMPARE_IMM:
2067 g_assert_not_reached ();
2070 g_assert_not_reached ();
2073 mips_break (code, 0xfd);
2076 g_assert_not_reached ();
2079 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
2082 g_assert_not_reached ();
2085 g_assert_not_reached ();
2088 if (mips_is_imm16 (ins->inst_imm)) {
2089 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
2091 mips_load_const (code, mips_at, ins->inst_imm);
2092 mips_addu (code, ins->dreg, ins->sreg1, mips_at);
2096 g_assert_not_reached ();
2099 /* rewritten in .brg file */
2100 g_assert_not_reached ();
2102 case CEE_ADD_OVF_UN:
2103 /* rewritten in .brg file */
2104 g_assert_not_reached ();
2107 /* rewritten in .brg file */
2108 g_assert_not_reached ();
2110 case CEE_SUB_OVF_UN:
2111 /* rewritten in .brg file */
2112 g_assert_not_reached ();
2114 case OP_ADD_OVF_CARRY:
2115 /* rewritten in .brg file */
2116 g_assert_not_reached ();
2118 case OP_ADD_OVF_UN_CARRY:
2119 /* rewritten in .brg file */
2120 g_assert_not_reached ();
2122 case OP_SUB_OVF_CARRY:
2123 /* rewritten in .brg file */
2124 g_assert_not_reached ();
2126 case OP_SUB_OVF_UN_CARRY:
2127 /* rewritten in .brg file */
2128 g_assert_not_reached ();
2131 /* rewritten in .brg file */
2132 g_assert_not_reached ();
2135 /* rewritten in .brg file */
2136 g_assert_not_reached ();
2139 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
2142 g_assert_not_reached ();
2145 // we add the negated value
2146 if (mips_is_imm16 (-ins->inst_imm))
2147 mips_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2149 mips_load_const (code, mips_at, ins->inst_imm);
2150 mips_subu (code, ins->dreg, ins->sreg1, mips_at);
2154 g_assert_not_reached ();
2157 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2160 if (mips_is_imm16 (ins->inst_imm)) {
2161 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2163 mips_load_const (code, mips_at, ins->inst_imm);
2164 mips_and (code, ins->dreg, ins->sreg1, mips_at);
2169 guint32 *divisor_is_m1;
2170 guint32 *divisor_is_zero;
2173 mips_addiu (code, mips_at, mips_zero, 0xffff);
2174 divisor_is_m1 = (guint32 *)code;
2175 mips_bne (code, ins->sreg2, mips_at, 0);
2178 /* Divide by -1 -- throw exception */
2179 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
2181 mips_patch (divisor_is_m1, (guint32)code);
2183 /* Put divide in branch delay slot (NOT YET) */
2184 divisor_is_zero = (guint32 *)code;
2185 mips_bne (code, ins->sreg2, mips_zero, 0);
2188 /* Divide by zero -- throw exception */
2189 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2191 mips_patch (divisor_is_zero, (guint32)code);
2192 mips_div (code, ins->sreg1, ins->sreg2);
2193 if (ins->opcode == CEE_DIV)
2194 mips_mflo (code, ins->dreg);
2196 mips_mfhi (code, ins->dreg);
2200 guint32 *divisor_is_zero = (guint32 *)(void *)code;
2202 /* Put divide in branch delay slot (NOT YET) */
2203 mips_bne (code, ins->sreg2, mips_zero, 0);
2206 /* Divide by zero -- throw exception */
2207 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2209 mips_patch (divisor_is_zero, (guint32)code);
2210 mips_divu (code, ins->sreg1, ins->sreg2);
2211 mips_mflo (code, ins->dreg);
2215 g_assert_not_reached ();
2217 ppc_load (code, ppc_r11, ins->inst_imm);
2218 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
2219 ppc_mfspr (code, ppc_r0, ppc_xer);
2220 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2221 /* FIXME: use OverflowException for 0x80000000/-1 */
2222 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2224 g_assert_not_reached();
2227 guint32 *divisor_is_zero = (guint32 *)(void *)code;
2229 /* Put divide in branch delay slot (NOT YET) */
2230 mips_bne (code, ins->sreg2, mips_zero, 0);
2233 /* Divide by zero -- throw exception */
2234 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2236 mips_patch (divisor_is_zero, (guint32)code);
2237 mips_divu (code, ins->sreg1, ins->sreg2);
2238 mips_mfhi (code, ins->dreg);
2242 g_assert_not_reached ();
2244 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2247 if (mips_is_imm16 (ins->inst_imm)) {
2248 mips_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2250 mips_load_const (code, mips_at, ins->inst_imm);
2251 mips_or (code, ins->dreg, ins->sreg1, mips_at);
2255 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2258 /* unsigned 16-bit immediate */
2259 if ((ins->inst_imm & 0xffff) == ins->inst_imm) {
2260 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
2262 mips_load_const (code, mips_at, ins->inst_imm);
2263 mips_xor (code, ins->dreg, ins->sreg1, mips_at);
2267 g_assert (mips_is_imm16 (ins->inst_imm));
2268 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
2271 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
2274 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2277 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
2280 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2283 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2286 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
2289 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
2292 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
2296 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
2298 mips_mult (code, ins->sreg1, ins->sreg2);
2299 mips_mflo (code, ins->dreg);
2305 mips_load_const (code, mips_at, ins->inst_imm);
2307 mips_mul (code, ins->dreg, ins->sreg1, mips_at);
2309 mips_mult (code, ins->sreg1, mips_at);
2310 mips_mflo (code, ins->dreg);
2317 mips_mult (code, ins->sreg1, ins->sreg2);
2318 mips_mflo (code, ins->dreg);
2319 mips_mfhi (code, mips_at);
2322 mips_sra (code, mips_temp, ins->dreg, 31);
2323 patch = (guint32 *)(void *)code;
2324 mips_beq (code, mips_temp, mips_at, 0);
2326 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
2327 mips_patch (patch, (guint32)code);
2330 case CEE_MUL_OVF_UN:
2332 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
2334 mips_mult (code, ins->sreg1, ins->sreg2);
2335 mips_mflo (code, ins->dreg);
2336 mips_mfhi (code, mips_at);
2340 /* XXX - Throw exception if we overflowed */
2343 mips_load_const (code, ins->dreg, ins->inst_c0);
2346 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2347 mips_load (code, ins->dreg, 0);
2351 mips_mtc1 (code, ins->dreg, ins->sreg1);
2354 mips_mfc1 (code, ins->dreg, ins->sreg1);
2357 mips_dmtc1 (code, ins->dreg, ins->sreg1);
2360 mips_dmfc1 (code, ins->dreg, ins->sreg1);
2366 if (ins->dreg != ins->sreg1)
2367 mips_move (code, ins->dreg, ins->sreg1);
2370 /* Get sreg1 into v1, sreg2 into v0 */
2372 if (ins->sreg1 == mips_v0) {
2373 if (ins->sreg1 != mips_at)
2374 mips_move (code, mips_at, ins->sreg1);
2375 if (ins->sreg2 != mips_v0)
2376 mips_move (code, mips_v0, ins->sreg2);
2377 mips_move (code, mips_v1, mips_at);
2380 if (ins->sreg2 != mips_v0)
2381 mips_move (code, mips_v0, ins->sreg2);
2382 if (ins->sreg1 != mips_v1)
2383 mips_move (code, mips_v1, ins->sreg1);
2387 if (ins->dreg != ins->sreg1) {
2388 mips_fmovd (code, ins->dreg, ins->sreg1);
2392 /* Convert from double to float and leave it there */
2393 mips_cvtsd (code, ins->dreg, ins->sreg1);
2395 case OP_FCONV_TO_R4:
2396 /* Convert from double to float and back again */
2397 mips_cvtsd (code, ins->dreg, ins->sreg1);
2398 mips_cvtds (code, ins->dreg, ins->dreg);
2401 code = emit_load_volatile_arguments(cfg, code);
2404 * Pop our stack, then jump to specified method (tail-call)
2405 * Keep in sync with mono_arch_emit_epilog
2407 code = mono_arch_emit_epilog_sub (cfg, code);
2409 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
2410 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2412 mips_lui (code, mips_t9, mips_zero, 0);
2413 mips_addiu (code, mips_t9, mips_t9, 0);
2414 mips_jr (code, mips_t9);
2417 mips_beq (code, mips_zero, mips_zero, 0);
2422 /* ensure ins->sreg1 is not NULL */
2423 mips_lw (code, mips_zero, ins->sreg1, 0);
2426 if (mips_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2427 mips_addiu (code, mips_at, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2429 mips_load_const (code, mips_at, cfg->sig_cookie + cfg->stack_usage);
2430 mips_addu (code, mips_at, cfg->frame_reg, mips_at);
2432 mips_sw (code, mips_at, ins->sreg1, 0);
2443 case OP_VOIDCALL_REG:
2445 case OP_FCALL_MEMBASE:
2446 case OP_LCALL_MEMBASE:
2447 case OP_VCALL_MEMBASE:
2448 case OP_VOIDCALL_MEMBASE:
2449 case OP_CALL_MEMBASE:
2450 call = (MonoCallInst*)ins;
2451 switch (ins->opcode) {
2457 if (ins->flags & MONO_INST_HAS_METHOD)
2458 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2460 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2461 mips_lui (code, mips_t9, mips_zero, 0);
2462 mips_addiu (code, mips_t9, mips_t9, 0);
2467 case OP_VOIDCALL_REG:
2469 mips_move (code, mips_t9, ins->sreg1);
2471 case OP_FCALL_MEMBASE:
2472 case OP_LCALL_MEMBASE:
2473 case OP_VCALL_MEMBASE:
2474 case OP_VOIDCALL_MEMBASE:
2475 case OP_CALL_MEMBASE:
2476 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
2479 mips_jalr (code, mips_t9, mips_ra);
2481 if ((ins->opcode == OP_FCALL ||
2482 ins->opcode == OP_FCALL_REG) &&
2483 call->signature->ret->type == MONO_TYPE_R4) {
2484 mips_cvtds (code, mips_f0, mips_f0);
2488 g_assert_not_reached ();
2491 int area_offset = cfg->param_area;
2493 /* Round up ins->sreg1, mips_at ends up holding size */
2494 mips_addiu (code, mips_at, ins->sreg1, 31);
2495 mips_andi (code, mips_at, mips_at, ~31);
2497 mips_subu (code, mips_sp, mips_sp, mips_at);
2498 mips_addiu (code, ins->dreg, mips_sp, area_offset);
2500 if (ins->flags & MONO_INST_INIT) {
2501 mips_move (code, mips_temp, ins->dreg);
2502 mips_sb (code, mips_zero, mips_temp, 0);
2503 mips_addiu (code, mips_at, mips_at, -1);
2504 mips_bne (code, mips_at, mips_zero, -4);
2505 mips_addiu (code, mips_temp, mips_temp, 1);
2510 gpointer addr = mono_arch_get_throw_exception();
2511 mips_move (code, mips_a0, ins->sreg1);
2512 mips_load_const (code, mips_t9, addr);
2513 mips_jalr (code, mips_t9, mips_ra);
2515 mips_break (code, 0xfc);
2519 gpointer addr = mono_arch_get_rethrow_exception();
2520 mips_move (code, mips_a0, ins->sreg1);
2521 mips_load_const (code, mips_t9, addr);
2522 mips_jalr (code, mips_t9, mips_ra);
2524 mips_break (code, 0xfb);
2527 case OP_START_HANDLER:
2529 * The START_HANDLER instruction marks the beginning of a handler
2530 * block. It is called using a call instruction, so mips_ra contains
2531 * the return address. Since the handler executes in the same stack
2532 * frame as the method itself, we can't use save/restore to save
2533 * the return address. Instead, we save it into a dedicated
2536 if (mips_is_imm16 (ins->inst_left->inst_offset)) {
2537 mips_sw (code, mips_ra, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2539 mips_load_const (code, mips_at, ins->inst_left->inst_offset);
2540 mips_add (code, mips_at, mips_at, ins->inst_left->inst_basereg);
2541 mips_sw (code, mips_ra, mips_at, 0);
2545 if (ins->sreg1 != mips_v0)
2546 mips_move (code, mips_v0, ins->sreg1);
2547 if (mips_is_imm16 (ins->inst_left->inst_offset)) {
2548 mips_lw (code, mips_ra, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2550 mips_load_const (code, mips_at, ins->inst_left->inst_offset);
2551 mips_addu (code, mips_at, mips_at, ins->inst_left->inst_basereg);
2552 mips_lw (code, mips_ra, mips_at, 0);
2554 mips_jr (code, mips_ra);
2558 mips_lw (code, mips_t9, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2559 mips_jalr (code, mips_t9, mips_ra);
2562 case OP_CALL_HANDLER:
2563 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2564 mips_lui (code, mips_t9, mips_zero, 0);
2565 mips_addiu (code, mips_t9, mips_t9, 0);
2566 mips_jalr (code, mips_t9, mips_ra);
2570 ins->inst_c0 = code - cfg->native_code;
2573 if (ins->flags & MONO_INST_BRLABEL) {
2574 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2576 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2579 mips_lui (code, mips_at, mips_zero, 0);
2580 mips_addiu (code, mips_at, mips_at, 0);
2581 mips_jr (code, mips_at);
2584 mips_beq (code, mips_zero, mips_zero, 0);
2589 mips_jr (code, ins->sreg1);
2595 max_len += 4 * GPOINTER_TO_INT (ins->klass);
2596 if (offset > (cfg->code_size - max_len - 16)) {
2597 cfg->code_size += max_len;
2598 cfg->code_size *= 2;
2599 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2600 code = cfg->native_code + offset;
2602 g_assert (ins->sreg1 != -1);
2603 mips_sll (code, mips_at, ins->sreg1, 2);
2604 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
2605 mips_move (code, mips_t8, mips_ra);
2606 mips_bgezal (code, mips_zero, 1); /* bal */
2608 mips_addu (code, mips_t9, mips_ra, mips_at);
2609 /* Table is 16 or 20 bytes from target of bal above */
2610 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
2611 mips_move (code, mips_ra, mips_t8);
2612 mips_lw (code, mips_t9, mips_t9, 20);
2615 mips_lw (code, mips_t9, mips_t9, 16);
2616 mips_jalr (code, mips_t9, mips_t8);
2618 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
2619 mips_emit32 (code, 0xfefefefe);
2623 mips_addiu (code, ins->dreg, mips_zero, 1);
2624 mips_beq (code, mips_at, mips_zero, 2);
2626 mips_move (code, ins->dreg, mips_zero);
2630 mips_addiu (code, ins->dreg, mips_zero, 1);
2631 mips_bltz (code, mips_at, 2);
2633 mips_move (code, ins->dreg, mips_zero);
2637 mips_addiu (code, ins->dreg, mips_zero, 1);
2638 mips_bgtz (code, mips_at, 2);
2640 mips_move (code, ins->dreg, mips_zero);
2643 case OP_COND_EXC_EQ:
2644 case OP_COND_EXC_GE:
2645 case OP_COND_EXC_GT:
2646 case OP_COND_EXC_LE:
2647 case OP_COND_EXC_LT:
2648 case OP_COND_EXC_NE_UN:
2649 case OP_COND_EXC_GE_UN:
2650 case OP_COND_EXC_GT_UN:
2651 case OP_COND_EXC_LE_UN:
2652 case OP_COND_EXC_LT_UN:
2654 case OP_COND_EXC_OV:
2655 case OP_COND_EXC_NO:
2657 case OP_COND_EXC_NC:
2659 case OP_COND_EXC_IEQ:
2660 case OP_COND_EXC_IGE:
2661 case OP_COND_EXC_IGT:
2662 case OP_COND_EXC_ILE:
2663 case OP_COND_EXC_ILT:
2664 case OP_COND_EXC_INE_UN:
2665 case OP_COND_EXC_IGE_UN:
2666 case OP_COND_EXC_IGT_UN:
2667 case OP_COND_EXC_ILE_UN:
2668 case OP_COND_EXC_ILT_UN:
2670 case OP_COND_EXC_IOV:
2671 case OP_COND_EXC_INO:
2672 case OP_COND_EXC_IC:
2673 case OP_COND_EXC_INC:
2674 /* Should be re-mapped to OP_MIPS_B* by *.inssel-mips.brg */
2675 g_warning ("unsupported conditional exception %s\n", mono_inst_name (ins->opcode));
2676 g_assert_not_reached ();
2679 case OP_MIPS_COND_EXC_EQ:
2680 case OP_MIPS_COND_EXC_GE:
2681 case OP_MIPS_COND_EXC_GT:
2682 case OP_MIPS_COND_EXC_LE:
2683 case OP_MIPS_COND_EXC_LT:
2684 case OP_MIPS_COND_EXC_NE_UN:
2685 case OP_MIPS_COND_EXC_GE_UN:
2686 case OP_MIPS_COND_EXC_GT_UN:
2687 case OP_MIPS_COND_EXC_LE_UN:
2688 case OP_MIPS_COND_EXC_LT_UN:
2690 case OP_MIPS_COND_EXC_OV:
2691 case OP_MIPS_COND_EXC_NO:
2692 case OP_MIPS_COND_EXC_C:
2693 case OP_MIPS_COND_EXC_NC:
2695 case OP_MIPS_COND_EXC_IEQ:
2696 case OP_MIPS_COND_EXC_IGE:
2697 case OP_MIPS_COND_EXC_IGT:
2698 case OP_MIPS_COND_EXC_ILE:
2699 case OP_MIPS_COND_EXC_ILT:
2700 case OP_MIPS_COND_EXC_INE_UN:
2701 case OP_MIPS_COND_EXC_IGE_UN:
2702 case OP_MIPS_COND_EXC_IGT_UN:
2703 case OP_MIPS_COND_EXC_ILE_UN:
2704 case OP_MIPS_COND_EXC_ILT_UN:
2706 case OP_MIPS_COND_EXC_IOV:
2707 case OP_MIPS_COND_EXC_INO:
2708 case OP_MIPS_COND_EXC_IC:
2709 case OP_MIPS_COND_EXC_INC: {
2713 /* If the condition is true, raise the exception */
2715 /* need to reverse test to skip around exception raising */
2717 /* For the moment, branch around a branch to avoid reversing
2720 /* Remember, an unpatched branch to 0 branches to the delay slot */
2721 throw = (guint32 *)(void *)code;
2722 switch (ins->opcode) {
2723 case OP_MIPS_COND_EXC_EQ:
2724 mips_beq (code, ins->sreg1, ins->sreg2, 0);
2727 case OP_MIPS_COND_EXC_NE_UN:
2728 mips_bne (code, ins->sreg1, ins->sreg2, 0);
2732 /* Not yet implemented */
2733 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
2734 g_assert_not_reached ();
2736 skip = (guint32 *)(void *)code;
2737 mips_beq (code, mips_zero, mips_zero, 0);
2739 mips_patch (throw, (guint32)code);
2740 code = mips_emit_exc_by_name (code, ins->inst_p1);
2741 mips_patch (skip, (guint32)code);
2742 cfg->bb_exit->max_offset += 24;
2755 /* Should be re-mapped to OP_MIPS_B* by *.inssel-mips.brg */
2756 g_warning ("unsupported conditional set %s\n", mono_inst_name (ins->opcode));
2757 g_assert_not_reached ();
2765 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
2768 /* floating point opcodes */
2770 if (((guint32)ins->inst_p0) & (1 << 15))
2771 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
2773 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
2774 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
2777 if (((guint32)ins->inst_p0) & (1 << 15))
2778 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
2780 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
2781 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
2782 mips_cvtds (code, ins->dreg, ins->dreg);
2784 case OP_STORER8_MEMBASE_REG:
2785 if (mips_is_imm16 (ins->inst_offset)) {
2787 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2789 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset+4);
2790 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset);
2793 mips_load_const (code, mips_at, ins->inst_offset);
2794 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
2795 mips_swc1 (code, ins->sreg1, mips_at, 4);
2796 mips_swc1 (code, ins->sreg1+1, mips_at, 0);
2799 case OP_LOADR8_MEMBASE:
2800 if (mips_is_imm16 (ins->inst_offset)) {
2802 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2804 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset+4);
2805 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset);
2808 mips_load_const (code, mips_at, ins->inst_offset);
2809 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2810 mips_lwc1 (code, ins->dreg, mips_at, 4);
2811 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
2814 case OP_STORER4_MEMBASE_REG:
2815 /* XXX Need to convert ins->sreg1 to single-precision first */
2816 mips_cvtsd (code, mips_ftemp, ins->sreg1);
2817 if (mips_is_imm16 (ins->inst_offset)) {
2818 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
2820 mips_load_const (code, mips_at, ins->inst_offset);
2821 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
2822 mips_swc1 (code, mips_ftemp, mips_at, 0);
2826 if (mips_is_imm16 (ins->inst_offset)) {
2827 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2829 mips_load_const (code, mips_at, ins->inst_offset);
2830 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2831 mips_lwc1 (code, ins->dreg, mips_at, 0);
2834 case OP_LOADR4_MEMBASE:
2835 if (mips_is_imm16 (ins->inst_offset)) {
2836 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2838 mips_load_const (code, mips_at, ins->inst_offset);
2839 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2840 mips_lwc1 (code, ins->dreg, mips_at, 0);
2842 /* Convert to double precision in place */
2843 mips_cvtds (code, ins->dreg, ins->dreg);
2845 case CEE_CONV_R_UN: {
2846 static const guint64 adjust_val = 0x41F0000000000000ULL;
2848 /* convert unsigned int to double */
2849 mips_mtc1 (code, mips_ftemp, ins->sreg1);
2850 mips_bgez (code, ins->sreg1, 5);
2851 mips_cvtdw (code, ins->dreg, mips_ftemp);
2853 mips_load (code, mips_at, (guint32) &adjust_val);
2854 mips_ldc1 (code, mips_ftemp, mips_at, 0);
2855 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
2856 /* target is here */
2860 mips_mtc1 (code, mips_ftemp, ins->sreg1);
2861 mips_cvtsw (code, ins->dreg, mips_ftemp);
2862 mips_cvtds (code, ins->dreg, ins->dreg);
2865 mips_mtc1 (code, mips_ftemp, ins->sreg1);
2866 mips_cvtdw (code, ins->dreg, mips_ftemp);
2868 case OP_FCONV_TO_I1:
2869 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2871 case OP_FCONV_TO_U1:
2872 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2874 case OP_FCONV_TO_I2:
2875 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
2877 case OP_FCONV_TO_U2:
2878 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
2880 case OP_FCONV_TO_I4:
2882 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
2884 case OP_FCONV_TO_U4:
2886 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
2888 case OP_FCONV_TO_I8:
2889 case OP_FCONV_TO_U8:
2890 g_assert_not_reached ();
2891 /* Implemented as helper calls */
2893 case OP_LCONV_TO_R_UN:
2894 g_assert_not_reached ();
2895 /* Implemented as helper calls */
2897 case OP_LCONV_TO_OVF_I:
2898 g_assert_not_reached ();
2899 /* split up by brg file */
2902 mips_fsqrtd (code, ins->dreg, ins->sreg1);
2905 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
2908 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
2911 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
2914 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
2917 mips_fnegd (code, ins->dreg, ins->sreg1);
2921 g_assert_not_reached ();
2924 g_assert_not_reached();
2927 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
2928 mips_addiu (code, ins->dreg, mips_zero, 1);
2929 mips_fbtrue (code, 2);
2931 mips_move (code, ins->dreg, mips_zero);
2934 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
2935 mips_addiu (code, ins->dreg, mips_zero, 1);
2936 mips_fbtrue (code, 2);
2938 mips_move (code, ins->dreg, mips_zero);
2941 /* Less than, or Unordered */
2942 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
2943 mips_addiu (code, ins->dreg, mips_zero, 1);
2944 mips_fbtrue (code, 2);
2946 mips_move (code, ins->dreg, mips_zero);
2949 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
2950 mips_move (code, ins->dreg, mips_zero);
2951 mips_fbtrue (code, 2);
2953 mips_addiu (code, ins->dreg, mips_zero, 1);
2956 /* Greater than, or Unordered */
2957 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
2958 mips_move (code, ins->dreg, mips_zero);
2959 mips_fbtrue (code, 2);
2961 mips_addiu (code, ins->dreg, mips_zero, 1);
2964 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
2966 if (ins->flags & MONO_INST_BRLABEL)
2967 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2969 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2970 mips_fbtrue (code, 0);
2974 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
2976 if (ins->flags & MONO_INST_BRLABEL)
2977 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2979 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2980 mips_fbfalse (code, 0);
2984 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
2986 if (ins->flags & MONO_INST_BRLABEL)
2987 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2989 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2990 mips_fbtrue (code, 0);
2994 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
2996 if (ins->flags & MONO_INST_BRLABEL)
2997 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2999 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3000 mips_fbtrue (code, 0);
3004 mips_fcmpd (code, MIPS_FPU_LE, ins->sreg1, ins->sreg2);
3006 if (ins->flags & MONO_INST_BRLABEL)
3007 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3009 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3010 mips_fbfalse (code, 0);
3014 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
3016 if (ins->flags & MONO_INST_BRLABEL)
3017 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3019 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3020 mips_fbfalse (code, 0);
3024 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
3026 if (ins->flags & MONO_INST_BRLABEL)
3027 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3029 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3030 mips_fbfalse (code, 0);
3034 mips_fcmpd (code, MIPS_FPU_OLT, ins->sreg1, ins->sreg2);
3036 if (ins->flags & MONO_INST_BRLABEL)
3037 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3039 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3040 mips_fbfalse (code, 0);
3044 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
3046 if (ins->flags & MONO_INST_BRLABEL)
3047 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3049 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3050 mips_fbtrue (code, 0);
3054 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
3056 if (ins->flags & MONO_INST_BRLABEL)
3057 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3059 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3060 mips_fbtrue (code, 0);
3064 g_assert_not_reached();
3066 ppc_stfd (code, ins->sreg1, -8, ppc_sp);
3067 ppc_lwz (code, ppc_r11, -8, ppc_sp);
3068 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 1, 31);
3069 ppc_addis (code, ppc_r11, ppc_r11, -32752);
3070 ppc_rlwinmd (code, ppc_r11, ppc_r11, 1, 31, 31);
3071 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3076 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3077 g_assert_not_reached ();
3080 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3081 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3082 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3083 g_assert_not_reached ();
3089 last_offset = offset;
3092 cfg->code_len = code - cfg->native_code;
3096 mono_arch_register_lowlevel_calls (void)
3101 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3103 MonoJumpInfo *patch_info;
3105 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3106 unsigned char *ip = patch_info->ip.i + code;
3107 const unsigned char *target;
3109 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3111 switch (patch_info->type) {
3112 case MONO_PATCH_INFO_IP:
3113 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
3115 case MONO_PATCH_INFO_SWITCH: {
3116 /* jt is the inlined jump table, 7 or 9 instructions after ip
3117 * In the normal case we store the absolute addresses.
3118 * otherwise the displacements.
3121 gpointer *table = (gpointer *)patch_info->data.table->table;
3122 gpointer *jt = ((gpointer*)(void *)ip) + 7;
3123 if (1 /* || !(cfg->->flags & MONO_CFG_HAS_CALLS) */)
3125 for (i = 0; i < patch_info->data.table->table_size; i++) {
3126 jt [i] = code + (int)table [i];
3130 case MONO_PATCH_INFO_METHODCONST:
3131 case MONO_PATCH_INFO_CLASS:
3132 case MONO_PATCH_INFO_IMAGE:
3133 case MONO_PATCH_INFO_FIELD:
3134 case MONO_PATCH_INFO_VTABLE:
3135 case MONO_PATCH_INFO_IID:
3136 case MONO_PATCH_INFO_SFLDA:
3137 case MONO_PATCH_INFO_LDSTR:
3138 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3139 case MONO_PATCH_INFO_LDTOKEN:
3140 case MONO_PATCH_INFO_R4:
3141 case MONO_PATCH_INFO_R8:
3142 /* from OP_AOTCONST : lui + addiu */
3143 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
3146 case MONO_PATCH_INFO_EXC_NAME:
3147 g_assert_not_reached ();
3148 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
3151 case MONO_PATCH_INFO_NONE:
3152 /* everything is dealt with at epilog output time */
3157 mips_patch ((guint32 *)(void *)ip, (guint32)target);
3163 mono_trace_lmf_prolog (MonoLMF *new_lmf)
3169 mono_trace_lmf_epilog (MonoLMF *old_lmf)
3174 * Allow tracing to work with this interface (with an optional argument)
3176 * This code is expected to be inserted just after the 'real' prolog code,
3177 * and before the first basic block. We need to allocate a 2nd, temporary
3178 * stack frame so that we can preserve f12-f15 as well as a0-a3.
3182 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
3185 int fp_stack_offset = 0;
3191 mips_sw (code, mips_a0, mips_sp, cfg->stack_offset + 0);
3192 mips_sw (code, mips_a1, mips_sp, cfg->stack_offset + 4);
3193 mips_sw (code, mips_a2, mips_sp, cfg->stack_offset + 8);
3194 mips_sw (code, mips_a3, mips_sp, cfg->stack_offset + 12);
3197 fp_stack_offset = MIPS_STACK_PARAM_OFFSET;
3198 mips_addiu (code, mips_sp, mips_sp, -64);
3199 mips_swc1 (code, mips_f12, mips_sp, fp_stack_offset + 16);
3200 mips_swc1 (code, mips_f13, mips_sp, fp_stack_offset + 20);
3201 mips_swc1 (code, mips_f14, mips_sp, fp_stack_offset + 24);
3202 mips_swc1 (code, mips_f15, mips_sp, fp_stack_offset + 28);
3204 mips_fmovs (code, mips_f22, mips_f12);
3205 mips_fmovs (code, mips_f23, mips_f13);
3206 mips_fmovs (code, mips_f24, mips_f14);
3207 mips_fmovs (code, mips_f25, mips_f15);
3210 mips_load_const (code, mips_a0, cfg->method);
3211 mips_addiu (code, mips_a1, mips_sp, cfg->stack_offset + fp_stack_offset);
3212 mips_load_const (code, mips_t9, func);
3213 mips_jalr (code, mips_t9, mips_ra);
3216 mips_lw (code, mips_a0, mips_sp, cfg->stack_offset + 0);
3217 mips_lw (code, mips_a1, mips_sp, cfg->stack_offset + 4);
3218 mips_lw (code, mips_a2, mips_sp, cfg->stack_offset + 8);
3219 mips_lw (code, mips_a3, mips_sp, cfg->stack_offset + 12);
3222 mips_lwc1 (code, mips_f12, mips_sp, fp_stack_offset + 16);
3223 mips_lwc1 (code, mips_f13, mips_sp, fp_stack_offset + 20);
3224 mips_lwc1 (code, mips_f14, mips_sp, fp_stack_offset + 24);
3225 mips_lwc1 (code, mips_f15, mips_sp, fp_stack_offset + 28);
3226 mips_addiu (code, mips_sp, mips_sp, 64);
3228 mips_fmovs (code, mips_f12, mips_f22);
3229 mips_fmovs (code, mips_f13, mips_f23);
3230 mips_fmovs (code, mips_f14, mips_f24);
3231 mips_fmovs (code, mips_f15, mips_f25);
3241 * Stack frame layout:
3243 * ------------------- sp + cfg->stack_usage + cfg->param_area
3244 * param area incoming
3245 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
3247 * ------------------- sp + cfg->stack_usage
3249 * ------------------- sp + cfg->stack_usage-4
3251 * ------------------- sp +
3252 * MonoLMF structure optional
3253 * ------------------- sp + cfg->arch.lmf_offset
3254 * saved registers s0-s8
3255 * ------------------- sp + cfg->arch.iregs_offset
3257 * ------------------- sp + cfg->param_area
3258 * param area outgoing
3259 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
3261 * ------------------- sp
3265 mono_arch_emit_prolog (MonoCompile *cfg)
3267 MonoMethod *method = cfg->method;
3268 MonoMethodSignature *sig;
3270 int alloc_size, pos, i;
3274 guint32 iregs_to_save = 0;
3276 guint32 fregs_to_save = 0;
3279 /* lmf_offset is the offset of the LMF from our stack pointer. */
3280 guint32 lmf_offset = cfg->arch.lmf_offset;
3283 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3287 cfg->flags |= MONO_CFG_HAS_CALLS;
3289 sig = mono_method_signature (method);
3290 cfg->code_size = 768 + sig->param_count * 20;
3291 code = cfg->native_code = g_malloc (cfg->code_size);
3293 /* re-align cfg->stack_offset if needed (due to var spilling in mini-codegen.c) */
3294 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
3296 /* stack_offset should not be changed here. */
3297 alloc_size = cfg->stack_offset;
3298 cfg->stack_usage = alloc_size;
3301 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
3303 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
3307 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
3309 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
3310 fregs_to_save |= (fregs_to_save << 1);
3314 if (mips_is_imm16 (-alloc_size)) {
3315 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
3317 mips_load_const (code, mips_at, -alloc_size);
3318 mips_addu (code, mips_sp, mips_sp, mips_at);
3322 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
3323 mips_sw (code, mips_ra, mips_sp, alloc_size + MIPS_RET_ADDR_OFFSET);
3325 /* XXX - optimize this later to not save all regs if LMF constructed */
3327 if (iregs_to_save) {
3328 /* save used registers in own stack frame (at pos) */
3329 pos = cfg->arch.iregs_offset;
3330 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
3331 if (iregs_to_save & (1 << i)) {
3332 g_assert (pos < cfg->stack_usage - 4);
3333 mips_sw (code, i, mips_sp, pos);
3334 pos += sizeof (gulong);
3339 if (method->save_lmf) {
3340 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
3341 mips_sw (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]));
3347 /* Save float registers */
3348 if (fregs_to_save) {
3349 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
3350 if (fregs_to_save & (1 << i)) {
3351 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
3352 mips_swc1 (code, i, mips_sp, pos);
3353 pos += sizeof (gulong);
3358 if (method->save_lmf) {
3359 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
3360 mips_swc1 (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]));
3365 if (cfg->frame_reg != mips_sp) {
3366 mips_move (code, cfg->frame_reg, mips_sp);
3368 if (method->save_lmf)
3369 mips_sw (code, cfg->frame_reg, mips_sp,
3370 lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]));
3374 /* Do instrumentation before assigning regvars to registers. Because they may be assigned
3375 * to the t* registers, which would be clobbered by the instrumentation calls.
3378 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3381 /* load arguments allocated to register from the stack */
3384 cinfo = calculate_sizes (sig, sig->pinvoke);
3386 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3387 ArgInfo *ainfo = &cinfo->ret;
3388 inst = cfg->vret_addr;
3389 if (inst->opcode == OP_REGVAR)
3390 mips_move (code, inst->dreg, ainfo->reg);
3391 else if (mips_is_imm16 (inst->inst_offset)) {
3392 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3394 mips_load_const (code, mips_at, inst->inst_offset);
3395 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
3396 mips_sw (code, ainfo->reg, mips_at, 0);
3399 /* Keep this in sync with emit_load_volatile_arguments */
3400 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3401 ArgInfo *ainfo = cinfo->args + i;
3402 inst = cfg->args [pos];
3404 if (cfg->verbose_level > 2)
3405 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3406 if (inst->opcode == OP_REGVAR) {
3407 /* Argument ends up in a register */
3408 if (ainfo->regtype == RegTypeGeneral)
3409 mips_move (code, inst->dreg, ainfo->reg);
3410 else if (ainfo->regtype == RegTypeFP) {
3411 g_assert_not_reached();
3413 ppc_fmr (code, inst->dreg, ainfo->reg);
3416 else if (ainfo->regtype == RegTypeBase) {
3417 mips_lw (code, inst->dreg, mips_sp, cfg->stack_usage + ainfo->offset);
3419 g_assert_not_reached ();
3421 if (cfg->verbose_level > 2)
3422 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3424 /* Argument ends up on the stack */
3425 if (ainfo->regtype == RegTypeGeneral) {
3426 /* Incoming parameters should be above this frame */
3427 g_assert (inst->inst_offset >= alloc_size);
3428 g_assert (mips_is_imm16 (inst->inst_offset));
3429 switch (ainfo->size) {
3431 mips_sb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3434 mips_sh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3438 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3441 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3442 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
3445 g_assert_not_reached ();
3448 } else if (ainfo->regtype == RegTypeBase) {
3450 * Argument comes in on the stack, and ends up on the stack
3451 * 1 and 2 byte args are passed as 32-bit quantities, but used as
3452 * 8 and 16 bit quantities. Shorten them in place.
3454 g_assert (mips_is_imm16 (inst->inst_offset));
3455 switch (ainfo->size) {
3457 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
3458 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
3461 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
3462 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
3469 g_assert_not_reached ();
3471 } else if (ainfo->regtype == RegTypeFP) {
3472 g_assert (mips_is_imm16 (inst->inst_offset));
3473 if (ainfo->size == 8) {
3475 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3477 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
3478 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
3481 else if (ainfo->size == 4)
3482 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3484 g_assert_not_reached ();
3485 } else if (ainfo->regtype == RegTypeStructByVal) {
3487 int doffset = inst->inst_offset;
3489 g_assert (mips_is_imm16 (inst->inst_offset));
3490 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3491 /* Push the argument registers into their stack slots */
3492 for (i = 0; i < ainfo->size; ++i) {
3493 mips_sw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3494 doffset += sizeof (gpointer);
3496 } else if (ainfo->regtype == RegTypeStructByAddr) {
3497 g_assert (mips_is_imm16 (inst->inst_offset));
3498 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3499 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
3501 g_assert_not_reached ();
3506 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
3507 mips_load_const (code, mips_a0, cfg->domain);
3508 mips_load_const (code, mips_t9, (gpointer)mono_jit_thread_attach);
3509 mips_jalr (code, mips_t9, mips_ra);
3514 if (method->save_lmf) {
3515 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
3516 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
3518 if (lmf_pthread_key != -1) {
3519 g_assert_not_reached();
3521 emit_tls_access (code, mips_temp, lmf_pthread_key);
3523 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
3524 mips_addiu (code, mips_a0, mips_temp, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3527 mips_addiu (code, mips_a0, mips_sp, lmf_offset);
3528 mips_load_const (code, mips_t9, (gpointer)mono_trace_lmf_prolog);
3529 mips_jalr (code, mips_t9, mips_ra);
3532 /* This can/will clobber the a0-a3 registers */
3533 mips_load_const (code, mips_t9, (gpointer)mono_get_lmf_addr);
3534 mips_jalr (code, mips_t9, mips_ra);
3538 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
3539 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
3540 /* new_lmf->previous_lmf = *lmf_addr */
3541 mips_lw (code, mips_at, mips_v0, 0);
3542 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
3543 /* *(lmf_addr) = sp + lmf_offset */
3544 mips_addiu (code, mips_at, mips_sp, lmf_offset);
3545 mips_sw (code, mips_at, mips_v0, 0);
3547 /* save method info */
3548 mips_load_const (code, mips_at, method);
3549 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
3550 mips_sw (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
3552 /* save the current IP */
3553 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3554 mips_load_const (code, mips_at, 0x01010101);
3555 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
3559 cfg->code_len = code - cfg->native_code;
3560 g_assert (cfg->code_len < cfg->code_size);
3575 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
3578 int save_mode = SAVE_NONE;
3580 MonoMethod *method = cfg->method;
3581 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
3582 int save_offset = MIPS_STACK_PARAM_OFFSET;
3584 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
3586 offset = code - cfg->native_code;
3587 /* we need about 16 instructions */
3588 if (offset > (cfg->code_size - 16 * 4)) {
3589 cfg->code_size *= 2;
3590 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3591 code = cfg->native_code + offset;
3596 case MONO_TYPE_VOID:
3597 /* special case string .ctor icall */
3598 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
3599 save_mode = SAVE_ONE;
3601 save_mode = SAVE_NONE;
3605 save_mode = SAVE_TWO;
3609 save_mode = SAVE_FP;
3611 case MONO_TYPE_VALUETYPE:
3612 save_mode = SAVE_STRUCT;
3615 save_mode = SAVE_ONE;
3619 mips_addiu (code, mips_sp, mips_sp, -32);
3620 switch (save_mode) {
3622 mips_sw (code, mips_v0, mips_sp, save_offset);
3623 mips_sw (code, mips_v1, mips_sp, save_offset + 4);
3624 if (enable_arguments) {
3625 mips_move (code, mips_a1, mips_v0);
3626 mips_move (code, mips_a2, mips_v1);
3630 mips_sw (code, mips_v0, mips_sp, save_offset);
3631 if (enable_arguments) {
3632 mips_move (code, mips_a1, mips_v0);
3636 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
3637 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
3638 mips_lw (code, mips_a0, mips_sp, save_offset);
3639 mips_lw (code, mips_a1, mips_sp, save_offset+4);
3646 mips_load_const (code, mips_a0, cfg->method);
3647 mips_load_const (code, mips_t9, func);
3648 mips_jalr (code, mips_t9, mips_ra);
3651 switch (save_mode) {
3653 mips_lw (code, mips_v0, mips_sp, save_offset);
3654 mips_lw (code, mips_v1, mips_sp, save_offset + 4);
3657 mips_lw (code, mips_v0, mips_sp, save_offset);
3660 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
3667 mips_addiu (code, mips_sp, mips_sp, 32);
3674 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
3676 MonoMethod *method = cfg->method;
3678 int max_epilog_size = 16 + 20*4;
3679 guint32 iregs_to_restore;
3681 guint32 fregs_to_restore;
3685 if (cfg->method->save_lmf)
3686 max_epilog_size += 128;
3689 if (mono_jit_trace_calls != NULL)
3690 max_epilog_size += 50;
3692 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3693 max_epilog_size += 50;
3696 pos = code - cfg->native_code;
3697 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3698 cfg->code_size *= 2;
3699 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3700 mono_jit_stats.code_reallocs++;
3704 * Keep in sync with OP_JMP
3707 code = cfg->native_code + pos;
3709 code = cfg->native_code + cfg->code_len;
3711 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3712 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3714 pos = cfg->arch.iregs_offset;
3715 if (cfg->frame_reg != mips_sp) {
3716 mips_move (code, mips_sp, cfg->frame_reg);
3719 iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
3721 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
3723 if (iregs_to_restore) {
3724 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
3725 if (iregs_to_restore & (1 << i)) {
3726 mips_lw (code, i, mips_sp, pos);
3727 pos += sizeof (gulong);
3734 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
3736 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
3737 fregs_to_restore |= (fregs_to_restore << 1);
3739 if (fregs_to_restore) {
3740 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
3741 if (fregs_to_restore & (1 << i)) {
3742 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
3743 mips_lwc1 (code, i, mips_sp, pos);
3744 pos += sizeof (gulong);
3750 /* Unlink the LMF if necessary */
3751 if (method->save_lmf) {
3752 int lmf_offset = cfg->arch.lmf_offset;
3754 /* t0 = current_lmf->previous_lmf */
3755 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
3757 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
3758 /* (*lmf_addr) = previous_lmf */
3759 mips_sw (code, mips_temp, mips_t1, 0);
3763 /* Restore the fp */
3764 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
3766 /* Correct the stack pointer */
3767 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
3768 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage + MIPS_RET_ADDR_OFFSET);
3769 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage);
3771 /* Caller will emit either return or tail-call sequence */
3773 cfg->code_len = code - cfg->native_code;
3775 g_assert (cfg->code_len < cfg->code_size);
3780 mono_arch_emit_epilog (MonoCompile *cfg)
3784 code = mono_arch_emit_epilog_sub (cfg, NULL);
3786 mips_jr (code, mips_ra);
3789 cfg->code_len = code - cfg->native_code;
3791 g_assert (cfg->code_len < cfg->code_size);
3794 /* remove once throw_exception_by_name is eliminated */
3796 exception_id_by_name (const char *name)
3798 if (strcmp (name, "IndexOutOfRangeException") == 0)
3799 return MONO_EXC_INDEX_OUT_OF_RANGE;
3800 if (strcmp (name, "OverflowException") == 0)
3801 return MONO_EXC_OVERFLOW;
3802 if (strcmp (name, "ArithmeticException") == 0)
3803 return MONO_EXC_ARITHMETIC;
3804 if (strcmp (name, "DivideByZeroException") == 0)
3805 return MONO_EXC_DIVIDE_BY_ZERO;
3806 if (strcmp (name, "InvalidCastException") == 0)
3807 return MONO_EXC_INVALID_CAST;
3808 if (strcmp (name, "NullReferenceException") == 0)
3809 return MONO_EXC_NULL_REF;
3810 if (strcmp (name, "ArrayTypeMismatchException") == 0)
3811 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3812 g_error ("Unknown intrinsic exception %s\n", name);
3817 mono_arch_emit_exceptions (MonoCompile *cfg)
3820 MonoJumpInfo *patch_info;
3823 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3824 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3825 int max_epilog_size = 50;
3827 /* count the number of exception infos */
3830 * make sure we have enough space for exceptions
3831 * 24 is the simulated call to throw_exception_by_name
3833 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3835 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3836 i = exception_id_by_name (patch_info->data.target);
3837 g_assert (i < MONO_EXC_INTRINS_NUM);
3838 if (!exc_throw_found [i]) {
3839 max_epilog_size += 12;
3840 exc_throw_found [i] = TRUE;
3846 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3847 cfg->code_size *= 2;
3848 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3849 mono_jit_stats.code_reallocs++;
3852 code = cfg->native_code + cfg->code_len;
3854 /* add code to raise exceptions */
3855 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3856 switch (patch_info->type) {
3857 case MONO_PATCH_INFO_EXC: {
3859 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
3861 i = exception_id_by_name (patch_info->data.target);
3862 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
3863 if (!exc_throw_pos [i]) {
3866 exc_throw_pos [i] = code;
3867 //g_print ("exc: writing stub at %p\n", code);
3868 mips_load_const (code, mips_a0, patch_info->data.target);
3869 addr = (guint32) mono_arch_get_throw_exception_by_name ();
3870 mips_load_const (code, mips_t9, addr);
3871 mips_jr (code, mips_t9);
3874 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
3876 /* Turn into a Relative patch, pointing at code stub */
3877 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
3878 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
3880 g_assert_not_reached();
3890 cfg->code_len = code - cfg->native_code;
3892 g_assert (cfg->code_len < cfg->code_size);
3897 * Thread local storage support
3900 setup_tls_access (void)
3903 //guint32 *ins, *code;
3905 if (tls_mode == TLS_MODE_FAILED)
3908 if (g_getenv ("MONO_NO_TLS")) {
3909 tls_mode = TLS_MODE_FAILED;
3913 if (tls_mode == TLS_MODE_DETECT) {
3915 tls_mode = TLS_MODE_FAILED;
3919 ins = (guint32*)pthread_getspecific;
3920 /* uncond branch to the real method */
3921 if ((*ins >> 26) == 18) {
3923 val = (*ins & ~3) << 6;
3927 ins = (guint32*)val;
3929 ins = (guint32*) ((char*)ins + val);
3932 code = &cmplwi_1023;
3933 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
3935 ppc_li (code, ppc_r4, 0x48);
3938 if (*ins == cmplwi_1023) {
3939 int found_lwz_284 = 0;
3940 for (ptk = 0; ptk < 20; ++ptk) {
3942 if (!*ins || *ins == blr_ins)
3944 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
3949 if (!found_lwz_284) {
3950 tls_mode = TLS_MODE_FAILED;
3953 tls_mode = TLS_MODE_LTHREADS;
3954 } else if (*ins == li_0x48) {
3956 /* uncond branch to the real method */
3957 if ((*ins >> 26) == 18) {
3959 val = (*ins & ~3) << 6;
3963 ins = (guint32*)val;
3965 ins = (guint32*) ((char*)ins + val);
3968 ppc_li (code, ppc_r0, 0x7FF2);
3969 if (ins [1] == val) {
3970 /* Darwin on G4, implement */
3971 tls_mode = TLS_MODE_FAILED;
3975 ppc_mfspr (code, ppc_r3, 104);
3976 if (ins [1] != val) {
3977 tls_mode = TLS_MODE_FAILED;
3980 tls_mode = TLS_MODE_DARWIN_G5;
3983 tls_mode = TLS_MODE_FAILED;
3987 tls_mode = TLS_MODE_FAILED;
3992 if (monodomain_key == -1) {
3993 ptk = mono_domain_get_tls_key ();
3995 ptk = mono_pthread_key_for_tls (ptk);
3997 monodomain_key = ptk;
4001 if (lmf_pthread_key == -1) {
4002 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
4004 /*g_print ("MonoLMF at: %d\n", ptk);*/
4005 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
4006 init_tls_failed = 1;
4009 lmf_pthread_key = ptk;
4012 if (monothread_key == -1) {
4013 ptk = mono_thread_get_tls_key ();
4015 ptk = mono_pthread_key_for_tls (ptk);
4017 monothread_key = ptk;
4018 /*g_print ("thread inited: %d\n", ptk);*/
4021 /*g_print ("thread not inited yet %d\n", ptk);*/
4027 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4029 setup_tls_access ();
4033 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4038 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4040 int this_dreg = mips_a0;
4043 this_dreg = mips_a1;
4045 /* add the this argument */
4046 if (this_reg != -1) {
4048 MONO_INST_NEW (cfg, this, OP_MOVE);
4049 this->type = this_type;
4050 this->sreg1 = this_reg;
4051 this->dreg = mono_regstate_next_int (cfg->rs);
4052 mono_bblock_add_inst (cfg->cbb, this);
4053 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
4058 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4059 vtarg->type = STACK_MP;
4060 vtarg->sreg1 = vt_reg;
4061 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4062 mono_bblock_add_inst (cfg->cbb, vtarg);
4063 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
4068 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4070 MonoInst *ins = NULL;
4076 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4082 mono_arch_print_tree (MonoInst *tree, int arity)
4087 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4091 setup_tls_access ();
4092 if (monodomain_key == -1)
4095 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4096 ins->inst_offset = monodomain_key;
4101 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4105 setup_tls_access ();
4106 if (monothread_key == -1)
4109 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4110 ins->inst_offset = monothread_key;
4115 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4117 /* FIXME: implement */
4118 g_assert_not_reached ();