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 #warning "The mips backend is still being ported to the linear IR."
28 #define SAVE_FP_REGS 0
29 #define SAVE_ALL_REGS 0
30 #define EXTRA_STACK_SPACE 1 /* 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 g_assert_not_reached (); \
68 ppc_lwz ((code), (dreg), off1, ppc_r2); \
69 ppc_lwz ((code), (dreg), off2, (dreg)); \
73 #define emit_tls_access(code,dreg,key) do { \
75 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
76 default: g_assert_not_reached (); \
80 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
82 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
83 inst->type = STACK_R8; \
85 inst->inst_p0 = (void*)(addr); \
86 mono_bblock_add_inst (cfg->cbb, inst); \
89 typedef struct InstList InstList;
107 guint16 vtsize; /* in param area */
109 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
110 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
127 void patch_lui_addiu(guint32 *ip, guint32 val);
128 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
131 mono_arch_flush_icache (guint8 *code, gint size)
133 /* Linux/MIPS specific */
134 cacheflush (code, size, BCACHE);
138 mono_arch_flush_register_windows (void)
143 mono_arch_is_inst_imm (gint64 imm)
149 mips_emit_exc_by_name(guint8 *code, const char *name)
153 mips_load_const (code, mips_a0, name);
154 addr = (guint32) mono_arch_get_throw_exception_by_name ();
155 mips_load_const (code, mips_t9, addr);
156 mips_jalr (code, mips_t9, mips_ra);
164 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
170 /* Invert test and emit branch around jump */
173 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
177 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
181 mips_bltz (code, ins->sreg1, br_offset);
185 mips_blez (code, ins->sreg1, br_offset);
189 mips_bgtz (code, ins->sreg1, br_offset);
193 mips_bgez (code, ins->sreg1, br_offset);
197 g_assert_not_reached ();
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);
205 mips_lui (code, mips_at, mips_zero, 0);
206 mips_addiu (code, mips_at, mips_at, 0);
207 mips_jr (code, mips_at);
210 if (ins->flags & MONO_INST_BRLABEL)
211 mono_add_patch_info (cfg, code - cfg->native_code,
212 MONO_PATCH_INFO_LABEL, ins->inst_i0);
214 mono_add_patch_info (cfg, code - cfg->native_code,
215 MONO_PATCH_INFO_BB, ins->inst_true_bb);
218 mips_beq (code, ins->sreg1, ins->sreg2, 0);
222 mips_bne (code, ins->sreg1, ins->sreg2, 0);
226 mips_bgez (code, ins->sreg1, 0);
230 mips_bgtz (code, ins->sreg1, 0);
234 mips_blez (code, ins->sreg1, 0);
238 mips_bltz (code, ins->sreg1, 0);
242 g_assert_not_reached ();
248 /* XXX - big-endian dependent? */
250 patch_lui_addiu(guint32 *ip, guint32 val)
252 guint16 *__lui_addiu = (guint16*)(void *)(ip);
255 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
256 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
259 if (((guint32)(val)) & (1 << 15))
260 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
262 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
263 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
264 mono_arch_flush_icache ((guint8 *)ip, 8);
269 mips_patch (guint32 *code, guint32 target)
272 guint32 op = ins >> 26;
273 guint32 diff, offset;
275 g_assert (trap_target != target);
276 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
278 case 0x00: /* jr ra */
279 if (ins == 0x3e00008)
281 g_assert_not_reached ();
285 g_assert (!(target & 0x03));
286 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
287 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
289 mono_arch_flush_icache ((guint8 *)code, 4);
291 case 0x01: /* BLTZ */
294 case 0x06: /* BLEZ */
295 case 0x07: /* BGTZ */
296 case 0x11: /* bc1t */
297 diff = target - (guint32)(code + 1);
298 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
299 g_assert (!(diff & 0x03));
300 offset = ((gint32)diff) >> 2;
301 g_assert (((int)offset) == ((int)(short)offset));
302 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
304 mono_arch_flush_icache ((guint8 *)code, 4);
306 case 0x0f: /* LUI / ADDIU pair */
307 patch_lui_addiu (code, target);
308 mono_arch_flush_icache ((guint8 *)code, 8);
312 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
313 g_assert_not_reached ();
318 offsets_from_pthread_key (guint32 key, int *offset2)
322 *offset2 = idx2 * sizeof (gpointer);
323 return 284 + idx1 * sizeof (gpointer);
327 mono_arch_regname (int reg) {
328 static const char * rnames[] = {
329 "zero", "at", "v0", "v1",
330 "a0", "a1", "a2", "a3",
331 "t0", "t1", "t2", "t3",
332 "t4", "t5", "t6", "t7",
333 "s0", "s1", "s2", "s3",
334 "s4", "s5", "s6", "s7",
335 "t8", "t9", "k0", "k1",
336 "gp", "sp", "fp", "ra"
338 if (reg >= 0 && reg < 32)
344 mono_arch_fregname (int reg) {
345 static const char * rnames[] = {
346 "f0", "f1", "f2", "f3",
347 "f4", "f5", "f6", "f7",
348 "f8", "f9", "f10", "f11",
349 "f12", "f13", "f14", "f15",
350 "f16", "f17", "f18", "f19",
351 "f20", "f21", "f22", "f23",
352 "f24", "f25", "f26", "f27",
353 "f28", "f29", "f30", "f31"
355 if (reg >= 0 && reg < 32)
360 /* this function overwrites at */
362 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
364 /* XXX write a loop, not an unrolled loop */
366 mips_lw (code, mips_at, sreg, soffset);
367 mips_sw (code, mips_at, dreg, doffset);
376 * mono_arch_get_argument_info:
377 * @csig: a method signature
378 * @param_count: the number of parameters to consider
379 * @arg_info: an array to store the result infos
381 * Gathers information on parameters such as size, alignment and
382 * padding. arg_info should be large enought to hold param_count + 1 entries.
384 * Returns the size of the activation frame.
387 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
389 int k, frame_size = 0;
390 guint32 size, align, pad;
393 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
394 frame_size += sizeof (gpointer);
398 arg_info [0].offset = offset;
401 frame_size += sizeof (gpointer);
405 arg_info [0].size = frame_size;
407 for (k = 0; k < param_count; k++) {
408 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
410 /* ignore alignment for now */
413 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
414 arg_info [k].pad = pad;
416 arg_info [k + 1].pad = 0;
417 arg_info [k + 1].size = size;
419 arg_info [k + 1].offset = offset;
423 align = MONO_ARCH_FRAME_ALIGNMENT;
424 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
425 arg_info [k].pad = pad;
432 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gssize *regs, guint8 *code)
434 /* FIXME: handle returning a struct */
435 if (MONO_TYPE_ISSTRUCT (sig->ret))
436 return (gpointer)regs [mips_a1];
437 return (gpointer)regs [mips_a0];
441 * Initialize the cpu to execute managed code.
444 mono_arch_cpu_init (void)
449 * Initialize architecture specific code.
452 mono_arch_init (void)
457 * Cleanup architecture specific code.
460 mono_arch_cleanup (void)
465 * This function returns the optimizations supported on this cpu.
468 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
472 /* no mips-specific optimizations yet */
478 is_regsize_var (MonoType *t) {
481 t = mono_type_get_underlying_type (t);
488 case MONO_TYPE_FNPTR:
490 case MONO_TYPE_OBJECT:
491 case MONO_TYPE_STRING:
492 case MONO_TYPE_CLASS:
493 case MONO_TYPE_SZARRAY:
494 case MONO_TYPE_ARRAY:
496 case MONO_TYPE_GENERICINST:
497 if (!mono_type_generic_inst_is_valuetype (t))
500 case MONO_TYPE_VALUETYPE:
507 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
512 for (i = 0; i < cfg->num_varinfo; i++) {
513 MonoInst *ins = cfg->varinfo [i];
514 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
517 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
520 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
523 /* we can only allocate 32 bit values */
524 if (is_regsize_var (ins->inst_vtype)) {
525 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
526 g_assert (i == vmv->idx);
527 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
535 mono_arch_get_global_int_regs (MonoCompile *cfg)
539 regs = g_list_prepend (regs, (gpointer)mips_s0);
540 regs = g_list_prepend (regs, (gpointer)mips_s1);
541 regs = g_list_prepend (regs, (gpointer)mips_s2);
542 regs = g_list_prepend (regs, (gpointer)mips_s3);
543 regs = g_list_prepend (regs, (gpointer)mips_s4);
544 //regs = g_list_prepend (regs, (gpointer)mips_s5);
545 regs = g_list_prepend (regs, (gpointer)mips_s6);
546 regs = g_list_prepend (regs, (gpointer)mips_s7);
552 * mono_arch_regalloc_cost:
554 * Return the cost, in number of memory references, of the action of
555 * allocating the variable VMV into a register during global register
559 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
566 args_onto_stack (CallInfo *info)
568 g_assert(!info->on_stack);
569 g_assert(info->stack_size <= MIPS_STACK_PARAM_OFFSET);
570 info->on_stack = TRUE;
571 info->stack_size = MIPS_STACK_PARAM_OFFSET;
575 * O32 calling convention version
579 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
580 /* First, see if we need to drop onto the stack */
581 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
582 args_onto_stack (info);
584 /* Now, place the argument */
585 if (info->on_stack) {
586 ainfo->regtype = RegTypeBase;
587 ainfo->reg = mips_sp; /* in the caller */
588 ainfo->offset = info->stack_size;
591 ainfo->regtype = RegTypeGeneral;
592 ainfo->reg = info->gr;
594 info->gr_passed = TRUE;
596 info->stack_size += 4;
600 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
601 /* First, see if we need to drop onto the stack */
602 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
603 args_onto_stack (info);
605 /* Now, place the argument */
606 if (info->on_stack) {
607 g_assert(info->stack_size % 4 == 0);
608 info->stack_size += (info->stack_size % 8);
610 ainfo->regtype = RegTypeBase;
611 ainfo->reg = mips_sp; /* in the caller */
612 ainfo->offset = info->stack_size;
615 // info->gr must be a0 or a2
616 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
617 g_assert(info->gr <= MIPS_LAST_ARG_REG);
619 ainfo->regtype = RegTypeGeneral;
620 ainfo->reg = info->gr;
622 info->gr_passed = TRUE;
624 info->stack_size += 8;
628 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
629 /* First, see if we need to drop onto the stack */
630 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
631 args_onto_stack (info);
633 /* Now, place the argument */
634 if (info->on_stack) {
635 ainfo->regtype = RegTypeBase;
636 ainfo->reg = mips_sp; /* in the caller */
637 ainfo->offset = info->stack_size;
640 /* Only use FP regs for args if no int args passed yet */
641 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
642 ainfo->regtype = RegTypeFP;
643 ainfo->reg = info->fr;
644 /* Even though it's a single-precision float, it takes up two FP regs */
646 /* FP and GP slots do not overlap */
650 /* Passing single-precision float arg in a GP register
651 * such as: func (0, 1.0, 2, 3);
652 * In this case, only one 'gr' register is consumed.
654 ainfo->regtype = RegTypeGeneral;
655 ainfo->reg = info->gr;
658 info->gr_passed = TRUE;
661 info->stack_size += 4;
665 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
666 /* First, see if we need to drop onto the stack */
667 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
668 args_onto_stack (info);
670 /* Now, place the argument */
671 if (info->on_stack) {
672 g_assert(info->stack_size % 4 == 0);
673 info->stack_size += (info->stack_size % 8);
675 ainfo->regtype = RegTypeBase;
676 ainfo->reg = mips_sp; /* in the caller */
677 ainfo->offset = info->stack_size;
680 /* Only use FP regs for args if no int args passed yet */
681 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
682 ainfo->regtype = RegTypeFP;
683 ainfo->reg = info->fr;
685 /* FP and GP slots do not overlap */
689 // info->gr must be a0 or a2
690 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
691 g_assert(info->gr <= MIPS_LAST_ARG_REG);
693 ainfo->regtype = RegTypeGeneral;
694 ainfo->reg = info->gr;
696 info->gr_passed = TRUE;
699 info->stack_size += 8;
703 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
706 int n = sig->hasthis + sig->param_count;
708 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
710 cinfo->fr = MIPS_FIRST_FPARG_REG;
711 cinfo->gr = MIPS_FIRST_ARG_REG;
712 cinfo->stack_size = 0;
714 DEBUG(printf("calculate_sizes\n"));
716 /* handle returning a struct */
717 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
718 cinfo->struct_ret = cinfo->gr;
719 add_int32_arg (cinfo, &cinfo->ret);
724 add_int32_arg (cinfo, cinfo->args + n);
727 DEBUG(printf("params: %d\n", sig->param_count));
728 for (i = 0; i < sig->param_count; ++i) {
729 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
730 /* Prevent implicit arguments and sig_cookie from
731 being passed in registers */
732 args_onto_stack (cinfo);
733 /* Emit the signature cookie just before the implicit arguments */
734 add_int32_arg (cinfo, &cinfo->sig_cookie);
736 DEBUG(printf("param %d: ", i));
737 if (sig->params [i]->byref) {
738 DEBUG(printf("byref\n"));
739 add_int32_arg (cinfo, &cinfo->args[n]);
743 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
744 switch (simpletype) {
745 case MONO_TYPE_BOOLEAN:
748 DEBUG(printf("1 byte\n"));
749 cinfo->args [n].size = 1;
750 add_int32_arg (cinfo, &cinfo->args[n]);
756 DEBUG(printf("2 bytes\n"));
757 cinfo->args [n].size = 2;
758 add_int32_arg (cinfo, &cinfo->args[n]);
763 DEBUG(printf("4 bytes\n"));
764 cinfo->args [n].size = 4;
765 add_int32_arg (cinfo, &cinfo->args[n]);
771 case MONO_TYPE_FNPTR:
772 case MONO_TYPE_CLASS:
773 case MONO_TYPE_OBJECT:
774 case MONO_TYPE_STRING:
775 case MONO_TYPE_SZARRAY:
776 case MONO_TYPE_ARRAY:
777 cinfo->args [n].size = sizeof (gpointer);
778 add_int32_arg (cinfo, &cinfo->args[n]);
781 case MONO_TYPE_GENERICINST:
782 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
783 cinfo->args [n].size = sizeof (gpointer);
784 add_int32_arg (cinfo, &cinfo->args[n]);
789 case MONO_TYPE_VALUETYPE: {
792 int has_offset = FALSE;
794 gint size, alignment;
797 klass = mono_class_from_mono_type (sig->params [i]);
799 size = mono_class_native_size (klass, NULL);
801 size = mono_class_value_size (klass, NULL);
802 alignment = mono_class_min_align (klass);
803 #if MIPS_PASS_STRUCTS_BY_VALUE
804 /* Need to do alignment if struct contains long or double */
806 if (cinfo->stack_size & (alignment - 1)) {
807 add_int32_arg (cinfo, &dummy_arg);
809 g_assert (!(cinfo->stack_size & (alignment - 1)));
813 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
814 mono_class_native_size (sig->params [i]->data.klass, NULL),
815 cinfo->stack_size, alignment);
817 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
818 g_assert(cinfo->args [n].size == 0);
819 g_assert(cinfo->args [n].vtsize == 0);
820 for (j = 0; j < nwords; ++j) {
822 add_int32_arg (cinfo, &cinfo->args [n]);
826 add_int32_arg (cinfo, &dummy_arg);
827 if (!has_offset && cinfo->on_stack) {
828 cinfo->args [n].offset = dummy_arg.offset;
833 cinfo->args [n].vtsize += 1;
835 cinfo->args [n].size += 1;
837 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
838 cinfo->args [n].regtype = RegTypeStructByVal;
840 add_int32_arg (cinfo, &cinfo->args[n]);
841 cinfo->args [n].regtype = RegTypeStructByAddr;
846 case MONO_TYPE_TYPEDBYREF: {
847 /* keep in sync or merge with the valuetype case */
848 #if MIPS_PASS_STRUCTS_BY_VALUE
850 int size = sizeof (MonoTypedRef);
851 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
852 cinfo->args [n].regtype = RegTypeStructByVal;
853 if (!cinfo->on_stack && cinfo->gr <= MIPS_LAST_ARG_REG) {
854 int rest = MIPS_LAST_ARG_REG - cinfo->gr + 1;
855 int n_in_regs = rest >= nwords? nwords: rest;
856 cinfo->args [n].size = n_in_regs;
857 cinfo->args [n].vtsize = nwords - n_in_regs;
858 cinfo->args [n].reg = cinfo->gr;
859 cinfo->gr += n_in_regs;
860 cinfo->gr_passed = TRUE;
862 cinfo->args [n].size = 0;
863 cinfo->args [n].vtsize = nwords;
865 if (cinfo->args [n].vtsize > 0) {
866 if (!cinfo->on_stack)
867 args_onto_stack (cinfo);
868 g_assert(cinfo->on_stack);
869 cinfo->args [n].offset = cinfo->stack_size;
870 g_print ("offset for arg %d at %d\n", n, cinfo->args [n].offset);
871 cinfo->stack_size += cinfo->args [n].vtsize * sizeof (gpointer);
875 add_int32_arg (cinfo, &cinfo->args[n]);
876 cinfo->args [n].regtype = RegTypeStructByAddr;
883 DEBUG(printf("8 bytes\n"));
884 cinfo->args [n].size = 8;
885 add_int64_arg (cinfo, &cinfo->args[n]);
889 DEBUG(printf("R4\n"));
890 cinfo->args [n].size = 4;
891 add_float32_arg (cinfo, &cinfo->args[n]);
895 DEBUG(printf("R8\n"));
896 cinfo->args [n].size = 8;
897 add_float64_arg (cinfo, &cinfo->args[n]);
901 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
906 simpletype = mono_type_get_underlying_type (sig->ret)->type;
907 switch (simpletype) {
908 case MONO_TYPE_BOOLEAN:
919 case MONO_TYPE_FNPTR:
920 case MONO_TYPE_CLASS:
921 case MONO_TYPE_OBJECT:
922 case MONO_TYPE_SZARRAY:
923 case MONO_TYPE_ARRAY:
924 case MONO_TYPE_STRING:
925 cinfo->ret.reg = mips_v0;
929 cinfo->ret.reg = mips_v0;
933 cinfo->ret.reg = mips_f0;
934 cinfo->ret.regtype = RegTypeFP;
936 case MONO_TYPE_GENERICINST:
937 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
938 cinfo->ret.reg = mips_v0;
942 case MONO_TYPE_VALUETYPE:
944 case MONO_TYPE_TYPEDBYREF:
948 g_error ("Can't handle as return value 0x%x", sig->ret->type);
952 /* align stack size to 16 */
953 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
955 cinfo->stack_usage = cinfo->stack_size;
961 * Set var information according to the calling convention. mips version.
962 * The locals var stuff should most likely be split in another method.
965 mono_arch_allocate_vars (MonoCompile *cfg)
967 MonoMethodSignature *sig;
968 MonoMethodHeader *header;
970 int i, offset, size, align, curinst;
971 int frame_reg = mips_sp;
972 guint32 iregs_to_save = 0;
973 guint32 fregs_to_restore;
975 cfg->flags |= MONO_CFG_HAS_SPILLUP;
977 /* allow room for the vararg method args: void* and long/double */
978 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
979 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
981 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
982 * call convs needs to be handled this way.
984 if (cfg->flags & MONO_CFG_HAS_VARARGS)
985 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
987 /* gtk-sharp and other broken code will dllimport vararg functions even with
988 * non-varargs signatures. Since there is little hope people will get this right
989 * we assume they won't.
991 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
992 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
994 /* a0-a3 always present */
995 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
997 header = mono_method_get_header (cfg->method);
999 sig = mono_method_signature (cfg->method);
1002 * We use the frame register also for any method that has
1003 * exception clauses. This way, when the handlers are called,
1004 * the code will reference local variables using the frame reg instead of
1005 * the stack pointer: if we had to restore the stack pointer, we'd
1006 * corrupt the method frames that are already on the stack (since
1007 * filters get called before stack unwinding happens) when the filter
1008 * code would call any method (this also applies to finally etc.).
1011 if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses || ALWAYS_USE_FP)
1012 frame_reg = mips_fp;
1013 cfg->frame_reg = frame_reg;
1014 if (frame_reg != mips_sp) {
1015 cfg->used_int_regs |= 1 << frame_reg;
1020 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1021 /* FIXME: handle long and FP values */
1022 switch (mono_type_get_underlying_type (sig->ret)->type) {
1023 case MONO_TYPE_VOID:
1026 cfg->ret->opcode = OP_REGVAR;
1027 cfg->ret->inst_c0 = mips_v0;
1031 /* Space for outgoing parameters, including a0-a3 */
1032 offset += cfg->param_area;
1034 /* allow room to save the return value (if it's a struct) */
1035 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1038 if (sig->call_convention == MONO_CALL_VARARG) {
1039 cfg->sig_cookie = MIPS_STACK_PARAM_OFFSET;
1042 /* Now handle the local variables */
1044 curinst = cfg->locals_start;
1045 for (i = curinst; i < cfg->num_varinfo; ++i) {
1046 inst = cfg->varinfo [i];
1047 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1050 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1051 * pinvoke wrappers when they call functions returning structure
1053 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1054 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
1056 size = mono_type_size (inst->inst_vtype, &align);
1058 offset += align - 1;
1059 offset &= ~(align - 1);
1060 inst->inst_offset = offset;
1061 inst->opcode = OP_REGOFFSET;
1062 inst->inst_basereg = frame_reg;
1064 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1067 /* Space for LMF (if needed) */
1069 if (cfg->method->save_lmf) {
1070 /* align the offset to 16 bytes */
1071 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1072 cfg->arch.lmf_offset = offset;
1073 offset += sizeof (MonoLMF);
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.
1083 /* Space for saved registers */
1084 cfg->arch.iregs_offset = offset;
1086 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
1088 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1090 if (iregs_to_save) {
1091 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1092 if (iregs_to_save & (1 << i)) {
1093 offset += sizeof (gulong);
1098 #if EXTRA_STACK_SPACE
1099 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1100 * args or return vals. Extra stack space avoids this in a lot of cases.
1105 /* saved float registers */
1107 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1108 if (fregs_to_restore) {
1109 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1110 if (fregs_to_restore & (1 << i)) {
1111 offset += sizeof (double);
1117 /* Now add space for saving the ra */
1121 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1122 cfg->stack_offset = offset;
1125 * Now allocate stack slots for the int arg regs (a0 - a3)
1126 * On MIPS o32, these are just above the incoming stack pointer
1127 * Even if the arg has been assigned to a regvar, it gets a stack slot
1130 /* Return struct-by-value results in a hidden first argument */
1131 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1132 cfg->vret_addr->opcode = OP_REGOFFSET;
1133 cfg->vret_addr->inst_c0 = mips_a0;
1134 cfg->vret_addr->inst_offset = offset;
1135 cfg->vret_addr->inst_basereg = frame_reg;
1139 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1140 inst = cfg->args [i];
1141 if (inst->opcode != OP_REGVAR) {
1144 if (sig->hasthis && (i == 0))
1145 arg_type = &mono_defaults.object_class->byval_arg;
1147 arg_type = sig->params [i - sig->hasthis];
1149 inst->opcode = OP_REGOFFSET;
1150 size = mono_type_size (arg_type, &align);
1156 inst->inst_basereg = frame_reg;
1157 offset = (offset + align - 1) & ~(align - 1);
1158 inst->inst_offset = offset;
1160 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1161 cfg->sig_cookie += size;
1162 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1165 /* Even a0-a3 get stack slots */
1166 size = sizeof (gpointer);
1167 align = sizeof (gpointer);
1168 inst->inst_basereg = frame_reg;
1169 offset = (offset + align - 1) & ~(align - 1);
1170 inst->inst_offset = offset;
1172 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1173 cfg->sig_cookie += size;
1174 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1180 mono_arch_create_vars (MonoCompile *cfg)
1182 MonoMethodSignature *sig;
1184 sig = mono_method_signature (cfg->method);
1186 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1187 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1188 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1189 printf ("vret_addr = ");
1190 mono_print_ins (cfg->vret_addr);
1195 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1196 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1200 * take the arguments and generate the arch-specific
1201 * instructions to properly call the function in call.
1202 * This includes pushing, moving arguments to the right register
1204 * Issue: who does the spilling if needed, and when?
1207 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1209 int sig_reg = mono_alloc_ireg (cfg);
1211 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (guint32)call->signature);
1212 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1213 mips_sp, cinfo->sig_cookie.offset, sig_reg);
1217 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1220 MonoMethodSignature *sig;
1225 sig = call->signature;
1226 n = sig->param_count + sig->hasthis;
1228 cinfo = calculate_sizes (sig, sig->pinvoke);
1229 if (cinfo->struct_ret)
1230 call->used_iregs |= 1 << cinfo->struct_ret;
1232 for (i = 0; i < n; ++i) {
1233 ArgInfo *ainfo = cinfo->args + i;
1236 if (i >= sig->hasthis)
1237 t = sig->params [i - sig->hasthis];
1239 t = &mono_defaults.int_class->byval_arg;
1240 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1242 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1243 emit_sig_cookie (cfg, call, cinfo);
1244 if (is_virtual && i == 0) {
1245 /* the argument will be attached to the call instrucion */
1246 in = call->args [i];
1247 call->used_iregs |= 1 << ainfo->reg;
1250 in = call->args [i];
1251 if (ainfo->regtype == RegTypeGeneral) {
1252 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1253 MONO_INST_NEW (cfg, ins, OP_MOVE);
1254 ins->dreg = mono_alloc_ireg (cfg);
1255 ins->sreg1 = in->dreg + 1;
1256 MONO_ADD_INS (cfg->cbb, ins);
1257 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1259 MONO_INST_NEW (cfg, ins, OP_MOVE);
1260 ins->dreg = mono_alloc_ireg (cfg);
1261 ins->sreg1 = in->dreg + 2;
1262 MONO_ADD_INS (cfg->cbb, ins);
1263 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1264 } else if (!t->byref && (t->type == MONO_TYPE_R4)) {
1265 /* trying to load float value into int registers */
1266 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1267 ins->dreg = mono_alloc_ireg (cfg);
1268 ins->sreg1 = in->dreg;
1269 MONO_ADD_INS (cfg->cbb, ins);
1270 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1271 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1272 /* trying to load float value into int registers */
1273 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1274 ins->dreg = mono_alloc_ireg (cfg);
1275 ins->sreg1 = in->dreg;
1276 MONO_ADD_INS (cfg->cbb, ins);
1277 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1279 MONO_INST_NEW (cfg, ins, OP_MOVE);
1280 ins->dreg = mono_alloc_ireg (cfg);
1281 ins->sreg1 = in->dreg;
1282 MONO_ADD_INS (cfg->cbb, ins);
1283 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1285 } else if (ainfo->regtype == RegTypeStructByAddr) {
1286 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1287 ins->opcode = OP_OUTARG_VT;
1288 ins->sreg1 = in->dreg;
1289 ins->klass = in->klass;
1290 ins->inst_p0 = call;
1291 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1292 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1293 MONO_ADD_INS (cfg->cbb, ins);
1294 } else if (ainfo->regtype == RegTypeStructByVal) {
1295 /* this is further handled in mono_arch_emit_outarg_vt () */
1296 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1297 ins->opcode = OP_OUTARG_VT;
1298 ins->sreg1 = in->dreg;
1299 ins->klass = in->klass;
1300 ins->inst_p0 = call;
1301 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1302 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1303 MONO_ADD_INS (cfg->cbb, ins);
1304 } else if (ainfo->regtype == RegTypeBase) {
1305 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1306 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1307 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1308 if (t->type == MONO_TYPE_R8)
1309 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1311 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1313 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1315 } else if (ainfo->regtype == RegTypeFP) {
1316 if (t->type == MONO_TYPE_VALUETYPE) {
1317 /* this is further handled in mono_arch_emit_outarg_vt () */
1318 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1319 ins->opcode = OP_OUTARG_VT;
1320 ins->sreg1 = in->dreg;
1321 ins->klass = in->klass;
1322 ins->inst_p0 = call;
1323 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1324 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1325 MONO_ADD_INS (cfg->cbb, ins);
1327 cfg->flags |= MONO_CFG_HAS_FPOUT;
1329 int dreg = mono_alloc_freg (cfg);
1331 if (ainfo->size == 4) {
1332 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1334 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1336 ins->sreg1 = in->dreg;
1337 MONO_ADD_INS (cfg->cbb, ins);
1340 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1341 cfg->flags |= MONO_CFG_HAS_FPOUT;
1344 g_assert_not_reached ();
1348 /* Emit the signature cookie in the case that there is no
1349 additional argument */
1350 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1351 emit_sig_cookie (cfg, call, cinfo);
1353 if (cinfo->struct_ret) {
1356 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1357 vtarg->sreg1 = call->vret_var->dreg;
1358 vtarg->dreg = mono_alloc_preg (cfg);
1359 MONO_ADD_INS (cfg->cbb, vtarg);
1361 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1365 * Reverse the call->out_args list.
1368 MonoInst *prev = NULL, *list = call->out_args, *next;
1375 call->out_args = prev;
1378 call->stack_usage = cinfo->stack_usage;
1379 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1380 cfg->param_area = MAX (cfg->param_area, 16); /* a0-a3 always present */
1381 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1382 cfg->flags |= MONO_CFG_HAS_CALLS;
1384 * should set more info in call, such as the stack space
1385 * used by the args that needs to be added back to esp
1392 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1394 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1395 ArgInfo *ainfo = ins->inst_p1;
1396 int ovf_size = ainfo->vtsize;
1397 int doffset = ainfo->offset;
1398 int i, soffset, dreg;
1400 if (ainfo->regtype == RegTypeStructByVal) {
1403 for (i = 0; i < ainfo->size; ++i) {
1404 dreg = mono_alloc_ireg (cfg);
1405 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1406 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1407 soffset += sizeof (gpointer);
1410 mini_emit_memcpy (cfg, mips_at, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1411 } else if (ainfo->regtype == RegTypeFP) {
1412 int tmpr = mono_alloc_freg (cfg);
1413 if (ainfo->size == 4)
1414 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1416 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1417 dreg = mono_alloc_freg (cfg);
1418 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1419 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1421 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1425 /* FIXME: alignment? */
1426 if (call->signature->pinvoke) {
1427 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1428 vtcopy->backend.is_pinvoke = 1;
1430 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1433 g_assert (ovf_size > 0);
1435 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1436 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1439 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1441 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1446 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1448 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1449 mono_method_signature (method)->ret);
1452 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1455 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1456 ins->sreg1 = val->dreg + 1;
1457 ins->sreg2 = val->dreg + 2;
1458 MONO_ADD_INS (cfg->cbb, ins);
1461 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1462 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1466 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1469 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) || ((ins)->opcode == OP_ICOMPARE)))
1470 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) || ((ins)->opcode == OP_ICOMPARE_IMM)))
1471 #define ins_rewrite(ins, op, s1, s2) do { \
1472 ins->opcode = (op); \
1473 ins->sreg1 = (s1); \
1474 ins->sreg2 = (s2); \
1478 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1480 MonoInst *ins, *n, *last_ins = NULL;
1484 if (cfg->verbose_level > 2)
1485 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1488 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1489 if (cfg->verbose_level > 2)
1490 mono_print_ins_index (0, ins);
1492 switch (ins->opcode) {
1495 if (ins->opcode == OP_IBEQ)
1497 else if (ins->opcode == OP_IBNE_UN)
1500 g_assert_not_reached ();
1501 g_assert (ins_is_compare(last_ins));
1502 ins_rewrite(ins, op, last_ins->sreg1, last_ins->sreg2);
1503 MONO_DELETE_INS(bb, last_ins);
1507 g_assert (ins_is_compare(last_ins));
1508 last_ins->opcode = OP_MIPS_SLT;
1509 last_ins->dreg = mips_at;
1510 ins_rewrite(ins, OP_MIPS_BNE, mips_at, mips_zero);
1514 g_assert (ins_is_compare(last_ins));
1515 last_ins->opcode = OP_MIPS_SLTU;
1516 last_ins->dreg = mips_at;
1517 ins_rewrite(ins, OP_MIPS_BNE, mips_at, mips_zero);
1521 g_assert (ins_is_compare(last_ins));
1522 ins_rewrite(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
1523 last_ins->dreg = mips_at;
1524 ins_rewrite(ins, OP_MIPS_BNE, mips_at, mips_zero);
1528 g_assert (ins_is_compare(last_ins));
1529 ins_rewrite(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
1530 last_ins->dreg = mips_at;
1531 ins_rewrite(ins, OP_MIPS_BNE, mips_at, mips_zero);
1535 g_assert (ins_is_compare(last_ins));
1536 ins_rewrite(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
1537 last_ins->dreg = mips_at;
1538 ins_rewrite(ins, OP_MIPS_BEQ, mips_at, mips_zero);
1542 g_assert (ins_is_compare(last_ins));
1543 ins_rewrite(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
1544 last_ins->dreg = mips_at;
1545 ins_rewrite(ins, OP_MIPS_BEQ, mips_at, mips_zero);
1549 g_assert (ins_is_compare(last_ins));
1550 ins_rewrite(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
1551 last_ins->dreg = mips_at;
1552 ins_rewrite(ins, OP_MIPS_BNE, mips_at, mips_zero);
1556 g_assert (ins_is_compare(last_ins));
1557 ins_rewrite(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
1558 last_ins->dreg = mips_at;
1559 ins_rewrite(ins, OP_MIPS_BNE, mips_at, mips_zero);
1564 g_assert (ins_is_compare(last_ins));
1565 last_ins->opcode = OP_IXOR;
1566 last_ins->dreg = mono_alloc_ireg(cfg);
1567 ins_rewrite(ins, OP_MIPS_SLTIU, last_ins->dreg, mips_zero);
1572 g_assert_not_reached ();
1577 g_assert_not_reached ();
1582 g_assert (ins_is_compare(last_ins));
1583 ins_rewrite(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
1584 MONO_DELETE_INS(bb, last_ins);
1589 g_assert (ins_is_compare(last_ins));
1590 ins_rewrite(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
1591 MONO_DELETE_INS(bb, last_ins);
1594 case OP_COND_EXC_NE_UN:
1595 g_assert (ins_is_compare(last_ins));
1596 ins_rewrite(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
1597 MONO_DELETE_INS(bb, last_ins);
1600 case OP_COND_EXC_LE_UN:
1601 g_assert (ins_is_compare(last_ins));
1602 ins_rewrite(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
1603 MONO_DELETE_INS(bb, last_ins);
1609 bb->last_ins = last_ins;
1613 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1615 MonoInst *ins, *n, *last_ins = NULL;
1618 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1619 MonoInst *last_ins = ins->prev;
1621 switch (ins->opcode) {
1623 /* remove unnecessary multiplication with 1 */
1624 if (ins->inst_imm == 1) {
1625 if (ins->dreg != ins->sreg1) {
1626 ins->opcode = OP_MOVE;
1628 MONO_DELETE_INS (bb, ins);
1632 int power2 = mono_is_power_of_two (ins->inst_imm);
1634 ins->opcode = OP_SHL_IMM;
1635 ins->inst_imm = power2;
1639 case OP_LOAD_MEMBASE:
1640 case OP_LOADI4_MEMBASE:
1642 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1643 * OP_LOAD_MEMBASE offset(basereg), reg
1645 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1646 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1647 ins->inst_basereg == last_ins->inst_destbasereg &&
1648 ins->inst_offset == last_ins->inst_offset) {
1649 if (ins->dreg == last_ins->sreg1) {
1650 MONO_DELETE_INS (bb, ins);
1653 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1654 ins->opcode = OP_MOVE;
1655 ins->sreg1 = last_ins->sreg1;
1660 * Note: reg1 must be different from the basereg in the second load
1661 * OP_LOAD_MEMBASE offset(basereg), reg1
1662 * OP_LOAD_MEMBASE offset(basereg), reg2
1664 * OP_LOAD_MEMBASE offset(basereg), reg1
1665 * OP_MOVE reg1, reg2
1667 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1668 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1669 ins->inst_basereg != last_ins->dreg &&
1670 ins->inst_basereg == last_ins->inst_basereg &&
1671 ins->inst_offset == last_ins->inst_offset) {
1673 if (ins->dreg == last_ins->dreg) {
1674 MONO_DELETE_INS (bb, ins);
1677 ins->opcode = OP_MOVE;
1678 ins->sreg1 = last_ins->dreg;
1681 //g_assert_not_reached ();
1686 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1687 * OP_LOAD_MEMBASE offset(basereg), reg
1689 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1690 * OP_ICONST reg, imm
1692 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1693 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1694 ins->inst_basereg == last_ins->inst_destbasereg &&
1695 ins->inst_offset == last_ins->inst_offset) {
1696 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1697 ins->opcode = OP_ICONST;
1698 ins->inst_c0 = last_ins->inst_imm;
1699 g_assert_not_reached (); // check this rule
1704 case OP_LOADU1_MEMBASE:
1705 case OP_LOADI1_MEMBASE:
1706 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1707 ins->inst_basereg == last_ins->inst_destbasereg &&
1708 ins->inst_offset == last_ins->inst_offset) {
1709 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? CEE_CONV_I1 : CEE_CONV_U1;
1710 ins->sreg1 = last_ins->sreg1;
1713 case OP_LOADU2_MEMBASE:
1714 case OP_LOADI2_MEMBASE:
1715 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1716 ins->inst_basereg == last_ins->inst_destbasereg &&
1717 ins->inst_offset == last_ins->inst_offset) {
1718 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? CEE_CONV_I2 : CEE_CONV_U2;
1719 ins->sreg1 = last_ins->sreg1;
1725 ins->opcode = OP_MOVE;
1729 if (ins->dreg == ins->sreg1) {
1730 MONO_DELETE_INS (bb, ins);
1734 * OP_MOVE sreg, dreg
1735 * OP_MOVE dreg, sreg
1737 if (last_ins && last_ins->opcode == OP_MOVE &&
1738 ins->sreg1 == last_ins->dreg &&
1739 ins->dreg == last_ins->sreg1) {
1740 MONO_DELETE_INS (bb, ins);
1748 bb->last_ins = last_ins;
1752 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
1754 switch (ins->opcode) {
1755 case OP_ICONV_TO_R_UN: {
1756 static const guint64 adjust_val = 0x4330000000000000ULL;
1757 int msw_reg = mono_alloc_ireg (cfg);
1758 int adj_reg = mono_alloc_freg (cfg);
1759 int tmp_reg = mono_alloc_freg (cfg);
1760 int basereg = mips_sp;
1763 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
1764 if (!mips_is_imm16 (offset + 4)) {
1765 basereg = mono_alloc_ireg (cfg);
1766 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
1768 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
1769 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
1770 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
1771 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
1772 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
1773 ins->opcode = OP_NOP;
1776 case OP_ICONV_TO_R4:
1777 case OP_ICONV_TO_R8: {
1778 /* FIXME: change precision for CEE_CONV_R4 */
1779 static const guint64 adjust_val = 0x4330000080000000ULL;
1780 int msw_reg = mono_alloc_ireg (cfg);
1781 int xored = mono_alloc_ireg (cfg);
1782 int adj_reg = mono_alloc_freg (cfg);
1783 int tmp_reg = mono_alloc_freg (cfg);
1784 int basereg = mips_sp;
1787 if (!mips_is_imm16 (offset + 4)) {
1788 basereg = mono_alloc_ireg (cfg);
1789 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
1791 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
1792 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
1793 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
1794 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
1795 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
1796 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
1797 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
1798 if (ins->opcode == OP_ICONV_TO_R4)
1799 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
1800 ins->opcode = OP_NOP;
1805 int msw_reg = mono_alloc_ireg (cfg);
1806 int basereg = mips_sp;
1809 if (!mips_is_imm16 (offset + 4)) {
1810 basereg = mono_alloc_ireg (cfg);
1811 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
1813 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
1814 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
1815 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
1816 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1817 ins->opcode = OP_NOP;
1825 #define NEW_INS(cfg,dest,op) do { \
1826 MONO_INST_NEW((cfg), (dest), (op)); \
1827 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
1831 map_to_reg_reg_op (int op)
1840 case OP_COMPARE_IMM:
1842 case OP_ICOMPARE_IMM:
1858 case OP_LOAD_MEMBASE:
1859 return OP_LOAD_MEMINDEX;
1860 case OP_LOADI4_MEMBASE:
1861 return OP_LOADI4_MEMINDEX;
1862 case OP_LOADU4_MEMBASE:
1863 return OP_LOADU4_MEMINDEX;
1864 case OP_LOADU1_MEMBASE:
1865 return OP_LOADU1_MEMINDEX;
1866 case OP_LOADI2_MEMBASE:
1867 return OP_LOADI2_MEMINDEX;
1868 case OP_LOADU2_MEMBASE:
1869 return OP_LOADU2_MEMINDEX;
1870 case OP_LOADI1_MEMBASE:
1871 return OP_LOADI1_MEMINDEX;
1872 case OP_LOADR4_MEMBASE:
1873 return OP_LOADR4_MEMINDEX;
1874 case OP_LOADR8_MEMBASE:
1875 return OP_LOADR8_MEMINDEX;
1876 case OP_STOREI1_MEMBASE_REG:
1877 return OP_STOREI1_MEMINDEX;
1878 case OP_STOREI2_MEMBASE_REG:
1879 return OP_STOREI2_MEMINDEX;
1880 case OP_STOREI4_MEMBASE_REG:
1881 return OP_STOREI4_MEMINDEX;
1882 case OP_STORE_MEMBASE_REG:
1883 return OP_STORE_MEMINDEX;
1884 case OP_STORER4_MEMBASE_REG:
1885 return OP_STORER4_MEMINDEX;
1886 case OP_STORER8_MEMBASE_REG:
1887 return OP_STORER8_MEMINDEX;
1888 case OP_STORE_MEMBASE_IMM:
1889 return OP_STORE_MEMBASE_REG;
1890 case OP_STOREI1_MEMBASE_IMM:
1891 return OP_STOREI1_MEMBASE_REG;
1892 case OP_STOREI2_MEMBASE_IMM:
1893 return OP_STOREI2_MEMBASE_REG;
1894 case OP_STOREI4_MEMBASE_IMM:
1895 return OP_STOREI4_MEMBASE_REG;
1897 g_assert_not_reached ();
1901 * Remove from the instruction list the instructions that can't be
1902 * represented with very simple instructions with no register
1906 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1908 MonoInst *ins, *next, *temp, *last_ins = NULL;
1912 MONO_BB_FOR_EACH_INS (bb, ins) {
1914 switch (ins->opcode) {
1915 case OP_COMPARE_IMM:
1916 case OP_ICOMPARE_IMM:
1918 /* Branch opts can eliminate the branch */
1919 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
1920 ins->opcode = OP_NOP;
1923 if (ins->inst_imm) {
1924 NEW_INS (cfg, temp, OP_ICONST);
1925 temp->inst_c0 = ins->inst_imm;
1926 temp->dreg = mono_alloc_ireg (cfg);
1927 ins->sreg2 = temp->dreg;
1931 ins->sreg2 = mips_zero;
1933 if (ins->opcode == OP_COMPARE_IMM)
1934 ins->opcode = OP_COMPARE;
1935 else if (ins->opcode == OP_ICOMPARE_IMM)
1936 ins->opcode = OP_ICOMPARE;
1939 case OP_IDIV_UN_IMM:
1942 case OP_IREM_UN_IMM:
1943 NEW_INS (cfg, temp, OP_ICONST);
1944 temp->inst_c0 = ins->inst_imm;
1945 temp->dreg = mono_alloc_ireg (cfg);
1946 ins->sreg2 = temp->dreg;
1947 if (ins->opcode == OP_IDIV_IMM)
1948 ins->opcode = OP_IDIV;
1949 else if (ins->opcode == OP_IREM_IMM)
1950 ins->opcode = OP_IREM;
1951 else if (ins->opcode == OP_IDIV_UN_IMM)
1952 ins->opcode = OP_IDIV_UN;
1953 else if (ins->opcode == OP_IREM_UN_IMM)
1954 ins->opcode = OP_IREM_UN;
1956 /* handle rem separately */
1961 if (!mips_is_imm16 (ins->inst_imm)) {
1962 NEW_INS (cfg, temp, OP_ICONST);
1963 temp->inst_c0 = ins->inst_imm;
1964 temp->dreg = mono_alloc_ireg (cfg);
1965 ins->sreg2 = temp->dreg;
1966 ins->opcode = map_to_reg_reg_op (ins->opcode);
1972 /* Branch opts can eliminate the branch */
1973 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
1974 ins->opcode = OP_NOP;
1980 * remap compare/branch and compare/set
1981 * to MIPS specific opcodes.
1984 switch (next->opcode) {
2001 ins->opcode = OP_NOP;
2002 next->sreg1 = ins->sreg1;
2003 next->sreg2 = ins->sreg2;
2007 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (next->opcode), __FUNCTION__);
2008 g_assert_not_reached ();
2013 if (!mips_is_imm16 (-ins->inst_imm)) {
2014 NEW_INS (cfg, temp, OP_ICONST);
2015 temp->inst_c0 = ins->inst_imm;
2016 temp->dreg = mono_alloc_ireg (cfg);
2017 ins->sreg2 = temp->dreg;
2018 ins->opcode = map_to_reg_reg_op (ins->opcode);
2025 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2026 NEW_INS (cfg, temp, OP_ICONST);
2027 temp->inst_c0 = ins->inst_imm;
2028 temp->dreg = mono_alloc_ireg (cfg);
2029 ins->sreg2 = temp->dreg;
2030 ins->opcode = map_to_reg_reg_op (ins->opcode);
2037 NEW_INS (cfg, temp, OP_ICONST);
2038 temp->inst_c0 = ins->inst_imm;
2039 temp->dreg = mono_alloc_ireg (cfg);
2040 ins->sreg2 = temp->dreg;
2041 ins->opcode = map_to_reg_reg_op (ins->opcode);
2045 if (ins->inst_imm == 1) {
2046 ins->opcode = OP_MOVE;
2049 if (ins->inst_imm == 0) {
2050 ins->opcode = OP_ICONST;
2054 imm = mono_is_power_of_two (ins->inst_imm);
2056 ins->opcode = OP_SHL_IMM;
2057 ins->inst_imm = imm;
2060 if (!mips_is_imm16 (ins->inst_imm)) {
2061 NEW_INS (cfg, temp, OP_ICONST);
2062 temp->inst_c0 = ins->inst_imm;
2063 temp->dreg = mono_alloc_ireg (cfg);
2064 ins->sreg2 = temp->dreg;
2065 ins->opcode = map_to_reg_reg_op (ins->opcode);
2069 case OP_LOAD_MEMBASE:
2070 case OP_LOADI4_MEMBASE:
2071 case OP_LOADU4_MEMBASE:
2072 case OP_LOADI2_MEMBASE:
2073 case OP_LOADU2_MEMBASE:
2074 case OP_LOADI1_MEMBASE:
2075 case OP_LOADU1_MEMBASE:
2076 case OP_LOADR4_MEMBASE:
2077 case OP_LOADR8_MEMBASE:
2078 case OP_STORE_MEMBASE_REG:
2079 case OP_STOREI4_MEMBASE_REG:
2080 case OP_STOREI2_MEMBASE_REG:
2081 case OP_STOREI1_MEMBASE_REG:
2082 case OP_STORER4_MEMBASE_REG:
2083 case OP_STORER8_MEMBASE_REG:
2084 /* we can do two things: load the immed in a register
2085 * and use an indexed load, or see if the immed can be
2086 * represented as an ad_imm + a load with a smaller offset
2087 * that fits. We just do the first for now, optimize later.
2089 if (mips_is_imm16 (ins->inst_offset))
2091 NEW_INS (cfg, temp, OP_ICONST);
2092 temp->inst_c0 = ins->inst_offset;
2093 temp->dreg = mono_alloc_ireg (cfg);
2094 ins->sreg2 = temp->dreg;
2095 ins->opcode = map_to_reg_reg_op (ins->opcode);
2098 case OP_STORE_MEMBASE_IMM:
2099 case OP_STOREI1_MEMBASE_IMM:
2100 case OP_STOREI2_MEMBASE_IMM:
2101 case OP_STOREI4_MEMBASE_IMM:
2103 if (!ins->inst_imm) {
2104 ins->sreg1 = mips_zero;
2105 ins->opcode = map_to_reg_reg_op (ins->opcode);
2108 NEW_INS (cfg, temp, OP_ICONST);
2109 temp->inst_c0 = ins->inst_imm;
2110 temp->dreg = mono_alloc_ireg (cfg);
2111 ins->sreg1 = temp->dreg;
2112 ins->opcode = map_to_reg_reg_op (ins->opcode);
2114 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2118 NEW_INS (cfg, temp, OP_ICONST);
2119 temp->inst_c0 = (guint32)ins->inst_p0;
2120 temp->dreg = mono_alloc_ireg (cfg);
2121 ins->inst_basereg = temp->dreg;
2122 ins->inst_offset = 0;
2123 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2125 /* make it handle the possibly big ins->inst_offset
2126 * later optimize to use lis + load_membase
2133 bb->last_ins = last_ins;
2134 bb->max_vreg = cfg->next_vreg;
2138 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2140 /* sreg is a float, dreg is an integer reg. mips_at is used a scratch */
2142 mips_truncwd (code, mips_ftemp, sreg);
2144 mips_cvtwd (code, mips_ftemp, sreg);
2146 mips_mfc1 (code, dreg, mips_ftemp);
2149 mips_andi (code, dreg, dreg, 0xff);
2150 else if (size == 2) {
2151 mips_sll (code, dreg, dreg, 16);
2152 mips_srl (code, dreg, dreg, 16);
2156 mips_sll (code, dreg, dreg, 24);
2157 mips_sra (code, dreg, dreg, 24);
2159 else if (size == 2) {
2160 mips_sll (code, dreg, dreg, 16);
2161 mips_sra (code, dreg, dreg, 16);
2168 * emit_load_volatile_arguments:
2170 * Load volatile arguments from the stack to the original input registers.
2171 * Required before a tail call.
2174 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
2176 MonoMethod *method = cfg->method;
2177 MonoMethodSignature *sig;
2182 sig = mono_method_signature (method);
2183 cinfo = calculate_sizes (sig, sig->pinvoke);
2184 if (cinfo->struct_ret) {
2185 ArgInfo *ainfo = &cinfo->ret;
2186 inst = cfg->vret_addr;
2187 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2190 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2191 ArgInfo *ainfo = cinfo->args + i;
2192 inst = cfg->args [i];
2193 if (inst->opcode == OP_REGVAR) {
2194 if (ainfo->regtype == RegTypeGeneral)
2195 mips_move (code, ainfo->reg, inst->dreg);
2196 else if (ainfo->regtype == RegTypeFP)
2197 g_assert_not_reached();
2198 else if (ainfo->regtype == RegTypeBase) {
2201 g_assert_not_reached ();
2203 if (ainfo->regtype == RegTypeGeneral) {
2204 g_assert (mips_is_imm16 (inst->inst_offset));
2205 switch (ainfo->size) {
2207 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2210 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2214 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2217 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2218 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
2221 g_assert_not_reached ();
2224 } else if (ainfo->regtype == RegTypeBase) {
2226 } else if (ainfo->regtype == RegTypeFP) {
2227 g_assert (mips_is_imm16 (inst->inst_offset));
2228 if (ainfo->size == 8)
2229 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2230 else if (ainfo->size == 4)
2231 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2233 g_assert_not_reached ();
2234 } else if (ainfo->regtype == RegTypeStructByVal) {
2236 int doffset = inst->inst_offset;
2238 g_assert (mips_is_imm16 (inst->inst_offset));
2239 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
2240 for (i = 0; i < ainfo->size; ++i) {
2241 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
2242 doffset += sizeof (gpointer);
2244 } else if (ainfo->regtype == RegTypeStructByAddr) {
2245 g_assert (mips_is_imm16 (inst->inst_offset));
2246 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2248 g_assert_not_reached ();
2258 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
2260 int size = cfg->param_area;
2262 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
2263 size &= -MONO_ARCH_FRAME_ALIGNMENT;
2268 ppc_lwz (code, ppc_r0, 0, ppc_sp);
2269 if (ppc_is_imm16 (-size)) {
2270 ppc_stwu (code, ppc_r0, -size, ppc_sp);
2272 ppc_load (code, ppc_r11, -size);
2273 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
2280 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
2282 int size = cfg->param_area;
2284 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
2285 size &= -MONO_ARCH_FRAME_ALIGNMENT;
2290 ppc_lwz (code, ppc_r0, 0, ppc_sp);
2291 if (ppc_is_imm16 (size)) {
2292 ppc_stwu (code, ppc_r0, size, ppc_sp);
2294 ppc_load (code, ppc_r11, size);
2295 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
2302 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2307 guint8 *code = cfg->native_code + cfg->code_len;
2308 MonoInst *last_ins = NULL;
2309 guint last_offset = 0;
2313 /* we don't align basic blocks of loops on mips */
2315 if (cfg->verbose_level > 2)
2316 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2318 cpos = bb->max_offset;
2321 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2322 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2323 g_assert (!mono_compile_aot);
2326 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2327 /* this is not thread save, but good enough */
2328 /* fixme: howto handle overflows? */
2329 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
2330 mips_lw (code, mips_temp, mips_at, 0);
2331 mips_addiu (code, mips_temp, mips_temp, 1);
2332 mips_sw (code, mips_temp, mips_at, 0);
2335 MONO_BB_FOR_EACH_INS (bb, ins) {
2336 offset = code - cfg->native_code;
2338 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2340 if (offset > (cfg->code_size - max_len - 16)) {
2341 cfg->code_size *= 2;
2342 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2343 code = cfg->native_code + offset;
2345 mono_debug_record_line_number (cfg, ins, offset);
2346 if (cfg->verbose_level > 2) {
2347 g_print (" @ 0x%x\t", offset);
2348 mono_print_ins_index (ins_cnt++, ins);
2350 /* Check for virtual regs that snuck by */
2351 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
2353 switch (ins->opcode) {
2354 case OP_RELAXED_NOP:
2357 case OP_DUMMY_STORE:
2358 case OP_NOT_REACHED:
2362 g_assert_not_reached();
2364 emit_tls_access (code, ins->dreg, ins->inst_offset);
2368 mips_mult (code, ins->sreg1, ins->sreg2);
2369 mips_mflo (code, ins->dreg);
2370 mips_mfhi (code, ins->dreg+1);
2373 mips_multu (code, ins->sreg1, ins->sreg2);
2374 mips_mflo (code, ins->dreg);
2375 mips_mfhi (code, ins->dreg+1);
2377 case OP_MEMORY_BARRIER:
2382 case OP_STOREI1_MEMBASE_IMM:
2383 mips_load_const (code, mips_temp, ins->inst_imm);
2384 if (mips_is_imm16 (ins->inst_offset)) {
2385 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
2387 mips_load_const (code, mips_at, ins->inst_offset);
2388 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
2391 case OP_STOREI2_MEMBASE_IMM:
2392 mips_load_const (code, mips_temp, ins->inst_imm);
2393 if (mips_is_imm16 (ins->inst_offset)) {
2394 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
2396 mips_load_const (code, mips_at, ins->inst_offset);
2397 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
2400 case OP_STORE_MEMBASE_IMM:
2401 case OP_STOREI4_MEMBASE_IMM:
2402 mips_load_const (code, mips_temp, ins->inst_imm);
2403 if (mips_is_imm16 (ins->inst_offset)) {
2404 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
2406 mips_load_const (code, mips_at, ins->inst_offset);
2407 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
2410 case OP_STOREI1_MEMBASE_REG:
2411 if (mips_is_imm16 (ins->inst_offset)) {
2412 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2414 mips_load_const (code, mips_at, ins->inst_offset);
2415 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
2416 mips_sb (code, ins->sreg1, mips_at, 0);
2419 case OP_STOREI2_MEMBASE_REG:
2420 if (mips_is_imm16 (ins->inst_offset)) {
2421 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2423 mips_load_const (code, mips_at, ins->inst_offset);
2424 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
2425 mips_sh (code, ins->sreg1, mips_at, 0);
2428 case OP_STORE_MEMBASE_REG:
2429 case OP_STOREI4_MEMBASE_REG:
2430 if (mips_is_imm16 (ins->inst_offset)) {
2431 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2433 mips_load_const (code, mips_at, ins->inst_offset);
2434 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
2435 mips_sw (code, ins->sreg1, mips_at, 0);
2439 g_assert_not_reached ();
2440 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
2441 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
2443 case OP_LOAD_MEMBASE:
2444 case OP_LOADI4_MEMBASE:
2445 case OP_LOADU4_MEMBASE:
2446 if (mips_is_imm16 (ins->inst_offset)) {
2447 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2449 mips_load_const (code, mips_at, ins->inst_offset);
2450 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2451 mips_lw (code, ins->dreg, mips_at, 0);
2454 case OP_LOADI1_MEMBASE:
2455 if (mips_is_imm16 (ins->inst_offset)) {
2456 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2458 mips_load_const (code, mips_at, ins->inst_offset);
2459 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2460 mips_lb (code, ins->dreg, mips_at, 0);
2463 case OP_LOADU1_MEMBASE:
2464 if (mips_is_imm16 (ins->inst_offset)) {
2465 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2467 mips_load_const (code, mips_at, ins->inst_offset);
2468 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2469 mips_lbu (code, ins->dreg, mips_at, 0);
2472 case OP_LOADI2_MEMBASE:
2473 if (mips_is_imm16 (ins->inst_offset)) {
2474 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2476 mips_load_const (code, mips_at, ins->inst_offset);
2477 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2478 mips_lh (code, ins->dreg, mips_at, 0);
2481 case OP_LOADU2_MEMBASE:
2482 if (mips_is_imm16 (ins->inst_offset)) {
2483 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2485 mips_load_const (code, mips_at, ins->inst_offset);
2486 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2487 mips_lhu (code, ins->dreg, mips_at, 0);
2491 mips_sll (code, mips_at, ins->sreg1, 24);
2492 mips_sra (code, ins->dreg, mips_at, 24);
2495 mips_sll (code, mips_at, ins->sreg1, 16);
2496 mips_sra (code, ins->dreg, mips_at, 16);
2499 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
2502 mips_sll (code, mips_at, ins->sreg1, 16);
2503 mips_srl (code, ins->dreg, mips_at, 16);
2506 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
2509 g_assert (mips_is_imm16 (ins->inst_imm));
2510 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
2513 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
2516 g_assert (mips_is_imm16 (ins->inst_imm));
2517 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
2519 case OP_COMPARE_IMM:
2520 g_assert_not_reached ();
2523 g_assert_not_reached ();
2526 mips_break (code, 0xfd);
2529 g_assert_not_reached ();
2532 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
2535 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
2538 g_assert_not_reached ();
2541 g_assert_not_reached ();
2545 if (mips_is_imm16 (ins->inst_imm)) {
2546 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
2548 mips_load_const (code, mips_at, ins->inst_imm);
2549 mips_addu (code, ins->dreg, ins->sreg1, mips_at);
2553 g_assert_not_reached ();
2556 /* rewritten in .brg file */
2557 g_assert_not_reached ();
2559 case CEE_ADD_OVF_UN:
2560 /* rewritten in .brg file */
2561 g_assert_not_reached ();
2564 /* rewritten in .brg file */
2565 g_assert_not_reached ();
2567 case CEE_SUB_OVF_UN:
2568 /* rewritten in .brg file */
2569 g_assert_not_reached ();
2571 case OP_ADD_OVF_CARRY:
2572 /* rewritten in .brg file */
2573 g_assert_not_reached ();
2575 case OP_ADD_OVF_UN_CARRY:
2576 /* rewritten in .brg file */
2577 g_assert_not_reached ();
2579 case OP_SUB_OVF_CARRY:
2580 /* rewritten in .brg file */
2581 g_assert_not_reached ();
2583 case OP_SUB_OVF_UN_CARRY:
2584 /* rewritten in .brg file */
2585 g_assert_not_reached ();
2589 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
2592 /* rewritten in .brg file */
2593 g_assert_not_reached ();
2596 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
2600 // we add the negated value
2601 if (mips_is_imm16 (-ins->inst_imm))
2602 mips_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2604 mips_load_const (code, mips_at, ins->inst_imm);
2605 mips_subu (code, ins->dreg, ins->sreg1, mips_at);
2610 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
2613 g_assert_not_reached ();
2616 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2620 if (mips_is_imm16 (ins->inst_imm)) {
2621 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2623 mips_load_const (code, mips_at, ins->inst_imm);
2624 mips_and (code, ins->dreg, ins->sreg1, mips_at);
2629 guint32 *divisor_is_m1;
2630 guint32 *divisor_is_zero;
2633 mips_addiu (code, mips_at, mips_zero, 0xffff);
2634 divisor_is_m1 = (guint32 *)code;
2635 mips_bne (code, ins->sreg2, mips_at, 0);
2638 /* Divide by -1 -- throw exception */
2639 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
2641 mips_patch (divisor_is_m1, (guint32)code);
2643 /* Put divide in branch delay slot (NOT YET) */
2644 divisor_is_zero = (guint32 *)code;
2645 mips_bne (code, ins->sreg2, mips_zero, 0);
2648 /* Divide by zero -- throw exception */
2649 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2651 mips_patch (divisor_is_zero, (guint32)code);
2652 mips_div (code, ins->sreg1, ins->sreg2);
2653 if (ins->opcode == OP_IDIV)
2654 mips_mflo (code, ins->dreg);
2656 mips_mfhi (code, ins->dreg);
2660 guint32 *divisor_is_zero = (guint32 *)(void *)code;
2662 /* Put divide in branch delay slot (NOT YET) */
2663 mips_bne (code, ins->sreg2, mips_zero, 0);
2666 /* Divide by zero -- throw exception */
2667 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2669 mips_patch (divisor_is_zero, (guint32)code);
2670 mips_divu (code, ins->sreg1, ins->sreg2);
2671 mips_mflo (code, ins->dreg);
2675 g_assert_not_reached ();
2677 ppc_load (code, ppc_r11, ins->inst_imm);
2678 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
2679 ppc_mfspr (code, ppc_r0, ppc_xer);
2680 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2681 /* FIXME: use OverflowException for 0x80000000/-1 */
2682 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2684 g_assert_not_reached();
2687 guint32 *divisor_is_zero = (guint32 *)(void *)code;
2689 /* Put divide in branch delay slot (NOT YET) */
2690 mips_bne (code, ins->sreg2, mips_zero, 0);
2693 /* Divide by zero -- throw exception */
2694 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2696 mips_patch (divisor_is_zero, (guint32)code);
2697 mips_divu (code, ins->sreg1, ins->sreg2);
2698 mips_mfhi (code, ins->dreg);
2702 g_assert_not_reached ();
2704 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2707 if (mips_is_imm16 (ins->inst_imm)) {
2708 mips_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2710 mips_load_const (code, mips_at, ins->inst_imm);
2711 mips_or (code, ins->dreg, ins->sreg1, mips_at);
2715 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2719 /* unsigned 16-bit immediate */
2720 if ((ins->inst_imm & 0xffff) == ins->inst_imm) {
2721 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
2723 mips_load_const (code, mips_at, ins->inst_imm);
2724 mips_xor (code, ins->dreg, ins->sreg1, mips_at);
2728 g_assert (mips_is_imm16 (ins->inst_imm));
2729 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
2732 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
2736 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2739 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
2743 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2746 case OP_ISHR_UN_IMM:
2747 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2750 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
2753 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
2756 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
2760 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
2762 mips_mult (code, ins->sreg1, ins->sreg2);
2763 mips_mflo (code, ins->dreg);
2770 mips_load_const (code, mips_at, ins->inst_imm);
2772 mips_mul (code, ins->dreg, ins->sreg1, mips_at);
2774 mips_mult (code, ins->sreg1, mips_at);
2775 mips_mflo (code, ins->dreg);
2782 mips_mult (code, ins->sreg1, ins->sreg2);
2783 mips_mflo (code, ins->dreg);
2784 mips_mfhi (code, mips_at);
2787 mips_sra (code, mips_temp, ins->dreg, 31);
2788 patch = (guint32 *)(void *)code;
2789 mips_beq (code, mips_temp, mips_at, 0);
2791 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
2792 mips_patch (patch, (guint32)code);
2795 case CEE_MUL_OVF_UN:
2797 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
2799 mips_mult (code, ins->sreg1, ins->sreg2);
2800 mips_mflo (code, ins->dreg);
2801 mips_mfhi (code, mips_at);
2805 /* XXX - Throw exception if we overflowed */
2808 mips_load_const (code, ins->dreg, ins->inst_c0);
2811 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2812 mips_load (code, ins->dreg, 0);
2816 mips_mtc1 (code, ins->dreg, ins->sreg1);
2819 mips_mfc1 (code, ins->dreg, ins->sreg1);
2822 mips_dmtc1 (code, ins->dreg, ins->sreg1);
2825 mips_dmfc1 (code, ins->dreg, ins->sreg1);
2831 if (ins->dreg != ins->sreg1)
2832 mips_move (code, ins->dreg, ins->sreg1);
2835 /* Get sreg1 into v1, sreg2 into v0 */
2837 if (ins->sreg1 == mips_v0) {
2838 if (ins->sreg1 != mips_at)
2839 mips_move (code, mips_at, ins->sreg1);
2840 if (ins->sreg2 != mips_v0)
2841 mips_move (code, mips_v0, ins->sreg2);
2842 mips_move (code, mips_v1, mips_at);
2845 if (ins->sreg2 != mips_v0)
2846 mips_move (code, mips_v0, ins->sreg2);
2847 if (ins->sreg1 != mips_v1)
2848 mips_move (code, mips_v1, ins->sreg1);
2852 if (ins->dreg != ins->sreg1) {
2853 mips_fmovd (code, ins->dreg, ins->sreg1);
2857 /* Convert from double to float and leave it there */
2858 mips_cvtsd (code, ins->dreg, ins->sreg1);
2860 case OP_FCONV_TO_R4:
2861 /* Convert from double to float and back again */
2862 mips_cvtsd (code, ins->dreg, ins->sreg1);
2863 mips_cvtds (code, ins->dreg, ins->dreg);
2866 code = emit_load_volatile_arguments(cfg, code);
2869 * Pop our stack, then jump to specified method (tail-call)
2870 * Keep in sync with mono_arch_emit_epilog
2872 code = mono_arch_emit_epilog_sub (cfg, code);
2874 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
2875 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2877 mips_lui (code, mips_t9, mips_zero, 0);
2878 mips_addiu (code, mips_t9, mips_t9, 0);
2879 mips_jr (code, mips_t9);
2882 mips_beq (code, mips_zero, mips_zero, 0);
2887 /* ensure ins->sreg1 is not NULL */
2888 mips_lw (code, mips_zero, ins->sreg1, 0);
2891 if (mips_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2892 mips_addiu (code, mips_at, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2894 mips_load_const (code, mips_at, cfg->sig_cookie + cfg->stack_usage);
2895 mips_addu (code, mips_at, cfg->frame_reg, mips_at);
2897 mips_sw (code, mips_at, ins->sreg1, 0);
2910 case OP_VOIDCALL_REG:
2912 case OP_FCALL_MEMBASE:
2913 case OP_LCALL_MEMBASE:
2914 case OP_VCALL_MEMBASE:
2915 case OP_VCALL2_MEMBASE:
2916 case OP_VOIDCALL_MEMBASE:
2917 case OP_CALL_MEMBASE:
2918 call = (MonoCallInst*)ins;
2919 switch (ins->opcode) {
2926 if (ins->flags & MONO_INST_HAS_METHOD)
2927 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2929 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2930 mips_lui (code, mips_t9, mips_zero, 0);
2931 mips_addiu (code, mips_t9, mips_t9, 0);
2937 case OP_VOIDCALL_REG:
2939 mips_move (code, mips_t9, ins->sreg1);
2941 case OP_FCALL_MEMBASE:
2942 case OP_LCALL_MEMBASE:
2943 case OP_VCALL_MEMBASE:
2944 case OP_VCALL2_MEMBASE:
2945 case OP_VOIDCALL_MEMBASE:
2946 case OP_CALL_MEMBASE:
2947 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
2950 mips_jalr (code, mips_t9, mips_ra);
2952 if ((ins->opcode == OP_FCALL ||
2953 ins->opcode == OP_FCALL_REG) &&
2954 call->signature->ret->type == MONO_TYPE_R4) {
2955 mips_cvtds (code, mips_f0, mips_f0);
2959 int area_offset = cfg->param_area;
2961 /* Round up ins->sreg1, mips_at ends up holding size */
2962 mips_addiu (code, mips_at, ins->sreg1, 31);
2963 mips_andi (code, mips_at, mips_at, ~31);
2965 mips_subu (code, mips_sp, mips_sp, mips_at);
2966 mips_addiu (code, ins->dreg, mips_sp, area_offset);
2968 if (ins->flags & MONO_INST_INIT) {
2969 mips_move (code, mips_temp, ins->dreg);
2970 mips_sb (code, mips_zero, mips_temp, 0);
2971 mips_addiu (code, mips_at, mips_at, -1);
2972 mips_bne (code, mips_at, mips_zero, -4);
2973 mips_addiu (code, mips_temp, mips_temp, 1);
2978 gpointer addr = mono_arch_get_throw_exception();
2979 mips_move (code, mips_a0, ins->sreg1);
2980 mips_load_const (code, mips_t9, addr);
2981 mips_jalr (code, mips_t9, mips_ra);
2983 mips_break (code, 0xfc);
2987 gpointer addr = mono_arch_get_rethrow_exception();
2988 mips_move (code, mips_a0, ins->sreg1);
2989 mips_load_const (code, mips_t9, addr);
2990 mips_jalr (code, mips_t9, mips_ra);
2992 mips_break (code, 0xfb);
2995 case OP_START_HANDLER: {
2997 * The START_HANDLER instruction marks the beginning of
2998 * a handler block. It is called using a call
2999 * instruction, so mips_ra contains the return address.
3000 * Since the handler executes in the same stack frame
3001 * as the method itself, we can't use save/restore to
3002 * save the return address. Instead, we save it into
3003 * a dedicated variable.
3005 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3006 g_assert (spvar->inst_basereg != mips_sp);
3007 code = emit_reserve_param_area (cfg, code);
3009 if (mips_is_imm16 (spvar->inst_offset)) {
3010 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3012 mips_load_const (code, mips_at, spvar->inst_offset);
3013 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3014 mips_sw (code, mips_ra, mips_at, 0);
3018 case OP_ENDFILTER: {
3019 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3020 g_assert (spvar->inst_basereg != mips_sp);
3021 code = emit_unreserve_param_area (cfg, code);
3023 if (ins->sreg1 != mips_v0)
3024 mips_move (code, mips_v0, ins->sreg1);
3025 if (mips_is_imm16 (spvar->inst_offset)) {
3026 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3028 mips_load_const (code, mips_at, spvar->inst_offset);
3029 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3030 mips_lw (code, mips_ra, mips_at, 0);
3032 mips_jr (code, mips_ra);
3036 case OP_ENDFINALLY: {
3037 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3038 g_assert (spvar->inst_basereg != mips_sp);
3039 code = emit_unreserve_param_area (cfg, code);
3040 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3041 mips_jalr (code, mips_t9, mips_ra);
3045 case OP_CALL_HANDLER:
3046 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3047 mips_lui (code, mips_t9, mips_zero, 0);
3048 mips_addiu (code, mips_t9, mips_t9, 0);
3049 mips_jalr (code, mips_t9, mips_ra);
3053 ins->inst_c0 = code - cfg->native_code;
3056 if (ins->flags & MONO_INST_BRLABEL) {
3057 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3059 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3062 mips_lui (code, mips_at, mips_zero, 0);
3063 mips_addiu (code, mips_at, mips_at, 0);
3064 mips_jr (code, mips_at);
3067 mips_beq (code, mips_zero, mips_zero, 0);
3072 mips_jr (code, ins->sreg1);
3078 max_len += 4 * GPOINTER_TO_INT (ins->klass);
3079 if (offset > (cfg->code_size - max_len - 16)) {
3080 cfg->code_size += max_len;
3081 cfg->code_size *= 2;
3082 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3083 code = cfg->native_code + offset;
3085 g_assert (ins->sreg1 != -1);
3086 mips_sll (code, mips_at, ins->sreg1, 2);
3087 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
3088 mips_move (code, mips_t8, mips_ra);
3089 mips_bgezal (code, mips_zero, 1); /* bal */
3091 mips_addu (code, mips_t9, mips_ra, mips_at);
3092 /* Table is 16 or 20 bytes from target of bal above */
3093 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
3094 mips_move (code, mips_ra, mips_t8);
3095 mips_lw (code, mips_t9, mips_t9, 20);
3098 mips_lw (code, mips_t9, mips_t9, 16);
3099 mips_jalr (code, mips_t9, mips_t8);
3101 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
3102 mips_emit32 (code, 0xfefefefe);
3107 mips_addiu (code, ins->dreg, mips_zero, 1);
3108 mips_beq (code, mips_at, mips_zero, 2);
3110 mips_move (code, ins->dreg, mips_zero);
3116 mips_addiu (code, ins->dreg, mips_zero, 1);
3117 mips_bltz (code, mips_at, 2);
3119 mips_move (code, ins->dreg, mips_zero);
3125 mips_addiu (code, ins->dreg, mips_zero, 1);
3126 mips_bgtz (code, mips_at, 2);
3128 mips_move (code, ins->dreg, mips_zero);
3131 case OP_COND_EXC_EQ:
3132 case OP_COND_EXC_GE:
3133 case OP_COND_EXC_GT:
3134 case OP_COND_EXC_LE:
3135 case OP_COND_EXC_LT:
3136 case OP_COND_EXC_NE_UN:
3137 case OP_COND_EXC_GE_UN:
3138 case OP_COND_EXC_GT_UN:
3139 case OP_COND_EXC_LE_UN:
3140 case OP_COND_EXC_LT_UN:
3142 case OP_COND_EXC_OV:
3143 case OP_COND_EXC_NO:
3145 case OP_COND_EXC_NC:
3147 case OP_COND_EXC_IEQ:
3148 case OP_COND_EXC_IGE:
3149 case OP_COND_EXC_IGT:
3150 case OP_COND_EXC_ILE:
3151 case OP_COND_EXC_ILT:
3152 case OP_COND_EXC_INE_UN:
3153 case OP_COND_EXC_IGE_UN:
3154 case OP_COND_EXC_IGT_UN:
3155 case OP_COND_EXC_ILE_UN:
3156 case OP_COND_EXC_ILT_UN:
3158 case OP_COND_EXC_IOV:
3159 case OP_COND_EXC_INO:
3160 case OP_COND_EXC_IC:
3161 case OP_COND_EXC_INC:
3162 /* Should be re-mapped to OP_MIPS_B* by *.inssel-mips.brg */
3163 g_warning ("unsupported conditional exception %s\n", mono_inst_name (ins->opcode));
3164 g_assert_not_reached ();
3167 case OP_MIPS_COND_EXC_EQ:
3168 case OP_MIPS_COND_EXC_GE:
3169 case OP_MIPS_COND_EXC_GT:
3170 case OP_MIPS_COND_EXC_LE:
3171 case OP_MIPS_COND_EXC_LT:
3172 case OP_MIPS_COND_EXC_NE_UN:
3173 case OP_MIPS_COND_EXC_GE_UN:
3174 case OP_MIPS_COND_EXC_GT_UN:
3175 case OP_MIPS_COND_EXC_LE_UN:
3176 case OP_MIPS_COND_EXC_LT_UN:
3178 case OP_MIPS_COND_EXC_OV:
3179 case OP_MIPS_COND_EXC_NO:
3180 case OP_MIPS_COND_EXC_C:
3181 case OP_MIPS_COND_EXC_NC:
3183 case OP_MIPS_COND_EXC_IEQ:
3184 case OP_MIPS_COND_EXC_IGE:
3185 case OP_MIPS_COND_EXC_IGT:
3186 case OP_MIPS_COND_EXC_ILE:
3187 case OP_MIPS_COND_EXC_ILT:
3188 case OP_MIPS_COND_EXC_INE_UN:
3189 case OP_MIPS_COND_EXC_IGE_UN:
3190 case OP_MIPS_COND_EXC_IGT_UN:
3191 case OP_MIPS_COND_EXC_ILE_UN:
3192 case OP_MIPS_COND_EXC_ILT_UN:
3194 case OP_MIPS_COND_EXC_IOV:
3195 case OP_MIPS_COND_EXC_INO:
3196 case OP_MIPS_COND_EXC_IC:
3197 case OP_MIPS_COND_EXC_INC: {
3201 /* If the condition is true, raise the exception */
3203 /* need to reverse test to skip around exception raising */
3205 /* For the moment, branch around a branch to avoid reversing
3208 /* Remember, an unpatched branch to 0 branches to the delay slot */
3209 switch (ins->opcode) {
3210 case OP_MIPS_COND_EXC_EQ:
3211 throw = (guint32 *)(void *)code;
3212 mips_beq (code, ins->sreg1, ins->sreg2, 0);
3215 case OP_MIPS_COND_EXC_NE_UN:
3216 throw = (guint32 *)(void *)code;
3217 mips_bne (code, ins->sreg1, ins->sreg2, 0);
3220 case OP_MIPS_COND_EXC_LE_UN:
3221 mips_subu (code, mips_at, ins->sreg1, ins->sreg2);
3222 throw = (guint32 *)(void *)code;
3223 mips_blez (code, mips_at, 0);
3227 /* Not yet implemented */
3228 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
3229 g_assert_not_reached ();
3231 skip = (guint32 *)(void *)code;
3232 mips_beq (code, mips_zero, mips_zero, 0);
3234 mips_patch (throw, (guint32)code);
3235 code = mips_emit_exc_by_name (code, ins->inst_p1);
3236 mips_patch (skip, (guint32)code);
3237 cfg->bb_exit->max_offset += 24;
3250 /* Should be re-mapped to OP_MIPS_B* by *.inssel-mips.brg */
3251 g_warning ("unsupported conditional set %s\n", mono_inst_name (ins->opcode));
3252 g_assert_not_reached ();
3260 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
3263 /* floating point opcodes */
3265 if (((guint32)ins->inst_p0) & (1 << 15))
3266 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
3268 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
3269 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
3272 if (((guint32)ins->inst_p0) & (1 << 15))
3273 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
3275 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
3276 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
3277 mips_cvtds (code, ins->dreg, ins->dreg);
3279 case OP_STORER8_MEMBASE_REG:
3280 if (mips_is_imm16 (ins->inst_offset)) {
3282 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3284 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset+4);
3285 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset);
3288 mips_load_const (code, mips_at, ins->inst_offset);
3289 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3290 mips_swc1 (code, ins->sreg1, mips_at, 4);
3291 mips_swc1 (code, ins->sreg1+1, mips_at, 0);
3294 case OP_LOADR8_MEMBASE:
3295 if (mips_is_imm16 (ins->inst_offset)) {
3297 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3299 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset+4);
3300 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset);
3303 mips_load_const (code, mips_at, ins->inst_offset);
3304 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3305 mips_lwc1 (code, ins->dreg, mips_at, 4);
3306 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
3309 case OP_STORER4_MEMBASE_REG:
3310 /* XXX Need to convert ins->sreg1 to single-precision first */
3311 mips_cvtsd (code, mips_ftemp, ins->sreg1);
3312 if (mips_is_imm16 (ins->inst_offset)) {
3313 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
3315 mips_load_const (code, mips_at, ins->inst_offset);
3316 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3317 mips_swc1 (code, mips_ftemp, mips_at, 0);
3321 if (mips_is_imm16 (ins->inst_offset)) {
3322 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3324 mips_load_const (code, mips_at, ins->inst_offset);
3325 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3326 mips_lwc1 (code, ins->dreg, mips_at, 0);
3329 case OP_LOADR4_MEMBASE:
3330 if (mips_is_imm16 (ins->inst_offset)) {
3331 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3333 mips_load_const (code, mips_at, ins->inst_offset);
3334 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3335 mips_lwc1 (code, ins->dreg, mips_at, 0);
3337 /* Convert to double precision in place */
3338 mips_cvtds (code, ins->dreg, ins->dreg);
3340 case CEE_CONV_R_UN: {
3341 static const guint64 adjust_val = 0x41F0000000000000ULL;
3343 /* convert unsigned int to double */
3344 mips_mtc1 (code, mips_ftemp, ins->sreg1);
3345 mips_bgez (code, ins->sreg1, 5);
3346 mips_cvtdw (code, ins->dreg, mips_ftemp);
3348 mips_load (code, mips_at, (guint32) &adjust_val);
3349 mips_ldc1 (code, mips_ftemp, mips_at, 0);
3350 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
3351 /* target is here */
3355 mips_mtc1 (code, mips_ftemp, ins->sreg1);
3356 mips_cvtsw (code, ins->dreg, mips_ftemp);
3357 mips_cvtds (code, ins->dreg, ins->dreg);
3360 mips_mtc1 (code, mips_ftemp, ins->sreg1);
3361 mips_cvtdw (code, ins->dreg, mips_ftemp);
3363 case OP_FCONV_TO_I1:
3364 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
3366 case OP_FCONV_TO_U1:
3367 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
3369 case OP_FCONV_TO_I2:
3370 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
3372 case OP_FCONV_TO_U2:
3373 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
3375 case OP_FCONV_TO_I4:
3377 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
3379 case OP_FCONV_TO_U4:
3381 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
3383 case OP_FCONV_TO_I8:
3384 case OP_FCONV_TO_U8:
3385 g_assert_not_reached ();
3386 /* Implemented as helper calls */
3388 case OP_LCONV_TO_R_UN:
3389 g_assert_not_reached ();
3390 /* Implemented as helper calls */
3392 case OP_LCONV_TO_OVF_I:
3393 g_assert_not_reached ();
3394 /* split up by brg file */
3397 mips_fsqrtd (code, ins->dreg, ins->sreg1);
3400 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
3403 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
3406 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
3409 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
3412 mips_fnegd (code, ins->dreg, ins->sreg1);
3416 g_assert_not_reached ();
3419 g_assert_not_reached();
3422 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
3423 mips_addiu (code, ins->dreg, mips_zero, 1);
3424 mips_fbtrue (code, 2);
3426 mips_move (code, ins->dreg, mips_zero);
3429 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
3430 mips_addiu (code, ins->dreg, mips_zero, 1);
3431 mips_fbtrue (code, 2);
3433 mips_move (code, ins->dreg, mips_zero);
3436 /* Less than, or Unordered */
3437 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
3438 mips_addiu (code, ins->dreg, mips_zero, 1);
3439 mips_fbtrue (code, 2);
3441 mips_move (code, ins->dreg, mips_zero);
3444 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
3445 mips_move (code, ins->dreg, mips_zero);
3446 mips_fbtrue (code, 2);
3448 mips_addiu (code, ins->dreg, mips_zero, 1);
3451 /* Greater than, or Unordered */
3452 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
3453 mips_move (code, ins->dreg, mips_zero);
3454 mips_fbtrue (code, 2);
3456 mips_addiu (code, ins->dreg, mips_zero, 1);
3459 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
3461 if (ins->flags & MONO_INST_BRLABEL)
3462 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3464 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3465 mips_fbtrue (code, 0);
3469 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
3471 if (ins->flags & MONO_INST_BRLABEL)
3472 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3474 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3475 mips_fbfalse (code, 0);
3479 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
3481 if (ins->flags & MONO_INST_BRLABEL)
3482 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3484 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3485 mips_fbtrue (code, 0);
3489 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
3491 if (ins->flags & MONO_INST_BRLABEL)
3492 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3494 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3495 mips_fbtrue (code, 0);
3499 mips_fcmpd (code, MIPS_FPU_LE, ins->sreg1, ins->sreg2);
3501 if (ins->flags & MONO_INST_BRLABEL)
3502 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3504 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3505 mips_fbfalse (code, 0);
3509 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
3511 if (ins->flags & MONO_INST_BRLABEL)
3512 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3514 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3515 mips_fbfalse (code, 0);
3519 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
3521 if (ins->flags & MONO_INST_BRLABEL)
3522 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3524 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3525 mips_fbfalse (code, 0);
3529 mips_fcmpd (code, MIPS_FPU_OLT, ins->sreg1, ins->sreg2);
3531 if (ins->flags & MONO_INST_BRLABEL)
3532 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3534 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3535 mips_fbfalse (code, 0);
3539 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
3541 if (ins->flags & MONO_INST_BRLABEL)
3542 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3544 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3545 mips_fbtrue (code, 0);
3549 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
3551 if (ins->flags & MONO_INST_BRLABEL)
3552 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3554 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3555 mips_fbtrue (code, 0);
3559 g_assert_not_reached();
3561 ppc_stfd (code, ins->sreg1, -8, ppc_sp);
3562 ppc_lwz (code, ppc_r11, -8, ppc_sp);
3563 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 1, 31);
3564 ppc_addis (code, ppc_r11, ppc_r11, -32752);
3565 ppc_rlwinmd (code, ppc_r11, ppc_r11, 1, 31, 31);
3566 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3571 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3572 mips_load (code, ins->dreg, 0x0f0f0f0f);
3577 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3578 g_assert_not_reached ();
3581 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3582 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3583 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3584 g_assert_not_reached ();
3590 last_offset = offset;
3593 cfg->code_len = code - cfg->native_code;
3597 mono_arch_register_lowlevel_calls (void)
3602 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3604 MonoJumpInfo *patch_info;
3606 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3607 unsigned char *ip = patch_info->ip.i + code;
3608 const unsigned char *target;
3610 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3612 switch (patch_info->type) {
3613 case MONO_PATCH_INFO_IP:
3614 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
3616 case MONO_PATCH_INFO_SWITCH: {
3617 /* jt is the inlined jump table, 7 or 9 instructions after ip
3618 * In the normal case we store the absolute addresses.
3619 * otherwise the displacements.
3622 gpointer *table = (gpointer *)patch_info->data.table->table;
3623 gpointer *jt = ((gpointer*)(void *)ip) + 7;
3624 if (1 /* || !(cfg->->flags & MONO_CFG_HAS_CALLS) */)
3626 for (i = 0; i < patch_info->data.table->table_size; i++) {
3627 jt [i] = code + (int)table [i];
3631 case MONO_PATCH_INFO_METHODCONST:
3632 case MONO_PATCH_INFO_CLASS:
3633 case MONO_PATCH_INFO_IMAGE:
3634 case MONO_PATCH_INFO_FIELD:
3635 case MONO_PATCH_INFO_VTABLE:
3636 case MONO_PATCH_INFO_IID:
3637 case MONO_PATCH_INFO_SFLDA:
3638 case MONO_PATCH_INFO_LDSTR:
3639 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3640 case MONO_PATCH_INFO_LDTOKEN:
3641 case MONO_PATCH_INFO_R4:
3642 case MONO_PATCH_INFO_R8:
3643 /* from OP_AOTCONST : lui + addiu */
3644 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
3647 case MONO_PATCH_INFO_EXC_NAME:
3648 g_assert_not_reached ();
3649 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
3652 case MONO_PATCH_INFO_NONE:
3653 /* everything is dealt with at epilog output time */
3658 mips_patch ((guint32 *)(void *)ip, (guint32)target);
3664 mono_trace_lmf_prolog (MonoLMF *new_lmf)
3670 mono_trace_lmf_epilog (MonoLMF *old_lmf)
3675 * Allow tracing to work with this interface (with an optional argument)
3677 * This code is expected to be inserted just after the 'real' prolog code,
3678 * and before the first basic block. We need to allocate a 2nd, temporary
3679 * stack frame so that we can preserve f12-f15 as well as a0-a3.
3683 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
3686 int fp_stack_offset = 0;
3692 mips_sw (code, mips_a0, mips_sp, cfg->stack_offset + 0);
3693 mips_sw (code, mips_a1, mips_sp, cfg->stack_offset + 4);
3694 mips_sw (code, mips_a2, mips_sp, cfg->stack_offset + 8);
3695 mips_sw (code, mips_a3, mips_sp, cfg->stack_offset + 12);
3698 fp_stack_offset = MIPS_STACK_PARAM_OFFSET;
3699 mips_addiu (code, mips_sp, mips_sp, -64);
3700 mips_swc1 (code, mips_f12, mips_sp, fp_stack_offset + 16);
3701 mips_swc1 (code, mips_f13, mips_sp, fp_stack_offset + 20);
3702 mips_swc1 (code, mips_f14, mips_sp, fp_stack_offset + 24);
3703 mips_swc1 (code, mips_f15, mips_sp, fp_stack_offset + 28);
3705 mips_fmovs (code, mips_f22, mips_f12);
3706 mips_fmovs (code, mips_f23, mips_f13);
3707 mips_fmovs (code, mips_f24, mips_f14);
3708 mips_fmovs (code, mips_f25, mips_f15);
3711 mips_load_const (code, mips_a0, cfg->method);
3712 mips_addiu (code, mips_a1, mips_sp, cfg->stack_offset + fp_stack_offset);
3713 mips_load_const (code, mips_t9, func);
3714 mips_jalr (code, mips_t9, mips_ra);
3717 mips_lw (code, mips_a0, mips_sp, cfg->stack_offset + 0);
3718 mips_lw (code, mips_a1, mips_sp, cfg->stack_offset + 4);
3719 mips_lw (code, mips_a2, mips_sp, cfg->stack_offset + 8);
3720 mips_lw (code, mips_a3, mips_sp, cfg->stack_offset + 12);
3723 mips_lwc1 (code, mips_f12, mips_sp, fp_stack_offset + 16);
3724 mips_lwc1 (code, mips_f13, mips_sp, fp_stack_offset + 20);
3725 mips_lwc1 (code, mips_f14, mips_sp, fp_stack_offset + 24);
3726 mips_lwc1 (code, mips_f15, mips_sp, fp_stack_offset + 28);
3727 mips_addiu (code, mips_sp, mips_sp, 64);
3729 mips_fmovs (code, mips_f12, mips_f22);
3730 mips_fmovs (code, mips_f13, mips_f23);
3731 mips_fmovs (code, mips_f14, mips_f24);
3732 mips_fmovs (code, mips_f15, mips_f25);
3742 * Stack frame layout:
3744 * ------------------- sp + cfg->stack_usage + cfg->param_area
3745 * param area incoming
3746 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
3748 * ------------------- sp + cfg->stack_usage
3750 * ------------------- sp + cfg->stack_usage-4
3752 * ------------------- sp +
3753 * MonoLMF structure optional
3754 * ------------------- sp + cfg->arch.lmf_offset
3755 * saved registers s0-s8
3756 * ------------------- sp + cfg->arch.iregs_offset
3758 * ------------------- sp + cfg->param_area
3759 * param area outgoing
3760 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
3762 * ------------------- sp
3766 mono_arch_emit_prolog (MonoCompile *cfg)
3768 MonoMethod *method = cfg->method;
3769 MonoMethodSignature *sig;
3771 int alloc_size, pos, i;
3775 guint32 iregs_to_save = 0;
3777 guint32 fregs_to_save = 0;
3780 /* lmf_offset is the offset of the LMF from our stack pointer. */
3781 guint32 lmf_offset = cfg->arch.lmf_offset;
3784 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3788 cfg->flags |= MONO_CFG_HAS_CALLS;
3790 sig = mono_method_signature (method);
3791 cfg->code_size = 768 + sig->param_count * 20;
3792 code = cfg->native_code = g_malloc (cfg->code_size);
3794 /* re-align cfg->stack_offset if needed (due to var spilling in mini-codegen.c) */
3795 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
3797 /* stack_offset should not be changed here. */
3798 alloc_size = cfg->stack_offset;
3799 cfg->stack_usage = alloc_size;
3802 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
3804 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
3808 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
3810 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
3811 fregs_to_save |= (fregs_to_save << 1);
3815 if (mips_is_imm16 (-alloc_size)) {
3816 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
3818 mips_load_const (code, mips_at, -alloc_size);
3819 mips_addu (code, mips_sp, mips_sp, mips_at);
3823 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
3824 mips_sw (code, mips_ra, mips_sp, alloc_size + MIPS_RET_ADDR_OFFSET);
3826 /* XXX - optimize this later to not save all regs if LMF constructed */
3828 if (iregs_to_save) {
3829 /* save used registers in own stack frame (at pos) */
3830 pos = cfg->arch.iregs_offset;
3831 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
3832 if (iregs_to_save & (1 << i)) {
3833 g_assert (pos < cfg->stack_usage - 4);
3834 mips_sw (code, i, mips_sp, pos);
3835 pos += sizeof (gulong);
3840 if (method->save_lmf) {
3841 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
3842 mips_sw (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]));
3848 /* Save float registers */
3849 if (fregs_to_save) {
3850 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
3851 if (fregs_to_save & (1 << i)) {
3852 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
3853 mips_swc1 (code, i, mips_sp, pos);
3854 pos += sizeof (gulong);
3859 if (method->save_lmf) {
3860 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
3861 mips_swc1 (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]));
3866 if (cfg->frame_reg != mips_sp) {
3867 mips_move (code, cfg->frame_reg, mips_sp);
3869 if (method->save_lmf)
3870 mips_sw (code, cfg->frame_reg, mips_sp,
3871 lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]));
3875 /* Do instrumentation before assigning regvars to registers. Because they may be assigned
3876 * to the t* registers, which would be clobbered by the instrumentation calls.
3879 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3882 /* load arguments allocated to register from the stack */
3885 cinfo = calculate_sizes (sig, sig->pinvoke);
3887 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3888 ArgInfo *ainfo = &cinfo->ret;
3889 inst = cfg->vret_addr;
3890 if (inst->opcode == OP_REGVAR)
3891 mips_move (code, inst->dreg, ainfo->reg);
3892 else if (mips_is_imm16 (inst->inst_offset)) {
3893 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3895 mips_load_const (code, mips_at, inst->inst_offset);
3896 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
3897 mips_sw (code, ainfo->reg, mips_at, 0);
3900 /* Keep this in sync with emit_load_volatile_arguments */
3901 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3902 ArgInfo *ainfo = cinfo->args + i;
3903 inst = cfg->args [pos];
3905 if (cfg->verbose_level > 2)
3906 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3907 if (inst->opcode == OP_REGVAR) {
3908 /* Argument ends up in a register */
3909 if (ainfo->regtype == RegTypeGeneral)
3910 mips_move (code, inst->dreg, ainfo->reg);
3911 else if (ainfo->regtype == RegTypeFP) {
3912 g_assert_not_reached();
3914 ppc_fmr (code, inst->dreg, ainfo->reg);
3917 else if (ainfo->regtype == RegTypeBase) {
3918 mips_lw (code, inst->dreg, mips_sp, cfg->stack_usage + ainfo->offset);
3920 g_assert_not_reached ();
3922 if (cfg->verbose_level > 2)
3923 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3925 /* Argument ends up on the stack */
3926 if (ainfo->regtype == RegTypeGeneral) {
3927 /* Incoming parameters should be above this frame */
3928 if (cfg->verbose_level > 2)
3929 g_print ("stack slot at %d of %d\n", inst->inst_offset, alloc_size);
3930 /* g_assert (inst->inst_offset >= alloc_size); */
3931 g_assert (mips_is_imm16 (inst->inst_offset));
3932 switch (ainfo->size) {
3934 mips_sb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3937 mips_sh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3941 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3944 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3945 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
3948 g_assert_not_reached ();
3951 } else if (ainfo->regtype == RegTypeBase) {
3953 * Argument comes in on the stack, and ends up on the stack
3954 * 1 and 2 byte args are passed as 32-bit quantities, but used as
3955 * 8 and 16 bit quantities. Shorten them in place.
3957 g_assert (mips_is_imm16 (inst->inst_offset));
3958 switch (ainfo->size) {
3960 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
3961 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
3964 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
3965 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
3972 g_assert_not_reached ();
3974 } else if (ainfo->regtype == RegTypeFP) {
3975 g_assert (mips_is_imm16 (inst->inst_offset));
3976 if (ainfo->size == 8) {
3978 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3980 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
3981 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
3984 else if (ainfo->size == 4)
3985 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3987 g_assert_not_reached ();
3988 } else if (ainfo->regtype == RegTypeStructByVal) {
3990 int doffset = inst->inst_offset;
3992 g_assert (mips_is_imm16 (inst->inst_offset));
3993 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3994 /* Push the argument registers into their stack slots */
3995 for (i = 0; i < ainfo->size; ++i) {
3996 mips_sw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3997 doffset += sizeof (gpointer);
3999 } else if (ainfo->regtype == RegTypeStructByAddr) {
4000 g_assert (mips_is_imm16 (inst->inst_offset));
4001 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
4002 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
4004 g_assert_not_reached ();
4009 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4010 mips_load_const (code, mips_a0, cfg->domain);
4011 mips_load_const (code, mips_t9, (gpointer)mono_jit_thread_attach);
4012 mips_jalr (code, mips_t9, mips_ra);
4017 if (method->save_lmf) {
4018 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
4019 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
4021 if (lmf_pthread_key != -1) {
4022 g_assert_not_reached();
4024 emit_tls_access (code, mips_temp, lmf_pthread_key);
4026 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
4027 mips_addiu (code, mips_a0, mips_temp, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4030 mips_addiu (code, mips_a0, mips_sp, lmf_offset);
4031 mips_load_const (code, mips_t9, (gpointer)mono_trace_lmf_prolog);
4032 mips_jalr (code, mips_t9, mips_ra);
4035 /* This can/will clobber the a0-a3 registers */
4036 mips_load_const (code, mips_t9, (gpointer)mono_get_lmf_addr);
4037 mips_jalr (code, mips_t9, mips_ra);
4041 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
4042 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
4043 /* new_lmf->previous_lmf = *lmf_addr */
4044 mips_lw (code, mips_at, mips_v0, 0);
4045 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
4046 /* *(lmf_addr) = sp + lmf_offset */
4047 mips_addiu (code, mips_at, mips_sp, lmf_offset);
4048 mips_sw (code, mips_at, mips_v0, 0);
4050 /* save method info */
4051 mips_load_const (code, mips_at, method);
4052 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
4053 mips_sw (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
4055 /* save the current IP */
4056 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4057 mips_load_const (code, mips_at, 0x01010101);
4058 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
4062 cfg->code_len = code - cfg->native_code;
4063 g_assert (cfg->code_len < cfg->code_size);
4078 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4081 int save_mode = SAVE_NONE;
4083 MonoMethod *method = cfg->method;
4084 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
4085 int save_offset = MIPS_STACK_PARAM_OFFSET;
4087 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
4089 offset = code - cfg->native_code;
4090 /* we need about 16 instructions */
4091 if (offset > (cfg->code_size - 16 * 4)) {
4092 cfg->code_size *= 2;
4093 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4094 code = cfg->native_code + offset;
4099 case MONO_TYPE_VOID:
4100 /* special case string .ctor icall */
4101 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
4102 save_mode = SAVE_ONE;
4104 save_mode = SAVE_NONE;
4108 save_mode = SAVE_TWO;
4112 save_mode = SAVE_FP;
4114 case MONO_TYPE_VALUETYPE:
4115 save_mode = SAVE_STRUCT;
4118 save_mode = SAVE_ONE;
4122 mips_addiu (code, mips_sp, mips_sp, -32);
4123 switch (save_mode) {
4125 mips_sw (code, mips_v0, mips_sp, save_offset);
4126 mips_sw (code, mips_v1, mips_sp, save_offset + 4);
4127 if (enable_arguments) {
4128 mips_move (code, mips_a1, mips_v0);
4129 mips_move (code, mips_a2, mips_v1);
4133 mips_sw (code, mips_v0, mips_sp, save_offset);
4134 if (enable_arguments) {
4135 mips_move (code, mips_a1, mips_v0);
4139 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
4140 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
4141 mips_lw (code, mips_a0, mips_sp, save_offset);
4142 mips_lw (code, mips_a1, mips_sp, save_offset+4);
4149 mips_load_const (code, mips_a0, cfg->method);
4150 mips_load_const (code, mips_t9, func);
4151 mips_jalr (code, mips_t9, mips_ra);
4154 switch (save_mode) {
4156 mips_lw (code, mips_v0, mips_sp, save_offset);
4157 mips_lw (code, mips_v1, mips_sp, save_offset + 4);
4160 mips_lw (code, mips_v0, mips_sp, save_offset);
4163 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
4170 mips_addiu (code, mips_sp, mips_sp, 32);
4177 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
4179 MonoMethod *method = cfg->method;
4181 int max_epilog_size = 16 + 20*4;
4182 guint32 iregs_to_restore;
4184 guint32 fregs_to_restore;
4188 if (cfg->method->save_lmf)
4189 max_epilog_size += 128;
4192 if (mono_jit_trace_calls != NULL)
4193 max_epilog_size += 50;
4195 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4196 max_epilog_size += 50;
4199 pos = code - cfg->native_code;
4200 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4201 cfg->code_size *= 2;
4202 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4203 mono_jit_stats.code_reallocs++;
4207 * Keep in sync with OP_JMP
4210 code = cfg->native_code + pos;
4212 code = cfg->native_code + cfg->code_len;
4214 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
4215 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
4217 pos = cfg->arch.iregs_offset;
4218 if (cfg->frame_reg != mips_sp) {
4219 mips_move (code, mips_sp, cfg->frame_reg);
4222 iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
4224 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4226 if (iregs_to_restore) {
4227 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4228 if (iregs_to_restore & (1 << i)) {
4229 mips_lw (code, i, mips_sp, pos);
4230 pos += sizeof (gulong);
4237 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4239 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
4240 fregs_to_restore |= (fregs_to_restore << 1);
4242 if (fregs_to_restore) {
4243 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4244 if (fregs_to_restore & (1 << i)) {
4245 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4246 mips_lwc1 (code, i, mips_sp, pos);
4247 pos += sizeof (gulong);
4253 /* Unlink the LMF if necessary */
4254 if (method->save_lmf) {
4255 int lmf_offset = cfg->arch.lmf_offset;
4257 /* t0 = current_lmf->previous_lmf */
4258 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
4260 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
4261 /* (*lmf_addr) = previous_lmf */
4262 mips_sw (code, mips_temp, mips_t1, 0);
4266 /* Restore the fp */
4267 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
4269 /* Correct the stack pointer */
4270 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
4271 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage + MIPS_RET_ADDR_OFFSET);
4272 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage);
4274 /* Caller will emit either return or tail-call sequence */
4276 cfg->code_len = code - cfg->native_code;
4278 g_assert (cfg->code_len < cfg->code_size);
4283 mono_arch_emit_epilog (MonoCompile *cfg)
4287 code = mono_arch_emit_epilog_sub (cfg, NULL);
4289 mips_jr (code, mips_ra);
4292 cfg->code_len = code - cfg->native_code;
4294 g_assert (cfg->code_len < cfg->code_size);
4297 /* remove once throw_exception_by_name is eliminated */
4299 exception_id_by_name (const char *name)
4301 if (strcmp (name, "IndexOutOfRangeException") == 0)
4302 return MONO_EXC_INDEX_OUT_OF_RANGE;
4303 if (strcmp (name, "OverflowException") == 0)
4304 return MONO_EXC_OVERFLOW;
4305 if (strcmp (name, "ArithmeticException") == 0)
4306 return MONO_EXC_ARITHMETIC;
4307 if (strcmp (name, "DivideByZeroException") == 0)
4308 return MONO_EXC_DIVIDE_BY_ZERO;
4309 if (strcmp (name, "InvalidCastException") == 0)
4310 return MONO_EXC_INVALID_CAST;
4311 if (strcmp (name, "NullReferenceException") == 0)
4312 return MONO_EXC_NULL_REF;
4313 if (strcmp (name, "ArrayTypeMismatchException") == 0)
4314 return MONO_EXC_ARRAY_TYPE_MISMATCH;
4315 g_error ("Unknown intrinsic exception %s\n", name);
4320 mono_arch_emit_exceptions (MonoCompile *cfg)
4323 MonoJumpInfo *patch_info;
4326 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
4327 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
4328 int max_epilog_size = 50;
4330 /* count the number of exception infos */
4333 * make sure we have enough space for exceptions
4334 * 24 is the simulated call to throw_exception_by_name
4336 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4338 if (patch_info->type == MONO_PATCH_INFO_EXC) {
4339 i = exception_id_by_name (patch_info->data.target);
4340 g_assert (i < MONO_EXC_INTRINS_NUM);
4341 if (!exc_throw_found [i]) {
4342 max_epilog_size += 12;
4343 exc_throw_found [i] = TRUE;
4349 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4350 cfg->code_size *= 2;
4351 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4352 mono_jit_stats.code_reallocs++;
4355 code = cfg->native_code + cfg->code_len;
4357 /* add code to raise exceptions */
4358 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4359 switch (patch_info->type) {
4360 case MONO_PATCH_INFO_EXC: {
4362 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
4364 i = exception_id_by_name (patch_info->data.target);
4365 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
4366 if (!exc_throw_pos [i]) {
4369 exc_throw_pos [i] = code;
4370 //g_print ("exc: writing stub at %p\n", code);
4371 mips_load_const (code, mips_a0, patch_info->data.target);
4372 addr = (guint32) mono_arch_get_throw_exception_by_name ();
4373 mips_load_const (code, mips_t9, addr);
4374 mips_jr (code, mips_t9);
4377 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
4379 /* Turn into a Relative patch, pointing at code stub */
4380 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
4381 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
4383 g_assert_not_reached();
4393 cfg->code_len = code - cfg->native_code;
4395 g_assert (cfg->code_len < cfg->code_size);
4400 * Thread local storage support
4403 setup_tls_access (void)
4406 //guint32 *ins, *code;
4408 if (tls_mode == TLS_MODE_FAILED)
4411 if (g_getenv ("MONO_NO_TLS")) {
4412 tls_mode = TLS_MODE_FAILED;
4416 if (tls_mode == TLS_MODE_DETECT) {
4418 tls_mode = TLS_MODE_FAILED;
4422 ins = (guint32*)pthread_getspecific;
4423 /* uncond branch to the real method */
4424 if ((*ins >> 26) == 18) {
4426 val = (*ins & ~3) << 6;
4430 ins = (guint32*)val;
4432 ins = (guint32*) ((char*)ins + val);
4435 code = &cmplwi_1023;
4436 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
4438 ppc_li (code, ppc_r4, 0x48);
4441 if (*ins == cmplwi_1023) {
4442 int found_lwz_284 = 0;
4443 for (ptk = 0; ptk < 20; ++ptk) {
4445 if (!*ins || *ins == blr_ins)
4447 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
4452 if (!found_lwz_284) {
4453 tls_mode = TLS_MODE_FAILED;
4456 tls_mode = TLS_MODE_LTHREADS;
4457 } else if (*ins == li_0x48) {
4459 /* uncond branch to the real method */
4460 if ((*ins >> 26) == 18) {
4462 val = (*ins & ~3) << 6;
4466 ins = (guint32*)val;
4468 ins = (guint32*) ((char*)ins + val);
4471 ppc_li (code, ppc_r0, 0x7FF2);
4472 if (ins [1] == val) {
4473 /* Darwin on G4, implement */
4474 tls_mode = TLS_MODE_FAILED;
4478 ppc_mfspr (code, ppc_r3, 104);
4479 if (ins [1] != val) {
4480 tls_mode = TLS_MODE_FAILED;
4483 tls_mode = TLS_MODE_DARWIN_G5;
4486 tls_mode = TLS_MODE_FAILED;
4490 tls_mode = TLS_MODE_FAILED;
4495 if (monodomain_key == -1) {
4496 ptk = mono_domain_get_tls_key ();
4498 ptk = mono_pthread_key_for_tls (ptk);
4500 monodomain_key = ptk;
4504 if (lmf_pthread_key == -1) {
4505 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
4507 /*g_print ("MonoLMF at: %d\n", ptk);*/
4508 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
4509 init_tls_failed = 1;
4512 lmf_pthread_key = ptk;
4515 if (monothread_key == -1) {
4516 ptk = mono_thread_get_tls_key ();
4518 ptk = mono_pthread_key_for_tls (ptk);
4520 monothread_key = ptk;
4521 /*g_print ("thread inited: %d\n", ptk);*/
4524 /*g_print ("thread not inited yet %d\n", ptk);*/
4530 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4532 setup_tls_access ();
4536 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4541 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4543 int this_dreg = mips_a0;
4546 this_dreg = mips_a1;
4548 /* add the this argument */
4549 if (this_reg != -1) {
4551 MONO_INST_NEW (cfg, this, OP_MOVE);
4552 this->type = this_type;
4553 this->sreg1 = this_reg;
4554 this->dreg = mono_alloc_ireg (cfg);
4555 mono_bblock_add_inst (cfg->cbb, this);
4556 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
4561 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4562 vtarg->type = STACK_MP;
4563 vtarg->sreg1 = vt_reg;
4564 vtarg->dreg = mono_alloc_ireg (cfg);
4565 mono_bblock_add_inst (cfg->cbb, vtarg);
4566 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
4571 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4573 MonoInst *ins = NULL;
4579 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4585 mono_arch_print_tree (MonoInst *tree, int arity)
4590 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4594 setup_tls_access ();
4595 if (monodomain_key == -1)
4598 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4599 ins->inst_offset = monodomain_key;
4604 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4608 setup_tls_access ();
4609 if (monothread_key == -1)
4612 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4613 ins->inst_offset = monothread_key;
4618 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4620 /* FIXME: implement */
4621 g_assert_not_reached ();
4624 #ifdef MONO_ARCH_HAVE_IMT
4628 #define JUMP_IMM_SIZE 12
4629 #define JUMP_IMM32_SIZE 16
4630 #define ENABLE_WRONG_METHOD_CHECK 0
4633 * LOCKING: called with the domain lock held
4636 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
4637 gpointer fail_tramp)
4643 guint8 *code, *start;
4645 for (i = 0; i < count; ++i) {
4646 MonoIMTCheckItem *item = imt_entries [i];
4647 if (item->is_equals) {
4648 if (item->check_target_idx) {
4649 if (!item->compare_done)
4650 item->chunk_size += CMP_SIZE;
4652 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
4654 item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
4657 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
4659 item->chunk_size += JUMP_IMM_SIZE;
4660 #if ENABLE_WRONG_METHOD_CHECK
4661 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
4666 item->chunk_size += CMP_SIZE + BR_SIZE;
4667 imt_entries [item->check_target_idx]->compare_done = TRUE;
4669 size += item->chunk_size;
4672 code = mono_method_alloc_generic_virtual_thunk (domain, size);
4674 /* the initial load of the vtable address */
4676 code = mono_code_manager_reserve (domain->code_mp, size);
4680 ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
4681 for (i = 0; i < count; ++i) {
4682 MonoIMTCheckItem *item = imt_entries [i];
4683 item->code_target = code;
4684 if (item->is_equals) {
4685 if (item->check_target_idx) {
4686 if (!item->compare_done) {
4687 ppc_load (code, ppc_r0, (guint32)item->key);
4688 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4690 item->jmp_code = code;
4691 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4693 ppc_load (code, ppc_r0, item->value.target_code);
4695 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
4696 ppc_mtctr (code, ppc_r0);
4697 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4700 ppc_load (code, ppc_r0, (guint32)item->key);
4701 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4702 item->jmp_code = code;
4703 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4704 ppc_load (code, ppc_r0, item->value.target_code);
4705 ppc_mtctr (code, ppc_r0);
4706 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4707 ppc_patch (item->jmp_code, code);
4708 ppc_load (code, ppc_r0, fail_tramp);
4709 ppc_mtctr (code, ppc_r0);
4710 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4711 item->jmp_code = NULL;
4713 /* enable the commented code to assert on wrong method */
4714 #if ENABLE_WRONG_METHOD_CHECK
4715 ppc_load (code, ppc_r0, (guint32)item->key);
4716 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4717 item->jmp_code = code;
4718 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4720 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
4721 ppc_mtctr (code, ppc_r0);
4722 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4723 #if ENABLE_WRONG_METHOD_CHECK
4724 ppc_patch (item->jmp_code, code);
4726 item->jmp_code = NULL;
4731 ppc_load (code, ppc_r0, (guint32)item->key);
4732 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4733 item->jmp_code = code;
4734 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
4737 /* patch the branches to get to the target items */
4738 for (i = 0; i < count; ++i) {
4739 MonoIMTCheckItem *item = imt_entries [i];
4740 if (item->jmp_code) {
4741 if (item->check_target_idx) {
4742 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4748 mono_stats.imt_thunks_size += code - start;
4749 g_assert (code - start <= size);
4750 mono_arch_flush_icache (start, size);
4756 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4758 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
4762 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
4764 return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
4769 mono_arch_find_static_call_vtable (gpointer *regs, guint8 *code)
4771 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];