1adf89bf177659c53b84dccdcbd2be415939a374
[mono.git] / mono / mini / mini-mips.h
1 #ifndef __MONO_MINI_MIPS_H__
2 #define __MONO_MINI_MIPS_H__
3
4 #include <mono/arch/mips/mips-codegen.h>
5 #include <glib.h>
6
7 #define MONO_ARCH_CPU_SPEC mips_desc
8
9 #define MONO_MAX_IREGS 32
10 #define MONO_MAX_FREGS 32
11
12 #define MONO_SAVED_GREGS 32
13 #define MONO_SAVED_FREGS 32
14
15 /*
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
20  */
21
22 #define MIPS_V_REGS     ((1 << mips_v0) | \
23                          (1 << mips_v1))
24 #define MIPS_T_REGS     ((1 << mips_t0) | \
25                          (1 << mips_t1) | \
26                          (1 << mips_t2) | \
27                          (1 << mips_t3) | \
28                          (1 << mips_t4) | \
29                          (1 << mips_t5) | \
30                          (1 << mips_t6) | \
31                          (1 << mips_t7))
32 #define MIPS_S_REGS     ((1 << mips_s0) | \
33                          (1 << mips_s1) | \
34                          (1 << mips_s2) | \
35                          (1 << mips_s3) | \
36                          (1 << mips_s4) | \
37                          (1 << mips_s5) | \
38                          (1 << mips_s6) | \
39                          (1 << mips_s7) | \
40                          (1 << mips_fp))
41 #define MIPS_A_REGS     ((1 << mips_a0) | \
42                          (1 << mips_a1) | \
43                          (1 << mips_a2) | \
44                          (1 << mips_a3))
45
46 #define mips_temp mips_t8
47
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
51
52 #if 0
53 #define MIPS_FP_PAIR(reg)       ((1 << (reg)) | (1 << ((reg)+1)))
54 #else
55 /* Only put the even regs in */
56 #define MIPS_FP_PAIR(reg)       (1 << (reg))
57 #endif
58
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))
69
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))
76
77 #define mips_ftemp mips_f18
78
79 #define MONO_ARCH_USE_FPSTACK FALSE
80 #define MONO_ARCH_FPSTACK_SIZE 0
81
82 /* Parameters used by the register allocator */
83
84 /* On Mips, for regpairs, the lower-numbered reg is most significant
85  * This is true in both big and little endian
86  */
87
88 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
89 #define RET_REG1 mips_v0
90 #define RET_REG2 mips_v1
91 #else
92 #define RET_REG1 mips_v1
93 #define RET_REG2 mips_v0
94 #endif
95
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'))
100
101 // This define is called to get specific dest register as defined
102 // by md file (letter after "dest"). Overwise return -1
103
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)))))
105
106 #define MONO_ARCH_FRAME_ALIGNMENT 8
107
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
111
112 void mips_patch (guint32 *code, guint32 target);
113
114 #define MIPS_LMF_MAGIC1 0xa5a5a5a5
115 #define MIPS_LMF_MAGIC2 0xc3c3c3c3
116
117 struct MonoLMF {
118         gpointer    previous_lmf;
119         gpointer    lmf_addr;
120         MonoMethod *method;
121         gulong     ebp;
122         gulong     eip;
123         gulong     iregs [MONO_SAVED_GREGS];
124         gfloat     fregs [MONO_SAVED_FREGS];
125         gulong     magic;
126 };
127
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.
133  */
134 typedef struct {
135         gulong sc_pc;
136         gulong sc_regs [MONO_SAVED_GREGS];
137         gfloat sc_fpregs [MONO_SAVED_FREGS];
138 } MonoContext;
139
140 typedef struct MonoCompileArch {
141         guint           iregs_offset;
142         guint           lmf_offset;
143         guint           local_alloc_offset;
144         guint           spillvar_offset;
145         guint           spillvar_offset_float;
146 } MonoCompileArch;
147
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
154
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
165
166 //#define MONO_ARCH_HAVE_IMT 1
167 //#define MONO_ARCH_IMT_REG mips_v0             /* XXX */
168 #define MONO_ARCH_COMMON_VTABLE_TRAMPOLINE 1
169
170 //#define MONO_ARCH_VTABLE_REG  mips_v0         /* XXX */
171 #define MONO_ARCH_RGCTX_REG     mips_v0         /* XXX */
172
173 #define MONO_ARCH_HAVE_DECOMPOSE_OPTS 1
174
175 #define MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK 1
176
177 /* XXX - a mystery, but it works */
178 #define MONO_GET_CONTEXT \
179         void *ctx = (void *)(((int)context)+24);
180
181 /* set the next to 0 once inssel-mips.brg is updated */
182 #define MIPS_PASS_STRUCTS_BY_VALUE 1
183 #define MIPS_SMALL_RET_STRUCT_IN_REG 0
184
185 #define MONO_ARCH_USE_SIGACTION
186 #define MONO_ARCH_NEED_DIV_CHECK 1
187 #define MONO_ARCH_ENABLE_NORMALIZE_OPCODES 1
188
189 #define MIPS_NUM_REG_ARGS (MIPS_LAST_ARG_REG-MIPS_FIRST_ARG_REG+1)
190 #define MIPS_NUM_REG_FPARGS (MIPS_LAST_FPARG_REG-MIPS_FIRST_FPARG_REG+1)
191
192 /* we have the stack pointer, not the base pointer in sigcontext */
193 #define MONO_CONTEXT_SET_IP(ctx,ip) do { (ctx)->sc_pc = (int)(ip); } while (0); 
194 #define MONO_CONTEXT_SET_BP(ctx,bp) do { (ctx)->sc_regs[mips_fp] = (int)(bp); } while (0); 
195 #define MONO_CONTEXT_SET_SP(ctx,sp) do { (ctx)->sc_regs[mips_sp] = (int)(sp); } while (0); 
196
197 #define MONO_CONTEXT_GET_IP(ctx) ((gpointer)((ctx)->sc_pc))
198 #define MONO_CONTEXT_GET_BP(ctx) ((gpointer)((ctx)->sc_regs[mips_fp]))
199 #define MONO_CONTEXT_GET_SP(ctx) ((gpointer)((ctx)->sc_regs[mips_sp]))
200
201 typedef struct {
202         unsigned long zero;
203         unsigned long at; /* assembler temp */
204         unsigned long v0; /* return values */
205         unsigned long v1;
206         unsigned long a0; /* 4 - func arguments */
207         unsigned long a1;
208         unsigned long a2;
209         unsigned long a3;
210         unsigned long t0; /* 8 temporaries */
211         unsigned long t1;
212         unsigned long t2;
213         unsigned long t3;
214         unsigned long t4;
215         unsigned long t5;
216         unsigned long t6;
217         unsigned long t7;
218         unsigned long s0; /* 16 calle saved */
219         unsigned long s1;
220         unsigned long s2;
221         unsigned long s3;
222         unsigned long s4;
223         unsigned long s5;
224         unsigned long s6;
225         unsigned long s7;
226         unsigned long t8; /* 24 temps */
227         unsigned long t9; /* 25 temp / pic call-through register */
228         unsigned long k0; /* 26 kernel-reserved */
229         unsigned long k1;
230         unsigned long gp; /* 28 */
231         unsigned long sp; /* stack pointer */
232         unsigned long fp; /* frame pointer */
233         unsigned long ra; /* return address */
234 } MonoMipsStackFrame;
235
236 #define MONO_INIT_CONTEXT_FROM_FUNC(ctx,func) do {      \
237                 guint32 sp, ra;                                 \
238                 guint32 *code = (guint32 *)(void *)func;        \
239                 short imm;                                      \
240                 memset ((ctx), 0, sizeof (*(ctx)));             \
241                 __asm__ volatile("addu %0,$0,$29" : "=r" (sp)); \
242                 /* Look for adjustment of sp */                 \
243                 while ((*code & 0xffff0000) != 0x27bd0000)      \
244                         ++code;                                 \
245                 imm = (short) (*code & 0xffff);                 \
246                 MONO_CONTEXT_SET_BP ((ctx), sp + (-imm));       \
247                 ra = *(guint32 *)(sp + (-imm) + MIPS_RET_ADDR_OFFSET);  \
248                 MONO_CONTEXT_SET_IP ((ctx),ra); \
249                 MONO_CONTEXT_SET_SP ((ctx), MONO_CONTEXT_GET_BP (ctx)); \
250         } while (0)
251
252 /* re-attaches with gdb - sometimes causes executable to hang */
253 #undef HAVE_BACKTRACE_SYMBOLS
254
255 #undef DEBUG_EXCEPTIONS
256
257 #define MONO_ZERO_REG           mips_zero
258
259 #define MONO_EMIT_NEW_BRANCH_UNREG_LABEL(cfg,op,sr1,label) do { \
260                 MonoInst *inst; \
261                 inst = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
262                 inst->opcode = op;      \
263                 inst->sreg1 = sr1;      \
264                 inst->inst_i0 = label;  \
265                 inst->flags = MONO_INST_BRLABEL;        \
266                 mono_bblock_add_inst ((cfg)->cbb, inst); \
267         } while (0)
268
269 #define MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg,op,sr1,sr2,label) do {     \
270                 MonoInst *inst; \
271                 inst = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
272                 inst->opcode = op;      \
273                 inst->sreg1 = sr1;      \
274                 inst->sreg2 = sr2;      \
275                 inst->inst_i0 = label;  \
276                 inst->flags = MONO_INST_BRLABEL;        \
277                 mono_bblock_add_inst ((cfg)->cbb, inst); \
278         } while (0)
279
280 #define MONO_EMIT_NEW_BRANCH_NONZERO_LABEL(cfg,op,sr1,targetbb) do {    \
281                 MonoInst *inst; \
282                 MonoInst *target_label; \
283                 target_label = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
284                 target_label->opcode = OP_LABEL;        \
285                 target_label->next = (targetbb)->code; \
286                 target_label->inst_c0 = (targetbb)->native_offset; \
287                 (targetbb)->code = target_label; \
288                 inst = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
289                 inst->opcode = op;      \
290                 (inst)->sreg1 = sr1; \
291                 (inst)->sreg2 = sr2; \
292                 inst->inst_i0 = target_label;   \
293                 inst->flags = MONO_INST_BRLABEL;        \
294                 mono_bblock_add_inst ((cfg)->cbb, inst); \
295         } while (0)
296
297 #define MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK(cfg,op,sr1,sr2,targetbb) do {        \
298                 MonoInst *inst; \
299                 MonoInst *target_label; \
300                 target_label = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
301                 target_label->opcode = OP_LABEL;        \
302                 target_label->next = (targetbb)->code; \
303                 target_label->inst_c0 = (targetbb)->native_offset; \
304                 (targetbb)->code = target_label; \
305                 inst = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
306                 inst->opcode = op;      \
307                 (inst)->sreg1 = sr1; \
308                 (inst)->sreg2 = sr2; \
309                 inst->inst_i0 = target_label;   \
310                 inst->flags = MONO_INST_BRLABEL;        \
311                 mono_bblock_add_inst ((cfg)->cbb, inst); \
312         } while (0)
313
314 #ifndef MONO_EMIT_NEW_COMPARE_BRANCH_LABEL
315 #define MONO_EMIT_NEW_COMPARE_BRANCH_LABEL(cfg, cmp_op, sreg1, sreg2, label) \
316         do { \
317                 switch (cmp_op) { \
318                 case CEE_BEQ: \
319                         MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BEQ, sreg1, sreg2, label); \
320                         break; \
321                 case CEE_BNE_UN: \
322                         MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BNE, sreg1, sreg2, label); \
323                         break; \
324                 case CEE_BGE: \
325                         MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLT, mips_at, sreg1, sreg2); \
326                         MONO_EMIT_NEW_BIALU_IMM (s, OP_MIPS_XORI, mips_at, mips_at, 1); \
327                         MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BNE, mips_at, mips_zero, label); \
328                         break; \
329                 case CEE_BGE_UN: \
330                         MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, mips_at, sreg1, sreg2); \
331                         MONO_EMIT_NEW_BIALU_IMM (s, OP_MIPS_XORI, mips_at, mips_at, 1); \
332                         MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BNE, mips_at, mips_zero, label); \
333                         break; \
334                 case CEE_BGT: \
335                         MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLT, mips_at, sreg2, sreg1); \
336                         MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BNE, mips_at, mips_zero, label); \
337                         break; \
338                 case CEE_BGT_UN: \
339                         MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, mips_at, sreg2, sreg1); \
340                         MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BNE, mips_at, mips_zero, label); \
341                         break; \
342                 case CEE_BLT: \
343                         MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLT, mips_at, sreg1, sreg2); \
344                         MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BNE, mips_at, mips_zero, label); \
345                         break; \
346                 case CEE_BLT_UN: \
347                         MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, mips_at, sreg1, sreg2); \
348                         MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BNE, mips_at, mips_zero, label); \
349                         break; \
350                 default: \
351                         g_assert_not_reached(); \
352                 } \
353         } while (0)
354 #endif
355
356 #ifndef MONO_EMIT_NEW_COMPARE_IMM_BRANCH_LABEL
357 #define MONO_EMIT_NEW_COMPARE_IMM_BRANCH_LABEL(cfg, cmp_op, sreg1, imm, label) \
358         do { \
359                 guint32 cmp_reg; \
360                 if (!(imm)) { \
361                         cmp_reg = mips_zero; \
362                 } \
363                 else { \
364                         cmp_reg = mips_at; \
365                         MONO_EMIT_NEW_ICONST (cfg, cmp_reg, (imm)); \
366                 } \
367                 MONO_EMIT_NEW_COMPARE_BRANCH_LABEL(cfg, cmp_op, sreg1, cmp_reg, label); \
368         } while (0)
369 #endif
370
371 #ifndef MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK
372 #define MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK(cfg, cmp_op, sreg1, sreg2, block) \
373         do { \
374                 switch (cmp_op) { \
375                 case CEE_BEQ: \
376                         MONO_EMIT_NEW_BRANCH_BIREG_BLOCK (cfg, OP_MIPS_BEQ, sreg1, sreg2, block); \
377                         break; \
378                 case CEE_BNE_UN: \
379                         MONO_EMIT_NEW_BRANCH_BIREG_BLOCK (cfg, OP_MIPS_BNE, sreg1, sreg2, block); \
380                         break; \
381                 case CEE_BLT_UN: \
382                         MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, mips_at, sreg1, sreg2); \
383                         MONO_EMIT_NEW_BRANCH_BIREG_BLOCK (cfg, OP_MIPS_BNE, mips_at, mips_zero, block); \
384                         break; \
385                 default: \
386                         g_assert_not_reached (); \
387                 } \
388         } while (0)
389 #endif
390
391 #ifndef MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK
392 #define MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK(cfg, cmp_op, sreg1, imm, block) \
393         do { \
394                 guint32 cmp_reg; \
395                 if (!(imm)) { \
396                         cmp_reg = mips_zero; \
397                 } \
398                 else { \
399                         cmp_reg = mips_at; \
400                         MONO_EMIT_NEW_ICONST (cfg, cmp_reg, (imm)); \
401                 } \
402                 MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK(cfg, cmp_op, sreg1, cmp_reg, block); \
403         } while (0)
404 #endif
405
406 #define MONO_EMIT_NEW_MIPS_COND_EXC(cfg,cond,sr1,sr2,name) do { \
407                 MonoInst *inst; \
408                 inst = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
409                 inst->opcode = cond;  \
410                 inst->inst_p1 = (char*)name; \
411                 inst->sreg1 = sr1; \
412                 inst->sreg2 = sr2; \
413                 mono_bblock_add_inst ((cfg)->cbb, inst); \
414         } while (0)
415
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); \
421                         break; \
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); \
424                         break; \
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); \
428                         break; \
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); \
432                         break; \
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); \
436                         break; \
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); \
440                         break; \
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); \
444                         break; \
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); \
448                         break; \
449                 default: \
450                         g_warning ("unknown comparison %s\n", #cmp_op); \
451                         g_assert_not_reached (); \
452                 } \
453         } while (0)
454 #endif
455
456 #ifndef MONO_EMIT_NEW_COMPARE_IMM_EXC
457 #define MONO_EMIT_NEW_COMPARE_IMM_EXC(cfg, cmp_op, sreg1, imm, exc) do { \
458                 guint32 cmp_reg; \
459                 if (!(imm)) { \
460                         cmp_reg = mips_zero; \
461                 } \
462                 else { \
463                         cmp_reg = mips_at; \
464                         MONO_EMIT_NEW_ICONST (cfg, cmp_reg, (imm)); \
465                 } \
466                 MONO_EMIT_NEW_COMPARE_EXC (cfg, cmp_op, sreg1, cmp_reg, exc); \
467         } while (0)
468 #endif
469
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); \
473         } while (0)
474 #endif
475
476 typedef struct {
477         gint8 reg;
478         gint8 size;
479         int vtsize;
480         int offset;
481 } MonoMIPSArgInfo;
482
483 #endif /* __MONO_MINI_MIPS_H__ */