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"
28 #define ALWAYS_USE_FP 1
29 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
38 int mono_exc_esp_offset = 0;
39 static int tls_mode = TLS_MODE_DETECT;
40 static int lmf_pthread_key = -1;
41 static int monothread_key = -1;
42 static int monodomain_key = -1;
45 #define DEBUG(a) if (cfg->verbose_level > 1) a
51 #define NOT_IMPLEMENTED(x) \
52 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
54 /* emit an exception if condition is failed
56 * We assign the extra code used to throw the implicit exceptions
57 * to cfg->bb_exit as far as the big branch handling is concerned
60 #define EMIT_SYSTEM_EXCEPTION_NAME_LEN 5
61 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
63 mono_add_patch_info (cfg, code - cfg->native_code, \
64 MONO_PATCH_INFO_EXC, exc_name); \
65 mips_lui (code, mips_t9, mips_zero, 0); \
66 mips_addiu (code, mips_t9, mips_t9, 0); \
67 mips_jalr (code, mips_t9, mips_ra); \
69 cfg->bb_exit->max_offset += 16; \
73 /* XXX - need to actually test the condition - not just bne */
74 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
76 mips_bne (code, mips_at, mips_zero, 5); \
78 EMIT_SYSTEM_EXCEPTION_NAME(exc_name); \
79 cfg->bb_exit->max_offset += 8; \
82 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) \
86 mips_bne (code, mips_at, mips_zero, 5); \
89 g_assert_not_reached(); \
92 EMIT_SYSTEM_EXCEPTION_NAME(exc_name); \
93 cfg->bb_exit->max_offset += 8; \
96 #define emit_linuxthreads_tls(code,dreg,key) do {\
98 off1 = offsets_from_pthread_key ((key), &off2); \
99 ppc_lwz ((code), (dreg), off1, ppc_r2); \
100 ppc_lwz ((code), (dreg), off2, (dreg)); \
104 #define emit_tls_access(code,dreg,key) do { \
105 switch (tls_mode) { \
106 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
107 default: g_assert_not_reached (); \
111 typedef struct InstList InstList;
119 #define ALWAYS_ON_STACK(s) s
120 #define FP_ALSO_IN_REG(s) s
121 #define ALIGN_DOUBLES
133 guint16 vtsize; /* in param area */
135 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
136 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
154 static const char*const * ins_spec = mips_desc;
156 void patch_lui_addiu(guint32 *ip, guint32 val);
159 mono_arch_flush_icache (guint8 *code, gint size)
161 /* Linux/MIPS specific */
162 cacheflush (code, size, BCACHE);
165 #ifndef CUSTOM_STACK_WALK
167 mono_arch_flush_register_windows (void)
172 /* XXX - big-endian dependent? */
174 patch_lui_addiu(guint32 *ip, guint32 val)
176 guint16 *__lui_addiu = (guint16*)(void *)(ip);
179 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
180 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
183 if (((guint32)(val)) & (1 << 15))
184 __lui_addiu [1] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
186 __lui_addiu [1] = (((guint32)(val)) >> 16) & 0xffff;
187 __lui_addiu [3] = ((guint32)(val)) & 0xffff;
188 mono_arch_flush_icache ((guint8 *)ip, 8);
192 mips_patch (guint32 *code, guint32 target)
195 guint32 op = ins >> 26;
196 guint32 diff, offset;
198 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
200 case 0x00: /* jr ra */
201 if (ins == 0x3e00008)
203 g_assert_not_reached ();
207 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
209 mono_arch_flush_icache ((guint8 *)code, 4);
211 case 0x01: /* BLTZ */
214 case 0x06: /* BLEZ */
215 case 0x07: /* BGTZ */
216 case 0x11: /* bc1t */
217 diff = target - (guint32)(code + 1);
219 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
221 mono_arch_flush_icache ((guint8 *)code, 4);
223 case 0x0f: /* LUI / ADDIU pair */
224 patch_lui_addiu (code, target);
225 mono_arch_flush_icache ((guint8 *)code, 8);
229 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
230 g_assert_not_reached ();
235 offsets_from_pthread_key (guint32 key, int *offset2)
239 *offset2 = idx2 * sizeof (gpointer);
240 return 284 + idx1 * sizeof (gpointer);
244 mono_arch_regname (int reg) {
245 static const char * rnames[] = {
246 "zero", "at", "v0", "v1",
247 "a0", "a1", "a2", "a3",
248 "t0", "t1", "t2", "t3",
249 "t4", "t5", "t6", "t7",
250 "s0", "s1", "s2", "s3",
251 "s4", "s5", "s6", "s7",
252 "t8", "t9", "k0", "k1",
253 "gp", "sp", "fp", "ra"
255 if (reg >= 0 && reg < 32)
261 mono_arch_fregname (int reg) {
262 static const char * rnames[] = {
263 "f0", "f1", "f2", "f3",
264 "f4", "f5", "f6", "f7",
265 "f8", "f9", "f10", "f11",
266 "f12", "f13", "f14", "f15",
267 "f16", "f17", "f18", "f19",
268 "f20", "f21", "f22", "f23",
269 "f24", "f25", "f26", "f27",
270 "f28", "f29", "f30", "f31"
272 if (reg >= 0 && reg < 32)
277 /* this function overwrites at */
279 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
281 /* XXX write a loop, not an unrolled loop */
283 mips_lw (code, mips_at, sreg, soffset);
284 mips_sw (code, mips_at, dreg, doffset);
293 * mono_arch_get_argument_info:
294 * @csig: a method signature
295 * @param_count: the number of parameters to consider
296 * @arg_info: an array to store the result infos
298 * Gathers information on parameters such as size, alignment and
299 * padding. arg_info should be large enought to hold param_count + 1 entries.
301 * Returns the size of the activation frame.
304 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
306 int k, frame_size = 0;
307 guint32 size, align, pad;
310 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
311 frame_size += sizeof (gpointer);
315 arg_info [0].offset = offset;
318 frame_size += sizeof (gpointer);
322 arg_info [0].size = frame_size;
324 for (k = 0; k < param_count; k++) {
327 size = mono_type_native_stack_size (csig->params [k], &align);
329 size = mono_type_stack_size (csig->params [k], &align);
331 /* ignore alignment for now */
334 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
335 arg_info [k].pad = pad;
337 arg_info [k + 1].pad = 0;
338 arg_info [k + 1].size = size;
340 arg_info [k + 1].offset = offset;
344 align = MONO_ARCH_FRAME_ALIGNMENT;
345 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
346 arg_info [k].pad = pad;
352 * Initialize the cpu to execute managed code.
355 mono_arch_cpu_init (void)
360 * This function returns the optimizations supported on this cpu.
363 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
367 /* no mips-specific optimizations yet */
373 is_regsize_var (MonoType *t) {
376 t = mono_type_get_underlying_type (t);
383 case MONO_TYPE_FNPTR:
385 case MONO_TYPE_OBJECT:
386 case MONO_TYPE_STRING:
387 case MONO_TYPE_CLASS:
388 case MONO_TYPE_SZARRAY:
389 case MONO_TYPE_ARRAY:
391 case MONO_TYPE_GENERICINST:
392 if (!mono_type_generic_inst_is_valuetype (t))
395 case MONO_TYPE_VALUETYPE:
402 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
407 for (i = 0; i < cfg->num_varinfo; i++) {
408 MonoInst *ins = cfg->varinfo [i];
409 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
412 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
415 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
418 /* we can only allocate 32 bit values */
419 if (is_regsize_var (ins->inst_vtype)) {
420 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
421 g_assert (i == vmv->idx);
422 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
430 mono_arch_get_global_int_regs (MonoCompile *cfg)
434 regs = g_list_prepend (regs, (gpointer)mips_s0);
435 regs = g_list_prepend (regs, (gpointer)mips_s1);
436 regs = g_list_prepend (regs, (gpointer)mips_s2);
437 regs = g_list_prepend (regs, (gpointer)mips_s3);
438 regs = g_list_prepend (regs, (gpointer)mips_s4);
439 regs = g_list_prepend (regs, (gpointer)mips_s5);
440 regs = g_list_prepend (regs, (gpointer)mips_s6);
441 regs = g_list_prepend (regs, (gpointer)mips_s7);
447 * mono_arch_regalloc_cost:
449 * Return the cost, in number of memory references, of the action of
450 * allocating the variable VMV into a register during global register
454 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
461 args_onto_stack (CallInfo *info, gboolean force)
463 if (!info->on_stack) {
464 if ((info->gr > MIPS_LAST_ARG_REG) || (info->fr > (MIPS_LAST_FPARG_REG+1))) {
468 info->on_stack = TRUE;
469 info->stack_size = MIPS_STACK_PARAM_OFFSET;
475 * O32 calling convention version
479 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
480 /* First, see if we need to drop onto the stack */
481 args_onto_stack (info, FALSE);
483 /* Now, place the argument */
484 ainfo->offset = info->stack_size;
485 info->stack_size += 4;
486 if (info->on_stack) {
487 ainfo->regtype = RegTypeBase;
488 ainfo->reg = mips_sp; /* in the caller */
491 ainfo->reg = info->gr;
493 info->gr_passed += 1;
494 /* FP and GP slots do not overlap */
500 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
501 /* First, see if we need to drop onto the stack */
502 args_onto_stack (info, FALSE);
504 /* Now, place the argument */
505 if (info->stack_size & 0x7) {
508 /* foo (int, long) -- need to align 2nd arg */
509 add_int32_arg (info, &dummy);
510 args_onto_stack (info, FALSE);
512 ainfo->offset = info->stack_size;
513 info->stack_size += 8;
514 if (info->on_stack) {
515 ainfo->regtype = RegTypeBase;
516 ainfo->reg = mips_sp; /* in the caller */
519 ainfo->reg = info->gr;
521 info->gr_passed += 2;
522 /* FP and GP slots do not overlap */
528 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
529 /* First, see if we need to drop onto the stack */
530 args_onto_stack (info, FALSE);
532 /* Now, place the argument */
533 ainfo->offset = info->stack_size;
534 if (info->on_stack) {
535 ainfo->regtype = RegTypeBase;
536 ainfo->reg = mips_sp; /* in the caller */
537 info->stack_size += 8;
540 /* Only use FP regs for args if no int args passed yet */
541 if (!info->gr_passed) {
542 ainfo->regtype = RegTypeFP;
543 ainfo->reg = info->fr;
544 info->stack_size += 8;
545 /* Even though it's a single-precision float, it takes up two FP regs */
547 info->fr_passed += 1;
548 /* FP and GP slots do not overlap */
552 /* Passing single-precision float arg in a GP register
553 * such as: func (0, 1.0, 2, 3);
554 * In this case, only one 'gr' register is consumed.
556 ainfo->regtype = RegTypeGeneral;
557 ainfo->reg = info->gr;
558 info->stack_size += 4;
560 /* Even though it's a single-precision float, it takes up two FP regs */
562 info->fr_passed += 1;
563 /* FP and GP slots do not overlap */
570 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
571 /* First, see if we need to drop onto the stack */
572 args_onto_stack (info, FALSE);
574 /* Now, place the argument */
576 // info->stack_size += (info->stack_size % 8);
578 ainfo->offset = info->stack_size;
579 info->stack_size += 8;
580 if (info->on_stack) {
581 ainfo->regtype = RegTypeBase;
582 ainfo->reg = mips_sp; /* in the caller */
585 /* Only use FP regs for args if no int args passed yet */
586 if (!info->gr_passed) {
587 ainfo->regtype = RegTypeFP;
588 ainfo->reg = info->fr;
591 ainfo->regtype = RegTypeGeneral;
592 ainfo->reg = info->gr;
595 info->fr_passed += 2;
596 /* FP and GP slots do not overlap */
602 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
605 int n = sig->hasthis + sig->param_count;
607 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
609 cinfo->fr = MIPS_FIRST_FPARG_REG;
610 cinfo->gr = MIPS_FIRST_ARG_REG;
611 cinfo->stack_size = 0;
613 DEBUG(printf("calculate_sizes\n"));
615 /* handle returning a struct */
616 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
617 cinfo->struct_ret = cinfo->gr;
618 add_int32_arg (cinfo, &cinfo->ret);
623 add_int32_arg (cinfo, cinfo->args + n);
626 DEBUG(printf("params: %d\n", sig->param_count));
627 for (i = 0; i < sig->param_count; ++i) {
628 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
629 /* Prevent implicit arguments and sig_cookie from
630 being passed in registers */
631 args_onto_stack (cinfo, TRUE);
632 /* Emit the signature cookie just before the implicit arguments */
633 add_int32_arg (cinfo, &cinfo->sig_cookie);
635 DEBUG(printf("param %d: ", i));
636 if (sig->params [i]->byref) {
637 DEBUG(printf("byref\n"));
638 add_int32_arg (cinfo, &cinfo->args[n]);
642 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
643 switch (simpletype) {
644 case MONO_TYPE_BOOLEAN:
647 DEBUG(printf("1 byte\n"));
648 cinfo->args [n].size = 1;
649 add_int32_arg (cinfo, &cinfo->args[n]);
655 DEBUG(printf("2 bytes\n"));
656 cinfo->args [n].size = 2;
657 add_int32_arg (cinfo, &cinfo->args[n]);
662 DEBUG(printf("4 bytes\n"));
663 cinfo->args [n].size = 4;
664 add_int32_arg (cinfo, &cinfo->args[n]);
670 case MONO_TYPE_FNPTR:
671 case MONO_TYPE_CLASS:
672 case MONO_TYPE_OBJECT:
673 case MONO_TYPE_STRING:
674 case MONO_TYPE_SZARRAY:
675 case MONO_TYPE_ARRAY:
676 cinfo->args [n].size = sizeof (gpointer);
677 add_int32_arg (cinfo, &cinfo->args[n]);
680 case MONO_TYPE_GENERICINST:
681 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
682 cinfo->args [n].size = sizeof (gpointer);
683 add_int32_arg (cinfo, &cinfo->args[n]);
688 case MONO_TYPE_VALUETYPE: {
693 gint size, alignment;
696 klass = mono_class_from_mono_type (sig->params [i]);
698 size = mono_class_native_size (klass, NULL);
700 size = mono_class_value_size (klass, NULL);
701 alignment = mono_class_min_align (klass);
702 DEBUG(printf ("load %d bytes struct\n",
703 mono_class_native_size (sig->params [i]->data.klass, NULL)));
704 #if MIPS_PASS_STRUCTS_BY_VALUE
705 cinfo->args [n].regtype = RegTypeStructByVal;
707 /* Need to do alignment if struct contains long or double */
708 if (cinfo->stack_size & (alignment - 1)) {
709 add_int32_arg (cinfo, &dummy_arg);
711 g_assert (!(cinfo->stack_size & (alignment - 1)));
714 align_size += (sizeof (gpointer) - 1);
715 align_size &= ~(sizeof (gpointer) - 1);
716 nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
717 for (j = 0; j < nwords; ++j) {
719 add_int32_arg (cinfo, &cinfo->args [n]);
721 add_int32_arg (cinfo, &dummy_arg);
723 cinfo->args [n].vtsize += 1;
725 cinfo->args [n].size += 1;
728 add_int32_arg (cinfo, &cinfo->args[n]);
729 cinfo->args [n].regtype = RegTypeStructByAddr;
734 case MONO_TYPE_TYPEDBYREF: {
735 /* keep in sync or merge with the valuetype case */
736 #if MIPS_PASS_STRUCTS_BY_VALUE
738 int size = sizeof (MonoTypedRef);
739 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
740 cinfo->args [n].regtype = RegTypeStructByVal;
741 if (cinfo->gr <= MIPS_LAST_ARG_REG) {
742 int rest = MIPS_LAST_ARG_REG - cinfo->gr + 1;
743 int n_in_regs = rest >= nwords? nwords: rest;
744 cinfo->args [n].size = n_in_regs;
745 cinfo->args [n].vtsize = nwords - n_in_regs;
746 cinfo->args [n].reg = cinfo->gr;
747 cinfo->gr += n_in_regs;
749 cinfo->args [n].size = 0;
750 cinfo->args [n].vtsize = nwords;
752 cinfo->args [n].offset = MIPS_STACK_PARAM_OFFSET + cinfo->stack_size;
753 g_print ("offset for arg %d at %d\n", n, MIPS_STACK_PARAM_OFFSET + cinfo->stack_size);
754 cinfo->stack_size += nwords * sizeof (gpointer);
757 add_int32_arg (cinfo, &cinfo->args[n]);
758 cinfo->args [n].regtype = RegTypeStructByAddr;
765 cinfo->args [n].size = 8;
766 add_int64_arg (cinfo, &cinfo->args[n]);
770 cinfo->args [n].size = 4;
771 add_float32_arg (cinfo, &cinfo->args[n]);
775 cinfo->args [n].size = 8;
776 add_float64_arg (cinfo, &cinfo->args[n]);
780 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
785 simpletype = mono_type_get_underlying_type (sig->ret)->type;
786 switch (simpletype) {
787 case MONO_TYPE_BOOLEAN:
798 case MONO_TYPE_FNPTR:
799 case MONO_TYPE_CLASS:
800 case MONO_TYPE_OBJECT:
801 case MONO_TYPE_SZARRAY:
802 case MONO_TYPE_ARRAY:
803 case MONO_TYPE_STRING:
804 cinfo->ret.reg = mips_v0;
808 cinfo->ret.reg = mips_v0;
812 cinfo->ret.reg = mips_f0;
813 cinfo->ret.regtype = RegTypeFP;
815 case MONO_TYPE_GENERICINST:
816 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
817 cinfo->ret.reg = mips_v0;
821 case MONO_TYPE_VALUETYPE:
823 case MONO_TYPE_TYPEDBYREF:
827 g_error ("Can't handle as return value 0x%x", sig->ret->type);
831 /* align stack size to 16 */
832 cinfo->stack_size = (cinfo->stack_size + 15) & ~15;
834 cinfo->stack_usage = cinfo->stack_size;
840 * Set var information according to the calling convention. mips version.
841 * The locals var stuff should most likely be split in another method.
844 mono_arch_allocate_vars (MonoCompile *cfg)
846 MonoMethodSignature *sig;
847 MonoMethodHeader *header;
849 int i, offset, size, align, curinst;
850 int frame_reg = mips_sp;
851 guint32 iregs_to_save = 0;
852 guint32 fregs_to_restore;
854 cfg->flags |= MONO_CFG_HAS_SPILLUP;
856 /* allow room for the vararg method args: void* and long/double */
857 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
858 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
860 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
861 * call convs needs to be handled this way.
863 if (cfg->flags & MONO_CFG_HAS_VARARGS)
864 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
866 /* gtk-sharp and other broken code will dllimport vararg functions even with
867 * non-varargs signatures. Since there is little hope people will get this right
868 * we assume they won't.
870 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
871 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
873 cfg->param_area = MAX (cfg->param_area, 16);
875 header = mono_method_get_header (cfg->method);
877 sig = mono_method_signature (cfg->method);
880 * We use the frame register also for any method that has
881 * exception clauses. This way, when the handlers are called,
882 * the code will reference local variables using the frame reg instead of
883 * the stack pointer: if we had to restore the stack pointer, we'd
884 * corrupt the method frames that are already on the stack (since
885 * filters get called before stack unwinding happens) when the filter
886 * code would call any method (this also applies to finally etc.).
889 if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses || ALWAYS_USE_FP)
891 cfg->frame_reg = frame_reg;
892 if (frame_reg != mips_sp) {
893 cfg->used_int_regs |= 1 << frame_reg;
898 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
899 /* FIXME: handle long and FP values */
900 switch (mono_type_get_underlying_type (sig->ret)->type) {
904 cfg->ret->opcode = OP_REGVAR;
905 cfg->ret->inst_c0 = mips_v0;
909 /* Space for outgoing parameters, including a0-a3 */
910 offset += cfg->param_area;
912 /* allow room to save the return value (if it's a struct) */
913 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
916 if (sig->call_convention == MONO_CALL_VARARG) {
917 cfg->sig_cookie = MIPS_STACK_PARAM_OFFSET;
920 /* Now handle the local variables */
922 curinst = cfg->locals_start;
923 for (i = curinst; i < cfg->num_varinfo; ++i) {
924 inst = cfg->varinfo [i];
925 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
928 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
929 * pinvoke wrappers when they call functions returning structure
931 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
932 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
934 size = mono_type_size (inst->inst_vtype, &align);
937 offset &= ~(align - 1);
938 inst->inst_offset = offset;
939 inst->opcode = OP_REGOFFSET;
940 inst->inst_basereg = frame_reg;
942 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
945 /* Space for LMF (if needed) */
947 if (cfg->method->save_lmf) {
948 /* align the offset to 16 bytes */
949 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
950 cfg->arch.lmf_offset = offset;
951 offset += sizeof (MonoLMF);
956 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
957 * args or return vals. Extra stack space avoids this in a lot of cases.
961 /* Space for saved registers */
962 cfg->arch.iregs_offset = offset;
963 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
965 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
966 if (iregs_to_save & (1 << i)) {
967 offset += sizeof (gulong);
973 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
974 * args or return vals. Extra stack space avoids this in a lot of cases.
979 /* saved float registers */
981 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
982 if (fregs_to_restore) {
983 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
984 if (fregs_to_restore & (1 << i)) {
985 offset += sizeof (double);
992 /* XXX - pre-allocate spill locations */
994 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
995 cfg->arch.spillvar_offset = offset;
997 cfg->arch.spillvar_offset_float = offset;
1000 /* Now add space for saving the ra */
1004 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1005 cfg->stack_offset = offset;
1008 * Now allocate stack slots for the int arg regs (a0 - a3)
1009 * On MIPS o32, these are just above the incoming stack pointer
1010 * Even if the arg has been assigned to a regvar, it gets a stack slot
1013 /* Return struct-by-value results in a hidden first argument */
1014 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1015 cfg->ret->opcode = OP_REGOFFSET;
1016 cfg->ret->inst_c0 = mips_a0;
1017 cfg->ret->inst_offset = offset;
1018 cfg->ret->inst_basereg = frame_reg;
1022 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1023 inst = cfg->varinfo [i];
1024 if (inst->opcode != OP_REGVAR) {
1027 if (sig->hasthis && (i == 0))
1028 arg_type = &mono_defaults.object_class->byval_arg;
1030 arg_type = sig->params [i - sig->hasthis];
1032 inst->opcode = OP_REGOFFSET;
1033 size = mono_type_size (arg_type, &align);
1035 /* Need to take references to R4 into account */
1036 /* If it's a single-precision float, allocate 8 bytes of stack for it */
1037 if ((arg_type->type == MONO_TYPE_R4) && !arg_type->byref) {
1045 inst->inst_basereg = frame_reg;
1046 offset = (offset + align - 1) & ~(align - 1);
1047 inst->inst_offset = offset;
1049 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1050 cfg->sig_cookie += size;
1051 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1054 /* Even a0-a3 get stack slots */
1055 size = sizeof (gpointer);
1056 align = sizeof (gpointer);
1057 inst->inst_basereg = frame_reg;
1058 offset = (offset + align - 1) & ~(align - 1);
1059 inst->inst_offset = offset;
1061 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1062 cfg->sig_cookie += size;
1063 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1068 inst = cfg->varinfo [curinst];
1069 if (inst->opcode != OP_REGVAR) {
1070 inst->opcode = OP_REGOFFSET;
1071 inst->inst_basereg = frame_reg;
1072 offset += sizeof (gpointer) - 1;
1073 offset &= ~(sizeof (gpointer) - 1);
1074 inst->inst_offset = offset;
1075 offset += sizeof (gpointer);
1076 if (sig->call_convention == MONO_CALL_VARARG)
1077 cfg->sig_cookie += sizeof (gpointer);
1078 // g_print ("allocating this to %d\n", inst->inst_offset);
1085 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1086 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1090 * take the arguments and generate the arch-specific
1091 * instructions to properly call the function in call.
1092 * This includes pushing, moving arguments to the right register
1094 * Issue: who does the spilling if needed, and when?
1097 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
1099 MonoMethodSignature *sig;
1104 sig = call->signature;
1105 n = sig->param_count + sig->hasthis;
1107 cinfo = calculate_sizes (sig, sig->pinvoke);
1108 if (cinfo->struct_ret)
1109 call->used_iregs |= 1 << cinfo->struct_ret;
1111 for (i = 0; i < n; ++i) {
1112 ainfo = cinfo->args + i;
1113 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1115 cfg->disable_aot = TRUE;
1117 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1118 sig_arg->inst_p0 = call->signature;
1120 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1121 arg->inst_imm = cinfo->sig_cookie.offset;
1122 arg->inst_left = sig_arg;
1124 /* prepend, so they get reversed */
1125 arg->next = call->out_args;
1126 call->out_args = arg;
1128 if (is_virtual && i == 0) {
1129 /* the argument will be attached to the call instrucion */
1130 in = call->args [i];
1131 call->used_iregs |= 1 << ainfo->reg;
1133 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1134 in = call->args [i];
1135 arg->cil_code = in->cil_code;
1136 arg->inst_left = in;
1137 arg->inst_call = call;
1138 arg->type = in->type;
1139 /* prepend, we'll need to reverse them later */
1140 arg->next = call->out_args;
1141 call->out_args = arg;
1142 if (ainfo->regtype == RegTypeGeneral) {
1143 arg->backend.reg3 = ainfo->reg;
1144 call->used_iregs |= 1 << ainfo->reg;
1145 if (arg->type == STACK_I8)
1146 call->used_iregs |= 1 << (ainfo->reg + 1);
1147 } else if (ainfo->regtype == RegTypeStructByAddr) {
1148 /* FIXME: where is the data allocated? */
1149 arg->backend.reg3 = ainfo->reg;
1150 call->used_iregs |= 1 << ainfo->reg;
1151 } else if (ainfo->regtype == RegTypeStructByVal) {
1153 MonoMIPSArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMIPSArgInfo));
1154 /* mark the used regs */
1155 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1156 call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1158 arg->opcode = OP_OUTARG_VT;
1159 ai->reg = ainfo->reg;
1160 ai->size = ainfo->size;
1161 ai->vtsize = ainfo->vtsize;
1162 ai->offset = ainfo->offset;
1163 arg->backend.data = ai;
1164 } else if (ainfo->regtype == RegTypeBase) {
1165 MonoMIPSArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMIPSArgInfo));
1166 arg->opcode = OP_OUTARG_MEMBASE;
1167 ai->reg = ainfo->reg;
1168 ai->size = ainfo->size;
1169 ai->offset = ainfo->offset;
1170 arg->backend.data = ai;
1171 } else if (ainfo->regtype == RegTypeFP) {
1172 arg->opcode = OP_OUTARG_R8;
1173 arg->backend.reg3 = ainfo->reg;
1174 call->used_fregs |= 1 << ainfo->reg;
1175 if (ainfo->size == 4) {
1176 arg->opcode = OP_OUTARG_R4;
1177 /* we reduce the precision */
1179 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1180 conv->inst_left = arg->inst_left;
1181 arg->inst_left = conv;*/
1184 g_assert_not_reached ();
1189 * Reverse the call->out_args list.
1192 MonoInst *prev = NULL, *list = call->out_args, *next;
1199 call->out_args = prev;
1201 call->stack_usage = cinfo->stack_usage;
1202 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1203 cfg->param_area = MAX (cfg->param_area, 16); /* a0-a3 always present */
1204 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1205 cfg->flags |= MONO_CFG_HAS_CALLS;
1207 * should set more info in call, such as the stack space
1208 * used by the args that needs to be added back to esp
1216 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1218 MonoInst *ins, *last_ins = NULL;
1223 switch (ins->opcode) {
1225 /* remove unnecessary multiplication with 1 */
1226 if (ins->inst_imm == 1) {
1227 if (ins->dreg != ins->sreg1) {
1228 ins->opcode = OP_MOVE;
1230 last_ins->next = ins->next;
1235 int power2 = mono_is_power_of_two (ins->inst_imm);
1237 ins->opcode = OP_SHL_IMM;
1238 ins->inst_imm = power2;
1242 case OP_LOAD_MEMBASE:
1243 case OP_LOADI4_MEMBASE:
1245 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1246 * OP_LOAD_MEMBASE offset(basereg), reg
1248 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1249 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1250 ins->inst_basereg == last_ins->inst_destbasereg &&
1251 ins->inst_offset == last_ins->inst_offset) {
1252 if (ins->dreg == last_ins->sreg1) {
1253 last_ins->next = ins->next;
1257 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1258 ins->opcode = OP_MOVE;
1259 ins->sreg1 = last_ins->sreg1;
1263 * Note: reg1 must be different from the basereg in the second load
1264 * OP_LOAD_MEMBASE offset(basereg), reg1
1265 * OP_LOAD_MEMBASE offset(basereg), reg2
1267 * OP_LOAD_MEMBASE offset(basereg), reg1
1268 * OP_MOVE reg1, reg2
1270 } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1271 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1272 ins->inst_basereg != last_ins->dreg &&
1273 ins->inst_basereg == last_ins->inst_basereg &&
1274 ins->inst_offset == last_ins->inst_offset) {
1276 if (ins->dreg == last_ins->dreg) {
1277 last_ins->next = ins->next;
1281 ins->opcode = OP_MOVE;
1282 ins->sreg1 = last_ins->dreg;
1285 //g_assert_not_reached ();
1289 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1290 * OP_LOAD_MEMBASE offset(basereg), reg
1292 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1293 * OP_ICONST reg, imm
1295 } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1296 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1297 ins->inst_basereg == last_ins->inst_destbasereg &&
1298 ins->inst_offset == last_ins->inst_offset) {
1299 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1300 ins->opcode = OP_ICONST;
1301 ins->inst_c0 = last_ins->inst_imm;
1302 g_assert_not_reached (); // check this rule
1306 case OP_LOADU1_MEMBASE:
1307 case OP_LOADI1_MEMBASE:
1308 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1309 ins->inst_basereg == last_ins->inst_destbasereg &&
1310 ins->inst_offset == last_ins->inst_offset) {
1311 if (ins->dreg == last_ins->sreg1) {
1312 last_ins->next = ins->next;
1316 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1317 ins->opcode = OP_MOVE;
1318 ins->sreg1 = last_ins->sreg1;
1322 case OP_LOADU2_MEMBASE:
1323 case OP_LOADI2_MEMBASE:
1324 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1325 ins->inst_basereg == last_ins->inst_destbasereg &&
1326 ins->inst_offset == last_ins->inst_offset) {
1327 if (ins->dreg == last_ins->sreg1) {
1328 last_ins->next = ins->next;
1332 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1333 ins->opcode = OP_MOVE;
1334 ins->sreg1 = last_ins->sreg1;
1342 ins->opcode = OP_MOVE;
1346 if (ins->dreg == ins->sreg1) {
1348 last_ins->next = ins->next;
1353 * OP_MOVE sreg, dreg
1354 * OP_MOVE dreg, sreg
1356 if (last_ins && last_ins->opcode == OP_MOVE &&
1357 ins->sreg1 == last_ins->dreg &&
1358 ins->dreg == last_ins->sreg1) {
1359 last_ins->next = ins->next;
1368 bb->last_ins = last_ins;
1371 static inline InstList*
1372 inst_list_prepend (MonoMemPool *pool, InstList *list, MonoInst *data)
1374 InstList *item = mono_mempool_alloc (pool, sizeof (InstList));
1384 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1388 bb->code = to_insert;
1389 to_insert->next = ins;
1391 to_insert->next = ins->next;
1392 ins->next = to_insert;
1396 #define NEW_INS(cfg,dest,op) do { \
1397 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1398 (dest)->opcode = (op); \
1399 insert_after_ins (bb, last_ins, (dest)); \
1403 map_to_reg_reg_op (int op)
1412 case OP_COMPARE_IMM:
1428 case OP_LOAD_MEMBASE:
1429 return OP_LOAD_MEMINDEX;
1430 case OP_LOADI4_MEMBASE:
1431 return OP_LOADI4_MEMINDEX;
1432 case OP_LOADU4_MEMBASE:
1433 return OP_LOADU4_MEMINDEX;
1434 case OP_LOADU1_MEMBASE:
1435 return OP_LOADU1_MEMINDEX;
1436 case OP_LOADI2_MEMBASE:
1437 return OP_LOADI2_MEMINDEX;
1438 case OP_LOADU2_MEMBASE:
1439 return OP_LOADU2_MEMINDEX;
1440 case OP_LOADI1_MEMBASE:
1441 return OP_LOADI1_MEMINDEX;
1442 case OP_LOADR4_MEMBASE:
1443 return OP_LOADR4_MEMINDEX;
1444 case OP_LOADR8_MEMBASE:
1445 return OP_LOADR8_MEMINDEX;
1446 case OP_STOREI1_MEMBASE_REG:
1447 return OP_STOREI1_MEMINDEX;
1448 case OP_STOREI2_MEMBASE_REG:
1449 return OP_STOREI2_MEMINDEX;
1450 case OP_STOREI4_MEMBASE_REG:
1451 return OP_STOREI4_MEMINDEX;
1452 case OP_STORE_MEMBASE_REG:
1453 return OP_STORE_MEMINDEX;
1454 case OP_STORER4_MEMBASE_REG:
1455 return OP_STORER4_MEMINDEX;
1456 case OP_STORER8_MEMBASE_REG:
1457 return OP_STORER8_MEMINDEX;
1458 case OP_STORE_MEMBASE_IMM:
1459 return OP_STORE_MEMBASE_REG;
1460 case OP_STOREI1_MEMBASE_IMM:
1461 return OP_STOREI1_MEMBASE_REG;
1462 case OP_STOREI2_MEMBASE_IMM:
1463 return OP_STOREI2_MEMBASE_REG;
1464 case OP_STOREI4_MEMBASE_IMM:
1465 return OP_STOREI4_MEMBASE_REG;
1467 g_assert_not_reached ();
1471 * Remove from the instruction list the instructions that can't be
1472 * represented with very simple instructions with no register
1476 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1478 MonoInst *ins, *next, *temp, *last_ins = NULL;
1481 /* setup the virtual reg allocator */
1482 if (bb->max_ireg > cfg->rs->next_vireg)
1483 cfg->rs->next_vireg = bb->max_ireg;
1488 switch (ins->opcode) {
1491 if (!mips_is_imm16 (ins->inst_imm)) {
1492 NEW_INS (cfg, temp, OP_ICONST);
1493 temp->inst_c0 = ins->inst_imm;
1494 temp->dreg = mono_regstate_next_int (cfg->rs);
1495 ins->sreg2 = temp->dreg;
1496 ins->opcode = map_to_reg_reg_op (ins->opcode);
1501 if (!mips_is_imm16 (-ins->inst_imm)) {
1502 NEW_INS (cfg, temp, OP_ICONST);
1503 temp->inst_c0 = ins->inst_imm;
1504 temp->dreg = mono_regstate_next_int (cfg->rs);
1505 ins->sreg2 = temp->dreg;
1506 ins->opcode = map_to_reg_reg_op (ins->opcode);
1514 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
1515 NEW_INS (cfg, temp, OP_ICONST);
1516 temp->inst_c0 = ins->inst_imm;
1517 temp->dreg = mono_regstate_next_int (cfg->rs);
1518 ins->sreg2 = temp->dreg;
1519 ins->opcode = map_to_reg_reg_op (ins->opcode);
1527 NEW_INS (cfg, temp, OP_ICONST);
1528 temp->inst_c0 = ins->inst_imm;
1529 temp->dreg = mono_regstate_next_int (cfg->rs);
1530 ins->sreg2 = temp->dreg;
1531 ins->opcode = map_to_reg_reg_op (ins->opcode);
1534 case OP_COMPARE_IMM:
1536 if (compare_opcode_is_unsigned (ins->next->opcode)) {
1537 if (!ppc_is_uimm16 (ins->inst_imm)) {
1538 NEW_INS (cfg, temp, OP_ICONST);
1539 temp->inst_c0 = ins->inst_imm;
1540 temp->dreg = mono_regstate_next_int (cfg->rs);
1541 ins->sreg2 = temp->dreg;
1542 ins->opcode = map_to_reg_reg_op (ins->opcode);
1545 if (!ppc_is_imm16 (ins->inst_imm)) {
1546 NEW_INS (cfg, temp, OP_ICONST);
1547 temp->inst_c0 = ins->inst_imm;
1548 temp->dreg = mono_regstate_next_int (cfg->rs);
1549 ins->sreg2 = temp->dreg;
1550 ins->opcode = map_to_reg_reg_op (ins->opcode);
1557 if (ins->inst_imm == 1) {
1558 ins->opcode = OP_MOVE;
1561 if (ins->inst_imm == 0) {
1562 ins->opcode = OP_ICONST;
1566 imm = mono_is_power_of_two (ins->inst_imm);
1568 ins->opcode = OP_SHL_IMM;
1569 ins->inst_imm = imm;
1572 if (!ppc_is_imm16 (ins->inst_imm)) {
1573 NEW_INS (cfg, temp, OP_ICONST);
1574 temp->inst_c0 = ins->inst_imm;
1575 temp->dreg = mono_regstate_next_int (cfg->rs);
1576 ins->sreg2 = temp->dreg;
1577 ins->opcode = map_to_reg_reg_op (ins->opcode);
1581 case OP_LOAD_MEMBASE:
1582 case OP_LOADI4_MEMBASE:
1583 case OP_LOADU4_MEMBASE:
1584 case OP_LOADI2_MEMBASE:
1585 case OP_LOADU2_MEMBASE:
1586 case OP_LOADI1_MEMBASE:
1587 case OP_LOADU1_MEMBASE:
1588 case OP_LOADR4_MEMBASE:
1589 case OP_LOADR8_MEMBASE:
1590 case OP_STORE_MEMBASE_REG:
1591 case OP_STOREI4_MEMBASE_REG:
1592 case OP_STOREI2_MEMBASE_REG:
1593 case OP_STOREI1_MEMBASE_REG:
1594 case OP_STORER4_MEMBASE_REG:
1595 case OP_STORER8_MEMBASE_REG:
1597 /* we can do two things: load the immed in a register
1598 * and use an indexed load, or see if the immed can be
1599 * represented as an ad_imm + a load with a smaller offset
1600 * that fits. We just do the first for now, optimize later.
1602 if (ppc_is_imm16 (ins->inst_offset))
1604 NEW_INS (cfg, temp, OP_ICONST);
1605 temp->inst_c0 = ins->inst_offset;
1606 temp->dreg = mono_regstate_next_int (cfg->rs);
1607 ins->sreg2 = temp->dreg;
1608 ins->opcode = map_to_reg_reg_op (ins->opcode);
1611 case OP_STORE_MEMBASE_IMM:
1612 case OP_STOREI1_MEMBASE_IMM:
1613 case OP_STOREI2_MEMBASE_IMM:
1614 case OP_STOREI4_MEMBASE_IMM:
1616 NEW_INS (cfg, temp, OP_ICONST);
1617 temp->inst_c0 = ins->inst_imm;
1618 temp->dreg = mono_regstate_next_int (cfg->rs);
1619 ins->sreg1 = temp->dreg;
1620 ins->opcode = map_to_reg_reg_op (ins->opcode);
1622 goto loop_start; /* make it handle the possibly big ins->inst_offset */
1631 bb->last_ins = last_ins;
1632 bb->max_ireg = cfg->rs->next_vireg;
1636 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1640 mono_arch_lowering_pass (cfg, bb);
1641 mono_local_regalloc (cfg, bb);
1643 mono_arch_allocate_vars (cfg);
1648 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
1650 /* sreg is a float, dreg is an integer reg. mips_at is used a scratch */
1652 mips_truncwd (code, mips_ftemp, sreg);
1654 mips_cvtwd (code, mips_ftemp, sreg);
1656 mips_mfc1 (code, dreg, mips_ftemp);
1659 mips_andi (code, dreg, dreg, 0xff);
1660 else if (size == 2) {
1661 mips_sll (code, dreg, dreg, 16);
1662 mips_srl (code, dreg, dreg, 16);
1666 mips_sll (code, dreg, dreg, 24);
1667 mips_sra (code, dreg, dreg, 24);
1669 else if (size == 2) {
1670 mips_sll (code, dreg, dreg, 16);
1671 mips_sra (code, dreg, dreg, 16);
1678 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
1683 guint8 *code = cfg->native_code + cfg->code_len;
1684 MonoInst *last_ins = NULL;
1685 guint last_offset = 0;
1689 if (cfg->opt & MONO_OPT_PEEPHOLE)
1690 peephole_pass (cfg, bb);
1692 /* we don't align basic blocks of loops on mips */
1694 if (cfg->verbose_level > 2)
1695 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
1697 cpos = bb->max_offset;
1700 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
1701 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
1702 g_assert (!mono_compile_aot);
1705 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
1706 /* this is not thread save, but good enough */
1707 /* fixme: howto handle overflows? */
1708 x86_inc_mem (code, &cov->data [bb->dfn].count);
1713 offset = code - cfg->native_code;
1715 max_len = ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
1717 if (offset > (cfg->code_size - max_len - 16)) {
1718 cfg->code_size *= 2;
1719 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1720 code = cfg->native_code + offset;
1722 mono_debug_record_line_number (cfg, ins, offset);
1723 if (cfg->verbose_level > 2) {
1724 g_print (" @ 0x%x\t", offset);
1725 mono_print_ins (ins_cnt++, ins);
1728 switch (ins->opcode) {
1730 g_assert_not_reached();
1732 emit_tls_access (code, ins->dreg, ins->inst_offset);
1736 mips_mult (code, ins->sreg1, ins->sreg2);
1737 mips_mflo (code, ins->dreg);
1738 mips_mfhi (code, ins->dreg+1);
1741 mips_multu (code, ins->sreg1, ins->sreg2);
1742 mips_mflo (code, ins->dreg);
1743 mips_mfhi (code, ins->dreg+1);
1745 case OP_MEMORY_BARRIER:
1750 case OP_STOREI1_MEMBASE_IMM:
1751 mips_load_const (code, mips_temp, ins->inst_imm);
1752 if (mips_is_imm16 (ins->inst_offset)) {
1753 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
1755 mips_load_const (code, mips_at, ins->inst_offset);
1756 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
1759 case OP_STOREI2_MEMBASE_IMM:
1760 mips_load_const (code, mips_temp, ins->inst_imm);
1761 if (mips_is_imm16 (ins->inst_offset)) {
1762 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
1764 mips_load_const (code, mips_at, ins->inst_offset);
1765 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
1768 case OP_STORE_MEMBASE_IMM:
1769 case OP_STOREI4_MEMBASE_IMM:
1770 mips_load_const (code, mips_temp, ins->inst_imm);
1771 if (mips_is_imm16 (ins->inst_offset)) {
1772 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
1774 mips_load_const (code, mips_at, ins->inst_offset);
1775 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
1778 case OP_STOREI1_MEMBASE_REG:
1779 if (mips_is_imm16 (ins->inst_offset)) {
1780 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1782 mips_load_const (code, mips_at, ins->inst_offset);
1783 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
1784 mips_sb (code, ins->sreg1, mips_at, 0);
1787 case OP_STOREI2_MEMBASE_REG:
1788 if (mips_is_imm16 (ins->inst_offset)) {
1789 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1791 mips_load_const (code, mips_at, ins->inst_offset);
1792 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
1793 mips_sh (code, ins->sreg1, mips_at, 0);
1796 case OP_STORE_MEMBASE_REG:
1797 case OP_STOREI4_MEMBASE_REG:
1798 if (mips_is_imm16 (ins->inst_offset)) {
1799 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1801 mips_load_const (code, mips_at, ins->inst_offset);
1802 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
1803 mips_sw (code, ins->sreg1, mips_at, 0);
1809 g_assert_not_reached ();
1810 //x86_mov_reg_mem (code, ins->dreg, ins->inst_p0, 4);
1813 g_assert_not_reached ();
1814 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
1815 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
1817 case OP_LOAD_MEMBASE:
1818 case OP_LOADI4_MEMBASE:
1819 case OP_LOADU4_MEMBASE:
1820 if (mips_is_imm16 (ins->inst_offset)) {
1821 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1823 mips_load_const (code, mips_at, ins->inst_offset);
1824 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1825 mips_lw (code, ins->dreg, mips_at, 0);
1828 case OP_LOADI1_MEMBASE:
1829 if (mips_is_imm16 (ins->inst_offset)) {
1830 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1832 mips_load_const (code, mips_at, ins->inst_offset);
1833 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1834 mips_lb (code, ins->dreg, mips_at, 0);
1837 case OP_LOADU1_MEMBASE:
1838 if (mips_is_imm16 (ins->inst_offset)) {
1839 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1841 mips_load_const (code, mips_at, ins->inst_offset);
1842 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1843 mips_lbu (code, ins->dreg, mips_at, 0);
1846 case OP_LOADI2_MEMBASE:
1847 if (mips_is_imm16 (ins->inst_offset)) {
1848 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1850 mips_load_const (code, mips_at, ins->inst_offset);
1851 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1852 mips_lh (code, ins->dreg, mips_at, 0);
1855 case OP_LOADU2_MEMBASE:
1856 if (mips_is_imm16 (ins->inst_offset)) {
1857 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1859 mips_load_const (code, mips_at, ins->inst_offset);
1860 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
1861 mips_lhu (code, ins->dreg, mips_at, 0);
1865 mips_sll (code, mips_at, ins->sreg1, 24);
1866 mips_sra (code, ins->dreg, mips_at, 24);
1869 mips_sll (code, mips_at, ins->sreg1, 16);
1870 mips_sra (code, ins->dreg, mips_at, 16);
1873 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
1876 mips_sll (code, mips_at, ins->sreg1, 16);
1877 mips_srl (code, ins->dreg, mips_at, 16);
1880 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
1883 g_assert (mips_is_imm16 (ins->inst_imm));
1884 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
1887 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
1890 g_assert (mips_is_imm16 (ins->inst_imm));
1891 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
1894 case OP_COMPARE_IMM:
1895 if (mips_is_imm16 (ins->inst_imm)) {
1896 mips_addiu (code, mips_at, ins->sreg1, ((-ins->inst_imm) & 0xffff));
1898 mips_load_const (code, mips_at, ins->inst_imm);
1899 mips_subu (code, mips_at, ins->sreg1, mips_at);
1903 mips_subu (code, mips_at, ins->sreg1, ins->sreg2);
1906 case OP_COMPARE_IMM:
1908 gboolean emitted = FALSE;
1909 guint cmp_reg = ins->sreg2;
1910 gboolean direct_imm = 0;
1913 if (ins->opcode == OP_COMPARE_IMM) {
1914 if (!mips_is_imm16 (ins->inst_imm)) {
1915 mips_load_const (code, mips_at, ins->inst_imm);
1920 imm = ins->inst_imm & 0xffff;
1926 switch (ins->next->opcode) {
1929 mips_sltiu (code, mips_at, ins->sreg1, imm);
1931 mips_sltu (code, mips_at, ins->sreg1, cmp_reg);
1933 mips_xori (code, mips_at, mips_at, 1);
1938 mips_sltiu (code, mips_at, ins->sreg1, imm);
1940 mips_sltu (code, mips_at, ins->sreg1, cmp_reg);
1945 mips_sll (code, mips_at, mips_at, 31);
1949 if (ins->inst_imm == 0) {
1950 mips_move (code, mips_at, ins->sreg1);
1951 } else if (mips_is_imm16 (-ins->inst_imm)) {
1952 mips_addiu (code, mips_at, ins->sreg1, ((-ins->inst_imm) & 0xffff));
1953 } else if (ins->opcode == OP_COMPARE_IMM) {
1954 mips_load_const (code, mips_at, ins->inst_imm);
1955 mips_subu (code, mips_at, ins->sreg1, mips_at);
1957 mips_subu (code, mips_at, ins->sreg1, ins->sreg2);
1965 mips_break (code, 0xfd);
1969 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
1972 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
1976 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
1979 /* XXX ppc_addc/ppc_addic */
1980 if (mips_is_imm16 (ins->inst_imm)) {
1981 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
1983 mips_load_const (code, mips_at, ins->inst_imm);
1984 mips_addu (code, ins->dreg, ins->sreg1, mips_at);
1988 if (mips_is_imm16 (ins->inst_imm)) {
1989 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
1991 mips_load_const (code, mips_at, ins->inst_imm);
1992 mips_add (code, ins->dreg, ins->sreg1, mips_at);
1997 mips_load_const (code, mips_at, ins->inst_imm);
1998 mips_addu (code, ins->dreg, ins->sreg1, mips_at);
2001 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
2002 /* XXX - Throw exception if overflowed */
2004 case CEE_ADD_OVF_UN:
2005 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
2006 /* XXX - Throw exception if overflowed */
2009 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
2010 /* XXX - Throw exception if overflowed */
2012 case CEE_SUB_OVF_UN:
2013 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
2014 /* XXX - Throw exception if overflowed */
2016 case OP_ADD_OVF_CARRY:
2017 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
2018 /* XXX - Throw exception if overflowed */
2020 case OP_ADD_OVF_UN_CARRY:
2021 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
2022 /* XXX - Throw exception if overflowed */
2024 case OP_SUB_OVF_CARRY:
2025 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
2026 /* XXX - Throw exception if overflowed */
2028 case OP_SUB_OVF_UN_CARRY:
2029 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
2030 /* XXX - Throw exception if overflowed */
2033 mips_subu (code, ins->dreg, ins->sreg2, ins->sreg1);
2037 mips_load_const (code, mips_at, ins->inst_imm);
2038 mips_subu (code, ins->dreg, mips_at, ins->sreg1);
2041 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
2045 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
2048 // we add the negated value
2049 if (mips_is_imm16 (-ins->inst_imm))
2050 mips_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2052 mips_load_const (code, mips_at, ins->inst_imm);
2053 mips_subu (code, ins->dreg, ins->sreg1, mips_at);
2057 mips_load_const (code, mips_at, ins->inst_imm);
2059 mips_subu (code, ins->dreg, mips_at, ins->sreg1);
2062 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
2065 if (mips_is_imm16 (ins->inst_imm)) {
2066 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2068 mips_load_const (code, mips_at, ins->inst_imm);
2069 mips_and (code, ins->dreg, ins->sreg1, mips_at);
2073 guint32 *divisor_is_zero = (guint32 *)(void *)code;
2075 /* Put divide in branch delay slot */
2076 mips_bne (code, ins->sreg2, mips_zero, 0);
2077 mips_div (code, ins->sreg1, ins->sreg2);
2079 /* Divide by zero -- throw exception */
2080 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2082 mips_patch (divisor_is_zero, (guint32)code);
2083 mips_mflo (code, ins->dreg);
2087 guint32 *divisor_is_zero = (guint32 *)(void *)code;
2089 /* Put divide in branch delay slot */
2090 mips_bne (code, ins->sreg2, mips_zero, 0);
2091 mips_divu (code, ins->sreg1, ins->sreg2);
2093 /* Divide by zero -- throw exception */
2094 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2096 mips_patch (divisor_is_zero, (guint32)code);
2097 mips_mflo (code, ins->dreg);
2101 g_assert_not_reached ();
2103 ppc_load (code, ppc_r11, ins->inst_imm);
2104 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
2105 ppc_mfspr (code, ppc_r0, ppc_xer);
2106 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2107 /* FIXME: use OverflowException for 0x80000000/-1 */
2108 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2110 g_assert_not_reached();
2115 guint32 *divisor_is_zero = (guint32 *)(void *)code;
2117 /* Put divide in branch delay slot */
2118 mips_bne (code, ins->sreg2, mips_zero, 0);
2119 mips_div (code, ins->sreg1, ins->sreg2);
2121 /* Divide by zero -- throw exception */
2122 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2124 mips_patch (divisor_is_zero, (guint32)code);
2125 mips_mfhi (code, ins->dreg);
2128 guint32 *divisor_is_m1;
2129 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2130 divisor_is_m1 = (guint32 *)(void *)code;
2131 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2132 ppc_lis (code, ppc_r11, 0x8000);
2133 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
2134 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2135 mips_patch (divisor_is_m1, (guint32)code);
2136 ppc_divwod (code, ppc_r11, ins->sreg1, ins->sreg2);
2137 ppc_mfspr (code, ppc_r0, ppc_xer);
2138 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2139 /* FIXME: use OverflowException for 0x80000000/-1 */
2140 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2141 ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
2142 ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
2147 guint32 *divisor_is_zero = (guint32 *)(void *)code;
2149 /* Put divide in branch delay slot */
2150 mips_bne (code, ins->sreg2, mips_zero, 0);
2151 mips_divu (code, ins->sreg1, ins->sreg2);
2153 /* Divide by zero -- throw exception */
2154 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
2156 mips_patch (divisor_is_zero, (guint32)code);
2157 mips_mfhi (code, ins->dreg);
2161 g_assert_not_reached ();
2163 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2166 if (mips_is_imm16 (ins->inst_imm)) {
2167 mips_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2169 mips_load_const (code, mips_at, ins->inst_imm);
2170 mips_or (code, ins->dreg, ins->sreg1, mips_at);
2174 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2177 /* unsigned 16-bit immediate */
2178 if ((ins->inst_imm & 0xffff) == ins->inst_imm) {
2179 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
2181 mips_load_const (code, mips_at, ins->inst_imm);
2182 mips_xor (code, ins->dreg, ins->sreg1, mips_at);
2186 g_assert (mips_is_imm16 (ins->inst_imm));
2187 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
2190 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
2193 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2196 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
2199 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2202 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
2205 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
2208 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
2211 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
2215 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
2217 mips_mult (code, ins->sreg1, ins->sreg2);
2218 mips_mflo (code, ins->dreg);
2224 mips_load_const (code, mips_at, ins->inst_imm);
2226 mips_mul (code, ins->dreg, ins->sreg1, mips_at);
2228 mips_mult (code, ins->sreg1, mips_at);
2229 mips_mflo (code, ins->dreg);
2236 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
2238 mips_mult (code, ins->sreg1, ins->sreg2);
2239 mips_mflo (code, ins->dreg);
2240 mips_mfhi (code, mips_at);
2244 /* XXX - Throw exception if we overflowed */
2246 case CEE_MUL_OVF_UN:
2248 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
2250 mips_mult (code, ins->sreg1, ins->sreg2);
2251 mips_mflo (code, ins->dreg);
2252 mips_mfhi (code, mips_at);
2256 /* XXX - Throw exception if we overflowed */
2260 mips_load_const (code, ins->dreg, ins->inst_c0);
2263 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2264 mips_load (code, ins->dreg, 0);
2268 mips_mtc1 (code, ins->dreg, ins->sreg1);
2271 mips_mfc1 (code, ins->dreg, ins->sreg1);
2274 mips_dmtc1 (code, ins->dreg, ins->sreg1);
2277 mips_dmfc1 (code, ins->dreg, ins->sreg1);
2284 if (ins->dreg != ins->sreg1)
2285 mips_move (code, ins->dreg, ins->sreg1);
2288 /* Get sreg1 into v1, sreg2 into v0 */
2290 if (ins->sreg1 == mips_v0) {
2291 if (ins->sreg1 != mips_at)
2292 mips_move (code, mips_at, ins->sreg1);
2293 if (ins->sreg2 != mips_v0)
2294 mips_move (code, mips_v0, ins->sreg2);
2295 mips_move (code, mips_v1, mips_at);
2298 if (ins->sreg2 != mips_v0)
2299 mips_move (code, mips_v0, ins->sreg2);
2300 if (ins->sreg1 != mips_v1)
2301 mips_move (code, mips_v1, ins->sreg1);
2305 if (ins->dreg != ins->sreg1) {
2306 mips_fmovd (code, ins->dreg, ins->sreg1);
2310 if (ins->dreg != ins->sreg1) {
2311 mips_fmovd (code, ins->dreg, ins->sreg1);
2315 /* Convert from double to float and leave it there */
2316 mips_cvtsd (code, ins->dreg, ins->sreg1);
2318 case OP_FCONV_TO_R4:
2319 /* Convert from double to float and back again */
2320 mips_cvtsd (code, ins->dreg, ins->sreg1);
2321 mips_cvtds (code, ins->dreg, ins->dreg);
2327 * Keep in sync with mono_arch_emit_epilog
2329 g_assert (!cfg->method->save_lmf);
2330 g_assert_not_reached();
2332 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
2333 if (ppc_is_imm16 (cfg->stack_usage + MIPS_RET_ADDR_OFFSET)) {
2334 ppc_lwz (code, ppc_r0, cfg->stack_usage + MIPS_RET_ADDR_OFFSET, cfg->frame_reg);
2336 ppc_load (code, ppc_r11, cfg->stack_usage + MIPS_RET_ADDR_OFFSET);
2337 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
2339 ppc_mtlr (code, ppc_r0);
2341 if (ppc_is_imm16 (cfg->stack_usage)) {
2342 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
2344 ppc_load (code, ppc_r11, cfg->stack_usage);
2345 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
2347 if (!cfg->method->save_lmf) {
2348 /*for (i = 31; i >= 14; --i) {
2349 if (cfg->used_float_regs & (1 << i)) {
2350 pos += sizeof (double);
2351 ppc_lfd (code, i, -pos, cfg->frame_reg);
2354 for (i = 31; i >= 13; --i) {
2355 if (cfg->used_int_regs & (1 << i)) {
2356 pos += sizeof (gulong);
2357 ppc_lwz (code, i, -pos, cfg->frame_reg);
2361 /* FIXME restore from MonoLMF: though this can't happen yet */
2364 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2365 mips_beq (code, mips_zero, mips_zero, 0);
2370 /* ensure ins->sreg1 is not NULL */
2371 mips_lw (code, mips_zero, ins->sreg1, 0);
2374 if (mips_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2375 mips_addiu (code, mips_at, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2377 mips_load_const (code, mips_at, cfg->sig_cookie + cfg->stack_usage);
2378 mips_add (code, mips_at, cfg->frame_reg, mips_at);
2380 mips_sw (code, mips_at, ins->sreg1, 0);
2391 case OP_VOIDCALL_REG:
2393 case OP_FCALL_MEMBASE:
2394 case OP_LCALL_MEMBASE:
2395 case OP_VCALL_MEMBASE:
2396 case OP_VOIDCALL_MEMBASE:
2397 case OP_CALL_MEMBASE:
2398 switch (ins->opcode) {
2404 call = (MonoCallInst*)ins;
2405 if (ins->flags & MONO_INST_HAS_METHOD)
2406 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2408 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2409 mips_lui (code, mips_t9, mips_zero, 0);
2410 mips_addiu (code, mips_t9, mips_t9, 0);
2415 case OP_VOIDCALL_REG:
2417 mips_move (code, mips_t9, ins->sreg1);
2419 case OP_FCALL_MEMBASE:
2420 case OP_LCALL_MEMBASE:
2421 case OP_VCALL_MEMBASE:
2422 case OP_VOIDCALL_MEMBASE:
2423 case OP_CALL_MEMBASE:
2424 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
2427 mips_jalr (code, mips_t9, mips_ra);
2431 g_assert_not_reached ();
2434 /* keep alignment */
2435 int alloca_waste = MIPS_STACK_PARAM_OFFSET + cfg->param_area + 31;
2436 int area_offset = alloca_waste;
2438 mips_addiu (code, mips_at, ins->sreg1, -alloca_waste);
2440 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
2441 /* use ctr to store the number of words to 0 if needed */
2442 if (ins->flags & MONO_INST_INIT) {
2443 /* we zero 4 bytes at a time */
2444 ppc_addi (code, ppc_r0, ins->sreg1, 3);
2445 ppc_srawi (code, ppc_r0, ppc_r0, 2);
2446 ppc_mtctr (code, ppc_r0);
2448 ppc_lwz (code, ppc_r0, 0, ppc_sp);
2449 ppc_neg (code, ppc_r11, ppc_r11);
2450 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
2452 if (ins->flags & MONO_INST_INIT) {
2453 mips_sw (code, mips_zero, ins->dreg, 0);
2454 mips_addiu (code, mips_at, mips_at, -4);
2455 mips_bne (code, mips_at, mips_zero, -3);
2458 mips_addiu (code, ins->dreg, mips_sp, area_offset);
2462 mips_jr (code, mips_ra);
2466 gpointer addr = mono_arch_get_throw_exception();
2467 mips_move (code, mips_a0, ins->sreg1);
2468 mips_load_const (code, mips_t9, addr);
2469 mips_jr (code, mips_t9);
2471 mips_break (code, 0xfc);
2475 gpointer addr = mono_arch_get_rethrow_exception();
2476 mips_move (code, mips_a0, ins->sreg1);
2477 mips_load_const (code, mips_t9, addr);
2478 mips_jr (code, mips_t9);
2480 mips_break (code, 0xfb);
2483 case OP_START_HANDLER:
2485 * The START_HANDLER instruction marks the beginning of a handler
2486 * block. It is called using a call instruction, so mips_ra contains
2487 * the return address. Since the handler executes in the same stack
2488 * frame as the method itself, we can't use save/restore to save
2489 * the return address. Instead, we save it into a dedicated
2492 if (mips_is_imm16 (ins->inst_left->inst_offset)) {
2493 mips_sw (code, mips_ra, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2495 mips_load_const (code, mips_at, ins->inst_left->inst_offset);
2496 mips_add (code, mips_at, mips_at, ins->inst_left->inst_basereg);
2497 mips_sw (code, mips_ra, mips_at, 0);
2501 if (ins->sreg1 != mips_v0)
2502 mips_move (code, mips_v0, ins->sreg1);
2503 if (mips_is_imm16 (ins->inst_left->inst_offset)) {
2504 mips_lw (code, mips_ra, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2506 mips_load_const (code, mips_at, ins->inst_left->inst_offset);
2507 mips_addu (code, mips_at, mips_at, ins->inst_left->inst_basereg);
2508 mips_lw (code, mips_ra, mips_at, 0);
2510 mips_jr (code, mips_ra);
2513 case CEE_ENDFINALLY:
2514 mips_lw (code, mips_t9, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2515 mips_jalr (code, mips_t9, mips_ra);
2518 case OP_CALL_HANDLER:
2519 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2520 mips_lui (code, mips_t9, mips_zero, 0);
2521 mips_addiu (code, mips_t9, mips_t9, 0);
2522 mips_jalr (code, mips_t9, mips_ra);
2526 ins->inst_c0 = code - cfg->native_code;
2529 if (ins->flags & MONO_INST_BRLABEL) {
2530 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2531 mips_beq (code, mips_zero, mips_zero, 0);
2534 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2535 mips_beq (code, mips_zero, mips_zero, 0);
2540 mips_jr (code, ins->sreg1);
2546 max_len += 4 * GPOINTER_TO_INT (ins->klass);
2547 if (offset > (cfg->code_size - max_len - 16)) {
2548 cfg->code_size += max_len;
2549 cfg->code_size *= 2;
2550 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2551 code = cfg->native_code + offset;
2553 g_assert (ins->sreg1 != -1);
2554 mips_sll (code, mips_at, ins->sreg1, 2);
2555 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
2556 mips_move (code, mips_t8, mips_ra);
2557 mips_bgezal (code, mips_zero, 1); /* bal */
2559 mips_addu (code, mips_t9, mips_ra, mips_at);
2560 /* Table is 16 or 20 bytes from target of bal above */
2561 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
2562 mips_move (code, mips_ra, mips_t8);
2563 mips_lw (code, mips_t9, mips_t9, 20);
2566 mips_lw (code, mips_t9, mips_t9, 16);
2567 mips_jalr (code, mips_t9, mips_t8);
2569 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
2570 mips_emit32 (code, 0xfefefefe);
2575 mips_addiu (code, ins->dreg, mips_zero, 1);
2576 mips_beq (code, mips_at, mips_zero, 2);
2578 mips_move (code, ins->dreg, mips_zero);
2583 mips_addiu (code, ins->dreg, mips_zero, 1);
2584 mips_bltz (code, mips_at, 2);
2586 mips_move (code, ins->dreg, mips_zero);
2591 mips_addiu (code, ins->dreg, mips_zero, 1);
2592 mips_bgtz (code, mips_at, 2);
2594 mips_move (code, ins->dreg, mips_zero);
2596 case OP_COND_EXC_EQ:
2597 case OP_COND_EXC_NE_UN:
2598 case OP_COND_EXC_LT:
2599 case OP_COND_EXC_LT_UN:
2600 case OP_COND_EXC_GT:
2601 case OP_COND_EXC_GT_UN:
2602 case OP_COND_EXC_GE:
2603 case OP_COND_EXC_GE_UN:
2604 case OP_COND_EXC_LE:
2605 case OP_COND_EXC_LE_UN:
2606 #if 0 /* Don't raise conditional exceptions at the moment */
2607 switch (ins->opcode) {
2608 case OP_COND_EXC_EQ:
2609 mips_bne (code, mips_at, mips_zero, 5);
2611 case OP_COND_EXC_NE_UN:
2612 mips_beq (code, mips_at, mips_zero, 5);
2614 case OP_COND_EXC_LT:
2615 case OP_COND_EXC_LT_UN:
2616 mips_bgez (code, mips_at, 5);
2618 case OP_COND_EXC_GT:
2619 case OP_COND_EXC_GT_UN:
2620 mips_blez (code, mips_at, 5);
2622 case OP_COND_EXC_GE:
2623 case OP_COND_EXC_GE_UN:
2624 mips_bltz (code, mips_at, 5);
2626 case OP_COND_EXC_LE:
2627 case OP_COND_EXC_LE_UN:
2628 mips_bgtz (code, mips_at, 5);
2632 mono_add_patch_info (cfg, code - cfg->native_code,
2633 MONO_PATCH_INFO_EXC, ins->inst_p1);
2634 mips_lui (code, mips_t9, mips_zero, 0);
2635 mips_addiu (code, mips_t9, mips_t9, 0);
2636 mips_jalr (code, mips_t9, mips_ra);
2638 cfg->bb_exit->max_offset += 24;
2642 g_assert_not_reached();
2644 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2646 ppc_mfspr (code, ppc_r0, ppc_xer);
2647 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2648 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2651 case OP_COND_EXC_OV:
2652 g_assert_not_reached();
2654 ppc_mcrxr (code, 0);
2655 EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
2658 case OP_COND_EXC_NC:
2659 case OP_COND_EXC_NO:
2660 g_assert_not_reached ();
2672 /* Should be re-mapped to OP_MIPS_B* by *.inssel-mips.brg */
2673 g_assert_not_reached ();
2676 if (ins->flags & MONO_INST_BRLABEL)
2677 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2679 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2680 mips_beq (code, ins->sreg1, ins->sreg2, 0);
2684 if (ins->flags & MONO_INST_BRLABEL)
2685 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2687 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2688 mips_bne (code, ins->sreg1, ins->sreg2, 0);
2692 if (ins->flags & MONO_INST_BRLABEL)
2693 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2695 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2696 mips_bgez (code, ins->sreg1, 0);
2700 if (ins->flags & MONO_INST_BRLABEL)
2701 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2703 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2704 mips_bgtz (code, ins->sreg1, 0);
2708 if (ins->flags & MONO_INST_BRLABEL)
2709 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2711 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2712 mips_blez (code, ins->sreg1, 0);
2716 if (ins->flags & MONO_INST_BRLABEL)
2717 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2719 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2720 mips_bltz (code, ins->sreg1, 0);
2724 /* floating point opcodes */
2726 if (((guint32)ins->inst_p0) & (1 << 15))
2727 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
2729 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
2730 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
2733 if (((guint32)ins->inst_p0) & (1 << 15))
2734 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
2736 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
2737 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
2738 mips_cvtds (code, ins->dreg, ins->dreg);
2740 case OP_STORER8_MEMBASE_REG:
2741 if (mips_is_imm16 (ins->inst_offset)) {
2743 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2745 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset+4);
2746 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset);
2749 mips_load_const (code, mips_at, ins->inst_offset);
2750 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
2751 mips_swc1 (code, ins->sreg1, mips_at, 4);
2752 mips_swc1 (code, ins->sreg1+1, mips_at, 0);
2755 case OP_LOADR8_MEMBASE:
2756 if (mips_is_imm16 (ins->inst_offset)) {
2758 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2760 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset+4);
2761 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset);
2764 mips_load_const (code, mips_at, ins->inst_offset);
2765 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2766 mips_lwc1 (code, ins->dreg, mips_at, 4);
2767 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
2770 case OP_STORER4_MEMBASE_REG:
2771 /* XXX Need to convert ins->sreg1 to single-precision first */
2772 mips_cvtsd (code, mips_ftemp, ins->sreg1);
2773 if (mips_is_imm16 (ins->inst_offset)) {
2774 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
2776 mips_load_const (code, mips_at, ins->inst_offset);
2777 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
2778 mips_swc1 (code, mips_ftemp, mips_at, 0);
2782 if (mips_is_imm16 (ins->inst_offset)) {
2783 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2785 mips_load_const (code, mips_at, ins->inst_offset);
2786 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2787 mips_lwc1 (code, ins->dreg, mips_at, 0);
2790 case OP_LOADR4_MEMBASE:
2791 if (mips_is_imm16 (ins->inst_offset)) {
2792 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2794 mips_load_const (code, mips_at, ins->inst_offset);
2795 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
2796 mips_lwc1 (code, ins->dreg, mips_at, 0);
2798 /* Convert to double precision in place */
2799 mips_cvtds (code, ins->dreg, ins->dreg);
2801 case CEE_CONV_R_UN: {
2802 g_assert_not_reached();
2804 static const guint64 adjust_val = 0x4330000000000000ULL;
2805 ppc_addis (code, ppc_r0, ppc_r0, 0x4330);
2806 ppc_stw (code, ppc_r0, -8, ppc_sp);
2807 ppc_stw (code, ins->sreg1, -4, ppc_sp);
2808 ppc_load (code, ppc_r11, &adjust_val);
2809 ppc_lfd (code, ins->dreg, -8, ppc_sp);
2810 ppc_lfd (code, ppc_f0, 0, ppc_r11);
2811 ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0);
2816 mips_mtc1 (code, mips_ftemp, ins->sreg1);
2817 mips_cvtsw (code, ins->dreg, mips_ftemp);
2818 mips_cvtds (code, ins->dreg, ins->dreg);
2821 mips_mtc1 (code, mips_ftemp, ins->sreg1);
2822 mips_cvtdw (code, ins->dreg, mips_ftemp);
2824 case OP_FCONV_TO_I1:
2825 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2827 case OP_FCONV_TO_U1:
2828 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2830 case OP_FCONV_TO_I2:
2831 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
2833 case OP_FCONV_TO_U2:
2834 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
2836 case OP_FCONV_TO_I4:
2838 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
2840 case OP_FCONV_TO_U4:
2842 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
2844 case OP_FCONV_TO_I8:
2845 case OP_FCONV_TO_U8:
2846 g_assert_not_reached ();
2847 /* Implemented as helper calls */
2849 case OP_LCONV_TO_R_UN:
2850 g_assert_not_reached ();
2851 /* Implemented as helper calls */
2853 case OP_LCONV_TO_OVF_I: {
2855 if (ins->dreg != ins->sreg1)
2856 mips_move (code, ins->dreg, ins->sreg1);
2858 guint32 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
2859 g_assert_not_reached();
2860 // Check if its negative
2861 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
2862 negative_branch = (guint32 *)(void *)code;
2863 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
2864 // Its positive msword == 0
2865 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
2866 msword_positive_branch = (guint32 *)(void *)code;
2867 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
2869 ovf_ex_target = (guint32 *)(void *)code;
2870 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
2872 mips_patch (negative_branch, (guint32)code);
2873 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2874 msword_negative_branch = (guint32 *)(void *)code;
2875 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
2876 mips_patch (msword_negative_branch, (guint32)ovf_ex_target);
2878 mips_patch (msword_positive_branch, (guint32)code);
2879 if (ins->dreg != ins->sreg1)
2880 ppc_mr (code, ins->dreg, ins->sreg1);
2885 mips_fsqrtd (code, ins->dreg, ins->sreg1);
2888 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
2891 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
2894 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
2897 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
2900 mips_fnegd (code, ins->dreg, ins->sreg1);
2904 g_assert_not_reached ();
2907 g_assert_not_reached();
2910 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
2911 mips_addiu (code, ins->dreg, mips_zero, 1);
2912 mips_fbtrue (code, 2);
2914 mips_move (code, ins->dreg, mips_zero);
2917 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
2918 mips_addiu (code, ins->dreg, mips_zero, 1);
2919 mips_fbtrue (code, 2);
2921 mips_move (code, ins->dreg, mips_zero);
2924 /* Less than, or Unordered */
2925 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
2926 mips_addiu (code, ins->dreg, mips_zero, 1);
2927 mips_fbtrue (code, 2);
2929 mips_move (code, ins->dreg, mips_zero);
2932 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
2933 mips_move (code, ins->dreg, mips_zero);
2934 mips_fbtrue (code, 2);
2936 mips_addiu (code, ins->dreg, mips_zero, 1);
2939 /* Greater than, or Unordered */
2940 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
2941 mips_move (code, ins->dreg, mips_zero);
2942 mips_fbtrue (code, 2);
2944 mips_addiu (code, ins->dreg, mips_zero, 1);
2947 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
2949 if (ins->flags & MONO_INST_BRLABEL)
2950 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2952 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2953 mips_fbtrue (code, 0);
2957 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
2959 if (ins->flags & MONO_INST_BRLABEL)
2960 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2962 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2963 mips_fbfalse (code, 0);
2967 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
2969 if (ins->flags & MONO_INST_BRLABEL)
2970 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2972 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2973 mips_fbtrue (code, 0);
2977 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
2979 if (ins->flags & MONO_INST_BRLABEL)
2980 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2982 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2983 mips_fbtrue (code, 0);
2987 mips_fcmpd (code, MIPS_FPU_LE, ins->sreg1, ins->sreg2);
2989 if (ins->flags & MONO_INST_BRLABEL)
2990 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2992 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
2993 mips_fbfalse (code, 0);
2997 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
2999 if (ins->flags & MONO_INST_BRLABEL)
3000 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3002 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3003 mips_fbfalse (code, 0);
3007 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
3009 if (ins->flags & MONO_INST_BRLABEL)
3010 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3012 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3013 mips_fbfalse (code, 0);
3017 mips_fcmpd (code, MIPS_FPU_OLT, ins->sreg1, ins->sreg2);
3019 if (ins->flags & MONO_INST_BRLABEL)
3020 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3022 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3023 mips_fbfalse (code, 0);
3027 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
3029 if (ins->flags & MONO_INST_BRLABEL)
3030 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3032 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3033 mips_fbtrue (code, 0);
3037 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
3039 if (ins->flags & MONO_INST_BRLABEL)
3040 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3042 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
3043 mips_fbtrue (code, 0);
3046 case CEE_CKFINITE: {
3047 g_assert_not_reached();
3049 ppc_stfd (code, ins->sreg1, -8, ppc_sp);
3050 ppc_lwz (code, ppc_r11, -8, ppc_sp);
3051 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 1, 31);
3052 ppc_addis (code, ppc_r11, ppc_r11, -32752);
3053 ppc_rlwinmd (code, ppc_r11, ppc_r11, 1, 31, 31);
3054 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3059 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3060 g_assert_not_reached ();
3063 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3064 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3065 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3066 g_assert_not_reached ();
3072 last_offset = offset;
3077 cfg->code_len = code - cfg->native_code;
3081 mono_arch_register_lowlevel_calls (void)
3086 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3088 MonoJumpInfo *patch_info;
3090 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3091 unsigned char *ip = patch_info->ip.i + code;
3092 const unsigned char *target;
3094 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3096 switch (patch_info->type) {
3097 case MONO_PATCH_INFO_IP:
3098 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
3100 case MONO_PATCH_INFO_SWITCH: {
3101 /* jt is the inlined jump table, 7 or 9 instructions after ip
3102 * In the normal case we store the absolute addresses.
3103 * otherwise the displacements.
3106 gpointer *table = (gpointer *)patch_info->data.table->table;
3107 gpointer *jt = ((gpointer*)(void *)ip) + 7;
3108 if (1 /* || !(cfg->->flags & MONO_CFG_HAS_CALLS) */)
3110 for (i = 0; i < patch_info->data.table->table_size; i++) {
3111 jt [i] = code + (int)table [i];
3115 case MONO_PATCH_INFO_METHODCONST:
3116 case MONO_PATCH_INFO_CLASS:
3117 case MONO_PATCH_INFO_IMAGE:
3118 case MONO_PATCH_INFO_FIELD:
3119 case MONO_PATCH_INFO_VTABLE:
3120 case MONO_PATCH_INFO_IID:
3121 case MONO_PATCH_INFO_SFLDA:
3122 case MONO_PATCH_INFO_LDSTR:
3123 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3124 case MONO_PATCH_INFO_LDTOKEN:
3125 case MONO_PATCH_INFO_R4:
3126 case MONO_PATCH_INFO_R8:
3127 /* from OP_AOTCONST : lui + addiu */
3128 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
3130 case MONO_PATCH_INFO_EXC_NAME:
3131 g_assert_not_reached ();
3132 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
3134 case MONO_PATCH_INFO_NONE:
3135 case MONO_PATCH_INFO_BB_OVF:
3136 case MONO_PATCH_INFO_EXC_OVF:
3137 /* everything is dealt with at epilog output time */
3142 mips_patch ((guint32 *)(void *)ip, (guint32)target);
3147 * Allow tracing to work with this interface (with an optional argument)
3149 * This code is expected to be inserted just after the 'real' prolog code,
3150 * and before the first basic block. We need to allocate a 2nd, temporary
3151 * stack frame so that we can preserve f12-f15 as well as a0-a3.
3155 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
3158 int fp_stack_offset = 0;
3164 mips_sw (code, mips_a0, mips_sp, cfg->stack_offset + 0);
3165 mips_sw (code, mips_a1, mips_sp, cfg->stack_offset + 4);
3166 mips_sw (code, mips_a2, mips_sp, cfg->stack_offset + 8);
3167 mips_sw (code, mips_a3, mips_sp, cfg->stack_offset + 12);
3170 fp_stack_offset = MIPS_STACK_PARAM_OFFSET;
3171 mips_addiu (code, mips_sp, mips_sp, -64);
3172 mips_swc1 (code, mips_f12, mips_sp, fp_stack_offset + 16);
3173 mips_swc1 (code, mips_f13, mips_sp, fp_stack_offset + 20);
3174 mips_swc1 (code, mips_f14, mips_sp, fp_stack_offset + 24);
3175 mips_swc1 (code, mips_f15, mips_sp, fp_stack_offset + 28);
3177 mips_fmovs (code, mips_f22, mips_f12);
3178 mips_fmovs (code, mips_f23, mips_f13);
3179 mips_fmovs (code, mips_f24, mips_f14);
3180 mips_fmovs (code, mips_f25, mips_f15);
3183 mips_load_const (code, mips_a0, cfg->method);
3184 mips_addiu (code, mips_a1, mips_sp, cfg->stack_offset + fp_stack_offset);
3185 mips_load_const (code, mips_t9, func);
3186 mips_jalr (code, mips_t9, mips_ra);
3189 mips_lw (code, mips_a0, mips_sp, cfg->stack_offset + 0);
3190 mips_lw (code, mips_a1, mips_sp, cfg->stack_offset + 4);
3191 mips_lw (code, mips_a2, mips_sp, cfg->stack_offset + 8);
3192 mips_lw (code, mips_a3, mips_sp, cfg->stack_offset + 12);
3195 mips_lwc1 (code, mips_f12, mips_sp, fp_stack_offset + 16);
3196 mips_lwc1 (code, mips_f13, mips_sp, fp_stack_offset + 20);
3197 mips_lwc1 (code, mips_f14, mips_sp, fp_stack_offset + 24);
3198 mips_lwc1 (code, mips_f15, mips_sp, fp_stack_offset + 28);
3199 mips_addiu (code, mips_sp, mips_sp, 64);
3201 mips_fmovs (code, mips_f12, mips_f22);
3202 mips_fmovs (code, mips_f13, mips_f23);
3203 mips_fmovs (code, mips_f14, mips_f24);
3204 mips_fmovs (code, mips_f15, mips_f25);
3214 * Stack frame layout:
3216 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET + cfg->param_area
3217 * param area incoming
3218 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
3220 * ------------------- sp + cfg->stack_usage
3222 * ------------------- sp + cfg->stack_usage-4
3224 * ------------------- sp +
3225 * MonoLMF structure optional
3226 * ------------------- sp + cfg->arch.lmf_offset
3227 * saved registers s0-s8
3228 * ------------------- sp + cfg->arch.iregs_offset
3230 * ------------------- sp + cfg->param_area
3231 * param area outgoing
3232 * ------------------- sp + 16
3234 * ------------------- sp
3238 mono_arch_emit_prolog (MonoCompile *cfg)
3240 MonoMethod *method = cfg->method;
3241 MonoMethodSignature *sig;
3243 int alloc_size, pos, i;
3247 guint32 iregs_to_save = 0;
3248 guint32 fregs_to_save = 0;
3250 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3254 cfg->flags |= MONO_CFG_HAS_CALLS;
3256 sig = mono_method_signature (method);
3257 cfg->code_size = 256 + sig->param_count * 20;
3258 code = cfg->native_code = g_malloc (cfg->code_size);
3260 alloc_size = cfg->stack_offset;
3261 g_assert ((alloc_size & (MIPS_STACK_ALIGNMENT-1)) == 0);
3263 /* re-align cfg->stack_offset if needed (due to var spilling in mini-codegen.c) */
3264 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
3266 /* stack_offset should not be changed here. */
3267 alloc_size = cfg->stack_offset;
3268 cfg->stack_usage = alloc_size;
3270 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
3273 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
3275 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
3276 fregs_to_save |= (fregs_to_save << 1);
3281 if (mips_is_imm16 (-alloc_size)) {
3282 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
3284 mips_load_const (code, mips_at, -alloc_size);
3285 mips_addu (code, mips_sp, mips_sp, mips_at);
3289 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
3290 mips_sw (code, mips_ra, mips_sp, alloc_size + MIPS_RET_ADDR_OFFSET);
3292 /* Do instrumentation before assigning regvars to registers. Because they may be assigned
3293 * to the t* registers, which would be clobbered by the instrumentation calls.
3296 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3298 /* XXX - optimize this later to not save all regs if LMF constructed */
3300 if (iregs_to_save) {
3301 /* save used registers in own stack frame (at pos) */
3302 pos = cfg->arch.iregs_offset;
3303 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
3304 if (iregs_to_save & (1 << i)) {
3305 g_assert (pos < cfg->stack_usage - 4);
3306 mips_sw (code, i, mips_sp, pos);
3307 pos += sizeof (gulong);
3313 /* Save float registers */
3314 if (fregs_to_save) {
3315 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
3316 if (fregs_to_save & (1 << i)) {
3317 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
3318 mips_swc1 (code, i, mips_sp, pos);
3319 pos += sizeof (gulong);
3325 if (method->save_lmf) {
3327 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3328 for (i = 14; i < 32; i++) {
3329 ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3334 if (cfg->frame_reg != mips_sp)
3335 mips_move (code, cfg->frame_reg, mips_sp);
3337 /* load arguments allocated to register from the stack */
3340 cinfo = calculate_sizes (sig, sig->pinvoke);
3342 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3343 ArgInfo *ainfo = &cinfo->ret;
3345 if (inst->opcode == OP_REGVAR)
3346 mips_move (code, inst->dreg, ainfo->reg);
3347 else if (mips_is_imm16 (inst->inst_offset)) {
3348 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3350 mips_load_const (code, mips_at, inst->inst_offset);
3351 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
3352 mips_sw (code, ainfo->reg, mips_at, 0);
3355 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3356 ArgInfo *ainfo = cinfo->args + i;
3357 inst = cfg->varinfo [pos];
3359 if (cfg->verbose_level > 2)
3360 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3361 if (inst->opcode == OP_REGVAR) {
3362 /* Argument ends up in a register */
3363 if (ainfo->regtype == RegTypeGeneral)
3364 mips_move (code, inst->dreg, ainfo->reg);
3365 else if (ainfo->regtype == RegTypeFP) {
3366 g_assert_not_reached();
3368 ppc_fmr (code, inst->dreg, ainfo->reg);
3371 else if (ainfo->regtype == RegTypeBase) {
3372 mips_lw (code, inst->dreg, mips_sp, cfg->stack_usage + ainfo->offset);
3374 g_assert_not_reached ();
3376 if (cfg->verbose_level > 2)
3377 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3379 /* Argument ends up on the stack */
3380 if (ainfo->regtype == RegTypeGeneral) {
3381 /* Incoming parameters should be above this frame */
3382 g_assert (inst->inst_offset >= alloc_size);
3383 g_assert (mips_is_imm16 (inst->inst_offset));
3384 switch (ainfo->size) {
3386 mips_sb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3389 mips_sh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3393 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3396 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3397 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
3400 g_assert_not_reached ();
3403 } else if (ainfo->regtype == RegTypeBase) {
3405 * Argument comes in on the stack, and ends up on the stack
3406 * 1 and 2 byte args are passed as 32-bit quantities, but used as
3407 * 8 and 16 bit quantities. Shorten them in place.
3409 g_assert (mips_is_imm16 (inst->inst_offset));
3410 switch (ainfo->size) {
3412 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
3413 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
3416 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
3417 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
3424 g_assert_not_reached ();
3426 } else if (ainfo->regtype == RegTypeFP) {
3427 g_assert (mips_is_imm16 (inst->inst_offset));
3428 if (ainfo->size == 8) {
3430 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3432 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
3433 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
3436 else if (ainfo->size == 4)
3437 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3439 g_assert_not_reached ();
3440 } else if (ainfo->regtype == RegTypeStructByVal) {
3442 int doffset = inst->inst_offset;
3444 g_assert (mips_is_imm16 (inst->inst_offset));
3445 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3446 /* Push the argument registers into their stack slots */
3447 for (i = 0; i < ainfo->size; ++i) {
3448 mips_sw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3449 doffset += sizeof (gpointer);
3451 } else if (ainfo->regtype == RegTypeStructByAddr) {
3452 g_assert (mips_is_imm16 (inst->inst_offset));
3453 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3454 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
3456 g_assert_not_reached ();
3461 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
3462 g_assert_not_reached();
3464 ppc_load (code, ppc_r3, cfg->domain);
3465 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
3471 if (method->save_lmf) {
3472 if (lmf_pthread_key != -1) {
3473 g_assert_not_reached();
3475 emit_tls_access (code, mips_temp, lmf_pthread_key);
3477 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
3478 mips_addiu (code, mips_a0, mips_temp, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3480 mips_load_const (code, mips_t9, (gpointer)mono_get_lmf_addr);
3481 mips_jalr (code, mips_t9, mips_ra);
3484 /* we build the MonoLMF structure on the stack - see mini-mips.h
3485 * The pointer to the struct is put in mips_t2 (new_lmf).
3486 * (t2 = r11, v0 = r3 in PPC)
3489 /* lmf_offset is the offset of the LMF from our stack pointer.
3490 * The callee-saved registers are already in the MonoLMF structure
3492 mips_addiu (code, mips_t2, mips_sp, cfg->arch.lmf_offset);
3493 mips_sw (code, mips_a0, mips_t2, G_STRUCT_OFFSET(MonoLMF, iregs[mips_a0]));
3494 mips_sw (code, mips_a1, mips_t2, G_STRUCT_OFFSET(MonoLMF, iregs[mips_a1]));
3495 mips_sw (code, mips_a2, mips_t2, G_STRUCT_OFFSET(MonoLMF, iregs[mips_a2]));
3496 mips_sw (code, mips_a3, mips_t2, G_STRUCT_OFFSET(MonoLMF, iregs[mips_a3]));
3497 mips_sw (code, mips_s0, mips_t2, G_STRUCT_OFFSET(MonoLMF, iregs[mips_s0]));
3498 mips_sw (code, mips_s1, mips_t2, G_STRUCT_OFFSET(MonoLMF, iregs[mips_s1]));
3499 mips_sw (code, mips_s2, mips_t2, G_STRUCT_OFFSET(MonoLMF, iregs[mips_s2]));
3500 mips_sw (code, mips_s3, mips_t2, G_STRUCT_OFFSET(MonoLMF, iregs[mips_s3]));
3501 mips_sw (code, mips_s4, mips_t2, G_STRUCT_OFFSET(MonoLMF, iregs[mips_s4]));
3502 mips_sw (code, mips_s5, mips_t2, G_STRUCT_OFFSET(MonoLMF, iregs[mips_s5]));
3503 mips_sw (code, mips_s6, mips_t2, G_STRUCT_OFFSET(MonoLMF, iregs[mips_s6]));
3504 mips_sw (code, mips_s7, mips_t2, G_STRUCT_OFFSET(MonoLMF, iregs[mips_s7]));
3505 mips_sw (code, mips_fp, mips_t2, G_STRUCT_OFFSET(MonoLMF, iregs[mips_fp]));
3507 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
3508 mips_sw (code, mips_v0, mips_t2, G_STRUCT_OFFSET(MonoLMF, lmf_addr));
3509 /* new_lmf->previous_lmf = *lmf_addr */
3510 mips_lw (code, mips_at, mips_v0, 0);
3511 mips_sw (code, mips_at, mips_t2, G_STRUCT_OFFSET(MonoLMF, previous_lmf));
3512 /* *(lmf_addr) = t2 */
3513 mips_sw (code, mips_t2, mips_v0, 0);
3515 /* save method info */
3516 mips_load_const (code, mips_at, method);
3517 mips_sw (code, mips_at, mips_t2, G_STRUCT_OFFSET(MonoLMF, method));
3518 mips_sw (code, mips_sp, mips_t2, G_STRUCT_OFFSET(MonoLMF, ebp));
3519 /* save the current IP */
3520 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3521 mips_load_const (code, mips_at, 0x01010101);
3522 mips_sw (code, mips_at, mips_t2, G_STRUCT_OFFSET(MonoLMF, eip));
3526 cfg->code_len = code - cfg->native_code;
3527 g_assert (cfg->code_len < cfg->code_size);
3542 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
3545 int save_mode = SAVE_NONE;
3547 MonoMethod *method = cfg->method;
3548 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
3549 int save_offset = MIPS_STACK_PARAM_OFFSET + cfg->param_area;
3554 offset = code - cfg->native_code;
3555 /* we need about 16 instructions */
3556 if (offset > (cfg->code_size - 16 * 4)) {
3557 cfg->code_size *= 2;
3558 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3559 code = cfg->native_code + offset;
3565 case MONO_TYPE_VOID:
3566 /* special case string .ctor icall */
3567 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
3568 save_mode = SAVE_ONE;
3570 save_mode = SAVE_NONE;
3574 save_mode = SAVE_TWO;
3578 save_mode = SAVE_FP;
3580 case MONO_TYPE_VALUETYPE:
3581 save_mode = SAVE_STRUCT;
3584 save_mode = SAVE_ONE;
3588 switch (save_mode) {
3590 mips_sw (code, mips_v0, cfg->frame_reg, save_offset);
3591 mips_sw (code, mips_v1, cfg->frame_reg, save_offset + 4);
3592 if (enable_arguments) {
3593 mips_move (code, mips_a1, mips_v0);
3594 mips_move (code, mips_a2, mips_v1);
3598 mips_sw (code, mips_v0, cfg->frame_reg, save_offset);
3599 if (enable_arguments) {
3600 mips_move (code, mips_a1, mips_v0);
3604 g_assert_not_reached();
3606 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
3607 if (enable_arguments) {
3608 /* FIXME: what reg? */
3609 ppc_fmr (code, ppc_f3, ppc_f1);
3610 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
3611 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
3621 mips_load_const (code, mips_a0, cfg->method);
3622 mips_load_const (code, mips_t9, func);
3623 mips_jalr (code, mips_t9, mips_ra);
3626 switch (save_mode) {
3628 mips_lw (code, mips_v0, cfg->frame_reg, save_offset);
3629 mips_lw (code, mips_v1, cfg->frame_reg, save_offset + 4);
3632 mips_lw (code, mips_v0, cfg->frame_reg, save_offset);
3635 g_assert_not_reached();
3637 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
3652 mono_arch_emit_epilog (MonoCompile *cfg)
3654 MonoMethod *method = cfg->method;
3656 int max_epilog_size = 16 + 20*4;
3658 guint32 iregs_to_restore;
3659 guint32 fregs_to_restore;
3662 if (cfg->method->save_lmf)
3663 max_epilog_size += 128;
3666 if (mono_jit_trace_calls != NULL)
3667 max_epilog_size += 50;
3669 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3670 max_epilog_size += 50;
3672 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3673 cfg->code_size *= 2;
3674 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3675 mono_jit_stats.code_reallocs++;
3679 * Keep in sync with CEE_JMP
3681 code = cfg->native_code + cfg->code_len;
3683 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3684 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3686 pos = cfg->arch.iregs_offset;
3687 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
3688 if (iregs_to_restore) {
3689 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
3690 if (iregs_to_restore & (1 << i)) {
3691 mips_lw (code, i, mips_sp, pos);
3692 pos += sizeof (gulong);
3699 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
3701 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
3702 fregs_to_restore |= (fregs_to_restore << 1);
3704 if (fregs_to_restore) {
3705 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
3706 if (fregs_to_restore & (1 << i)) {
3707 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
3708 mips_lwc1 (code, i, mips_sp, pos);
3709 pos += sizeof (gulong);
3715 /* Unlink the LMF if necessary */
3716 if (method->save_lmf) {
3717 int lmf_offset = cfg->arch.lmf_offset;
3719 /* t0 = current_lmf->previous_lmf */
3720 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
3722 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
3723 /* (*lmf_addr) = previous_lmf */
3724 mips_sw (code, mips_temp, mips_t1, 0);
3728 /* Restore the fp */
3729 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
3731 /* Correct the stack pointer, and return */
3732 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
3733 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage + MIPS_RET_ADDR_OFFSET);
3734 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage);
3735 mips_jr (code, mips_ra);
3738 cfg->code_len = code - cfg->native_code;
3740 g_assert (cfg->code_len < cfg->code_size);
3744 /* remove once throw_exception_by_name is eliminated */
3746 exception_id_by_name (const char *name)
3748 if (strcmp (name, "IndexOutOfRangeException") == 0)
3749 return MONO_EXC_INDEX_OUT_OF_RANGE;
3750 if (strcmp (name, "OverflowException") == 0)
3751 return MONO_EXC_OVERFLOW;
3752 if (strcmp (name, "ArithmeticException") == 0)
3753 return MONO_EXC_ARITHMETIC;
3754 if (strcmp (name, "DivideByZeroException") == 0)
3755 return MONO_EXC_DIVIDE_BY_ZERO;
3756 if (strcmp (name, "InvalidCastException") == 0)
3757 return MONO_EXC_INVALID_CAST;
3758 if (strcmp (name, "NullReferenceException") == 0)
3759 return MONO_EXC_NULL_REF;
3760 if (strcmp (name, "ArrayTypeMismatchException") == 0)
3761 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3762 g_error ("Unknown intrinsic exception %s\n", name);
3767 mono_arch_emit_exceptions (MonoCompile *cfg)
3769 MonoJumpInfo *patch_info;
3772 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3773 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3774 int max_epilog_size = 50;
3776 /* count the number of exception infos */
3779 * make sure we have enough space for exceptions
3780 * 24 is the simulated call to throw_exception_by_name
3782 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3783 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3784 i = exception_id_by_name (patch_info->data.target);
3785 g_assert (i < MONO_EXC_INTRINS_NUM);
3786 if (!exc_throw_found [i]) {
3787 max_epilog_size += 12;
3788 exc_throw_found [i] = TRUE;
3790 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
3791 max_epilog_size += 12;
3793 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
3794 MonoOvfJump *ovfj = (MonoOvfJump *)patch_info->data.target;
3795 i = exception_id_by_name (ovfj->data.exception);
3796 g_assert (i < MONO_EXC_INTRINS_NUM);
3797 if (!exc_throw_found [i]) {
3798 max_epilog_size += 12;
3799 exc_throw_found [i] = TRUE;
3801 max_epilog_size += 8;
3806 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3807 cfg->code_size *= 2;
3808 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3809 mono_jit_stats.code_reallocs++;
3812 code = cfg->native_code + cfg->code_len;
3814 /* add code to raise exceptions */
3815 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3816 switch (patch_info->type) {
3818 case MONO_PATCH_INFO_BB_OVF: {
3819 MonoOvfJump *ovfj = (MonoOvfJump *)patch_info->data.target;
3820 guint32 *ip = (guint32 *)(void *)(patch_info->ip.i + cfg->native_code);
3821 /* patch the initial jump */
3822 mips_patch (ip, (guint32)code);
3823 mips_bne (code, ovfj->b0_cond, ovfj->b1_cond, 2);
3825 mips_lui (code, mips_at, mips_zero, 0);
3826 mips_addiu (code, mips_at, mips_at, 0);
3827 mips_jr (code, mips_at);
3828 mips_patch ((guint32 *)(void *)(code - 4), (guint32)(ip + 1)); /* jump back after the initial branch */
3830 /* jump back to the true target */
3831 mips_jump (code, 0);
3832 ip = (guint32 *)(void *)(ovfj->data.bb->native_offset + cfg->native_code);
3833 mips_patch ((guint32 *)(void *)(code - 4), (guint32)ip);
3837 case MONO_PATCH_INFO_EXC_OVF: {
3838 MonoOvfJump *ovfj = (MonoOvfJump *)patch_info->data.target;
3839 MonoJumpInfo *newji;
3840 guint32 *ip = (guint32 *)(void *)(patch_info->ip.i + cfg->native_code);
3841 unsigned char *bcl = code;
3843 /* patch the initial jump: we arrived here with a call */
3844 mips_patch (ip, (guint32)code);
3845 mips_bne (code, ovfj->b0_cond, ovfj->b1_cond, 0);
3847 mips_jump (code, 0);
3848 /* jump back after the initial branch */
3849 mips_patch ((guint32 *)(void *)(code - 4), (guint32)(ip + 1));
3851 /* patch the conditional jump to the right handler */
3852 /* make it processed next */
3853 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
3854 newji->type = MONO_PATCH_INFO_EXC;
3855 newji->ip.i = bcl - cfg->native_code;
3856 newji->data.target = ovfj->data.exception;
3857 newji->next = patch_info->next;
3858 patch_info->next = newji;
3862 case MONO_PATCH_INFO_EXC: {
3863 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
3865 i = exception_id_by_name (patch_info->data.target);
3866 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
3867 if (!exc_throw_pos [i]) {
3870 exc_throw_pos [i] = code;
3871 //g_print ("exc: writing stub at %p\n", code);
3872 mips_load_const (code, mips_a0, patch_info->data.target);
3873 addr = (guint32) mono_arch_get_throw_exception_by_name ();
3874 mips_load_const (code, mips_t9, addr);
3875 mips_jr (code, mips_t9);
3878 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
3880 /* Turn into a Relative patch, pointing at code stub */
3881 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
3882 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
3891 cfg->code_len = code - cfg->native_code;
3893 g_assert (cfg->code_len < cfg->code_size);
3898 * Thread local storage support
3901 setup_tls_access (void)
3904 //guint32 *ins, *code;
3906 if (tls_mode == TLS_MODE_FAILED)
3909 if (g_getenv ("MONO_NO_TLS")) {
3910 tls_mode = TLS_MODE_FAILED;
3914 if (tls_mode == TLS_MODE_DETECT) {
3916 tls_mode = TLS_MODE_FAILED;
3920 ins = (guint32*)pthread_getspecific;
3921 /* uncond branch to the real method */
3922 if ((*ins >> 26) == 18) {
3924 val = (*ins & ~3) << 6;
3928 ins = (guint32*)val;
3930 ins = (guint32*) ((char*)ins + val);
3933 code = &cmplwi_1023;
3934 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
3936 ppc_li (code, ppc_r4, 0x48);
3939 if (*ins == cmplwi_1023) {
3940 int found_lwz_284 = 0;
3941 for (ptk = 0; ptk < 20; ++ptk) {
3943 if (!*ins || *ins == blr_ins)
3945 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
3950 if (!found_lwz_284) {
3951 tls_mode = TLS_MODE_FAILED;
3954 tls_mode = TLS_MODE_LTHREADS;
3955 } else if (*ins == li_0x48) {
3957 /* uncond branch to the real method */
3958 if ((*ins >> 26) == 18) {
3960 val = (*ins & ~3) << 6;
3964 ins = (guint32*)val;
3966 ins = (guint32*) ((char*)ins + val);
3969 ppc_li (code, ppc_r0, 0x7FF2);
3970 if (ins [1] == val) {
3971 /* Darwin on G4, implement */
3972 tls_mode = TLS_MODE_FAILED;
3976 ppc_mfspr (code, ppc_r3, 104);
3977 if (ins [1] != val) {
3978 tls_mode = TLS_MODE_FAILED;
3981 tls_mode = TLS_MODE_DARWIN_G5;
3984 tls_mode = TLS_MODE_FAILED;
3988 tls_mode = TLS_MODE_FAILED;
3993 if (monodomain_key == -1) {
3994 ptk = mono_domain_get_tls_key ();
3996 ptk = mono_pthread_key_for_tls (ptk);
3998 monodomain_key = ptk;
4002 if (lmf_pthread_key == -1) {
4003 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
4005 /*g_print ("MonoLMF at: %d\n", ptk);*/
4006 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
4007 init_tls_failed = 1;
4010 lmf_pthread_key = ptk;
4013 if (monothread_key == -1) {
4014 ptk = mono_thread_get_tls_key ();
4016 ptk = mono_pthread_key_for_tls (ptk);
4018 monothread_key = ptk;
4019 /*g_print ("thread inited: %d\n", ptk);*/
4022 /*g_print ("thread not inited yet %d\n", ptk);*/
4028 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4030 setup_tls_access ();
4034 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4039 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4041 int this_dreg = mips_a0;
4044 this_dreg = mips_a1;
4046 /* add the this argument */
4047 if (this_reg != -1) {
4049 MONO_INST_NEW (cfg, this, OP_SETREG);
4050 this->type = this_type;
4051 this->sreg1 = this_reg;
4052 this->dreg = mono_regstate_next_int (cfg->rs);
4053 mono_bblock_add_inst (cfg->cbb, this);
4054 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
4059 MONO_INST_NEW (cfg, vtarg, OP_SETREG);
4060 vtarg->type = STACK_MP;
4061 vtarg->sreg1 = vt_reg;
4062 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4063 mono_bblock_add_inst (cfg->cbb, vtarg);
4064 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
4069 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4071 MonoInst *ins = NULL;
4073 if (cmethod->klass == mono_defaults.thread_class &&
4074 strcmp (cmethod->name, "MemoryBarrier") == 0) {
4075 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4077 /*if (cmethod->klass == mono_defaults.math_class) {
4078 if (strcmp (cmethod->name, "Sqrt") == 0) {
4079 MONO_INST_NEW (cfg, ins, OP_SQRT);
4080 ins->inst_i0 = args [0];
4087 mono_arch_print_tree (MonoInst *tree, int arity)
4092 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4096 setup_tls_access ();
4097 if (monodomain_key == -1)
4100 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4101 ins->inst_offset = monodomain_key;
4106 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4110 setup_tls_access ();
4111 if (monothread_key == -1)
4114 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4115 ins->inst_offset = monothread_key;