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;
85 #define ALWAYS_ON_STACK(s) s
86 #define FP_ALSO_IN_REG(s) s
99 guint16 vtsize; /* in param area */
101 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
102 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
120 void patch_lui_addiu(guint32 *ip, guint32 val);
121 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
124 mono_arch_flush_icache (guint8 *code, gint size)
126 /* Linux/MIPS specific */
127 cacheflush (code, size, BCACHE);
130 #ifndef CUSTOM_STACK_WALK
132 mono_arch_flush_register_windows (void)
138 mips_emit_exc_by_name(guint8 *code, const char *name)
142 mips_load_const (code, mips_a0, name);
143 addr = (guint32) mono_arch_get_throw_exception_by_name ();
144 mips_load_const (code, mips_t9, addr);
145 mips_jalr (code, mips_t9, mips_ra);
152 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
158 /* Invert test and emit branch around jump */
161 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
165 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
169 mips_bltz (code, ins->sreg1, br_offset);
173 mips_blez (code, ins->sreg1, br_offset);
177 mips_bgtz (code, ins->sreg1, br_offset);
181 mips_bgez (code, ins->sreg1, br_offset);
185 g_assert_not_reached ();
187 if (ins->flags & MONO_INST_BRLABEL)
188 mono_add_patch_info (cfg, code - cfg->native_code,
189 MONO_PATCH_INFO_LABEL, ins->inst_i0);
191 mono_add_patch_info (cfg, code - cfg->native_code,
192 MONO_PATCH_INFO_BB, ins->inst_true_bb);
193 mips_lui (code, mips_at, mips_zero, 0);
194 mips_addiu (code, mips_at, mips_at, 0);
195 mips_jr (code, mips_at);
198 if (ins->flags & MONO_INST_BRLABEL)
199 mono_add_patch_info (cfg, code - cfg->native_code,
200 MONO_PATCH_INFO_LABEL, ins->inst_i0);
202 mono_add_patch_info (cfg, code - cfg->native_code,
203 MONO_PATCH_INFO_BB, ins->inst_true_bb);
206 mips_beq (code, ins->sreg1, ins->sreg2, 0);
210 mips_bne (code, ins->sreg1, ins->sreg2, 0);
214 mips_bgez (code, ins->sreg1, 0);
218 mips_bgtz (code, ins->sreg1, 0);
222 mips_blez (code, ins->sreg1, 0);
226 mips_bltz (code, ins->sreg1, 0);
230 g_assert_not_reached ();
236 /* XXX - big-endian dependent? */
238 patch_lui_addiu(guint32 *ip, guint32 val)
240 guint16 *__lui_addiu = (guint16*)(void *)(ip);
243 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
244 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
247 if (((guint32)(val)) & (1 << 15))
248 __lui_addiu [1] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
250 __lui_addiu [1] = (((guint32)(val)) >> 16) & 0xffff;
251 __lui_addiu [3] = ((guint32)(val)) & 0xffff;
252 mono_arch_flush_icache ((guint8 *)ip, 8);
257 mips_patch (guint32 *code, guint32 target)
260 guint32 op = ins >> 26;
261 guint32 diff, offset;
263 g_assert (trap_target != target);
264 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
266 case 0x00: /* jr ra */
267 if (ins == 0x3e00008)
269 g_assert_not_reached ();
273 g_assert (!(target & 0x03));
274 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
275 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
277 mono_arch_flush_icache ((guint8 *)code, 4);
279 case 0x01: /* BLTZ */
282 case 0x06: /* BLEZ */
283 case 0x07: /* BGTZ */
284 case 0x11: /* bc1t */
285 diff = target - (guint32)(code + 1);
286 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
287 g_assert (!(diff & 0x03));
288 offset = ((gint32)diff) >> 2;
289 g_assert (((int)offset) == ((int)(short)offset));
290 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
292 mono_arch_flush_icache ((guint8 *)code, 4);
294 case 0x0f: /* LUI / ADDIU pair */
295 patch_lui_addiu (code, target);
296 mono_arch_flush_icache ((guint8 *)code, 8);
300 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
301 g_assert_not_reached ();
306 offsets_from_pthread_key (guint32 key, int *offset2)
310 *offset2 = idx2 * sizeof (gpointer);
311 return 284 + idx1 * sizeof (gpointer);
315 mono_arch_regname (int reg) {
316 static const char * rnames[] = {
317 "zero", "at", "v0", "v1",
318 "a0", "a1", "a2", "a3",
319 "t0", "t1", "t2", "t3",
320 "t4", "t5", "t6", "t7",
321 "s0", "s1", "s2", "s3",
322 "s4", "s5", "s6", "s7",
323 "t8", "t9", "k0", "k1",
324 "gp", "sp", "fp", "ra"
326 if (reg >= 0 && reg < 32)
332 mono_arch_fregname (int reg) {
333 static const char * rnames[] = {
334 "f0", "f1", "f2", "f3",
335 "f4", "f5", "f6", "f7",
336 "f8", "f9", "f10", "f11",
337 "f12", "f13", "f14", "f15",
338 "f16", "f17", "f18", "f19",
339 "f20", "f21", "f22", "f23",
340 "f24", "f25", "f26", "f27",
341 "f28", "f29", "f30", "f31"
343 if (reg >= 0 && reg < 32)
348 /* this function overwrites at */
350 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
352 /* XXX write a loop, not an unrolled loop */
354 mips_lw (code, mips_at, sreg, soffset);
355 mips_sw (code, mips_at, dreg, doffset);
364 * mono_arch_get_argument_info:
365 * @csig: a method signature
366 * @param_count: the number of parameters to consider
367 * @arg_info: an array to store the result infos
369 * Gathers information on parameters such as size, alignment and
370 * padding. arg_info should be large enought to hold param_count + 1 entries.
372 * Returns the size of the activation frame.
375 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
377 int k, frame_size = 0;
378 guint32 size, align, pad;
381 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
382 frame_size += sizeof (gpointer);
386 arg_info [0].offset = offset;
389 frame_size += sizeof (gpointer);
393 arg_info [0].size = frame_size;
395 for (k = 0; k < param_count; k++) {
398 size = mono_type_native_stack_size (csig->params [k], &align);
400 size = mono_type_stack_size (csig->params [k], &align);
402 /* ignore alignment for now */
405 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
406 arg_info [k].pad = pad;
408 arg_info [k + 1].pad = 0;
409 arg_info [k + 1].size = size;
411 arg_info [k + 1].offset = offset;
415 align = MONO_ARCH_FRAME_ALIGNMENT;
416 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
417 arg_info [k].pad = pad;
423 * Initialize the cpu to execute managed code.
426 mono_arch_cpu_init (void)
431 * This function returns the optimizations supported on this cpu.
434 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
438 /* no mips-specific optimizations yet */
444 is_regsize_var (MonoType *t) {
447 t = mono_type_get_underlying_type (t);
454 case MONO_TYPE_FNPTR:
456 case MONO_TYPE_OBJECT:
457 case MONO_TYPE_STRING:
458 case MONO_TYPE_CLASS:
459 case MONO_TYPE_SZARRAY:
460 case MONO_TYPE_ARRAY:
462 case MONO_TYPE_GENERICINST:
463 if (!mono_type_generic_inst_is_valuetype (t))
466 case MONO_TYPE_VALUETYPE:
473 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
478 for (i = 0; i < cfg->num_varinfo; i++) {
479 MonoInst *ins = cfg->varinfo [i];
480 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
483 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
486 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
489 /* we can only allocate 32 bit values */
490 if (is_regsize_var (ins->inst_vtype)) {
491 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
492 g_assert (i == vmv->idx);
493 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
501 mono_arch_get_global_int_regs (MonoCompile *cfg)
505 regs = g_list_prepend (regs, (gpointer)mips_s0);
506 regs = g_list_prepend (regs, (gpointer)mips_s1);
507 regs = g_list_prepend (regs, (gpointer)mips_s2);
508 regs = g_list_prepend (regs, (gpointer)mips_s3);
509 regs = g_list_prepend (regs, (gpointer)mips_s4);
510 regs = g_list_prepend (regs, (gpointer)mips_s5);
511 regs = g_list_prepend (regs, (gpointer)mips_s6);
512 regs = g_list_prepend (regs, (gpointer)mips_s7);
518 * mono_arch_regalloc_cost:
520 * Return the cost, in number of memory references, of the action of
521 * allocating the variable VMV into a register during global register
525 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
532 args_onto_stack (CallInfo *info, gboolean force)
534 if (!info->on_stack) {
535 if ((info->gr > MIPS_LAST_ARG_REG) || (info->fr > (MIPS_LAST_FPARG_REG+1))) {
539 info->on_stack = TRUE;
540 info->stack_size = MIPS_STACK_PARAM_OFFSET;
546 * O32 calling convention version
550 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
551 /* First, see if we need to drop onto the stack */
552 args_onto_stack (info, FALSE);
554 /* Now, place the argument */
555 ainfo->offset = info->stack_size;
556 info->stack_size += 4;
557 if (info->on_stack) {
558 ainfo->regtype = RegTypeBase;
559 ainfo->reg = mips_sp; /* in the caller */
562 ainfo->reg = info->gr;
564 info->gr_passed += 1;
565 /* FP and GP slots do not overlap */
571 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
572 /* First, see if we need to drop onto the stack */
573 args_onto_stack (info, FALSE);
575 /* Now, place the argument */
576 if (info->stack_size & 0x7) {
579 /* foo (int, long) -- need to align 2nd arg */
580 add_int32_arg (info, &dummy);
581 args_onto_stack (info, FALSE);
583 ainfo->offset = info->stack_size;
584 info->stack_size += 8;
585 if (info->on_stack) {
586 ainfo->regtype = RegTypeBase;
587 ainfo->reg = mips_sp; /* in the caller */
590 ainfo->reg = info->gr;
592 info->gr_passed += 2;
593 /* FP and GP slots do not overlap */
599 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
600 /* First, see if we need to drop onto the stack */
601 args_onto_stack (info, FALSE);
603 /* Now, place the argument */
604 ainfo->offset = info->stack_size;
605 if (info->on_stack) {
606 ainfo->regtype = RegTypeBase;
607 ainfo->reg = mips_sp; /* in the caller */
608 info->stack_size += 8;
611 /* Only use FP regs for args if no int args passed yet */
612 if (!info->gr_passed) {
613 ainfo->regtype = RegTypeFP;
614 ainfo->reg = info->fr;
615 info->stack_size += 8;
616 /* Even though it's a single-precision float, it takes up two FP regs */
618 info->fr_passed += 1;
619 /* FP and GP slots do not overlap */
623 /* Passing single-precision float arg in a GP register
624 * such as: func (0, 1.0, 2, 3);
625 * In this case, only one 'gr' register is consumed.
627 ainfo->regtype = RegTypeGeneral;
628 ainfo->reg = info->gr;
629 info->stack_size += 4;
631 /* Even though it's a single-precision float, it takes up two FP regs */
633 info->fr_passed += 1;
634 /* FP and GP slots do not overlap */
641 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
642 /* First, see if we need to drop onto the stack */
643 args_onto_stack (info, FALSE);
645 /* Now, place the argument */
647 // info->stack_size += (info->stack_size % 8);
649 ainfo->offset = info->stack_size;
650 info->stack_size += 8;
651 if (info->on_stack) {
652 ainfo->regtype = RegTypeBase;
653 ainfo->reg = mips_sp; /* in the caller */
656 /* Only use FP regs for args if no int args passed yet */
657 if (!info->gr_passed) {
658 ainfo->regtype = RegTypeFP;
659 ainfo->reg = info->fr;
662 ainfo->regtype = RegTypeGeneral;
663 ainfo->reg = info->gr;
666 info->fr_passed += 2;
667 /* FP and GP slots do not overlap */
673 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
676 int n = sig->hasthis + sig->param_count;
678 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
680 cinfo->fr = MIPS_FIRST_FPARG_REG;
681 cinfo->gr = MIPS_FIRST_ARG_REG;
682 cinfo->stack_size = 0;
684 DEBUG(printf("calculate_sizes\n"));
686 /* handle returning a struct */
687 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
688 cinfo->struct_ret = cinfo->gr;
689 add_int32_arg (cinfo, &cinfo->ret);
694 add_int32_arg (cinfo, cinfo->args + n);
697 DEBUG(printf("params: %d\n", sig->param_count));
698 for (i = 0; i < sig->param_count; ++i) {
699 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
700 /* Prevent implicit arguments and sig_cookie from
701 being passed in registers */
702 args_onto_stack (cinfo, TRUE);
703 /* Emit the signature cookie just before the implicit arguments */
704 add_int32_arg (cinfo, &cinfo->sig_cookie);
706 DEBUG(printf("param %d: ", i));
707 if (sig->params [i]->byref) {
708 DEBUG(printf("byref\n"));
709 add_int32_arg (cinfo, &cinfo->args[n]);
713 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
714 switch (simpletype) {
715 case MONO_TYPE_BOOLEAN:
718 DEBUG(printf("1 byte\n"));
719 cinfo->args [n].size = 1;
720 add_int32_arg (cinfo, &cinfo->args[n]);
726 DEBUG(printf("2 bytes\n"));
727 cinfo->args [n].size = 2;
728 add_int32_arg (cinfo, &cinfo->args[n]);
733 DEBUG(printf("4 bytes\n"));
734 cinfo->args [n].size = 4;
735 add_int32_arg (cinfo, &cinfo->args[n]);
741 case MONO_TYPE_FNPTR:
742 case MONO_TYPE_CLASS:
743 case MONO_TYPE_OBJECT:
744 case MONO_TYPE_STRING:
745 case MONO_TYPE_SZARRAY:
746 case MONO_TYPE_ARRAY:
747 cinfo->args [n].size = sizeof (gpointer);
748 add_int32_arg (cinfo, &cinfo->args[n]);
751 case MONO_TYPE_GENERICINST:
752 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
753 cinfo->args [n].size = sizeof (gpointer);
754 add_int32_arg (cinfo, &cinfo->args[n]);
759 case MONO_TYPE_VALUETYPE: {
764 gint size, alignment;
767 klass = mono_class_from_mono_type (sig->params [i]);
769 size = mono_class_native_size (klass, NULL);
771 size = mono_class_value_size (klass, NULL);
772 alignment = mono_class_min_align (klass);
773 #if MIPS_PASS_STRUCTS_BY_VALUE
774 /* Need to do alignment if struct contains long or double */
775 if (cinfo->stack_size & (alignment - 1)) {
776 add_int32_arg (cinfo, &dummy_arg);
778 g_assert (!(cinfo->stack_size & (alignment - 1)));
781 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
782 mono_class_native_size (sig->params [i]->data.klass, NULL),
783 cinfo->stack_size, alignment);
786 align_size += (sizeof (gpointer) - 1);
787 align_size &= ~(sizeof (gpointer) - 1);
788 nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
789 for (j = 0; j < nwords; ++j) {
791 add_int32_arg (cinfo, &cinfo->args [n]);
793 add_int32_arg (cinfo, &dummy_arg);
795 cinfo->args [n].vtsize += 1;
797 cinfo->args [n].size += 1;
799 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
800 cinfo->args [n].regtype = RegTypeStructByVal;
802 add_int32_arg (cinfo, &cinfo->args[n]);
803 cinfo->args [n].regtype = RegTypeStructByAddr;
808 case MONO_TYPE_TYPEDBYREF: {
809 /* keep in sync or merge with the valuetype case */
810 #if MIPS_PASS_STRUCTS_BY_VALUE
812 int size = sizeof (MonoTypedRef);
813 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
814 cinfo->args [n].regtype = RegTypeStructByVal;
815 if (cinfo->gr <= MIPS_LAST_ARG_REG) {
816 int rest = MIPS_LAST_ARG_REG - cinfo->gr + 1;
817 int n_in_regs = rest >= nwords? nwords: rest;
818 cinfo->args [n].size = n_in_regs;
819 cinfo->args [n].vtsize = nwords - n_in_regs;
820 cinfo->args [n].reg = cinfo->gr;
821 cinfo->gr += n_in_regs;
823 cinfo->args [n].size = 0;
824 cinfo->args [n].vtsize = nwords;
826 cinfo->args [n].offset = MIPS_STACK_PARAM_OFFSET + cinfo->stack_size;
827 g_print ("offset for arg %d at %d\n", n, MIPS_STACK_PARAM_OFFSET + cinfo->stack_size);
828 cinfo->stack_size += nwords * sizeof (gpointer);
831 add_int32_arg (cinfo, &cinfo->args[n]);
832 cinfo->args [n].regtype = RegTypeStructByAddr;
839 cinfo->args [n].size = 8;
840 add_int64_arg (cinfo, &cinfo->args[n]);
844 cinfo->args [n].size = 4;
845 add_float32_arg (cinfo, &cinfo->args[n]);
849 cinfo->args [n].size = 8;
850 add_float64_arg (cinfo, &cinfo->args[n]);
854 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
859 simpletype = mono_type_get_underlying_type (sig->ret)->type;
860 switch (simpletype) {
861 case MONO_TYPE_BOOLEAN:
872 case MONO_TYPE_FNPTR:
873 case MONO_TYPE_CLASS:
874 case MONO_TYPE_OBJECT:
875 case MONO_TYPE_SZARRAY:
876 case MONO_TYPE_ARRAY:
877 case MONO_TYPE_STRING:
878 cinfo->ret.reg = mips_v0;
882 cinfo->ret.reg = mips_v0;
886 cinfo->ret.reg = mips_f0;
887 cinfo->ret.regtype = RegTypeFP;
889 case MONO_TYPE_GENERICINST:
890 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
891 cinfo->ret.reg = mips_v0;
895 case MONO_TYPE_VALUETYPE:
897 case MONO_TYPE_TYPEDBYREF:
901 g_error ("Can't handle as return value 0x%x", sig->ret->type);
905 /* align stack size to 16 */
906 cinfo->stack_size = (cinfo->stack_size + 15) & ~15;
908 cinfo->stack_usage = cinfo->stack_size;
914 * Set var information according to the calling convention. mips version.
915 * The locals var stuff should most likely be split in another method.
918 mono_arch_allocate_vars (MonoCompile *cfg)
920 MonoMethodSignature *sig;
921 MonoMethodHeader *header;
923 int i, offset, size, align, curinst;
924 int frame_reg = mips_sp;
925 guint32 iregs_to_save = 0;
926 guint32 fregs_to_restore;
928 cfg->flags |= MONO_CFG_HAS_SPILLUP;
930 /* allow room for the vararg method args: void* and long/double */
931 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
932 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
934 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
935 * call convs needs to be handled this way.
937 if (cfg->flags & MONO_CFG_HAS_VARARGS)
938 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
940 /* gtk-sharp and other broken code will dllimport vararg functions even with
941 * non-varargs signatures. Since there is little hope people will get this right
942 * we assume they won't.
944 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
945 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
947 cfg->param_area = MAX (cfg->param_area, 16);
949 header = mono_method_get_header (cfg->method);
951 sig = mono_method_signature (cfg->method);
954 * We use the frame register also for any method that has
955 * exception clauses. This way, when the handlers are called,
956 * the code will reference local variables using the frame reg instead of
957 * the stack pointer: if we had to restore the stack pointer, we'd
958 * corrupt the method frames that are already on the stack (since
959 * filters get called before stack unwinding happens) when the filter
960 * code would call any method (this also applies to finally etc.).
963 if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses || ALWAYS_USE_FP)
965 cfg->frame_reg = frame_reg;
966 if (frame_reg != mips_sp) {
967 cfg->used_int_regs |= 1 << frame_reg;
972 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
973 /* FIXME: handle long and FP values */
974 switch (mono_type_get_underlying_type (sig->ret)->type) {
978 cfg->ret->opcode = OP_REGVAR;
979 cfg->ret->inst_c0 = mips_v0;
983 /* Space for outgoing parameters, including a0-a3 */
984 offset += cfg->param_area;
986 /* allow room to save the return value (if it's a struct) */
987 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
990 if (sig->call_convention == MONO_CALL_VARARG) {
991 cfg->sig_cookie = MIPS_STACK_PARAM_OFFSET;
994 /* Now handle the local variables */
996 curinst = cfg->locals_start;
997 for (i = curinst; i < cfg->num_varinfo; ++i) {
998 inst = cfg->varinfo [i];
999 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1002 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1003 * pinvoke wrappers when they call functions returning structure
1005 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1006 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
1008 size = mono_type_size (inst->inst_vtype, &align);
1010 offset += align - 1;
1011 offset &= ~(align - 1);
1012 inst->inst_offset = offset;
1013 inst->opcode = OP_REGOFFSET;
1014 inst->inst_basereg = frame_reg;
1016 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1019 /* Space for LMF (if needed) */
1021 if (cfg->method->save_lmf) {
1022 /* align the offset to 16 bytes */
1023 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1024 cfg->arch.lmf_offset = offset;
1025 offset += sizeof (MonoLMF);
1029 #if EXTRA_STACK_SPACE
1030 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1031 * args or return vals. Extra stack space avoids this in a lot of cases.
1035 /* Space for saved registers */
1036 cfg->arch.iregs_offset = offset;
1038 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
1040 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1042 if (iregs_to_save) {
1043 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1044 if (iregs_to_save & (1 << i)) {
1045 offset += sizeof (gulong);
1050 #if EXTRA_STACK_SPACE
1051 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1052 * args or return vals. Extra stack space avoids this in a lot of cases.
1057 /* saved float registers */
1059 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1060 if (fregs_to_restore) {
1061 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1062 if (fregs_to_restore & (1 << i)) {
1063 offset += sizeof (double);
1069 /* Now add space for saving the ra */
1073 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1074 cfg->stack_offset = offset;
1077 * Now allocate stack slots for the int arg regs (a0 - a3)
1078 * On MIPS o32, these are just above the incoming stack pointer
1079 * Even if the arg has been assigned to a regvar, it gets a stack slot
1082 /* Return struct-by-value results in a hidden first argument */
1083 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1084 cfg->ret->opcode = OP_REGOFFSET;
1085 cfg->ret->inst_c0 = mips_a0;
1086 cfg->ret->inst_offset = offset;
1087 cfg->ret->inst_basereg = frame_reg;
1091 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1092 inst = cfg->varinfo [i];
1093 if (inst->opcode != OP_REGVAR) {
1096 if (sig->hasthis && (i == 0))
1097 arg_type = &mono_defaults.object_class->byval_arg;
1099 arg_type = sig->params [i - sig->hasthis];
1101 inst->opcode = OP_REGOFFSET;
1102 size = mono_type_size (arg_type, &align);
1104 /* Need to take references to R4 into account */
1105 /* If it's a single-precision float, allocate 8 bytes of stack for it */
1106 if ((arg_type->type == MONO_TYPE_R4) && !arg_type->byref) {
1114 inst->inst_basereg = frame_reg;
1115 offset = (offset + align - 1) & ~(align - 1);
1116 inst->inst_offset = offset;
1118 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1119 cfg->sig_cookie += size;
1120 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1123 /* Even a0-a3 get stack slots */
1124 size = sizeof (gpointer);
1125 align = sizeof (gpointer);
1126 inst->inst_basereg = frame_reg;
1127 offset = (offset + align - 1) & ~(align - 1);
1128 inst->inst_offset = offset;
1130 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1131 cfg->sig_cookie += size;
1132 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1137 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1138 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1142 * take the arguments and generate the arch-specific
1143 * instructions to properly call the function in call.
1144 * This includes pushing, moving arguments to the right register
1146 * Issue: who does the spilling if needed, and when?
1149 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
1151 MonoMethodSignature *sig;
1156 sig = call->signature;
1157 n = sig->param_count + sig->hasthis;
1159 cinfo = calculate_sizes (sig, sig->pinvoke);
1160 if (cinfo->struct_ret)
1161 call->used_iregs |= 1 << cinfo->struct_ret;
1163 for (i = 0; i < n; ++i) {
1164 ainfo = cinfo->args + i;
1165 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1167 cfg->disable_aot = TRUE;
1169 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1170 sig_arg->inst_p0 = call->signature;
1172 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1173 arg->inst_imm = cinfo->sig_cookie.offset;
1174 arg->inst_left = sig_arg;
1176 /* prepend, so they get reversed */
1177 arg->next = call->out_args;
1178 call->out_args = arg;
1180 if (is_virtual && i == 0) {
1181 /* the argument will be attached to the call instrucion */
1182 in = call->args [i];
1183 call->used_iregs |= 1 << ainfo->reg;
1185 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1186 in = call->args [i];
1187 arg->cil_code = in->cil_code;
1188 arg->inst_left = in;
1189 arg->inst_call = call;
1190 arg->type = in->type;
1191 /* prepend, we'll need to reverse them later */
1192 arg->next = call->out_args;
1193 call->out_args = arg;
1194 if (ainfo->regtype == RegTypeGeneral) {
1195 arg->backend.reg3 = ainfo->reg;
1196 call->used_iregs |= 1 << ainfo->reg;
1197 if (arg->type == STACK_I8)
1198 call->used_iregs |= 1 << (ainfo->reg + 1);
1199 } else if (ainfo->regtype == RegTypeStructByAddr) {
1200 /* FIXME: where is the data allocated? */
1201 arg->backend.reg3 = ainfo->reg;
1202 call->used_iregs |= 1 << ainfo->reg;
1203 } else if (ainfo->regtype == RegTypeStructByVal) {
1205 MonoMIPSArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMIPSArgInfo));
1206 /* mark the used regs */
1207 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1208 call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1210 arg->opcode = OP_OUTARG_VT;
1211 ai->reg = ainfo->reg;
1212 ai->size = ainfo->size;
1213 ai->vtsize = ainfo->vtsize;
1214 ai->offset = ainfo->offset;
1215 arg->backend.data = ai;
1217 g_printf ("OUTARG_VT reg=%d size=%d vtsize=%d offset=%d\n",
1218 ai->reg, ai->size, ai->vtsize, ai->offset);
1220 } else if (ainfo->regtype == RegTypeBase) {
1221 MonoMIPSArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMIPSArgInfo));
1222 arg->opcode = OP_OUTARG_MEMBASE;
1223 ai->reg = ainfo->reg;
1224 ai->size = ainfo->size;
1225 ai->offset = ainfo->offset;
1226 arg->backend.data = ai;
1227 } else if (ainfo->regtype == RegTypeFP) {
1228 arg->opcode = OP_OUTARG_R8;
1229 arg->backend.reg3 = ainfo->reg;
1230 call->used_fregs |= 1 << ainfo->reg;
1231 if (ainfo->size == 4) {
1232 arg->opcode = OP_OUTARG_R4;
1233 /* we reduce the precision */
1235 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1236 conv->inst_left = arg->inst_left;
1237 arg->inst_left = conv;*/
1240 g_assert_not_reached ();
1245 * Reverse the call->out_args list.
1248 MonoInst *prev = NULL, *list = call->out_args, *next;
1255 call->out_args = prev;
1257 call->stack_usage = cinfo->stack_usage;
1258 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1259 cfg->param_area = MAX (cfg->param_area, 16); /* a0-a3 always present */
1260 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1261 cfg->flags |= MONO_CFG_HAS_CALLS;
1263 * should set more info in call, such as the stack space
1264 * used by the args that needs to be added back to esp
1272 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1274 MonoInst *ins, *last_ins = NULL;
1279 switch (ins->opcode) {
1281 /* remove unnecessary multiplication with 1 */
1282 if (ins->inst_imm == 1) {
1283 if (ins->dreg != ins->sreg1) {
1284 ins->opcode = OP_MOVE;
1286 last_ins->next = ins->next;
1291 int power2 = mono_is_power_of_two (ins->inst_imm);
1293 ins->opcode = OP_SHL_IMM;
1294 ins->inst_imm = power2;
1298 case OP_LOAD_MEMBASE:
1299 case OP_LOADI4_MEMBASE:
1301 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1302 * OP_LOAD_MEMBASE offset(basereg), reg
1304 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1305 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1306 ins->inst_basereg == last_ins->inst_destbasereg &&
1307 ins->inst_offset == last_ins->inst_offset) {
1308 if (ins->dreg == last_ins->sreg1) {
1309 last_ins->next = ins->next;
1313 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1314 ins->opcode = OP_MOVE;
1315 ins->sreg1 = last_ins->sreg1;
1320 * Note: reg1 must be different from the basereg in the second load
1321 * OP_LOAD_MEMBASE offset(basereg), reg1
1322 * OP_LOAD_MEMBASE offset(basereg), reg2
1324 * OP_LOAD_MEMBASE offset(basereg), reg1
1325 * OP_MOVE reg1, reg2
1327 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1328 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1329 ins->inst_basereg != last_ins->dreg &&
1330 ins->inst_basereg == last_ins->inst_basereg &&
1331 ins->inst_offset == last_ins->inst_offset) {
1333 if (ins->dreg == last_ins->dreg) {
1334 last_ins->next = ins->next;
1338 ins->opcode = OP_MOVE;
1339 ins->sreg1 = last_ins->dreg;
1342 //g_assert_not_reached ();
1347 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1348 * OP_LOAD_MEMBASE offset(basereg), reg
1350 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1351 * OP_ICONST reg, imm
1353 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1354 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1355 ins->inst_basereg == last_ins->inst_destbasereg &&
1356 ins->inst_offset == last_ins->inst_offset) {
1357 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1358 ins->opcode = OP_ICONST;
1359 ins->inst_c0 = last_ins->inst_imm;
1360 g_assert_not_reached (); // check this rule
1365 case OP_LOADU1_MEMBASE:
1366 case OP_LOADI1_MEMBASE:
1367 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1368 ins->inst_basereg == last_ins->inst_destbasereg &&
1369 ins->inst_offset == last_ins->inst_offset) {
1370 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? CEE_CONV_I1 : CEE_CONV_U1;
1371 ins->sreg1 = last_ins->sreg1;
1374 case OP_LOADU2_MEMBASE:
1375 case OP_LOADI2_MEMBASE:
1376 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1377 ins->inst_basereg == last_ins->inst_destbasereg &&
1378 ins->inst_offset == last_ins->inst_offset) {
1379 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? CEE_CONV_I2 : CEE_CONV_U2;
1380 ins->sreg1 = last_ins->sreg1;
1387 ins->opcode = OP_MOVE;
1391 if (ins->dreg == ins->sreg1) {
1393 last_ins->next = ins->next;
1398 * OP_MOVE sreg, dreg
1399 * OP_MOVE dreg, sreg
1401 if (last_ins && last_ins->opcode == OP_MOVE &&
1402 ins->sreg1 == last_ins->dreg &&
1403 ins->dreg == last_ins->sreg1) {
1404 last_ins->next = ins->next;
1413 bb->last_ins = last_ins;
1416 static inline InstList*
1417 inst_list_prepend (MonoMemPool *pool, InstList *list, MonoInst *data)
1419 InstList *item = mono_mempool_alloc (pool, sizeof (InstList));
1429 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1433 bb->code = to_insert;
1434 to_insert->next = ins;
1436 to_insert->next = ins->next;
1437 ins->next = to_insert;
1441 #define NEW_INS(cfg,dest,op) do { \
1442 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1443 (dest)->opcode = (op); \
1444 insert_after_ins (bb, last_ins, (dest)); \
1448 map_to_reg_reg_op (int op)
1457 case OP_COMPARE_IMM:
1473 case OP_LOAD_MEMBASE:
1474 return OP_LOAD_MEMINDEX;
1475 case OP_LOADI4_MEMBASE:
1476 return OP_LOADI4_MEMINDEX;
1477 case OP_LOADU4_MEMBASE:
1478 return OP_LOADU4_MEMINDEX;
1479 case OP_LOADU1_MEMBASE:
1480 return OP_LOADU1_MEMINDEX;
1481 case OP_LOADI2_MEMBASE:
1482 return OP_LOADI2_MEMINDEX;
1483 case OP_LOADU2_MEMBASE:
1484 return OP_LOADU2_MEMINDEX;
1485 case OP_LOADI1_MEMBASE:
1486 return OP_LOADI1_MEMINDEX;
1487 case OP_LOADR4_MEMBASE:
1488 return OP_LOADR4_MEMINDEX;
1489 case OP_LOADR8_MEMBASE:
1490 return OP_LOADR8_MEMINDEX;
1491 case OP_STOREI1_MEMBASE_REG:
1492 return OP_STOREI1_MEMINDEX;
1493 case OP_STOREI2_MEMBASE_REG:
1494 return OP_STOREI2_MEMINDEX;
1495 case OP_STOREI4_MEMBASE_REG:
1496 return OP_STOREI4_MEMINDEX;
1497 case OP_STORE_MEMBASE_REG:
1498 return OP_STORE_MEMINDEX;
1499 case OP_STORER4_MEMBASE_REG:
1500 return OP_STORER4_MEMINDEX;
1501 case OP_STORER8_MEMBASE_REG:
1502 return OP_STORER8_MEMINDEX;
1503 case OP_STORE_MEMBASE_IMM:
1504 return OP_STORE_MEMBASE_REG;
1505 case OP_STOREI1_MEMBASE_IMM:
1506 return OP_STOREI1_MEMBASE_REG;
1507 case OP_STOREI2_MEMBASE_IMM:
1508 return OP_STOREI2_MEMBASE_REG;
1509 case OP_STOREI4_MEMBASE_IMM:
1510 return OP_STOREI4_MEMBASE_REG;
1512 g_assert_not_reached ();
1516 * Remove from the instruction list the instructions that can't be
1517 * represented with very simple instructions with no register
1521 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1523 MonoInst *ins, *next, *temp, *last_ins = NULL;
1526 /* setup the virtual reg allocator */
1527 if (bb->max_vreg > cfg->rs->next_vreg)
1528 cfg->rs->next_vreg = bb->max_vreg;
1533 switch (ins->opcode) {
1536 if (!mips_is_imm16 (ins->inst_imm)) {
1537 NEW_INS (cfg, temp, OP_ICONST);
1538 temp->inst_c0 = ins->inst_imm;
1539 temp->dreg = mono_regstate_next_int (cfg->rs);
1540 ins->sreg2 = temp->dreg;
1541 ins->opcode = map_to_reg_reg_op (ins->opcode);
1546 if (!mips_is_imm16 (-ins->inst_imm)) {
1547 NEW_INS (cfg, 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 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
1560 NEW_INS (cfg, temp, OP_ICONST);
1561 temp->inst_c0 = ins->inst_imm;
1562 temp->dreg = mono_regstate_next_int (cfg->rs);
1563 ins->sreg2 = temp->dreg;
1564 ins->opcode = map_to_reg_reg_op (ins->opcode);
1572 NEW_INS (cfg, 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);
1580 case OP_COMPARE_IMM:
1581 if (compare_opcode_is_unsigned (ins->next->opcode)) {
1582 if (!ppc_is_uimm16 (ins->inst_imm)) {
1583 NEW_INS (cfg, temp, OP_ICONST);
1584 temp->inst_c0 = ins->inst_imm;
1585 temp->dreg = mono_regstate_next_int (cfg->rs);
1586 ins->sreg2 = temp->dreg;
1587 ins->opcode = map_to_reg_reg_op (ins->opcode);
1590 if (!ppc_is_imm16 (ins->inst_imm)) {
1591 NEW_INS (cfg, temp, OP_ICONST);
1592 temp->inst_c0 = ins->inst_imm;
1593 temp->dreg = mono_regstate_next_int (cfg->rs);
1594 ins->sreg2 = temp->dreg;
1595 ins->opcode = map_to_reg_reg_op (ins->opcode);
1602 if (ins->inst_imm == 1) {
1603 ins->opcode = OP_MOVE;
1606 if (ins->inst_imm == 0) {
1607 ins->opcode = OP_ICONST;
1611 imm = mono_is_power_of_two (ins->inst_imm);
1613 ins->opcode = OP_SHL_IMM;
1614 ins->inst_imm = imm;
1617 if (!ppc_is_imm16 (ins->inst_imm)) {
1618 NEW_INS (cfg, temp, OP_ICONST);
1619 temp->inst_c0 = ins->inst_imm;
1620 temp->dreg = mono_regstate_next_int (cfg->rs);
1621 ins->sreg2 = temp->dreg;
1622 ins->opcode = map_to_reg_reg_op (ins->opcode);
1627 case OP_LOAD_MEMBASE:
1628 case OP_LOADI4_MEMBASE:
1629 case OP_LOADU4_MEMBASE:
1630 case OP_LOADI2_MEMBASE:
1631 case OP_LOADU2_MEMBASE:
1632 case OP_LOADI1_MEMBASE:
1633 case OP_LOADU1_MEMBASE:
1634 case OP_LOADR4_MEMBASE:
1635 case OP_LOADR8_MEMBASE:
1636 case OP_STORE_MEMBASE_REG:
1637 case OP_STOREI4_MEMBASE_REG:
1638 case OP_STOREI2_MEMBASE_REG:
1639 case OP_STOREI1_MEMBASE_REG:
1640 case OP_STORER4_MEMBASE_REG:
1641 case OP_STORER8_MEMBASE_REG:
1642 /* we can do two things: load the immed in a register
1643 * and use an indexed load, or see if the immed can be
1644 * represented as an ad_imm + a load with a smaller offset
1645 * that fits. We just do the first for now, optimize later.
1647 if (ppc_is_imm16 (ins->inst_offset))
1649 NEW_INS (cfg, temp, OP_ICONST);
1650 temp->inst_c0 = ins->inst_offset;
1651 temp->dreg = mono_regstate_next_int (cfg->rs);
1652 ins->sreg2 = temp->dreg;
1653 ins->opcode = map_to_reg_reg_op (ins->opcode);
1656 case OP_STORE_MEMBASE_IMM:
1657 case OP_STOREI1_MEMBASE_IMM:
1658 case OP_STOREI2_MEMBASE_IMM:
1659 case OP_STOREI4_MEMBASE_IMM:
1660 if (!ins->inst_imm) {
1661 ins->sreg1 = mips_zero;
1662 ins->opcode = map_to_reg_reg_op (ins->opcode);
1665 NEW_INS (cfg, temp, OP_ICONST);
1666 temp->inst_c0 = ins->inst_imm;
1667 temp->dreg = mono_regstate_next_int (cfg->rs);
1668 ins->sreg1 = temp->dreg;
1669 ins->opcode = map_to_reg_reg_op (ins->opcode);
1671 goto loop_start; /* make it handle the possibly big ins->inst_offset */
1678 bb->last_ins = last_ins;
1679 bb->max_vreg = cfg->rs->next_vreg;
1683 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1687 mono_arch_lowering_pass (cfg, bb);
1688 mono_local_regalloc (cfg, bb);
1692 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
1694 /* sreg is a float, dreg is an integer reg. mips_at is used a scratch */
1696 mips_truncwd (code, mips_ftemp, sreg);
1698 mips_cvtwd (code, mips_ftemp, sreg);
1700 mips_mfc1 (code, dreg, mips_ftemp);
1703 mips_andi (code, dreg, dreg, 0xff);
1704 else if (size == 2) {
1705 mips_sll (code, dreg, dreg, 16);
1706 mips_srl (code, dreg, dreg, 16);
1710 mips_sll (code, dreg, dreg, 24);
1711 mips_sra (code, dreg, dreg, 24);
1713 else if (size == 2) {
1714 mips_sll (code, dreg, dreg, 16);
1715 mips_sra (code, dreg, dreg, 16);
1722 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
1727 guint8 *code = cfg->native_code + cfg->code_len;
1728 MonoInst *last_ins = NULL;
1729 guint last_offset = 0;
1733 if (cfg->opt & MONO_OPT_PEEPHOLE)
1734 peephole_pass (cfg, bb);
1736 /* we don't align basic blocks of loops on mips */
1738 if (cfg->verbose_level > 2)
1739 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
1741 cpos = bb->max_offset;
1744 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
1745 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
1746 g_assert (!mono_compile_aot);
1749 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
1750 /* this is not thread save, but good enough */
1751 /* fixme: howto handle overflows? */
1752 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
1753 mips_lw (code, mips_temp, mips_at, 0);
1754 mips_addiu (code, mips_temp, mips_temp, 1);
1755 mips_sw (code, mips_temp, mips_at, 0);
1760 offset = code - cfg->native_code;
1762 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
1764 if (offset > (cfg->code_size - max_len - 16)) {
1765 cfg->code_size *= 2;
1766 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1767 code = cfg->native_code + offset;
1769 mono_debug_record_line_number (cfg, ins, offset);
1770 if (cfg->verbose_level > 2) {
1771 g_print (" @ 0x%x\t", offset);
1772 mono_print_ins (ins_cnt++, ins);
1775 switch (ins->opcode) {
1777 g_assert_not_reached();
1779 emit_tls_access (code, ins->dreg, ins->inst_offset);
1783 mips_mult (code, ins->sreg1, ins->sreg2);
1784 mips_mflo (code, ins->dreg);
1785 mips_mfhi (code, ins->dreg+1);
1788 mips_multu (code, ins->sreg1, ins->sreg2);
1789 mips_mflo (code, ins->dreg);
1790 mips_mfhi (code, ins->dreg+1);
1792 case OP_MEMORY_BARRIER:
1797 case OP_STOREI1_MEMBASE_IMM:
1798 mips_load_const (code, mips_temp, ins->inst_imm);
1799 if (mips_is_imm16 (ins->inst_offset)) {
1800 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
1802 mips_load_const (code, mips_at, ins->inst_offset);
1803 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
1806 case OP_STOREI2_MEMBASE_IMM:
1807 mips_load_const (code, mips_temp, ins->inst_imm);
1808 if (mips_is_imm16 (ins->inst_offset)) {
1809 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
1811 mips_load_const (code, mips_at, ins->inst_offset);
1812 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
1815 case OP_STORE_MEMBASE_IMM:
1816 case OP_STOREI4_MEMBASE_IMM:
1817 mips_load_const (code, mips_temp, ins->inst_imm);
1818 if (mips_is_imm16 (ins->inst_offset)) {
1819 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
1821 mips_load_const (code, mips_at, ins->inst_offset);
1822 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
1825 case OP_STOREI1_MEMBASE_REG:
1826 if (mips_is_imm16 (ins->inst_offset)) {
1827 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1829 mips_load_const (code, mips_at, ins->inst_offset);
1830 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
1831 mips_sb (code, ins->sreg1, mips_at, 0);
1834 case OP_STOREI2_MEMBASE_REG:
1835 if (mips_is_imm16 (ins->inst_offset)) {
1836 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1838 mips_load_const (code, mips_at, ins->inst_offset);
1839 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
1840 mips_sh (code, ins->sreg1, mips_at, 0);
1843 case OP_STORE_MEMBASE_REG:
1844 case OP_STOREI4_MEMBASE_REG:
1845 if (mips_is_imm16 (ins->inst_offset)) {
1846 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1848 mips_load_const (code, mips_at, ins->inst_offset);
1849 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
1850 mips_sw (code, ins->sreg1, mips_at, 0);
1856 g_assert_not_reached ();
1857 //x86_mov_reg_mem (code, ins->dreg, ins->inst_p0, 4);
1860 g_assert_not_reached ();
1861 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
1862 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
1864 case OP_LOAD_MEMBASE:
1865 case OP_LOADI4_MEMBASE:
1866 case OP_LOADU4_MEMBASE:
1867 if (mips_is_imm16 (ins->inst_offset)) {
1868 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1870 mips_load_const (code, mips_at, ins->inst_offset);
1871 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1872 mips_lw (code, ins->dreg, mips_at, 0);
1875 case OP_LOADI1_MEMBASE:
1876 if (mips_is_imm16 (ins->inst_offset)) {
1877 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1879 mips_load_const (code, mips_at, ins->inst_offset);
1880 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1881 mips_lb (code, ins->dreg, mips_at, 0);
1884 case OP_LOADU1_MEMBASE:
1885 if (mips_is_imm16 (ins->inst_offset)) {
1886 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1888 mips_load_const (code, mips_at, ins->inst_offset);
1889 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1890 mips_lbu (code, ins->dreg, mips_at, 0);
1893 case OP_LOADI2_MEMBASE:
1894 if (mips_is_imm16 (ins->inst_offset)) {
1895 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1897 mips_load_const (code, mips_at, ins->inst_offset);
1898 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1899 mips_lh (code, ins->dreg, mips_at, 0);
1902 case OP_LOADU2_MEMBASE:
1903 if (mips_is_imm16 (ins->inst_offset)) {
1904 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1906 mips_load_const (code, mips_at, ins->inst_offset);
1907 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1908 mips_lhu (code, ins->dreg, mips_at, 0);
1912 mips_sll (code, mips_at, ins->sreg1, 24);
1913 mips_sra (code, ins->dreg, mips_at, 24);
1916 mips_sll (code, mips_at, ins->sreg1, 16);
1917 mips_sra (code, ins->dreg, mips_at, 16);
1920 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
1923 mips_sll (code, mips_at, ins->sreg1, 16);
1924 mips_srl (code, ins->dreg, mips_at, 16);
1927 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
1930 g_assert (mips_is_imm16 (ins->inst_imm));
1931 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
1934 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
1937 g_assert (mips_is_imm16 (ins->inst_imm));
1938 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
1940 case OP_COMPARE_IMM:
1941 g_assert_not_reached ();
1944 g_assert_not_reached ();
1947 mips_break (code, 0xfd);
1950 g_assert_not_reached ();
1953 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
1956 g_assert_not_reached ();
1959 g_assert_not_reached ();
1962 if (mips_is_imm16 (ins->inst_imm)) {
1963 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
1965 mips_load_const (code, mips_at, ins->inst_imm);
1966 mips_addu (code, ins->dreg, ins->sreg1, mips_at);
1970 g_assert_not_reached ();
1973 /* rewritten in .brg file */
1974 g_assert_not_reached ();
1976 case CEE_ADD_OVF_UN:
1977 /* rewritten in .brg file */
1978 g_assert_not_reached ();
1981 /* rewritten in .brg file */
1982 g_assert_not_reached ();
1984 case CEE_SUB_OVF_UN:
1985 /* rewritten in .brg file */
1986 g_assert_not_reached ();
1988 case OP_ADD_OVF_CARRY:
1989 /* rewritten in .brg file */
1990 g_assert_not_reached ();
1992 case OP_ADD_OVF_UN_CARRY:
1993 /* rewritten in .brg file */
1994 g_assert_not_reached ();
1996 case OP_SUB_OVF_CARRY:
1997 /* rewritten in .brg file */
1998 g_assert_not_reached ();
2000 case OP_SUB_OVF_UN_CARRY:
2001 /* rewritten in .brg file */
2002 g_assert_not_reached ();
2005 /* rewritten in .brg file */
2006 g_assert_not_reached ();
2009 /* rewritten in .brg file */
2010 g_assert_not_reached ();
2013 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
2016 g_assert_not_reached ();
2019 // we add the negated value
2020 if (mips_is_imm16 (-ins->inst_imm))
2021 mips_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2023 mips_load_const (code, mips_at, ins->inst_imm);
2024 mips_subu (code, ins->dreg, ins->sreg1, mips_at);
2028 g_assert_not_reached ();
2031 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2034 if (mips_is_imm16 (ins->inst_imm)) {
2035 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2037 mips_load_const (code, mips_at, ins->inst_imm);
2038 mips_and (code, ins->dreg, ins->sreg1, mips_at);
2043 guint32 *divisor_is_m1;
2044 guint32 *divisor_is_zero;
2047 mips_addiu (code, mips_at, mips_zero, 0xffff);
2048 divisor_is_m1 = (guint32 *)code;
2049 mips_bne (code, ins->sreg2, mips_at, 0);
2052 /* Divide by -1 -- throw exception */
2053 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
2055 mips_patch (divisor_is_m1, (guint32)code);
2057 /* Put divide in branch delay slot (NOT YET) */
2058 divisor_is_zero = (guint32 *)code;
2059 mips_bne (code, ins->sreg2, mips_zero, 0);
2062 /* Divide by zero -- throw exception */
2063 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2065 mips_patch (divisor_is_zero, (guint32)code);
2066 mips_div (code, ins->sreg1, ins->sreg2);
2067 if (ins->opcode == CEE_DIV)
2068 mips_mflo (code, ins->dreg);
2070 mips_mfhi (code, ins->dreg);
2074 guint32 *divisor_is_zero = (guint32 *)(void *)code;
2076 /* Put divide in branch delay slot (NOT YET) */
2077 mips_bne (code, ins->sreg2, mips_zero, 0);
2080 /* Divide by zero -- throw exception */
2081 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2083 mips_patch (divisor_is_zero, (guint32)code);
2084 mips_divu (code, ins->sreg1, ins->sreg2);
2085 mips_mflo (code, ins->dreg);
2089 g_assert_not_reached ();
2091 ppc_load (code, ppc_r11, ins->inst_imm);
2092 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
2093 ppc_mfspr (code, ppc_r0, ppc_xer);
2094 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2095 /* FIXME: use OverflowException for 0x80000000/-1 */
2096 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2098 g_assert_not_reached();
2101 guint32 *divisor_is_zero = (guint32 *)(void *)code;
2103 /* Put divide in branch delay slot (NOT YET) */
2104 mips_bne (code, ins->sreg2, mips_zero, 0);
2107 /* Divide by zero -- throw exception */
2108 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2110 mips_patch (divisor_is_zero, (guint32)code);
2111 mips_divu (code, ins->sreg1, ins->sreg2);
2112 mips_mfhi (code, ins->dreg);
2116 g_assert_not_reached ();
2118 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2121 if (mips_is_imm16 (ins->inst_imm)) {
2122 mips_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2124 mips_load_const (code, mips_at, ins->inst_imm);
2125 mips_or (code, ins->dreg, ins->sreg1, mips_at);
2129 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2132 /* unsigned 16-bit immediate */
2133 if ((ins->inst_imm & 0xffff) == ins->inst_imm) {
2134 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
2136 mips_load_const (code, mips_at, ins->inst_imm);
2137 mips_xor (code, ins->dreg, ins->sreg1, mips_at);
2141 g_assert (mips_is_imm16 (ins->inst_imm));
2142 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
2145 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
2148 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2151 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
2154 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2157 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2160 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
2163 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
2166 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
2170 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
2172 mips_mult (code, ins->sreg1, ins->sreg2);
2173 mips_mflo (code, ins->dreg);
2179 mips_load_const (code, mips_at, ins->inst_imm);
2181 mips_mul (code, ins->dreg, ins->sreg1, mips_at);
2183 mips_mult (code, ins->sreg1, mips_at);
2184 mips_mflo (code, ins->dreg);
2191 mips_mult (code, ins->sreg1, ins->sreg2);
2192 mips_mflo (code, ins->dreg);
2193 mips_mfhi (code, mips_at);
2196 mips_sra (code, mips_temp, ins->dreg, 31);
2197 patch = (guint32 *)(void *)code;
2198 mips_beq (code, mips_temp, mips_at, 0);
2200 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
2201 mips_patch (patch, (guint32)code);
2204 case CEE_MUL_OVF_UN:
2206 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
2208 mips_mult (code, ins->sreg1, ins->sreg2);
2209 mips_mflo (code, ins->dreg);
2210 mips_mfhi (code, mips_at);
2214 /* XXX - Throw exception if we overflowed */
2218 mips_load_const (code, ins->dreg, ins->inst_c0);
2221 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2222 mips_load (code, ins->dreg, 0);
2226 mips_mtc1 (code, ins->dreg, ins->sreg1);
2229 mips_mfc1 (code, ins->dreg, ins->sreg1);
2232 mips_dmtc1 (code, ins->dreg, ins->sreg1);
2235 mips_dmfc1 (code, ins->dreg, ins->sreg1);
2242 if (ins->dreg != ins->sreg1)
2243 mips_move (code, ins->dreg, ins->sreg1);
2246 /* Get sreg1 into v1, sreg2 into v0 */
2248 if (ins->sreg1 == mips_v0) {
2249 if (ins->sreg1 != mips_at)
2250 mips_move (code, mips_at, ins->sreg1);
2251 if (ins->sreg2 != mips_v0)
2252 mips_move (code, mips_v0, ins->sreg2);
2253 mips_move (code, mips_v1, mips_at);
2256 if (ins->sreg2 != mips_v0)
2257 mips_move (code, mips_v0, ins->sreg2);
2258 if (ins->sreg1 != mips_v1)
2259 mips_move (code, mips_v1, ins->sreg1);
2263 if (ins->dreg != ins->sreg1) {
2264 mips_fmovd (code, ins->dreg, ins->sreg1);
2268 if (ins->dreg != ins->sreg1) {
2269 mips_fmovd (code, ins->dreg, ins->sreg1);
2273 /* Convert from double to float and leave it there */
2274 mips_cvtsd (code, ins->dreg, ins->sreg1);
2276 case OP_FCONV_TO_R4:
2277 /* Convert from double to float and back again */
2278 mips_cvtsd (code, ins->dreg, ins->sreg1);
2279 mips_cvtds (code, ins->dreg, ins->dreg);
2283 * Pop our stack, then jump to specified method (tail-call)
2284 * Keep in sync with mono_arch_emit_epilog
2286 code = mono_arch_emit_epilog_sub (cfg, code);
2288 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
2289 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2291 mips_lui (code, mips_t9, mips_zero, 0);
2292 mips_addiu (code, mips_t9, mips_t9, 0);
2293 mips_jr (code, mips_t9);
2296 mips_beq (code, mips_zero, mips_zero, 0);
2301 /* ensure ins->sreg1 is not NULL */
2302 mips_lw (code, mips_zero, ins->sreg1, 0);
2305 if (mips_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2306 mips_addiu (code, mips_at, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2308 mips_load_const (code, mips_at, cfg->sig_cookie + cfg->stack_usage);
2309 mips_addu (code, mips_at, cfg->frame_reg, mips_at);
2311 mips_sw (code, mips_at, ins->sreg1, 0);
2322 case OP_VOIDCALL_REG:
2324 case OP_FCALL_MEMBASE:
2325 case OP_LCALL_MEMBASE:
2326 case OP_VCALL_MEMBASE:
2327 case OP_VOIDCALL_MEMBASE:
2328 case OP_CALL_MEMBASE:
2329 switch (ins->opcode) {
2335 call = (MonoCallInst*)ins;
2336 if (ins->flags & MONO_INST_HAS_METHOD)
2337 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2339 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2340 mips_lui (code, mips_t9, mips_zero, 0);
2341 mips_addiu (code, mips_t9, mips_t9, 0);
2346 case OP_VOIDCALL_REG:
2348 mips_move (code, mips_t9, ins->sreg1);
2350 case OP_FCALL_MEMBASE:
2351 case OP_LCALL_MEMBASE:
2352 case OP_VCALL_MEMBASE:
2353 case OP_VOIDCALL_MEMBASE:
2354 case OP_CALL_MEMBASE:
2355 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
2358 mips_jalr (code, mips_t9, mips_ra);
2362 g_assert_not_reached ();
2365 int area_offset = cfg->param_area;
2367 /* Round up ins->sreg1, mips_at ends up holding size */
2368 mips_addiu (code, mips_at, ins->sreg1, 31);
2369 mips_andi (code, mips_at, mips_at, ~31);
2371 mips_subu (code, mips_sp, mips_sp, mips_at);
2372 mips_addiu (code, ins->dreg, mips_sp, area_offset);
2374 if (ins->flags & MONO_INST_INIT) {
2375 mips_move (code, mips_temp, ins->dreg);
2376 mips_sb (code, mips_zero, mips_temp, 0);
2377 mips_addiu (code, mips_at, mips_at, -1);
2378 mips_bne (code, mips_at, mips_zero, -4);
2379 mips_addiu (code, mips_temp, mips_temp, 1);
2384 mips_jr (code, mips_ra);
2388 gpointer addr = mono_arch_get_throw_exception();
2389 mips_move (code, mips_a0, ins->sreg1);
2390 mips_load_const (code, mips_t9, addr);
2391 mips_jalr (code, mips_t9, mips_ra);
2393 mips_break (code, 0xfc);
2397 gpointer addr = mono_arch_get_rethrow_exception();
2398 mips_move (code, mips_a0, ins->sreg1);
2399 mips_load_const (code, mips_t9, addr);
2400 mips_jalr (code, mips_t9, mips_ra);
2402 mips_break (code, 0xfb);
2405 case OP_START_HANDLER:
2407 * The START_HANDLER instruction marks the beginning of a handler
2408 * block. It is called using a call instruction, so mips_ra contains
2409 * the return address. Since the handler executes in the same stack
2410 * frame as the method itself, we can't use save/restore to save
2411 * the return address. Instead, we save it into a dedicated
2414 if (mips_is_imm16 (ins->inst_left->inst_offset)) {
2415 mips_sw (code, mips_ra, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2417 mips_load_const (code, mips_at, ins->inst_left->inst_offset);
2418 mips_add (code, mips_at, mips_at, ins->inst_left->inst_basereg);
2419 mips_sw (code, mips_ra, mips_at, 0);
2423 if (ins->sreg1 != mips_v0)
2424 mips_move (code, mips_v0, ins->sreg1);
2425 if (mips_is_imm16 (ins->inst_left->inst_offset)) {
2426 mips_lw (code, mips_ra, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2428 mips_load_const (code, mips_at, ins->inst_left->inst_offset);
2429 mips_addu (code, mips_at, mips_at, ins->inst_left->inst_basereg);
2430 mips_lw (code, mips_ra, mips_at, 0);
2432 mips_jr (code, mips_ra);
2436 mips_lw (code, mips_t9, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2437 mips_jalr (code, mips_t9, mips_ra);
2440 case OP_CALL_HANDLER:
2441 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2442 mips_lui (code, mips_t9, mips_zero, 0);
2443 mips_addiu (code, mips_t9, mips_t9, 0);
2444 mips_jalr (code, mips_t9, mips_ra);
2448 ins->inst_c0 = code - cfg->native_code;
2451 if (ins->flags & MONO_INST_BRLABEL) {
2452 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2454 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2457 mips_lui (code, mips_at, mips_zero, 0);
2458 mips_addiu (code, mips_at, mips_at, 0);
2459 mips_jr (code, mips_at);
2462 mips_beq (code, mips_zero, mips_zero, 0);
2467 mips_jr (code, ins->sreg1);
2473 max_len += 4 * GPOINTER_TO_INT (ins->klass);
2474 if (offset > (cfg->code_size - max_len - 16)) {
2475 cfg->code_size += max_len;
2476 cfg->code_size *= 2;
2477 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2478 code = cfg->native_code + offset;
2480 g_assert (ins->sreg1 != -1);
2481 mips_sll (code, mips_at, ins->sreg1, 2);
2482 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
2483 mips_move (code, mips_t8, mips_ra);
2484 mips_bgezal (code, mips_zero, 1); /* bal */
2486 mips_addu (code, mips_t9, mips_ra, mips_at);
2487 /* Table is 16 or 20 bytes from target of bal above */
2488 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
2489 mips_move (code, mips_ra, mips_t8);
2490 mips_lw (code, mips_t9, mips_t9, 20);
2493 mips_lw (code, mips_t9, mips_t9, 16);
2494 mips_jalr (code, mips_t9, mips_t8);
2496 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
2497 mips_emit32 (code, 0xfefefefe);
2501 mips_addiu (code, ins->dreg, mips_zero, 1);
2502 mips_beq (code, mips_at, mips_zero, 2);
2504 mips_move (code, ins->dreg, mips_zero);
2508 mips_addiu (code, ins->dreg, mips_zero, 1);
2509 mips_bltz (code, mips_at, 2);
2511 mips_move (code, ins->dreg, mips_zero);
2515 mips_addiu (code, ins->dreg, mips_zero, 1);
2516 mips_bgtz (code, mips_at, 2);
2518 mips_move (code, ins->dreg, mips_zero);
2521 case OP_COND_EXC_EQ:
2522 case OP_COND_EXC_GE:
2523 case OP_COND_EXC_GT:
2524 case OP_COND_EXC_LE:
2525 case OP_COND_EXC_LT:
2526 case OP_COND_EXC_NE_UN:
2527 case OP_COND_EXC_GE_UN:
2528 case OP_COND_EXC_GT_UN:
2529 case OP_COND_EXC_LE_UN:
2530 case OP_COND_EXC_LT_UN:
2532 case OP_COND_EXC_OV:
2533 case OP_COND_EXC_NO:
2535 case OP_COND_EXC_NC:
2537 case OP_COND_EXC_IEQ:
2538 case OP_COND_EXC_IGE:
2539 case OP_COND_EXC_IGT:
2540 case OP_COND_EXC_ILE:
2541 case OP_COND_EXC_ILT:
2542 case OP_COND_EXC_INE_UN:
2543 case OP_COND_EXC_IGE_UN:
2544 case OP_COND_EXC_IGT_UN:
2545 case OP_COND_EXC_ILE_UN:
2546 case OP_COND_EXC_ILT_UN:
2548 case OP_COND_EXC_IOV:
2549 case OP_COND_EXC_INO:
2550 case OP_COND_EXC_IC:
2551 case OP_COND_EXC_INC:
2552 /* Should be re-mapped to OP_MIPS_B* by *.inssel-mips.brg */
2553 g_warning ("unsupported conditional exception %s\n", mono_inst_name (ins->opcode));
2554 g_assert_not_reached ();
2557 case OP_MIPS_COND_EXC_EQ:
2558 case OP_MIPS_COND_EXC_GE:
2559 case OP_MIPS_COND_EXC_GT:
2560 case OP_MIPS_COND_EXC_LE:
2561 case OP_MIPS_COND_EXC_LT:
2562 case OP_MIPS_COND_EXC_NE_UN:
2563 case OP_MIPS_COND_EXC_GE_UN:
2564 case OP_MIPS_COND_EXC_GT_UN:
2565 case OP_MIPS_COND_EXC_LE_UN:
2566 case OP_MIPS_COND_EXC_LT_UN:
2568 case OP_MIPS_COND_EXC_OV:
2569 case OP_MIPS_COND_EXC_NO:
2570 case OP_MIPS_COND_EXC_C:
2571 case OP_MIPS_COND_EXC_NC:
2573 case OP_MIPS_COND_EXC_IEQ:
2574 case OP_MIPS_COND_EXC_IGE:
2575 case OP_MIPS_COND_EXC_IGT:
2576 case OP_MIPS_COND_EXC_ILE:
2577 case OP_MIPS_COND_EXC_ILT:
2578 case OP_MIPS_COND_EXC_INE_UN:
2579 case OP_MIPS_COND_EXC_IGE_UN:
2580 case OP_MIPS_COND_EXC_IGT_UN:
2581 case OP_MIPS_COND_EXC_ILE_UN:
2582 case OP_MIPS_COND_EXC_ILT_UN:
2584 case OP_MIPS_COND_EXC_IOV:
2585 case OP_MIPS_COND_EXC_INO:
2586 case OP_MIPS_COND_EXC_IC:
2587 case OP_MIPS_COND_EXC_INC: {
2591 /* If the condition is true, raise the exception */
2593 /* need to reverse test to skip around exception raising */
2595 /* For the moment, branch around a branch to avoid reversing
2598 /* Remember, an unpatched branch to 0 branches to the delay slot */
2599 throw = (guint32 *)(void *)code;
2600 switch (ins->opcode) {
2601 case OP_MIPS_COND_EXC_EQ:
2602 mips_beq (code, ins->sreg1, ins->sreg2, 0);
2605 case OP_MIPS_COND_EXC_NE_UN:
2606 mips_bne (code, ins->sreg1, ins->sreg2, 0);
2610 /* Not yet implemented */
2611 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
2612 g_assert_not_reached ();
2614 skip = (guint32 *)(void *)code;
2615 mips_beq (code, mips_zero, mips_zero, 0);
2617 mips_patch (throw, (guint32)code);
2618 code = mips_emit_exc_by_name (code, ins->inst_p1);
2619 mips_patch (skip, (guint32)code);
2620 cfg->bb_exit->max_offset += 24;
2633 /* Should be re-mapped to OP_MIPS_B* by *.inssel-mips.brg */
2634 g_warning ("unsupported conditional set %s\n", mono_inst_name (ins->opcode));
2635 g_assert_not_reached ();
2643 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
2646 /* floating point opcodes */
2648 if (((guint32)ins->inst_p0) & (1 << 15))
2649 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
2651 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
2652 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
2655 if (((guint32)ins->inst_p0) & (1 << 15))
2656 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
2658 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
2659 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
2660 mips_cvtds (code, ins->dreg, ins->dreg);
2662 case OP_STORER8_MEMBASE_REG:
2663 if (mips_is_imm16 (ins->inst_offset)) {
2665 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2667 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset+4);
2668 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset);
2671 mips_load_const (code, mips_at, ins->inst_offset);
2672 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
2673 mips_swc1 (code, ins->sreg1, mips_at, 4);
2674 mips_swc1 (code, ins->sreg1+1, mips_at, 0);
2677 case OP_LOADR8_MEMBASE:
2678 if (mips_is_imm16 (ins->inst_offset)) {
2680 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2682 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset+4);
2683 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset);
2686 mips_load_const (code, mips_at, ins->inst_offset);
2687 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2688 mips_lwc1 (code, ins->dreg, mips_at, 4);
2689 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
2692 case OP_STORER4_MEMBASE_REG:
2693 /* XXX Need to convert ins->sreg1 to single-precision first */
2694 mips_cvtsd (code, mips_ftemp, ins->sreg1);
2695 if (mips_is_imm16 (ins->inst_offset)) {
2696 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
2698 mips_load_const (code, mips_at, ins->inst_offset);
2699 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
2700 mips_swc1 (code, mips_ftemp, mips_at, 0);
2704 if (mips_is_imm16 (ins->inst_offset)) {
2705 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2707 mips_load_const (code, mips_at, ins->inst_offset);
2708 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2709 mips_lwc1 (code, ins->dreg, mips_at, 0);
2712 case OP_LOADR4_MEMBASE:
2713 if (mips_is_imm16 (ins->inst_offset)) {
2714 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2716 mips_load_const (code, mips_at, ins->inst_offset);
2717 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2718 mips_lwc1 (code, ins->dreg, mips_at, 0);
2720 /* Convert to double precision in place */
2721 mips_cvtds (code, ins->dreg, ins->dreg);
2723 case CEE_CONV_R_UN: {
2724 static const guint64 adjust_val = 0x41F0000000000000ULL;
2726 /* convert unsigned int to double */
2727 mips_mtc1 (code, mips_ftemp, ins->sreg1);
2728 mips_bgez (code, ins->sreg1, 5);
2729 mips_cvtdw (code, ins->dreg, mips_ftemp);
2731 mips_load (code, mips_at, (guint32) &adjust_val);
2732 mips_ldc1 (code, mips_ftemp, mips_at, 0);
2733 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
2734 /* target is here */
2738 mips_mtc1 (code, mips_ftemp, ins->sreg1);
2739 mips_cvtsw (code, ins->dreg, mips_ftemp);
2740 mips_cvtds (code, ins->dreg, ins->dreg);
2743 mips_mtc1 (code, mips_ftemp, ins->sreg1);
2744 mips_cvtdw (code, ins->dreg, mips_ftemp);
2746 case OP_FCONV_TO_I1:
2747 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2749 case OP_FCONV_TO_U1:
2750 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2752 case OP_FCONV_TO_I2:
2753 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
2755 case OP_FCONV_TO_U2:
2756 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
2758 case OP_FCONV_TO_I4:
2760 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
2762 case OP_FCONV_TO_U4:
2764 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
2766 case OP_FCONV_TO_I8:
2767 case OP_FCONV_TO_U8:
2768 g_assert_not_reached ();
2769 /* Implemented as helper calls */
2771 case OP_LCONV_TO_R_UN:
2772 g_assert_not_reached ();
2773 /* Implemented as helper calls */
2775 case OP_LCONV_TO_OVF_I:
2776 g_assert_not_reached ();
2777 /* split up by brg file */
2780 mips_fsqrtd (code, ins->dreg, ins->sreg1);
2783 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
2786 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
2789 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
2792 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
2795 mips_fnegd (code, ins->dreg, ins->sreg1);
2799 g_assert_not_reached ();
2802 g_assert_not_reached();
2805 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
2806 mips_addiu (code, ins->dreg, mips_zero, 1);
2807 mips_fbtrue (code, 2);
2809 mips_move (code, ins->dreg, mips_zero);
2812 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
2813 mips_addiu (code, ins->dreg, mips_zero, 1);
2814 mips_fbtrue (code, 2);
2816 mips_move (code, ins->dreg, mips_zero);
2819 /* Less than, or Unordered */
2820 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
2821 mips_addiu (code, ins->dreg, mips_zero, 1);
2822 mips_fbtrue (code, 2);
2824 mips_move (code, ins->dreg, mips_zero);
2827 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
2828 mips_move (code, ins->dreg, mips_zero);
2829 mips_fbtrue (code, 2);
2831 mips_addiu (code, ins->dreg, mips_zero, 1);
2834 /* Greater than, or Unordered */
2835 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
2836 mips_move (code, ins->dreg, mips_zero);
2837 mips_fbtrue (code, 2);
2839 mips_addiu (code, ins->dreg, mips_zero, 1);
2842 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
2844 if (ins->flags & MONO_INST_BRLABEL)
2845 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2847 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2848 mips_fbtrue (code, 0);
2852 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
2854 if (ins->flags & MONO_INST_BRLABEL)
2855 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2857 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2858 mips_fbfalse (code, 0);
2862 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
2864 if (ins->flags & MONO_INST_BRLABEL)
2865 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2867 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2868 mips_fbtrue (code, 0);
2872 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
2874 if (ins->flags & MONO_INST_BRLABEL)
2875 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2877 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2878 mips_fbtrue (code, 0);
2882 mips_fcmpd (code, MIPS_FPU_LE, ins->sreg1, ins->sreg2);
2884 if (ins->flags & MONO_INST_BRLABEL)
2885 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2887 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2888 mips_fbfalse (code, 0);
2892 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
2894 if (ins->flags & MONO_INST_BRLABEL)
2895 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2897 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2898 mips_fbfalse (code, 0);
2902 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
2904 if (ins->flags & MONO_INST_BRLABEL)
2905 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2907 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2908 mips_fbfalse (code, 0);
2912 mips_fcmpd (code, MIPS_FPU_OLT, ins->sreg1, ins->sreg2);
2914 if (ins->flags & MONO_INST_BRLABEL)
2915 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2917 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2918 mips_fbfalse (code, 0);
2922 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
2924 if (ins->flags & MONO_INST_BRLABEL)
2925 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2927 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2928 mips_fbtrue (code, 0);
2932 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
2934 if (ins->flags & MONO_INST_BRLABEL)
2935 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2937 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2938 mips_fbtrue (code, 0);
2942 g_assert_not_reached();
2944 ppc_stfd (code, ins->sreg1, -8, ppc_sp);
2945 ppc_lwz (code, ppc_r11, -8, ppc_sp);
2946 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 1, 31);
2947 ppc_addis (code, ppc_r11, ppc_r11, -32752);
2948 ppc_rlwinmd (code, ppc_r11, ppc_r11, 1, 31, 31);
2949 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
2954 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
2955 g_assert_not_reached ();
2958 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
2959 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
2960 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
2961 g_assert_not_reached ();
2967 last_offset = offset;
2972 cfg->code_len = code - cfg->native_code;
2976 mono_arch_register_lowlevel_calls (void)
2981 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
2983 MonoJumpInfo *patch_info;
2985 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
2986 unsigned char *ip = patch_info->ip.i + code;
2987 const unsigned char *target;
2989 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
2991 switch (patch_info->type) {
2992 case MONO_PATCH_INFO_IP:
2993 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
2995 case MONO_PATCH_INFO_SWITCH: {
2996 /* jt is the inlined jump table, 7 or 9 instructions after ip
2997 * In the normal case we store the absolute addresses.
2998 * otherwise the displacements.
3001 gpointer *table = (gpointer *)patch_info->data.table->table;
3002 gpointer *jt = ((gpointer*)(void *)ip) + 7;
3003 if (1 /* || !(cfg->->flags & MONO_CFG_HAS_CALLS) */)
3005 for (i = 0; i < patch_info->data.table->table_size; i++) {
3006 jt [i] = code + (int)table [i];
3010 case MONO_PATCH_INFO_METHODCONST:
3011 case MONO_PATCH_INFO_CLASS:
3012 case MONO_PATCH_INFO_IMAGE:
3013 case MONO_PATCH_INFO_FIELD:
3014 case MONO_PATCH_INFO_VTABLE:
3015 case MONO_PATCH_INFO_IID:
3016 case MONO_PATCH_INFO_SFLDA:
3017 case MONO_PATCH_INFO_LDSTR:
3018 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3019 case MONO_PATCH_INFO_LDTOKEN:
3020 case MONO_PATCH_INFO_R4:
3021 case MONO_PATCH_INFO_R8:
3022 /* from OP_AOTCONST : lui + addiu */
3023 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
3026 case MONO_PATCH_INFO_EXC_NAME:
3027 g_assert_not_reached ();
3028 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
3031 case MONO_PATCH_INFO_NONE:
3032 /* everything is dealt with at epilog output time */
3037 mips_patch ((guint32 *)(void *)ip, (guint32)target);
3043 mono_trace_lmf_prolog (MonoLMF *new_lmf)
3049 mono_trace_lmf_epilog (MonoLMF *old_lmf)
3054 * Allow tracing to work with this interface (with an optional argument)
3056 * This code is expected to be inserted just after the 'real' prolog code,
3057 * and before the first basic block. We need to allocate a 2nd, temporary
3058 * stack frame so that we can preserve f12-f15 as well as a0-a3.
3062 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
3065 int fp_stack_offset = 0;
3071 mips_sw (code, mips_a0, mips_sp, cfg->stack_offset + 0);
3072 mips_sw (code, mips_a1, mips_sp, cfg->stack_offset + 4);
3073 mips_sw (code, mips_a2, mips_sp, cfg->stack_offset + 8);
3074 mips_sw (code, mips_a3, mips_sp, cfg->stack_offset + 12);
3077 fp_stack_offset = MIPS_STACK_PARAM_OFFSET;
3078 mips_addiu (code, mips_sp, mips_sp, -64);
3079 mips_swc1 (code, mips_f12, mips_sp, fp_stack_offset + 16);
3080 mips_swc1 (code, mips_f13, mips_sp, fp_stack_offset + 20);
3081 mips_swc1 (code, mips_f14, mips_sp, fp_stack_offset + 24);
3082 mips_swc1 (code, mips_f15, mips_sp, fp_stack_offset + 28);
3084 mips_fmovs (code, mips_f22, mips_f12);
3085 mips_fmovs (code, mips_f23, mips_f13);
3086 mips_fmovs (code, mips_f24, mips_f14);
3087 mips_fmovs (code, mips_f25, mips_f15);
3090 mips_load_const (code, mips_a0, cfg->method);
3091 mips_addiu (code, mips_a1, mips_sp, cfg->stack_offset + fp_stack_offset);
3092 mips_load_const (code, mips_t9, func);
3093 mips_jalr (code, mips_t9, mips_ra);
3096 mips_lw (code, mips_a0, mips_sp, cfg->stack_offset + 0);
3097 mips_lw (code, mips_a1, mips_sp, cfg->stack_offset + 4);
3098 mips_lw (code, mips_a2, mips_sp, cfg->stack_offset + 8);
3099 mips_lw (code, mips_a3, mips_sp, cfg->stack_offset + 12);
3102 mips_lwc1 (code, mips_f12, mips_sp, fp_stack_offset + 16);
3103 mips_lwc1 (code, mips_f13, mips_sp, fp_stack_offset + 20);
3104 mips_lwc1 (code, mips_f14, mips_sp, fp_stack_offset + 24);
3105 mips_lwc1 (code, mips_f15, mips_sp, fp_stack_offset + 28);
3106 mips_addiu (code, mips_sp, mips_sp, 64);
3108 mips_fmovs (code, mips_f12, mips_f22);
3109 mips_fmovs (code, mips_f13, mips_f23);
3110 mips_fmovs (code, mips_f14, mips_f24);
3111 mips_fmovs (code, mips_f15, mips_f25);
3121 * Stack frame layout:
3123 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET + cfg->param_area
3124 * param area incoming
3125 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
3127 * ------------------- sp + cfg->stack_usage
3129 * ------------------- sp + cfg->stack_usage-4
3131 * ------------------- sp +
3132 * MonoLMF structure optional
3133 * ------------------- sp + cfg->arch.lmf_offset
3134 * saved registers s0-s8
3135 * ------------------- sp + cfg->arch.iregs_offset
3137 * ------------------- sp + cfg->param_area
3138 * param area outgoing
3139 * ------------------- sp + 16
3141 * ------------------- sp
3145 mono_arch_emit_prolog (MonoCompile *cfg)
3147 MonoMethod *method = cfg->method;
3148 MonoMethodSignature *sig;
3150 int alloc_size, pos, i;
3154 guint32 iregs_to_save = 0;
3156 guint32 fregs_to_save = 0;
3159 /* lmf_offset is the offset of the LMF from our stack pointer. */
3160 guint32 lmf_offset = cfg->arch.lmf_offset;
3163 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3167 cfg->flags |= MONO_CFG_HAS_CALLS;
3169 sig = mono_method_signature (method);
3170 cfg->code_size = 768 + sig->param_count * 20;
3171 code = cfg->native_code = g_malloc (cfg->code_size);
3173 alloc_size = cfg->stack_offset;
3174 g_assert ((alloc_size & (MIPS_STACK_ALIGNMENT-1)) == 0);
3176 /* re-align cfg->stack_offset if needed (due to var spilling in mini-codegen.c) */
3177 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
3179 /* stack_offset should not be changed here. */
3180 alloc_size = cfg->stack_offset;
3181 cfg->stack_usage = alloc_size;
3184 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
3186 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
3190 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
3192 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
3193 fregs_to_save |= (fregs_to_save << 1);
3197 if (mips_is_imm16 (-alloc_size)) {
3198 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
3200 mips_load_const (code, mips_at, -alloc_size);
3201 mips_addu (code, mips_sp, mips_sp, mips_at);
3205 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
3206 mips_sw (code, mips_ra, mips_sp, alloc_size + MIPS_RET_ADDR_OFFSET);
3208 /* XXX - optimize this later to not save all regs if LMF constructed */
3210 if (iregs_to_save) {
3211 /* save used registers in own stack frame (at pos) */
3212 pos = cfg->arch.iregs_offset;
3213 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
3214 if (iregs_to_save & (1 << i)) {
3215 g_assert (pos < cfg->stack_usage - 4);
3216 mips_sw (code, i, mips_sp, pos);
3217 pos += sizeof (gulong);
3222 if (method->save_lmf) {
3223 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
3224 mips_sw (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]));
3230 /* Save float registers */
3231 if (fregs_to_save) {
3232 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
3233 if (fregs_to_save & (1 << i)) {
3234 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
3235 mips_swc1 (code, i, mips_sp, pos);
3236 pos += sizeof (gulong);
3241 if (method->save_lmf) {
3242 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
3243 mips_swc1 (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]));
3248 if (cfg->frame_reg != mips_sp) {
3249 mips_move (code, cfg->frame_reg, mips_sp);
3251 if (method->save_lmf)
3252 mips_sw (code, cfg->frame_reg, mips_sp,
3253 lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]));
3257 /* Do instrumentation before assigning regvars to registers. Because they may be assigned
3258 * to the t* registers, which would be clobbered by the instrumentation calls.
3261 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3264 /* load arguments allocated to register from the stack */
3267 cinfo = calculate_sizes (sig, sig->pinvoke);
3269 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3270 ArgInfo *ainfo = &cinfo->ret;
3272 if (inst->opcode == OP_REGVAR)
3273 mips_move (code, inst->dreg, ainfo->reg);
3274 else if (mips_is_imm16 (inst->inst_offset)) {
3275 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3277 mips_load_const (code, mips_at, inst->inst_offset);
3278 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
3279 mips_sw (code, ainfo->reg, mips_at, 0);
3282 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3283 ArgInfo *ainfo = cinfo->args + i;
3284 inst = cfg->varinfo [pos];
3286 if (cfg->verbose_level > 2)
3287 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3288 if (inst->opcode == OP_REGVAR) {
3289 /* Argument ends up in a register */
3290 if (ainfo->regtype == RegTypeGeneral)
3291 mips_move (code, inst->dreg, ainfo->reg);
3292 else if (ainfo->regtype == RegTypeFP) {
3293 g_assert_not_reached();
3295 ppc_fmr (code, inst->dreg, ainfo->reg);
3298 else if (ainfo->regtype == RegTypeBase) {
3299 mips_lw (code, inst->dreg, mips_sp, cfg->stack_usage + ainfo->offset);
3301 g_assert_not_reached ();
3303 if (cfg->verbose_level > 2)
3304 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3306 /* Argument ends up on the stack */
3307 if (ainfo->regtype == RegTypeGeneral) {
3308 /* Incoming parameters should be above this frame */
3309 g_assert (inst->inst_offset >= alloc_size);
3310 g_assert (mips_is_imm16 (inst->inst_offset));
3311 switch (ainfo->size) {
3313 mips_sb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3316 mips_sh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3320 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3323 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3324 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
3327 g_assert_not_reached ();
3330 } else if (ainfo->regtype == RegTypeBase) {
3332 * Argument comes in on the stack, and ends up on the stack
3333 * 1 and 2 byte args are passed as 32-bit quantities, but used as
3334 * 8 and 16 bit quantities. Shorten them in place.
3336 g_assert (mips_is_imm16 (inst->inst_offset));
3337 switch (ainfo->size) {
3339 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
3340 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
3343 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
3344 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
3351 g_assert_not_reached ();
3353 } else if (ainfo->regtype == RegTypeFP) {
3354 g_assert (mips_is_imm16 (inst->inst_offset));
3355 if (ainfo->size == 8) {
3357 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3359 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
3360 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
3363 else if (ainfo->size == 4)
3364 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3366 g_assert_not_reached ();
3367 } else if (ainfo->regtype == RegTypeStructByVal) {
3369 int doffset = inst->inst_offset;
3371 g_assert (mips_is_imm16 (inst->inst_offset));
3372 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3373 /* Push the argument registers into their stack slots */
3374 for (i = 0; i < ainfo->size; ++i) {
3375 mips_sw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3376 doffset += sizeof (gpointer);
3378 } else if (ainfo->regtype == RegTypeStructByAddr) {
3379 g_assert (mips_is_imm16 (inst->inst_offset));
3380 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3381 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
3383 g_assert_not_reached ();
3388 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
3389 mips_load_const (code, mips_a0, cfg->domain);
3390 mips_load_const (code, mips_t9, (gpointer)mono_jit_thread_attach);
3391 mips_jalr (code, mips_t9, mips_ra);
3396 if (method->save_lmf) {
3397 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
3398 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
3400 if (lmf_pthread_key != -1) {
3401 g_assert_not_reached();
3403 emit_tls_access (code, mips_temp, lmf_pthread_key);
3405 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
3406 mips_addiu (code, mips_a0, mips_temp, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3409 mips_addiu (code, mips_a0, mips_sp, lmf_offset);
3410 mips_load_const (code, mips_t9, (gpointer)mono_trace_lmf_prolog);
3411 mips_jalr (code, mips_t9, mips_ra);
3414 /* This can/will clobber the a0-a3 registers */
3415 mips_load_const (code, mips_t9, (gpointer)mono_get_lmf_addr);
3416 mips_jalr (code, mips_t9, mips_ra);
3420 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
3421 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
3422 /* new_lmf->previous_lmf = *lmf_addr */
3423 mips_lw (code, mips_at, mips_v0, 0);
3424 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
3425 /* *(lmf_addr) = sp + lmf_offset */
3426 mips_addiu (code, mips_at, mips_sp, lmf_offset);
3427 mips_sw (code, mips_at, mips_v0, 0);
3429 /* save method info */
3430 mips_load_const (code, mips_at, method);
3431 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
3432 mips_sw (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
3434 /* save the current IP */
3435 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3436 mips_load_const (code, mips_at, 0x01010101);
3437 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
3441 cfg->code_len = code - cfg->native_code;
3442 g_assert (cfg->code_len < cfg->code_size);
3457 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
3460 int save_mode = SAVE_NONE;
3462 MonoMethod *method = cfg->method;
3463 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
3464 int save_offset = 16;
3469 offset = code - cfg->native_code;
3470 /* we need about 16 instructions */
3471 if (offset > (cfg->code_size - 16 * 4)) {
3472 cfg->code_size *= 2;
3473 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3474 code = cfg->native_code + offset;
3479 case MONO_TYPE_VOID:
3480 /* special case string .ctor icall */
3481 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
3482 save_mode = SAVE_ONE;
3484 save_mode = SAVE_NONE;
3488 save_mode = SAVE_TWO;
3492 save_mode = SAVE_FP;
3494 case MONO_TYPE_VALUETYPE:
3495 save_mode = SAVE_STRUCT;
3498 save_mode = SAVE_ONE;
3502 mips_addiu (code, mips_sp, mips_sp, -32);
3503 switch (save_mode) {
3505 mips_sw (code, mips_v0, mips_sp, save_offset);
3506 mips_sw (code, mips_v1, mips_sp, save_offset + 4);
3507 if (enable_arguments) {
3508 mips_move (code, mips_a1, mips_v0);
3509 mips_move (code, mips_a2, mips_v1);
3513 mips_sw (code, mips_v0, mips_sp, save_offset);
3514 if (enable_arguments) {
3515 mips_move (code, mips_a1, mips_v0);
3519 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
3520 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
3521 mips_lw (code, mips_a0, mips_sp, save_offset);
3522 mips_lw (code, mips_a1, mips_sp, save_offset+4);
3529 mips_load_const (code, mips_a0, cfg->method);
3530 mips_load_const (code, mips_t9, func);
3531 mips_jalr (code, mips_t9, mips_ra);
3534 switch (save_mode) {
3536 mips_lw (code, mips_v0, mips_sp, save_offset);
3537 mips_lw (code, mips_v1, mips_sp, save_offset + 4);
3540 mips_lw (code, mips_v0, mips_sp, save_offset);
3543 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
3550 mips_addiu (code, mips_sp, mips_sp, 32);
3557 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
3559 MonoMethod *method = cfg->method;
3561 int max_epilog_size = 16 + 20*4;
3562 guint32 iregs_to_restore;
3564 guint32 fregs_to_restore;
3568 if (cfg->method->save_lmf)
3569 max_epilog_size += 128;
3572 if (mono_jit_trace_calls != NULL)
3573 max_epilog_size += 50;
3575 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3576 max_epilog_size += 50;
3579 pos = code - cfg->native_code;
3580 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3581 cfg->code_size *= 2;
3582 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3583 mono_jit_stats.code_reallocs++;
3587 * Keep in sync with OP_JMP
3590 code = cfg->native_code + pos;
3592 code = cfg->native_code + cfg->code_len;
3594 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3595 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3597 pos = cfg->arch.iregs_offset;
3598 if (cfg->frame_reg != mips_sp) {
3599 mips_move (code, mips_sp, cfg->frame_reg);
3602 iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
3604 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
3606 if (iregs_to_restore) {
3607 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
3608 if (iregs_to_restore & (1 << i)) {
3609 mips_lw (code, i, mips_sp, pos);
3610 pos += sizeof (gulong);
3617 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
3619 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
3620 fregs_to_restore |= (fregs_to_restore << 1);
3622 if (fregs_to_restore) {
3623 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
3624 if (fregs_to_restore & (1 << i)) {
3625 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
3626 mips_lwc1 (code, i, mips_sp, pos);
3627 pos += sizeof (gulong);
3633 /* Unlink the LMF if necessary */
3634 if (method->save_lmf) {
3635 int lmf_offset = cfg->arch.lmf_offset;
3637 /* t0 = current_lmf->previous_lmf */
3638 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
3640 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
3641 /* (*lmf_addr) = previous_lmf */
3642 mips_sw (code, mips_temp, mips_t1, 0);
3646 /* Restore the fp */
3647 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
3649 /* Correct the stack pointer */
3650 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
3651 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage + MIPS_RET_ADDR_OFFSET);
3652 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage);
3654 /* Caller will emit either return or tail-call sequence */
3656 cfg->code_len = code - cfg->native_code;
3658 g_assert (cfg->code_len < cfg->code_size);
3663 mono_arch_emit_epilog (MonoCompile *cfg)
3667 code = mono_arch_emit_epilog_sub (cfg, NULL);
3669 mips_jr (code, mips_ra);
3672 cfg->code_len = code - cfg->native_code;
3674 g_assert (cfg->code_len < cfg->code_size);
3677 /* remove once throw_exception_by_name is eliminated */
3679 exception_id_by_name (const char *name)
3681 if (strcmp (name, "IndexOutOfRangeException") == 0)
3682 return MONO_EXC_INDEX_OUT_OF_RANGE;
3683 if (strcmp (name, "OverflowException") == 0)
3684 return MONO_EXC_OVERFLOW;
3685 if (strcmp (name, "ArithmeticException") == 0)
3686 return MONO_EXC_ARITHMETIC;
3687 if (strcmp (name, "DivideByZeroException") == 0)
3688 return MONO_EXC_DIVIDE_BY_ZERO;
3689 if (strcmp (name, "InvalidCastException") == 0)
3690 return MONO_EXC_INVALID_CAST;
3691 if (strcmp (name, "NullReferenceException") == 0)
3692 return MONO_EXC_NULL_REF;
3693 if (strcmp (name, "ArrayTypeMismatchException") == 0)
3694 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3695 g_error ("Unknown intrinsic exception %s\n", name);
3700 mono_arch_emit_exceptions (MonoCompile *cfg)
3703 MonoJumpInfo *patch_info;
3706 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3707 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3708 int max_epilog_size = 50;
3710 /* count the number of exception infos */
3713 * make sure we have enough space for exceptions
3714 * 24 is the simulated call to throw_exception_by_name
3716 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3718 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3719 i = exception_id_by_name (patch_info->data.target);
3720 g_assert (i < MONO_EXC_INTRINS_NUM);
3721 if (!exc_throw_found [i]) {
3722 max_epilog_size += 12;
3723 exc_throw_found [i] = TRUE;
3729 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3730 cfg->code_size *= 2;
3731 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3732 mono_jit_stats.code_reallocs++;
3735 code = cfg->native_code + cfg->code_len;
3737 /* add code to raise exceptions */
3738 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3739 switch (patch_info->type) {
3740 case MONO_PATCH_INFO_EXC: {
3742 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
3744 i = exception_id_by_name (patch_info->data.target);
3745 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
3746 if (!exc_throw_pos [i]) {
3749 exc_throw_pos [i] = code;
3750 //g_print ("exc: writing stub at %p\n", code);
3751 mips_load_const (code, mips_a0, patch_info->data.target);
3752 addr = (guint32) mono_arch_get_throw_exception_by_name ();
3753 mips_load_const (code, mips_t9, addr);
3754 mips_jr (code, mips_t9);
3757 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
3759 /* Turn into a Relative patch, pointing at code stub */
3760 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
3761 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
3763 g_assert_not_reached();
3773 cfg->code_len = code - cfg->native_code;
3775 g_assert (cfg->code_len < cfg->code_size);
3780 * Thread local storage support
3783 setup_tls_access (void)
3786 //guint32 *ins, *code;
3788 if (tls_mode == TLS_MODE_FAILED)
3791 if (g_getenv ("MONO_NO_TLS")) {
3792 tls_mode = TLS_MODE_FAILED;
3796 if (tls_mode == TLS_MODE_DETECT) {
3798 tls_mode = TLS_MODE_FAILED;
3802 ins = (guint32*)pthread_getspecific;
3803 /* uncond branch to the real method */
3804 if ((*ins >> 26) == 18) {
3806 val = (*ins & ~3) << 6;
3810 ins = (guint32*)val;
3812 ins = (guint32*) ((char*)ins + val);
3815 code = &cmplwi_1023;
3816 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
3818 ppc_li (code, ppc_r4, 0x48);
3821 if (*ins == cmplwi_1023) {
3822 int found_lwz_284 = 0;
3823 for (ptk = 0; ptk < 20; ++ptk) {
3825 if (!*ins || *ins == blr_ins)
3827 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
3832 if (!found_lwz_284) {
3833 tls_mode = TLS_MODE_FAILED;
3836 tls_mode = TLS_MODE_LTHREADS;
3837 } else if (*ins == li_0x48) {
3839 /* uncond branch to the real method */
3840 if ((*ins >> 26) == 18) {
3842 val = (*ins & ~3) << 6;
3846 ins = (guint32*)val;
3848 ins = (guint32*) ((char*)ins + val);
3851 ppc_li (code, ppc_r0, 0x7FF2);
3852 if (ins [1] == val) {
3853 /* Darwin on G4, implement */
3854 tls_mode = TLS_MODE_FAILED;
3858 ppc_mfspr (code, ppc_r3, 104);
3859 if (ins [1] != val) {
3860 tls_mode = TLS_MODE_FAILED;
3863 tls_mode = TLS_MODE_DARWIN_G5;
3866 tls_mode = TLS_MODE_FAILED;
3870 tls_mode = TLS_MODE_FAILED;
3875 if (monodomain_key == -1) {
3876 ptk = mono_domain_get_tls_key ();
3878 ptk = mono_pthread_key_for_tls (ptk);
3880 monodomain_key = ptk;
3884 if (lmf_pthread_key == -1) {
3885 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
3887 /*g_print ("MonoLMF at: %d\n", ptk);*/
3888 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
3889 init_tls_failed = 1;
3892 lmf_pthread_key = ptk;
3895 if (monothread_key == -1) {
3896 ptk = mono_thread_get_tls_key ();
3898 ptk = mono_pthread_key_for_tls (ptk);
3900 monothread_key = ptk;
3901 /*g_print ("thread inited: %d\n", ptk);*/
3904 /*g_print ("thread not inited yet %d\n", ptk);*/
3910 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3912 setup_tls_access ();
3916 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3921 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3923 int this_dreg = mips_a0;
3926 this_dreg = mips_a1;
3928 /* add the this argument */
3929 if (this_reg != -1) {
3931 MONO_INST_NEW (cfg, this, OP_SETREG);
3932 this->type = this_type;
3933 this->sreg1 = this_reg;
3934 this->dreg = mono_regstate_next_int (cfg->rs);
3935 mono_bblock_add_inst (cfg->cbb, this);
3936 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
3941 MONO_INST_NEW (cfg, vtarg, OP_SETREG);
3942 vtarg->type = STACK_MP;
3943 vtarg->sreg1 = vt_reg;
3944 vtarg->dreg = mono_regstate_next_int (cfg->rs);
3945 mono_bblock_add_inst (cfg->cbb, vtarg);
3946 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
3951 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3953 MonoInst *ins = NULL;
3955 if (cmethod->klass == mono_defaults.thread_class &&
3956 strcmp (cmethod->name, "MemoryBarrier") == 0) {
3957 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
3960 if (cmethod->klass == mono_defaults.math_class) {
3961 if (strcmp (cmethod->name, "Sqrt") == 0) {
3962 MONO_INST_NEW (cfg, ins, OP_SQRT);
3963 ins->inst_i0 = args [0];
3971 mono_arch_print_tree (MonoInst *tree, int arity)
3976 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
3980 setup_tls_access ();
3981 if (monodomain_key == -1)
3984 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
3985 ins->inst_offset = monodomain_key;
3990 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
3994 setup_tls_access ();
3995 if (monothread_key == -1)
3998 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
3999 ins->inst_offset = monothread_key;