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 [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
250 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
251 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((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 * Initialize architecture specific code.
434 mono_arch_init (void)
439 * Cleanup architecture specific code.
442 mono_arch_cleanup (void)
447 * This function returns the optimizations supported on this cpu.
450 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
454 /* no mips-specific optimizations yet */
460 is_regsize_var (MonoType *t) {
463 t = mono_type_get_underlying_type (t);
470 case MONO_TYPE_FNPTR:
472 case MONO_TYPE_OBJECT:
473 case MONO_TYPE_STRING:
474 case MONO_TYPE_CLASS:
475 case MONO_TYPE_SZARRAY:
476 case MONO_TYPE_ARRAY:
478 case MONO_TYPE_GENERICINST:
479 if (!mono_type_generic_inst_is_valuetype (t))
482 case MONO_TYPE_VALUETYPE:
489 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
494 for (i = 0; i < cfg->num_varinfo; i++) {
495 MonoInst *ins = cfg->varinfo [i];
496 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
499 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
502 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
505 /* we can only allocate 32 bit values */
506 if (is_regsize_var (ins->inst_vtype)) {
507 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
508 g_assert (i == vmv->idx);
509 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
517 mono_arch_get_global_int_regs (MonoCompile *cfg)
521 regs = g_list_prepend (regs, (gpointer)mips_s0);
522 regs = g_list_prepend (regs, (gpointer)mips_s1);
523 regs = g_list_prepend (regs, (gpointer)mips_s2);
524 regs = g_list_prepend (regs, (gpointer)mips_s3);
525 regs = g_list_prepend (regs, (gpointer)mips_s4);
526 regs = g_list_prepend (regs, (gpointer)mips_s5);
527 regs = g_list_prepend (regs, (gpointer)mips_s6);
528 regs = g_list_prepend (regs, (gpointer)mips_s7);
534 * mono_arch_regalloc_cost:
536 * Return the cost, in number of memory references, of the action of
537 * allocating the variable VMV into a register during global register
541 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
548 args_onto_stack (CallInfo *info, gboolean force)
550 if (!info->on_stack) {
551 if ((info->gr > MIPS_LAST_ARG_REG) || (info->fr > (MIPS_LAST_FPARG_REG+1))) {
555 info->on_stack = TRUE;
556 info->stack_size = MIPS_STACK_PARAM_OFFSET;
562 * O32 calling convention version
566 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
567 /* First, see if we need to drop onto the stack */
568 args_onto_stack (info, FALSE);
570 /* Now, place the argument */
571 ainfo->offset = info->stack_size;
572 info->stack_size += 4;
573 if (info->on_stack) {
574 ainfo->regtype = RegTypeBase;
575 ainfo->reg = mips_sp; /* in the caller */
578 ainfo->reg = info->gr;
580 info->gr_passed += 1;
581 /* FP and GP slots do not overlap */
587 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
588 /* First, see if we need to drop onto the stack */
589 args_onto_stack (info, FALSE);
591 /* Now, place the argument */
592 if (info->stack_size & 0x7) {
595 /* foo (int, long) -- need to align 2nd arg */
596 add_int32_arg (info, &dummy);
597 args_onto_stack (info, FALSE);
599 ainfo->offset = info->stack_size;
600 info->stack_size += 8;
601 if (info->on_stack) {
602 ainfo->regtype = RegTypeBase;
603 ainfo->reg = mips_sp; /* in the caller */
606 ainfo->reg = info->gr;
608 info->gr_passed += 2;
609 /* FP and GP slots do not overlap */
615 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
616 /* First, see if we need to drop onto the stack */
617 args_onto_stack (info, FALSE);
619 /* Now, place the argument */
620 ainfo->offset = info->stack_size;
621 if (info->on_stack) {
622 ainfo->regtype = RegTypeBase;
623 ainfo->reg = mips_sp; /* in the caller */
624 info->stack_size += 8;
627 /* Only use FP regs for args if no int args passed yet */
628 if (!info->gr_passed) {
629 ainfo->regtype = RegTypeFP;
630 ainfo->reg = info->fr;
631 info->stack_size += 8;
632 /* Even though it's a single-precision float, it takes up two FP regs */
634 info->fr_passed += 1;
635 /* FP and GP slots do not overlap */
639 /* Passing single-precision float arg in a GP register
640 * such as: func (0, 1.0, 2, 3);
641 * In this case, only one 'gr' register is consumed.
643 ainfo->regtype = RegTypeGeneral;
644 ainfo->reg = info->gr;
645 info->stack_size += 4;
647 /* Even though it's a single-precision float, it takes up two FP regs */
649 info->fr_passed += 1;
650 /* FP and GP slots do not overlap */
657 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
658 /* First, see if we need to drop onto the stack */
659 args_onto_stack (info, FALSE);
661 /* Now, place the argument */
663 // info->stack_size += (info->stack_size % 8);
665 ainfo->offset = info->stack_size;
666 info->stack_size += 8;
667 if (info->on_stack) {
668 ainfo->regtype = RegTypeBase;
669 ainfo->reg = mips_sp; /* in the caller */
672 /* Only use FP regs for args if no int args passed yet */
673 if (!info->gr_passed) {
674 ainfo->regtype = RegTypeFP;
675 ainfo->reg = info->fr;
678 ainfo->regtype = RegTypeGeneral;
679 ainfo->reg = info->gr;
682 info->fr_passed += 2;
683 /* FP and GP slots do not overlap */
689 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
692 int n = sig->hasthis + sig->param_count;
694 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
696 cinfo->fr = MIPS_FIRST_FPARG_REG;
697 cinfo->gr = MIPS_FIRST_ARG_REG;
698 cinfo->stack_size = 0;
700 DEBUG(printf("calculate_sizes\n"));
702 /* handle returning a struct */
703 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
704 cinfo->struct_ret = cinfo->gr;
705 add_int32_arg (cinfo, &cinfo->ret);
710 add_int32_arg (cinfo, cinfo->args + n);
713 DEBUG(printf("params: %d\n", sig->param_count));
714 for (i = 0; i < sig->param_count; ++i) {
715 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
716 /* Prevent implicit arguments and sig_cookie from
717 being passed in registers */
718 args_onto_stack (cinfo, TRUE);
719 /* Emit the signature cookie just before the implicit arguments */
720 add_int32_arg (cinfo, &cinfo->sig_cookie);
722 DEBUG(printf("param %d: ", i));
723 if (sig->params [i]->byref) {
724 DEBUG(printf("byref\n"));
725 add_int32_arg (cinfo, &cinfo->args[n]);
729 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
730 switch (simpletype) {
731 case MONO_TYPE_BOOLEAN:
734 DEBUG(printf("1 byte\n"));
735 cinfo->args [n].size = 1;
736 add_int32_arg (cinfo, &cinfo->args[n]);
742 DEBUG(printf("2 bytes\n"));
743 cinfo->args [n].size = 2;
744 add_int32_arg (cinfo, &cinfo->args[n]);
749 DEBUG(printf("4 bytes\n"));
750 cinfo->args [n].size = 4;
751 add_int32_arg (cinfo, &cinfo->args[n]);
757 case MONO_TYPE_FNPTR:
758 case MONO_TYPE_CLASS:
759 case MONO_TYPE_OBJECT:
760 case MONO_TYPE_STRING:
761 case MONO_TYPE_SZARRAY:
762 case MONO_TYPE_ARRAY:
763 cinfo->args [n].size = sizeof (gpointer);
764 add_int32_arg (cinfo, &cinfo->args[n]);
767 case MONO_TYPE_GENERICINST:
768 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
769 cinfo->args [n].size = sizeof (gpointer);
770 add_int32_arg (cinfo, &cinfo->args[n]);
775 case MONO_TYPE_VALUETYPE: {
780 gint size, alignment;
783 klass = mono_class_from_mono_type (sig->params [i]);
785 size = mono_class_native_size (klass, NULL);
787 size = mono_class_value_size (klass, NULL);
788 alignment = mono_class_min_align (klass);
789 #if MIPS_PASS_STRUCTS_BY_VALUE
790 /* Need to do alignment if struct contains long or double */
791 if (cinfo->stack_size & (alignment - 1)) {
792 add_int32_arg (cinfo, &dummy_arg);
794 g_assert (!(cinfo->stack_size & (alignment - 1)));
797 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
798 mono_class_native_size (sig->params [i]->data.klass, NULL),
799 cinfo->stack_size, alignment);
802 align_size += (sizeof (gpointer) - 1);
803 align_size &= ~(sizeof (gpointer) - 1);
804 nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
805 for (j = 0; j < nwords; ++j) {
807 add_int32_arg (cinfo, &cinfo->args [n]);
809 add_int32_arg (cinfo, &dummy_arg);
811 cinfo->args [n].vtsize += 1;
813 cinfo->args [n].size += 1;
815 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
816 cinfo->args [n].regtype = RegTypeStructByVal;
818 add_int32_arg (cinfo, &cinfo->args[n]);
819 cinfo->args [n].regtype = RegTypeStructByAddr;
824 case MONO_TYPE_TYPEDBYREF: {
825 /* keep in sync or merge with the valuetype case */
826 #if MIPS_PASS_STRUCTS_BY_VALUE
828 int size = sizeof (MonoTypedRef);
829 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
830 cinfo->args [n].regtype = RegTypeStructByVal;
831 if (cinfo->gr <= MIPS_LAST_ARG_REG) {
832 int rest = MIPS_LAST_ARG_REG - cinfo->gr + 1;
833 int n_in_regs = rest >= nwords? nwords: rest;
834 cinfo->args [n].size = n_in_regs;
835 cinfo->args [n].vtsize = nwords - n_in_regs;
836 cinfo->args [n].reg = cinfo->gr;
837 cinfo->gr += n_in_regs;
839 cinfo->args [n].size = 0;
840 cinfo->args [n].vtsize = nwords;
842 cinfo->args [n].offset = MIPS_STACK_PARAM_OFFSET + cinfo->stack_size;
843 g_print ("offset for arg %d at %d\n", n, MIPS_STACK_PARAM_OFFSET + cinfo->stack_size);
844 cinfo->stack_size += nwords * sizeof (gpointer);
847 add_int32_arg (cinfo, &cinfo->args[n]);
848 cinfo->args [n].regtype = RegTypeStructByAddr;
855 cinfo->args [n].size = 8;
856 add_int64_arg (cinfo, &cinfo->args[n]);
860 cinfo->args [n].size = 4;
861 add_float32_arg (cinfo, &cinfo->args[n]);
865 cinfo->args [n].size = 8;
866 add_float64_arg (cinfo, &cinfo->args[n]);
870 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
875 simpletype = mono_type_get_underlying_type (sig->ret)->type;
876 switch (simpletype) {
877 case MONO_TYPE_BOOLEAN:
888 case MONO_TYPE_FNPTR:
889 case MONO_TYPE_CLASS:
890 case MONO_TYPE_OBJECT:
891 case MONO_TYPE_SZARRAY:
892 case MONO_TYPE_ARRAY:
893 case MONO_TYPE_STRING:
894 cinfo->ret.reg = mips_v0;
898 cinfo->ret.reg = mips_v0;
902 cinfo->ret.reg = mips_f0;
903 cinfo->ret.regtype = RegTypeFP;
905 case MONO_TYPE_GENERICINST:
906 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
907 cinfo->ret.reg = mips_v0;
911 case MONO_TYPE_VALUETYPE:
913 case MONO_TYPE_TYPEDBYREF:
917 g_error ("Can't handle as return value 0x%x", sig->ret->type);
921 /* align stack size to 16 */
922 cinfo->stack_size = (cinfo->stack_size + 15) & ~15;
924 cinfo->stack_usage = cinfo->stack_size;
930 * Set var information according to the calling convention. mips version.
931 * The locals var stuff should most likely be split in another method.
934 mono_arch_allocate_vars (MonoCompile *cfg)
936 MonoMethodSignature *sig;
937 MonoMethodHeader *header;
939 int i, offset, size, align, curinst;
940 int frame_reg = mips_sp;
941 guint32 iregs_to_save = 0;
942 guint32 fregs_to_restore;
944 cfg->flags |= MONO_CFG_HAS_SPILLUP;
946 /* allow room for the vararg method args: void* and long/double */
947 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
948 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
950 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
951 * call convs needs to be handled this way.
953 if (cfg->flags & MONO_CFG_HAS_VARARGS)
954 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
956 /* gtk-sharp and other broken code will dllimport vararg functions even with
957 * non-varargs signatures. Since there is little hope people will get this right
958 * we assume they won't.
960 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
961 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
963 cfg->param_area = MAX (cfg->param_area, 16);
965 header = mono_method_get_header (cfg->method);
967 sig = mono_method_signature (cfg->method);
970 * We use the frame register also for any method that has
971 * exception clauses. This way, when the handlers are called,
972 * the code will reference local variables using the frame reg instead of
973 * the stack pointer: if we had to restore the stack pointer, we'd
974 * corrupt the method frames that are already on the stack (since
975 * filters get called before stack unwinding happens) when the filter
976 * code would call any method (this also applies to finally etc.).
979 if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses || ALWAYS_USE_FP)
981 cfg->frame_reg = frame_reg;
982 if (frame_reg != mips_sp) {
983 cfg->used_int_regs |= 1 << frame_reg;
988 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
989 /* FIXME: handle long and FP values */
990 switch (mono_type_get_underlying_type (sig->ret)->type) {
994 cfg->ret->opcode = OP_REGVAR;
995 cfg->ret->inst_c0 = mips_v0;
999 /* Space for outgoing parameters, including a0-a3 */
1000 offset += cfg->param_area;
1002 /* allow room to save the return value (if it's a struct) */
1003 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1006 if (sig->call_convention == MONO_CALL_VARARG) {
1007 cfg->sig_cookie = MIPS_STACK_PARAM_OFFSET;
1010 /* Now handle the local variables */
1012 curinst = cfg->locals_start;
1013 for (i = curinst; i < cfg->num_varinfo; ++i) {
1014 inst = cfg->varinfo [i];
1015 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1018 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1019 * pinvoke wrappers when they call functions returning structure
1021 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1022 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
1024 size = mono_type_size (inst->inst_vtype, &align);
1026 offset += align - 1;
1027 offset &= ~(align - 1);
1028 inst->inst_offset = offset;
1029 inst->opcode = OP_REGOFFSET;
1030 inst->inst_basereg = frame_reg;
1032 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1035 /* Space for LMF (if needed) */
1037 if (cfg->method->save_lmf) {
1038 /* align the offset to 16 bytes */
1039 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1040 cfg->arch.lmf_offset = offset;
1041 offset += sizeof (MonoLMF);
1045 #if EXTRA_STACK_SPACE
1046 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1047 * args or return vals. Extra stack space avoids this in a lot of cases.
1051 /* Space for saved registers */
1052 cfg->arch.iregs_offset = offset;
1054 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
1056 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1058 if (iregs_to_save) {
1059 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1060 if (iregs_to_save & (1 << i)) {
1061 offset += sizeof (gulong);
1066 #if EXTRA_STACK_SPACE
1067 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1068 * args or return vals. Extra stack space avoids this in a lot of cases.
1073 /* saved float registers */
1075 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1076 if (fregs_to_restore) {
1077 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1078 if (fregs_to_restore & (1 << i)) {
1079 offset += sizeof (double);
1085 /* Now add space for saving the ra */
1089 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1090 cfg->stack_offset = offset;
1093 * Now allocate stack slots for the int arg regs (a0 - a3)
1094 * On MIPS o32, these are just above the incoming stack pointer
1095 * Even if the arg has been assigned to a regvar, it gets a stack slot
1098 /* Return struct-by-value results in a hidden first argument */
1099 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1100 cfg->ret->opcode = OP_REGOFFSET;
1101 cfg->ret->inst_c0 = mips_a0;
1102 cfg->ret->inst_offset = offset;
1103 cfg->ret->inst_basereg = frame_reg;
1107 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1108 inst = cfg->args [i];
1109 if (inst->opcode != OP_REGVAR) {
1112 if (sig->hasthis && (i == 0))
1113 arg_type = &mono_defaults.object_class->byval_arg;
1115 arg_type = sig->params [i - sig->hasthis];
1117 inst->opcode = OP_REGOFFSET;
1118 size = mono_type_size (arg_type, &align);
1120 /* Need to take references to R4 into account */
1121 /* If it's a single-precision float, allocate 8 bytes of stack for it */
1122 if ((arg_type->type == MONO_TYPE_R4) && !arg_type->byref) {
1130 inst->inst_basereg = frame_reg;
1131 offset = (offset + align - 1) & ~(align - 1);
1132 inst->inst_offset = offset;
1134 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1135 cfg->sig_cookie += size;
1136 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1139 /* Even a0-a3 get stack slots */
1140 size = sizeof (gpointer);
1141 align = sizeof (gpointer);
1142 inst->inst_basereg = frame_reg;
1143 offset = (offset + align - 1) & ~(align - 1);
1144 inst->inst_offset = offset;
1146 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1147 cfg->sig_cookie += size;
1148 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1153 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1154 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1158 * take the arguments and generate the arch-specific
1159 * instructions to properly call the function in call.
1160 * This includes pushing, moving arguments to the right register
1162 * Issue: who does the spilling if needed, and when?
1165 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
1167 MonoMethodSignature *sig;
1172 sig = call->signature;
1173 n = sig->param_count + sig->hasthis;
1175 cinfo = calculate_sizes (sig, sig->pinvoke);
1176 if (cinfo->struct_ret)
1177 call->used_iregs |= 1 << cinfo->struct_ret;
1179 for (i = 0; i < n; ++i) {
1180 ainfo = cinfo->args + i;
1181 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1183 cfg->disable_aot = TRUE;
1185 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1186 sig_arg->inst_p0 = call->signature;
1188 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1189 arg->inst_imm = cinfo->sig_cookie.offset;
1190 arg->inst_left = sig_arg;
1192 /* prepend, so they get reversed */
1193 arg->next = call->out_args;
1194 call->out_args = arg;
1196 if (is_virtual && i == 0) {
1197 /* the argument will be attached to the call instrucion */
1198 in = call->args [i];
1199 call->used_iregs |= 1 << ainfo->reg;
1201 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1202 in = call->args [i];
1203 arg->cil_code = in->cil_code;
1204 arg->inst_left = in;
1205 arg->inst_call = call;
1206 arg->type = in->type;
1207 /* prepend, we'll need to reverse them later */
1208 arg->next = call->out_args;
1209 call->out_args = arg;
1210 if (ainfo->regtype == RegTypeGeneral) {
1211 arg->backend.reg3 = ainfo->reg;
1212 call->used_iregs |= 1 << ainfo->reg;
1213 if (arg->type == STACK_I8)
1214 call->used_iregs |= 1 << (ainfo->reg + 1);
1215 } else if (ainfo->regtype == RegTypeStructByAddr) {
1216 /* FIXME: where is the data allocated? */
1217 arg->backend.reg3 = ainfo->reg;
1218 call->used_iregs |= 1 << ainfo->reg;
1219 } else if (ainfo->regtype == RegTypeStructByVal) {
1221 MonoMIPSArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMIPSArgInfo));
1222 /* mark the used regs */
1223 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1224 call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1226 arg->opcode = OP_OUTARG_VT;
1227 ai->reg = ainfo->reg;
1228 ai->size = ainfo->size;
1229 ai->vtsize = ainfo->vtsize;
1230 ai->offset = ainfo->offset;
1231 arg->backend.data = ai;
1233 g_printf ("OUTARG_VT reg=%d size=%d vtsize=%d offset=%d\n",
1234 ai->reg, ai->size, ai->vtsize, ai->offset);
1236 } else if (ainfo->regtype == RegTypeBase) {
1237 MonoMIPSArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMIPSArgInfo));
1238 arg->opcode = OP_OUTARG_MEMBASE;
1239 ai->reg = ainfo->reg;
1240 ai->size = ainfo->size;
1241 ai->offset = ainfo->offset;
1242 arg->backend.data = ai;
1243 } else if (ainfo->regtype == RegTypeFP) {
1244 arg->opcode = OP_OUTARG_R8;
1245 arg->backend.reg3 = ainfo->reg;
1246 call->used_fregs |= 1 << ainfo->reg;
1247 if (ainfo->size == 4) {
1248 arg->opcode = OP_OUTARG_R4;
1249 /* we reduce the precision */
1251 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1252 conv->inst_left = arg->inst_left;
1253 arg->inst_left = conv;*/
1256 g_assert_not_reached ();
1261 * Reverse the call->out_args list.
1264 MonoInst *prev = NULL, *list = call->out_args, *next;
1271 call->out_args = prev;
1273 call->stack_usage = cinfo->stack_usage;
1274 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1275 cfg->param_area = MAX (cfg->param_area, 16); /* a0-a3 always present */
1276 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1277 cfg->flags |= MONO_CFG_HAS_CALLS;
1279 * should set more info in call, such as the stack space
1280 * used by the args that needs to be added back to esp
1288 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1290 MonoInst *ins, *last_ins = NULL;
1295 switch (ins->opcode) {
1297 /* remove unnecessary multiplication with 1 */
1298 if (ins->inst_imm == 1) {
1299 if (ins->dreg != ins->sreg1) {
1300 ins->opcode = OP_MOVE;
1302 last_ins->next = ins->next;
1307 int power2 = mono_is_power_of_two (ins->inst_imm);
1309 ins->opcode = OP_SHL_IMM;
1310 ins->inst_imm = power2;
1314 case OP_LOAD_MEMBASE:
1315 case OP_LOADI4_MEMBASE:
1317 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1318 * OP_LOAD_MEMBASE offset(basereg), reg
1320 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1321 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1322 ins->inst_basereg == last_ins->inst_destbasereg &&
1323 ins->inst_offset == last_ins->inst_offset) {
1324 if (ins->dreg == last_ins->sreg1) {
1325 last_ins->next = ins->next;
1329 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1330 ins->opcode = OP_MOVE;
1331 ins->sreg1 = last_ins->sreg1;
1336 * Note: reg1 must be different from the basereg in the second load
1337 * OP_LOAD_MEMBASE offset(basereg), reg1
1338 * OP_LOAD_MEMBASE offset(basereg), reg2
1340 * OP_LOAD_MEMBASE offset(basereg), reg1
1341 * OP_MOVE reg1, reg2
1343 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1344 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1345 ins->inst_basereg != last_ins->dreg &&
1346 ins->inst_basereg == last_ins->inst_basereg &&
1347 ins->inst_offset == last_ins->inst_offset) {
1349 if (ins->dreg == last_ins->dreg) {
1350 last_ins->next = ins->next;
1354 ins->opcode = OP_MOVE;
1355 ins->sreg1 = last_ins->dreg;
1358 //g_assert_not_reached ();
1363 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1364 * OP_LOAD_MEMBASE offset(basereg), reg
1366 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1367 * OP_ICONST reg, imm
1369 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1370 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1371 ins->inst_basereg == last_ins->inst_destbasereg &&
1372 ins->inst_offset == last_ins->inst_offset) {
1373 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1374 ins->opcode = OP_ICONST;
1375 ins->inst_c0 = last_ins->inst_imm;
1376 g_assert_not_reached (); // check this rule
1381 case OP_LOADU1_MEMBASE:
1382 case OP_LOADI1_MEMBASE:
1383 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1384 ins->inst_basereg == last_ins->inst_destbasereg &&
1385 ins->inst_offset == last_ins->inst_offset) {
1386 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? CEE_CONV_I1 : CEE_CONV_U1;
1387 ins->sreg1 = last_ins->sreg1;
1390 case OP_LOADU2_MEMBASE:
1391 case OP_LOADI2_MEMBASE:
1392 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1393 ins->inst_basereg == last_ins->inst_destbasereg &&
1394 ins->inst_offset == last_ins->inst_offset) {
1395 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? CEE_CONV_I2 : CEE_CONV_U2;
1396 ins->sreg1 = last_ins->sreg1;
1403 ins->opcode = OP_MOVE;
1407 if (ins->dreg == ins->sreg1) {
1409 last_ins->next = ins->next;
1414 * OP_MOVE sreg, dreg
1415 * OP_MOVE dreg, sreg
1417 if (last_ins && last_ins->opcode == OP_MOVE &&
1418 ins->sreg1 == last_ins->dreg &&
1419 ins->dreg == last_ins->sreg1) {
1420 last_ins->next = ins->next;
1429 bb->last_ins = last_ins;
1432 static inline InstList*
1433 inst_list_prepend (MonoMemPool *pool, InstList *list, MonoInst *data)
1435 InstList *item = mono_mempool_alloc (pool, sizeof (InstList));
1445 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1449 bb->code = to_insert;
1450 to_insert->next = ins;
1452 to_insert->next = ins->next;
1453 ins->next = to_insert;
1457 #define NEW_INS(cfg,dest,op) do { \
1458 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1459 (dest)->opcode = (op); \
1460 insert_after_ins (bb, last_ins, (dest)); \
1464 map_to_reg_reg_op (int op)
1473 case OP_COMPARE_IMM:
1489 case OP_LOAD_MEMBASE:
1490 return OP_LOAD_MEMINDEX;
1491 case OP_LOADI4_MEMBASE:
1492 return OP_LOADI4_MEMINDEX;
1493 case OP_LOADU4_MEMBASE:
1494 return OP_LOADU4_MEMINDEX;
1495 case OP_LOADU1_MEMBASE:
1496 return OP_LOADU1_MEMINDEX;
1497 case OP_LOADI2_MEMBASE:
1498 return OP_LOADI2_MEMINDEX;
1499 case OP_LOADU2_MEMBASE:
1500 return OP_LOADU2_MEMINDEX;
1501 case OP_LOADI1_MEMBASE:
1502 return OP_LOADI1_MEMINDEX;
1503 case OP_LOADR4_MEMBASE:
1504 return OP_LOADR4_MEMINDEX;
1505 case OP_LOADR8_MEMBASE:
1506 return OP_LOADR8_MEMINDEX;
1507 case OP_STOREI1_MEMBASE_REG:
1508 return OP_STOREI1_MEMINDEX;
1509 case OP_STOREI2_MEMBASE_REG:
1510 return OP_STOREI2_MEMINDEX;
1511 case OP_STOREI4_MEMBASE_REG:
1512 return OP_STOREI4_MEMINDEX;
1513 case OP_STORE_MEMBASE_REG:
1514 return OP_STORE_MEMINDEX;
1515 case OP_STORER4_MEMBASE_REG:
1516 return OP_STORER4_MEMINDEX;
1517 case OP_STORER8_MEMBASE_REG:
1518 return OP_STORER8_MEMINDEX;
1519 case OP_STORE_MEMBASE_IMM:
1520 return OP_STORE_MEMBASE_REG;
1521 case OP_STOREI1_MEMBASE_IMM:
1522 return OP_STOREI1_MEMBASE_REG;
1523 case OP_STOREI2_MEMBASE_IMM:
1524 return OP_STOREI2_MEMBASE_REG;
1525 case OP_STOREI4_MEMBASE_IMM:
1526 return OP_STOREI4_MEMBASE_REG;
1528 g_assert_not_reached ();
1532 * Remove from the instruction list the instructions that can't be
1533 * represented with very simple instructions with no register
1537 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1539 MonoInst *ins, *next, *temp, *last_ins = NULL;
1542 /* setup the virtual reg allocator */
1543 if (bb->max_vreg > cfg->rs->next_vreg)
1544 cfg->rs->next_vreg = bb->max_vreg;
1549 switch (ins->opcode) {
1552 if (!mips_is_imm16 (ins->inst_imm)) {
1553 NEW_INS (cfg, temp, OP_ICONST);
1554 temp->inst_c0 = ins->inst_imm;
1555 temp->dreg = mono_regstate_next_int (cfg->rs);
1556 ins->sreg2 = temp->dreg;
1557 ins->opcode = map_to_reg_reg_op (ins->opcode);
1562 if (!mips_is_imm16 (-ins->inst_imm)) {
1563 NEW_INS (cfg, temp, OP_ICONST);
1564 temp->inst_c0 = ins->inst_imm;
1565 temp->dreg = mono_regstate_next_int (cfg->rs);
1566 ins->sreg2 = temp->dreg;
1567 ins->opcode = map_to_reg_reg_op (ins->opcode);
1575 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
1576 NEW_INS (cfg, temp, OP_ICONST);
1577 temp->inst_c0 = ins->inst_imm;
1578 temp->dreg = mono_regstate_next_int (cfg->rs);
1579 ins->sreg2 = temp->dreg;
1580 ins->opcode = map_to_reg_reg_op (ins->opcode);
1588 NEW_INS (cfg, temp, OP_ICONST);
1589 temp->inst_c0 = ins->inst_imm;
1590 temp->dreg = mono_regstate_next_int (cfg->rs);
1591 ins->sreg2 = temp->dreg;
1592 ins->opcode = map_to_reg_reg_op (ins->opcode);
1596 case OP_COMPARE_IMM:
1597 if (compare_opcode_is_unsigned (ins->next->opcode)) {
1598 if (!ppc_is_uimm16 (ins->inst_imm)) {
1599 NEW_INS (cfg, temp, OP_ICONST);
1600 temp->inst_c0 = ins->inst_imm;
1601 temp->dreg = mono_regstate_next_int (cfg->rs);
1602 ins->sreg2 = temp->dreg;
1603 ins->opcode = map_to_reg_reg_op (ins->opcode);
1606 if (!ppc_is_imm16 (ins->inst_imm)) {
1607 NEW_INS (cfg, temp, OP_ICONST);
1608 temp->inst_c0 = ins->inst_imm;
1609 temp->dreg = mono_regstate_next_int (cfg->rs);
1610 ins->sreg2 = temp->dreg;
1611 ins->opcode = map_to_reg_reg_op (ins->opcode);
1618 if (ins->inst_imm == 1) {
1619 ins->opcode = OP_MOVE;
1622 if (ins->inst_imm == 0) {
1623 ins->opcode = OP_ICONST;
1627 imm = mono_is_power_of_two (ins->inst_imm);
1629 ins->opcode = OP_SHL_IMM;
1630 ins->inst_imm = imm;
1633 if (!ppc_is_imm16 (ins->inst_imm)) {
1634 NEW_INS (cfg, temp, OP_ICONST);
1635 temp->inst_c0 = ins->inst_imm;
1636 temp->dreg = mono_regstate_next_int (cfg->rs);
1637 ins->sreg2 = temp->dreg;
1638 ins->opcode = map_to_reg_reg_op (ins->opcode);
1643 case OP_LOAD_MEMBASE:
1644 case OP_LOADI4_MEMBASE:
1645 case OP_LOADU4_MEMBASE:
1646 case OP_LOADI2_MEMBASE:
1647 case OP_LOADU2_MEMBASE:
1648 case OP_LOADI1_MEMBASE:
1649 case OP_LOADU1_MEMBASE:
1650 case OP_LOADR4_MEMBASE:
1651 case OP_LOADR8_MEMBASE:
1652 case OP_STORE_MEMBASE_REG:
1653 case OP_STOREI4_MEMBASE_REG:
1654 case OP_STOREI2_MEMBASE_REG:
1655 case OP_STOREI1_MEMBASE_REG:
1656 case OP_STORER4_MEMBASE_REG:
1657 case OP_STORER8_MEMBASE_REG:
1658 /* we can do two things: load the immed in a register
1659 * and use an indexed load, or see if the immed can be
1660 * represented as an ad_imm + a load with a smaller offset
1661 * that fits. We just do the first for now, optimize later.
1663 if (ppc_is_imm16 (ins->inst_offset))
1665 NEW_INS (cfg, temp, OP_ICONST);
1666 temp->inst_c0 = ins->inst_offset;
1667 temp->dreg = mono_regstate_next_int (cfg->rs);
1668 ins->sreg2 = temp->dreg;
1669 ins->opcode = map_to_reg_reg_op (ins->opcode);
1672 case OP_STORE_MEMBASE_IMM:
1673 case OP_STOREI1_MEMBASE_IMM:
1674 case OP_STOREI2_MEMBASE_IMM:
1675 case OP_STOREI4_MEMBASE_IMM:
1676 if (!ins->inst_imm) {
1677 ins->sreg1 = mips_zero;
1678 ins->opcode = map_to_reg_reg_op (ins->opcode);
1681 NEW_INS (cfg, temp, OP_ICONST);
1682 temp->inst_c0 = ins->inst_imm;
1683 temp->dreg = mono_regstate_next_int (cfg->rs);
1684 ins->sreg1 = temp->dreg;
1685 ins->opcode = map_to_reg_reg_op (ins->opcode);
1687 goto loop_start; /* make it handle the possibly big ins->inst_offset */
1694 bb->last_ins = last_ins;
1695 bb->max_vreg = cfg->rs->next_vreg;
1699 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1703 mono_arch_lowering_pass (cfg, bb);
1704 mono_local_regalloc (cfg, bb);
1708 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
1710 /* sreg is a float, dreg is an integer reg. mips_at is used a scratch */
1712 mips_truncwd (code, mips_ftemp, sreg);
1714 mips_cvtwd (code, mips_ftemp, sreg);
1716 mips_mfc1 (code, dreg, mips_ftemp);
1719 mips_andi (code, dreg, dreg, 0xff);
1720 else if (size == 2) {
1721 mips_sll (code, dreg, dreg, 16);
1722 mips_srl (code, dreg, dreg, 16);
1726 mips_sll (code, dreg, dreg, 24);
1727 mips_sra (code, dreg, dreg, 24);
1729 else if (size == 2) {
1730 mips_sll (code, dreg, dreg, 16);
1731 mips_sra (code, dreg, dreg, 16);
1738 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
1743 guint8 *code = cfg->native_code + cfg->code_len;
1744 MonoInst *last_ins = NULL;
1745 guint last_offset = 0;
1749 if (cfg->opt & MONO_OPT_PEEPHOLE)
1750 peephole_pass (cfg, bb);
1752 /* we don't align basic blocks of loops on mips */
1754 if (cfg->verbose_level > 2)
1755 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
1757 cpos = bb->max_offset;
1760 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
1761 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
1762 g_assert (!mono_compile_aot);
1765 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
1766 /* this is not thread save, but good enough */
1767 /* fixme: howto handle overflows? */
1768 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
1769 mips_lw (code, mips_temp, mips_at, 0);
1770 mips_addiu (code, mips_temp, mips_temp, 1);
1771 mips_sw (code, mips_temp, mips_at, 0);
1776 offset = code - cfg->native_code;
1778 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
1780 if (offset > (cfg->code_size - max_len - 16)) {
1781 cfg->code_size *= 2;
1782 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1783 code = cfg->native_code + offset;
1785 mono_debug_record_line_number (cfg, ins, offset);
1786 if (cfg->verbose_level > 2) {
1787 g_print (" @ 0x%x\t", offset);
1788 mono_print_ins (ins_cnt++, ins);
1791 switch (ins->opcode) {
1793 g_assert_not_reached();
1795 emit_tls_access (code, ins->dreg, ins->inst_offset);
1799 mips_mult (code, ins->sreg1, ins->sreg2);
1800 mips_mflo (code, ins->dreg);
1801 mips_mfhi (code, ins->dreg+1);
1804 mips_multu (code, ins->sreg1, ins->sreg2);
1805 mips_mflo (code, ins->dreg);
1806 mips_mfhi (code, ins->dreg+1);
1808 case OP_MEMORY_BARRIER:
1813 case OP_STOREI1_MEMBASE_IMM:
1814 mips_load_const (code, mips_temp, ins->inst_imm);
1815 if (mips_is_imm16 (ins->inst_offset)) {
1816 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
1818 mips_load_const (code, mips_at, ins->inst_offset);
1819 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
1822 case OP_STOREI2_MEMBASE_IMM:
1823 mips_load_const (code, mips_temp, ins->inst_imm);
1824 if (mips_is_imm16 (ins->inst_offset)) {
1825 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
1827 mips_load_const (code, mips_at, ins->inst_offset);
1828 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
1831 case OP_STORE_MEMBASE_IMM:
1832 case OP_STOREI4_MEMBASE_IMM:
1833 mips_load_const (code, mips_temp, ins->inst_imm);
1834 if (mips_is_imm16 (ins->inst_offset)) {
1835 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
1837 mips_load_const (code, mips_at, ins->inst_offset);
1838 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
1841 case OP_STOREI1_MEMBASE_REG:
1842 if (mips_is_imm16 (ins->inst_offset)) {
1843 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1845 mips_load_const (code, mips_at, ins->inst_offset);
1846 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
1847 mips_sb (code, ins->sreg1, mips_at, 0);
1850 case OP_STOREI2_MEMBASE_REG:
1851 if (mips_is_imm16 (ins->inst_offset)) {
1852 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1854 mips_load_const (code, mips_at, ins->inst_offset);
1855 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
1856 mips_sh (code, ins->sreg1, mips_at, 0);
1859 case OP_STORE_MEMBASE_REG:
1860 case OP_STOREI4_MEMBASE_REG:
1861 if (mips_is_imm16 (ins->inst_offset)) {
1862 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1864 mips_load_const (code, mips_at, ins->inst_offset);
1865 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
1866 mips_sw (code, ins->sreg1, mips_at, 0);
1872 g_assert_not_reached ();
1873 //x86_mov_reg_mem (code, ins->dreg, ins->inst_p0, 4);
1876 g_assert_not_reached ();
1877 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
1878 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
1880 case OP_LOAD_MEMBASE:
1881 case OP_LOADI4_MEMBASE:
1882 case OP_LOADU4_MEMBASE:
1883 if (mips_is_imm16 (ins->inst_offset)) {
1884 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1886 mips_load_const (code, mips_at, ins->inst_offset);
1887 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1888 mips_lw (code, ins->dreg, mips_at, 0);
1891 case OP_LOADI1_MEMBASE:
1892 if (mips_is_imm16 (ins->inst_offset)) {
1893 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1895 mips_load_const (code, mips_at, ins->inst_offset);
1896 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1897 mips_lb (code, ins->dreg, mips_at, 0);
1900 case OP_LOADU1_MEMBASE:
1901 if (mips_is_imm16 (ins->inst_offset)) {
1902 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1904 mips_load_const (code, mips_at, ins->inst_offset);
1905 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1906 mips_lbu (code, ins->dreg, mips_at, 0);
1909 case OP_LOADI2_MEMBASE:
1910 if (mips_is_imm16 (ins->inst_offset)) {
1911 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1913 mips_load_const (code, mips_at, ins->inst_offset);
1914 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1915 mips_lh (code, ins->dreg, mips_at, 0);
1918 case OP_LOADU2_MEMBASE:
1919 if (mips_is_imm16 (ins->inst_offset)) {
1920 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1922 mips_load_const (code, mips_at, ins->inst_offset);
1923 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1924 mips_lhu (code, ins->dreg, mips_at, 0);
1928 mips_sll (code, mips_at, ins->sreg1, 24);
1929 mips_sra (code, ins->dreg, mips_at, 24);
1932 mips_sll (code, mips_at, ins->sreg1, 16);
1933 mips_sra (code, ins->dreg, mips_at, 16);
1936 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
1939 mips_sll (code, mips_at, ins->sreg1, 16);
1940 mips_srl (code, ins->dreg, mips_at, 16);
1943 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
1946 g_assert (mips_is_imm16 (ins->inst_imm));
1947 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
1950 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
1953 g_assert (mips_is_imm16 (ins->inst_imm));
1954 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
1956 case OP_COMPARE_IMM:
1957 g_assert_not_reached ();
1960 g_assert_not_reached ();
1963 mips_break (code, 0xfd);
1966 g_assert_not_reached ();
1969 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
1972 g_assert_not_reached ();
1975 g_assert_not_reached ();
1978 if (mips_is_imm16 (ins->inst_imm)) {
1979 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
1981 mips_load_const (code, mips_at, ins->inst_imm);
1982 mips_addu (code, ins->dreg, ins->sreg1, mips_at);
1986 g_assert_not_reached ();
1989 /* rewritten in .brg file */
1990 g_assert_not_reached ();
1992 case CEE_ADD_OVF_UN:
1993 /* rewritten in .brg file */
1994 g_assert_not_reached ();
1997 /* rewritten in .brg file */
1998 g_assert_not_reached ();
2000 case CEE_SUB_OVF_UN:
2001 /* rewritten in .brg file */
2002 g_assert_not_reached ();
2004 case OP_ADD_OVF_CARRY:
2005 /* rewritten in .brg file */
2006 g_assert_not_reached ();
2008 case OP_ADD_OVF_UN_CARRY:
2009 /* rewritten in .brg file */
2010 g_assert_not_reached ();
2012 case OP_SUB_OVF_CARRY:
2013 /* rewritten in .brg file */
2014 g_assert_not_reached ();
2016 case OP_SUB_OVF_UN_CARRY:
2017 /* rewritten in .brg file */
2018 g_assert_not_reached ();
2021 /* rewritten in .brg file */
2022 g_assert_not_reached ();
2025 /* rewritten in .brg file */
2026 g_assert_not_reached ();
2029 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
2032 g_assert_not_reached ();
2035 // we add the negated value
2036 if (mips_is_imm16 (-ins->inst_imm))
2037 mips_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2039 mips_load_const (code, mips_at, ins->inst_imm);
2040 mips_subu (code, ins->dreg, ins->sreg1, mips_at);
2044 g_assert_not_reached ();
2047 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2050 if (mips_is_imm16 (ins->inst_imm)) {
2051 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2053 mips_load_const (code, mips_at, ins->inst_imm);
2054 mips_and (code, ins->dreg, ins->sreg1, mips_at);
2059 guint32 *divisor_is_m1;
2060 guint32 *divisor_is_zero;
2063 mips_addiu (code, mips_at, mips_zero, 0xffff);
2064 divisor_is_m1 = (guint32 *)code;
2065 mips_bne (code, ins->sreg2, mips_at, 0);
2068 /* Divide by -1 -- throw exception */
2069 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
2071 mips_patch (divisor_is_m1, (guint32)code);
2073 /* Put divide in branch delay slot (NOT YET) */
2074 divisor_is_zero = (guint32 *)code;
2075 mips_bne (code, ins->sreg2, mips_zero, 0);
2078 /* Divide by zero -- throw exception */
2079 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2081 mips_patch (divisor_is_zero, (guint32)code);
2082 mips_div (code, ins->sreg1, ins->sreg2);
2083 if (ins->opcode == CEE_DIV)
2084 mips_mflo (code, ins->dreg);
2086 mips_mfhi (code, ins->dreg);
2090 guint32 *divisor_is_zero = (guint32 *)(void *)code;
2092 /* Put divide in branch delay slot (NOT YET) */
2093 mips_bne (code, ins->sreg2, mips_zero, 0);
2096 /* Divide by zero -- throw exception */
2097 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2099 mips_patch (divisor_is_zero, (guint32)code);
2100 mips_divu (code, ins->sreg1, ins->sreg2);
2101 mips_mflo (code, ins->dreg);
2105 g_assert_not_reached ();
2107 ppc_load (code, ppc_r11, ins->inst_imm);
2108 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
2109 ppc_mfspr (code, ppc_r0, ppc_xer);
2110 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2111 /* FIXME: use OverflowException for 0x80000000/-1 */
2112 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2114 g_assert_not_reached();
2117 guint32 *divisor_is_zero = (guint32 *)(void *)code;
2119 /* Put divide in branch delay slot (NOT YET) */
2120 mips_bne (code, ins->sreg2, mips_zero, 0);
2123 /* Divide by zero -- throw exception */
2124 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2126 mips_patch (divisor_is_zero, (guint32)code);
2127 mips_divu (code, ins->sreg1, ins->sreg2);
2128 mips_mfhi (code, ins->dreg);
2132 g_assert_not_reached ();
2134 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2137 if (mips_is_imm16 (ins->inst_imm)) {
2138 mips_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2140 mips_load_const (code, mips_at, ins->inst_imm);
2141 mips_or (code, ins->dreg, ins->sreg1, mips_at);
2145 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2148 /* unsigned 16-bit immediate */
2149 if ((ins->inst_imm & 0xffff) == ins->inst_imm) {
2150 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
2152 mips_load_const (code, mips_at, ins->inst_imm);
2153 mips_xor (code, ins->dreg, ins->sreg1, mips_at);
2157 g_assert (mips_is_imm16 (ins->inst_imm));
2158 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
2161 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
2164 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2167 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
2170 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2173 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2176 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
2179 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
2182 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
2186 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
2188 mips_mult (code, ins->sreg1, ins->sreg2);
2189 mips_mflo (code, ins->dreg);
2195 mips_load_const (code, mips_at, ins->inst_imm);
2197 mips_mul (code, ins->dreg, ins->sreg1, mips_at);
2199 mips_mult (code, ins->sreg1, mips_at);
2200 mips_mflo (code, ins->dreg);
2207 mips_mult (code, ins->sreg1, ins->sreg2);
2208 mips_mflo (code, ins->dreg);
2209 mips_mfhi (code, mips_at);
2212 mips_sra (code, mips_temp, ins->dreg, 31);
2213 patch = (guint32 *)(void *)code;
2214 mips_beq (code, mips_temp, mips_at, 0);
2216 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
2217 mips_patch (patch, (guint32)code);
2220 case CEE_MUL_OVF_UN:
2222 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
2224 mips_mult (code, ins->sreg1, ins->sreg2);
2225 mips_mflo (code, ins->dreg);
2226 mips_mfhi (code, mips_at);
2230 /* XXX - Throw exception if we overflowed */
2234 mips_load_const (code, ins->dreg, ins->inst_c0);
2237 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2238 mips_load (code, ins->dreg, 0);
2242 mips_mtc1 (code, ins->dreg, ins->sreg1);
2245 mips_mfc1 (code, ins->dreg, ins->sreg1);
2248 mips_dmtc1 (code, ins->dreg, ins->sreg1);
2251 mips_dmfc1 (code, ins->dreg, ins->sreg1);
2258 if (ins->dreg != ins->sreg1)
2259 mips_move (code, ins->dreg, ins->sreg1);
2262 /* Get sreg1 into v1, sreg2 into v0 */
2264 if (ins->sreg1 == mips_v0) {
2265 if (ins->sreg1 != mips_at)
2266 mips_move (code, mips_at, ins->sreg1);
2267 if (ins->sreg2 != mips_v0)
2268 mips_move (code, mips_v0, ins->sreg2);
2269 mips_move (code, mips_v1, mips_at);
2272 if (ins->sreg2 != mips_v0)
2273 mips_move (code, mips_v0, ins->sreg2);
2274 if (ins->sreg1 != mips_v1)
2275 mips_move (code, mips_v1, ins->sreg1);
2279 if (ins->dreg != ins->sreg1) {
2280 mips_fmovd (code, ins->dreg, ins->sreg1);
2284 if (ins->dreg != ins->sreg1) {
2285 mips_fmovd (code, ins->dreg, ins->sreg1);
2289 /* Convert from double to float and leave it there */
2290 mips_cvtsd (code, ins->dreg, ins->sreg1);
2292 case OP_FCONV_TO_R4:
2293 /* Convert from double to float and back again */
2294 mips_cvtsd (code, ins->dreg, ins->sreg1);
2295 mips_cvtds (code, ins->dreg, ins->dreg);
2299 * Pop our stack, then jump to specified method (tail-call)
2300 * Keep in sync with mono_arch_emit_epilog
2302 code = mono_arch_emit_epilog_sub (cfg, code);
2304 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
2305 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2307 mips_lui (code, mips_t9, mips_zero, 0);
2308 mips_addiu (code, mips_t9, mips_t9, 0);
2309 mips_jr (code, mips_t9);
2312 mips_beq (code, mips_zero, mips_zero, 0);
2317 /* ensure ins->sreg1 is not NULL */
2318 mips_lw (code, mips_zero, ins->sreg1, 0);
2321 if (mips_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2322 mips_addiu (code, mips_at, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2324 mips_load_const (code, mips_at, cfg->sig_cookie + cfg->stack_usage);
2325 mips_addu (code, mips_at, cfg->frame_reg, mips_at);
2327 mips_sw (code, mips_at, ins->sreg1, 0);
2338 case OP_VOIDCALL_REG:
2340 case OP_FCALL_MEMBASE:
2341 case OP_LCALL_MEMBASE:
2342 case OP_VCALL_MEMBASE:
2343 case OP_VOIDCALL_MEMBASE:
2344 case OP_CALL_MEMBASE:
2345 switch (ins->opcode) {
2351 call = (MonoCallInst*)ins;
2352 if (ins->flags & MONO_INST_HAS_METHOD)
2353 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2355 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2356 mips_lui (code, mips_t9, mips_zero, 0);
2357 mips_addiu (code, mips_t9, mips_t9, 0);
2362 case OP_VOIDCALL_REG:
2364 mips_move (code, mips_t9, ins->sreg1);
2366 case OP_FCALL_MEMBASE:
2367 case OP_LCALL_MEMBASE:
2368 case OP_VCALL_MEMBASE:
2369 case OP_VOIDCALL_MEMBASE:
2370 case OP_CALL_MEMBASE:
2371 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
2374 mips_jalr (code, mips_t9, mips_ra);
2378 g_assert_not_reached ();
2381 int area_offset = cfg->param_area;
2383 /* Round up ins->sreg1, mips_at ends up holding size */
2384 mips_addiu (code, mips_at, ins->sreg1, 31);
2385 mips_andi (code, mips_at, mips_at, ~31);
2387 mips_subu (code, mips_sp, mips_sp, mips_at);
2388 mips_addiu (code, ins->dreg, mips_sp, area_offset);
2390 if (ins->flags & MONO_INST_INIT) {
2391 mips_move (code, mips_temp, ins->dreg);
2392 mips_sb (code, mips_zero, mips_temp, 0);
2393 mips_addiu (code, mips_at, mips_at, -1);
2394 mips_bne (code, mips_at, mips_zero, -4);
2395 mips_addiu (code, mips_temp, mips_temp, 1);
2400 mips_jr (code, mips_ra);
2404 gpointer addr = mono_arch_get_throw_exception();
2405 mips_move (code, mips_a0, ins->sreg1);
2406 mips_load_const (code, mips_t9, addr);
2407 mips_jalr (code, mips_t9, mips_ra);
2409 mips_break (code, 0xfc);
2413 gpointer addr = mono_arch_get_rethrow_exception();
2414 mips_move (code, mips_a0, ins->sreg1);
2415 mips_load_const (code, mips_t9, addr);
2416 mips_jalr (code, mips_t9, mips_ra);
2418 mips_break (code, 0xfb);
2421 case OP_START_HANDLER:
2423 * The START_HANDLER instruction marks the beginning of a handler
2424 * block. It is called using a call instruction, so mips_ra contains
2425 * the return address. Since the handler executes in the same stack
2426 * frame as the method itself, we can't use save/restore to save
2427 * the return address. Instead, we save it into a dedicated
2430 if (mips_is_imm16 (ins->inst_left->inst_offset)) {
2431 mips_sw (code, mips_ra, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2433 mips_load_const (code, mips_at, ins->inst_left->inst_offset);
2434 mips_add (code, mips_at, mips_at, ins->inst_left->inst_basereg);
2435 mips_sw (code, mips_ra, mips_at, 0);
2439 if (ins->sreg1 != mips_v0)
2440 mips_move (code, mips_v0, ins->sreg1);
2441 if (mips_is_imm16 (ins->inst_left->inst_offset)) {
2442 mips_lw (code, mips_ra, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2444 mips_load_const (code, mips_at, ins->inst_left->inst_offset);
2445 mips_addu (code, mips_at, mips_at, ins->inst_left->inst_basereg);
2446 mips_lw (code, mips_ra, mips_at, 0);
2448 mips_jr (code, mips_ra);
2452 mips_lw (code, mips_t9, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2453 mips_jalr (code, mips_t9, mips_ra);
2456 case OP_CALL_HANDLER:
2457 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2458 mips_lui (code, mips_t9, mips_zero, 0);
2459 mips_addiu (code, mips_t9, mips_t9, 0);
2460 mips_jalr (code, mips_t9, mips_ra);
2464 ins->inst_c0 = code - cfg->native_code;
2467 if (ins->flags & MONO_INST_BRLABEL) {
2468 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2470 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2473 mips_lui (code, mips_at, mips_zero, 0);
2474 mips_addiu (code, mips_at, mips_at, 0);
2475 mips_jr (code, mips_at);
2478 mips_beq (code, mips_zero, mips_zero, 0);
2483 mips_jr (code, ins->sreg1);
2489 max_len += 4 * GPOINTER_TO_INT (ins->klass);
2490 if (offset > (cfg->code_size - max_len - 16)) {
2491 cfg->code_size += max_len;
2492 cfg->code_size *= 2;
2493 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2494 code = cfg->native_code + offset;
2496 g_assert (ins->sreg1 != -1);
2497 mips_sll (code, mips_at, ins->sreg1, 2);
2498 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
2499 mips_move (code, mips_t8, mips_ra);
2500 mips_bgezal (code, mips_zero, 1); /* bal */
2502 mips_addu (code, mips_t9, mips_ra, mips_at);
2503 /* Table is 16 or 20 bytes from target of bal above */
2504 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
2505 mips_move (code, mips_ra, mips_t8);
2506 mips_lw (code, mips_t9, mips_t9, 20);
2509 mips_lw (code, mips_t9, mips_t9, 16);
2510 mips_jalr (code, mips_t9, mips_t8);
2512 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
2513 mips_emit32 (code, 0xfefefefe);
2517 mips_addiu (code, ins->dreg, mips_zero, 1);
2518 mips_beq (code, mips_at, mips_zero, 2);
2520 mips_move (code, ins->dreg, mips_zero);
2524 mips_addiu (code, ins->dreg, mips_zero, 1);
2525 mips_bltz (code, mips_at, 2);
2527 mips_move (code, ins->dreg, mips_zero);
2531 mips_addiu (code, ins->dreg, mips_zero, 1);
2532 mips_bgtz (code, mips_at, 2);
2534 mips_move (code, ins->dreg, mips_zero);
2537 case OP_COND_EXC_EQ:
2538 case OP_COND_EXC_GE:
2539 case OP_COND_EXC_GT:
2540 case OP_COND_EXC_LE:
2541 case OP_COND_EXC_LT:
2542 case OP_COND_EXC_NE_UN:
2543 case OP_COND_EXC_GE_UN:
2544 case OP_COND_EXC_GT_UN:
2545 case OP_COND_EXC_LE_UN:
2546 case OP_COND_EXC_LT_UN:
2548 case OP_COND_EXC_OV:
2549 case OP_COND_EXC_NO:
2551 case OP_COND_EXC_NC:
2553 case OP_COND_EXC_IEQ:
2554 case OP_COND_EXC_IGE:
2555 case OP_COND_EXC_IGT:
2556 case OP_COND_EXC_ILE:
2557 case OP_COND_EXC_ILT:
2558 case OP_COND_EXC_INE_UN:
2559 case OP_COND_EXC_IGE_UN:
2560 case OP_COND_EXC_IGT_UN:
2561 case OP_COND_EXC_ILE_UN:
2562 case OP_COND_EXC_ILT_UN:
2564 case OP_COND_EXC_IOV:
2565 case OP_COND_EXC_INO:
2566 case OP_COND_EXC_IC:
2567 case OP_COND_EXC_INC:
2568 /* Should be re-mapped to OP_MIPS_B* by *.inssel-mips.brg */
2569 g_warning ("unsupported conditional exception %s\n", mono_inst_name (ins->opcode));
2570 g_assert_not_reached ();
2573 case OP_MIPS_COND_EXC_EQ:
2574 case OP_MIPS_COND_EXC_GE:
2575 case OP_MIPS_COND_EXC_GT:
2576 case OP_MIPS_COND_EXC_LE:
2577 case OP_MIPS_COND_EXC_LT:
2578 case OP_MIPS_COND_EXC_NE_UN:
2579 case OP_MIPS_COND_EXC_GE_UN:
2580 case OP_MIPS_COND_EXC_GT_UN:
2581 case OP_MIPS_COND_EXC_LE_UN:
2582 case OP_MIPS_COND_EXC_LT_UN:
2584 case OP_MIPS_COND_EXC_OV:
2585 case OP_MIPS_COND_EXC_NO:
2586 case OP_MIPS_COND_EXC_C:
2587 case OP_MIPS_COND_EXC_NC:
2589 case OP_MIPS_COND_EXC_IEQ:
2590 case OP_MIPS_COND_EXC_IGE:
2591 case OP_MIPS_COND_EXC_IGT:
2592 case OP_MIPS_COND_EXC_ILE:
2593 case OP_MIPS_COND_EXC_ILT:
2594 case OP_MIPS_COND_EXC_INE_UN:
2595 case OP_MIPS_COND_EXC_IGE_UN:
2596 case OP_MIPS_COND_EXC_IGT_UN:
2597 case OP_MIPS_COND_EXC_ILE_UN:
2598 case OP_MIPS_COND_EXC_ILT_UN:
2600 case OP_MIPS_COND_EXC_IOV:
2601 case OP_MIPS_COND_EXC_INO:
2602 case OP_MIPS_COND_EXC_IC:
2603 case OP_MIPS_COND_EXC_INC: {
2607 /* If the condition is true, raise the exception */
2609 /* need to reverse test to skip around exception raising */
2611 /* For the moment, branch around a branch to avoid reversing
2614 /* Remember, an unpatched branch to 0 branches to the delay slot */
2615 throw = (guint32 *)(void *)code;
2616 switch (ins->opcode) {
2617 case OP_MIPS_COND_EXC_EQ:
2618 mips_beq (code, ins->sreg1, ins->sreg2, 0);
2621 case OP_MIPS_COND_EXC_NE_UN:
2622 mips_bne (code, ins->sreg1, ins->sreg2, 0);
2626 /* Not yet implemented */
2627 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
2628 g_assert_not_reached ();
2630 skip = (guint32 *)(void *)code;
2631 mips_beq (code, mips_zero, mips_zero, 0);
2633 mips_patch (throw, (guint32)code);
2634 code = mips_emit_exc_by_name (code, ins->inst_p1);
2635 mips_patch (skip, (guint32)code);
2636 cfg->bb_exit->max_offset += 24;
2649 /* Should be re-mapped to OP_MIPS_B* by *.inssel-mips.brg */
2650 g_warning ("unsupported conditional set %s\n", mono_inst_name (ins->opcode));
2651 g_assert_not_reached ();
2659 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
2662 /* floating point opcodes */
2664 if (((guint32)ins->inst_p0) & (1 << 15))
2665 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
2667 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
2668 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
2671 if (((guint32)ins->inst_p0) & (1 << 15))
2672 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
2674 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
2675 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
2676 mips_cvtds (code, ins->dreg, ins->dreg);
2678 case OP_STORER8_MEMBASE_REG:
2679 if (mips_is_imm16 (ins->inst_offset)) {
2681 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2683 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset+4);
2684 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset);
2687 mips_load_const (code, mips_at, ins->inst_offset);
2688 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
2689 mips_swc1 (code, ins->sreg1, mips_at, 4);
2690 mips_swc1 (code, ins->sreg1+1, mips_at, 0);
2693 case OP_LOADR8_MEMBASE:
2694 if (mips_is_imm16 (ins->inst_offset)) {
2696 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2698 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset+4);
2699 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset);
2702 mips_load_const (code, mips_at, ins->inst_offset);
2703 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2704 mips_lwc1 (code, ins->dreg, mips_at, 4);
2705 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
2708 case OP_STORER4_MEMBASE_REG:
2709 /* XXX Need to convert ins->sreg1 to single-precision first */
2710 mips_cvtsd (code, mips_ftemp, ins->sreg1);
2711 if (mips_is_imm16 (ins->inst_offset)) {
2712 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
2714 mips_load_const (code, mips_at, ins->inst_offset);
2715 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
2716 mips_swc1 (code, mips_ftemp, mips_at, 0);
2720 if (mips_is_imm16 (ins->inst_offset)) {
2721 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2723 mips_load_const (code, mips_at, ins->inst_offset);
2724 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2725 mips_lwc1 (code, ins->dreg, mips_at, 0);
2728 case OP_LOADR4_MEMBASE:
2729 if (mips_is_imm16 (ins->inst_offset)) {
2730 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2732 mips_load_const (code, mips_at, ins->inst_offset);
2733 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2734 mips_lwc1 (code, ins->dreg, mips_at, 0);
2736 /* Convert to double precision in place */
2737 mips_cvtds (code, ins->dreg, ins->dreg);
2739 case CEE_CONV_R_UN: {
2740 static const guint64 adjust_val = 0x41F0000000000000ULL;
2742 /* convert unsigned int to double */
2743 mips_mtc1 (code, mips_ftemp, ins->sreg1);
2744 mips_bgez (code, ins->sreg1, 5);
2745 mips_cvtdw (code, ins->dreg, mips_ftemp);
2747 mips_load (code, mips_at, (guint32) &adjust_val);
2748 mips_ldc1 (code, mips_ftemp, mips_at, 0);
2749 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
2750 /* target is here */
2754 mips_mtc1 (code, mips_ftemp, ins->sreg1);
2755 mips_cvtsw (code, ins->dreg, mips_ftemp);
2756 mips_cvtds (code, ins->dreg, ins->dreg);
2759 mips_mtc1 (code, mips_ftemp, ins->sreg1);
2760 mips_cvtdw (code, ins->dreg, mips_ftemp);
2762 case OP_FCONV_TO_I1:
2763 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2765 case OP_FCONV_TO_U1:
2766 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2768 case OP_FCONV_TO_I2:
2769 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
2771 case OP_FCONV_TO_U2:
2772 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
2774 case OP_FCONV_TO_I4:
2776 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
2778 case OP_FCONV_TO_U4:
2780 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
2782 case OP_FCONV_TO_I8:
2783 case OP_FCONV_TO_U8:
2784 g_assert_not_reached ();
2785 /* Implemented as helper calls */
2787 case OP_LCONV_TO_R_UN:
2788 g_assert_not_reached ();
2789 /* Implemented as helper calls */
2791 case OP_LCONV_TO_OVF_I:
2792 g_assert_not_reached ();
2793 /* split up by brg file */
2796 mips_fsqrtd (code, ins->dreg, ins->sreg1);
2799 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
2802 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
2805 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
2808 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
2811 mips_fnegd (code, ins->dreg, ins->sreg1);
2815 g_assert_not_reached ();
2818 g_assert_not_reached();
2821 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
2822 mips_addiu (code, ins->dreg, mips_zero, 1);
2823 mips_fbtrue (code, 2);
2825 mips_move (code, ins->dreg, mips_zero);
2828 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
2829 mips_addiu (code, ins->dreg, mips_zero, 1);
2830 mips_fbtrue (code, 2);
2832 mips_move (code, ins->dreg, mips_zero);
2835 /* Less than, or Unordered */
2836 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
2837 mips_addiu (code, ins->dreg, mips_zero, 1);
2838 mips_fbtrue (code, 2);
2840 mips_move (code, ins->dreg, mips_zero);
2843 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
2844 mips_move (code, ins->dreg, mips_zero);
2845 mips_fbtrue (code, 2);
2847 mips_addiu (code, ins->dreg, mips_zero, 1);
2850 /* Greater than, or Unordered */
2851 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
2852 mips_move (code, ins->dreg, mips_zero);
2853 mips_fbtrue (code, 2);
2855 mips_addiu (code, ins->dreg, mips_zero, 1);
2858 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
2860 if (ins->flags & MONO_INST_BRLABEL)
2861 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2863 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2864 mips_fbtrue (code, 0);
2868 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
2870 if (ins->flags & MONO_INST_BRLABEL)
2871 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2873 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2874 mips_fbfalse (code, 0);
2878 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
2880 if (ins->flags & MONO_INST_BRLABEL)
2881 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2883 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2884 mips_fbtrue (code, 0);
2888 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
2890 if (ins->flags & MONO_INST_BRLABEL)
2891 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2893 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2894 mips_fbtrue (code, 0);
2898 mips_fcmpd (code, MIPS_FPU_LE, ins->sreg1, ins->sreg2);
2900 if (ins->flags & MONO_INST_BRLABEL)
2901 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2903 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2904 mips_fbfalse (code, 0);
2908 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
2910 if (ins->flags & MONO_INST_BRLABEL)
2911 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2913 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2914 mips_fbfalse (code, 0);
2918 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
2920 if (ins->flags & MONO_INST_BRLABEL)
2921 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2923 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2924 mips_fbfalse (code, 0);
2928 mips_fcmpd (code, MIPS_FPU_OLT, ins->sreg1, ins->sreg2);
2930 if (ins->flags & MONO_INST_BRLABEL)
2931 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2933 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2934 mips_fbfalse (code, 0);
2938 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
2940 if (ins->flags & MONO_INST_BRLABEL)
2941 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2943 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2944 mips_fbtrue (code, 0);
2948 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
2950 if (ins->flags & MONO_INST_BRLABEL)
2951 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2953 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2954 mips_fbtrue (code, 0);
2958 g_assert_not_reached();
2960 ppc_stfd (code, ins->sreg1, -8, ppc_sp);
2961 ppc_lwz (code, ppc_r11, -8, ppc_sp);
2962 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 1, 31);
2963 ppc_addis (code, ppc_r11, ppc_r11, -32752);
2964 ppc_rlwinmd (code, ppc_r11, ppc_r11, 1, 31, 31);
2965 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
2970 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
2971 g_assert_not_reached ();
2974 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
2975 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
2976 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
2977 g_assert_not_reached ();
2983 last_offset = offset;
2988 cfg->code_len = code - cfg->native_code;
2992 mono_arch_register_lowlevel_calls (void)
2997 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
2999 MonoJumpInfo *patch_info;
3001 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3002 unsigned char *ip = patch_info->ip.i + code;
3003 const unsigned char *target;
3005 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3007 switch (patch_info->type) {
3008 case MONO_PATCH_INFO_IP:
3009 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
3011 case MONO_PATCH_INFO_SWITCH: {
3012 /* jt is the inlined jump table, 7 or 9 instructions after ip
3013 * In the normal case we store the absolute addresses.
3014 * otherwise the displacements.
3017 gpointer *table = (gpointer *)patch_info->data.table->table;
3018 gpointer *jt = ((gpointer*)(void *)ip) + 7;
3019 if (1 /* || !(cfg->->flags & MONO_CFG_HAS_CALLS) */)
3021 for (i = 0; i < patch_info->data.table->table_size; i++) {
3022 jt [i] = code + (int)table [i];
3026 case MONO_PATCH_INFO_METHODCONST:
3027 case MONO_PATCH_INFO_CLASS:
3028 case MONO_PATCH_INFO_IMAGE:
3029 case MONO_PATCH_INFO_FIELD:
3030 case MONO_PATCH_INFO_VTABLE:
3031 case MONO_PATCH_INFO_IID:
3032 case MONO_PATCH_INFO_SFLDA:
3033 case MONO_PATCH_INFO_LDSTR:
3034 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3035 case MONO_PATCH_INFO_LDTOKEN:
3036 case MONO_PATCH_INFO_R4:
3037 case MONO_PATCH_INFO_R8:
3038 /* from OP_AOTCONST : lui + addiu */
3039 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
3042 case MONO_PATCH_INFO_EXC_NAME:
3043 g_assert_not_reached ();
3044 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
3047 case MONO_PATCH_INFO_NONE:
3048 /* everything is dealt with at epilog output time */
3053 mips_patch ((guint32 *)(void *)ip, (guint32)target);
3059 mono_trace_lmf_prolog (MonoLMF *new_lmf)
3065 mono_trace_lmf_epilog (MonoLMF *old_lmf)
3070 * Allow tracing to work with this interface (with an optional argument)
3072 * This code is expected to be inserted just after the 'real' prolog code,
3073 * and before the first basic block. We need to allocate a 2nd, temporary
3074 * stack frame so that we can preserve f12-f15 as well as a0-a3.
3078 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
3081 int fp_stack_offset = 0;
3087 mips_sw (code, mips_a0, mips_sp, cfg->stack_offset + 0);
3088 mips_sw (code, mips_a1, mips_sp, cfg->stack_offset + 4);
3089 mips_sw (code, mips_a2, mips_sp, cfg->stack_offset + 8);
3090 mips_sw (code, mips_a3, mips_sp, cfg->stack_offset + 12);
3093 fp_stack_offset = MIPS_STACK_PARAM_OFFSET;
3094 mips_addiu (code, mips_sp, mips_sp, -64);
3095 mips_swc1 (code, mips_f12, mips_sp, fp_stack_offset + 16);
3096 mips_swc1 (code, mips_f13, mips_sp, fp_stack_offset + 20);
3097 mips_swc1 (code, mips_f14, mips_sp, fp_stack_offset + 24);
3098 mips_swc1 (code, mips_f15, mips_sp, fp_stack_offset + 28);
3100 mips_fmovs (code, mips_f22, mips_f12);
3101 mips_fmovs (code, mips_f23, mips_f13);
3102 mips_fmovs (code, mips_f24, mips_f14);
3103 mips_fmovs (code, mips_f25, mips_f15);
3106 mips_load_const (code, mips_a0, cfg->method);
3107 mips_addiu (code, mips_a1, mips_sp, cfg->stack_offset + fp_stack_offset);
3108 mips_load_const (code, mips_t9, func);
3109 mips_jalr (code, mips_t9, mips_ra);
3112 mips_lw (code, mips_a0, mips_sp, cfg->stack_offset + 0);
3113 mips_lw (code, mips_a1, mips_sp, cfg->stack_offset + 4);
3114 mips_lw (code, mips_a2, mips_sp, cfg->stack_offset + 8);
3115 mips_lw (code, mips_a3, mips_sp, cfg->stack_offset + 12);
3118 mips_lwc1 (code, mips_f12, mips_sp, fp_stack_offset + 16);
3119 mips_lwc1 (code, mips_f13, mips_sp, fp_stack_offset + 20);
3120 mips_lwc1 (code, mips_f14, mips_sp, fp_stack_offset + 24);
3121 mips_lwc1 (code, mips_f15, mips_sp, fp_stack_offset + 28);
3122 mips_addiu (code, mips_sp, mips_sp, 64);
3124 mips_fmovs (code, mips_f12, mips_f22);
3125 mips_fmovs (code, mips_f13, mips_f23);
3126 mips_fmovs (code, mips_f14, mips_f24);
3127 mips_fmovs (code, mips_f15, mips_f25);
3137 * Stack frame layout:
3139 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET + cfg->param_area
3140 * param area incoming
3141 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
3143 * ------------------- sp + cfg->stack_usage
3145 * ------------------- sp + cfg->stack_usage-4
3147 * ------------------- sp +
3148 * MonoLMF structure optional
3149 * ------------------- sp + cfg->arch.lmf_offset
3150 * saved registers s0-s8
3151 * ------------------- sp + cfg->arch.iregs_offset
3153 * ------------------- sp + cfg->param_area
3154 * param area outgoing
3155 * ------------------- sp + 16
3157 * ------------------- sp
3161 mono_arch_emit_prolog (MonoCompile *cfg)
3163 MonoMethod *method = cfg->method;
3164 MonoMethodSignature *sig;
3166 int alloc_size, pos, i;
3170 guint32 iregs_to_save = 0;
3172 guint32 fregs_to_save = 0;
3175 /* lmf_offset is the offset of the LMF from our stack pointer. */
3176 guint32 lmf_offset = cfg->arch.lmf_offset;
3179 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3183 cfg->flags |= MONO_CFG_HAS_CALLS;
3185 sig = mono_method_signature (method);
3186 cfg->code_size = 768 + sig->param_count * 20;
3187 code = cfg->native_code = g_malloc (cfg->code_size);
3189 alloc_size = cfg->stack_offset;
3190 g_assert ((alloc_size & (MIPS_STACK_ALIGNMENT-1)) == 0);
3192 /* re-align cfg->stack_offset if needed (due to var spilling in mini-codegen.c) */
3193 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
3195 /* stack_offset should not be changed here. */
3196 alloc_size = cfg->stack_offset;
3197 cfg->stack_usage = alloc_size;
3200 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
3202 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
3206 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
3208 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
3209 fregs_to_save |= (fregs_to_save << 1);
3213 if (mips_is_imm16 (-alloc_size)) {
3214 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
3216 mips_load_const (code, mips_at, -alloc_size);
3217 mips_addu (code, mips_sp, mips_sp, mips_at);
3221 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
3222 mips_sw (code, mips_ra, mips_sp, alloc_size + MIPS_RET_ADDR_OFFSET);
3224 /* XXX - optimize this later to not save all regs if LMF constructed */
3226 if (iregs_to_save) {
3227 /* save used registers in own stack frame (at pos) */
3228 pos = cfg->arch.iregs_offset;
3229 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
3230 if (iregs_to_save & (1 << i)) {
3231 g_assert (pos < cfg->stack_usage - 4);
3232 mips_sw (code, i, mips_sp, pos);
3233 pos += sizeof (gulong);
3238 if (method->save_lmf) {
3239 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
3240 mips_sw (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]));
3246 /* Save float registers */
3247 if (fregs_to_save) {
3248 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
3249 if (fregs_to_save & (1 << i)) {
3250 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
3251 mips_swc1 (code, i, mips_sp, pos);
3252 pos += sizeof (gulong);
3257 if (method->save_lmf) {
3258 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
3259 mips_swc1 (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]));
3264 if (cfg->frame_reg != mips_sp) {
3265 mips_move (code, cfg->frame_reg, mips_sp);
3267 if (method->save_lmf)
3268 mips_sw (code, cfg->frame_reg, mips_sp,
3269 lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]));
3273 /* Do instrumentation before assigning regvars to registers. Because they may be assigned
3274 * to the t* registers, which would be clobbered by the instrumentation calls.
3277 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3280 /* load arguments allocated to register from the stack */
3283 cinfo = calculate_sizes (sig, sig->pinvoke);
3285 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3286 ArgInfo *ainfo = &cinfo->ret;
3288 if (inst->opcode == OP_REGVAR)
3289 mips_move (code, inst->dreg, ainfo->reg);
3290 else if (mips_is_imm16 (inst->inst_offset)) {
3291 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3293 mips_load_const (code, mips_at, inst->inst_offset);
3294 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
3295 mips_sw (code, ainfo->reg, mips_at, 0);
3298 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3299 ArgInfo *ainfo = cinfo->args + i;
3300 inst = cfg->args [pos];
3302 if (cfg->verbose_level > 2)
3303 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3304 if (inst->opcode == OP_REGVAR) {
3305 /* Argument ends up in a register */
3306 if (ainfo->regtype == RegTypeGeneral)
3307 mips_move (code, inst->dreg, ainfo->reg);
3308 else if (ainfo->regtype == RegTypeFP) {
3309 g_assert_not_reached();
3311 ppc_fmr (code, inst->dreg, ainfo->reg);
3314 else if (ainfo->regtype == RegTypeBase) {
3315 mips_lw (code, inst->dreg, mips_sp, cfg->stack_usage + ainfo->offset);
3317 g_assert_not_reached ();
3319 if (cfg->verbose_level > 2)
3320 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3322 /* Argument ends up on the stack */
3323 if (ainfo->regtype == RegTypeGeneral) {
3324 /* Incoming parameters should be above this frame */
3325 g_assert (inst->inst_offset >= alloc_size);
3326 g_assert (mips_is_imm16 (inst->inst_offset));
3327 switch (ainfo->size) {
3329 mips_sb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3332 mips_sh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3336 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3339 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3340 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
3343 g_assert_not_reached ();
3346 } else if (ainfo->regtype == RegTypeBase) {
3348 * Argument comes in on the stack, and ends up on the stack
3349 * 1 and 2 byte args are passed as 32-bit quantities, but used as
3350 * 8 and 16 bit quantities. Shorten them in place.
3352 g_assert (mips_is_imm16 (inst->inst_offset));
3353 switch (ainfo->size) {
3355 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
3356 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
3359 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
3360 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
3367 g_assert_not_reached ();
3369 } else if (ainfo->regtype == RegTypeFP) {
3370 g_assert (mips_is_imm16 (inst->inst_offset));
3371 if (ainfo->size == 8) {
3373 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3375 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
3376 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
3379 else if (ainfo->size == 4)
3380 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3382 g_assert_not_reached ();
3383 } else if (ainfo->regtype == RegTypeStructByVal) {
3385 int doffset = inst->inst_offset;
3387 g_assert (mips_is_imm16 (inst->inst_offset));
3388 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3389 /* Push the argument registers into their stack slots */
3390 for (i = 0; i < ainfo->size; ++i) {
3391 mips_sw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3392 doffset += sizeof (gpointer);
3394 } else if (ainfo->regtype == RegTypeStructByAddr) {
3395 g_assert (mips_is_imm16 (inst->inst_offset));
3396 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3397 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
3399 g_assert_not_reached ();
3404 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
3405 mips_load_const (code, mips_a0, cfg->domain);
3406 mips_load_const (code, mips_t9, (gpointer)mono_jit_thread_attach);
3407 mips_jalr (code, mips_t9, mips_ra);
3412 if (method->save_lmf) {
3413 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
3414 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
3416 if (lmf_pthread_key != -1) {
3417 g_assert_not_reached();
3419 emit_tls_access (code, mips_temp, lmf_pthread_key);
3421 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
3422 mips_addiu (code, mips_a0, mips_temp, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3425 mips_addiu (code, mips_a0, mips_sp, lmf_offset);
3426 mips_load_const (code, mips_t9, (gpointer)mono_trace_lmf_prolog);
3427 mips_jalr (code, mips_t9, mips_ra);
3430 /* This can/will clobber the a0-a3 registers */
3431 mips_load_const (code, mips_t9, (gpointer)mono_get_lmf_addr);
3432 mips_jalr (code, mips_t9, mips_ra);
3436 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
3437 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
3438 /* new_lmf->previous_lmf = *lmf_addr */
3439 mips_lw (code, mips_at, mips_v0, 0);
3440 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
3441 /* *(lmf_addr) = sp + lmf_offset */
3442 mips_addiu (code, mips_at, mips_sp, lmf_offset);
3443 mips_sw (code, mips_at, mips_v0, 0);
3445 /* save method info */
3446 mips_load_const (code, mips_at, method);
3447 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
3448 mips_sw (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
3450 /* save the current IP */
3451 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3452 mips_load_const (code, mips_at, 0x01010101);
3453 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
3457 cfg->code_len = code - cfg->native_code;
3458 g_assert (cfg->code_len < cfg->code_size);
3473 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
3476 int save_mode = SAVE_NONE;
3478 MonoMethod *method = cfg->method;
3479 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
3480 int save_offset = 16;
3485 offset = code - cfg->native_code;
3486 /* we need about 16 instructions */
3487 if (offset > (cfg->code_size - 16 * 4)) {
3488 cfg->code_size *= 2;
3489 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3490 code = cfg->native_code + offset;
3495 case MONO_TYPE_VOID:
3496 /* special case string .ctor icall */
3497 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
3498 save_mode = SAVE_ONE;
3500 save_mode = SAVE_NONE;
3504 save_mode = SAVE_TWO;
3508 save_mode = SAVE_FP;
3510 case MONO_TYPE_VALUETYPE:
3511 save_mode = SAVE_STRUCT;
3514 save_mode = SAVE_ONE;
3518 mips_addiu (code, mips_sp, mips_sp, -32);
3519 switch (save_mode) {
3521 mips_sw (code, mips_v0, mips_sp, save_offset);
3522 mips_sw (code, mips_v1, mips_sp, save_offset + 4);
3523 if (enable_arguments) {
3524 mips_move (code, mips_a1, mips_v0);
3525 mips_move (code, mips_a2, mips_v1);
3529 mips_sw (code, mips_v0, mips_sp, save_offset);
3530 if (enable_arguments) {
3531 mips_move (code, mips_a1, mips_v0);
3535 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
3536 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
3537 mips_lw (code, mips_a0, mips_sp, save_offset);
3538 mips_lw (code, mips_a1, mips_sp, save_offset+4);
3545 mips_load_const (code, mips_a0, cfg->method);
3546 mips_load_const (code, mips_t9, func);
3547 mips_jalr (code, mips_t9, mips_ra);
3550 switch (save_mode) {
3552 mips_lw (code, mips_v0, mips_sp, save_offset);
3553 mips_lw (code, mips_v1, mips_sp, save_offset + 4);
3556 mips_lw (code, mips_v0, mips_sp, save_offset);
3559 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
3566 mips_addiu (code, mips_sp, mips_sp, 32);
3573 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
3575 MonoMethod *method = cfg->method;
3577 int max_epilog_size = 16 + 20*4;
3578 guint32 iregs_to_restore;
3580 guint32 fregs_to_restore;
3584 if (cfg->method->save_lmf)
3585 max_epilog_size += 128;
3588 if (mono_jit_trace_calls != NULL)
3589 max_epilog_size += 50;
3591 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3592 max_epilog_size += 50;
3595 pos = code - cfg->native_code;
3596 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3597 cfg->code_size *= 2;
3598 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3599 mono_jit_stats.code_reallocs++;
3603 * Keep in sync with OP_JMP
3606 code = cfg->native_code + pos;
3608 code = cfg->native_code + cfg->code_len;
3610 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3611 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3613 pos = cfg->arch.iregs_offset;
3614 if (cfg->frame_reg != mips_sp) {
3615 mips_move (code, mips_sp, cfg->frame_reg);
3618 iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
3620 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
3622 if (iregs_to_restore) {
3623 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
3624 if (iregs_to_restore & (1 << i)) {
3625 mips_lw (code, i, mips_sp, pos);
3626 pos += sizeof (gulong);
3633 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
3635 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
3636 fregs_to_restore |= (fregs_to_restore << 1);
3638 if (fregs_to_restore) {
3639 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
3640 if (fregs_to_restore & (1 << i)) {
3641 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
3642 mips_lwc1 (code, i, mips_sp, pos);
3643 pos += sizeof (gulong);
3649 /* Unlink the LMF if necessary */
3650 if (method->save_lmf) {
3651 int lmf_offset = cfg->arch.lmf_offset;
3653 /* t0 = current_lmf->previous_lmf */
3654 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
3656 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
3657 /* (*lmf_addr) = previous_lmf */
3658 mips_sw (code, mips_temp, mips_t1, 0);
3662 /* Restore the fp */
3663 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
3665 /* Correct the stack pointer */
3666 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
3667 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage + MIPS_RET_ADDR_OFFSET);
3668 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage);
3670 /* Caller will emit either return or tail-call sequence */
3672 cfg->code_len = code - cfg->native_code;
3674 g_assert (cfg->code_len < cfg->code_size);
3679 mono_arch_emit_epilog (MonoCompile *cfg)
3683 code = mono_arch_emit_epilog_sub (cfg, NULL);
3685 mips_jr (code, mips_ra);
3688 cfg->code_len = code - cfg->native_code;
3690 g_assert (cfg->code_len < cfg->code_size);
3693 /* remove once throw_exception_by_name is eliminated */
3695 exception_id_by_name (const char *name)
3697 if (strcmp (name, "IndexOutOfRangeException") == 0)
3698 return MONO_EXC_INDEX_OUT_OF_RANGE;
3699 if (strcmp (name, "OverflowException") == 0)
3700 return MONO_EXC_OVERFLOW;
3701 if (strcmp (name, "ArithmeticException") == 0)
3702 return MONO_EXC_ARITHMETIC;
3703 if (strcmp (name, "DivideByZeroException") == 0)
3704 return MONO_EXC_DIVIDE_BY_ZERO;
3705 if (strcmp (name, "InvalidCastException") == 0)
3706 return MONO_EXC_INVALID_CAST;
3707 if (strcmp (name, "NullReferenceException") == 0)
3708 return MONO_EXC_NULL_REF;
3709 if (strcmp (name, "ArrayTypeMismatchException") == 0)
3710 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3711 g_error ("Unknown intrinsic exception %s\n", name);
3716 mono_arch_emit_exceptions (MonoCompile *cfg)
3719 MonoJumpInfo *patch_info;
3722 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3723 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3724 int max_epilog_size = 50;
3726 /* count the number of exception infos */
3729 * make sure we have enough space for exceptions
3730 * 24 is the simulated call to throw_exception_by_name
3732 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3734 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3735 i = exception_id_by_name (patch_info->data.target);
3736 g_assert (i < MONO_EXC_INTRINS_NUM);
3737 if (!exc_throw_found [i]) {
3738 max_epilog_size += 12;
3739 exc_throw_found [i] = TRUE;
3745 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3746 cfg->code_size *= 2;
3747 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3748 mono_jit_stats.code_reallocs++;
3751 code = cfg->native_code + cfg->code_len;
3753 /* add code to raise exceptions */
3754 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3755 switch (patch_info->type) {
3756 case MONO_PATCH_INFO_EXC: {
3758 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
3760 i = exception_id_by_name (patch_info->data.target);
3761 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
3762 if (!exc_throw_pos [i]) {
3765 exc_throw_pos [i] = code;
3766 //g_print ("exc: writing stub at %p\n", code);
3767 mips_load_const (code, mips_a0, patch_info->data.target);
3768 addr = (guint32) mono_arch_get_throw_exception_by_name ();
3769 mips_load_const (code, mips_t9, addr);
3770 mips_jr (code, mips_t9);
3773 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
3775 /* Turn into a Relative patch, pointing at code stub */
3776 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
3777 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
3779 g_assert_not_reached();
3789 cfg->code_len = code - cfg->native_code;
3791 g_assert (cfg->code_len < cfg->code_size);
3796 * Thread local storage support
3799 setup_tls_access (void)
3802 //guint32 *ins, *code;
3804 if (tls_mode == TLS_MODE_FAILED)
3807 if (g_getenv ("MONO_NO_TLS")) {
3808 tls_mode = TLS_MODE_FAILED;
3812 if (tls_mode == TLS_MODE_DETECT) {
3814 tls_mode = TLS_MODE_FAILED;
3818 ins = (guint32*)pthread_getspecific;
3819 /* uncond branch to the real method */
3820 if ((*ins >> 26) == 18) {
3822 val = (*ins & ~3) << 6;
3826 ins = (guint32*)val;
3828 ins = (guint32*) ((char*)ins + val);
3831 code = &cmplwi_1023;
3832 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
3834 ppc_li (code, ppc_r4, 0x48);
3837 if (*ins == cmplwi_1023) {
3838 int found_lwz_284 = 0;
3839 for (ptk = 0; ptk < 20; ++ptk) {
3841 if (!*ins || *ins == blr_ins)
3843 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
3848 if (!found_lwz_284) {
3849 tls_mode = TLS_MODE_FAILED;
3852 tls_mode = TLS_MODE_LTHREADS;
3853 } else if (*ins == li_0x48) {
3855 /* uncond branch to the real method */
3856 if ((*ins >> 26) == 18) {
3858 val = (*ins & ~3) << 6;
3862 ins = (guint32*)val;
3864 ins = (guint32*) ((char*)ins + val);
3867 ppc_li (code, ppc_r0, 0x7FF2);
3868 if (ins [1] == val) {
3869 /* Darwin on G4, implement */
3870 tls_mode = TLS_MODE_FAILED;
3874 ppc_mfspr (code, ppc_r3, 104);
3875 if (ins [1] != val) {
3876 tls_mode = TLS_MODE_FAILED;
3879 tls_mode = TLS_MODE_DARWIN_G5;
3882 tls_mode = TLS_MODE_FAILED;
3886 tls_mode = TLS_MODE_FAILED;
3891 if (monodomain_key == -1) {
3892 ptk = mono_domain_get_tls_key ();
3894 ptk = mono_pthread_key_for_tls (ptk);
3896 monodomain_key = ptk;
3900 if (lmf_pthread_key == -1) {
3901 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
3903 /*g_print ("MonoLMF at: %d\n", ptk);*/
3904 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
3905 init_tls_failed = 1;
3908 lmf_pthread_key = ptk;
3911 if (monothread_key == -1) {
3912 ptk = mono_thread_get_tls_key ();
3914 ptk = mono_pthread_key_for_tls (ptk);
3916 monothread_key = ptk;
3917 /*g_print ("thread inited: %d\n", ptk);*/
3920 /*g_print ("thread not inited yet %d\n", ptk);*/
3926 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3928 setup_tls_access ();
3932 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3937 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3939 int this_dreg = mips_a0;
3942 this_dreg = mips_a1;
3944 /* add the this argument */
3945 if (this_reg != -1) {
3947 MONO_INST_NEW (cfg, this, OP_SETREG);
3948 this->type = this_type;
3949 this->sreg1 = this_reg;
3950 this->dreg = mono_regstate_next_int (cfg->rs);
3951 mono_bblock_add_inst (cfg->cbb, this);
3952 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
3957 MONO_INST_NEW (cfg, vtarg, OP_SETREG);
3958 vtarg->type = STACK_MP;
3959 vtarg->sreg1 = vt_reg;
3960 vtarg->dreg = mono_regstate_next_int (cfg->rs);
3961 mono_bblock_add_inst (cfg->cbb, vtarg);
3962 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
3967 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3969 MonoInst *ins = NULL;
3971 if (cmethod->klass == mono_defaults.thread_class &&
3972 strcmp (cmethod->name, "MemoryBarrier") == 0) {
3973 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
3976 if (cmethod->klass == mono_defaults.math_class) {
3977 if (strcmp (cmethod->name, "Sqrt") == 0) {
3978 MONO_INST_NEW (cfg, ins, OP_SQRT);
3979 ins->inst_i0 = args [0];
3987 mono_arch_print_tree (MonoInst *tree, int arity)
3992 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
3996 setup_tls_access ();
3997 if (monodomain_key == -1)
4000 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4001 ins->inst_offset = monodomain_key;
4006 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4010 setup_tls_access ();
4011 if (monothread_key == -1)
4014 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4015 ins->inst_offset = monothread_key;