b535ad436f4d2c5ea80ed51ae0d7fdae46c3748f
[mono.git] / mono / mini / mini-mips.h
1 #ifndef __MONO_MINI_MIPS_H__
2 #define __MONO_MINI_MIPS_H__
3
4 #include <glib.h>
5 #include <mono/arch/mips/mips-codegen.h>
6 #include <mono/utils/mono-context.h>
7
8 #if _MIPS_SIM == _ABIO32
9 /* o32 fully supported */
10 #elif _MIPS_SIM == _ABIN32
11 /* n32 under development */
12 #warning "MIPS using n32 - under development"
13 #else
14 /* o64 not supported */
15 /* n64 not supported */
16 #error "MIPS unsupported ABI"
17 #endif
18
19
20 #define MONO_ARCH_CPU_SPEC mips_desc
21
22 #define MONO_MAX_IREGS 32
23 #define MONO_MAX_FREGS 32
24
25 #define MONO_SAVED_GREGS 32
26 #define MONO_SAVED_FREGS 32
27
28
29 #if SIZEOF_REGISTER == 4
30 #define IREG_SIZE       4
31 typedef guint32         mips_ireg;
32 #define FREG_SIZE       4
33 typedef gfloat          mips_freg;
34
35 #elif SIZEOF_REGISTER == 8
36
37 #define IREG_SIZE       8
38 typedef guint64         mips_ireg;
39 #define FREG_SIZE       8
40 typedef gdouble         mips_freg;
41
42 #else
43 #error Unknown REGISTER_SIZE
44 #endif
45
46 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
47 #define MSW_OFFSET      sizeof(mips_ireg)
48 #define LSW_OFFSET      0
49 #else
50 #define MSW_OFFSET      0
51 #define LSW_OFFSET      sizeof(mips_ireg)
52 #endif
53
54 /*
55  * at and t0 used internally
56  * v0, v1 aren't here for clarity reasons
57  * a0, a1, a2, a3 are for arguments
58  * Use t9 for indirect calls to match the ABI
59  */
60
61 #define MIPS_V_REGS     ((1 << mips_v0) | \
62                          (1 << mips_v1))
63 #if _MIPS_SIM == _ABIO32
64 #define MIPS_T_REGS     ((1 << mips_t0) | \
65                          (1 << mips_t1) | \
66                          (1 << mips_t2) | \
67                          (1 << mips_t3) | \
68                          (1 << mips_t4) | \
69                          (1 << mips_t5) | \
70                          (1 << mips_t6) | \
71                          (1 << mips_t7))
72 #elif _MIPS_SIM == _ABIN32
73 #define MIPS_T_REGS     ((1 << mips_t0) | \
74                          (1 << mips_t1) | \
75                          (1 << mips_t2) | \
76                          (1 << mips_t3))
77 #endif
78
79
80 #define MIPS_S_REGS     ((1 << mips_s0) | \
81                          (1 << mips_s1) | \
82                          (1 << mips_s2) | \
83                          (1 << mips_s3) | \
84                          (1 << mips_s4) | \
85                          (1 << mips_s5) | \
86                          (1 << mips_s6) | \
87                          (1 << mips_s7) | \
88                          (1 << mips_fp))
89 #if _MIPS_SIM == _ABIO32
90 #define MIPS_A_REGS     ((1 << mips_a0) | \
91                          (1 << mips_a1) | \
92                          (1 << mips_a2) | \
93                          (1 << mips_a3))
94 #elif _MIPS_SIM == _ABIN32
95 #define MIPS_A_REGS     ((1 << mips_a0) | \
96                          (1 << mips_a1) | \
97                          (1 << mips_a2) | \
98                          (1 << mips_a3) | \
99                          (1 << mips_a4) | \
100                          (1 << mips_a5) | \
101                          (1 << mips_a6) | \
102                          (1 << mips_a7))
103 #endif
104
105 #define mips_temp mips_t8
106
107 #define MONO_ARCH_CALLEE_REGS           (MIPS_T_REGS | MIPS_V_REGS)
108 #define MONO_ARCH_CALLEE_SAVED_REGS     MIPS_S_REGS
109 #define MIPS_ARG_REGS                   MIPS_A_REGS
110
111 #if 0
112 #define MIPS_FP_PAIR(reg)       ((1 << (reg)) | (1 << ((reg)+1)))
113 #else
114 /* Only put the even regs in */
115 #define MIPS_FP_PAIR(reg)       (1 << (reg))
116 #endif
117
118 #if _MIPS_SIM == _ABIO32
119 #define MONO_ARCH_CALLEE_FREGS          (MIPS_FP_PAIR(mips_f0) |        \
120                                          MIPS_FP_PAIR(mips_f2) |        \
121                                          MIPS_FP_PAIR(mips_f4) |        \
122                                          MIPS_FP_PAIR(mips_f6) |        \
123                                          MIPS_FP_PAIR(mips_f8) |        \
124                                          MIPS_FP_PAIR(mips_f10) |       \
125                                          MIPS_FP_PAIR(mips_f12) |       \
126                                          MIPS_FP_PAIR(mips_f14) |       \
127                                          MIPS_FP_PAIR(mips_f16) |       \
128                                          MIPS_FP_PAIR(mips_f18))
129
130 #define MONO_ARCH_CALLEE_SAVED_FREGS    (MIPS_FP_PAIR(mips_f20) |       \
131                                          MIPS_FP_PAIR(mips_f22) |       \
132                                          MIPS_FP_PAIR(mips_f24) |       \
133                                          MIPS_FP_PAIR(mips_f26) |       \
134                                          MIPS_FP_PAIR(mips_f28) |       \
135                                          MIPS_FP_PAIR(mips_f30))
136 #elif _MIPS_SIM == _ABIN32
137 #define MONO_ARCH_CALLEE_FREGS          (MIPS_FP_PAIR(mips_f0) |        \
138                                          MIPS_FP_PAIR(mips_f1) |        \
139                                          MIPS_FP_PAIR(mips_f2) |        \
140                                          MIPS_FP_PAIR(mips_f3) |        \
141                                          MIPS_FP_PAIR(mips_f4) |        \
142                                          MIPS_FP_PAIR(mips_f5) |        \
143                                          MIPS_FP_PAIR(mips_f6) |        \
144                                          MIPS_FP_PAIR(mips_f7) |        \
145                                          MIPS_FP_PAIR(mips_f8) |        \
146                                          MIPS_FP_PAIR(mips_f9) |        \
147                                          MIPS_FP_PAIR(mips_f10) |       \
148                                          MIPS_FP_PAIR(mips_f11) |       \
149                                          MIPS_FP_PAIR(mips_f12) |       \
150                                          MIPS_FP_PAIR(mips_f13) |       \
151                                          MIPS_FP_PAIR(mips_f14) |       \
152                                          MIPS_FP_PAIR(mips_f15) |       \
153                                          MIPS_FP_PAIR(mips_f16) |       \
154                                          MIPS_FP_PAIR(mips_f17) |       \
155                                          MIPS_FP_PAIR(mips_f18) |       \
156                                          MIPS_FP_PAIR(mips_f19))
157
158 #define MONO_ARCH_CALLEE_SAVED_FREGS    (MIPS_FP_PAIR(mips_f20) |       \
159                                          MIPS_FP_PAIR(mips_f21) |       \
160                                          MIPS_FP_PAIR(mips_f22) |       \
161                                          MIPS_FP_PAIR(mips_f23) |       \
162                                          MIPS_FP_PAIR(mips_f24) |       \
163                                          MIPS_FP_PAIR(mips_f25) |       \
164                                          MIPS_FP_PAIR(mips_f26) |       \
165                                          MIPS_FP_PAIR(mips_f27) |       \
166                                          MIPS_FP_PAIR(mips_f28) |       \
167                                          MIPS_FP_PAIR(mips_f29) |       \
168                                          MIPS_FP_PAIR(mips_f30) |       \
169                                          MIPS_FP_PAIR(mips_f31))
170 #endif
171
172 #define mips_ftemp mips_f18
173
174 #define MONO_ARCH_USE_FPSTACK FALSE
175 #define MONO_ARCH_FPSTACK_SIZE 0
176
177 /* Parameters used by the register allocator */
178
179 /* On Mips, for regpairs, the lower-numbered reg is most significant
180  * This is true in both big and little endian
181  */
182
183 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
184 #define RET_REG1 mips_v0
185 #define RET_REG2 mips_v1
186 #else
187 #define RET_REG1 mips_v1
188 #define RET_REG2 mips_v0
189 #endif
190
191 #define MONO_ARCH_INST_SREG2_MASK(ins)          (0)
192 #define MONO_ARCH_INST_IS_REGPAIR(desc)         ((desc) == 'V' || (desc) == 'l')
193 #define MONO_ARCH_INST_REGPAIR_REG2(desc,hreg1) (((desc) == 'l') ? ((hreg1) + 1) : (((desc) == 'V') ? RET_REG2 : -1))
194 #define MONO_ARCH_INST_IS_FLOAT(desc)           ((desc == 'f') || (desc == 'g'))
195
196 // This define is called to get specific dest register as defined
197 // by md file (letter after "dest"). Overwise return -1
198
199 #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)))))
200
201 #define MONO_ARCH_FRAME_ALIGNMENT 8
202
203 /* fixme: align to 16byte instead of 32byte (we align to 32byte to get 
204  * reproduceable results for benchmarks */
205 #define MONO_ARCH_CODE_ALIGNMENT 32
206
207 void mips_patch (guint32 *code, guint32 target);
208
209 #define MIPS_LMF_MAGIC1 0xa5a5a5a5
210 #define MIPS_LMF_MAGIC2 0xc3c3c3c3
211
212 struct MonoLMF {
213         gpointer        previous_lmf;
214         gpointer        lmf_addr;
215         MonoMethod      *method;
216         mips_ireg       ebp;
217         gpointer        eip;
218         mips_ireg       iregs [MONO_SAVED_GREGS];
219         mips_freg       fregs [MONO_SAVED_FREGS];
220         gulong          magic;
221 };
222
223 typedef struct MonoCompileArch {
224         guint           iregs_offset;
225         guint           lmf_offset;
226         guint           local_alloc_offset;
227         guint           spillvar_offset;
228         guint           spillvar_offset_float;
229         guint           tracing_offset;
230         guint           long_branch;
231 } MonoCompileArch;
232
233 #if SIZEOF_REGISTER == 4
234 #define MONO_ARCH_EMULATE_FCONV_TO_I8 1
235 #define MONO_ARCH_EMULATE_LCONV_TO_R8 1
236 #define MONO_ARCH_EMULATE_LCONV_TO_R4 1
237 #define MONO_ARCH_EMULATE_LCONV_TO_R8_UN 1
238 #define MONO_ARCH_EMULATE_FREM 1
239 #define MONO_ARCH_BIGMUL_INTRINS 1
240 #endif
241
242 #if SIZEOF_REGISTER == 8
243 #define MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
244 #endif
245
246 #define MIPS_RET_ADDR_OFFSET    (-sizeof(gpointer))
247 #define MIPS_FP_ADDR_OFFSET     (-8)
248 #define MIPS_STACK_ALIGNMENT    16
249 #define MIPS_STACK_PARAM_OFFSET 16              /* from sp to first parameter */
250 #define MIPS_MINIMAL_STACK_SIZE (4*sizeof(mips_ireg) + 4*sizeof(mips_ireg))
251 #define MIPS_EXTRA_STACK_SIZE   16              /* from last parameter to top of frame */
252
253 #if _MIPS_SIM == _ABIO32
254 #define MIPS_FIRST_ARG_REG      mips_a0
255 #define MIPS_LAST_ARG_REG       mips_a3
256 #define MIPS_FIRST_FPARG_REG    mips_f12
257 #define MIPS_LAST_FPARG_REG     mips_f14
258 #elif _MIPS_SIM == _ABIN32
259 #define MIPS_FIRST_ARG_REG      mips_a0
260 #define MIPS_LAST_ARG_REG       mips_t3
261 #define MIPS_FIRST_FPARG_REG    mips_f12
262 #define MIPS_LAST_FPARG_REG     mips_f19
263 #endif
264
265 #define MONO_ARCH_HAVE_IMT      1
266 #define MONO_ARCH_IMT_REG       mips_t0
267
268 #define MONO_ARCH_VTABLE_REG    mips_t0
269 #define MONO_ARCH_RGCTX_REG     mips_t0
270
271 #define MONO_ARCH_HAVE_DECOMPOSE_OPTS 1
272 #define MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS 1
273
274 #define MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK 1
275
276 /* XXX - a mystery, but it works */
277 #define MONO_GET_CONTEXT \
278         void *ctx = (void *)(((int)context)+24);
279
280 /* set the next to 0 once inssel-mips.brg is updated */
281 #define MIPS_PASS_STRUCTS_BY_VALUE 1
282 #define MIPS_SMALL_RET_STRUCT_IN_REG 0
283
284 #define MONO_ARCH_USE_SIGACTION
285 #define MONO_ARCH_NEED_DIV_CHECK 1
286 #define MONO_ARCH_NO_IOV_CHECK 1
287
288 #define MONO_ARCH_THIS_AS_FIRST_ARG 1
289
290 #define MIPS_NUM_REG_ARGS (MIPS_LAST_ARG_REG-MIPS_FIRST_ARG_REG+1)
291 #define MIPS_NUM_REG_FPARGS (MIPS_LAST_FPARG_REG-MIPS_FIRST_FPARG_REG+1)
292
293 typedef struct {
294         unsigned long zero;
295         unsigned long at; /* assembler temp */
296         unsigned long v0; /* return values */
297         unsigned long v1;
298         unsigned long a0; /* 4 - func arguments */
299         unsigned long a1;
300         unsigned long a2;
301         unsigned long a3;
302         unsigned long t0; /* 8 temporaries */
303         unsigned long t1;
304         unsigned long t2;
305         unsigned long t3;
306         unsigned long t4;
307         unsigned long t5;
308         unsigned long t6;
309         unsigned long t7;
310         unsigned long s0; /* 16 calle saved */
311         unsigned long s1;
312         unsigned long s2;
313         unsigned long s3;
314         unsigned long s4;
315         unsigned long s5;
316         unsigned long s6;
317         unsigned long s7;
318         unsigned long t8; /* 24 temps */
319         unsigned long t9; /* 25 temp / pic call-through register */
320         unsigned long k0; /* 26 kernel-reserved */
321         unsigned long k1;
322         unsigned long gp; /* 28 */
323         unsigned long sp; /* stack pointer */
324         unsigned long fp; /* frame pointer */
325         unsigned long ra; /* return address */
326 } MonoMipsStackFrame;
327
328 #define MONO_INIT_CONTEXT_FROM_FUNC(ctx,func) do {      \
329                 guint32 sp, ra;                                 \
330                 guint32 *code = (guint32 *)(void *)func;        \
331                 short imm;                                      \
332                 memset ((ctx), 0, sizeof (*(ctx)));             \
333                 __asm__ volatile("addu %0,$0,$29" : "=r" (sp)); \
334                 /* Look for adjustment of sp */                 \
335                 while ((*code & 0xffff0000) != 0x27bd0000)      \
336                         ++code;                                 \
337                 imm = (short) (*code & 0xffff);                 \
338                 MONO_CONTEXT_SET_BP ((ctx), sp + (-imm));       \
339                 ra = *(guint32 *)(sp + (-imm) + MIPS_RET_ADDR_OFFSET);  \
340                 MONO_CONTEXT_SET_IP ((ctx),ra); \
341                 MONO_CONTEXT_SET_SP ((ctx), MONO_CONTEXT_GET_BP (ctx)); \
342         } while (0)
343
344 #define MONO_ARCH_INIT_TOP_LMF_ENTRY(lmf) do { (lmf)->ebp = -1; } while (0)
345
346 /* re-attaches with gdb - sometimes causes executable to hang */
347 #undef HAVE_BACKTRACE_SYMBOLS
348
349 #undef DEBUG_EXCEPTIONS
350
351 #define MONO_ZERO_REG           mips_zero
352
353 #define MONO_EMIT_NEW_MIPS_COND_EXC(cfg,cond,sr1,sr2,name) do { \
354                 MonoInst *inst; \
355                 MONO_INST_NEW ((cfg), (inst), cond); \
356                 inst->inst_p1 = (char*)name; \
357                 inst->sreg1 = sr1; \
358                 inst->sreg2 = sr2; \
359                 MONO_ADD_INS ((cfg)->cbb, inst); \
360         } while (0)
361
362 #ifndef MONO_EMIT_NEW_COMPARE_EXC
363 #define MONO_EMIT_NEW_COMPARE_EXC(cfg, cmp_op, sreg1, sreg2, exc) do { \
364                 switch (OP_MIPS_COND_EXC_##cmp_op) { \
365                 case OP_MIPS_COND_EXC_EQ: \
366                         MONO_EMIT_NEW_MIPS_COND_EXC (cfg, OP_MIPS_COND_EXC_EQ, sreg1, sreg2, exc); \
367                         break; \
368                 case OP_MIPS_COND_EXC_NE_UN: \
369                         MONO_EMIT_NEW_MIPS_COND_EXC (cfg, OP_MIPS_COND_EXC_NE_UN, sreg1, sreg2, exc); \
370                         break; \
371                 case OP_MIPS_COND_EXC_GT: \
372                         MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLT, mips_at, sreg2, sreg1); \
373                         MONO_EMIT_NEW_MIPS_COND_EXC (cfg, OP_MIPS_COND_EXC_NE_UN, mips_at, mips_zero, exc); \
374                         break; \
375                 case OP_MIPS_COND_EXC_GT_UN: \
376                         MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, mips_at, sreg2, sreg1); \
377                         MONO_EMIT_NEW_MIPS_COND_EXC (cfg, OP_MIPS_COND_EXC_NE_UN, mips_at, mips_zero, exc); \
378                         break; \
379                 case OP_MIPS_COND_EXC_LE: \
380                         MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLT, mips_at, sreg2, sreg1); \
381                         MONO_EMIT_NEW_MIPS_COND_EXC (cfg, OP_MIPS_COND_EXC_EQ, mips_at, mips_zero, exc); \
382                         break; \
383                 case OP_MIPS_COND_EXC_LE_UN: \
384                         MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, mips_at, sreg2, sreg1); \
385                         MONO_EMIT_NEW_MIPS_COND_EXC (cfg, OP_MIPS_COND_EXC_EQ, mips_at, mips_zero, exc); \
386                         break; \
387                 case OP_MIPS_COND_EXC_LT: \
388                         MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLT, mips_at, sreg1, sreg2); \
389                         MONO_EMIT_NEW_MIPS_COND_EXC (cfg, OP_MIPS_COND_EXC_NE_UN, mips_at, mips_zero, exc); \
390                         break; \
391                 case OP_MIPS_COND_EXC_LT_UN: \
392                         MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, mips_at, sreg1, sreg2); \
393                         MONO_EMIT_NEW_MIPS_COND_EXC (cfg, OP_MIPS_COND_EXC_NE_UN, mips_at, mips_zero, exc); \
394                         break; \
395                 default: \
396                         g_warning ("unknown comparison %s\n", #cmp_op); \
397                         g_assert_not_reached (); \
398                 } \
399         } while (0)
400 #endif
401
402 #ifndef MONO_EMIT_NEW_COMPARE_IMM_EXC
403 #define MONO_EMIT_NEW_COMPARE_IMM_EXC(cfg, cmp_op, sreg1, imm, exc) do { \
404                 guint32 cmp_reg; \
405                 if (!(imm)) { \
406                         cmp_reg = mips_zero; \
407                 } \
408                 else { \
409                         cmp_reg = mips_at; \
410                         MONO_EMIT_NEW_ICONST (cfg, cmp_reg, (imm)); \
411                 } \
412                 MONO_EMIT_NEW_COMPARE_EXC (cfg, cmp_op, sreg1, cmp_reg, exc); \
413         } while (0)
414 #endif
415
416 #ifndef MONO_EMIT_NEW_ICOMPARE_IMM_EXC
417 #define MONO_EMIT_NEW_ICOMPARE_IMM_EXC(cfg, cmp_op, sreg1, imm, exc) do { \
418                 MONO_EMIT_NEW_COMPARE_IMM_EXC(cfg, cmp_op, sreg1, imm, exc); \
419         } while (0)
420 #endif
421
422 typedef struct {
423         gint8 reg;
424         gint8 size;
425         int vtsize;
426         int offset;
427 } MonoMIPSArgInfo;
428
429 extern guint8 *mips_emit_load_const(guint8 *code, int dreg, mgreg_t v);
430
431 #endif /* __MONO_MINI_MIPS_H__ */