2 * mini-mips.c: MIPS backend for the Mono code generator
5 * Mark Mason (mason@broadcom.com)
7 * Based on mini-ppc.c by
8 * Paolo Molaro (lupus@ximian.com)
9 * Dietmar Maurer (dietmar@ximian.com)
12 * (C) 2003 Ximian, Inc.
16 #include <asm/cachectl.h>
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/debug-helpers.h>
21 #include "mini-mips.h"
26 #define SAVE_FP_REGS 0
27 #define SAVE_ALL_REGS 0
28 #define EXTRA_STACK_SPACE 0 /* suppresses some s-reg corruption issues */
29 #define LONG_BRANCH 1 /* needed for yyparse in mcs */
32 #define ALWAYS_USE_FP 1
33 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
42 int mono_exc_esp_offset = 0;
43 static int tls_mode = TLS_MODE_DETECT;
44 static int lmf_pthread_key = -1;
45 static int monothread_key = -1;
46 static int monodomain_key = -1;
49 #define DEBUG(a) if (cfg->verbose_level > 1) a
55 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
57 code = mips_emit_exc_by_name (code, exc_name); \
58 cfg->bb_exit->max_offset += 16; \
62 #define emit_linuxthreads_tls(code,dreg,key) do {\
64 off1 = offsets_from_pthread_key ((key), &off2); \
65 ppc_lwz ((code), (dreg), off1, ppc_r2); \
66 ppc_lwz ((code), (dreg), off2, (dreg)); \
70 #define emit_tls_access(code,dreg,key) do { \
72 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
73 default: g_assert_not_reached (); \
77 typedef struct InstList InstList;
95 guint16 vtsize; /* in param area */
97 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
98 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
115 void patch_lui_addiu(guint32 *ip, guint32 val);
116 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
119 mono_arch_flush_icache (guint8 *code, gint size)
121 /* Linux/MIPS specific */
122 cacheflush (code, size, BCACHE);
125 #ifndef CUSTOM_STACK_WALK
127 mono_arch_flush_register_windows (void)
133 mips_emit_exc_by_name(guint8 *code, const char *name)
137 mips_load_const (code, mips_a0, name);
138 addr = (guint32) mono_arch_get_throw_exception_by_name ();
139 mips_load_const (code, mips_t9, addr);
140 mips_jalr (code, mips_t9, mips_ra);
147 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
153 /* Invert test and emit branch around jump */
156 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
160 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
164 mips_bltz (code, ins->sreg1, br_offset);
168 mips_blez (code, ins->sreg1, br_offset);
172 mips_bgtz (code, ins->sreg1, br_offset);
176 mips_bgez (code, ins->sreg1, br_offset);
180 g_assert_not_reached ();
182 if (ins->flags & MONO_INST_BRLABEL)
183 mono_add_patch_info (cfg, code - cfg->native_code,
184 MONO_PATCH_INFO_LABEL, ins->inst_i0);
186 mono_add_patch_info (cfg, code - cfg->native_code,
187 MONO_PATCH_INFO_BB, ins->inst_true_bb);
188 mips_lui (code, mips_at, mips_zero, 0);
189 mips_addiu (code, mips_at, mips_at, 0);
190 mips_jr (code, mips_at);
193 if (ins->flags & MONO_INST_BRLABEL)
194 mono_add_patch_info (cfg, code - cfg->native_code,
195 MONO_PATCH_INFO_LABEL, ins->inst_i0);
197 mono_add_patch_info (cfg, code - cfg->native_code,
198 MONO_PATCH_INFO_BB, ins->inst_true_bb);
201 mips_beq (code, ins->sreg1, ins->sreg2, 0);
205 mips_bne (code, ins->sreg1, ins->sreg2, 0);
209 mips_bgez (code, ins->sreg1, 0);
213 mips_bgtz (code, ins->sreg1, 0);
217 mips_blez (code, ins->sreg1, 0);
221 mips_bltz (code, ins->sreg1, 0);
225 g_assert_not_reached ();
231 /* XXX - big-endian dependent? */
233 patch_lui_addiu(guint32 *ip, guint32 val)
235 guint16 *__lui_addiu = (guint16*)(void *)(ip);
238 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
239 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
242 if (((guint32)(val)) & (1 << 15))
243 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
245 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
246 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
247 mono_arch_flush_icache ((guint8 *)ip, 8);
252 mips_patch (guint32 *code, guint32 target)
255 guint32 op = ins >> 26;
256 guint32 diff, offset;
258 g_assert (trap_target != target);
259 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
261 case 0x00: /* jr ra */
262 if (ins == 0x3e00008)
264 g_assert_not_reached ();
268 g_assert (!(target & 0x03));
269 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
270 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
272 mono_arch_flush_icache ((guint8 *)code, 4);
274 case 0x01: /* BLTZ */
277 case 0x06: /* BLEZ */
278 case 0x07: /* BGTZ */
279 case 0x11: /* bc1t */
280 diff = target - (guint32)(code + 1);
281 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
282 g_assert (!(diff & 0x03));
283 offset = ((gint32)diff) >> 2;
284 g_assert (((int)offset) == ((int)(short)offset));
285 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
287 mono_arch_flush_icache ((guint8 *)code, 4);
289 case 0x0f: /* LUI / ADDIU pair */
290 patch_lui_addiu (code, target);
291 mono_arch_flush_icache ((guint8 *)code, 8);
295 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
296 g_assert_not_reached ();
301 offsets_from_pthread_key (guint32 key, int *offset2)
305 *offset2 = idx2 * sizeof (gpointer);
306 return 284 + idx1 * sizeof (gpointer);
310 mono_arch_regname (int reg) {
311 static const char * rnames[] = {
312 "zero", "at", "v0", "v1",
313 "a0", "a1", "a2", "a3",
314 "t0", "t1", "t2", "t3",
315 "t4", "t5", "t6", "t7",
316 "s0", "s1", "s2", "s3",
317 "s4", "s5", "s6", "s7",
318 "t8", "t9", "k0", "k1",
319 "gp", "sp", "fp", "ra"
321 if (reg >= 0 && reg < 32)
327 mono_arch_fregname (int reg) {
328 static const char * rnames[] = {
329 "f0", "f1", "f2", "f3",
330 "f4", "f5", "f6", "f7",
331 "f8", "f9", "f10", "f11",
332 "f12", "f13", "f14", "f15",
333 "f16", "f17", "f18", "f19",
334 "f20", "f21", "f22", "f23",
335 "f24", "f25", "f26", "f27",
336 "f28", "f29", "f30", "f31"
338 if (reg >= 0 && reg < 32)
343 /* this function overwrites at */
345 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
347 /* XXX write a loop, not an unrolled loop */
349 mips_lw (code, mips_at, sreg, soffset);
350 mips_sw (code, mips_at, dreg, doffset);
359 * mono_arch_get_argument_info:
360 * @csig: a method signature
361 * @param_count: the number of parameters to consider
362 * @arg_info: an array to store the result infos
364 * Gathers information on parameters such as size, alignment and
365 * padding. arg_info should be large enought to hold param_count + 1 entries.
367 * Returns the size of the activation frame.
370 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
372 int k, frame_size = 0;
373 guint32 size, align, pad;
376 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
377 frame_size += sizeof (gpointer);
381 arg_info [0].offset = offset;
384 frame_size += sizeof (gpointer);
388 arg_info [0].size = frame_size;
390 for (k = 0; k < param_count; k++) {
393 size = mono_type_native_stack_size (csig->params [k], &align);
395 size = mini_type_stack_size (NULL, csig->params [k], &align);
397 /* ignore alignment for now */
400 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
401 arg_info [k].pad = pad;
403 arg_info [k + 1].pad = 0;
404 arg_info [k + 1].size = size;
406 arg_info [k + 1].offset = offset;
410 align = MONO_ARCH_FRAME_ALIGNMENT;
411 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
412 arg_info [k].pad = pad;
418 * Initialize the cpu to execute managed code.
421 mono_arch_cpu_init (void)
426 * Initialize architecture specific code.
429 mono_arch_init (void)
434 * Cleanup architecture specific code.
437 mono_arch_cleanup (void)
442 * This function returns the optimizations supported on this cpu.
445 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
449 /* no mips-specific optimizations yet */
455 is_regsize_var (MonoType *t) {
458 t = mono_type_get_underlying_type (t);
465 case MONO_TYPE_FNPTR:
467 case MONO_TYPE_OBJECT:
468 case MONO_TYPE_STRING:
469 case MONO_TYPE_CLASS:
470 case MONO_TYPE_SZARRAY:
471 case MONO_TYPE_ARRAY:
473 case MONO_TYPE_GENERICINST:
474 if (!mono_type_generic_inst_is_valuetype (t))
477 case MONO_TYPE_VALUETYPE:
484 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
489 for (i = 0; i < cfg->num_varinfo; i++) {
490 MonoInst *ins = cfg->varinfo [i];
491 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
494 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
497 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
500 /* we can only allocate 32 bit values */
501 if (is_regsize_var (ins->inst_vtype)) {
502 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
503 g_assert (i == vmv->idx);
504 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
512 mono_arch_get_global_int_regs (MonoCompile *cfg)
516 regs = g_list_prepend (regs, (gpointer)mips_s0);
517 regs = g_list_prepend (regs, (gpointer)mips_s1);
518 regs = g_list_prepend (regs, (gpointer)mips_s2);
519 regs = g_list_prepend (regs, (gpointer)mips_s3);
520 regs = g_list_prepend (regs, (gpointer)mips_s4);
521 regs = g_list_prepend (regs, (gpointer)mips_s5);
522 regs = g_list_prepend (regs, (gpointer)mips_s6);
523 regs = g_list_prepend (regs, (gpointer)mips_s7);
529 * mono_arch_regalloc_cost:
531 * Return the cost, in number of memory references, of the action of
532 * allocating the variable VMV into a register during global register
536 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
543 args_onto_stack (CallInfo *info)
545 g_assert(!info->on_stack);
546 g_assert(info->stack_size <= MIPS_STACK_PARAM_OFFSET);
547 info->on_stack = TRUE;
548 info->stack_size = MIPS_STACK_PARAM_OFFSET;
552 * O32 calling convention version
556 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
557 /* First, see if we need to drop onto the stack */
558 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
559 args_onto_stack (info);
561 /* Now, place the argument */
562 if (info->on_stack) {
563 ainfo->regtype = RegTypeBase;
564 ainfo->reg = mips_sp; /* in the caller */
565 ainfo->offset = info->stack_size;
568 ainfo->regtype = RegTypeGeneral;
569 ainfo->reg = info->gr;
571 info->gr_passed = TRUE;
573 info->stack_size += 4;
577 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
578 /* First, see if we need to drop onto the stack */
579 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
580 args_onto_stack (info);
582 /* Now, place the argument */
583 if (info->on_stack) {
584 g_assert(info->stack_size % 4 == 0);
585 info->stack_size += (info->stack_size % 8);
587 ainfo->regtype = RegTypeBase;
588 ainfo->reg = mips_sp; /* in the caller */
589 ainfo->offset = info->stack_size;
592 // info->gr must be a0 or a2
593 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
594 g_assert(info->gr <= MIPS_LAST_ARG_REG);
596 ainfo->regtype = RegTypeGeneral;
597 ainfo->reg = info->gr;
599 info->gr_passed = TRUE;
601 info->stack_size += 8;
605 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
606 /* First, see if we need to drop onto the stack */
607 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
608 args_onto_stack (info);
610 /* Now, place the argument */
611 if (info->on_stack) {
612 ainfo->regtype = RegTypeBase;
613 ainfo->reg = mips_sp; /* in the caller */
614 ainfo->offset = info->stack_size;
617 /* Only use FP regs for args if no int args passed yet */
618 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
619 ainfo->regtype = RegTypeFP;
620 ainfo->reg = info->fr;
621 /* Even though it's a single-precision float, it takes up two FP regs */
623 /* FP and GP slots do not overlap */
627 /* Passing single-precision float arg in a GP register
628 * such as: func (0, 1.0, 2, 3);
629 * In this case, only one 'gr' register is consumed.
631 ainfo->regtype = RegTypeGeneral;
632 ainfo->reg = info->gr;
635 info->gr_passed = TRUE;
638 info->stack_size += 4;
642 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
643 /* First, see if we need to drop onto the stack */
644 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
645 args_onto_stack (info);
647 /* Now, place the argument */
648 if (info->on_stack) {
649 g_assert(info->stack_size % 4 == 0);
650 info->stack_size += (info->stack_size % 8);
652 ainfo->regtype = RegTypeBase;
653 ainfo->reg = mips_sp; /* in the caller */
654 ainfo->offset = info->stack_size;
657 /* Only use FP regs for args if no int args passed yet */
658 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
659 ainfo->regtype = RegTypeFP;
660 ainfo->reg = info->fr;
662 /* FP and GP slots do not overlap */
666 // info->gr must be a0 or a2
667 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
668 g_assert(info->gr <= MIPS_LAST_ARG_REG);
670 ainfo->regtype = RegTypeGeneral;
671 ainfo->reg = info->gr;
673 info->gr_passed = TRUE;
676 info->stack_size += 8;
680 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
683 int n = sig->hasthis + sig->param_count;
685 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
687 cinfo->fr = MIPS_FIRST_FPARG_REG;
688 cinfo->gr = MIPS_FIRST_ARG_REG;
689 cinfo->stack_size = 0;
691 DEBUG(printf("calculate_sizes\n"));
693 /* handle returning a struct */
694 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
695 cinfo->struct_ret = cinfo->gr;
696 add_int32_arg (cinfo, &cinfo->ret);
701 add_int32_arg (cinfo, cinfo->args + n);
704 DEBUG(printf("params: %d\n", sig->param_count));
705 for (i = 0; i < sig->param_count; ++i) {
706 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
707 /* Prevent implicit arguments and sig_cookie from
708 being passed in registers */
709 args_onto_stack (cinfo);
710 /* Emit the signature cookie just before the implicit arguments */
711 add_int32_arg (cinfo, &cinfo->sig_cookie);
713 DEBUG(printf("param %d: ", i));
714 if (sig->params [i]->byref) {
715 DEBUG(printf("byref\n"));
716 add_int32_arg (cinfo, &cinfo->args[n]);
720 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
721 switch (simpletype) {
722 case MONO_TYPE_BOOLEAN:
725 DEBUG(printf("1 byte\n"));
726 cinfo->args [n].size = 1;
727 add_int32_arg (cinfo, &cinfo->args[n]);
733 DEBUG(printf("2 bytes\n"));
734 cinfo->args [n].size = 2;
735 add_int32_arg (cinfo, &cinfo->args[n]);
740 DEBUG(printf("4 bytes\n"));
741 cinfo->args [n].size = 4;
742 add_int32_arg (cinfo, &cinfo->args[n]);
748 case MONO_TYPE_FNPTR:
749 case MONO_TYPE_CLASS:
750 case MONO_TYPE_OBJECT:
751 case MONO_TYPE_STRING:
752 case MONO_TYPE_SZARRAY:
753 case MONO_TYPE_ARRAY:
754 cinfo->args [n].size = sizeof (gpointer);
755 add_int32_arg (cinfo, &cinfo->args[n]);
758 case MONO_TYPE_GENERICINST:
759 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
760 cinfo->args [n].size = sizeof (gpointer);
761 add_int32_arg (cinfo, &cinfo->args[n]);
766 case MONO_TYPE_VALUETYPE: {
769 int has_offset = FALSE;
771 gint size, alignment;
774 klass = mono_class_from_mono_type (sig->params [i]);
776 size = mono_class_native_size (klass, NULL);
778 size = mono_class_value_size (klass, NULL);
779 alignment = mono_class_min_align (klass);
780 #if MIPS_PASS_STRUCTS_BY_VALUE
781 /* Need to do alignment if struct contains long or double */
783 if (cinfo->stack_size & (alignment - 1)) {
784 add_int32_arg (cinfo, &dummy_arg);
786 g_assert (!(cinfo->stack_size & (alignment - 1)));
790 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
791 mono_class_native_size (sig->params [i]->data.klass, NULL),
792 cinfo->stack_size, alignment);
794 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
795 g_assert(cinfo->args [n].size == 0);
796 g_assert(cinfo->args [n].vtsize == 0);
797 for (j = 0; j < nwords; ++j) {
799 add_int32_arg (cinfo, &cinfo->args [n]);
803 add_int32_arg (cinfo, &dummy_arg);
804 if (!has_offset && cinfo->on_stack) {
805 cinfo->args [n].offset = dummy_arg.offset;
810 cinfo->args [n].vtsize += 1;
812 cinfo->args [n].size += 1;
814 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
815 cinfo->args [n].regtype = RegTypeStructByVal;
817 add_int32_arg (cinfo, &cinfo->args[n]);
818 cinfo->args [n].regtype = RegTypeStructByAddr;
823 case MONO_TYPE_TYPEDBYREF: {
824 /* keep in sync or merge with the valuetype case */
825 #if MIPS_PASS_STRUCTS_BY_VALUE
827 int size = sizeof (MonoTypedRef);
828 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
829 cinfo->args [n].regtype = RegTypeStructByVal;
830 if (!cinfo->on_stack && cinfo->gr <= MIPS_LAST_ARG_REG) {
831 int rest = MIPS_LAST_ARG_REG - cinfo->gr + 1;
832 int n_in_regs = rest >= nwords? nwords: rest;
833 cinfo->args [n].size = n_in_regs;
834 cinfo->args [n].vtsize = nwords - n_in_regs;
835 cinfo->args [n].reg = cinfo->gr;
836 cinfo->gr += n_in_regs;
837 cinfo->gr_passed = TRUE;
839 cinfo->args [n].size = 0;
840 cinfo->args [n].vtsize = nwords;
842 if (cinfo->args [n].vtsize > 0) {
843 if (!cinfo->on_stack)
844 args_onto_stack (cinfo);
845 g_assert(cinfo->on_stack);
846 cinfo->args [n].offset = cinfo->stack_size;
847 g_print ("offset for arg %d at %d\n", n, cinfo->args [n].offset);
848 cinfo->stack_size += cinfo->args [n].vtsize * sizeof (gpointer);
852 add_int32_arg (cinfo, &cinfo->args[n]);
853 cinfo->args [n].regtype = RegTypeStructByAddr;
860 DEBUG(printf("8 bytes\n"));
861 cinfo->args [n].size = 8;
862 add_int64_arg (cinfo, &cinfo->args[n]);
866 DEBUG(printf("R4\n"));
867 cinfo->args [n].size = 4;
868 add_float32_arg (cinfo, &cinfo->args[n]);
872 DEBUG(printf("R8\n"));
873 cinfo->args [n].size = 8;
874 add_float64_arg (cinfo, &cinfo->args[n]);
878 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
883 simpletype = mono_type_get_underlying_type (sig->ret)->type;
884 switch (simpletype) {
885 case MONO_TYPE_BOOLEAN:
896 case MONO_TYPE_FNPTR:
897 case MONO_TYPE_CLASS:
898 case MONO_TYPE_OBJECT:
899 case MONO_TYPE_SZARRAY:
900 case MONO_TYPE_ARRAY:
901 case MONO_TYPE_STRING:
902 cinfo->ret.reg = mips_v0;
906 cinfo->ret.reg = mips_v0;
910 cinfo->ret.reg = mips_f0;
911 cinfo->ret.regtype = RegTypeFP;
913 case MONO_TYPE_GENERICINST:
914 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
915 cinfo->ret.reg = mips_v0;
919 case MONO_TYPE_VALUETYPE:
921 case MONO_TYPE_TYPEDBYREF:
925 g_error ("Can't handle as return value 0x%x", sig->ret->type);
929 /* align stack size to 16 */
930 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
932 cinfo->stack_usage = cinfo->stack_size;
938 * Set var information according to the calling convention. mips version.
939 * The locals var stuff should most likely be split in another method.
942 mono_arch_allocate_vars (MonoCompile *cfg)
944 MonoMethodSignature *sig;
945 MonoMethodHeader *header;
947 int i, offset, size, align, curinst;
948 int frame_reg = mips_sp;
949 guint32 iregs_to_save = 0;
950 guint32 fregs_to_restore;
952 cfg->flags |= MONO_CFG_HAS_SPILLUP;
954 /* allow room for the vararg method args: void* and long/double */
955 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
956 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
958 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
959 * call convs needs to be handled this way.
961 if (cfg->flags & MONO_CFG_HAS_VARARGS)
962 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
964 /* gtk-sharp and other broken code will dllimport vararg functions even with
965 * non-varargs signatures. Since there is little hope people will get this right
966 * we assume they won't.
968 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
969 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
971 /* a0-a3 always present */
972 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
974 header = mono_method_get_header (cfg->method);
976 sig = mono_method_signature (cfg->method);
979 * We use the frame register also for any method that has
980 * exception clauses. This way, when the handlers are called,
981 * the code will reference local variables using the frame reg instead of
982 * the stack pointer: if we had to restore the stack pointer, we'd
983 * corrupt the method frames that are already on the stack (since
984 * filters get called before stack unwinding happens) when the filter
985 * code would call any method (this also applies to finally etc.).
988 if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses || ALWAYS_USE_FP)
990 cfg->frame_reg = frame_reg;
991 if (frame_reg != mips_sp) {
992 cfg->used_int_regs |= 1 << frame_reg;
997 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
998 /* FIXME: handle long and FP values */
999 switch (mono_type_get_underlying_type (sig->ret)->type) {
1000 case MONO_TYPE_VOID:
1003 cfg->ret->opcode = OP_REGVAR;
1004 cfg->ret->inst_c0 = mips_v0;
1008 /* Space for outgoing parameters, including a0-a3 */
1009 offset += cfg->param_area;
1011 /* allow room to save the return value (if it's a struct) */
1012 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1015 if (sig->call_convention == MONO_CALL_VARARG) {
1016 cfg->sig_cookie = MIPS_STACK_PARAM_OFFSET;
1019 /* Now handle the local variables */
1021 curinst = cfg->locals_start;
1022 for (i = curinst; i < cfg->num_varinfo; ++i) {
1023 inst = cfg->varinfo [i];
1024 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1027 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1028 * pinvoke wrappers when they call functions returning structure
1030 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1031 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
1033 size = mono_type_size (inst->inst_vtype, &align);
1035 offset += align - 1;
1036 offset &= ~(align - 1);
1037 inst->inst_offset = offset;
1038 inst->opcode = OP_REGOFFSET;
1039 inst->inst_basereg = frame_reg;
1041 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1044 /* Space for LMF (if needed) */
1046 if (cfg->method->save_lmf) {
1047 /* align the offset to 16 bytes */
1048 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1049 cfg->arch.lmf_offset = offset;
1050 offset += sizeof (MonoLMF);
1054 #if EXTRA_STACK_SPACE
1055 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1056 * args or return vals. Extra stack space avoids this in a lot of cases.
1060 /* Space for saved registers */
1061 cfg->arch.iregs_offset = offset;
1063 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
1065 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1067 if (iregs_to_save) {
1068 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1069 if (iregs_to_save & (1 << i)) {
1070 offset += sizeof (gulong);
1075 #if EXTRA_STACK_SPACE
1076 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1077 * args or return vals. Extra stack space avoids this in a lot of cases.
1082 /* saved float registers */
1084 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1085 if (fregs_to_restore) {
1086 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1087 if (fregs_to_restore & (1 << i)) {
1088 offset += sizeof (double);
1094 /* Now add space for saving the ra */
1098 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1099 cfg->stack_offset = offset;
1102 * Now allocate stack slots for the int arg regs (a0 - a3)
1103 * On MIPS o32, these are just above the incoming stack pointer
1104 * Even if the arg has been assigned to a regvar, it gets a stack slot
1107 /* Return struct-by-value results in a hidden first argument */
1108 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1109 cfg->vret_addr->opcode = OP_REGOFFSET;
1110 cfg->vret_addr->inst_c0 = mips_a0;
1111 cfg->vret_addr->inst_offset = offset;
1112 cfg->vret_addr->inst_basereg = frame_reg;
1116 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1117 inst = cfg->args [i];
1118 if (inst->opcode != OP_REGVAR) {
1121 if (sig->hasthis && (i == 0))
1122 arg_type = &mono_defaults.object_class->byval_arg;
1124 arg_type = sig->params [i - sig->hasthis];
1126 inst->opcode = OP_REGOFFSET;
1127 size = mono_type_size (arg_type, &align);
1133 inst->inst_basereg = frame_reg;
1134 offset = (offset + align - 1) & ~(align - 1);
1135 inst->inst_offset = offset;
1137 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1138 cfg->sig_cookie += size;
1139 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1142 /* Even a0-a3 get stack slots */
1143 size = sizeof (gpointer);
1144 align = sizeof (gpointer);
1145 inst->inst_basereg = frame_reg;
1146 offset = (offset + align - 1) & ~(align - 1);
1147 inst->inst_offset = offset;
1149 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1150 cfg->sig_cookie += size;
1151 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1157 mono_arch_create_vars (MonoCompile *cfg)
1159 MonoMethodSignature *sig;
1161 sig = mono_method_signature (cfg->method);
1163 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1164 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1165 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1166 printf ("vret_addr = ");
1167 mono_print_ins (cfg->vret_addr);
1172 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1173 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1177 * take the arguments and generate the arch-specific
1178 * instructions to properly call the function in call.
1179 * This includes pushing, moving arguments to the right register
1181 * Issue: who does the spilling if needed, and when?
1184 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
1186 MonoMethodSignature *sig;
1191 sig = call->signature;
1192 n = sig->param_count + sig->hasthis;
1194 cinfo = calculate_sizes (sig, sig->pinvoke);
1195 if (cinfo->struct_ret)
1196 call->used_iregs |= 1 << cinfo->struct_ret;
1198 for (i = 0; i < n; ++i) {
1199 ainfo = cinfo->args + i;
1200 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1202 cfg->disable_aot = TRUE;
1204 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1205 sig_arg->inst_p0 = call->signature;
1207 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1208 arg->inst_imm = cinfo->sig_cookie.offset;
1209 arg->inst_left = sig_arg;
1210 MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
1212 if (is_virtual && i == 0) {
1213 /* the argument will be attached to the call instrucion */
1214 in = call->args [i];
1215 call->used_iregs |= 1 << ainfo->reg;
1217 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1218 in = call->args [i];
1219 arg->cil_code = in->cil_code;
1220 arg->inst_left = in;
1221 arg->inst_call = call;
1222 arg->type = in->type;
1223 MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
1224 if (ainfo->regtype == RegTypeGeneral) {
1225 arg->backend.reg3 = ainfo->reg;
1226 call->used_iregs |= 1 << ainfo->reg;
1227 if (arg->type == STACK_I8)
1228 call->used_iregs |= 1 << (ainfo->reg + 1);
1229 } else if (ainfo->regtype == RegTypeStructByAddr) {
1230 /* FIXME: where is the data allocated? */
1231 arg->backend.reg3 = ainfo->reg;
1232 call->used_iregs |= 1 << ainfo->reg;
1233 } else if (ainfo->regtype == RegTypeStructByVal) {
1235 MonoMIPSArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMIPSArgInfo));
1236 /* mark the used regs */
1237 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1238 call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1240 arg->opcode = OP_OUTARG_VT;
1241 ai->reg = ainfo->reg;
1242 ai->size = ainfo->size;
1243 ai->vtsize = ainfo->vtsize;
1244 ai->offset = ainfo->offset;
1245 arg->backend.data = ai;
1247 g_printf ("OUTARG_VT reg=%d size=%d vtsize=%d offset=%d\n",
1248 ai->reg, ai->size, ai->vtsize, ai->offset);
1250 } else if (ainfo->regtype == RegTypeBase) {
1251 MonoMIPSArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMIPSArgInfo));
1252 g_assert(ainfo->reg == mips_sp);
1253 arg->opcode = OP_OUTARG_MEMBASE;
1254 ai->reg = ainfo->reg;
1255 ai->size = ainfo->size;
1256 ai->offset = ainfo->offset;
1257 arg->backend.data = ai;
1258 } else if (ainfo->regtype == RegTypeFP) {
1259 arg->opcode = OP_OUTARG_R8;
1260 arg->backend.reg3 = ainfo->reg;
1261 call->used_fregs |= 1 << ainfo->reg;
1262 if (ainfo->size == 4) {
1263 arg->opcode = OP_OUTARG_R4;
1264 /* we reduce the precision */
1266 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1267 conv->inst_left = arg->inst_left;
1268 arg->inst_left = conv;*/
1271 g_assert_not_reached ();
1275 call->stack_usage = cinfo->stack_usage;
1276 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1277 cfg->param_area = MAX (cfg->param_area, 16); /* a0-a3 always present */
1278 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1279 cfg->flags |= MONO_CFG_HAS_CALLS;
1281 * should set more info in call, such as the stack space
1282 * used by the args that needs to be added back to esp
1290 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1295 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1299 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1300 MonoInst *last_ins = mono_inst_list_prev (&ins->node, &bb->ins_list);
1302 switch (ins->opcode) {
1304 /* remove unnecessary multiplication with 1 */
1305 if (ins->inst_imm == 1) {
1306 if (ins->dreg != ins->sreg1) {
1307 ins->opcode = OP_MOVE;
1309 MONO_DELETE_INS (bb, ins);
1313 int power2 = mono_is_power_of_two (ins->inst_imm);
1315 ins->opcode = OP_SHL_IMM;
1316 ins->inst_imm = power2;
1320 case OP_LOAD_MEMBASE:
1321 case OP_LOADI4_MEMBASE:
1323 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1324 * OP_LOAD_MEMBASE offset(basereg), reg
1326 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1327 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1328 ins->inst_basereg == last_ins->inst_destbasereg &&
1329 ins->inst_offset == last_ins->inst_offset) {
1330 if (ins->dreg == last_ins->sreg1) {
1331 MONO_DELETE_INS (bb, ins);
1334 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1335 ins->opcode = OP_MOVE;
1336 ins->sreg1 = last_ins->sreg1;
1341 * Note: reg1 must be different from the basereg in the second load
1342 * OP_LOAD_MEMBASE offset(basereg), reg1
1343 * OP_LOAD_MEMBASE offset(basereg), reg2
1345 * OP_LOAD_MEMBASE offset(basereg), reg1
1346 * OP_MOVE reg1, reg2
1348 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1349 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1350 ins->inst_basereg != last_ins->dreg &&
1351 ins->inst_basereg == last_ins->inst_basereg &&
1352 ins->inst_offset == last_ins->inst_offset) {
1354 if (ins->dreg == last_ins->dreg) {
1355 MONO_DELETE_INS (bb, ins);
1358 ins->opcode = OP_MOVE;
1359 ins->sreg1 = last_ins->dreg;
1362 //g_assert_not_reached ();
1367 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1368 * OP_LOAD_MEMBASE offset(basereg), reg
1370 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1371 * OP_ICONST reg, imm
1373 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1374 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1375 ins->inst_basereg == last_ins->inst_destbasereg &&
1376 ins->inst_offset == last_ins->inst_offset) {
1377 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1378 ins->opcode = OP_ICONST;
1379 ins->inst_c0 = last_ins->inst_imm;
1380 g_assert_not_reached (); // check this rule
1385 case OP_LOADU1_MEMBASE:
1386 case OP_LOADI1_MEMBASE:
1387 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1388 ins->inst_basereg == last_ins->inst_destbasereg &&
1389 ins->inst_offset == last_ins->inst_offset) {
1390 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? CEE_CONV_I1 : CEE_CONV_U1;
1391 ins->sreg1 = last_ins->sreg1;
1394 case OP_LOADU2_MEMBASE:
1395 case OP_LOADI2_MEMBASE:
1396 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1397 ins->inst_basereg == last_ins->inst_destbasereg &&
1398 ins->inst_offset == last_ins->inst_offset) {
1399 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? CEE_CONV_I2 : CEE_CONV_U2;
1400 ins->sreg1 = last_ins->sreg1;
1406 ins->opcode = OP_MOVE;
1410 if (ins->dreg == ins->sreg1) {
1411 MONO_DELETE_INS (bb, ins);
1415 * OP_MOVE sreg, dreg
1416 * OP_MOVE dreg, sreg
1418 if (last_ins && last_ins->opcode == OP_MOVE &&
1419 ins->sreg1 == last_ins->dreg &&
1420 ins->dreg == last_ins->sreg1) {
1421 MONO_DELETE_INS (bb, ins);
1429 #define NEW_INS(cfg,ins,dest,op) do { \
1430 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1431 (dest)->opcode = (op); \
1432 MONO_INST_LIST_ADD_TAIL (&(dest)->node, &(ins)->node); \
1436 map_to_reg_reg_op (int op)
1445 case OP_COMPARE_IMM:
1461 case OP_LOAD_MEMBASE:
1462 return OP_LOAD_MEMINDEX;
1463 case OP_LOADI4_MEMBASE:
1464 return OP_LOADI4_MEMINDEX;
1465 case OP_LOADU4_MEMBASE:
1466 return OP_LOADU4_MEMINDEX;
1467 case OP_LOADU1_MEMBASE:
1468 return OP_LOADU1_MEMINDEX;
1469 case OP_LOADI2_MEMBASE:
1470 return OP_LOADI2_MEMINDEX;
1471 case OP_LOADU2_MEMBASE:
1472 return OP_LOADU2_MEMINDEX;
1473 case OP_LOADI1_MEMBASE:
1474 return OP_LOADI1_MEMINDEX;
1475 case OP_LOADR4_MEMBASE:
1476 return OP_LOADR4_MEMINDEX;
1477 case OP_LOADR8_MEMBASE:
1478 return OP_LOADR8_MEMINDEX;
1479 case OP_STOREI1_MEMBASE_REG:
1480 return OP_STOREI1_MEMINDEX;
1481 case OP_STOREI2_MEMBASE_REG:
1482 return OP_STOREI2_MEMINDEX;
1483 case OP_STOREI4_MEMBASE_REG:
1484 return OP_STOREI4_MEMINDEX;
1485 case OP_STORE_MEMBASE_REG:
1486 return OP_STORE_MEMINDEX;
1487 case OP_STORER4_MEMBASE_REG:
1488 return OP_STORER4_MEMINDEX;
1489 case OP_STORER8_MEMBASE_REG:
1490 return OP_STORER8_MEMINDEX;
1491 case OP_STORE_MEMBASE_IMM:
1492 return OP_STORE_MEMBASE_REG;
1493 case OP_STOREI1_MEMBASE_IMM:
1494 return OP_STOREI1_MEMBASE_REG;
1495 case OP_STOREI2_MEMBASE_IMM:
1496 return OP_STOREI2_MEMBASE_REG;
1497 case OP_STOREI4_MEMBASE_IMM:
1498 return OP_STOREI4_MEMBASE_REG;
1500 g_assert_not_reached ();
1504 * Remove from the instruction list the instructions that can't be
1505 * represented with very simple instructions with no register
1509 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1511 MonoInst *ins, *next, *temp;
1514 /* setup the virtual reg allocator */
1515 if (bb->max_vreg > cfg->rs->next_vreg)
1516 cfg->rs->next_vreg = bb->max_vreg;
1518 MONO_BB_FOR_EACH_INS (bb, ins) {
1520 switch (ins->opcode) {
1523 if (!mips_is_imm16 (ins->inst_imm)) {
1524 NEW_INS (cfg, ins, temp, OP_ICONST);
1525 temp->inst_c0 = ins->inst_imm;
1526 temp->dreg = mono_regstate_next_int (cfg->rs);
1527 ins->sreg2 = temp->dreg;
1528 ins->opcode = map_to_reg_reg_op (ins->opcode);
1533 if (!mips_is_imm16 (-ins->inst_imm)) {
1534 NEW_INS (cfg, ins, temp, OP_ICONST);
1535 temp->inst_c0 = ins->inst_imm;
1536 temp->dreg = mono_regstate_next_int (cfg->rs);
1537 ins->sreg2 = temp->dreg;
1538 ins->opcode = map_to_reg_reg_op (ins->opcode);
1546 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
1547 NEW_INS (cfg, ins, temp, OP_ICONST);
1548 temp->inst_c0 = ins->inst_imm;
1549 temp->dreg = mono_regstate_next_int (cfg->rs);
1550 ins->sreg2 = temp->dreg;
1551 ins->opcode = map_to_reg_reg_op (ins->opcode);
1559 NEW_INS (cfg, ins, temp, OP_ICONST);
1560 temp->inst_c0 = ins->inst_imm;
1561 temp->dreg = mono_regstate_next_int (cfg->rs);
1562 ins->sreg2 = temp->dreg;
1563 ins->opcode = map_to_reg_reg_op (ins->opcode);
1567 case OP_COMPARE_IMM:
1568 next = mono_inst_list_next (&ins->node, &bb->ins_list);
1570 if (compare_opcode_is_unsigned (next->opcode)) {
1571 if (!ppc_is_uimm16 (ins->inst_imm)) {
1572 NEW_INS (cfg, ins, temp, OP_ICONST);
1573 temp->inst_c0 = ins->inst_imm;
1574 temp->dreg = mono_regstate_next_int (cfg->rs);
1575 ins->sreg2 = temp->dreg;
1576 ins->opcode = map_to_reg_reg_op (ins->opcode);
1579 if (!ppc_is_imm16 (ins->inst_imm)) {
1580 NEW_INS (cfg, ins, temp, OP_ICONST);
1581 temp->inst_c0 = ins->inst_imm;
1582 temp->dreg = mono_regstate_next_int (cfg->rs);
1583 ins->sreg2 = temp->dreg;
1584 ins->opcode = map_to_reg_reg_op (ins->opcode);
1591 if (ins->inst_imm == 1) {
1592 ins->opcode = OP_MOVE;
1595 if (ins->inst_imm == 0) {
1596 ins->opcode = OP_ICONST;
1600 imm = mono_is_power_of_two (ins->inst_imm);
1602 ins->opcode = OP_SHL_IMM;
1603 ins->inst_imm = imm;
1606 if (!ppc_is_imm16 (ins->inst_imm)) {
1607 NEW_INS (cfg, ins, temp, OP_ICONST);
1608 temp->inst_c0 = ins->inst_imm;
1609 temp->dreg = mono_regstate_next_int (cfg->rs);
1610 ins->sreg2 = temp->dreg;
1611 ins->opcode = map_to_reg_reg_op (ins->opcode);
1616 case OP_LOAD_MEMBASE:
1617 case OP_LOADI4_MEMBASE:
1618 case OP_LOADU4_MEMBASE:
1619 case OP_LOADI2_MEMBASE:
1620 case OP_LOADU2_MEMBASE:
1621 case OP_LOADI1_MEMBASE:
1622 case OP_LOADU1_MEMBASE:
1623 case OP_LOADR4_MEMBASE:
1624 case OP_LOADR8_MEMBASE:
1625 case OP_STORE_MEMBASE_REG:
1626 case OP_STOREI4_MEMBASE_REG:
1627 case OP_STOREI2_MEMBASE_REG:
1628 case OP_STOREI1_MEMBASE_REG:
1629 case OP_STORER4_MEMBASE_REG:
1630 case OP_STORER8_MEMBASE_REG:
1631 /* we can do two things: load the immed in a register
1632 * and use an indexed load, or see if the immed can be
1633 * represented as an ad_imm + a load with a smaller offset
1634 * that fits. We just do the first for now, optimize later.
1636 if (ppc_is_imm16 (ins->inst_offset))
1638 NEW_INS (cfg, ins, temp, OP_ICONST);
1639 temp->inst_c0 = ins->inst_offset;
1640 temp->dreg = mono_regstate_next_int (cfg->rs);
1641 ins->sreg2 = temp->dreg;
1642 ins->opcode = map_to_reg_reg_op (ins->opcode);
1645 case OP_STORE_MEMBASE_IMM:
1646 case OP_STOREI1_MEMBASE_IMM:
1647 case OP_STOREI2_MEMBASE_IMM:
1648 case OP_STOREI4_MEMBASE_IMM:
1649 if (!ins->inst_imm) {
1650 ins->sreg1 = mips_zero;
1651 ins->opcode = map_to_reg_reg_op (ins->opcode);
1654 NEW_INS (cfg, ins, temp, OP_ICONST);
1655 temp->inst_c0 = ins->inst_imm;
1656 temp->dreg = mono_regstate_next_int (cfg->rs);
1657 ins->sreg1 = temp->dreg;
1658 ins->opcode = map_to_reg_reg_op (ins->opcode);
1659 goto loop_start; /* make it handle the possibly big ins->inst_offset */
1664 bb->max_vreg = cfg->rs->next_vreg;
1668 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
1670 /* sreg is a float, dreg is an integer reg. mips_at is used a scratch */
1672 mips_truncwd (code, mips_ftemp, sreg);
1674 mips_cvtwd (code, mips_ftemp, sreg);
1676 mips_mfc1 (code, dreg, mips_ftemp);
1679 mips_andi (code, dreg, dreg, 0xff);
1680 else if (size == 2) {
1681 mips_sll (code, dreg, dreg, 16);
1682 mips_srl (code, dreg, dreg, 16);
1686 mips_sll (code, dreg, dreg, 24);
1687 mips_sra (code, dreg, dreg, 24);
1689 else if (size == 2) {
1690 mips_sll (code, dreg, dreg, 16);
1691 mips_sra (code, dreg, dreg, 16);
1698 * emit_load_volatile_arguments:
1700 * Load volatile arguments from the stack to the original input registers.
1701 * Required before a tail call.
1704 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
1706 MonoMethod *method = cfg->method;
1707 MonoMethodSignature *sig;
1712 sig = mono_method_signature (method);
1713 cinfo = calculate_sizes (sig, sig->pinvoke);
1714 if (cinfo->struct_ret) {
1715 ArgInfo *ainfo = &cinfo->ret;
1716 inst = cfg->vret_addr;
1717 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1720 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1721 ArgInfo *ainfo = cinfo->args + i;
1722 inst = cfg->args [i];
1723 if (inst->opcode == OP_REGVAR) {
1724 if (ainfo->regtype == RegTypeGeneral)
1725 mips_move (code, ainfo->reg, inst->dreg);
1726 else if (ainfo->regtype == RegTypeFP)
1727 g_assert_not_reached();
1728 else if (ainfo->regtype == RegTypeBase) {
1731 g_assert_not_reached ();
1733 if (ainfo->regtype == RegTypeGeneral) {
1734 g_assert (mips_is_imm16 (inst->inst_offset));
1735 switch (ainfo->size) {
1737 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1740 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1744 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1747 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1748 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
1751 g_assert_not_reached ();
1754 } else if (ainfo->regtype == RegTypeBase) {
1756 } else if (ainfo->regtype == RegTypeFP) {
1757 g_assert (mips_is_imm16 (inst->inst_offset));
1758 if (ainfo->size == 8)
1759 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1760 else if (ainfo->size == 4)
1761 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1763 g_assert_not_reached ();
1764 } else if (ainfo->regtype == RegTypeStructByVal) {
1766 int doffset = inst->inst_offset;
1768 g_assert (mips_is_imm16 (inst->inst_offset));
1769 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
1770 for (i = 0; i < ainfo->size; ++i) {
1771 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
1772 doffset += sizeof (gpointer);
1774 } else if (ainfo->regtype == RegTypeStructByAddr) {
1775 g_assert (mips_is_imm16 (inst->inst_offset));
1776 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
1778 g_assert_not_reached ();
1788 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
1793 guint8 *code = cfg->native_code + cfg->code_len;
1794 guint last_offset = 0;
1798 /* we don't align basic blocks of loops on mips */
1800 if (cfg->verbose_level > 2)
1801 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
1803 cpos = bb->max_offset;
1806 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
1807 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
1808 g_assert (!mono_compile_aot);
1811 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
1812 /* this is not thread save, but good enough */
1813 /* fixme: howto handle overflows? */
1814 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
1815 mips_lw (code, mips_temp, mips_at, 0);
1816 mips_addiu (code, mips_temp, mips_temp, 1);
1817 mips_sw (code, mips_temp, mips_at, 0);
1820 MONO_BB_FOR_EACH_INS (bb, ins) {
1821 offset = code - cfg->native_code;
1823 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
1825 if (offset > (cfg->code_size - max_len - 16)) {
1826 cfg->code_size *= 2;
1827 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1828 code = cfg->native_code + offset;
1830 mono_debug_record_line_number (cfg, ins, offset);
1831 if (cfg->verbose_level > 2) {
1832 g_print (" @ 0x%x\t", offset);
1833 mono_print_ins (ins_cnt++, ins);
1836 switch (ins->opcode) {
1838 g_assert_not_reached();
1840 emit_tls_access (code, ins->dreg, ins->inst_offset);
1844 mips_mult (code, ins->sreg1, ins->sreg2);
1845 mips_mflo (code, ins->dreg);
1846 mips_mfhi (code, ins->dreg+1);
1849 mips_multu (code, ins->sreg1, ins->sreg2);
1850 mips_mflo (code, ins->dreg);
1851 mips_mfhi (code, ins->dreg+1);
1853 case OP_MEMORY_BARRIER:
1858 case OP_STOREI1_MEMBASE_IMM:
1859 mips_load_const (code, mips_temp, ins->inst_imm);
1860 if (mips_is_imm16 (ins->inst_offset)) {
1861 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
1863 mips_load_const (code, mips_at, ins->inst_offset);
1864 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
1867 case OP_STOREI2_MEMBASE_IMM:
1868 mips_load_const (code, mips_temp, ins->inst_imm);
1869 if (mips_is_imm16 (ins->inst_offset)) {
1870 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
1872 mips_load_const (code, mips_at, ins->inst_offset);
1873 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
1876 case OP_STORE_MEMBASE_IMM:
1877 case OP_STOREI4_MEMBASE_IMM:
1878 mips_load_const (code, mips_temp, ins->inst_imm);
1879 if (mips_is_imm16 (ins->inst_offset)) {
1880 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
1882 mips_load_const (code, mips_at, ins->inst_offset);
1883 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
1886 case OP_STOREI1_MEMBASE_REG:
1887 if (mips_is_imm16 (ins->inst_offset)) {
1888 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1890 mips_load_const (code, mips_at, ins->inst_offset);
1891 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
1892 mips_sb (code, ins->sreg1, mips_at, 0);
1895 case OP_STOREI2_MEMBASE_REG:
1896 if (mips_is_imm16 (ins->inst_offset)) {
1897 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1899 mips_load_const (code, mips_at, ins->inst_offset);
1900 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
1901 mips_sh (code, ins->sreg1, mips_at, 0);
1904 case OP_STORE_MEMBASE_REG:
1905 case OP_STOREI4_MEMBASE_REG:
1906 if (mips_is_imm16 (ins->inst_offset)) {
1907 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1909 mips_load_const (code, mips_at, ins->inst_offset);
1910 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
1911 mips_sw (code, ins->sreg1, mips_at, 0);
1915 g_assert_not_reached ();
1916 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
1917 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
1919 case OP_LOAD_MEMBASE:
1920 case OP_LOADI4_MEMBASE:
1921 case OP_LOADU4_MEMBASE:
1922 if (mips_is_imm16 (ins->inst_offset)) {
1923 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1925 mips_load_const (code, mips_at, ins->inst_offset);
1926 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1927 mips_lw (code, ins->dreg, mips_at, 0);
1930 case OP_LOADI1_MEMBASE:
1931 if (mips_is_imm16 (ins->inst_offset)) {
1932 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1934 mips_load_const (code, mips_at, ins->inst_offset);
1935 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1936 mips_lb (code, ins->dreg, mips_at, 0);
1939 case OP_LOADU1_MEMBASE:
1940 if (mips_is_imm16 (ins->inst_offset)) {
1941 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1943 mips_load_const (code, mips_at, ins->inst_offset);
1944 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1945 mips_lbu (code, ins->dreg, mips_at, 0);
1948 case OP_LOADI2_MEMBASE:
1949 if (mips_is_imm16 (ins->inst_offset)) {
1950 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1952 mips_load_const (code, mips_at, ins->inst_offset);
1953 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1954 mips_lh (code, ins->dreg, mips_at, 0);
1957 case OP_LOADU2_MEMBASE:
1958 if (mips_is_imm16 (ins->inst_offset)) {
1959 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1961 mips_load_const (code, mips_at, ins->inst_offset);
1962 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1963 mips_lhu (code, ins->dreg, mips_at, 0);
1967 mips_sll (code, mips_at, ins->sreg1, 24);
1968 mips_sra (code, ins->dreg, mips_at, 24);
1971 mips_sll (code, mips_at, ins->sreg1, 16);
1972 mips_sra (code, ins->dreg, mips_at, 16);
1975 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
1978 mips_sll (code, mips_at, ins->sreg1, 16);
1979 mips_srl (code, ins->dreg, mips_at, 16);
1982 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
1985 g_assert (mips_is_imm16 (ins->inst_imm));
1986 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
1989 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
1992 g_assert (mips_is_imm16 (ins->inst_imm));
1993 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
1995 case OP_COMPARE_IMM:
1996 g_assert_not_reached ();
1999 g_assert_not_reached ();
2002 mips_break (code, 0xfd);
2005 g_assert_not_reached ();
2008 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
2011 g_assert_not_reached ();
2014 g_assert_not_reached ();
2017 if (mips_is_imm16 (ins->inst_imm)) {
2018 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
2020 mips_load_const (code, mips_at, ins->inst_imm);
2021 mips_addu (code, ins->dreg, ins->sreg1, mips_at);
2025 g_assert_not_reached ();
2028 /* rewritten in .brg file */
2029 g_assert_not_reached ();
2031 case CEE_ADD_OVF_UN:
2032 /* rewritten in .brg file */
2033 g_assert_not_reached ();
2036 /* rewritten in .brg file */
2037 g_assert_not_reached ();
2039 case CEE_SUB_OVF_UN:
2040 /* rewritten in .brg file */
2041 g_assert_not_reached ();
2043 case OP_ADD_OVF_CARRY:
2044 /* rewritten in .brg file */
2045 g_assert_not_reached ();
2047 case OP_ADD_OVF_UN_CARRY:
2048 /* rewritten in .brg file */
2049 g_assert_not_reached ();
2051 case OP_SUB_OVF_CARRY:
2052 /* rewritten in .brg file */
2053 g_assert_not_reached ();
2055 case OP_SUB_OVF_UN_CARRY:
2056 /* rewritten in .brg file */
2057 g_assert_not_reached ();
2060 /* rewritten in .brg file */
2061 g_assert_not_reached ();
2064 /* rewritten in .brg file */
2065 g_assert_not_reached ();
2068 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
2071 g_assert_not_reached ();
2074 // we add the negated value
2075 if (mips_is_imm16 (-ins->inst_imm))
2076 mips_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2078 mips_load_const (code, mips_at, ins->inst_imm);
2079 mips_subu (code, ins->dreg, ins->sreg1, mips_at);
2083 g_assert_not_reached ();
2086 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2089 if (mips_is_imm16 (ins->inst_imm)) {
2090 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2092 mips_load_const (code, mips_at, ins->inst_imm);
2093 mips_and (code, ins->dreg, ins->sreg1, mips_at);
2098 guint32 *divisor_is_m1;
2099 guint32 *divisor_is_zero;
2102 mips_addiu (code, mips_at, mips_zero, 0xffff);
2103 divisor_is_m1 = (guint32 *)code;
2104 mips_bne (code, ins->sreg2, mips_at, 0);
2107 /* Divide by -1 -- throw exception */
2108 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
2110 mips_patch (divisor_is_m1, (guint32)code);
2112 /* Put divide in branch delay slot (NOT YET) */
2113 divisor_is_zero = (guint32 *)code;
2114 mips_bne (code, ins->sreg2, mips_zero, 0);
2117 /* Divide by zero -- throw exception */
2118 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2120 mips_patch (divisor_is_zero, (guint32)code);
2121 mips_div (code, ins->sreg1, ins->sreg2);
2122 if (ins->opcode == CEE_DIV)
2123 mips_mflo (code, ins->dreg);
2125 mips_mfhi (code, ins->dreg);
2129 guint32 *divisor_is_zero = (guint32 *)(void *)code;
2131 /* Put divide in branch delay slot (NOT YET) */
2132 mips_bne (code, ins->sreg2, mips_zero, 0);
2135 /* Divide by zero -- throw exception */
2136 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2138 mips_patch (divisor_is_zero, (guint32)code);
2139 mips_divu (code, ins->sreg1, ins->sreg2);
2140 mips_mflo (code, ins->dreg);
2144 g_assert_not_reached ();
2146 ppc_load (code, ppc_r11, ins->inst_imm);
2147 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
2148 ppc_mfspr (code, ppc_r0, ppc_xer);
2149 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2150 /* FIXME: use OverflowException for 0x80000000/-1 */
2151 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2153 g_assert_not_reached();
2156 guint32 *divisor_is_zero = (guint32 *)(void *)code;
2158 /* Put divide in branch delay slot (NOT YET) */
2159 mips_bne (code, ins->sreg2, mips_zero, 0);
2162 /* Divide by zero -- throw exception */
2163 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2165 mips_patch (divisor_is_zero, (guint32)code);
2166 mips_divu (code, ins->sreg1, ins->sreg2);
2167 mips_mfhi (code, ins->dreg);
2171 g_assert_not_reached ();
2173 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2176 if (mips_is_imm16 (ins->inst_imm)) {
2177 mips_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2179 mips_load_const (code, mips_at, ins->inst_imm);
2180 mips_or (code, ins->dreg, ins->sreg1, mips_at);
2184 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2187 /* unsigned 16-bit immediate */
2188 if ((ins->inst_imm & 0xffff) == ins->inst_imm) {
2189 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
2191 mips_load_const (code, mips_at, ins->inst_imm);
2192 mips_xor (code, ins->dreg, ins->sreg1, mips_at);
2196 g_assert (mips_is_imm16 (ins->inst_imm));
2197 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
2200 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
2203 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2206 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
2209 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2212 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2215 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
2218 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
2221 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
2225 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
2227 mips_mult (code, ins->sreg1, ins->sreg2);
2228 mips_mflo (code, ins->dreg);
2234 mips_load_const (code, mips_at, ins->inst_imm);
2236 mips_mul (code, ins->dreg, ins->sreg1, mips_at);
2238 mips_mult (code, ins->sreg1, mips_at);
2239 mips_mflo (code, ins->dreg);
2246 mips_mult (code, ins->sreg1, ins->sreg2);
2247 mips_mflo (code, ins->dreg);
2248 mips_mfhi (code, mips_at);
2251 mips_sra (code, mips_temp, ins->dreg, 31);
2252 patch = (guint32 *)(void *)code;
2253 mips_beq (code, mips_temp, mips_at, 0);
2255 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
2256 mips_patch (patch, (guint32)code);
2259 case CEE_MUL_OVF_UN:
2261 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
2263 mips_mult (code, ins->sreg1, ins->sreg2);
2264 mips_mflo (code, ins->dreg);
2265 mips_mfhi (code, mips_at);
2269 /* XXX - Throw exception if we overflowed */
2272 mips_load_const (code, ins->dreg, ins->inst_c0);
2275 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2276 mips_load (code, ins->dreg, 0);
2280 mips_mtc1 (code, ins->dreg, ins->sreg1);
2283 mips_mfc1 (code, ins->dreg, ins->sreg1);
2286 mips_dmtc1 (code, ins->dreg, ins->sreg1);
2289 mips_dmfc1 (code, ins->dreg, ins->sreg1);
2295 if (ins->dreg != ins->sreg1)
2296 mips_move (code, ins->dreg, ins->sreg1);
2299 /* Get sreg1 into v1, sreg2 into v0 */
2301 if (ins->sreg1 == mips_v0) {
2302 if (ins->sreg1 != mips_at)
2303 mips_move (code, mips_at, ins->sreg1);
2304 if (ins->sreg2 != mips_v0)
2305 mips_move (code, mips_v0, ins->sreg2);
2306 mips_move (code, mips_v1, mips_at);
2309 if (ins->sreg2 != mips_v0)
2310 mips_move (code, mips_v0, ins->sreg2);
2311 if (ins->sreg1 != mips_v1)
2312 mips_move (code, mips_v1, ins->sreg1);
2316 if (ins->dreg != ins->sreg1) {
2317 mips_fmovd (code, ins->dreg, ins->sreg1);
2321 /* Convert from double to float and leave it there */
2322 mips_cvtsd (code, ins->dreg, ins->sreg1);
2324 case OP_FCONV_TO_R4:
2325 /* Convert from double to float and back again */
2326 mips_cvtsd (code, ins->dreg, ins->sreg1);
2327 mips_cvtds (code, ins->dreg, ins->dreg);
2330 code = emit_load_volatile_arguments(cfg, code);
2333 * Pop our stack, then jump to specified method (tail-call)
2334 * Keep in sync with mono_arch_emit_epilog
2336 code = mono_arch_emit_epilog_sub (cfg, code);
2338 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
2339 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2341 mips_lui (code, mips_t9, mips_zero, 0);
2342 mips_addiu (code, mips_t9, mips_t9, 0);
2343 mips_jr (code, mips_t9);
2346 mips_beq (code, mips_zero, mips_zero, 0);
2351 /* ensure ins->sreg1 is not NULL */
2352 mips_lw (code, mips_zero, ins->sreg1, 0);
2355 if (mips_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2356 mips_addiu (code, mips_at, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2358 mips_load_const (code, mips_at, cfg->sig_cookie + cfg->stack_usage);
2359 mips_addu (code, mips_at, cfg->frame_reg, mips_at);
2361 mips_sw (code, mips_at, ins->sreg1, 0);
2372 case OP_VOIDCALL_REG:
2374 case OP_FCALL_MEMBASE:
2375 case OP_LCALL_MEMBASE:
2376 case OP_VCALL_MEMBASE:
2377 case OP_VOIDCALL_MEMBASE:
2378 case OP_CALL_MEMBASE:
2379 call = (MonoCallInst*)ins;
2380 switch (ins->opcode) {
2386 if (ins->flags & MONO_INST_HAS_METHOD)
2387 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2389 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2390 mips_lui (code, mips_t9, mips_zero, 0);
2391 mips_addiu (code, mips_t9, mips_t9, 0);
2396 case OP_VOIDCALL_REG:
2398 mips_move (code, mips_t9, ins->sreg1);
2400 case OP_FCALL_MEMBASE:
2401 case OP_LCALL_MEMBASE:
2402 case OP_VCALL_MEMBASE:
2403 case OP_VOIDCALL_MEMBASE:
2404 case OP_CALL_MEMBASE:
2405 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
2408 mips_jalr (code, mips_t9, mips_ra);
2410 if ((ins->opcode == OP_FCALL ||
2411 ins->opcode == OP_FCALL_REG) &&
2412 call->signature->ret->type == MONO_TYPE_R4) {
2413 mips_cvtds (code, mips_f0, mips_f0);
2417 g_assert_not_reached ();
2420 int area_offset = cfg->param_area;
2422 /* Round up ins->sreg1, mips_at ends up holding size */
2423 mips_addiu (code, mips_at, ins->sreg1, 31);
2424 mips_andi (code, mips_at, mips_at, ~31);
2426 mips_subu (code, mips_sp, mips_sp, mips_at);
2427 mips_addiu (code, ins->dreg, mips_sp, area_offset);
2429 if (ins->flags & MONO_INST_INIT) {
2430 mips_move (code, mips_temp, ins->dreg);
2431 mips_sb (code, mips_zero, mips_temp, 0);
2432 mips_addiu (code, mips_at, mips_at, -1);
2433 mips_bne (code, mips_at, mips_zero, -4);
2434 mips_addiu (code, mips_temp, mips_temp, 1);
2439 gpointer addr = mono_arch_get_throw_exception();
2440 mips_move (code, mips_a0, ins->sreg1);
2441 mips_load_const (code, mips_t9, addr);
2442 mips_jalr (code, mips_t9, mips_ra);
2444 mips_break (code, 0xfc);
2448 gpointer addr = mono_arch_get_rethrow_exception();
2449 mips_move (code, mips_a0, ins->sreg1);
2450 mips_load_const (code, mips_t9, addr);
2451 mips_jalr (code, mips_t9, mips_ra);
2453 mips_break (code, 0xfb);
2456 case OP_START_HANDLER:
2458 * The START_HANDLER instruction marks the beginning of a handler
2459 * block. It is called using a call instruction, so mips_ra contains
2460 * the return address. Since the handler executes in the same stack
2461 * frame as the method itself, we can't use save/restore to save
2462 * the return address. Instead, we save it into a dedicated
2465 if (mips_is_imm16 (ins->inst_left->inst_offset)) {
2466 mips_sw (code, mips_ra, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2468 mips_load_const (code, mips_at, ins->inst_left->inst_offset);
2469 mips_add (code, mips_at, mips_at, ins->inst_left->inst_basereg);
2470 mips_sw (code, mips_ra, mips_at, 0);
2474 if (ins->sreg1 != mips_v0)
2475 mips_move (code, mips_v0, ins->sreg1);
2476 if (mips_is_imm16 (ins->inst_left->inst_offset)) {
2477 mips_lw (code, mips_ra, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2479 mips_load_const (code, mips_at, ins->inst_left->inst_offset);
2480 mips_addu (code, mips_at, mips_at, ins->inst_left->inst_basereg);
2481 mips_lw (code, mips_ra, mips_at, 0);
2483 mips_jr (code, mips_ra);
2487 mips_lw (code, mips_t9, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2488 mips_jalr (code, mips_t9, mips_ra);
2491 case OP_CALL_HANDLER:
2492 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2493 mips_lui (code, mips_t9, mips_zero, 0);
2494 mips_addiu (code, mips_t9, mips_t9, 0);
2495 mips_jalr (code, mips_t9, mips_ra);
2499 ins->inst_c0 = code - cfg->native_code;
2502 if (ins->flags & MONO_INST_BRLABEL) {
2503 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2505 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2508 mips_lui (code, mips_at, mips_zero, 0);
2509 mips_addiu (code, mips_at, mips_at, 0);
2510 mips_jr (code, mips_at);
2513 mips_beq (code, mips_zero, mips_zero, 0);
2518 mips_jr (code, ins->sreg1);
2524 max_len += 4 * GPOINTER_TO_INT (ins->klass);
2525 if (offset > (cfg->code_size - max_len - 16)) {
2526 cfg->code_size += max_len;
2527 cfg->code_size *= 2;
2528 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2529 code = cfg->native_code + offset;
2531 g_assert (ins->sreg1 != -1);
2532 mips_sll (code, mips_at, ins->sreg1, 2);
2533 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
2534 mips_move (code, mips_t8, mips_ra);
2535 mips_bgezal (code, mips_zero, 1); /* bal */
2537 mips_addu (code, mips_t9, mips_ra, mips_at);
2538 /* Table is 16 or 20 bytes from target of bal above */
2539 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
2540 mips_move (code, mips_ra, mips_t8);
2541 mips_lw (code, mips_t9, mips_t9, 20);
2544 mips_lw (code, mips_t9, mips_t9, 16);
2545 mips_jalr (code, mips_t9, mips_t8);
2547 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
2548 mips_emit32 (code, 0xfefefefe);
2552 mips_addiu (code, ins->dreg, mips_zero, 1);
2553 mips_beq (code, mips_at, mips_zero, 2);
2555 mips_move (code, ins->dreg, mips_zero);
2559 mips_addiu (code, ins->dreg, mips_zero, 1);
2560 mips_bltz (code, mips_at, 2);
2562 mips_move (code, ins->dreg, mips_zero);
2566 mips_addiu (code, ins->dreg, mips_zero, 1);
2567 mips_bgtz (code, mips_at, 2);
2569 mips_move (code, ins->dreg, mips_zero);
2572 case OP_COND_EXC_EQ:
2573 case OP_COND_EXC_GE:
2574 case OP_COND_EXC_GT:
2575 case OP_COND_EXC_LE:
2576 case OP_COND_EXC_LT:
2577 case OP_COND_EXC_NE_UN:
2578 case OP_COND_EXC_GE_UN:
2579 case OP_COND_EXC_GT_UN:
2580 case OP_COND_EXC_LE_UN:
2581 case OP_COND_EXC_LT_UN:
2583 case OP_COND_EXC_OV:
2584 case OP_COND_EXC_NO:
2586 case OP_COND_EXC_NC:
2588 case OP_COND_EXC_IEQ:
2589 case OP_COND_EXC_IGE:
2590 case OP_COND_EXC_IGT:
2591 case OP_COND_EXC_ILE:
2592 case OP_COND_EXC_ILT:
2593 case OP_COND_EXC_INE_UN:
2594 case OP_COND_EXC_IGE_UN:
2595 case OP_COND_EXC_IGT_UN:
2596 case OP_COND_EXC_ILE_UN:
2597 case OP_COND_EXC_ILT_UN:
2599 case OP_COND_EXC_IOV:
2600 case OP_COND_EXC_INO:
2601 case OP_COND_EXC_IC:
2602 case OP_COND_EXC_INC:
2603 /* Should be re-mapped to OP_MIPS_B* by *.inssel-mips.brg */
2604 g_warning ("unsupported conditional exception %s\n", mono_inst_name (ins->opcode));
2605 g_assert_not_reached ();
2608 case OP_MIPS_COND_EXC_EQ:
2609 case OP_MIPS_COND_EXC_GE:
2610 case OP_MIPS_COND_EXC_GT:
2611 case OP_MIPS_COND_EXC_LE:
2612 case OP_MIPS_COND_EXC_LT:
2613 case OP_MIPS_COND_EXC_NE_UN:
2614 case OP_MIPS_COND_EXC_GE_UN:
2615 case OP_MIPS_COND_EXC_GT_UN:
2616 case OP_MIPS_COND_EXC_LE_UN:
2617 case OP_MIPS_COND_EXC_LT_UN:
2619 case OP_MIPS_COND_EXC_OV:
2620 case OP_MIPS_COND_EXC_NO:
2621 case OP_MIPS_COND_EXC_C:
2622 case OP_MIPS_COND_EXC_NC:
2624 case OP_MIPS_COND_EXC_IEQ:
2625 case OP_MIPS_COND_EXC_IGE:
2626 case OP_MIPS_COND_EXC_IGT:
2627 case OP_MIPS_COND_EXC_ILE:
2628 case OP_MIPS_COND_EXC_ILT:
2629 case OP_MIPS_COND_EXC_INE_UN:
2630 case OP_MIPS_COND_EXC_IGE_UN:
2631 case OP_MIPS_COND_EXC_IGT_UN:
2632 case OP_MIPS_COND_EXC_ILE_UN:
2633 case OP_MIPS_COND_EXC_ILT_UN:
2635 case OP_MIPS_COND_EXC_IOV:
2636 case OP_MIPS_COND_EXC_INO:
2637 case OP_MIPS_COND_EXC_IC:
2638 case OP_MIPS_COND_EXC_INC: {
2642 /* If the condition is true, raise the exception */
2644 /* need to reverse test to skip around exception raising */
2646 /* For the moment, branch around a branch to avoid reversing
2649 /* Remember, an unpatched branch to 0 branches to the delay slot */
2650 throw = (guint32 *)(void *)code;
2651 switch (ins->opcode) {
2652 case OP_MIPS_COND_EXC_EQ:
2653 mips_beq (code, ins->sreg1, ins->sreg2, 0);
2656 case OP_MIPS_COND_EXC_NE_UN:
2657 mips_bne (code, ins->sreg1, ins->sreg2, 0);
2661 /* Not yet implemented */
2662 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
2663 g_assert_not_reached ();
2665 skip = (guint32 *)(void *)code;
2666 mips_beq (code, mips_zero, mips_zero, 0);
2668 mips_patch (throw, (guint32)code);
2669 code = mips_emit_exc_by_name (code, ins->inst_p1);
2670 mips_patch (skip, (guint32)code);
2671 cfg->bb_exit->max_offset += 24;
2684 /* Should be re-mapped to OP_MIPS_B* by *.inssel-mips.brg */
2685 g_warning ("unsupported conditional set %s\n", mono_inst_name (ins->opcode));
2686 g_assert_not_reached ();
2694 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
2697 /* floating point opcodes */
2699 if (((guint32)ins->inst_p0) & (1 << 15))
2700 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
2702 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
2703 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
2706 if (((guint32)ins->inst_p0) & (1 << 15))
2707 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
2709 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
2710 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
2711 mips_cvtds (code, ins->dreg, ins->dreg);
2713 case OP_STORER8_MEMBASE_REG:
2714 if (mips_is_imm16 (ins->inst_offset)) {
2716 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2718 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset+4);
2719 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset);
2722 mips_load_const (code, mips_at, ins->inst_offset);
2723 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
2724 mips_swc1 (code, ins->sreg1, mips_at, 4);
2725 mips_swc1 (code, ins->sreg1+1, mips_at, 0);
2728 case OP_LOADR8_MEMBASE:
2729 if (mips_is_imm16 (ins->inst_offset)) {
2731 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2733 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset+4);
2734 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset);
2737 mips_load_const (code, mips_at, ins->inst_offset);
2738 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2739 mips_lwc1 (code, ins->dreg, mips_at, 4);
2740 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
2743 case OP_STORER4_MEMBASE_REG:
2744 /* XXX Need to convert ins->sreg1 to single-precision first */
2745 mips_cvtsd (code, mips_ftemp, ins->sreg1);
2746 if (mips_is_imm16 (ins->inst_offset)) {
2747 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
2749 mips_load_const (code, mips_at, ins->inst_offset);
2750 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
2751 mips_swc1 (code, mips_ftemp, mips_at, 0);
2755 if (mips_is_imm16 (ins->inst_offset)) {
2756 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2758 mips_load_const (code, mips_at, ins->inst_offset);
2759 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2760 mips_lwc1 (code, ins->dreg, mips_at, 0);
2763 case OP_LOADR4_MEMBASE:
2764 if (mips_is_imm16 (ins->inst_offset)) {
2765 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2767 mips_load_const (code, mips_at, ins->inst_offset);
2768 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2769 mips_lwc1 (code, ins->dreg, mips_at, 0);
2771 /* Convert to double precision in place */
2772 mips_cvtds (code, ins->dreg, ins->dreg);
2774 case CEE_CONV_R_UN: {
2775 static const guint64 adjust_val = 0x41F0000000000000ULL;
2777 /* convert unsigned int to double */
2778 mips_mtc1 (code, mips_ftemp, ins->sreg1);
2779 mips_bgez (code, ins->sreg1, 5);
2780 mips_cvtdw (code, ins->dreg, mips_ftemp);
2782 mips_load (code, mips_at, (guint32) &adjust_val);
2783 mips_ldc1 (code, mips_ftemp, mips_at, 0);
2784 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
2785 /* target is here */
2789 mips_mtc1 (code, mips_ftemp, ins->sreg1);
2790 mips_cvtsw (code, ins->dreg, mips_ftemp);
2791 mips_cvtds (code, ins->dreg, ins->dreg);
2794 mips_mtc1 (code, mips_ftemp, ins->sreg1);
2795 mips_cvtdw (code, ins->dreg, mips_ftemp);
2797 case OP_FCONV_TO_I1:
2798 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2800 case OP_FCONV_TO_U1:
2801 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2803 case OP_FCONV_TO_I2:
2804 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
2806 case OP_FCONV_TO_U2:
2807 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
2809 case OP_FCONV_TO_I4:
2811 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
2813 case OP_FCONV_TO_U4:
2815 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
2817 case OP_FCONV_TO_I8:
2818 case OP_FCONV_TO_U8:
2819 g_assert_not_reached ();
2820 /* Implemented as helper calls */
2822 case OP_LCONV_TO_R_UN:
2823 g_assert_not_reached ();
2824 /* Implemented as helper calls */
2826 case OP_LCONV_TO_OVF_I:
2827 g_assert_not_reached ();
2828 /* split up by brg file */
2831 mips_fsqrtd (code, ins->dreg, ins->sreg1);
2834 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
2837 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
2840 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
2843 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
2846 mips_fnegd (code, ins->dreg, ins->sreg1);
2850 g_assert_not_reached ();
2853 g_assert_not_reached();
2856 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
2857 mips_addiu (code, ins->dreg, mips_zero, 1);
2858 mips_fbtrue (code, 2);
2860 mips_move (code, ins->dreg, mips_zero);
2863 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
2864 mips_addiu (code, ins->dreg, mips_zero, 1);
2865 mips_fbtrue (code, 2);
2867 mips_move (code, ins->dreg, mips_zero);
2870 /* Less than, or Unordered */
2871 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
2872 mips_addiu (code, ins->dreg, mips_zero, 1);
2873 mips_fbtrue (code, 2);
2875 mips_move (code, ins->dreg, mips_zero);
2878 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
2879 mips_move (code, ins->dreg, mips_zero);
2880 mips_fbtrue (code, 2);
2882 mips_addiu (code, ins->dreg, mips_zero, 1);
2885 /* Greater than, or Unordered */
2886 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
2887 mips_move (code, ins->dreg, mips_zero);
2888 mips_fbtrue (code, 2);
2890 mips_addiu (code, ins->dreg, mips_zero, 1);
2893 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
2895 if (ins->flags & MONO_INST_BRLABEL)
2896 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2898 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2899 mips_fbtrue (code, 0);
2903 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
2905 if (ins->flags & MONO_INST_BRLABEL)
2906 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2908 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2909 mips_fbfalse (code, 0);
2913 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
2915 if (ins->flags & MONO_INST_BRLABEL)
2916 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2918 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2919 mips_fbtrue (code, 0);
2923 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
2925 if (ins->flags & MONO_INST_BRLABEL)
2926 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2928 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2929 mips_fbtrue (code, 0);
2933 mips_fcmpd (code, MIPS_FPU_LE, ins->sreg1, ins->sreg2);
2935 if (ins->flags & MONO_INST_BRLABEL)
2936 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2938 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2939 mips_fbfalse (code, 0);
2943 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
2945 if (ins->flags & MONO_INST_BRLABEL)
2946 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2948 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2949 mips_fbfalse (code, 0);
2953 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
2955 if (ins->flags & MONO_INST_BRLABEL)
2956 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2958 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2959 mips_fbfalse (code, 0);
2963 mips_fcmpd (code, MIPS_FPU_OLT, ins->sreg1, ins->sreg2);
2965 if (ins->flags & MONO_INST_BRLABEL)
2966 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2968 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2969 mips_fbfalse (code, 0);
2973 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
2975 if (ins->flags & MONO_INST_BRLABEL)
2976 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2978 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2979 mips_fbtrue (code, 0);
2983 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
2985 if (ins->flags & MONO_INST_BRLABEL)
2986 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2988 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2989 mips_fbtrue (code, 0);
2993 g_assert_not_reached();
2995 ppc_stfd (code, ins->sreg1, -8, ppc_sp);
2996 ppc_lwz (code, ppc_r11, -8, ppc_sp);
2997 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 1, 31);
2998 ppc_addis (code, ppc_r11, ppc_r11, -32752);
2999 ppc_rlwinmd (code, ppc_r11, ppc_r11, 1, 31, 31);
3000 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3005 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3006 g_assert_not_reached ();
3009 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3010 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3011 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3012 g_assert_not_reached ();
3017 last_offset = offset;
3020 cfg->code_len = code - cfg->native_code;
3024 mono_arch_register_lowlevel_calls (void)
3029 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3031 MonoJumpInfo *patch_info;
3033 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3034 unsigned char *ip = patch_info->ip.i + code;
3035 const unsigned char *target;
3037 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3039 switch (patch_info->type) {
3040 case MONO_PATCH_INFO_IP:
3041 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
3043 case MONO_PATCH_INFO_SWITCH: {
3044 /* jt is the inlined jump table, 7 or 9 instructions after ip
3045 * In the normal case we store the absolute addresses.
3046 * otherwise the displacements.
3049 gpointer *table = (gpointer *)patch_info->data.table->table;
3050 gpointer *jt = ((gpointer*)(void *)ip) + 7;
3051 if (1 /* || !(cfg->->flags & MONO_CFG_HAS_CALLS) */)
3053 for (i = 0; i < patch_info->data.table->table_size; i++) {
3054 jt [i] = code + (int)table [i];
3058 case MONO_PATCH_INFO_METHODCONST:
3059 case MONO_PATCH_INFO_CLASS:
3060 case MONO_PATCH_INFO_IMAGE:
3061 case MONO_PATCH_INFO_FIELD:
3062 case MONO_PATCH_INFO_VTABLE:
3063 case MONO_PATCH_INFO_IID:
3064 case MONO_PATCH_INFO_SFLDA:
3065 case MONO_PATCH_INFO_LDSTR:
3066 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3067 case MONO_PATCH_INFO_LDTOKEN:
3068 case MONO_PATCH_INFO_R4:
3069 case MONO_PATCH_INFO_R8:
3070 /* from OP_AOTCONST : lui + addiu */
3071 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
3074 case MONO_PATCH_INFO_EXC_NAME:
3075 g_assert_not_reached ();
3076 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
3079 case MONO_PATCH_INFO_NONE:
3080 /* everything is dealt with at epilog output time */
3085 mips_patch ((guint32 *)(void *)ip, (guint32)target);
3091 mono_trace_lmf_prolog (MonoLMF *new_lmf)
3097 mono_trace_lmf_epilog (MonoLMF *old_lmf)
3102 * Allow tracing to work with this interface (with an optional argument)
3104 * This code is expected to be inserted just after the 'real' prolog code,
3105 * and before the first basic block. We need to allocate a 2nd, temporary
3106 * stack frame so that we can preserve f12-f15 as well as a0-a3.
3110 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
3113 int fp_stack_offset = 0;
3119 mips_sw (code, mips_a0, mips_sp, cfg->stack_offset + 0);
3120 mips_sw (code, mips_a1, mips_sp, cfg->stack_offset + 4);
3121 mips_sw (code, mips_a2, mips_sp, cfg->stack_offset + 8);
3122 mips_sw (code, mips_a3, mips_sp, cfg->stack_offset + 12);
3125 fp_stack_offset = MIPS_STACK_PARAM_OFFSET;
3126 mips_addiu (code, mips_sp, mips_sp, -64);
3127 mips_swc1 (code, mips_f12, mips_sp, fp_stack_offset + 16);
3128 mips_swc1 (code, mips_f13, mips_sp, fp_stack_offset + 20);
3129 mips_swc1 (code, mips_f14, mips_sp, fp_stack_offset + 24);
3130 mips_swc1 (code, mips_f15, mips_sp, fp_stack_offset + 28);
3132 mips_fmovs (code, mips_f22, mips_f12);
3133 mips_fmovs (code, mips_f23, mips_f13);
3134 mips_fmovs (code, mips_f24, mips_f14);
3135 mips_fmovs (code, mips_f25, mips_f15);
3138 mips_load_const (code, mips_a0, cfg->method);
3139 mips_addiu (code, mips_a1, mips_sp, cfg->stack_offset + fp_stack_offset);
3140 mips_load_const (code, mips_t9, func);
3141 mips_jalr (code, mips_t9, mips_ra);
3144 mips_lw (code, mips_a0, mips_sp, cfg->stack_offset + 0);
3145 mips_lw (code, mips_a1, mips_sp, cfg->stack_offset + 4);
3146 mips_lw (code, mips_a2, mips_sp, cfg->stack_offset + 8);
3147 mips_lw (code, mips_a3, mips_sp, cfg->stack_offset + 12);
3150 mips_lwc1 (code, mips_f12, mips_sp, fp_stack_offset + 16);
3151 mips_lwc1 (code, mips_f13, mips_sp, fp_stack_offset + 20);
3152 mips_lwc1 (code, mips_f14, mips_sp, fp_stack_offset + 24);
3153 mips_lwc1 (code, mips_f15, mips_sp, fp_stack_offset + 28);
3154 mips_addiu (code, mips_sp, mips_sp, 64);
3156 mips_fmovs (code, mips_f12, mips_f22);
3157 mips_fmovs (code, mips_f13, mips_f23);
3158 mips_fmovs (code, mips_f14, mips_f24);
3159 mips_fmovs (code, mips_f15, mips_f25);
3169 * Stack frame layout:
3171 * ------------------- sp + cfg->stack_usage + cfg->param_area
3172 * param area incoming
3173 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
3175 * ------------------- sp + cfg->stack_usage
3177 * ------------------- sp + cfg->stack_usage-4
3179 * ------------------- sp +
3180 * MonoLMF structure optional
3181 * ------------------- sp + cfg->arch.lmf_offset
3182 * saved registers s0-s8
3183 * ------------------- sp + cfg->arch.iregs_offset
3185 * ------------------- sp + cfg->param_area
3186 * param area outgoing
3187 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
3189 * ------------------- sp
3193 mono_arch_emit_prolog (MonoCompile *cfg)
3195 MonoMethod *method = cfg->method;
3196 MonoMethodSignature *sig;
3198 int alloc_size, pos, i;
3202 guint32 iregs_to_save = 0;
3204 guint32 fregs_to_save = 0;
3207 /* lmf_offset is the offset of the LMF from our stack pointer. */
3208 guint32 lmf_offset = cfg->arch.lmf_offset;
3211 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3215 cfg->flags |= MONO_CFG_HAS_CALLS;
3217 sig = mono_method_signature (method);
3218 cfg->code_size = 768 + sig->param_count * 20;
3219 code = cfg->native_code = g_malloc (cfg->code_size);
3221 /* re-align cfg->stack_offset if needed (due to var spilling in mini-codegen.c) */
3222 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
3224 /* stack_offset should not be changed here. */
3225 alloc_size = cfg->stack_offset;
3226 cfg->stack_usage = alloc_size;
3229 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
3231 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
3235 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
3237 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
3238 fregs_to_save |= (fregs_to_save << 1);
3242 if (mips_is_imm16 (-alloc_size)) {
3243 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
3245 mips_load_const (code, mips_at, -alloc_size);
3246 mips_addu (code, mips_sp, mips_sp, mips_at);
3250 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
3251 mips_sw (code, mips_ra, mips_sp, alloc_size + MIPS_RET_ADDR_OFFSET);
3253 /* XXX - optimize this later to not save all regs if LMF constructed */
3255 if (iregs_to_save) {
3256 /* save used registers in own stack frame (at pos) */
3257 pos = cfg->arch.iregs_offset;
3258 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
3259 if (iregs_to_save & (1 << i)) {
3260 g_assert (pos < cfg->stack_usage - 4);
3261 mips_sw (code, i, mips_sp, pos);
3262 pos += sizeof (gulong);
3267 if (method->save_lmf) {
3268 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
3269 mips_sw (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]));
3275 /* Save float registers */
3276 if (fregs_to_save) {
3277 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
3278 if (fregs_to_save & (1 << i)) {
3279 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
3280 mips_swc1 (code, i, mips_sp, pos);
3281 pos += sizeof (gulong);
3286 if (method->save_lmf) {
3287 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
3288 mips_swc1 (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]));
3293 if (cfg->frame_reg != mips_sp) {
3294 mips_move (code, cfg->frame_reg, mips_sp);
3296 if (method->save_lmf)
3297 mips_sw (code, cfg->frame_reg, mips_sp,
3298 lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]));
3302 /* Do instrumentation before assigning regvars to registers. Because they may be assigned
3303 * to the t* registers, which would be clobbered by the instrumentation calls.
3306 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3309 /* load arguments allocated to register from the stack */
3312 cinfo = calculate_sizes (sig, sig->pinvoke);
3314 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3315 ArgInfo *ainfo = &cinfo->ret;
3316 inst = cfg->vret_addr;
3317 if (inst->opcode == OP_REGVAR)
3318 mips_move (code, inst->dreg, ainfo->reg);
3319 else if (mips_is_imm16 (inst->inst_offset)) {
3320 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3322 mips_load_const (code, mips_at, inst->inst_offset);
3323 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
3324 mips_sw (code, ainfo->reg, mips_at, 0);
3327 /* Keep this in sync with emit_load_volatile_arguments */
3328 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3329 ArgInfo *ainfo = cinfo->args + i;
3330 inst = cfg->args [pos];
3332 if (cfg->verbose_level > 2)
3333 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3334 if (inst->opcode == OP_REGVAR) {
3335 /* Argument ends up in a register */
3336 if (ainfo->regtype == RegTypeGeneral)
3337 mips_move (code, inst->dreg, ainfo->reg);
3338 else if (ainfo->regtype == RegTypeFP) {
3339 g_assert_not_reached();
3341 ppc_fmr (code, inst->dreg, ainfo->reg);
3344 else if (ainfo->regtype == RegTypeBase) {
3345 mips_lw (code, inst->dreg, mips_sp, cfg->stack_usage + ainfo->offset);
3347 g_assert_not_reached ();
3349 if (cfg->verbose_level > 2)
3350 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3352 /* Argument ends up on the stack */
3353 if (ainfo->regtype == RegTypeGeneral) {
3354 /* Incoming parameters should be above this frame */
3355 g_assert (inst->inst_offset >= alloc_size);
3356 g_assert (mips_is_imm16 (inst->inst_offset));
3357 switch (ainfo->size) {
3359 mips_sb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3362 mips_sh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3366 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3369 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3370 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
3373 g_assert_not_reached ();
3376 } else if (ainfo->regtype == RegTypeBase) {
3378 * Argument comes in on the stack, and ends up on the stack
3379 * 1 and 2 byte args are passed as 32-bit quantities, but used as
3380 * 8 and 16 bit quantities. Shorten them in place.
3382 g_assert (mips_is_imm16 (inst->inst_offset));
3383 switch (ainfo->size) {
3385 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
3386 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
3389 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
3390 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
3397 g_assert_not_reached ();
3399 } else if (ainfo->regtype == RegTypeFP) {
3400 g_assert (mips_is_imm16 (inst->inst_offset));
3401 if (ainfo->size == 8) {
3403 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3405 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
3406 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
3409 else if (ainfo->size == 4)
3410 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3412 g_assert_not_reached ();
3413 } else if (ainfo->regtype == RegTypeStructByVal) {
3415 int doffset = inst->inst_offset;
3417 g_assert (mips_is_imm16 (inst->inst_offset));
3418 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3419 /* Push the argument registers into their stack slots */
3420 for (i = 0; i < ainfo->size; ++i) {
3421 mips_sw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3422 doffset += sizeof (gpointer);
3424 } else if (ainfo->regtype == RegTypeStructByAddr) {
3425 g_assert (mips_is_imm16 (inst->inst_offset));
3426 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3427 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
3429 g_assert_not_reached ();
3434 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
3435 mips_load_const (code, mips_a0, cfg->domain);
3436 mips_load_const (code, mips_t9, (gpointer)mono_jit_thread_attach);
3437 mips_jalr (code, mips_t9, mips_ra);
3442 if (method->save_lmf) {
3443 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
3444 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
3446 if (lmf_pthread_key != -1) {
3447 g_assert_not_reached();
3449 emit_tls_access (code, mips_temp, lmf_pthread_key);
3451 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
3452 mips_addiu (code, mips_a0, mips_temp, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3455 mips_addiu (code, mips_a0, mips_sp, lmf_offset);
3456 mips_load_const (code, mips_t9, (gpointer)mono_trace_lmf_prolog);
3457 mips_jalr (code, mips_t9, mips_ra);
3460 /* This can/will clobber the a0-a3 registers */
3461 mips_load_const (code, mips_t9, (gpointer)mono_get_lmf_addr);
3462 mips_jalr (code, mips_t9, mips_ra);
3466 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
3467 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
3468 /* new_lmf->previous_lmf = *lmf_addr */
3469 mips_lw (code, mips_at, mips_v0, 0);
3470 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
3471 /* *(lmf_addr) = sp + lmf_offset */
3472 mips_addiu (code, mips_at, mips_sp, lmf_offset);
3473 mips_sw (code, mips_at, mips_v0, 0);
3475 /* save method info */
3476 mips_load_const (code, mips_at, method);
3477 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
3478 mips_sw (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
3480 /* save the current IP */
3481 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3482 mips_load_const (code, mips_at, 0x01010101);
3483 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
3487 cfg->code_len = code - cfg->native_code;
3488 g_assert (cfg->code_len < cfg->code_size);
3503 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
3506 int save_mode = SAVE_NONE;
3508 MonoMethod *method = cfg->method;
3509 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
3510 int save_offset = MIPS_STACK_PARAM_OFFSET;
3512 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
3514 offset = code - cfg->native_code;
3515 /* we need about 16 instructions */
3516 if (offset > (cfg->code_size - 16 * 4)) {
3517 cfg->code_size *= 2;
3518 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3519 code = cfg->native_code + offset;
3524 case MONO_TYPE_VOID:
3525 /* special case string .ctor icall */
3526 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
3527 save_mode = SAVE_ONE;
3529 save_mode = SAVE_NONE;
3533 save_mode = SAVE_TWO;
3537 save_mode = SAVE_FP;
3539 case MONO_TYPE_VALUETYPE:
3540 save_mode = SAVE_STRUCT;
3543 save_mode = SAVE_ONE;
3547 mips_addiu (code, mips_sp, mips_sp, -32);
3548 switch (save_mode) {
3550 mips_sw (code, mips_v0, mips_sp, save_offset);
3551 mips_sw (code, mips_v1, mips_sp, save_offset + 4);
3552 if (enable_arguments) {
3553 mips_move (code, mips_a1, mips_v0);
3554 mips_move (code, mips_a2, mips_v1);
3558 mips_sw (code, mips_v0, mips_sp, save_offset);
3559 if (enable_arguments) {
3560 mips_move (code, mips_a1, mips_v0);
3564 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
3565 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
3566 mips_lw (code, mips_a0, mips_sp, save_offset);
3567 mips_lw (code, mips_a1, mips_sp, save_offset+4);
3574 mips_load_const (code, mips_a0, cfg->method);
3575 mips_load_const (code, mips_t9, func);
3576 mips_jalr (code, mips_t9, mips_ra);
3579 switch (save_mode) {
3581 mips_lw (code, mips_v0, mips_sp, save_offset);
3582 mips_lw (code, mips_v1, mips_sp, save_offset + 4);
3585 mips_lw (code, mips_v0, mips_sp, save_offset);
3588 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
3595 mips_addiu (code, mips_sp, mips_sp, 32);
3602 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
3604 MonoMethod *method = cfg->method;
3606 int max_epilog_size = 16 + 20*4;
3607 guint32 iregs_to_restore;
3609 guint32 fregs_to_restore;
3613 if (cfg->method->save_lmf)
3614 max_epilog_size += 128;
3617 if (mono_jit_trace_calls != NULL)
3618 max_epilog_size += 50;
3620 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3621 max_epilog_size += 50;
3624 pos = code - cfg->native_code;
3625 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3626 cfg->code_size *= 2;
3627 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3628 mono_jit_stats.code_reallocs++;
3632 * Keep in sync with OP_JMP
3635 code = cfg->native_code + pos;
3637 code = cfg->native_code + cfg->code_len;
3639 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3640 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3642 pos = cfg->arch.iregs_offset;
3643 if (cfg->frame_reg != mips_sp) {
3644 mips_move (code, mips_sp, cfg->frame_reg);
3647 iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
3649 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
3651 if (iregs_to_restore) {
3652 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
3653 if (iregs_to_restore & (1 << i)) {
3654 mips_lw (code, i, mips_sp, pos);
3655 pos += sizeof (gulong);
3662 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
3664 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
3665 fregs_to_restore |= (fregs_to_restore << 1);
3667 if (fregs_to_restore) {
3668 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
3669 if (fregs_to_restore & (1 << i)) {
3670 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
3671 mips_lwc1 (code, i, mips_sp, pos);
3672 pos += sizeof (gulong);
3678 /* Unlink the LMF if necessary */
3679 if (method->save_lmf) {
3680 int lmf_offset = cfg->arch.lmf_offset;
3682 /* t0 = current_lmf->previous_lmf */
3683 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
3685 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
3686 /* (*lmf_addr) = previous_lmf */
3687 mips_sw (code, mips_temp, mips_t1, 0);
3691 /* Restore the fp */
3692 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
3694 /* Correct the stack pointer */
3695 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
3696 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage + MIPS_RET_ADDR_OFFSET);
3697 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage);
3699 /* Caller will emit either return or tail-call sequence */
3701 cfg->code_len = code - cfg->native_code;
3703 g_assert (cfg->code_len < cfg->code_size);
3708 mono_arch_emit_epilog (MonoCompile *cfg)
3712 code = mono_arch_emit_epilog_sub (cfg, NULL);
3714 mips_jr (code, mips_ra);
3717 cfg->code_len = code - cfg->native_code;
3719 g_assert (cfg->code_len < cfg->code_size);
3722 /* remove once throw_exception_by_name is eliminated */
3724 exception_id_by_name (const char *name)
3726 if (strcmp (name, "IndexOutOfRangeException") == 0)
3727 return MONO_EXC_INDEX_OUT_OF_RANGE;
3728 if (strcmp (name, "OverflowException") == 0)
3729 return MONO_EXC_OVERFLOW;
3730 if (strcmp (name, "ArithmeticException") == 0)
3731 return MONO_EXC_ARITHMETIC;
3732 if (strcmp (name, "DivideByZeroException") == 0)
3733 return MONO_EXC_DIVIDE_BY_ZERO;
3734 if (strcmp (name, "InvalidCastException") == 0)
3735 return MONO_EXC_INVALID_CAST;
3736 if (strcmp (name, "NullReferenceException") == 0)
3737 return MONO_EXC_NULL_REF;
3738 if (strcmp (name, "ArrayTypeMismatchException") == 0)
3739 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3740 g_error ("Unknown intrinsic exception %s\n", name);
3745 mono_arch_emit_exceptions (MonoCompile *cfg)
3748 MonoJumpInfo *patch_info;
3751 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3752 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3753 int max_epilog_size = 50;
3755 /* count the number of exception infos */
3758 * make sure we have enough space for exceptions
3759 * 24 is the simulated call to throw_exception_by_name
3761 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3763 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3764 i = exception_id_by_name (patch_info->data.target);
3765 g_assert (i < MONO_EXC_INTRINS_NUM);
3766 if (!exc_throw_found [i]) {
3767 max_epilog_size += 12;
3768 exc_throw_found [i] = TRUE;
3774 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3775 cfg->code_size *= 2;
3776 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3777 mono_jit_stats.code_reallocs++;
3780 code = cfg->native_code + cfg->code_len;
3782 /* add code to raise exceptions */
3783 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3784 switch (patch_info->type) {
3785 case MONO_PATCH_INFO_EXC: {
3787 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
3789 i = exception_id_by_name (patch_info->data.target);
3790 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
3791 if (!exc_throw_pos [i]) {
3794 exc_throw_pos [i] = code;
3795 //g_print ("exc: writing stub at %p\n", code);
3796 mips_load_const (code, mips_a0, patch_info->data.target);
3797 addr = (guint32) mono_arch_get_throw_exception_by_name ();
3798 mips_load_const (code, mips_t9, addr);
3799 mips_jr (code, mips_t9);
3802 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
3804 /* Turn into a Relative patch, pointing at code stub */
3805 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
3806 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
3808 g_assert_not_reached();
3818 cfg->code_len = code - cfg->native_code;
3820 g_assert (cfg->code_len < cfg->code_size);
3825 * Thread local storage support
3828 setup_tls_access (void)
3831 //guint32 *ins, *code;
3833 if (tls_mode == TLS_MODE_FAILED)
3836 if (g_getenv ("MONO_NO_TLS")) {
3837 tls_mode = TLS_MODE_FAILED;
3841 if (tls_mode == TLS_MODE_DETECT) {
3843 tls_mode = TLS_MODE_FAILED;
3847 ins = (guint32*)pthread_getspecific;
3848 /* uncond branch to the real method */
3849 if ((*ins >> 26) == 18) {
3851 val = (*ins & ~3) << 6;
3855 ins = (guint32*)val;
3857 ins = (guint32*) ((char*)ins + val);
3860 code = &cmplwi_1023;
3861 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
3863 ppc_li (code, ppc_r4, 0x48);
3866 if (*ins == cmplwi_1023) {
3867 int found_lwz_284 = 0;
3868 for (ptk = 0; ptk < 20; ++ptk) {
3870 if (!*ins || *ins == blr_ins)
3872 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
3877 if (!found_lwz_284) {
3878 tls_mode = TLS_MODE_FAILED;
3881 tls_mode = TLS_MODE_LTHREADS;
3882 } else if (*ins == li_0x48) {
3884 /* uncond branch to the real method */
3885 if ((*ins >> 26) == 18) {
3887 val = (*ins & ~3) << 6;
3891 ins = (guint32*)val;
3893 ins = (guint32*) ((char*)ins + val);
3896 ppc_li (code, ppc_r0, 0x7FF2);
3897 if (ins [1] == val) {
3898 /* Darwin on G4, implement */
3899 tls_mode = TLS_MODE_FAILED;
3903 ppc_mfspr (code, ppc_r3, 104);
3904 if (ins [1] != val) {
3905 tls_mode = TLS_MODE_FAILED;
3908 tls_mode = TLS_MODE_DARWIN_G5;
3911 tls_mode = TLS_MODE_FAILED;
3915 tls_mode = TLS_MODE_FAILED;
3920 if (monodomain_key == -1) {
3921 ptk = mono_domain_get_tls_key ();
3923 ptk = mono_pthread_key_for_tls (ptk);
3925 monodomain_key = ptk;
3929 if (lmf_pthread_key == -1) {
3930 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
3932 /*g_print ("MonoLMF at: %d\n", ptk);*/
3933 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
3934 init_tls_failed = 1;
3937 lmf_pthread_key = ptk;
3940 if (monothread_key == -1) {
3941 ptk = mono_thread_get_tls_key ();
3943 ptk = mono_pthread_key_for_tls (ptk);
3945 monothread_key = ptk;
3946 /*g_print ("thread inited: %d\n", ptk);*/
3949 /*g_print ("thread not inited yet %d\n", ptk);*/
3955 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3957 setup_tls_access ();
3961 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3966 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3968 int this_dreg = mips_a0;
3971 this_dreg = mips_a1;
3973 /* add the this argument */
3974 if (this_reg != -1) {
3976 MONO_INST_NEW (cfg, this, OP_MOVE);
3977 this->type = this_type;
3978 this->sreg1 = this_reg;
3979 this->dreg = mono_regstate_next_int (cfg->rs);
3980 mono_bblock_add_inst (cfg->cbb, this);
3981 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
3986 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
3987 vtarg->type = STACK_MP;
3988 vtarg->sreg1 = vt_reg;
3989 vtarg->dreg = mono_regstate_next_int (cfg->rs);
3990 mono_bblock_add_inst (cfg->cbb, vtarg);
3991 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
3996 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3998 MonoInst *ins = NULL;
4004 mono_arch_print_tree (MonoInst *tree, int arity)
4009 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4013 setup_tls_access ();
4014 if (monodomain_key == -1)
4017 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4018 ins->inst_offset = monodomain_key;
4023 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4027 setup_tls_access ();
4028 if (monothread_key == -1)
4031 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4032 ins->inst_offset = monothread_key;
4037 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4039 /* FIXME: implement */
4040 g_assert_not_reached ();