Added/Updated .gitignore files
[mono.git] / mono / mini / mini-mips.c
blobe2487779fde15282ddbd1add8a6357b340475a41
1 /*
2 * mini-mips.c: MIPS backend for the Mono code generator
4 * Authors:
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)
11 * (C) 2006 Broadcom
12 * (C) 2003 Ximian, Inc.
14 #include "mini.h"
15 #include <string.h>
16 #include <asm/cachectl.h>
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/debug-helpers.h>
21 #include <mono/arch/mips/mips-codegen.h>
23 #include "mini-mips.h"
24 #include "cpu-mips.h"
25 #include "trace.h"
26 #include "ir-emit.h"
28 #define SAVE_FP_REGS 0
29 #define SAVE_ALL_REGS 0
30 #define EXTRA_STACK_SPACE 0 /* suppresses some s-reg corruption issues */
31 #define LONG_BRANCH 1 /* needed for yyparse in mcs */
33 #define SAVE_LMF 1
34 #define ALWAYS_USE_FP 1
35 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
37 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
38 #define USE_MUL 1 /* use mul instead of mult/mflo for multiply */
40 enum {
41 TLS_MODE_DETECT,
42 TLS_MODE_FAILED,
43 TLS_MODE_LTHREADS,
44 TLS_MODE_NPTL
47 /* This mutex protects architecture specific caches */
48 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
49 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
50 static CRITICAL_SECTION mini_arch_mutex;
52 int mono_exc_esp_offset = 0;
53 static int tls_mode = TLS_MODE_DETECT;
54 static int lmf_pthread_key = -1;
55 static int monothread_key = -1;
56 static int monodomain_key = -1;
58 #undef DEBUG
59 #define DEBUG(a) if (cfg->verbose_level > 1) a
60 #undef DEBUG
61 #define DEBUG(a) a
62 #undef DEBUG
63 #define DEBUG(a)
65 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
66 do { \
67 code = mips_emit_exc_by_name (code, exc_name); \
68 cfg->bb_exit->max_offset += 16; \
69 } while (0)
72 #define emit_linuxthreads_tls(code,dreg,key) do {\
73 int off1, off2; \
74 off1 = offsets_from_pthread_key ((key), &off2); \
75 g_assert_not_reached (); \
76 ppc_lwz ((code), (dreg), off1, ppc_r2); \
77 ppc_lwz ((code), (dreg), off2, (dreg)); \
78 } while (0);
81 #define emit_tls_access(code,dreg,key) do { \
82 switch (tls_mode) { \
83 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
84 default: g_assert_not_reached (); \
85 } \
86 } while (0)
88 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
89 MonoInst *inst; \
90 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
91 inst->type = STACK_R8; \
92 inst->dreg = (dr); \
93 inst->inst_p0 = (void*)(addr); \
94 mono_bblock_add_inst (cfg->cbb, inst); \
95 } while (0)
97 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
98 || ((ins)->opcode == OP_ICOMPARE) \
99 || ((ins)->opcode == OP_LCOMPARE)))
100 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
101 || ((ins)->opcode == OP_ICOMPARE_IMM) \
102 || ((ins)->opcode == OP_LCOMPARE_IMM)))
104 #define INS_REWRITE(ins, op, _s1, _s2) do { \
105 int s1 = _s1; \
106 int s2 = _s2; \
107 ins->opcode = (op); \
108 ins->sreg1 = (s1); \
109 ins->sreg2 = (s2); \
110 } while (0);
112 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
113 int s1 = _s1; \
114 ins->opcode = (op); \
115 ins->sreg1 = (s1); \
116 ins->inst_imm = (_imm); \
117 } while (0);
120 typedef struct InstList InstList;
122 struct InstList {
123 InstList *prev;
124 InstList *next;
125 MonoInst *data;
128 enum {
129 RegTypeGeneral,
130 RegTypeBase,
131 RegTypeFP,
132 RegTypeStructByVal,
133 RegTypeStructByAddr
136 typedef struct {
137 gint32 offset;
138 guint16 vtsize; /* in param area */
139 guint8 reg;
140 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
141 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
142 } ArgInfo;
144 typedef struct {
145 int nargs;
146 int gr;
147 int fr;
148 gboolean gr_passed;
149 gboolean on_stack;
150 int stack_size;
151 guint32 stack_usage;
152 guint32 struct_ret;
153 ArgInfo ret;
154 ArgInfo sig_cookie;
155 ArgInfo args [1];
156 } CallInfo;
158 void patch_lui_addiu(guint32 *ip, guint32 val);
159 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
160 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
161 void mips_adjust_stackframe(MonoCompile *cfg);
162 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
163 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
166 void
167 mono_arch_flush_icache (guint8 *code, gint size)
169 /* Linux/MIPS specific */
170 cacheflush (code, size, BCACHE);
173 void
174 mono_arch_flush_register_windows (void)
178 gboolean
179 mono_arch_is_inst_imm (gint64 imm)
181 return TRUE;
184 static guint8 *
185 mips_emit_exc_by_name(guint8 *code, const char *name)
187 guint32 addr;
188 MonoClass *exc_class;
190 exc_class = mono_class_from_name (mono_defaults.corlib, "System", name);
191 g_assert (exc_class);
193 mips_load_const (code, mips_a0, exc_class->type_token);
194 addr = (guint32) mono_arch_get_throw_corlib_exception ();
195 mips_load_const (code, mips_t9, addr);
196 mips_jalr (code, mips_t9, mips_ra);
197 mips_nop (code);
199 return code;
203 guint8 *
204 mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
206 if (mips_is_imm16 (v))
207 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
208 else {
209 #ifdef SIZEOF_REGISTER == 8
210 if (v != (long) v) {
211 /* v is not a sign-extended 32-bit value */
212 mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
213 mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
214 mips_dsll (code, dreg, dreg, 16);
215 mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
216 mips_dsll (code, dreg, dreg, 16);
217 mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
218 return code;
220 #endif
221 if (((guint32)v) & (1 << 15)) {
222 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
224 else {
225 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
227 if (((guint32)v) & 0xffff)
228 mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
230 return code;
233 guint8 *
234 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
236 #if LONG_BRANCH
237 int br_offset = 5;
238 #endif
240 g_assert (ins);
241 #if LONG_BRANCH
242 /* Invert test and emit branch around jump */
243 switch (op) {
244 case OP_MIPS_BEQ:
245 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
246 mips_nop (code);
247 break;
248 case OP_MIPS_BNE:
249 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
250 mips_nop (code);
251 break;
252 case OP_MIPS_BGEZ:
253 mips_bltz (code, ins->sreg1, br_offset);
254 mips_nop (code);
255 break;
256 case OP_MIPS_BGTZ:
257 mips_blez (code, ins->sreg1, br_offset);
258 mips_nop (code);
259 break;
260 case OP_MIPS_BLEZ:
261 mips_bgtz (code, ins->sreg1, br_offset);
262 mips_nop (code);
263 break;
264 case OP_MIPS_BLTZ:
265 mips_bgez (code, ins->sreg1, br_offset);
266 mips_nop (code);
267 break;
268 default:
269 g_assert_not_reached ();
271 mono_add_patch_info (cfg, code - cfg->native_code,
272 MONO_PATCH_INFO_BB, ins->inst_true_bb);
273 mips_lui (code, mips_at, mips_zero, 0);
274 mips_addiu (code, mips_at, mips_at, 0);
275 mips_jr (code, mips_at);
276 mips_nop (code);
277 #else
278 mono_add_patch_info (cfg, code - cfg->native_code,
279 MONO_PATCH_INFO_BB, ins->inst_true_bb);
280 switch (op) {
281 case OP_MIPS_BEQ:
282 mips_beq (code, ins->sreg1, ins->sreg2, 0);
283 mips_nop (code);
284 break;
285 case OP_MIPS_BNE:
286 mips_bne (code, ins->sreg1, ins->sreg2, 0);
287 mips_nop (code);
288 break;
289 case OP_MIPS_BGEZ:
290 mips_bgez (code, ins->sreg1, 0);
291 mips_nop (code);
292 break;
293 case OP_MIPS_BGTZ:
294 mips_bgtz (code, ins->sreg1, 0);
295 mips_nop (code);
296 break;
297 case OP_MIPS_BLEZ:
298 mips_blez (code, ins->sreg1, 0);
299 mips_nop (code);
300 break;
301 case OP_MIPS_BLTZ:
302 mips_bltz (code, ins->sreg1, 0);
303 mips_nop (code);
304 break;
305 default:
306 g_assert_not_reached ();
308 #endif
309 return (code);
312 /* XXX - big-endian dependent? */
313 void
314 patch_lui_addiu(guint32 *ip, guint32 val)
316 guint16 *__lui_addiu = (guint16*)(void *)(ip);
318 #if 0
319 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
320 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
321 fflush (stdout);
322 #endif
323 if (((guint32)(val)) & (1 << 15))
324 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
325 else
326 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
327 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
328 mono_arch_flush_icache ((guint8 *)ip, 8);
331 guint32 trap_target;
332 void
333 mips_patch (guint32 *code, guint32 target)
335 guint32 ins = *code;
336 guint32 op = ins >> 26;
337 guint32 diff, offset;
339 g_assert (trap_target != target);
340 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
341 switch (op) {
342 case 0x00: /* jr ra */
343 if (ins == 0x3e00008)
344 break;
345 g_assert_not_reached ();
346 break;
347 case 0x02: /* j */
348 case 0x03: /* jal */
349 g_assert (!(target & 0x03));
350 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
351 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
352 *code = ins;
353 mono_arch_flush_icache ((guint8 *)code, 4);
354 break;
355 case 0x01: /* BLTZ */
356 case 0x04: /* BEQ */
357 case 0x05: /* BNE */
358 case 0x06: /* BLEZ */
359 case 0x07: /* BGTZ */
360 case 0x11: /* bc1t */
361 diff = target - (guint32)(code + 1);
362 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
363 g_assert (!(diff & 0x03));
364 offset = ((gint32)diff) >> 2;
365 g_assert (((int)offset) == ((int)(short)offset));
366 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
367 *code = ins;
368 mono_arch_flush_icache ((guint8 *)code, 4);
369 break;
370 case 0x0f: /* LUI / ADDIU pair */
371 patch_lui_addiu (code, target);
372 mono_arch_flush_icache ((guint8 *)code, 8);
373 break;
375 default:
376 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
377 g_assert_not_reached ();
381 #if 0
382 static int
383 offsets_from_pthread_key (guint32 key, int *offset2)
385 int idx1 = key / 32;
386 int idx2 = key % 32;
387 *offset2 = idx2 * sizeof (gpointer);
388 return 284 + idx1 * sizeof (gpointer);
390 #endif
392 const char*
393 mono_arch_regname (int reg) {
394 #if _MIPS_SIM == _ABIO32
395 static const char * rnames[] = {
396 "zero", "at", "v0", "v1",
397 "a0", "a1", "a2", "a3",
398 "t0", "t1", "t2", "t3",
399 "t4", "t5", "t6", "t7",
400 "s0", "s1", "s2", "s3",
401 "s4", "s5", "s6", "s7",
402 "t8", "t9", "k0", "k1",
403 "gp", "sp", "fp", "ra"
405 #elif _MIPS_SIM == _ABIN32
406 static const char * rnames[] = {
407 "zero", "at", "v0", "v1",
408 "a0", "a1", "a2", "a3",
409 "a4", "a5", "a6", "a7",
410 "t0", "t1", "t2", "t3",
411 "s0", "s1", "s2", "s3",
412 "s4", "s5", "s6", "s7",
413 "t8", "t9", "k0", "k1",
414 "gp", "sp", "fp", "ra"
416 #endif
417 if (reg >= 0 && reg < 32)
418 return rnames [reg];
419 return "unknown";
422 const char*
423 mono_arch_fregname (int reg) {
424 static const char * rnames[] = {
425 "f0", "f1", "f2", "f3",
426 "f4", "f5", "f6", "f7",
427 "f8", "f9", "f10", "f11",
428 "f12", "f13", "f14", "f15",
429 "f16", "f17", "f18", "f19",
430 "f20", "f21", "f22", "f23",
431 "f24", "f25", "f26", "f27",
432 "f28", "f29", "f30", "f31"
434 if (reg >= 0 && reg < 32)
435 return rnames [reg];
436 return "unknown";
439 /* this function overwrites at */
440 static guint8*
441 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
443 /* XXX write a loop, not an unrolled loop */
444 while (size > 0) {
445 mips_lw (code, mips_at, sreg, soffset);
446 mips_sw (code, mips_at, dreg, doffset);
447 size -= 4;
448 soffset += 4;
449 doffset += 4;
451 return code;
455 * mono_arch_get_argument_info:
456 * @csig: a method signature
457 * @param_count: the number of parameters to consider
458 * @arg_info: an array to store the result infos
460 * Gathers information on parameters such as size, alignment and
461 * padding. arg_info should be large enought to hold param_count + 1 entries.
463 * Returns the size of the activation frame.
466 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
468 int k, frame_size = 0;
469 guint32 size, align, pad;
470 int offset = 0;
472 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
473 frame_size += sizeof (gpointer);
474 offset += 4;
477 arg_info [0].offset = offset;
479 if (csig->hasthis) {
480 frame_size += sizeof (gpointer);
481 offset += 4;
484 arg_info [0].size = frame_size;
486 for (k = 0; k < param_count; k++) {
487 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
489 /* ignore alignment for now */
490 align = 1;
492 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
493 arg_info [k].pad = pad;
494 frame_size += size;
495 arg_info [k + 1].pad = 0;
496 arg_info [k + 1].size = size;
497 offset += pad;
498 arg_info [k + 1].offset = offset;
499 offset += size;
502 align = MONO_ARCH_FRAME_ALIGNMENT;
503 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
504 arg_info [k].pad = pad;
506 return frame_size;
510 gpointer
511 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, mgreg_t *regs, guint8 *code)
513 /* FIXME: handle returning a struct */
514 if (MONO_TYPE_ISSTRUCT (sig->ret))
515 return (gpointer)regs [mips_a1];
516 return (gpointer)regs [mips_a0];
520 * Initialize the cpu to execute managed code.
522 void
523 mono_arch_cpu_init (void)
528 * Initialize architecture specific code.
530 void
531 mono_arch_init (void)
533 InitializeCriticalSection (&mini_arch_mutex);
537 * Cleanup architecture specific code.
539 void
540 mono_arch_cleanup (void)
542 DeleteCriticalSection (&mini_arch_mutex);
546 * This function returns the optimizations supported on this cpu.
548 guint32
549 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
551 guint32 opts = 0;
553 /* no mips-specific optimizations yet */
554 *exclude_mask = 0;
555 return opts;
558 static gboolean
559 is_regsize_var (MonoType *t) {
560 if (t->byref)
561 return TRUE;
562 t = mono_type_get_underlying_type (t);
563 switch (t->type) {
564 case MONO_TYPE_I4:
565 case MONO_TYPE_U4:
566 #if (SIZEOF_REGISTER == 8)
567 case MONO_TYPE_I8:
568 case MONO_TYPE_U8:
569 #endif
570 case MONO_TYPE_I:
571 case MONO_TYPE_U:
572 case MONO_TYPE_PTR:
573 case MONO_TYPE_FNPTR:
574 return TRUE;
575 case MONO_TYPE_OBJECT:
576 case MONO_TYPE_STRING:
577 case MONO_TYPE_CLASS:
578 case MONO_TYPE_SZARRAY:
579 case MONO_TYPE_ARRAY:
580 return TRUE;
581 case MONO_TYPE_GENERICINST:
582 if (!mono_type_generic_inst_is_valuetype (t))
583 return TRUE;
584 return FALSE;
585 case MONO_TYPE_VALUETYPE:
586 return FALSE;
588 return FALSE;
591 GList *
592 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
594 GList *vars = NULL;
595 int i;
597 for (i = 0; i < cfg->num_varinfo; i++) {
598 MonoInst *ins = cfg->varinfo [i];
599 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
601 /* unused vars */
602 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
603 continue;
605 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
606 continue;
608 /* we can only allocate 32 bit values */
609 if (is_regsize_var (ins->inst_vtype)) {
610 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
611 g_assert (i == vmv->idx);
612 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
616 return vars;
619 GList *
620 mono_arch_get_global_int_regs (MonoCompile *cfg)
622 GList *regs = NULL;
624 regs = g_list_prepend (regs, (gpointer)mips_s0);
625 regs = g_list_prepend (regs, (gpointer)mips_s1);
626 regs = g_list_prepend (regs, (gpointer)mips_s2);
627 regs = g_list_prepend (regs, (gpointer)mips_s3);
628 regs = g_list_prepend (regs, (gpointer)mips_s4);
629 //regs = g_list_prepend (regs, (gpointer)mips_s5);
630 regs = g_list_prepend (regs, (gpointer)mips_s6);
631 regs = g_list_prepend (regs, (gpointer)mips_s7);
633 return regs;
637 * mono_arch_regalloc_cost:
639 * Return the cost, in number of memory references, of the action of
640 * allocating the variable VMV into a register during global register
641 * allocation.
643 guint32
644 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
646 /* FIXME: */
647 return 2;
650 static void
651 args_onto_stack (CallInfo *info)
653 g_assert (!info->on_stack);
654 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
655 info->on_stack = TRUE;
656 info->stack_size = MIPS_STACK_PARAM_OFFSET;
659 #if _MIPS_SIM == _ABIO32
661 * O32 calling convention version
664 static void
665 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
666 /* First, see if we need to drop onto the stack */
667 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
668 args_onto_stack (info);
670 /* Now, place the argument */
671 if (info->on_stack) {
672 ainfo->regtype = RegTypeBase;
673 ainfo->reg = mips_sp; /* in the caller */
674 ainfo->offset = info->stack_size;
676 else {
677 ainfo->regtype = RegTypeGeneral;
678 ainfo->reg = info->gr;
679 info->gr += 1;
680 info->gr_passed = TRUE;
682 info->stack_size += 4;
685 static void
686 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
687 /* First, see if we need to drop onto the stack */
688 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
689 args_onto_stack (info);
691 /* Now, place the argument */
692 if (info->on_stack) {
693 g_assert (info->stack_size % 4 == 0);
694 info->stack_size += (info->stack_size % 8);
696 ainfo->regtype = RegTypeBase;
697 ainfo->reg = mips_sp; /* in the caller */
698 ainfo->offset = info->stack_size;
700 else {
701 // info->gr must be a0 or a2
702 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
703 g_assert(info->gr <= MIPS_LAST_ARG_REG);
705 ainfo->regtype = RegTypeGeneral;
706 ainfo->reg = info->gr;
707 info->gr += 2;
708 info->gr_passed = TRUE;
710 info->stack_size += 8;
713 static void
714 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
715 /* First, see if we need to drop onto the stack */
716 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
717 args_onto_stack (info);
719 /* Now, place the argument */
720 if (info->on_stack) {
721 ainfo->regtype = RegTypeBase;
722 ainfo->reg = mips_sp; /* in the caller */
723 ainfo->offset = info->stack_size;
725 else {
726 /* Only use FP regs for args if no int args passed yet */
727 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
728 ainfo->regtype = RegTypeFP;
729 ainfo->reg = info->fr;
730 /* Even though it's a single-precision float, it takes up two FP regs */
731 info->fr += 2;
732 /* FP and GP slots do not overlap */
733 info->gr += 1;
735 else {
736 /* Passing single-precision float arg in a GP register
737 * such as: func (0, 1.0, 2, 3);
738 * In this case, only one 'gr' register is consumed.
740 ainfo->regtype = RegTypeGeneral;
741 ainfo->reg = info->gr;
743 info->gr += 1;
744 info->gr_passed = TRUE;
747 info->stack_size += 4;
750 static void
751 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
752 /* First, see if we need to drop onto the stack */
753 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
754 args_onto_stack (info);
756 /* Now, place the argument */
757 if (info->on_stack) {
758 g_assert(info->stack_size % 4 == 0);
759 info->stack_size += (info->stack_size % 8);
761 ainfo->regtype = RegTypeBase;
762 ainfo->reg = mips_sp; /* in the caller */
763 ainfo->offset = info->stack_size;
765 else {
766 /* Only use FP regs for args if no int args passed yet */
767 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
768 ainfo->regtype = RegTypeFP;
769 ainfo->reg = info->fr;
770 info->fr += 2;
771 /* FP and GP slots do not overlap */
772 info->gr += 2;
774 else {
775 // info->gr must be a0 or a2
776 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
777 g_assert(info->gr <= MIPS_LAST_ARG_REG);
779 ainfo->regtype = RegTypeGeneral;
780 ainfo->reg = info->gr;
781 info->gr += 2;
782 info->gr_passed = TRUE;
785 info->stack_size += 8;
787 #elif _MIPS_SIM == _ABIN32
789 * N32 calling convention version
792 static void
793 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
794 /* First, see if we need to drop onto the stack */
795 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
796 args_onto_stack (info);
798 /* Now, place the argument */
799 if (info->on_stack) {
800 ainfo->regtype = RegTypeBase;
801 ainfo->reg = mips_sp; /* in the caller */
802 ainfo->offset = info->stack_size;
803 info->stack_size += SIZEOF_REGISTER;
805 else {
806 ainfo->regtype = RegTypeGeneral;
807 ainfo->reg = info->gr;
808 info->gr += 1;
809 info->gr_passed = TRUE;
813 static void
814 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
815 /* First, see if we need to drop onto the stack */
816 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
817 args_onto_stack (info);
819 /* Now, place the argument */
820 if (info->on_stack) {
821 g_assert (info->stack_size % 4 == 0);
822 info->stack_size += (info->stack_size % 8);
824 ainfo->regtype = RegTypeBase;
825 ainfo->reg = mips_sp; /* in the caller */
826 ainfo->offset = info->stack_size;
827 info->stack_size += SIZEOF_REGISTER;
829 else {
830 g_assert (info->gr <= MIPS_LAST_ARG_REG);
832 ainfo->regtype = RegTypeGeneral;
833 ainfo->reg = info->gr;
834 info->gr += 1;
835 info->gr_passed = TRUE;
839 static void
840 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
841 /* First, see if we need to drop onto the stack */
842 if (!info->on_stack) {
843 if (info->gr > MIPS_LAST_ARG_REG)
844 args_onto_stack (info);
845 else if (info->fr > MIPS_LAST_FPARG_REG)
846 args_onto_stack (info);
849 /* Now, place the argument */
850 if (info->on_stack) {
851 ainfo->regtype = RegTypeBase;
852 ainfo->reg = mips_sp; /* in the caller */
853 ainfo->offset = info->stack_size;
854 info->stack_size += FREG_SIZE;
856 else {
857 ainfo->regtype = RegTypeFP;
858 ainfo->reg = info->fr;
859 info->fr += 1;
860 /* FP and GP slots do not overlap */
861 info->gr += 1;
865 static void
866 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
867 /* First, see if we need to drop onto the stack */
868 if (!info->on_stack) {
869 if (info->gr > MIPS_LAST_ARG_REG)
870 args_onto_stack (info);
871 else if (info->fr > MIPS_LAST_FPARG_REG)
872 args_onto_stack (info);
875 /* Now, place the argument */
876 if (info->on_stack) {
877 g_assert(info->stack_size % 4 == 0);
878 info->stack_size += (info->stack_size % 8);
880 ainfo->regtype = RegTypeBase;
881 ainfo->reg = mips_sp; /* in the caller */
882 ainfo->offset = info->stack_size;
883 info->stack_size += FREG_SIZE;
885 else {
886 ainfo->regtype = RegTypeFP;
887 ainfo->reg = info->fr;
888 info->fr += 1;
889 /* FP and GP slots do not overlap */
890 info->gr += 1;
893 #endif
895 static CallInfo*
896 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
898 guint i;
899 int n = sig->hasthis + sig->param_count;
900 MonoType* simpletype;
901 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
903 cinfo->fr = MIPS_FIRST_FPARG_REG;
904 cinfo->gr = MIPS_FIRST_ARG_REG;
905 cinfo->stack_size = 0;
907 DEBUG(printf("calculate_sizes\n"));
909 /* handle returning a struct */
910 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
911 cinfo->struct_ret = cinfo->gr;
912 add_int32_arg (cinfo, &cinfo->ret);
915 n = 0;
916 if (sig->hasthis) {
917 add_int32_arg (cinfo, cinfo->args + n);
918 n++;
920 DEBUG(printf("params: %d\n", sig->param_count));
921 for (i = 0; i < sig->param_count; ++i) {
922 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
923 /* Prevent implicit arguments and sig_cookie from
924 being passed in registers */
925 args_onto_stack (cinfo);
926 /* Emit the signature cookie just before the implicit arguments */
927 add_int32_arg (cinfo, &cinfo->sig_cookie);
929 DEBUG(printf("param %d: ", i));
930 if (sig->params [i]->byref) {
931 DEBUG(printf("byref\n"));
932 add_int32_arg (cinfo, &cinfo->args[n]);
933 n++;
934 continue;
936 simpletype = mono_type_get_underlying_type (sig->params [i]);
937 switch (simpletype->type) {
938 case MONO_TYPE_BOOLEAN:
939 case MONO_TYPE_I1:
940 case MONO_TYPE_U1:
941 DEBUG(printf("1 byte\n"));
942 cinfo->args [n].size = 1;
943 add_int32_arg (cinfo, &cinfo->args[n]);
944 n++;
945 break;
946 case MONO_TYPE_CHAR:
947 case MONO_TYPE_I2:
948 case MONO_TYPE_U2:
949 DEBUG(printf("2 bytes\n"));
950 cinfo->args [n].size = 2;
951 add_int32_arg (cinfo, &cinfo->args[n]);
952 n++;
953 break;
954 case MONO_TYPE_I4:
955 case MONO_TYPE_U4:
956 DEBUG(printf("4 bytes\n"));
957 cinfo->args [n].size = 4;
958 add_int32_arg (cinfo, &cinfo->args[n]);
959 n++;
960 break;
961 case MONO_TYPE_I:
962 case MONO_TYPE_U:
963 case MONO_TYPE_PTR:
964 case MONO_TYPE_FNPTR:
965 case MONO_TYPE_CLASS:
966 case MONO_TYPE_OBJECT:
967 case MONO_TYPE_STRING:
968 case MONO_TYPE_SZARRAY:
969 case MONO_TYPE_ARRAY:
970 cinfo->args [n].size = sizeof (gpointer);
971 add_int32_arg (cinfo, &cinfo->args[n]);
972 n++;
973 break;
974 case MONO_TYPE_GENERICINST:
975 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
976 cinfo->args [n].size = sizeof (gpointer);
977 add_int32_arg (cinfo, &cinfo->args[n]);
978 n++;
979 break;
981 /* Fall through */
982 case MONO_TYPE_VALUETYPE: {
983 int j;
984 int nwords = 0;
985 int has_offset = FALSE;
986 ArgInfo dummy_arg;
987 gint size, alignment;
988 MonoClass *klass;
990 klass = mono_class_from_mono_type (sig->params [i]);
991 if (is_pinvoke)
992 size = mono_class_native_size (klass, NULL);
993 else
994 size = mono_class_value_size (klass, NULL);
995 alignment = mono_class_min_align (klass);
996 #if MIPS_PASS_STRUCTS_BY_VALUE
997 /* Need to do alignment if struct contains long or double */
998 if (alignment > 4) {
999 if (cinfo->stack_size & (alignment - 1)) {
1000 add_int32_arg (cinfo, &dummy_arg);
1002 g_assert (!(cinfo->stack_size & (alignment - 1)));
1005 #if 0
1006 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1007 mono_class_native_size (sig->params [i]->data.klass, NULL),
1008 cinfo->stack_size, alignment);
1009 #endif
1010 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1011 g_assert (cinfo->args [n].size == 0);
1012 g_assert (cinfo->args [n].vtsize == 0);
1013 for (j = 0; j < nwords; ++j) {
1014 if (j == 0) {
1015 add_int32_arg (cinfo, &cinfo->args [n]);
1016 if (cinfo->on_stack)
1017 has_offset = TRUE;
1018 } else {
1019 add_int32_arg (cinfo, &dummy_arg);
1020 if (!has_offset && cinfo->on_stack) {
1021 cinfo->args [n].offset = dummy_arg.offset;
1022 has_offset = TRUE;
1025 if (cinfo->on_stack)
1026 cinfo->args [n].vtsize += 1;
1027 else
1028 cinfo->args [n].size += 1;
1030 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1031 cinfo->args [n].regtype = RegTypeStructByVal;
1032 #else
1033 add_int32_arg (cinfo, &cinfo->args[n]);
1034 cinfo->args [n].regtype = RegTypeStructByAddr;
1035 #endif
1036 n++;
1037 break;
1039 case MONO_TYPE_TYPEDBYREF: {
1040 /* keep in sync or merge with the valuetype case */
1041 #if MIPS_PASS_STRUCTS_BY_VALUE
1043 int size = sizeof (MonoTypedRef);
1044 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1045 cinfo->args [n].regtype = RegTypeStructByVal;
1046 if (!cinfo->on_stack && cinfo->gr <= MIPS_LAST_ARG_REG) {
1047 int rest = MIPS_LAST_ARG_REG - cinfo->gr + 1;
1048 int n_in_regs = rest >= nwords? nwords: rest;
1049 cinfo->args [n].size = n_in_regs;
1050 cinfo->args [n].vtsize = nwords - n_in_regs;
1051 cinfo->args [n].reg = cinfo->gr;
1052 cinfo->gr += n_in_regs;
1053 cinfo->gr_passed = TRUE;
1054 } else {
1055 cinfo->args [n].size = 0;
1056 cinfo->args [n].vtsize = nwords;
1058 if (cinfo->args [n].vtsize > 0) {
1059 if (!cinfo->on_stack)
1060 args_onto_stack (cinfo);
1061 g_assert(cinfo->on_stack);
1062 cinfo->args [n].offset = cinfo->stack_size;
1063 g_print ("offset for arg %d at %d\n", n, cinfo->args [n].offset);
1064 cinfo->stack_size += cinfo->args [n].vtsize * sizeof (gpointer);
1067 #else
1068 add_int32_arg (cinfo, &cinfo->args[n]);
1069 cinfo->args [n].regtype = RegTypeStructByAddr;
1070 #endif
1071 n++;
1072 break;
1074 case MONO_TYPE_U8:
1075 case MONO_TYPE_I8:
1076 DEBUG(printf("8 bytes\n"));
1077 cinfo->args [n].size = 8;
1078 add_int64_arg (cinfo, &cinfo->args[n]);
1079 n++;
1080 break;
1081 case MONO_TYPE_R4:
1082 DEBUG(printf("R4\n"));
1083 cinfo->args [n].size = 4;
1084 add_float32_arg (cinfo, &cinfo->args[n]);
1085 n++;
1086 break;
1087 case MONO_TYPE_R8:
1088 DEBUG(printf("R8\n"));
1089 cinfo->args [n].size = 8;
1090 add_float64_arg (cinfo, &cinfo->args[n]);
1091 n++;
1092 break;
1093 default:
1094 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1099 simpletype = mono_type_get_underlying_type (sig->ret);
1100 switch (simpletype->type) {
1101 case MONO_TYPE_BOOLEAN:
1102 case MONO_TYPE_I1:
1103 case MONO_TYPE_U1:
1104 case MONO_TYPE_I2:
1105 case MONO_TYPE_U2:
1106 case MONO_TYPE_CHAR:
1107 case MONO_TYPE_I4:
1108 case MONO_TYPE_U4:
1109 case MONO_TYPE_I:
1110 case MONO_TYPE_U:
1111 case MONO_TYPE_PTR:
1112 case MONO_TYPE_FNPTR:
1113 case MONO_TYPE_CLASS:
1114 case MONO_TYPE_OBJECT:
1115 case MONO_TYPE_SZARRAY:
1116 case MONO_TYPE_ARRAY:
1117 case MONO_TYPE_STRING:
1118 cinfo->ret.reg = mips_v0;
1119 break;
1120 case MONO_TYPE_U8:
1121 case MONO_TYPE_I8:
1122 cinfo->ret.reg = mips_v0;
1123 break;
1124 case MONO_TYPE_R4:
1125 case MONO_TYPE_R8:
1126 cinfo->ret.reg = mips_f0;
1127 cinfo->ret.regtype = RegTypeFP;
1128 break;
1129 case MONO_TYPE_GENERICINST:
1130 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1131 cinfo->ret.reg = mips_v0;
1132 break;
1134 break;
1135 case MONO_TYPE_VALUETYPE:
1136 break;
1137 case MONO_TYPE_TYPEDBYREF:
1138 case MONO_TYPE_VOID:
1139 break;
1140 default:
1141 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1145 /* align stack size to 16 */
1146 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1148 cinfo->stack_usage = cinfo->stack_size;
1149 return cinfo;
1154 * Set var information according to the calling convention. mips version.
1155 * The locals var stuff should most likely be split in another method.
1157 void
1158 mono_arch_allocate_vars (MonoCompile *cfg)
1160 MonoMethodSignature *sig;
1161 MonoMethodHeader *header;
1162 MonoInst *inst;
1163 int i, offset, size, align, curinst;
1164 int frame_reg = mips_sp;
1165 guint32 iregs_to_save = 0;
1166 #if SAVE_FP_REGS
1167 guint32 fregs_to_restore;
1168 #endif
1170 /* spill down, we'll fix it in a separate pass */
1171 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1173 /* allow room for the vararg method args: void* and long/double */
1174 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1175 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1177 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1178 * call convs needs to be handled this way.
1180 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1181 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1183 /* gtk-sharp and other broken code will dllimport vararg functions even with
1184 * non-varargs signatures. Since there is little hope people will get this right
1185 * we assume they won't.
1187 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1188 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1190 /* a0-a3 always present */
1191 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1193 header = mono_method_get_header (cfg->method);
1195 sig = mono_method_signature (cfg->method);
1198 * We use the frame register also for any method that has
1199 * exception clauses. This way, when the handlers are called,
1200 * the code will reference local variables using the frame reg instead of
1201 * the stack pointer: if we had to restore the stack pointer, we'd
1202 * corrupt the method frames that are already on the stack (since
1203 * filters get called before stack unwinding happens) when the filter
1204 * code would call any method (this also applies to finally etc.).
1207 if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses || ALWAYS_USE_FP)
1208 frame_reg = mips_fp;
1209 cfg->frame_reg = frame_reg;
1210 if (frame_reg != mips_sp) {
1211 cfg->used_int_regs |= 1 << frame_reg;
1214 offset = 0;
1215 curinst = 0;
1216 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1217 /* FIXME: handle long and FP values */
1218 switch (mono_type_get_underlying_type (sig->ret)->type) {
1219 case MONO_TYPE_VOID:
1220 break;
1221 case MONO_TYPE_R4:
1222 case MONO_TYPE_R8:
1223 cfg->ret->opcode = OP_REGVAR;
1224 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1225 break;
1226 default:
1227 cfg->ret->opcode = OP_REGVAR;
1228 cfg->ret->inst_c0 = mips_v0;
1229 break;
1232 /* Space for outgoing parameters, including a0-a3 */
1233 offset += cfg->param_area;
1235 /* allow room to save the return value (if it's a struct) */
1236 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1237 offset += 8;
1239 if (sig->call_convention == MONO_CALL_VARARG) {
1240 cfg->sig_cookie = MIPS_STACK_PARAM_OFFSET;
1243 /* Now handle the local variables */
1245 curinst = cfg->locals_start;
1246 for (i = curinst; i < cfg->num_varinfo; ++i) {
1247 inst = cfg->varinfo [i];
1248 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1249 continue;
1251 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1252 * pinvoke wrappers when they call functions returning structure
1254 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1255 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
1256 else
1257 size = mono_type_size (inst->inst_vtype, &align);
1259 offset += align - 1;
1260 offset &= ~(align - 1);
1261 inst->inst_offset = offset;
1262 inst->opcode = OP_REGOFFSET;
1263 inst->inst_basereg = frame_reg;
1264 offset += size;
1265 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1268 /* Space for LMF (if needed) */
1269 #if SAVE_LMF
1270 if (cfg->method->save_lmf) {
1271 /* align the offset to 16 bytes */
1272 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1273 cfg->arch.lmf_offset = offset;
1274 offset += sizeof (MonoLMF);
1276 #endif
1278 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1279 * args or return vals. Extra stack space avoids this in a lot of cases.
1281 offset += EXTRA_STACK_SPACE;
1283 /* Space for saved registers */
1284 cfg->arch.iregs_offset = offset;
1285 #if SAVE_ALL_REGS
1286 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
1287 #else
1288 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1289 #endif
1290 if (iregs_to_save) {
1291 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1292 if (iregs_to_save & (1 << i)) {
1293 offset += SIZEOF_REGISTER;
1298 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1299 * args or return vals. Extra stack space avoids this in a lot of cases.
1301 offset += EXTRA_STACK_SPACE;
1303 /* saved float registers */
1304 #if SAVE_FP_REGS
1305 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1306 if (fregs_to_restore) {
1307 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1308 if (fregs_to_restore & (1 << i)) {
1309 offset += sizeof(double);
1313 #endif
1315 #if _MIPS_SIM == _ABIO32
1316 /* Now add space for saving the ra */
1317 offset += SIZEOF_VOID_P;
1319 /* change sign? */
1320 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1321 cfg->stack_offset = offset;
1322 cfg->arch.local_alloc_offset = cfg->stack_offset;
1323 #endif
1326 * Now allocate stack slots for the int arg regs (a0 - a3)
1327 * On MIPS o32, these are just above the incoming stack pointer
1328 * Even if the arg has been assigned to a regvar, it gets a stack slot
1331 /* Return struct-by-value results in a hidden first argument */
1332 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1333 cfg->vret_addr->opcode = OP_REGOFFSET;
1334 cfg->vret_addr->inst_c0 = mips_a0;
1335 cfg->vret_addr->inst_offset = offset;
1336 cfg->vret_addr->inst_basereg = frame_reg;
1337 offset += SIZEOF_REGISTER;
1340 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1341 inst = cfg->args [i];
1342 if (inst->opcode != OP_REGVAR) {
1343 MonoType *arg_type;
1345 if (sig->hasthis && (i == 0))
1346 arg_type = &mono_defaults.object_class->byval_arg;
1347 else
1348 arg_type = sig->params [i - sig->hasthis];
1350 inst->opcode = OP_REGOFFSET;
1351 size = mono_type_size (arg_type, &align);
1353 if (size < SIZEOF_REGISTER) {
1354 size = SIZEOF_REGISTER;
1355 align = SIZEOF_REGISTER;
1357 inst->inst_basereg = frame_reg;
1358 offset = (offset + align - 1) & ~(align - 1);
1359 inst->inst_offset = offset;
1360 offset += size;
1361 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1362 cfg->sig_cookie += size;
1363 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1365 else {
1366 #if _MIPS_SIM == _ABIO32
1367 /* o32: Even a0-a3 get stack slots */
1368 size = SIZEOF_REGISTER;
1369 align = SIZEOF_REGISTER;
1370 inst->inst_basereg = frame_reg;
1371 offset = (offset + align - 1) & ~(align - 1);
1372 inst->inst_offset = offset;
1373 offset += size;
1374 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1375 cfg->sig_cookie += size;
1376 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1377 #endif
1380 #if _MIPS_SIM == _ABIN32
1381 /* Now add space for saving the ra */
1382 offset += SIZEOF_VOID_P;
1384 /* change sign? */
1385 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1386 cfg->stack_offset = offset;
1387 cfg->arch.local_alloc_offset = cfg->stack_offset;
1388 #endif
1391 void
1392 mono_arch_create_vars (MonoCompile *cfg)
1394 MonoMethodSignature *sig;
1396 sig = mono_method_signature (cfg->method);
1398 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1399 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1400 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1401 printf ("vret_addr = ");
1402 mono_print_ins (cfg->vret_addr);
1407 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1408 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1412 * take the arguments and generate the arch-specific
1413 * instructions to properly call the function in call.
1414 * This includes pushing, moving arguments to the right register
1415 * etc.
1416 * Issue: who does the spilling if needed, and when?
1418 static void
1419 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1421 int sig_reg = mono_alloc_ireg (cfg);
1423 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (guint32)call->signature);
1424 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1425 mips_sp, cinfo->sig_cookie.offset, sig_reg);
1428 void
1429 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1431 MonoInst *in, *ins;
1432 MonoMethodSignature *sig;
1433 int i, n;
1434 CallInfo *cinfo;
1435 int is_virtual = 0;
1437 sig = call->signature;
1438 n = sig->param_count + sig->hasthis;
1440 cinfo = calculate_sizes (sig, sig->pinvoke);
1441 if (cinfo->struct_ret)
1442 call->used_iregs |= 1 << cinfo->struct_ret;
1444 for (i = 0; i < n; ++i) {
1445 ArgInfo *ainfo = cinfo->args + i;
1446 MonoType *t;
1448 if (i >= sig->hasthis)
1449 t = sig->params [i - sig->hasthis];
1450 else
1451 t = &mono_defaults.int_class->byval_arg;
1452 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1454 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1455 emit_sig_cookie (cfg, call, cinfo);
1456 if (is_virtual && i == 0) {
1457 /* the argument will be attached to the call instrucion */
1458 in = call->args [i];
1459 call->used_iregs |= 1 << ainfo->reg;
1460 continue;
1462 in = call->args [i];
1463 if (ainfo->regtype == RegTypeGeneral) {
1464 #if SIZEOF_REGISTER == 4
1465 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1466 MONO_INST_NEW (cfg, ins, OP_MOVE);
1467 ins->dreg = mono_alloc_ireg (cfg);
1468 ins->sreg1 = in->dreg + 1;
1469 MONO_ADD_INS (cfg->cbb, ins);
1470 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1472 MONO_INST_NEW (cfg, ins, OP_MOVE);
1473 ins->dreg = mono_alloc_ireg (cfg);
1474 ins->sreg1 = in->dreg + 2;
1475 MONO_ADD_INS (cfg->cbb, ins);
1476 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1477 } else
1478 #endif
1479 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1480 int freg;
1482 #if PROMOTE_R4_TO_R8
1483 /* ??? - convert to single first? */
1484 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1485 ins->dreg = mono_alloc_freg (cfg);
1486 ins->sreg1 = in->dreg;
1487 MONO_ADD_INS (cfg->cbb, ins);
1488 freg = ins->dreg;
1489 #else
1490 freg = in->dreg;
1491 #endif
1492 /* trying to load float value into int registers */
1493 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1494 ins->dreg = mono_alloc_ireg (cfg);
1495 ins->sreg1 = freg;
1496 MONO_ADD_INS (cfg->cbb, ins);
1497 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1498 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1499 /* trying to load float value into int registers */
1500 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1501 ins->dreg = mono_alloc_ireg (cfg);
1502 ins->sreg1 = in->dreg;
1503 MONO_ADD_INS (cfg->cbb, ins);
1504 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1505 } else {
1506 MONO_INST_NEW (cfg, ins, OP_MOVE);
1507 ins->dreg = mono_alloc_ireg (cfg);
1508 ins->sreg1 = in->dreg;
1509 MONO_ADD_INS (cfg->cbb, ins);
1510 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1512 } else if (ainfo->regtype == RegTypeStructByAddr) {
1513 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1514 ins->opcode = OP_OUTARG_VT;
1515 ins->sreg1 = in->dreg;
1516 ins->klass = in->klass;
1517 ins->inst_p0 = call;
1518 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1519 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1520 MONO_ADD_INS (cfg->cbb, ins);
1521 } else if (ainfo->regtype == RegTypeStructByVal) {
1522 /* this is further handled in mono_arch_emit_outarg_vt () */
1523 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1524 ins->opcode = OP_OUTARG_VT;
1525 ins->sreg1 = in->dreg;
1526 ins->klass = in->klass;
1527 ins->inst_p0 = call;
1528 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1529 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1530 MONO_ADD_INS (cfg->cbb, ins);
1531 } else if (ainfo->regtype == RegTypeBase) {
1532 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1533 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1534 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1535 if (t->type == MONO_TYPE_R8)
1536 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1537 else
1538 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1539 } else {
1540 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1542 } else if (ainfo->regtype == RegTypeFP) {
1543 if (t->type == MONO_TYPE_VALUETYPE) {
1544 /* this is further handled in mono_arch_emit_outarg_vt () */
1545 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1546 ins->opcode = OP_OUTARG_VT;
1547 ins->sreg1 = in->dreg;
1548 ins->klass = in->klass;
1549 ins->inst_p0 = call;
1550 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1551 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1552 MONO_ADD_INS (cfg->cbb, ins);
1554 cfg->flags |= MONO_CFG_HAS_FPOUT;
1555 } else {
1556 int dreg = mono_alloc_freg (cfg);
1558 if (ainfo->size == 4) {
1559 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1560 } else {
1561 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1562 ins->dreg = dreg;
1563 ins->sreg1 = in->dreg;
1564 MONO_ADD_INS (cfg->cbb, ins);
1567 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1568 cfg->flags |= MONO_CFG_HAS_FPOUT;
1570 } else {
1571 g_assert_not_reached ();
1575 /* Emit the signature cookie in the case that there is no
1576 additional argument */
1577 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1578 emit_sig_cookie (cfg, call, cinfo);
1580 if (cinfo->struct_ret) {
1581 MonoInst *vtarg;
1583 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1584 vtarg->sreg1 = call->vret_var->dreg;
1585 vtarg->dreg = mono_alloc_preg (cfg);
1586 MONO_ADD_INS (cfg->cbb, vtarg);
1588 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1590 #if 0
1592 * Reverse the call->out_args list.
1595 MonoInst *prev = NULL, *list = call->out_args, *next;
1596 while (list) {
1597 next = list->next;
1598 list->next = prev;
1599 prev = list;
1600 list = next;
1602 call->out_args = prev;
1604 #endif
1605 call->stack_usage = cinfo->stack_usage;
1606 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1607 #if _MIPS_SIM == _ABIO32
1608 /* a0-a3 always present */
1609 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1610 #endif
1611 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1612 cfg->flags |= MONO_CFG_HAS_CALLS;
1614 * should set more info in call, such as the stack space
1615 * used by the args that needs to be added back to esp
1618 g_free (cinfo);
1621 void
1622 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1624 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1625 ArgInfo *ainfo = ins->inst_p1;
1626 int ovf_size = ainfo->vtsize;
1627 int doffset = ainfo->offset;
1628 int i, soffset, dreg;
1630 if (ainfo->regtype == RegTypeStructByVal) {
1631 #if 1
1632 if (cfg->verbose_level > 0) {
1633 char* nm = mono_method_full_name (cfg->method, TRUE);
1634 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1635 nm, doffset, ainfo->size, ovf_size);
1636 g_free (nm);
1638 #endif
1640 soffset = 0;
1641 for (i = 0; i < ainfo->size; ++i) {
1642 dreg = mono_alloc_ireg (cfg);
1643 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1644 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1645 soffset += SIZEOF_REGISTER;
1647 if (ovf_size != 0) {
1648 mini_emit_memcpy (cfg, mips_fp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1650 } else if (ainfo->regtype == RegTypeFP) {
1651 int tmpr = mono_alloc_freg (cfg);
1653 if (ainfo->size == 4)
1654 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1655 else
1656 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1657 dreg = mono_alloc_freg (cfg);
1658 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1659 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1660 } else {
1661 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1662 MonoInst *load;
1663 guint32 size;
1665 /* FIXME: alignment? */
1666 if (call->signature->pinvoke) {
1667 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1668 vtcopy->backend.is_pinvoke = 1;
1669 } else {
1670 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1672 if (size > 0)
1673 g_assert (ovf_size > 0);
1675 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1676 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1678 if (ainfo->offset)
1679 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1680 else
1681 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1685 void
1686 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1688 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1689 mono_method_signature (method)->ret);
1691 if (!ret->byref) {
1692 #if (SIZEOF_REGISTER == 4)
1693 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1694 MonoInst *ins;
1696 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1697 ins->sreg1 = val->dreg + 1;
1698 ins->sreg2 = val->dreg + 2;
1699 MONO_ADD_INS (cfg->cbb, ins);
1700 return;
1702 #endif
1703 if (ret->type == MONO_TYPE_R8) {
1704 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1705 return;
1707 if (ret->type == MONO_TYPE_R4) {
1708 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1709 return;
1712 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1715 void
1716 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1718 MonoInst *ins, *n, *last_ins = NULL;
1720 if (cfg->verbose_level > 2)
1721 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1723 ins = bb->code;
1724 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1725 if (cfg->verbose_level > 2)
1726 mono_print_ins_index (0, ins);
1728 switch (ins->opcode) {
1729 #if 0
1730 case OP_LOAD_MEMBASE:
1731 case OP_LOADI4_MEMBASE:
1733 * OP_IADD reg2, reg1, const1
1734 * OP_LOAD_MEMBASE const2(reg2), reg3
1735 * ->
1736 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1738 if (last_ins && (last_ins->opcode == OP_IADD_IMM || last_ins->opcode == OP_ADD_IMM) && (last_ins->dreg == ins->inst_basereg) && (last_ins->sreg1 != last_ins->dreg)){
1739 int const1 = last_ins->inst_imm;
1740 int const2 = ins->inst_offset;
1742 if (mips_is_imm16 (const1 + const2)) {
1743 ins->inst_basereg = last_ins->sreg1;
1744 ins->inst_offset = const1 + const2;
1747 break;
1748 #endif
1751 last_ins = ins;
1752 ins = ins->next;
1754 bb->last_ins = last_ins;
1757 void
1758 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1760 MonoInst *ins, *n, *last_ins = NULL;
1761 ins = bb->code;
1763 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1764 MonoInst *last_ins = ins->prev;
1766 switch (ins->opcode) {
1767 case OP_MUL_IMM:
1768 /* remove unnecessary multiplication with 1 */
1769 if (ins->inst_imm == 1) {
1770 if (ins->dreg != ins->sreg1) {
1771 ins->opcode = OP_MOVE;
1772 } else {
1773 MONO_DELETE_INS (bb, ins);
1774 continue;
1776 } else {
1777 int power2 = mono_is_power_of_two (ins->inst_imm);
1778 if (power2 > 0) {
1779 ins->opcode = OP_SHL_IMM;
1780 ins->inst_imm = power2;
1783 break;
1784 case OP_LOAD_MEMBASE:
1785 case OP_LOADI4_MEMBASE:
1787 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1788 * OP_LOAD_MEMBASE offset(basereg), reg
1790 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1791 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1792 ins->inst_basereg == last_ins->inst_destbasereg &&
1793 ins->inst_offset == last_ins->inst_offset) {
1794 if (ins->dreg == last_ins->sreg1) {
1795 MONO_DELETE_INS (bb, ins);
1796 continue;
1797 } else {
1798 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1799 ins->opcode = OP_MOVE;
1800 ins->sreg1 = last_ins->sreg1;
1802 break;
1805 * Note: reg1 must be different from the basereg in the second load
1806 * OP_LOAD_MEMBASE offset(basereg), reg1
1807 * OP_LOAD_MEMBASE offset(basereg), reg2
1808 * -->
1809 * OP_LOAD_MEMBASE offset(basereg), reg1
1810 * OP_MOVE reg1, reg2
1812 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1813 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1814 ins->inst_basereg != last_ins->dreg &&
1815 ins->inst_basereg == last_ins->inst_basereg &&
1816 ins->inst_offset == last_ins->inst_offset) {
1818 if (ins->dreg == last_ins->dreg) {
1819 MONO_DELETE_INS (bb, ins);
1820 continue;
1821 } else {
1822 ins->opcode = OP_MOVE;
1823 ins->sreg1 = last_ins->dreg;
1826 //g_assert_not_reached ();
1827 break;
1829 #if 0
1831 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1832 * OP_LOAD_MEMBASE offset(basereg), reg
1833 * -->
1834 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1835 * OP_ICONST reg, imm
1837 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1838 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1839 ins->inst_basereg == last_ins->inst_destbasereg &&
1840 ins->inst_offset == last_ins->inst_offset) {
1841 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1842 ins->opcode = OP_ICONST;
1843 ins->inst_c0 = last_ins->inst_imm;
1844 g_assert_not_reached (); // check this rule
1845 break;
1847 #endif
1848 break;
1849 case OP_LOADU1_MEMBASE:
1850 case OP_LOADI1_MEMBASE:
1851 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1852 ins->inst_basereg == last_ins->inst_destbasereg &&
1853 ins->inst_offset == last_ins->inst_offset) {
1854 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1855 ins->sreg1 = last_ins->sreg1;
1857 break;
1858 case OP_LOADU2_MEMBASE:
1859 case OP_LOADI2_MEMBASE:
1860 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1861 ins->inst_basereg == last_ins->inst_destbasereg &&
1862 ins->inst_offset == last_ins->inst_offset) {
1863 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1864 ins->sreg1 = last_ins->sreg1;
1866 break;
1867 case OP_ICONV_TO_I4:
1868 case OP_ICONV_TO_U4:
1869 case OP_MOVE:
1870 ins->opcode = OP_MOVE;
1872 * OP_MOVE reg, reg
1874 if (ins->dreg == ins->sreg1) {
1875 MONO_DELETE_INS (bb, ins);
1876 continue;
1879 * OP_MOVE sreg, dreg
1880 * OP_MOVE dreg, sreg
1882 if (last_ins && last_ins->opcode == OP_MOVE &&
1883 ins->sreg1 == last_ins->dreg &&
1884 ins->dreg == last_ins->sreg1) {
1885 MONO_DELETE_INS (bb, ins);
1886 continue;
1888 break;
1890 last_ins = ins;
1891 ins = ins->next;
1893 bb->last_ins = last_ins;
1896 void
1897 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
1899 int tmp1 = -1;
1900 int tmp2 = -1;
1901 int tmp3 = -1;
1902 int tmp4 = -1;
1903 int tmp5 = -1;
1905 switch (ins->opcode) {
1906 #if 0
1907 case OP_LCOMPARE:
1908 case OP_LCOMPARE_IMM:
1909 mono_print_ins (ins);
1910 g_assert_not_reached ();
1911 #endif
1912 case OP_LADD:
1913 tmp1 = mono_alloc_ireg (cfg);
1914 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
1915 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
1916 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
1917 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
1918 ins->opcode = OP_NOP;
1919 break;
1921 case OP_LADD_IMM:
1922 tmp1 = mono_alloc_ireg (cfg);
1923 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
1924 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
1925 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
1926 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
1927 ins->opcode = OP_NOP;
1928 break;
1930 case OP_LSUB:
1931 tmp1 = mono_alloc_ireg (cfg);
1932 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
1933 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
1934 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
1935 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
1936 ins->opcode = OP_NOP;
1937 break;
1939 case OP_LSUB_IMM:
1940 tmp1 = mono_alloc_ireg (cfg);
1941 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
1942 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
1943 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
1944 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
1945 ins->opcode = OP_NOP;
1946 break;
1948 case OP_LMUL:
1949 case OP_LDIV:
1950 case OP_LDIV_UN:
1951 case OP_LREM:
1952 case OP_LREM_UN:
1953 case OP_LSHL:
1954 case OP_LSHR:
1955 case OP_LSHR_UN:
1956 mono_print_ins (ins);
1957 g_assert_not_reached ();
1959 case OP_LNEG:
1960 tmp1 = mono_alloc_ireg (cfg);
1961 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
1962 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
1963 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
1964 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
1965 ins->opcode = OP_NOP;
1966 break;
1968 #if 0
1969 case OP_LNOT:
1970 #endif
1971 #if 0
1972 case OP_LCONV_TO_I1:
1973 case OP_LCONV_TO_I2:
1974 case OP_LCONV_TO_I4:
1975 case OP_LCONV_TO_I8:
1976 case OP_LCONV_TO_R4:
1977 case OP_LCONV_TO_R8:
1978 case OP_LCONV_TO_U4:
1979 case OP_LCONV_TO_U8:
1980 case OP_LCONV_TO_U2:
1981 case OP_LCONV_TO_U1:
1982 case OP_LCONV_TO_I:
1983 case OP_LCONV_TO_OVF_I:
1984 case OP_LCONV_TO_OVF_U:
1985 #endif
1986 mono_print_ins (ins);
1987 g_assert_not_reached ();
1989 case OP_LADD_OVF:
1990 tmp1 = mono_alloc_ireg (cfg);
1991 tmp2 = mono_alloc_ireg (cfg);
1992 tmp3 = mono_alloc_ireg (cfg);
1993 tmp4 = mono_alloc_ireg (cfg);
1994 tmp5 = mono_alloc_ireg (cfg);
1996 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
1998 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
1999 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2001 /* add the high 32-bits, and add in the carry from the low 32-bits */
2002 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2003 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2005 /* Overflow happens if
2006 * neg + neg = pos or
2007 * pos + pos = neg
2008 * XOR of the high bits returns 0 if the signs match
2009 * XOR of that with the high bit of the result return 1 if overflow.
2012 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2013 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2015 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2016 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2017 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2019 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2020 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2021 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2023 /* Now, if (tmp4 == 0) then overflow */
2024 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2025 ins->opcode = OP_NOP;
2026 break;
2028 case OP_LADD_OVF_UN:
2029 tmp1 = mono_alloc_ireg (cfg);
2030 tmp2 = mono_alloc_ireg (cfg);
2032 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2033 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2034 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2035 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2036 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2037 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2038 ins->opcode = OP_NOP;
2039 break;
2041 case OP_LMUL_OVF:
2042 case OP_LMUL_OVF_UN:
2043 mono_print_ins (ins);
2044 g_assert_not_reached ();
2046 case OP_LSUB_OVF:
2047 tmp1 = mono_alloc_ireg (cfg);
2048 tmp2 = mono_alloc_ireg (cfg);
2049 tmp3 = mono_alloc_ireg (cfg);
2050 tmp4 = mono_alloc_ireg (cfg);
2051 tmp5 = mono_alloc_ireg (cfg);
2053 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2055 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2056 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2057 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2059 /* Overflow happens if
2060 * neg - pos = pos or
2061 * pos - neg = neg
2062 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2064 * tmp1 = (lhs ^ rhs)
2065 * tmp2 = (lhs ^ result)
2066 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2069 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2070 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2071 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2072 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2074 /* Now, if (tmp4 == 1) then overflow */
2075 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2076 ins->opcode = OP_NOP;
2077 break;
2079 case OP_LSUB_OVF_UN:
2080 tmp1 = mono_alloc_ireg (cfg);
2081 tmp2 = mono_alloc_ireg (cfg);
2083 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2084 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2085 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2086 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2088 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2089 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2090 ins->opcode = OP_NOP;
2091 break;
2092 #if 0
2093 case OP_LCONV_TO_OVF_I1_UN:
2094 case OP_LCONV_TO_OVF_I2_UN:
2095 case OP_LCONV_TO_OVF_I4_UN:
2096 case OP_LCONV_TO_OVF_I8_UN:
2097 case OP_LCONV_TO_OVF_U1_UN:
2098 case OP_LCONV_TO_OVF_U2_UN:
2099 case OP_LCONV_TO_OVF_U4_UN:
2100 case OP_LCONV_TO_OVF_U8_UN:
2101 case OP_LCONV_TO_OVF_I_UN:
2102 case OP_LCONV_TO_OVF_U_UN:
2103 case OP_LCONV_TO_OVF_I1:
2104 case OP_LCONV_TO_OVF_U1:
2105 case OP_LCONV_TO_OVF_I2:
2106 case OP_LCONV_TO_OVF_U2:
2107 case OP_LCONV_TO_OVF_I4:
2108 case OP_LCONV_TO_OVF_U4:
2109 case OP_LCONV_TO_OVF_I8:
2110 case OP_LCONV_TO_OVF_U8:
2111 #endif
2112 case OP_LCEQ:
2113 case OP_LCGT:
2114 case OP_LCGT_UN:
2115 case OP_LCLT:
2116 case OP_LCLT_UN:
2117 #if 0
2118 case OP_LCONV_TO_R_UN:
2119 case OP_LCONV_TO_U:
2120 #endif
2121 case OP_LMUL_IMM:
2122 case OP_LSHL_IMM:
2123 case OP_LSHR_IMM:
2124 case OP_LSHR_UN_IMM:
2125 case OP_LDIV_IMM:
2126 case OP_LDIV_UN_IMM:
2127 case OP_LREM_IMM:
2128 case OP_LREM_UN_IMM:
2129 case OP_LBEQ:
2130 case OP_LBGE:
2131 case OP_LBGT:
2132 case OP_LBLE:
2133 case OP_LBLT:
2134 case OP_LBNE_UN:
2135 case OP_LBGE_UN:
2136 case OP_LBGT_UN:
2137 case OP_LBLE_UN:
2138 case OP_LBLT_UN:
2139 mono_print_ins (ins);
2140 g_assert_not_reached ();
2141 #if 0
2142 case OP_LCONV_TO_R8_2:
2143 case OP_LCONV_TO_R4_2:
2144 case OP_LCONV_TO_R_UN_2:
2145 #endif
2146 case OP_LCONV_TO_OVF_I4_2:
2147 tmp1 = mono_alloc_ireg (cfg);
2149 /* Overflows if reg2 != sign extension of reg1 */
2150 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2151 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2152 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2153 ins->opcode = OP_NOP;
2154 break;
2156 case OP_LMIN_UN:
2157 case OP_LMAX_UN:
2158 case OP_LMIN:
2159 case OP_LMAX:
2160 mono_print_ins (ins);
2161 g_assert_not_reached ();
2163 default:
2164 break;
2168 void
2169 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2171 int tmp1 = -1;
2172 int tmp2 = -1;
2173 int tmp3 = -1;
2174 int tmp4 = -1;
2175 int tmp5 = -1;
2177 switch (ins->opcode) {
2178 case OP_IADD_OVF:
2179 tmp1 = mono_alloc_ireg (cfg);
2180 tmp2 = mono_alloc_ireg (cfg);
2181 tmp3 = mono_alloc_ireg (cfg);
2182 tmp4 = mono_alloc_ireg (cfg);
2183 tmp5 = mono_alloc_ireg (cfg);
2185 /* add the operands */
2187 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2189 /* Overflow happens if
2190 * neg + neg = pos or
2191 * pos + pos = neg
2193 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2194 * XOR of the high bit returns 0 if the signs match
2195 * XOR of that with the high bit of the result return 1 if overflow.
2198 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2199 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2201 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2202 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2203 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2205 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2206 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2208 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2210 /* Now, if (tmp4 == 0) then overflow */
2211 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2212 ins->opcode = OP_NOP;
2213 break;
2215 case OP_IADD_OVF_UN:
2216 tmp1 = mono_alloc_ireg (cfg);
2218 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2219 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2220 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2221 ins->opcode = OP_NOP;
2222 break;
2224 case OP_ISUB_OVF:
2225 tmp1 = mono_alloc_ireg (cfg);
2226 tmp2 = mono_alloc_ireg (cfg);
2227 tmp3 = mono_alloc_ireg (cfg);
2228 tmp4 = mono_alloc_ireg (cfg);
2229 tmp5 = mono_alloc_ireg (cfg);
2231 /* add the operands */
2233 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2235 /* Overflow happens if
2236 * neg - pos = pos or
2237 * pos - neg = neg
2238 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2240 * tmp1 = (lhs ^ rhs)
2241 * tmp2 = (lhs ^ result)
2242 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2245 /* tmp3 = 1 if the signs of the two inputs differ */
2246 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2247 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2248 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2249 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2250 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2252 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2253 ins->opcode = OP_NOP;
2254 break;
2256 case OP_ISUB_OVF_UN:
2257 tmp1 = mono_alloc_ireg (cfg);
2259 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2260 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2261 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2262 ins->opcode = OP_NOP;
2263 break;
2268 static int
2269 map_to_reg_reg_op (int op)
2271 switch (op) {
2272 case OP_ADD_IMM:
2273 return OP_IADD;
2274 case OP_SUB_IMM:
2275 return OP_ISUB;
2276 case OP_AND_IMM:
2277 return OP_IAND;
2278 case OP_COMPARE_IMM:
2279 return OP_COMPARE;
2280 case OP_ICOMPARE_IMM:
2281 return OP_ICOMPARE;
2282 case OP_LCOMPARE_IMM:
2283 return OP_LCOMPARE;
2284 case OP_ADDCC_IMM:
2285 return OP_IADDCC;
2286 case OP_ADC_IMM:
2287 return OP_IADC;
2288 case OP_SUBCC_IMM:
2289 return OP_ISUBCC;
2290 case OP_SBB_IMM:
2291 return OP_ISBB;
2292 case OP_OR_IMM:
2293 return OP_IOR;
2294 case OP_XOR_IMM:
2295 return OP_IXOR;
2296 case OP_MUL_IMM:
2297 return OP_IMUL;
2298 case OP_LOAD_MEMBASE:
2299 return OP_LOAD_MEMINDEX;
2300 case OP_LOADI4_MEMBASE:
2301 return OP_LOADI4_MEMINDEX;
2302 case OP_LOADU4_MEMBASE:
2303 return OP_LOADU4_MEMINDEX;
2304 case OP_LOADU1_MEMBASE:
2305 return OP_LOADU1_MEMINDEX;
2306 case OP_LOADI2_MEMBASE:
2307 return OP_LOADI2_MEMINDEX;
2308 case OP_LOADU2_MEMBASE:
2309 return OP_LOADU2_MEMINDEX;
2310 case OP_LOADI1_MEMBASE:
2311 return OP_LOADI1_MEMINDEX;
2312 case OP_LOADR4_MEMBASE:
2313 return OP_LOADR4_MEMINDEX;
2314 case OP_LOADR8_MEMBASE:
2315 return OP_LOADR8_MEMINDEX;
2316 case OP_STOREI1_MEMBASE_REG:
2317 return OP_STOREI1_MEMINDEX;
2318 case OP_STOREI2_MEMBASE_REG:
2319 return OP_STOREI2_MEMINDEX;
2320 case OP_STOREI4_MEMBASE_REG:
2321 return OP_STOREI4_MEMINDEX;
2322 case OP_STORE_MEMBASE_REG:
2323 return OP_STORE_MEMINDEX;
2324 case OP_STORER4_MEMBASE_REG:
2325 return OP_STORER4_MEMINDEX;
2326 case OP_STORER8_MEMBASE_REG:
2327 return OP_STORER8_MEMINDEX;
2328 case OP_STORE_MEMBASE_IMM:
2329 return OP_STORE_MEMBASE_REG;
2330 case OP_STOREI1_MEMBASE_IMM:
2331 return OP_STOREI1_MEMBASE_REG;
2332 case OP_STOREI2_MEMBASE_IMM:
2333 return OP_STOREI2_MEMBASE_REG;
2334 case OP_STOREI4_MEMBASE_IMM:
2335 return OP_STOREI4_MEMBASE_REG;
2336 case OP_STOREI8_MEMBASE_IMM:
2337 return OP_STOREI8_MEMBASE_REG;
2339 return mono_op_imm_to_op (op);
2342 static int
2343 map_to_mips_op (int op)
2345 switch (op) {
2346 case OP_FBEQ:
2347 return OP_MIPS_FBEQ;
2348 case OP_FBGE:
2349 return OP_MIPS_FBGE;
2350 case OP_FBGT:
2351 return OP_MIPS_FBGT;
2352 case OP_FBLE:
2353 return OP_MIPS_FBLE;
2354 case OP_FBLT:
2355 return OP_MIPS_FBLT;
2356 case OP_FBNE_UN:
2357 return OP_MIPS_FBNE;
2358 case OP_FBGE_UN:
2359 return OP_MIPS_FBGE_UN;
2360 case OP_FBGT_UN:
2361 return OP_MIPS_FBGT_UN;
2362 case OP_FBLE_UN:
2363 return OP_MIPS_FBLE_UN;
2364 case OP_FBLT_UN:
2365 return OP_MIPS_FBLT_UN;
2367 case OP_FCEQ:
2368 case OP_FCGT:
2369 case OP_FCGT_UN:
2370 case OP_FCLT:
2371 case OP_FCLT_UN:
2372 default:
2373 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2374 g_assert_not_reached ();
2378 #define NEW_INS(cfg,after,dest,op) do { \
2379 MONO_INST_NEW((cfg), (dest), (op)); \
2380 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2381 } while (0)
2383 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2384 MonoInst *temp; \
2385 MONO_INST_NEW(cfg, temp, (op)); \
2386 mono_bblock_insert_after_ins (bb, (pos), temp); \
2387 temp->dreg = (_dreg); \
2388 temp->sreg1 = (_sreg1); \
2389 temp->sreg2 = (_sreg2); \
2390 pos = temp; \
2391 } while (0)
2393 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2394 MonoInst *temp; \
2395 MONO_INST_NEW(cfg, temp, (op)); \
2396 mono_bblock_insert_after_ins (bb, (pos), temp); \
2397 temp->dreg = (_dreg); \
2398 temp->sreg1 = (_sreg1); \
2399 temp->inst_c0 = (_imm); \
2400 pos = temp; \
2401 } while (0)
2404 * Remove from the instruction list the instructions that can't be
2405 * represented with very simple instructions with no register
2406 * requirements.
2408 void
2409 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2411 MonoInst *ins, *next, *temp, *last_ins = NULL;
2412 int imm;
2414 #if 1
2415 if (cfg->verbose_level > 2) {
2416 int idx = 0;
2418 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2419 MONO_BB_FOR_EACH_INS (bb, ins) {
2420 mono_print_ins_index (idx++, ins);
2424 #endif
2426 MONO_BB_FOR_EACH_INS (bb, ins) {
2427 loop_start:
2428 switch (ins->opcode) {
2429 case OP_COMPARE:
2430 case OP_ICOMPARE:
2431 case OP_LCOMPARE:
2432 next = ins->next;
2433 /* Branch opts can eliminate the branch */
2434 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2435 ins->opcode = OP_NOP;
2436 break;
2438 break;
2440 case OP_COMPARE_IMM:
2441 case OP_ICOMPARE_IMM:
2442 case OP_LCOMPARE_IMM:
2443 next = ins->next;
2444 /* Branch opts can eliminate the branch */
2445 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2446 ins->opcode = OP_NOP;
2447 break;
2449 if (ins->inst_imm) {
2450 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2451 temp->inst_c0 = ins->inst_imm;
2452 temp->dreg = mono_alloc_ireg (cfg);
2453 ins->sreg2 = temp->dreg;
2454 last_ins = temp;
2456 else {
2457 ins->sreg2 = mips_zero;
2459 if (ins->opcode == OP_COMPARE_IMM)
2460 ins->opcode = OP_COMPARE;
2461 else if (ins->opcode == OP_ICOMPARE_IMM)
2462 ins->opcode = OP_ICOMPARE;
2463 else if (ins->opcode == OP_LCOMPARE_IMM)
2464 ins->opcode = OP_LCOMPARE;
2465 goto loop_start;
2467 case OP_IDIV_UN_IMM:
2468 case OP_IDIV_IMM:
2469 case OP_IREM_IMM:
2470 case OP_IREM_UN_IMM:
2471 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2472 temp->inst_c0 = ins->inst_imm;
2473 temp->dreg = mono_alloc_ireg (cfg);
2474 ins->sreg2 = temp->dreg;
2475 if (ins->opcode == OP_IDIV_IMM)
2476 ins->opcode = OP_IDIV;
2477 else if (ins->opcode == OP_IREM_IMM)
2478 ins->opcode = OP_IREM;
2479 else if (ins->opcode == OP_IDIV_UN_IMM)
2480 ins->opcode = OP_IDIV_UN;
2481 else if (ins->opcode == OP_IREM_UN_IMM)
2482 ins->opcode = OP_IREM_UN;
2483 last_ins = temp;
2484 /* handle rem separately */
2485 goto loop_start;
2487 #if 0
2488 case OP_AND_IMM:
2489 case OP_OR_IMM:
2490 case OP_XOR_IMM:
2491 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2492 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2493 temp->inst_c0 = ins->inst_imm;
2494 temp->dreg = mono_alloc_ireg (cfg);
2495 ins->sreg2 = temp->dreg;
2496 ins->opcode = map_to_reg_reg_op (ins->opcode);
2498 break;
2499 #endif
2500 case OP_AND_IMM:
2501 case OP_IAND_IMM:
2502 case OP_OR_IMM:
2503 case OP_IOR_IMM:
2504 case OP_XOR_IMM:
2505 case OP_IXOR_IMM:
2506 /* unsigned 16 bit immediate */
2507 if (ins->inst_imm & 0xffff0000) {
2508 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2509 temp->inst_c0 = ins->inst_imm;
2510 temp->dreg = mono_alloc_ireg (cfg);
2511 ins->sreg2 = temp->dreg;
2512 ins->opcode = map_to_reg_reg_op (ins->opcode);
2514 break;
2516 case OP_IADD_IMM:
2517 case OP_ADD_IMM:
2518 case OP_ADDCC_IMM:
2519 /* signed 16 bit immediate */
2520 if (!mips_is_imm16 (ins->inst_imm)) {
2521 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2522 temp->inst_c0 = ins->inst_imm;
2523 temp->dreg = mono_alloc_ireg (cfg);
2524 ins->sreg2 = temp->dreg;
2525 ins->opcode = map_to_reg_reg_op (ins->opcode);
2527 break;
2529 case OP_SUB_IMM:
2530 case OP_ISUB_IMM:
2531 if (!mips_is_imm16 (-ins->inst_imm)) {
2532 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2533 temp->inst_c0 = ins->inst_imm;
2534 temp->dreg = mono_alloc_ireg (cfg);
2535 ins->sreg2 = temp->dreg;
2536 ins->opcode = map_to_reg_reg_op (ins->opcode);
2538 break;
2540 case OP_MUL_IMM:
2541 case OP_IMUL_IMM:
2542 if (ins->inst_imm == 1) {
2543 ins->opcode = OP_MOVE;
2544 break;
2546 if (ins->inst_imm == 0) {
2547 ins->opcode = OP_ICONST;
2548 ins->inst_c0 = 0;
2549 break;
2551 imm = mono_is_power_of_two (ins->inst_imm);
2552 if (imm > 0) {
2553 ins->opcode = OP_SHL_IMM;
2554 ins->inst_imm = imm;
2555 break;
2557 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2558 temp->inst_c0 = ins->inst_imm;
2559 temp->dreg = mono_alloc_ireg (cfg);
2560 ins->sreg2 = temp->dreg;
2561 ins->opcode = map_to_reg_reg_op (ins->opcode);
2562 break;
2564 case OP_LOCALLOC_IMM:
2565 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2566 temp->inst_c0 = ins->inst_imm;
2567 temp->dreg = mono_alloc_ireg (cfg);
2568 ins->sreg1 = temp->dreg;
2569 ins->opcode = OP_LOCALLOC;
2570 break;
2572 case OP_LOAD_MEMBASE:
2573 case OP_LOADI4_MEMBASE:
2574 case OP_LOADU4_MEMBASE:
2575 case OP_LOADI2_MEMBASE:
2576 case OP_LOADU2_MEMBASE:
2577 case OP_LOADI1_MEMBASE:
2578 case OP_LOADU1_MEMBASE:
2579 case OP_LOADR4_MEMBASE:
2580 case OP_LOADR8_MEMBASE:
2581 case OP_STORE_MEMBASE_REG:
2582 case OP_STOREI4_MEMBASE_REG:
2583 case OP_STOREI2_MEMBASE_REG:
2584 case OP_STOREI1_MEMBASE_REG:
2585 case OP_STORER4_MEMBASE_REG:
2586 case OP_STORER8_MEMBASE_REG:
2587 /* we can do two things: load the immed in a register
2588 * and use an indexed load, or see if the immed can be
2589 * represented as an ad_imm + a load with a smaller offset
2590 * that fits. We just do the first for now, optimize later.
2592 if (mips_is_imm16 (ins->inst_offset))
2593 break;
2594 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2595 temp->inst_c0 = ins->inst_offset;
2596 temp->dreg = mono_alloc_ireg (cfg);
2597 ins->sreg2 = temp->dreg;
2598 ins->opcode = map_to_reg_reg_op (ins->opcode);
2599 break;
2601 case OP_STORE_MEMBASE_IMM:
2602 case OP_STOREI1_MEMBASE_IMM:
2603 case OP_STOREI2_MEMBASE_IMM:
2604 case OP_STOREI4_MEMBASE_IMM:
2605 case OP_STOREI8_MEMBASE_IMM:
2606 if (!ins->inst_imm) {
2607 ins->sreg1 = mips_zero;
2608 ins->opcode = map_to_reg_reg_op (ins->opcode);
2610 else {
2611 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2612 temp->inst_c0 = ins->inst_imm;
2613 temp->dreg = mono_alloc_ireg (cfg);
2614 ins->sreg1 = temp->dreg;
2615 ins->opcode = map_to_reg_reg_op (ins->opcode);
2616 last_ins = temp;
2617 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2619 break;
2621 case OP_FCOMPARE:
2622 next = ins->next;
2623 /* Branch opts can eliminate the branch */
2624 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2625 ins->opcode = OP_NOP;
2626 break;
2628 g_assert(next);
2631 * remap compare/branch and compare/set
2632 * to MIPS specific opcodes.
2634 ins->opcode = OP_NOP;
2635 next->opcode = map_to_mips_op (next->opcode);
2636 next->sreg1 = ins->sreg1;
2637 next->sreg2 = ins->sreg2;
2638 break;
2640 #if 0
2641 case OP_R8CONST:
2642 case OP_R4CONST:
2643 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2644 temp->inst_c0 = (guint32)ins->inst_p0;
2645 temp->dreg = mono_alloc_ireg (cfg);
2646 ins->inst_basereg = temp->dreg;
2647 ins->inst_offset = 0;
2648 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2649 last_ins = temp;
2650 /* make it handle the possibly big ins->inst_offset
2651 * later optimize to use lis + load_membase
2653 goto loop_start;
2654 #endif
2655 case OP_IBEQ:
2656 g_assert (ins_is_compare(last_ins));
2657 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2658 last_ins->opcode = OP_NOP;
2659 break;
2661 case OP_IBNE_UN:
2662 g_assert (ins_is_compare(last_ins));
2663 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2664 last_ins->opcode = OP_NOP;
2665 break;
2667 case OP_IBGE:
2668 g_assert (ins_is_compare(last_ins));
2669 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2670 last_ins->dreg = mono_alloc_ireg (cfg);
2671 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2672 break;
2674 case OP_IBGE_UN:
2675 g_assert (ins_is_compare(last_ins));
2676 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2677 last_ins->dreg = mono_alloc_ireg (cfg);
2678 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2679 break;
2681 case OP_IBLT:
2682 g_assert (ins_is_compare(last_ins));
2683 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2684 last_ins->dreg = mono_alloc_ireg (cfg);
2685 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2686 break;
2688 case OP_IBLT_UN:
2689 g_assert (ins_is_compare(last_ins));
2690 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2691 last_ins->dreg = mono_alloc_ireg (cfg);
2692 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2693 break;
2695 case OP_IBLE:
2696 g_assert (ins_is_compare(last_ins));
2697 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2698 last_ins->dreg = mono_alloc_ireg (cfg);
2699 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2700 break;
2702 case OP_IBLE_UN:
2703 g_assert (ins_is_compare(last_ins));
2704 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2705 last_ins->dreg = mono_alloc_ireg (cfg);
2706 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2707 break;
2709 case OP_IBGT:
2710 g_assert (ins_is_compare(last_ins));
2711 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2712 last_ins->dreg = mono_alloc_ireg (cfg);
2713 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2714 break;
2716 case OP_IBGT_UN:
2717 g_assert (ins_is_compare(last_ins));
2718 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2719 last_ins->dreg = mono_alloc_ireg (cfg);
2720 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2721 break;
2723 case OP_CEQ:
2724 case OP_ICEQ:
2725 g_assert (ins_is_compare(last_ins));
2726 last_ins->opcode = OP_IXOR;
2727 last_ins->dreg = mono_alloc_ireg(cfg);
2728 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2729 break;
2731 case OP_CLT:
2732 case OP_ICLT:
2733 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2734 last_ins->opcode = OP_NOP;
2735 break;
2738 case OP_CLT_UN:
2739 case OP_ICLT_UN:
2740 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2741 last_ins->opcode = OP_NOP;
2742 break;
2744 case OP_CGT:
2745 case OP_ICGT:
2746 g_assert (ins_is_compare(last_ins));
2747 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2748 MONO_DELETE_INS(bb, last_ins);
2749 break;
2751 case OP_CGT_UN:
2752 case OP_ICGT_UN:
2753 g_assert (ins_is_compare(last_ins));
2754 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2755 MONO_DELETE_INS(bb, last_ins);
2756 break;
2758 case OP_COND_EXC_EQ:
2759 case OP_COND_EXC_IEQ:
2760 g_assert (ins_is_compare(last_ins));
2761 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
2762 MONO_DELETE_INS(bb, last_ins);
2763 break;
2765 case OP_COND_EXC_GE:
2766 case OP_COND_EXC_IGE:
2767 g_assert (ins_is_compare(last_ins));
2768 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
2769 MONO_DELETE_INS(bb, last_ins);
2770 break;
2772 case OP_COND_EXC_GT:
2773 case OP_COND_EXC_IGT:
2774 g_assert (ins_is_compare(last_ins));
2775 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
2776 MONO_DELETE_INS(bb, last_ins);
2777 break;
2779 case OP_COND_EXC_LE:
2780 case OP_COND_EXC_ILE:
2781 g_assert (ins_is_compare(last_ins));
2782 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
2783 MONO_DELETE_INS(bb, last_ins);
2784 break;
2786 case OP_COND_EXC_LT:
2787 case OP_COND_EXC_ILT:
2788 g_assert (ins_is_compare(last_ins));
2789 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
2790 MONO_DELETE_INS(bb, last_ins);
2791 break;
2793 case OP_COND_EXC_NE_UN:
2794 case OP_COND_EXC_INE_UN:
2795 g_assert (ins_is_compare(last_ins));
2796 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
2797 MONO_DELETE_INS(bb, last_ins);
2798 break;
2800 case OP_COND_EXC_GE_UN:
2801 case OP_COND_EXC_IGE_UN:
2802 g_assert (ins_is_compare(last_ins));
2803 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
2804 MONO_DELETE_INS(bb, last_ins);
2805 break;
2807 case OP_COND_EXC_GT_UN:
2808 case OP_COND_EXC_IGT_UN:
2809 g_assert (ins_is_compare(last_ins));
2810 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
2811 MONO_DELETE_INS(bb, last_ins);
2812 break;
2814 case OP_COND_EXC_LE_UN:
2815 case OP_COND_EXC_ILE_UN:
2816 g_assert (ins_is_compare(last_ins));
2817 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
2818 MONO_DELETE_INS(bb, last_ins);
2819 break;
2821 case OP_COND_EXC_LT_UN:
2822 case OP_COND_EXC_ILT_UN:
2823 g_assert (ins_is_compare(last_ins));
2824 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
2825 MONO_DELETE_INS(bb, last_ins);
2826 break;
2828 case OP_COND_EXC_OV:
2829 case OP_COND_EXC_IOV: {
2830 int tmp1, tmp2, tmp3, tmp4, tmp5;
2831 MonoInst *pos = last_ins;
2833 /* Overflow happens if
2834 * neg + neg = pos or
2835 * pos + pos = neg
2837 * (bit31s of operands match) AND (bit31 of operand
2838 * != bit31 of result)
2839 * XOR of the high bit returns 0 if the signs match
2840 * XOR of that with the high bit of the result return 1
2841 * if overflow.
2843 g_assert (last_ins->opcode == OP_IADC);
2845 tmp1 = mono_alloc_ireg (cfg);
2846 tmp2 = mono_alloc_ireg (cfg);
2847 tmp3 = mono_alloc_ireg (cfg);
2848 tmp4 = mono_alloc_ireg (cfg);
2849 tmp5 = mono_alloc_ireg (cfg);
2851 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2852 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
2854 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2855 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
2856 INS (pos, OP_INOT, tmp3, tmp2, -1);
2858 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2859 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
2860 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
2862 /* Now, if (tmp5 == 0) then overflow */
2863 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
2864 ins->dreg = -1;
2865 break;
2868 case OP_COND_EXC_NO:
2869 case OP_COND_EXC_INO:
2870 g_assert_not_reached ();
2871 break;
2873 case OP_COND_EXC_C:
2874 case OP_COND_EXC_IC:
2875 g_assert_not_reached ();
2876 break;
2878 case OP_COND_EXC_NC:
2879 case OP_COND_EXC_INC:
2880 g_assert_not_reached ();
2881 break;
2884 last_ins = ins;
2886 bb->last_ins = last_ins;
2887 bb->max_vreg = cfg->next_vreg;
2889 #if 1
2890 if (cfg->verbose_level > 2) {
2891 int idx = 0;
2893 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
2894 MONO_BB_FOR_EACH_INS (bb, ins) {
2895 mono_print_ins_index (idx++, ins);
2899 #endif
2903 static guchar*
2904 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2906 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
2907 #if 1
2908 mips_truncwd (code, mips_ftemp, sreg);
2909 #else
2910 mips_cvtwd (code, mips_ftemp, sreg);
2911 #endif
2912 mips_mfc1 (code, dreg, mips_ftemp);
2913 if (!is_signed) {
2914 if (size == 1)
2915 mips_andi (code, dreg, dreg, 0xff);
2916 else if (size == 2) {
2917 mips_sll (code, dreg, dreg, 16);
2918 mips_srl (code, dreg, dreg, 16);
2920 } else {
2921 if (size == 1) {
2922 mips_sll (code, dreg, dreg, 24);
2923 mips_sra (code, dreg, dreg, 24);
2925 else if (size == 2) {
2926 mips_sll (code, dreg, dreg, 16);
2927 mips_sra (code, dreg, dreg, 16);
2930 return code;
2934 * emit_load_volatile_arguments:
2936 * Load volatile arguments from the stack to the original input registers.
2937 * Required before a tail call.
2939 static guint8 *
2940 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
2942 MonoMethod *method = cfg->method;
2943 MonoMethodSignature *sig;
2944 MonoInst *inst;
2945 CallInfo *cinfo;
2946 int i;
2948 sig = mono_method_signature (method);
2949 cinfo = calculate_sizes (sig, sig->pinvoke);
2950 if (cinfo->struct_ret) {
2951 ArgInfo *ainfo = &cinfo->ret;
2952 inst = cfg->vret_addr;
2953 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2956 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2957 ArgInfo *ainfo = cinfo->args + i;
2958 inst = cfg->args [i];
2959 if (inst->opcode == OP_REGVAR) {
2960 if (ainfo->regtype == RegTypeGeneral)
2961 MIPS_MOVE (code, ainfo->reg, inst->dreg);
2962 else if (ainfo->regtype == RegTypeFP)
2963 g_assert_not_reached();
2964 else if (ainfo->regtype == RegTypeBase) {
2965 /* do nothing */
2966 } else
2967 g_assert_not_reached ();
2968 } else {
2969 if (ainfo->regtype == RegTypeGeneral) {
2970 g_assert (mips_is_imm16 (inst->inst_offset));
2971 switch (ainfo->size) {
2972 case 1:
2973 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2974 break;
2975 case 2:
2976 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2977 break;
2978 case 0: /* XXX */
2979 case 4:
2980 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2981 break;
2982 case 8:
2983 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2984 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
2985 break;
2986 default:
2987 g_assert_not_reached ();
2988 break;
2990 } else if (ainfo->regtype == RegTypeBase) {
2991 /* do nothing */
2992 } else if (ainfo->regtype == RegTypeFP) {
2993 g_assert (mips_is_imm16 (inst->inst_offset));
2994 if (ainfo->size == 8) {
2995 #if _MIPS_SIM == _ABIO32
2996 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
2997 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
2998 #elif _MIPS_SIM == _ABIN32
2999 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3000 #endif
3002 else if (ainfo->size == 4)
3003 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3004 else
3005 g_assert_not_reached ();
3006 } else if (ainfo->regtype == RegTypeStructByVal) {
3007 int i;
3008 int doffset = inst->inst_offset;
3010 g_assert (mips_is_imm16 (inst->inst_offset));
3011 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3012 for (i = 0; i < ainfo->size; ++i) {
3013 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3014 doffset += SIZEOF_REGISTER;
3016 } else if (ainfo->regtype == RegTypeStructByAddr) {
3017 g_assert (mips_is_imm16 (inst->inst_offset));
3018 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3019 } else
3020 g_assert_not_reached ();
3024 g_free (cinfo);
3026 return code;
3029 static guint8*
3030 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3032 int size = cfg->param_area;
3034 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3035 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3037 if (!size)
3038 return code;
3039 #if 0
3040 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3041 if (ppc_is_imm16 (-size)) {
3042 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3043 } else {
3044 ppc_load (code, ppc_r11, -size);
3045 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3047 #endif
3048 return code;
3051 static guint8*
3052 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3054 int size = cfg->param_area;
3056 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3057 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3059 if (!size)
3060 return code;
3061 #if 0
3062 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3063 if (ppc_is_imm16 (size)) {
3064 ppc_stwu (code, ppc_r0, size, ppc_sp);
3065 } else {
3066 ppc_load (code, ppc_r11, size);
3067 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3069 #endif
3070 return code;
3073 void
3074 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3076 MonoInst *ins;
3077 MonoCallInst *call;
3078 guint offset;
3079 guint8 *code = cfg->native_code + cfg->code_len;
3080 MonoInst *last_ins = NULL;
3081 guint last_offset = 0;
3082 int max_len, cpos;
3083 int ins_cnt = 0;
3085 /* we don't align basic blocks of loops on mips */
3087 if (cfg->verbose_level > 2)
3088 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3090 cpos = bb->max_offset;
3092 #if 0
3093 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3094 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3095 g_assert (!mono_compile_aot);
3096 cpos += 20;
3097 if (bb->cil_code)
3098 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3099 /* this is not thread save, but good enough */
3100 /* fixme: howto handle overflows? */
3101 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3102 mips_lw (code, mips_temp, mips_at, 0);
3103 mips_addiu (code, mips_temp, mips_temp, 1);
3104 mips_sw (code, mips_temp, mips_at, 0);
3106 #endif
3107 MONO_BB_FOR_EACH_INS (bb, ins) {
3108 offset = code - cfg->native_code;
3110 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3112 if (offset > (cfg->code_size - max_len - 16)) {
3113 cfg->code_size *= 2;
3114 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3115 code = cfg->native_code + offset;
3117 mono_debug_record_line_number (cfg, ins, offset);
3118 if (cfg->verbose_level > 2) {
3119 g_print (" @ 0x%x\t", offset);
3120 mono_print_ins_index (ins_cnt++, ins);
3122 /* Check for virtual regs that snuck by */
3123 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3125 switch (ins->opcode) {
3126 case OP_RELAXED_NOP:
3127 case OP_NOP:
3128 case OP_DUMMY_USE:
3129 case OP_DUMMY_STORE:
3130 case OP_NOT_REACHED:
3131 case OP_NOT_NULL:
3132 break;
3133 case OP_TLS_GET:
3134 g_assert_not_reached();
3135 #if 0
3136 emit_tls_access (code, ins->dreg, ins->inst_offset);
3137 #endif
3138 break;
3139 case OP_BIGMUL:
3140 mips_mult (code, ins->sreg1, ins->sreg2);
3141 mips_mflo (code, ins->dreg);
3142 mips_mfhi (code, ins->dreg+1);
3143 break;
3144 case OP_BIGMUL_UN:
3145 mips_multu (code, ins->sreg1, ins->sreg2);
3146 mips_mflo (code, ins->dreg);
3147 mips_mfhi (code, ins->dreg+1);
3148 break;
3149 case OP_MEMORY_BARRIER:
3150 #if 0
3151 ppc_sync (code);
3152 #endif
3153 break;
3154 case OP_STOREI1_MEMBASE_IMM:
3155 mips_load_const (code, mips_temp, ins->inst_imm);
3156 if (mips_is_imm16 (ins->inst_offset)) {
3157 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3158 } else {
3159 mips_load_const (code, mips_at, ins->inst_offset);
3160 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3162 break;
3163 case OP_STOREI2_MEMBASE_IMM:
3164 mips_load_const (code, mips_temp, ins->inst_imm);
3165 if (mips_is_imm16 (ins->inst_offset)) {
3166 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3167 } else {
3168 mips_load_const (code, mips_at, ins->inst_offset);
3169 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3171 break;
3172 case OP_STOREI8_MEMBASE_IMM:
3173 mips_load_const (code, mips_temp, ins->inst_imm);
3174 if (mips_is_imm16 (ins->inst_offset)) {
3175 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3176 } else {
3177 mips_load_const (code, mips_at, ins->inst_offset);
3178 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3180 break;
3181 case OP_STORE_MEMBASE_IMM:
3182 case OP_STOREI4_MEMBASE_IMM:
3183 mips_load_const (code, mips_temp, ins->inst_imm);
3184 if (mips_is_imm16 (ins->inst_offset)) {
3185 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3186 } else {
3187 mips_load_const (code, mips_at, ins->inst_offset);
3188 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3190 break;
3191 case OP_STOREI1_MEMBASE_REG:
3192 if (mips_is_imm16 (ins->inst_offset)) {
3193 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3194 } else {
3195 mips_load_const (code, mips_at, ins->inst_offset);
3196 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3197 mips_sb (code, ins->sreg1, mips_at, 0);
3199 break;
3200 case OP_STOREI2_MEMBASE_REG:
3201 if (mips_is_imm16 (ins->inst_offset)) {
3202 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3203 } else {
3204 mips_load_const (code, mips_at, ins->inst_offset);
3205 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3206 mips_sh (code, ins->sreg1, mips_at, 0);
3208 break;
3209 case OP_STORE_MEMBASE_REG:
3210 case OP_STOREI4_MEMBASE_REG:
3211 if (mips_is_imm16 (ins->inst_offset)) {
3212 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3213 } else {
3214 mips_load_const (code, mips_at, ins->inst_offset);
3215 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3216 mips_sw (code, ins->sreg1, mips_at, 0);
3218 break;
3219 case OP_STOREI8_MEMBASE_REG:
3220 if (mips_is_imm16 (ins->inst_offset)) {
3221 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3222 } else {
3223 mips_load_const (code, mips_at, ins->inst_offset);
3224 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3225 mips_sd (code, ins->sreg1, mips_at, 0);
3227 break;
3228 case OP_LOADU4_MEM:
3229 g_assert_not_reached ();
3230 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3231 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3232 break;
3233 case OP_LOADI8_MEMBASE:
3234 if (mips_is_imm16 (ins->inst_offset)) {
3235 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3236 } else {
3237 mips_load_const (code, mips_at, ins->inst_offset);
3238 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3239 mips_ld (code, ins->dreg, mips_at, 0);
3241 break;
3242 case OP_LOAD_MEMBASE:
3243 case OP_LOADI4_MEMBASE:
3244 case OP_LOADU4_MEMBASE:
3245 if (mips_is_imm16 (ins->inst_offset)) {
3246 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3247 } else {
3248 mips_load_const (code, mips_at, ins->inst_offset);
3249 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3250 mips_lw (code, ins->dreg, mips_at, 0);
3252 break;
3253 case OP_LOADI1_MEMBASE:
3254 if (mips_is_imm16 (ins->inst_offset)) {
3255 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3256 } else {
3257 mips_load_const (code, mips_at, ins->inst_offset);
3258 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3259 mips_lb (code, ins->dreg, mips_at, 0);
3261 break;
3262 case OP_LOADU1_MEMBASE:
3263 if (mips_is_imm16 (ins->inst_offset)) {
3264 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3265 } else {
3266 mips_load_const (code, mips_at, ins->inst_offset);
3267 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3268 mips_lbu (code, ins->dreg, mips_at, 0);
3270 break;
3271 case OP_LOADI2_MEMBASE:
3272 if (mips_is_imm16 (ins->inst_offset)) {
3273 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3274 } else {
3275 mips_load_const (code, mips_at, ins->inst_offset);
3276 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3277 mips_lh (code, ins->dreg, mips_at, 0);
3279 break;
3280 case OP_LOADU2_MEMBASE:
3281 if (mips_is_imm16 (ins->inst_offset)) {
3282 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3283 } else {
3284 mips_load_const (code, mips_at, ins->inst_offset);
3285 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3286 mips_lhu (code, ins->dreg, mips_at, 0);
3288 break;
3289 case OP_ICONV_TO_I1:
3290 mips_sll (code, mips_at, ins->sreg1, 24);
3291 mips_sra (code, ins->dreg, mips_at, 24);
3292 break;
3293 case OP_ICONV_TO_I2:
3294 mips_sll (code, mips_at, ins->sreg1, 16);
3295 mips_sra (code, ins->dreg, mips_at, 16);
3296 break;
3297 case OP_ICONV_TO_U1:
3298 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3299 break;
3300 case OP_ICONV_TO_U2:
3301 mips_sll (code, mips_at, ins->sreg1, 16);
3302 mips_srl (code, ins->dreg, mips_at, 16);
3303 break;
3304 case OP_MIPS_SLT:
3305 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3306 break;
3307 case OP_MIPS_SLTI:
3308 g_assert (mips_is_imm16 (ins->inst_imm));
3309 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3310 break;
3311 case OP_MIPS_SLTU:
3312 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3313 break;
3314 case OP_MIPS_SLTIU:
3315 g_assert (mips_is_imm16 (ins->inst_imm));
3316 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3317 break;
3318 case OP_BREAK:
3319 mips_break (code, 0xfd);
3320 break;
3321 case OP_IADD:
3322 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3323 break;
3324 case OP_LADD:
3325 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3326 break;
3328 case OP_ADD_IMM:
3329 case OP_IADD_IMM:
3330 g_assert (mips_is_imm16 (ins->inst_imm));
3331 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3332 break;
3333 case OP_LADD_IMM:
3334 g_assert (mips_is_imm16 (ins->inst_imm));
3335 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3336 break;
3338 case OP_ISUB:
3339 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3340 break;
3341 case OP_LSUB:
3342 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3343 break;
3345 case OP_ISUB_IMM:
3346 case OP_SUB_IMM:
3347 // we add the negated value
3348 g_assert (mips_is_imm16 (-ins->inst_imm));
3349 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3350 break;
3352 case OP_LSUB_IMM:
3353 // we add the negated value
3354 g_assert (mips_is_imm16 (-ins->inst_imm));
3355 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3356 break;
3358 case OP_IAND:
3359 case OP_LAND:
3360 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3361 break;
3363 case OP_AND_IMM:
3364 case OP_IAND_IMM:
3365 case OP_LAND_IMM:
3366 g_assert (!(ins->inst_imm & 0xffff0000));
3367 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3368 break;
3370 case OP_IDIV:
3371 case OP_IREM: {
3372 guint32 *divisor_is_m1;
3373 guint32 *divisor_is_zero;
3375 /* */
3376 mips_addiu (code, mips_at, mips_zero, 0xffff);
3377 divisor_is_m1 = (guint32 *)(void *)code;
3378 mips_bne (code, ins->sreg2, mips_at, 0);
3379 mips_nop (code);
3381 /* Divide by -1 -- throw exception */
3382 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
3384 mips_patch (divisor_is_m1, (guint32)code);
3386 /* Put divide in branch delay slot (NOT YET) */
3387 divisor_is_zero = (guint32 *)(void *)code;
3388 mips_bne (code, ins->sreg2, mips_zero, 0);
3389 mips_nop (code);
3391 /* Divide by zero -- throw exception */
3392 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3394 mips_patch (divisor_is_zero, (guint32)code);
3395 mips_div (code, ins->sreg1, ins->sreg2);
3396 if (ins->opcode == OP_IDIV)
3397 mips_mflo (code, ins->dreg);
3398 else
3399 mips_mfhi (code, ins->dreg);
3400 break;
3402 case OP_IDIV_UN:
3403 case OP_IREM_UN: {
3404 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3406 /* Put divide in branch delay slot (NOT YET) */
3407 mips_bne (code, ins->sreg2, mips_zero, 0);
3408 mips_nop (code);
3410 /* Divide by zero -- throw exception */
3411 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3413 mips_patch (divisor_is_zero, (guint32)code);
3414 mips_divu (code, ins->sreg1, ins->sreg2);
3415 if (ins->opcode == OP_IDIV_UN)
3416 mips_mflo (code, ins->dreg);
3417 else
3418 mips_mfhi (code, ins->dreg);
3419 break;
3421 case OP_DIV_IMM:
3422 g_assert_not_reached ();
3423 #if 0
3424 ppc_load (code, ppc_r11, ins->inst_imm);
3425 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
3426 ppc_mfspr (code, ppc_r0, ppc_xer);
3427 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3428 /* FIXME: use OverflowException for 0x80000000/-1 */
3429 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3430 #endif
3431 g_assert_not_reached();
3432 break;
3433 case OP_REM_IMM:
3434 g_assert_not_reached ();
3435 case OP_IOR:
3436 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3437 break;
3438 case OP_OR_IMM:
3439 case OP_IOR_IMM:
3440 g_assert (!(ins->inst_imm & 0xffff0000));
3441 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3442 break;
3443 case OP_IXOR:
3444 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3445 break;
3446 case OP_XOR_IMM:
3447 case OP_IXOR_IMM:
3448 /* unsigned 16-bit immediate */
3449 g_assert (!(ins->inst_imm & 0xffff0000));
3450 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3451 break;
3452 case OP_ISHL:
3453 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3454 break;
3455 case OP_SHL_IMM:
3456 case OP_ISHL_IMM:
3457 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3458 break;
3459 case OP_ISHR:
3460 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3461 break;
3462 case OP_LSHR:
3463 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3464 break;
3465 case OP_SHR_IMM:
3466 case OP_ISHR_IMM:
3467 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3468 break;
3469 case OP_LSHR_IMM:
3470 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3471 break;
3472 case OP_SHR_UN_IMM:
3473 case OP_ISHR_UN_IMM:
3474 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3475 break;
3476 case OP_LSHR_UN_IMM:
3477 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3478 break;
3479 case OP_ISHR_UN:
3480 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3481 break;
3482 case OP_LSHR_UN:
3483 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3484 break;
3485 case OP_INOT:
3486 case OP_LNOT:
3487 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3488 break;
3489 case OP_INEG:
3490 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3491 break;
3492 case OP_LNEG:
3493 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3494 break;
3495 case OP_IMUL:
3496 #if USE_MUL
3497 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3498 #else
3499 mips_mult (code, ins->sreg1, ins->sreg2);
3500 mips_mflo (code, ins->dreg);
3501 mips_nop (code);
3502 mips_nop (code);
3503 #endif
3504 break;
3505 #if SIZEOF_REGISTER == 8
3506 case OP_LMUL:
3507 mips_dmult (code, ins->sreg1, ins->sreg2);
3508 mips_mflo (code, ins->dreg);
3509 break;
3510 #endif
3511 case OP_IMUL_OVF: {
3512 guint32 *patch;
3513 mips_mult (code, ins->sreg1, ins->sreg2);
3514 mips_mflo (code, ins->dreg);
3515 mips_mfhi (code, mips_at);
3516 mips_nop (code);
3517 mips_nop (code);
3518 mips_sra (code, mips_temp, ins->dreg, 31);
3519 patch = (guint32 *)(void *)code;
3520 mips_beq (code, mips_temp, mips_at, 0);
3521 mips_nop (code);
3522 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3523 mips_patch (patch, (guint32)code);
3524 break;
3526 case OP_IMUL_OVF_UN:
3527 #if 0
3528 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3529 #else
3530 mips_mult (code, ins->sreg1, ins->sreg2);
3531 mips_mflo (code, ins->dreg);
3532 mips_mfhi (code, mips_at);
3533 mips_nop (code);
3534 mips_nop (code);
3535 #endif
3536 /* XXX - Throw exception if we overflowed */
3537 break;
3538 case OP_ICONST:
3539 mips_load_const (code, ins->dreg, ins->inst_c0);
3540 break;
3541 #if SIZEOF_REGISTER == 8
3542 case OP_I8CONST:
3543 mips_load_const (code, ins->dreg, ins->inst_c0);
3544 break;
3545 #endif
3546 case OP_AOTCONST:
3547 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3548 mips_load (code, ins->dreg, 0);
3549 break;
3551 case OP_MIPS_MTC1S:
3552 mips_mtc1 (code, ins->dreg, ins->sreg1);
3553 break;
3554 case OP_MIPS_MTC1S_2:
3555 mips_mtc1 (code, ins->dreg, ins->sreg1);
3556 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3557 break;
3558 case OP_MIPS_MFC1S:
3559 mips_mfc1 (code, ins->dreg, ins->sreg1);
3560 break;
3561 case OP_MIPS_MTC1D:
3562 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3563 break;
3564 case OP_MIPS_MFC1D:
3565 #if 0
3566 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3567 #else
3568 mips_mfc1 (code, ins->dreg+1, ins->sreg1);
3569 mips_mfc1 (code, ins->dreg, ins->sreg1+1);
3570 #endif
3571 break;
3573 case OP_ICONV_TO_I4:
3574 case OP_ICONV_TO_U4:
3575 case OP_MOVE:
3576 if (ins->dreg != ins->sreg1)
3577 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3578 break;
3579 #if SIZEOF_REGISTER == 8
3580 case OP_ZEXT_I4:
3581 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3582 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3583 break;
3584 case OP_SEXT_I4:
3585 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3586 mips_dsra (code, ins->dreg, ins->dreg, 32);
3587 break;
3588 #endif
3589 case OP_SETLRET:
3590 /* Get sreg1 into v1, sreg2 into v0 */
3592 if (ins->sreg1 == mips_v0) {
3593 if (ins->sreg1 != mips_at)
3594 MIPS_MOVE (code, mips_at, ins->sreg1);
3595 if (ins->sreg2 != mips_v0)
3596 MIPS_MOVE (code, mips_v0, ins->sreg2);
3597 MIPS_MOVE (code, mips_v1, mips_at);
3599 else {
3600 if (ins->sreg2 != mips_v0)
3601 MIPS_MOVE (code, mips_v0, ins->sreg2);
3602 if (ins->sreg1 != mips_v1)
3603 MIPS_MOVE (code, mips_v1, ins->sreg1);
3605 break;
3606 case OP_FMOVE:
3607 if (ins->dreg != ins->sreg1) {
3608 mips_fmovd (code, ins->dreg, ins->sreg1);
3610 break;
3611 case OP_MIPS_CVTSD:
3612 /* Convert from double to float and leave it there */
3613 mips_cvtsd (code, ins->dreg, ins->sreg1);
3614 break;
3615 case OP_FCONV_TO_R4:
3616 #if 0
3617 mips_cvtsd (code, ins->dreg, ins->sreg1);
3618 #else
3619 /* Just a move, no precision change */
3620 if (ins->dreg != ins->sreg1) {
3621 mips_fmovd (code, ins->dreg, ins->sreg1);
3623 #endif
3624 break;
3625 case OP_JMP:
3626 code = emit_load_volatile_arguments(cfg, code);
3629 * Pop our stack, then jump to specified method (tail-call)
3630 * Keep in sync with mono_arch_emit_epilog
3632 code = mono_arch_emit_epilog_sub (cfg, code);
3634 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3635 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3636 #if LONG_BRANCH
3637 mips_lui (code, mips_t9, mips_zero, 0);
3638 mips_addiu (code, mips_t9, mips_t9, 0);
3639 mips_jr (code, mips_t9);
3640 mips_nop (code);
3641 #else
3642 mips_beq (code, mips_zero, mips_zero, 0);
3643 mips_nop (code);
3644 #endif
3645 break;
3646 case OP_CHECK_THIS:
3647 /* ensure ins->sreg1 is not NULL */
3648 mips_lw (code, mips_zero, ins->sreg1, 0);
3649 break;
3650 case OP_ARGLIST: {
3651 if (mips_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3652 mips_addiu (code, mips_at, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3653 } else {
3654 mips_load_const (code, mips_at, cfg->sig_cookie + cfg->stack_usage);
3655 mips_addu (code, mips_at, cfg->frame_reg, mips_at);
3657 mips_sw (code, mips_at, ins->sreg1, 0);
3658 break;
3660 case OP_FCALL:
3661 case OP_LCALL:
3662 case OP_VCALL:
3663 case OP_VCALL2:
3664 case OP_VOIDCALL:
3665 case OP_CALL:
3666 case OP_FCALL_REG:
3667 case OP_LCALL_REG:
3668 case OP_VCALL_REG:
3669 case OP_VCALL2_REG:
3670 case OP_VOIDCALL_REG:
3671 case OP_CALL_REG:
3672 case OP_FCALL_MEMBASE:
3673 case OP_LCALL_MEMBASE:
3674 case OP_VCALL_MEMBASE:
3675 case OP_VCALL2_MEMBASE:
3676 case OP_VOIDCALL_MEMBASE:
3677 case OP_CALL_MEMBASE:
3678 call = (MonoCallInst*)ins;
3679 switch (ins->opcode) {
3680 case OP_FCALL:
3681 case OP_LCALL:
3682 case OP_VCALL:
3683 case OP_VCALL2:
3684 case OP_VOIDCALL:
3685 case OP_CALL:
3686 if (ins->flags & MONO_INST_HAS_METHOD)
3687 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3688 else
3689 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3690 mips_lui (code, mips_t9, mips_zero, 0);
3691 mips_addiu (code, mips_t9, mips_t9, 0);
3692 break;
3693 case OP_FCALL_REG:
3694 case OP_LCALL_REG:
3695 case OP_VCALL_REG:
3696 case OP_VCALL2_REG:
3697 case OP_VOIDCALL_REG:
3698 case OP_CALL_REG:
3699 MIPS_MOVE (code, mips_t9, ins->sreg1);
3700 break;
3701 case OP_FCALL_MEMBASE:
3702 case OP_LCALL_MEMBASE:
3703 case OP_VCALL_MEMBASE:
3704 case OP_VCALL2_MEMBASE:
3705 case OP_VOIDCALL_MEMBASE:
3706 case OP_CALL_MEMBASE:
3707 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3708 break;
3710 mips_jalr (code, mips_t9, mips_ra);
3711 mips_nop (code);
3712 #if PROMOTE_R4_TO_R8
3713 /* returned an FP R4 (single), promote to R8 (double) in place */
3714 if ((ins->opcode == OP_FCALL ||
3715 ins->opcode == OP_FCALL_REG) &&
3716 call->signature->ret->type == MONO_TYPE_R4) {
3717 mips_cvtds (code, mips_f0, mips_f0);
3719 #endif
3720 break;
3721 case OP_LOCALLOC: {
3722 int area_offset = cfg->param_area;
3724 /* Round up ins->sreg1, mips_at ends up holding size */
3725 mips_addiu (code, mips_at, ins->sreg1, 31);
3726 mips_addiu (code, mips_temp, mips_zero, ~31);
3727 mips_and (code, mips_at, mips_at, mips_temp);
3729 mips_subu (code, mips_sp, mips_sp, mips_at);
3730 g_assert (mips_is_imm16 (area_offset));
3731 mips_addiu (code, ins->dreg, mips_sp, area_offset);
3733 if (ins->flags & MONO_INST_INIT) {
3734 mips_move (code, mips_temp, ins->dreg);
3735 mips_sb (code, mips_zero, mips_temp, 0);
3736 mips_addiu (code, mips_at, mips_at, -1);
3737 mips_bne (code, mips_at, mips_zero, -3);
3738 mips_addiu (code, mips_temp, mips_temp, 1);
3740 break;
3742 case OP_THROW: {
3743 gpointer addr = mono_arch_get_throw_exception();
3744 mips_move (code, mips_a0, ins->sreg1);
3745 mips_load_const (code, mips_t9, addr);
3746 mips_jalr (code, mips_t9, mips_ra);
3747 mips_nop (code);
3748 mips_break (code, 0xfc);
3749 break;
3751 case OP_RETHROW: {
3752 gpointer addr = mono_arch_get_rethrow_exception();
3753 mips_move (code, mips_a0, ins->sreg1);
3754 mips_load_const (code, mips_t9, addr);
3755 mips_jalr (code, mips_t9, mips_ra);
3756 mips_nop (code);
3757 mips_break (code, 0xfb);
3758 break;
3760 case OP_START_HANDLER: {
3762 * The START_HANDLER instruction marks the beginning of
3763 * a handler block. It is called using a call
3764 * instruction, so mips_ra contains the return address.
3765 * Since the handler executes in the same stack frame
3766 * as the method itself, we can't use save/restore to
3767 * save the return address. Instead, we save it into
3768 * a dedicated variable.
3770 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3771 g_assert (spvar->inst_basereg != mips_sp);
3772 code = emit_reserve_param_area (cfg, code);
3774 if (mips_is_imm16 (spvar->inst_offset)) {
3775 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3776 } else {
3777 mips_load_const (code, mips_at, spvar->inst_offset);
3778 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3779 mips_sw (code, mips_ra, mips_at, 0);
3781 break;
3783 case OP_ENDFILTER: {
3784 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3785 g_assert (spvar->inst_basereg != mips_sp);
3786 code = emit_unreserve_param_area (cfg, code);
3788 if (ins->sreg1 != mips_v0)
3789 MIPS_MOVE (code, mips_v0, ins->sreg1);
3790 if (mips_is_imm16 (spvar->inst_offset)) {
3791 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3792 } else {
3793 mips_load_const (code, mips_at, spvar->inst_offset);
3794 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3795 mips_lw (code, mips_ra, mips_at, 0);
3797 mips_jr (code, mips_ra);
3798 mips_nop (code);
3799 break;
3801 case OP_ENDFINALLY: {
3802 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3803 g_assert (spvar->inst_basereg != mips_sp);
3804 code = emit_unreserve_param_area (cfg, code);
3805 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3806 mips_jalr (code, mips_t9, mips_ra);
3807 mips_nop (code);
3808 break;
3810 case OP_CALL_HANDLER:
3811 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3812 mips_lui (code, mips_t9, mips_zero, 0);
3813 mips_addiu (code, mips_t9, mips_t9, 0);
3814 mips_jalr (code, mips_t9, mips_ra);
3815 mips_nop (code);
3816 break;
3817 case OP_LABEL:
3818 ins->inst_c0 = code - cfg->native_code;
3819 break;
3820 case OP_BR:
3821 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3822 #if LONG_BRANCH
3823 mips_lui (code, mips_at, mips_zero, 0);
3824 mips_addiu (code, mips_at, mips_at, 0);
3825 mips_jr (code, mips_at);
3826 mips_nop (code);
3827 #else
3828 mips_beq (code, mips_zero, mips_zero, 0);
3829 mips_nop (code);
3830 #endif
3831 break;
3832 case OP_BR_REG:
3833 mips_jr (code, ins->sreg1);
3834 mips_nop (code);
3835 break;
3836 case OP_SWITCH: {
3837 int i;
3839 max_len += 4 * GPOINTER_TO_INT (ins->klass);
3840 if (offset > (cfg->code_size - max_len - 16)) {
3841 cfg->code_size += max_len;
3842 cfg->code_size *= 2;
3843 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3844 code = cfg->native_code + offset;
3846 g_assert (ins->sreg1 != -1);
3847 mips_sll (code, mips_at, ins->sreg1, 2);
3848 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
3849 MIPS_MOVE (code, mips_t8, mips_ra);
3850 mips_bgezal (code, mips_zero, 1); /* bal */
3851 mips_nop (code);
3852 mips_addu (code, mips_t9, mips_ra, mips_at);
3853 /* Table is 16 or 20 bytes from target of bal above */
3854 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
3855 MIPS_MOVE (code, mips_ra, mips_t8);
3856 mips_lw (code, mips_t9, mips_t9, 20);
3858 else
3859 mips_lw (code, mips_t9, mips_t9, 16);
3860 mips_jalr (code, mips_t9, mips_t8);
3861 mips_nop (code);
3862 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
3863 mips_emit32 (code, 0xfefefefe);
3864 break;
3866 case OP_CEQ:
3867 case OP_ICEQ:
3868 mips_addiu (code, ins->dreg, mips_zero, 1);
3869 mips_beq (code, mips_at, mips_zero, 2);
3870 mips_nop (code);
3871 MIPS_MOVE (code, ins->dreg, mips_zero);
3872 break;
3873 case OP_CLT:
3874 case OP_CLT_UN:
3875 case OP_ICLT:
3876 case OP_ICLT_UN:
3877 mips_addiu (code, ins->dreg, mips_zero, 1);
3878 mips_bltz (code, mips_at, 2);
3879 mips_nop (code);
3880 MIPS_MOVE (code, ins->dreg, mips_zero);
3881 break;
3882 case OP_CGT:
3883 case OP_CGT_UN:
3884 case OP_ICGT:
3885 case OP_ICGT_UN:
3886 mips_addiu (code, ins->dreg, mips_zero, 1);
3887 mips_bgtz (code, mips_at, 2);
3888 mips_nop (code);
3889 MIPS_MOVE (code, ins->dreg, mips_zero);
3890 break;
3892 case OP_MIPS_COND_EXC_EQ:
3893 case OP_MIPS_COND_EXC_GE:
3894 case OP_MIPS_COND_EXC_GT:
3895 case OP_MIPS_COND_EXC_LE:
3896 case OP_MIPS_COND_EXC_LT:
3897 case OP_MIPS_COND_EXC_NE_UN:
3898 case OP_MIPS_COND_EXC_GE_UN:
3899 case OP_MIPS_COND_EXC_GT_UN:
3900 case OP_MIPS_COND_EXC_LE_UN:
3901 case OP_MIPS_COND_EXC_LT_UN:
3903 case OP_MIPS_COND_EXC_OV:
3904 case OP_MIPS_COND_EXC_NO:
3905 case OP_MIPS_COND_EXC_C:
3906 case OP_MIPS_COND_EXC_NC:
3908 case OP_MIPS_COND_EXC_IEQ:
3909 case OP_MIPS_COND_EXC_IGE:
3910 case OP_MIPS_COND_EXC_IGT:
3911 case OP_MIPS_COND_EXC_ILE:
3912 case OP_MIPS_COND_EXC_ILT:
3913 case OP_MIPS_COND_EXC_INE_UN:
3914 case OP_MIPS_COND_EXC_IGE_UN:
3915 case OP_MIPS_COND_EXC_IGT_UN:
3916 case OP_MIPS_COND_EXC_ILE_UN:
3917 case OP_MIPS_COND_EXC_ILT_UN:
3919 case OP_MIPS_COND_EXC_IOV:
3920 case OP_MIPS_COND_EXC_INO:
3921 case OP_MIPS_COND_EXC_IC:
3922 case OP_MIPS_COND_EXC_INC: {
3923 guint32 *skip;
3924 guint32 *throw;
3926 /* If the condition is true, raise the exception */
3928 /* need to reverse test to skip around exception raising */
3930 /* For the moment, branch around a branch to avoid reversing
3931 the tests. */
3933 /* Remember, an unpatched branch to 0 branches to the delay slot */
3934 switch (ins->opcode) {
3935 case OP_MIPS_COND_EXC_EQ:
3936 throw = (guint32 *)(void *)code;
3937 mips_beq (code, ins->sreg1, ins->sreg2, 0);
3938 mips_nop (code);
3939 break;
3941 case OP_MIPS_COND_EXC_NE_UN:
3942 throw = (guint32 *)(void *)code;
3943 mips_bne (code, ins->sreg1, ins->sreg2, 0);
3944 mips_nop (code);
3945 break;
3947 case OP_MIPS_COND_EXC_LE_UN:
3948 mips_subu (code, mips_at, ins->sreg1, ins->sreg2);
3949 throw = (guint32 *)(void *)code;
3950 mips_blez (code, mips_at, 0);
3951 mips_nop (code);
3952 break;
3954 case OP_MIPS_COND_EXC_GT:
3955 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
3956 throw = (guint32 *)(void *)code;
3957 mips_bne (code, mips_at, mips_zero, 0);
3958 mips_nop (code);
3959 break;
3961 case OP_MIPS_COND_EXC_GT_UN:
3962 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
3963 throw = (guint32 *)(void *)code;
3964 mips_bne (code, mips_at, mips_zero, 0);
3965 mips_nop (code);
3966 break;
3968 case OP_MIPS_COND_EXC_LT:
3969 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
3970 throw = (guint32 *)(void *)code;
3971 mips_bne (code, mips_at, mips_zero, 0);
3972 mips_nop (code);
3973 break;
3975 case OP_MIPS_COND_EXC_LT_UN:
3976 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
3977 throw = (guint32 *)(void *)code;
3978 mips_bne (code, mips_at, mips_zero, 0);
3979 mips_nop (code);
3980 break;
3982 default:
3983 /* Not yet implemented */
3984 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
3985 g_assert_not_reached ();
3987 skip = (guint32 *)(void *)code;
3988 mips_beq (code, mips_zero, mips_zero, 0);
3989 mips_nop (code);
3990 mips_patch (throw, (guint32)code);
3991 code = mips_emit_exc_by_name (code, ins->inst_p1);
3992 mips_patch (skip, (guint32)code);
3993 cfg->bb_exit->max_offset += 24;
3994 break;
3996 case OP_MIPS_BEQ:
3997 case OP_MIPS_BNE:
3998 case OP_MIPS_BGEZ:
3999 case OP_MIPS_BGTZ:
4000 case OP_MIPS_BLEZ:
4001 case OP_MIPS_BLTZ:
4002 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4003 break;
4005 /* floating point opcodes */
4006 case OP_R8CONST:
4007 #if 0
4008 if (((guint32)ins->inst_p0) & (1 << 15))
4009 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4010 else
4011 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4012 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4013 #else
4014 mips_load_const (code, mips_at, ins->inst_p0);
4015 mips_lwc1 (code, ins->dreg, mips_at, 4);
4016 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
4017 #endif
4018 break;
4019 case OP_R4CONST:
4020 if (((guint32)ins->inst_p0) & (1 << 15))
4021 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4022 else
4023 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4024 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4025 #if PROMOTE_R4_TO_R8
4026 mips_cvtds (code, ins->dreg, ins->dreg);
4027 #endif
4028 break;
4029 case OP_STORER8_MEMBASE_REG:
4030 if (mips_is_imm16 (ins->inst_offset)) {
4031 #if _MIPS_SIM == _ABIO32
4032 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset+4);
4033 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset);
4034 #elif _MIPS_SIM == _ABIN32
4035 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4036 #endif
4037 } else {
4038 mips_load_const (code, mips_at, ins->inst_offset);
4039 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4040 mips_swc1 (code, ins->sreg1, mips_at, 4);
4041 mips_swc1 (code, ins->sreg1+1, mips_at, 0);
4043 break;
4044 case OP_LOADR8_MEMBASE:
4045 if (mips_is_imm16 (ins->inst_offset)) {
4046 #if _MIPS_SIM == _ABIO32
4047 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset+4);
4048 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset);
4049 #elif _MIPS_SIM == _ABIN32
4050 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4051 #endif
4052 } else {
4053 mips_load_const (code, mips_at, ins->inst_offset);
4054 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4055 mips_lwc1 (code, ins->dreg, mips_at, 4);
4056 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
4058 break;
4059 case OP_STORER4_MEMBASE_REG:
4060 g_assert (mips_is_imm16 (ins->inst_offset));
4061 #if PROMOTE_R4_TO_R8
4062 /* Need to convert ins->sreg1 to single-precision first */
4063 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4064 #endif
4065 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4066 break;
4067 case OP_MIPS_LWC1:
4068 g_assert (mips_is_imm16 (ins->inst_offset));
4069 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4070 break;
4071 case OP_LOADR4_MEMBASE:
4072 g_assert (mips_is_imm16 (ins->inst_offset));
4073 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4074 #if PROMOTE_R4_TO_R8
4075 /* Convert to double precision in place */
4076 mips_cvtds (code, ins->dreg, ins->dreg);
4077 #endif
4078 break;
4079 case OP_ICONV_TO_R_UN: {
4080 static const guint64 adjust_val = 0x41F0000000000000ULL;
4082 /* convert unsigned int to double */
4083 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4084 mips_bgez (code, ins->sreg1, 5);
4085 mips_cvtdw (code, ins->dreg, mips_ftemp);
4087 mips_load (code, mips_at, (guint32) &adjust_val);
4088 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4089 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4090 /* target is here */
4091 break;
4093 case OP_ICONV_TO_R4:
4094 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4095 mips_cvtsw (code, ins->dreg, mips_ftemp);
4096 mips_cvtds (code, ins->dreg, ins->dreg);
4097 break;
4098 case OP_ICONV_TO_R8:
4099 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4100 mips_cvtdw (code, ins->dreg, mips_ftemp);
4101 break;
4102 case OP_FCONV_TO_I1:
4103 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4104 break;
4105 case OP_FCONV_TO_U1:
4106 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4107 break;
4108 case OP_FCONV_TO_I2:
4109 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4110 break;
4111 case OP_FCONV_TO_U2:
4112 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4113 break;
4114 case OP_FCONV_TO_I4:
4115 case OP_FCONV_TO_I:
4116 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4117 break;
4118 case OP_FCONV_TO_U4:
4119 case OP_FCONV_TO_U:
4120 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4121 break;
4122 case OP_SQRT:
4123 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4124 break;
4125 case OP_FADD:
4126 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4127 break;
4128 case OP_FSUB:
4129 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4130 break;
4131 case OP_FMUL:
4132 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4133 break;
4134 case OP_FDIV:
4135 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4136 break;
4137 case OP_FNEG:
4138 mips_fnegd (code, ins->dreg, ins->sreg1);
4139 break;
4140 case OP_FCEQ:
4141 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4142 mips_addiu (code, ins->dreg, mips_zero, 1);
4143 mips_fbtrue (code, 2);
4144 mips_nop (code);
4145 MIPS_MOVE (code, ins->dreg, mips_zero);
4146 break;
4147 case OP_FCLT:
4148 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4149 mips_addiu (code, ins->dreg, mips_zero, 1);
4150 mips_fbtrue (code, 2);
4151 mips_nop (code);
4152 MIPS_MOVE (code, ins->dreg, mips_zero);
4153 break;
4154 case OP_FCLT_UN:
4155 /* Less than, or Unordered */
4156 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4157 mips_addiu (code, ins->dreg, mips_zero, 1);
4158 mips_fbtrue (code, 2);
4159 mips_nop (code);
4160 MIPS_MOVE (code, ins->dreg, mips_zero);
4161 break;
4162 case OP_FCGT:
4163 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4164 MIPS_MOVE (code, ins->dreg, mips_zero);
4165 mips_fbtrue (code, 2);
4166 mips_nop (code);
4167 mips_addiu (code, ins->dreg, mips_zero, 1);
4168 break;
4169 case OP_FCGT_UN:
4170 /* Greater than, or Unordered */
4171 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4172 MIPS_MOVE (code, ins->dreg, mips_zero);
4173 mips_fbtrue (code, 2);
4174 mips_nop (code);
4175 mips_addiu (code, ins->dreg, mips_zero, 1);
4176 break;
4177 case OP_MIPS_FBEQ:
4178 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4179 mips_nop (code);
4180 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4181 mips_fbtrue (code, 0);
4182 mips_nop (code);
4183 break;
4184 case OP_MIPS_FBNE:
4185 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4186 mips_nop (code);
4187 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4188 mips_fbfalse (code, 0);
4189 mips_nop (code);
4190 break;
4191 case OP_MIPS_FBLT:
4192 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4193 mips_nop (code);
4194 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4195 mips_fbtrue (code, 0);
4196 mips_nop (code);
4197 break;
4198 case OP_MIPS_FBLT_UN:
4199 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4200 mips_nop (code);
4201 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4202 mips_fbtrue (code, 0);
4203 mips_nop (code);
4204 break;
4205 case OP_MIPS_FBGT:
4206 mips_fcmpd (code, MIPS_FPU_LE, ins->sreg1, ins->sreg2);
4207 mips_nop (code);
4208 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4209 mips_fbfalse (code, 0);
4210 mips_nop (code);
4211 break;
4212 case OP_MIPS_FBGT_UN:
4213 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4214 mips_nop (code);
4215 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4216 mips_fbfalse (code, 0);
4217 mips_nop (code);
4218 break;
4219 case OP_MIPS_FBGE:
4220 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4221 mips_nop (code);
4222 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4223 mips_fbfalse (code, 0);
4224 mips_nop (code);
4225 break;
4226 case OP_MIPS_FBGE_UN:
4227 mips_fcmpd (code, MIPS_FPU_OLT, ins->sreg1, ins->sreg2);
4228 mips_nop (code);
4229 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4230 mips_fbfalse (code, 0);
4231 mips_nop (code);
4232 break;
4233 case OP_MIPS_FBLE:
4234 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4235 mips_nop (code);
4236 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4237 mips_fbtrue (code, 0);
4238 mips_nop (code);
4239 break;
4240 case OP_MIPS_FBLE_UN:
4241 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4242 mips_nop (code);
4243 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4244 mips_fbtrue (code, 0);
4245 mips_nop (code);
4246 break;
4247 case OP_CKFINITE: {
4248 guint32 *branch_patch;
4250 mips_mfc1 (code, mips_at, ins->sreg1+1);
4251 mips_srl (code, mips_at, mips_at, 16+4);
4252 mips_andi (code, mips_at, mips_at, 2047);
4253 mips_addiu (code, mips_at, mips_at, -2047);
4255 branch_patch = (guint32 *)(void *)code;
4256 mips_bne (code, mips_at, mips_zero, 0);
4257 mips_nop (code);
4259 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4260 mips_patch (branch_patch, (guint32)code);
4261 mips_fmovd (code, ins->dreg, ins->sreg1);
4262 break;
4264 case OP_JUMP_TABLE:
4265 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4266 mips_load (code, ins->dreg, 0x0f0f0f0f);
4267 break;
4270 default:
4271 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4272 g_assert_not_reached ();
4275 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4276 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4277 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4278 g_assert_not_reached ();
4281 cpos += max_len;
4283 last_ins = ins;
4284 last_offset = offset;
4287 cfg->code_len = code - cfg->native_code;
4290 void
4291 mono_arch_register_lowlevel_calls (void)
4295 void
4296 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4298 MonoJumpInfo *patch_info;
4300 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4301 unsigned char *ip = patch_info->ip.i + code;
4302 const unsigned char *target = NULL;
4304 switch (patch_info->type) {
4305 case MONO_PATCH_INFO_IP:
4306 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4307 continue;
4308 case MONO_PATCH_INFO_SWITCH: {
4309 gpointer *table = (gpointer *)patch_info->data.table->table;
4310 int i;
4312 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4314 for (i = 0; i < patch_info->data.table->table_size; i++) {
4315 table [i] = (int)patch_info->data.table->table [i] + code;
4317 continue;
4319 case MONO_PATCH_INFO_METHODCONST:
4320 case MONO_PATCH_INFO_CLASS:
4321 case MONO_PATCH_INFO_IMAGE:
4322 case MONO_PATCH_INFO_FIELD:
4323 case MONO_PATCH_INFO_VTABLE:
4324 case MONO_PATCH_INFO_IID:
4325 case MONO_PATCH_INFO_SFLDA:
4326 case MONO_PATCH_INFO_LDSTR:
4327 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4328 case MONO_PATCH_INFO_LDTOKEN:
4329 case MONO_PATCH_INFO_R4:
4330 case MONO_PATCH_INFO_R8:
4331 /* from OP_AOTCONST : lui + addiu */
4332 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4333 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4334 continue;
4335 #if 0
4336 case MONO_PATCH_INFO_EXC_NAME:
4337 g_assert_not_reached ();
4338 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4339 continue;
4340 #endif
4341 case MONO_PATCH_INFO_NONE:
4342 /* everything is dealt with at epilog output time */
4343 continue;
4344 default:
4345 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4346 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4347 break;
4352 #if 0
4353 static
4354 void
4355 mono_trace_lmf_prolog (MonoLMF *new_lmf)
4359 static
4360 void
4361 mono_trace_lmf_epilog (MonoLMF *old_lmf)
4364 #endif
4367 * Allow tracing to work with this interface (with an optional argument)
4369 * This code is expected to be inserted just after the 'real' prolog code,
4370 * and before the first basic block. We need to allocate a 2nd, temporary
4371 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4374 void*
4375 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4377 guchar *code = p;
4378 int offset = cfg->arch.tracing_offset;
4380 mips_nop (code);
4381 mips_nop (code);
4382 mips_nop (code);
4384 /* For N32, need to know for each stack slot if it's an integer
4385 * or float argument, and save/restore the appropriate register
4387 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4388 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4389 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4390 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4391 #if _MIPS_SIM == _ABIN32
4392 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4393 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4394 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4395 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4396 #endif
4398 mips_load_const (code, mips_a0, cfg->method);
4399 mips_addiu (code, mips_a1, mips_sp, offset);
4400 mips_load_const (code, mips_t9, func);
4401 mips_jalr (code, mips_t9, mips_ra);
4402 mips_nop (code);
4404 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4405 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4406 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4407 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4408 #if _MIPS_SIM == _ABIN32
4409 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4410 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4411 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4412 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4413 #endif
4415 mips_nop (code);
4416 mips_nop (code);
4417 mips_nop (code);
4418 return code;
4421 void
4422 mips_adjust_stackframe(MonoCompile *cfg)
4424 MonoBasicBlock *bb;
4425 int delta, threshold, i;
4426 MonoMethodSignature *sig;
4427 int ra_offset;
4429 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4430 return;
4432 /* adjust cfg->stack_offset for account for down-spilling */
4433 cfg->stack_offset += SIZEOF_REGISTER;
4435 /* re-align cfg->stack_offset if needed (due to var spilling) */
4436 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4437 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4438 if (cfg->verbose_level > 2) {
4439 g_print ("mips_adjust_stackframe:\n");
4440 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4442 threshold = cfg->arch.local_alloc_offset;
4443 ra_offset = cfg->stack_offset - sizeof(gpointer);
4444 if (cfg->verbose_level > 2) {
4445 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4448 sig = mono_method_signature (cfg->method);
4449 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4450 cfg->vret_addr->inst_offset += delta;
4452 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4453 MonoInst *inst = cfg->args [i];
4455 inst->inst_offset += delta;
4459 * loads and stores based off the frame reg that (used to) lie
4460 * above the spill var area need to be increased by 'delta'
4461 * to make room for the spill vars.
4463 /* Need to find loads and stores to adjust that
4464 * are above where the spillvars were inserted, but
4465 * which are not the spillvar references themselves.
4467 * Idea - since all offsets from fp are positive, make
4468 * spillvar offsets negative to begin with so we can spot
4469 * them here.
4472 #if 1
4473 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4474 int ins_cnt = 0;
4475 MonoInst *ins;
4477 if (cfg->verbose_level > 2) {
4478 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4480 MONO_BB_FOR_EACH_INS (bb, ins) {
4481 int adj_c0 = 0;
4482 int adj_imm = 0;
4484 if (cfg->verbose_level > 2) {
4485 mono_print_ins_index (ins_cnt, ins);
4487 if (MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_fp))
4488 adj_c0 = 1;
4489 if (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_fp))
4490 adj_c0 = 1;
4491 /* The following two catch FP spills */
4492 if (MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_sp))
4493 adj_c0 = 1;
4494 if (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_sp))
4495 adj_c0 = 1;
4496 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == mips_fp))
4497 adj_imm = 1;
4498 if (adj_c0) {
4499 if (ins->inst_c0 >= threshold) {
4500 ins->inst_c0 += delta;
4501 if (cfg->verbose_level > 2) {
4502 g_print ("adj");
4503 mono_print_ins_index (ins_cnt, ins);
4506 else if (ins->inst_c0 < 0) {
4507 ins->inst_c0 = - ins->inst_c0 - 4;
4508 if (cfg->verbose_level > 2) {
4509 g_print ("spill");
4510 mono_print_ins_index (ins_cnt, ins);
4513 g_assert (ins->inst_c0 != ra_offset);
4515 if (adj_imm) {
4516 if (ins->inst_imm >= threshold) {
4517 ins->inst_imm += delta;
4518 if (cfg->verbose_level > 2) {
4519 g_print ("adj");
4520 mono_print_ins_index (ins_cnt, ins);
4523 g_assert (ins->inst_c0 != ra_offset);
4526 ++ins_cnt;
4529 #endif
4533 * Stack frame layout:
4535 * ------------------- sp + cfg->stack_usage + cfg->param_area
4536 * param area incoming
4537 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4538 * a0-a3 incoming
4539 * ------------------- sp + cfg->stack_usage
4540 * ra
4541 * ------------------- sp + cfg->stack_usage-4
4542 * spilled regs
4543 * ------------------- sp +
4544 * MonoLMF structure optional
4545 * ------------------- sp + cfg->arch.lmf_offset
4546 * saved registers s0-s8
4547 * ------------------- sp + cfg->arch.iregs_offset
4548 * locals
4549 * ------------------- sp + cfg->param_area
4550 * param area outgoing
4551 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4552 * a0-a3 outgoing
4553 * ------------------- sp
4554 * red zone
4556 guint8 *
4557 mono_arch_emit_prolog (MonoCompile *cfg)
4559 MonoMethod *method = cfg->method;
4560 MonoMethodSignature *sig;
4561 MonoInst *inst;
4562 int alloc_size, pos, i;
4563 guint8 *code;
4564 CallInfo *cinfo;
4565 int tracing = 0;
4566 guint32 iregs_to_save = 0;
4567 #if SAVE_FP_REGS
4568 guint32 fregs_to_save = 0;
4569 #endif
4570 #if SAVE_LMF
4571 /* lmf_offset is the offset of the LMF from our stack pointer. */
4572 guint32 lmf_offset = cfg->arch.lmf_offset;
4573 #endif
4575 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4576 tracing = 1;
4578 if (tracing)
4579 cfg->flags |= MONO_CFG_HAS_CALLS;
4581 sig = mono_method_signature (method);
4582 cfg->code_size = 768 + sig->param_count * 20;
4583 code = cfg->native_code = g_malloc (cfg->code_size);
4585 if (tracing) {
4586 #if _MIPS_SIM == _ABIO32
4587 cfg->arch.tracing_offset = cfg->stack_offset;
4588 #elif _MIPS_SIM == _ABIN32
4589 /* no stack slots by default for argument regs, reserve a special block */
4590 cfg->arch.tracing_offset = cfg->stack_offset;
4591 cfg->stack_offset += 8 * SIZEOF_REGISTER;
4592 #endif
4595 /* adjust stackframe assignments for spillvars if needed */
4596 mips_adjust_stackframe (cfg);
4598 /* stack_offset should not be changed here. */
4599 alloc_size = cfg->stack_offset;
4600 cfg->stack_usage = alloc_size;
4602 #if SAVE_ALL_REGS
4603 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
4604 #else
4605 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4606 #endif
4607 #if SAVE_FP_REGS
4608 #if 0
4609 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4610 #else
4611 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4612 fregs_to_save |= (fregs_to_save << 1);
4613 #endif
4614 #endif
4615 if (alloc_size) {
4616 if (mips_is_imm16 (-alloc_size)) {
4617 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4618 } else {
4619 mips_load_const (code, mips_at, -alloc_size);
4620 mips_addu (code, mips_sp, mips_sp, mips_at);
4624 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
4625 mips_sw (code, mips_ra, mips_sp, alloc_size + MIPS_RET_ADDR_OFFSET);
4627 /* XXX - optimize this later to not save all regs if LMF constructed */
4629 if (iregs_to_save) {
4630 /* save used registers in own stack frame (at pos) */
4631 pos = cfg->arch.iregs_offset;
4632 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4633 if (iregs_to_save & (1 << i)) {
4634 g_assert (pos < cfg->stack_usage - sizeof(gpointer));
4635 MIPS_SW (code, i, mips_sp, pos);
4636 pos += SIZEOF_REGISTER;
4640 #if SAVE_LMF
4641 if (method->save_lmf) {
4642 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4643 MIPS_SW (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]));
4646 #endif
4648 #if SAVE_FP_REGS
4649 /* Save float registers */
4650 if (fregs_to_save) {
4651 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4652 if (fregs_to_save & (1 << i)) {
4653 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4654 mips_swc1 (code, i, mips_sp, pos);
4655 pos += sizeof (gulong);
4659 #if SAVE_LMF
4660 if (method->save_lmf) {
4661 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4662 mips_swc1 (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]));
4665 #endif
4666 #endif
4667 if (cfg->frame_reg != mips_sp) {
4668 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4669 #if SAVE_LMF
4670 if (method->save_lmf)
4671 MIPS_SW (code, cfg->frame_reg, mips_sp,
4672 lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]));
4673 #endif
4676 /* Do instrumentation before assigning regvars to registers. Because they may be assigned
4677 * to the t* registers, which would be clobbered by the instrumentation calls.
4679 if (tracing) {
4680 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4684 /* load arguments allocated to register from the stack */
4685 pos = 0;
4687 cinfo = calculate_sizes (sig, sig->pinvoke);
4689 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4690 ArgInfo *ainfo = &cinfo->ret;
4691 inst = cfg->vret_addr;
4692 if (inst->opcode == OP_REGVAR)
4693 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4694 else if (mips_is_imm16 (inst->inst_offset)) {
4695 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4696 } else {
4697 mips_load_const (code, mips_at, inst->inst_offset);
4698 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4699 mips_sw (code, ainfo->reg, mips_at, 0);
4702 /* Keep this in sync with emit_load_volatile_arguments */
4703 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4704 ArgInfo *ainfo = cinfo->args + i;
4705 inst = cfg->args [pos];
4707 if (cfg->verbose_level > 2)
4708 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4709 if (inst->opcode == OP_REGVAR) {
4710 /* Argument ends up in a register */
4711 if (ainfo->regtype == RegTypeGeneral)
4712 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4713 else if (ainfo->regtype == RegTypeFP) {
4714 g_assert_not_reached();
4715 #if 0
4716 ppc_fmr (code, inst->dreg, ainfo->reg);
4717 #endif
4719 else if (ainfo->regtype == RegTypeBase) {
4720 mips_lw (code, inst->dreg, mips_sp, cfg->stack_usage + ainfo->offset);
4721 } else
4722 g_assert_not_reached ();
4724 if (cfg->verbose_level > 2)
4725 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4726 } else {
4727 /* Argument ends up on the stack */
4728 if (ainfo->regtype == RegTypeGeneral) {
4729 /* Incoming parameters should be above this frame */
4730 if (cfg->verbose_level > 2)
4731 g_print ("stack slot at %d of %d\n", inst->inst_offset, alloc_size);
4732 /* g_assert (inst->inst_offset >= alloc_size); */
4733 g_assert (mips_is_imm16 (inst->inst_offset));
4734 switch (ainfo->size) {
4735 case 1:
4736 mips_sb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4737 break;
4738 case 2:
4739 mips_sh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4740 break;
4741 case 0: /* XXX */
4742 case 4:
4743 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4744 break;
4745 case 8:
4746 #if (SIZEOF_REGISTER == 4)
4747 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4748 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
4749 #elif (SIZEOF_REGISTER == 8)
4750 mips_sd (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4751 #endif
4752 break;
4753 default:
4754 g_assert_not_reached ();
4755 break;
4757 } else if (ainfo->regtype == RegTypeBase) {
4759 * Argument comes in on the stack, and ends up on the stack
4760 * 1 and 2 byte args are passed as 32-bit quantities, but used as
4761 * 8 and 16 bit quantities. Shorten them in place.
4763 g_assert (mips_is_imm16 (inst->inst_offset));
4764 switch (ainfo->size) {
4765 case 1:
4766 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4767 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
4768 break;
4769 case 2:
4770 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4771 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
4772 break;
4773 case 0: /* XXX */
4774 case 4:
4775 case 8:
4776 break;
4777 default:
4778 g_assert_not_reached ();
4780 } else if (ainfo->regtype == RegTypeFP) {
4781 g_assert (mips_is_imm16 (inst->inst_offset));
4782 if (ainfo->size == 8) {
4783 #if _MIPS_SIM == _ABIO32
4784 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
4785 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
4786 #elif _MIPS_SIM == _ABIN32
4787 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4788 #endif
4790 else if (ainfo->size == 4)
4791 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4792 else
4793 g_assert_not_reached ();
4794 } else if (ainfo->regtype == RegTypeStructByVal) {
4795 int i;
4796 int doffset = inst->inst_offset;
4798 g_assert (mips_is_imm16 (inst->inst_offset));
4799 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
4800 /* Push the argument registers into their stack slots */
4801 for (i = 0; i < ainfo->size; ++i) {
4802 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
4803 doffset += SIZEOF_REGISTER;
4805 } else if (ainfo->regtype == RegTypeStructByAddr) {
4806 g_assert (mips_is_imm16 (inst->inst_offset));
4807 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
4808 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
4809 } else
4810 g_assert_not_reached ();
4812 pos++;
4815 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4816 mips_load_const (code, mips_a0, cfg->domain);
4817 mips_load_const (code, mips_t9, (gpointer)mono_jit_thread_attach);
4818 mips_jalr (code, mips_t9, mips_ra);
4819 mips_nop (code);
4822 #if SAVE_LMF
4823 if (method->save_lmf) {
4824 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
4825 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
4827 if (lmf_pthread_key != -1) {
4828 g_assert_not_reached();
4829 #if 0
4830 emit_tls_access (code, mips_temp, lmf_pthread_key);
4831 #endif
4832 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
4833 mips_addiu (code, mips_a0, mips_temp, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4834 } else {
4835 #if 0
4836 mips_addiu (code, mips_a0, mips_sp, lmf_offset);
4837 mips_load_const (code, mips_t9, (gpointer)mono_trace_lmf_prolog);
4838 mips_jalr (code, mips_t9, mips_ra);
4839 mips_nop (code);
4840 #endif
4841 /* This can/will clobber the a0-a3 registers */
4842 mips_load_const (code, mips_t9, (gpointer)mono_get_lmf_addr);
4843 mips_jalr (code, mips_t9, mips_ra);
4844 mips_nop (code);
4847 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
4848 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
4849 /* new_lmf->previous_lmf = *lmf_addr */
4850 mips_lw (code, mips_at, mips_v0, 0);
4851 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
4852 /* *(lmf_addr) = sp + lmf_offset */
4853 mips_addiu (code, mips_at, mips_sp, lmf_offset);
4854 mips_sw (code, mips_at, mips_v0, 0);
4856 /* save method info */
4857 mips_load_const (code, mips_at, method);
4858 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
4859 MIPS_SW (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
4861 /* save the current IP */
4862 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4863 mips_load_const (code, mips_at, 0x01010101);
4864 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
4866 #endif
4868 cfg->code_len = code - cfg->native_code;
4869 g_assert (cfg->code_len < cfg->code_size);
4870 g_free (cinfo);
4872 return code;
4875 enum {
4876 SAVE_NONE,
4877 SAVE_STRUCT,
4878 SAVE_ONE,
4879 SAVE_TWO,
4880 SAVE_FP
4883 void*
4884 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
4886 guchar *code = p;
4887 int save_mode = SAVE_NONE;
4888 int offset;
4889 MonoMethod *method = cfg->method;
4890 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
4891 int save_offset = MIPS_STACK_PARAM_OFFSET;
4893 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
4895 offset = code - cfg->native_code;
4896 /* we need about 16 instructions */
4897 if (offset > (cfg->code_size - 16 * 4)) {
4898 cfg->code_size *= 2;
4899 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4900 code = cfg->native_code + offset;
4902 mips_nop (code);
4903 mips_nop (code);
4904 switch (rtype) {
4905 case MONO_TYPE_VOID:
4906 /* special case string .ctor icall */
4907 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
4908 save_mode = SAVE_ONE;
4909 else
4910 save_mode = SAVE_NONE;
4911 break;
4912 case MONO_TYPE_R4:
4913 case MONO_TYPE_R8:
4914 save_mode = SAVE_FP;
4915 break;
4916 case MONO_TYPE_VALUETYPE:
4917 save_mode = SAVE_STRUCT;
4918 break;
4919 case MONO_TYPE_I8:
4920 case MONO_TYPE_U8:
4921 #if SIZEOF_REGISTER == 4
4922 save_mode = SAVE_TWO;
4923 #elif SIZEOF_REGISTER == 8
4924 save_mode = SAVE_ONE;
4925 #endif
4926 break;
4927 default:
4928 save_mode = SAVE_ONE;
4929 break;
4932 mips_addiu (code, mips_sp, mips_sp, -32);
4933 switch (save_mode) {
4934 case SAVE_TWO:
4935 mips_sw (code, mips_v0, mips_sp, save_offset);
4936 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
4937 if (enable_arguments) {
4938 MIPS_MOVE (code, mips_a1, mips_v0);
4939 MIPS_MOVE (code, mips_a2, mips_v1);
4941 break;
4942 case SAVE_ONE:
4943 MIPS_SW (code, mips_v0, mips_sp, save_offset);
4944 if (enable_arguments) {
4945 MIPS_MOVE (code, mips_a1, mips_v0);
4947 break;
4948 case SAVE_FP:
4949 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
4950 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
4951 mips_lw (code, mips_a0, mips_sp, save_offset);
4952 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
4953 break;
4954 case SAVE_STRUCT:
4955 case SAVE_NONE:
4956 default:
4957 break;
4959 mips_load_const (code, mips_a0, cfg->method);
4960 mips_load_const (code, mips_t9, func);
4961 mips_jalr (code, mips_t9, mips_ra);
4962 mips_nop (code);
4964 switch (save_mode) {
4965 case SAVE_TWO:
4966 mips_lw (code, mips_v0, mips_sp, save_offset);
4967 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
4968 break;
4969 case SAVE_ONE:
4970 MIPS_LW (code, mips_v0, mips_sp, save_offset);
4971 break;
4972 case SAVE_FP:
4973 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
4974 break;
4975 case SAVE_STRUCT:
4976 case SAVE_NONE:
4977 default:
4978 break;
4980 mips_addiu (code, mips_sp, mips_sp, 32);
4981 mips_nop (code);
4982 mips_nop (code);
4983 return code;
4986 guint8 *
4987 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
4989 MonoMethod *method = cfg->method;
4990 int pos = 0, i;
4991 int max_epilog_size = 16 + 20*4;
4992 guint32 iregs_to_restore;
4993 #if SAVE_FP_REGS
4994 guint32 fregs_to_restore;
4995 #endif
4997 #if SAVE_LMF
4998 if (cfg->method->save_lmf)
4999 max_epilog_size += 128;
5000 #endif
5002 if (mono_jit_trace_calls != NULL)
5003 max_epilog_size += 50;
5005 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5006 max_epilog_size += 50;
5008 if (code)
5009 pos = code - cfg->native_code;
5010 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5011 cfg->code_size *= 2;
5012 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5013 mono_jit_stats.code_reallocs++;
5017 * Keep in sync with OP_JMP
5019 if (code)
5020 code = cfg->native_code + pos;
5021 else
5022 code = cfg->native_code + cfg->code_len;
5024 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5025 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5027 pos = cfg->arch.iregs_offset;
5028 if (cfg->frame_reg != mips_sp) {
5029 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5031 #if SAVE_ALL_REGS
5032 iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
5033 #else
5034 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5035 #endif
5036 if (iregs_to_restore) {
5037 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5038 if (iregs_to_restore & (1 << i)) {
5039 MIPS_LW (code, i, mips_sp, pos);
5040 pos += SIZEOF_REGISTER;
5045 #if SAVE_FP_REGS
5046 #if 0
5047 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5048 #else
5049 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5050 fregs_to_restore |= (fregs_to_restore << 1);
5051 #endif
5052 if (fregs_to_restore) {
5053 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5054 if (fregs_to_restore & (1 << i)) {
5055 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5056 mips_lwc1 (code, i, mips_sp, pos);
5057 pos += FREG_SIZE
5061 #endif
5062 #if SAVE_LMF
5063 /* Unlink the LMF if necessary */
5064 if (method->save_lmf) {
5065 int lmf_offset = cfg->arch.lmf_offset;
5067 /* t0 = current_lmf->previous_lmf */
5068 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5069 /* t1 = lmf_addr */
5070 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5071 /* (*lmf_addr) = previous_lmf */
5072 mips_sw (code, mips_temp, mips_t1, 0);
5074 #endif
5075 #if 0
5076 /* Restore the fp */
5077 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5078 #endif
5079 /* Correct the stack pointer */
5080 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
5081 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage + MIPS_RET_ADDR_OFFSET);
5082 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage);
5084 /* Caller will emit either return or tail-call sequence */
5086 cfg->code_len = code - cfg->native_code;
5088 g_assert (cfg->code_len < cfg->code_size);
5089 return (code);
5092 void
5093 mono_arch_emit_epilog (MonoCompile *cfg)
5095 guint8 *code;
5097 code = mono_arch_emit_epilog_sub (cfg, NULL);
5099 mips_jr (code, mips_ra);
5100 mips_nop (code);
5102 cfg->code_len = code - cfg->native_code;
5104 g_assert (cfg->code_len < cfg->code_size);
5107 /* remove once throw_exception_by_name is eliminated */
5108 #if 0
5109 static int
5110 exception_id_by_name (const char *name)
5112 if (strcmp (name, "IndexOutOfRangeException") == 0)
5113 return MONO_EXC_INDEX_OUT_OF_RANGE;
5114 if (strcmp (name, "OverflowException") == 0)
5115 return MONO_EXC_OVERFLOW;
5116 if (strcmp (name, "ArithmeticException") == 0)
5117 return MONO_EXC_ARITHMETIC;
5118 if (strcmp (name, "DivideByZeroException") == 0)
5119 return MONO_EXC_DIVIDE_BY_ZERO;
5120 if (strcmp (name, "InvalidCastException") == 0)
5121 return MONO_EXC_INVALID_CAST;
5122 if (strcmp (name, "NullReferenceException") == 0)
5123 return MONO_EXC_NULL_REF;
5124 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5125 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5126 g_error ("Unknown intrinsic exception %s\n", name);
5127 return 0;
5129 #endif
5131 void
5132 mono_arch_emit_exceptions (MonoCompile *cfg)
5134 #if 0
5135 MonoJumpInfo *patch_info;
5136 int i;
5137 guint8 *code;
5138 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5139 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5140 int max_epilog_size = 50;
5142 /* count the number of exception infos */
5145 * make sure we have enough space for exceptions
5146 * 24 is the simulated call to throw_exception_by_name
5148 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5149 #if 0
5150 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5151 i = exception_id_by_name (patch_info->data.target);
5152 g_assert (i < MONO_EXC_INTRINS_NUM);
5153 if (!exc_throw_found [i]) {
5154 max_epilog_size += 12;
5155 exc_throw_found [i] = TRUE;
5158 #endif
5161 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5162 cfg->code_size *= 2;
5163 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5164 mono_jit_stats.code_reallocs++;
5167 code = cfg->native_code + cfg->code_len;
5169 /* add code to raise exceptions */
5170 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5171 switch (patch_info->type) {
5172 case MONO_PATCH_INFO_EXC: {
5173 #if 0
5174 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5176 i = exception_id_by_name (patch_info->data.target);
5177 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5178 if (!exc_throw_pos [i]) {
5179 guint32 addr;
5181 exc_throw_pos [i] = code;
5182 //g_print ("exc: writing stub at %p\n", code);
5183 mips_load_const (code, mips_a0, patch_info->data.target);
5184 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5185 mips_load_const (code, mips_t9, addr);
5186 mips_jr (code, mips_t9);
5187 mips_nop (code);
5189 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5191 /* Turn into a Relative patch, pointing at code stub */
5192 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5193 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5194 #else
5195 g_assert_not_reached();
5196 #endif
5197 break;
5199 default:
5200 /* do nothing */
5201 break;
5205 cfg->code_len = code - cfg->native_code;
5207 g_assert (cfg->code_len < cfg->code_size);
5208 #endif
5212 * Thread local storage support
5214 static void
5215 setup_tls_access (void)
5217 guint32 ptk;
5218 //guint32 *ins, *code;
5220 if (tls_mode == TLS_MODE_FAILED)
5221 return;
5223 if (g_getenv ("MONO_NO_TLS")) {
5224 tls_mode = TLS_MODE_FAILED;
5225 return;
5228 if (tls_mode == TLS_MODE_DETECT) {
5229 /* XXX */
5230 tls_mode = TLS_MODE_FAILED;
5231 return;
5232 #if 0
5234 ins = (guint32*)pthread_getspecific;
5235 /* uncond branch to the real method */
5236 if ((*ins >> 26) == 18) {
5237 gint32 val;
5238 val = (*ins & ~3) << 6;
5239 val >>= 6;
5240 if (*ins & 2) {
5241 /* absolute */
5242 ins = (guint32*)val;
5243 } else {
5244 ins = (guint32*) ((char*)ins + val);
5247 code = &cmplwi_1023;
5248 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5249 code = &li_0x48;
5250 ppc_li (code, ppc_r4, 0x48);
5251 code = &blr_ins;
5252 ppc_blr (code);
5253 if (*ins == cmplwi_1023) {
5254 int found_lwz_284 = 0;
5255 for (ptk = 0; ptk < 20; ++ptk) {
5256 ++ins;
5257 if (!*ins || *ins == blr_ins)
5258 break;
5259 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5260 found_lwz_284 = 1;
5261 break;
5264 if (!found_lwz_284) {
5265 tls_mode = TLS_MODE_FAILED;
5266 return;
5268 tls_mode = TLS_MODE_LTHREADS;
5269 } else if (*ins == li_0x48) {
5270 ++ins;
5271 /* uncond branch to the real method */
5272 if ((*ins >> 26) == 18) {
5273 gint32 val;
5274 val = (*ins & ~3) << 6;
5275 val >>= 6;
5276 if (*ins & 2) {
5277 /* absolute */
5278 ins = (guint32*)val;
5279 } else {
5280 ins = (guint32*) ((char*)ins + val);
5282 code = &val;
5283 ppc_li (code, ppc_r0, 0x7FF2);
5284 if (ins [1] == val) {
5285 /* Darwin on G4, implement */
5286 tls_mode = TLS_MODE_FAILED;
5287 return;
5288 } else {
5289 code = &val;
5290 ppc_mfspr (code, ppc_r3, 104);
5291 if (ins [1] != val) {
5292 tls_mode = TLS_MODE_FAILED;
5293 return;
5295 tls_mode = TLS_MODE_DARWIN_G5;
5297 } else {
5298 tls_mode = TLS_MODE_FAILED;
5299 return;
5301 } else {
5302 tls_mode = TLS_MODE_FAILED;
5303 return;
5305 #endif
5307 if (monodomain_key == -1) {
5308 ptk = mono_domain_get_tls_key ();
5309 if (ptk < 1024) {
5310 ptk = mono_pthread_key_for_tls (ptk);
5311 if (ptk < 1024) {
5312 monodomain_key = ptk;
5316 if (lmf_pthread_key == -1) {
5317 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
5318 if (ptk < 1024) {
5319 /*g_print ("MonoLMF at: %d\n", ptk);*/
5320 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5321 init_tls_failed = 1;
5322 return;
5324 lmf_pthread_key = ptk;
5327 if (monothread_key == -1) {
5328 ptk = mono_thread_get_tls_key ();
5329 if (ptk < 1024) {
5330 ptk = mono_pthread_key_for_tls (ptk);
5331 if (ptk < 1024) {
5332 monothread_key = ptk;
5333 /*g_print ("thread inited: %d\n", ptk);*/
5335 } else {
5336 /*g_print ("thread not inited yet %d\n", ptk);*/
5341 void
5342 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5344 setup_tls_access ();
5347 void
5348 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5352 void
5353 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5355 int this_dreg = mips_a0;
5357 if (vt_reg != -1)
5358 this_dreg = mips_a1;
5360 /* add the this argument */
5361 if (this_reg != -1) {
5362 MonoInst *this;
5363 MONO_INST_NEW (cfg, this, OP_MOVE);
5364 this->type = this_type;
5365 this->sreg1 = this_reg;
5366 this->dreg = mono_alloc_ireg (cfg);
5367 mono_bblock_add_inst (cfg->cbb, this);
5368 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
5371 if (vt_reg != -1) {
5372 MonoInst *vtarg;
5373 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5374 vtarg->type = STACK_MP;
5375 vtarg->sreg1 = vt_reg;
5376 vtarg->dreg = mono_alloc_ireg (cfg);
5377 mono_bblock_add_inst (cfg->cbb, vtarg);
5378 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5382 MonoInst*
5383 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5385 MonoInst *ins = NULL;
5387 return ins;
5390 MonoInst*
5391 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5393 return NULL;
5396 gboolean
5397 mono_arch_print_tree (MonoInst *tree, int arity)
5399 return 0;
5402 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5404 MonoInst* ins;
5406 setup_tls_access ();
5407 if (monodomain_key == -1)
5408 return NULL;
5410 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5411 ins->inst_offset = monodomain_key;
5412 return ins;
5415 gpointer
5416 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5418 /* FIXME: implement */
5419 g_assert_not_reached ();
5422 #ifdef MONO_ARCH_HAVE_IMT
5424 #define CMP_SIZE 12
5425 #define BR_SIZE 4
5426 #define JUMP_IMM_SIZE 12
5427 #define JUMP_IMM32_SIZE 16
5428 #define ENABLE_WRONG_METHOD_CHECK 0
5431 * LOCKING: called with the domain lock held
5433 gpointer
5434 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5435 gpointer fail_tramp)
5437 NOT_IMPLEMENTED;
5438 #if 0
5439 int i;
5440 int size = 0;
5441 guint8 *code, *start;
5443 for (i = 0; i < count; ++i) {
5444 MonoIMTCheckItem *item = imt_entries [i];
5445 if (item->is_equals) {
5446 if (item->check_target_idx) {
5447 if (!item->compare_done)
5448 item->chunk_size += CMP_SIZE;
5449 if (fail_tramp)
5450 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5451 else
5452 item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
5453 } else {
5454 if (fail_tramp) {
5455 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5456 } else {
5457 item->chunk_size += JUMP_IMM_SIZE;
5458 #if ENABLE_WRONG_METHOD_CHECK
5459 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5460 #endif
5463 } else {
5464 item->chunk_size += CMP_SIZE + BR_SIZE;
5465 imt_entries [item->check_target_idx]->compare_done = TRUE;
5467 size += item->chunk_size;
5469 if (fail_tramp) {
5470 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5471 } else {
5472 /* the initial load of the vtable address */
5473 size += 8;
5474 code = mono_domain_code_reserve (domain, size);
5476 start = code;
5477 if (!fail_tramp)
5478 ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
5479 for (i = 0; i < count; ++i) {
5480 MonoIMTCheckItem *item = imt_entries [i];
5481 item->code_target = code;
5482 if (item->is_equals) {
5483 if (item->check_target_idx) {
5484 if (!item->compare_done) {
5485 ppc_load (code, ppc_r0, (guint32)item->key);
5486 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
5488 item->jmp_code = code;
5489 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5490 if (fail_tramp)
5491 ppc_load (code, ppc_r0, item->value.target_code);
5492 else
5493 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5494 ppc_mtctr (code, ppc_r0);
5495 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5496 } else {
5497 if (fail_tramp) {
5498 ppc_load (code, ppc_r0, (guint32)item->key);
5499 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
5500 item->jmp_code = code;
5501 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5502 ppc_load (code, ppc_r0, item->value.target_code);
5503 ppc_mtctr (code, ppc_r0);
5504 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5505 ppc_patch (item->jmp_code, code);
5506 ppc_load (code, ppc_r0, fail_tramp);
5507 ppc_mtctr (code, ppc_r0);
5508 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5509 item->jmp_code = NULL;
5510 } else {
5511 /* enable the commented code to assert on wrong method */
5512 #if ENABLE_WRONG_METHOD_CHECK
5513 ppc_load (code, ppc_r0, (guint32)item->key);
5514 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
5515 item->jmp_code = code;
5516 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5517 #endif
5518 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5519 ppc_mtctr (code, ppc_r0);
5520 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5521 #if ENABLE_WRONG_METHOD_CHECK
5522 ppc_patch (item->jmp_code, code);
5523 ppc_break (code);
5524 item->jmp_code = NULL;
5525 #endif
5528 } else {
5529 ppc_load (code, ppc_r0, (guint32)item->key);
5530 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
5531 item->jmp_code = code;
5532 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5535 /* patch the branches to get to the target items */
5536 for (i = 0; i < count; ++i) {
5537 MonoIMTCheckItem *item = imt_entries [i];
5538 if (item->jmp_code) {
5539 if (item->check_target_idx) {
5540 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5545 if (!fail_tramp)
5546 mono_stats.imt_thunks_size += code - start;
5547 g_assert (code - start <= size);
5548 mono_arch_flush_icache (start, size);
5549 return start;
5550 #endif
5553 MonoMethod*
5554 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5556 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5558 #endif
5560 MonoVTable*
5561 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5563 NOT_IMPLEMENTED;
5564 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];