1 #ifndef __MONO_MINI_MIPS_H__
2 #define __MONO_MINI_MIPS_H__
4 #include <mono/arch/mips/mips-codegen.h>
7 #define MONO_ARCH_CPU_SPEC mips_desc
9 #define MONO_MAX_IREGS 32
10 #define MONO_MAX_FREGS 32
12 #define MONO_SAVED_GREGS 32
13 #define MONO_SAVED_FREGS 32
16 * at and t0 used internally
17 * v0, v1 aren't here for clarity reasons
18 * a0, a1, a2, a3 are for arguments
19 * Use t9 for indirect calls to match the ABI
22 #define MIPS_V_REGS ((1 << mips_v0) | \
24 #define MIPS_T_REGS ((1 << mips_t0) | \
32 #define MIPS_S_REGS ((1 << mips_s0) | \
41 #define MIPS_A_REGS ((1 << mips_a0) | \
46 #define mips_temp mips_t8
48 #define MONO_ARCH_CALLEE_REGS (MIPS_T_REGS | MIPS_V_REGS)
49 #define MONO_ARCH_CALLEE_SAVED_REGS MIPS_S_REGS
50 #define MIPS_ARG_REGS MIPS_A_REGS
53 #define MIPS_FP_PAIR(reg) ((1 << (reg)) | (1 << ((reg)+1)))
55 /* Only put the even regs in */
56 #define MIPS_FP_PAIR(reg) (1 << (reg))
59 #define MONO_ARCH_CALLEE_FREGS (MIPS_FP_PAIR(mips_f0) | \
60 MIPS_FP_PAIR(mips_f2) | \
61 MIPS_FP_PAIR(mips_f4) | \
62 MIPS_FP_PAIR(mips_f6) | \
63 MIPS_FP_PAIR(mips_f8) | \
64 MIPS_FP_PAIR(mips_f10) | \
65 MIPS_FP_PAIR(mips_f12) | \
66 MIPS_FP_PAIR(mips_f14) | \
67 MIPS_FP_PAIR(mips_f16) | \
68 MIPS_FP_PAIR(mips_f18))
70 #define MONO_ARCH_CALLEE_SAVED_FREGS (MIPS_FP_PAIR(mips_f20) | \
71 MIPS_FP_PAIR(mips_f22) | \
72 MIPS_FP_PAIR(mips_f24) | \
73 MIPS_FP_PAIR(mips_f26) | \
74 MIPS_FP_PAIR(mips_f28) | \
75 MIPS_FP_PAIR(mips_f30))
77 #define mips_ftemp mips_f18
79 #define MONO_ARCH_USE_FPSTACK FALSE
80 #define MONO_ARCH_FPSTACK_SIZE 0
82 /* Parameters used by the register allocator */
84 /* On Mips, for regpairs, the lower-numbered reg is most significant
85 * This is true in both big and little endian
88 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
89 #define RET_REG1 mips_v0
90 #define RET_REG2 mips_v1
92 #define RET_REG1 mips_v1
93 #define RET_REG2 mips_v0
96 #define MONO_ARCH_INST_SREG2_MASK(ins) (0)
97 #define MONO_ARCH_INST_IS_REGPAIR(desc) ((desc) == 'V' || (desc) == 'l')
98 #define MONO_ARCH_INST_REGPAIR_REG2(desc,hreg1) (((desc) == 'l') ? ((hreg1) + 1) : (((desc) == 'V') ? RET_REG2 : -1))
99 #define MONO_ARCH_INST_IS_FLOAT(desc) ((desc == 'f') || (desc == 'g'))
101 // This define is called to get specific dest register as defined
102 // by md file (letter after "dest"). Overwise return -1
104 #define MONO_ARCH_INST_FIXED_REG(desc) (((desc) == '0') ? mips_zero : (((desc) == 'a') ? mips_at : ((((desc) == 'v')) ? mips_v0 : (((desc) == 'V') ? RET_REG1 : (((desc) == 'g') ? mips_f0 : -1)))))
106 #define MONO_ARCH_FRAME_ALIGNMENT 8
108 /* fixme: align to 16byte instead of 32byte (we align to 32byte to get
109 * reproduceable results for benchmarks */
110 #define MONO_ARCH_CODE_ALIGNMENT 32
112 void mips_patch (guint32 *code, guint32 target);
114 #define MIPS_LMF_MAGIC1 0xa5a5a5a5
115 #define MIPS_LMF_MAGIC2 0xc3c3c3c3
118 gpointer previous_lmf;
123 gulong iregs [MONO_SAVED_GREGS];
124 gfloat fregs [MONO_SAVED_FREGS];
128 /* we define our own structure and we'll copy the data
129 * from sigcontext/ucontext/mach when we need it.
130 * This also makes us save stack space and time when copying
131 * We might also want to add an additional field to propagate
132 * the original context from the signal handler.
136 gulong sc_regs [MONO_SAVED_GREGS];
137 gfloat sc_fpregs [MONO_SAVED_FREGS];
140 typedef struct MonoCompileArch {
143 guint local_alloc_offset;
144 guint spillvar_offset;
145 guint spillvar_offset_float;
148 #define MONO_ARCH_EMULATE_FCONV_TO_I8 1
149 #define MONO_ARCH_EMULATE_LCONV_TO_R8 1
150 #define MONO_ARCH_EMULATE_LCONV_TO_R4 1
151 #define MONO_ARCH_EMULATE_LCONV_TO_R8_UN 1
152 #define MONO_ARCH_EMULATE_FREM 1
153 #define MONO_ARCH_BIGMUL_INTRINS 1
155 #define MIPS_RET_ADDR_OFFSET (-4)
156 #define MIPS_FP_ADDR_OFFSET (-8)
157 #define MIPS_STACK_ALIGNMENT 16
158 #define MIPS_STACK_PARAM_OFFSET 16 /* from sp to first parameter */
159 #define MIPS_MINIMAL_STACK_SIZE (4*4 + 4*4)
160 #define MIPS_EXTRA_STACK_SIZE 16 /* from last parameter to top of frame */
161 #define MIPS_FIRST_ARG_REG mips_a0
162 #define MIPS_LAST_ARG_REG mips_a3
163 #define MIPS_FIRST_FPARG_REG mips_f12
164 #define MIPS_LAST_FPARG_REG mips_f14
166 //#define MONO_ARCH_HAVE_IMT 1
167 //#define MONO_ARCH_IMT_REG mips_v0 /* XXX */
168 #define MONO_ARCH_COMMON_VTABLE_TRAMPOLINE 1
170 //#define MONO_ARCH_VTABLE_REG mips_v0 /* XXX */
171 #define MONO_ARCH_RGCTX_REG mips_v0 /* XXX */
173 #define MONO_ARCH_HAVE_DECOMPOSE_OPTS 1
174 #define MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS 1
176 #define MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK 1
178 /* XXX - a mystery, but it works */
179 #define MONO_GET_CONTEXT \
180 void *ctx = (void *)(((int)context)+24);
182 /* set the next to 0 once inssel-mips.brg is updated */
183 #define MIPS_PASS_STRUCTS_BY_VALUE 1
184 #define MIPS_SMALL_RET_STRUCT_IN_REG 0
186 #define MONO_ARCH_USE_SIGACTION
187 #define MONO_ARCH_NEED_DIV_CHECK 1
188 #define MONO_ARCH_ENABLE_NORMALIZE_OPCODES 1
190 #define MIPS_NUM_REG_ARGS (MIPS_LAST_ARG_REG-MIPS_FIRST_ARG_REG+1)
191 #define MIPS_NUM_REG_FPARGS (MIPS_LAST_FPARG_REG-MIPS_FIRST_FPARG_REG+1)
193 /* we have the stack pointer, not the base pointer in sigcontext */
194 #define MONO_CONTEXT_SET_IP(ctx,ip) do { (ctx)->sc_pc = (int)(ip); } while (0);
195 #define MONO_CONTEXT_SET_BP(ctx,bp) do { (ctx)->sc_regs[mips_fp] = (int)(bp); } while (0);
196 #define MONO_CONTEXT_SET_SP(ctx,sp) do { (ctx)->sc_regs[mips_sp] = (int)(sp); } while (0);
198 #define MONO_CONTEXT_GET_IP(ctx) ((gpointer)((ctx)->sc_pc))
199 #define MONO_CONTEXT_GET_BP(ctx) ((gpointer)((ctx)->sc_regs[mips_fp]))
200 #define MONO_CONTEXT_GET_SP(ctx) ((gpointer)((ctx)->sc_regs[mips_sp]))
204 unsigned long at; /* assembler temp */
205 unsigned long v0; /* return values */
207 unsigned long a0; /* 4 - func arguments */
211 unsigned long t0; /* 8 temporaries */
219 unsigned long s0; /* 16 calle saved */
227 unsigned long t8; /* 24 temps */
228 unsigned long t9; /* 25 temp / pic call-through register */
229 unsigned long k0; /* 26 kernel-reserved */
231 unsigned long gp; /* 28 */
232 unsigned long sp; /* stack pointer */
233 unsigned long fp; /* frame pointer */
234 unsigned long ra; /* return address */
235 } MonoMipsStackFrame;
237 #define MONO_INIT_CONTEXT_FROM_FUNC(ctx,func) do { \
239 guint32 *code = (guint32 *)(void *)func; \
241 memset ((ctx), 0, sizeof (*(ctx))); \
242 __asm__ volatile("addu %0,$0,$29" : "=r" (sp)); \
243 /* Look for adjustment of sp */ \
244 while ((*code & 0xffff0000) != 0x27bd0000) \
246 imm = (short) (*code & 0xffff); \
247 MONO_CONTEXT_SET_BP ((ctx), sp + (-imm)); \
248 ra = *(guint32 *)(sp + (-imm) + MIPS_RET_ADDR_OFFSET); \
249 MONO_CONTEXT_SET_IP ((ctx),ra); \
250 MONO_CONTEXT_SET_SP ((ctx), MONO_CONTEXT_GET_BP (ctx)); \
253 /* re-attaches with gdb - sometimes causes executable to hang */
254 #undef HAVE_BACKTRACE_SYMBOLS
256 #undef DEBUG_EXCEPTIONS
258 #define MONO_ZERO_REG mips_zero
260 #define MONO_EMIT_NEW_BRANCH_UNREG_LABEL(cfg,op,sr1,label) do { \
262 inst = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
265 inst->inst_i0 = label; \
266 inst->flags = MONO_INST_BRLABEL; \
267 mono_bblock_add_inst ((cfg)->cbb, inst); \
270 #define MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg,op,sr1,sr2,label) do { \
272 inst = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
276 inst->inst_i0 = label; \
277 inst->flags = MONO_INST_BRLABEL; \
278 mono_bblock_add_inst ((cfg)->cbb, inst); \
281 #define MONO_EMIT_NEW_BRANCH_NONZERO_LABEL(cfg,op,sr1,targetbb) do { \
283 MonoInst *target_label; \
284 target_label = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
285 target_label->opcode = OP_LABEL; \
286 target_label->next = (targetbb)->code; \
287 target_label->inst_c0 = (targetbb)->native_offset; \
288 (targetbb)->code = target_label; \
289 inst = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
291 (inst)->sreg1 = sr1; \
292 (inst)->sreg2 = sr2; \
293 inst->inst_i0 = target_label; \
294 inst->flags = MONO_INST_BRLABEL; \
295 mono_bblock_add_inst ((cfg)->cbb, inst); \
298 #define MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK(cfg,op,sr1,sr2,targetbb) do { \
300 MonoInst *target_label; \
301 target_label = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
302 target_label->opcode = OP_LABEL; \
303 target_label->next = (targetbb)->code; \
304 target_label->inst_c0 = (targetbb)->native_offset; \
305 (targetbb)->code = target_label; \
306 inst = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
308 (inst)->sreg1 = sr1; \
309 (inst)->sreg2 = sr2; \
310 inst->inst_i0 = target_label; \
311 inst->flags = MONO_INST_BRLABEL; \
312 mono_bblock_add_inst ((cfg)->cbb, inst); \
315 #ifndef MONO_EMIT_NEW_COMPARE_BRANCH_LABEL
316 #define MONO_EMIT_NEW_COMPARE_BRANCH_LABEL(cfg, cmp_op, sreg1, sreg2, label) \
320 MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BEQ, sreg1, sreg2, label); \
323 MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BNE, sreg1, sreg2, label); \
326 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLT, mips_at, sreg1, sreg2); \
327 MONO_EMIT_NEW_BIALU_IMM (s, OP_MIPS_XORI, mips_at, mips_at, 1); \
328 MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BNE, mips_at, mips_zero, label); \
331 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, mips_at, sreg1, sreg2); \
332 MONO_EMIT_NEW_BIALU_IMM (s, OP_MIPS_XORI, mips_at, mips_at, 1); \
333 MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BNE, mips_at, mips_zero, label); \
336 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLT, mips_at, sreg2, sreg1); \
337 MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BNE, mips_at, mips_zero, label); \
340 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, mips_at, sreg2, sreg1); \
341 MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BNE, mips_at, mips_zero, label); \
344 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLT, mips_at, sreg1, sreg2); \
345 MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BNE, mips_at, mips_zero, label); \
348 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, mips_at, sreg1, sreg2); \
349 MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BNE, mips_at, mips_zero, label); \
352 g_assert_not_reached(); \
357 #ifndef MONO_EMIT_NEW_COMPARE_IMM_BRANCH_LABEL
358 #define MONO_EMIT_NEW_COMPARE_IMM_BRANCH_LABEL(cfg, cmp_op, sreg1, imm, label) \
362 cmp_reg = mips_zero; \
366 MONO_EMIT_NEW_ICONST (cfg, cmp_reg, (imm)); \
368 MONO_EMIT_NEW_COMPARE_BRANCH_LABEL(cfg, cmp_op, sreg1, cmp_reg, label); \
372 #ifndef MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK
373 #define MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK(cfg, cmp_op, sreg1, sreg2, block) \
377 MONO_EMIT_NEW_BRANCH_BIREG_BLOCK (cfg, OP_MIPS_BEQ, sreg1, sreg2, block); \
380 MONO_EMIT_NEW_BRANCH_BIREG_BLOCK (cfg, OP_MIPS_BNE, sreg1, sreg2, block); \
383 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, mips_at, sreg1, sreg2); \
384 MONO_EMIT_NEW_BRANCH_BIREG_BLOCK (cfg, OP_MIPS_BNE, mips_at, mips_zero, block); \
387 g_assert_not_reached (); \
392 #ifndef MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK
393 #define MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK(cfg, cmp_op, sreg1, imm, block) \
397 cmp_reg = mips_zero; \
401 MONO_EMIT_NEW_ICONST (cfg, cmp_reg, (imm)); \
403 MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK(cfg, cmp_op, sreg1, cmp_reg, block); \
407 #define MONO_EMIT_NEW_MIPS_COND_EXC(cfg,cond,sr1,sr2,name) do { \
409 MONO_INST_NEW ((cfg), (inst), cond); \
410 inst->inst_p1 = (char*)name; \
413 MONO_ADD_INS ((cfg)->cbb, inst); \
416 #ifndef MONO_EMIT_NEW_COMPARE_EXC
417 #define MONO_EMIT_NEW_COMPARE_EXC(cfg, cmp_op, sreg1, sreg2, exc) do { \
418 switch (OP_MIPS_COND_EXC_##cmp_op) { \
419 case OP_MIPS_COND_EXC_EQ: \
420 MONO_EMIT_NEW_MIPS_COND_EXC (cfg, OP_MIPS_COND_EXC_EQ, sreg1, sreg2, exc); \
422 case OP_MIPS_COND_EXC_NE_UN: \
423 MONO_EMIT_NEW_MIPS_COND_EXC (cfg, OP_MIPS_COND_EXC_NE_UN, sreg1, sreg2, exc); \
425 case OP_MIPS_COND_EXC_GT: \
426 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLT, mips_at, sreg2, sreg1); \
427 MONO_EMIT_NEW_MIPS_COND_EXC (cfg, OP_MIPS_COND_EXC_NE_UN, mips_at, mips_zero, exc); \
429 case OP_MIPS_COND_EXC_GT_UN: \
430 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, mips_at, sreg2, sreg1); \
431 MONO_EMIT_NEW_MIPS_COND_EXC (cfg, OP_MIPS_COND_EXC_NE_UN, mips_at, mips_zero, exc); \
433 case OP_MIPS_COND_EXC_LE: \
434 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLT, mips_at, sreg2, sreg1); \
435 MONO_EMIT_NEW_MIPS_COND_EXC (cfg, OP_MIPS_COND_EXC_EQ, mips_at, mips_zero, exc); \
437 case OP_MIPS_COND_EXC_LE_UN: \
438 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, mips_at, sreg2, sreg1); \
439 MONO_EMIT_NEW_MIPS_COND_EXC (cfg, OP_MIPS_COND_EXC_EQ, mips_at, mips_zero, exc); \
441 case OP_MIPS_COND_EXC_LT: \
442 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLT, mips_at, sreg1, sreg2); \
443 MONO_EMIT_NEW_MIPS_COND_EXC (cfg, OP_MIPS_COND_EXC_NE_UN, mips_at, mips_zero, exc); \
445 case OP_MIPS_COND_EXC_LT_UN: \
446 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, mips_at, sreg1, sreg2); \
447 MONO_EMIT_NEW_MIPS_COND_EXC (cfg, OP_MIPS_COND_EXC_NE_UN, mips_at, mips_zero, exc); \
450 g_warning ("unknown comparison %s\n", #cmp_op); \
451 g_assert_not_reached (); \
456 #ifndef MONO_EMIT_NEW_COMPARE_IMM_EXC
457 #define MONO_EMIT_NEW_COMPARE_IMM_EXC(cfg, cmp_op, sreg1, imm, exc) do { \
460 cmp_reg = mips_zero; \
464 MONO_EMIT_NEW_ICONST (cfg, cmp_reg, (imm)); \
466 MONO_EMIT_NEW_COMPARE_EXC (cfg, cmp_op, sreg1, cmp_reg, exc); \
470 #ifndef MONO_EMIT_NEW_ICOMPARE_IMM_EXC
471 #define MONO_EMIT_NEW_ICOMPARE_IMM_EXC(cfg, cmp_op, sreg1, imm, exc) do { \
472 MONO_EMIT_NEW_COMPARE_IMM_EXC(cfg, cmp_op, sreg1, imm, exc); \
483 #endif /* __MONO_MINI_MIPS_H__ */