eaf92e1fdcd4206ada40bae327228c933599e12d
[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_MAX_IREGS 32
8 #define MONO_MAX_FREGS 32
9
10 #define MONO_SAVED_GREGS 32
11 #define MONO_SAVED_FREGS 32
12
13 /*
14  * at and t0 used internally
15  * v0, v1 aren't here for clarity reasons
16  * a0, a1, a2, a3 are for arguments
17  * Use t9 for indirect calls to match the ABI
18  */
19
20 #define MIPS_V_REGS     ((1 << mips_v0) | \
21                          (1 << mips_v1))
22 #define MIPS_T_REGS     ((1 << mips_t0) | \
23                          (1 << mips_t1) | \
24                          (1 << mips_t2) | \
25                          (1 << mips_t3) | \
26                          (1 << mips_t4) | \
27                          (1 << mips_t5) | \
28                          (1 << mips_t6) | \
29                          (1 << mips_t7))
30 #define MIPS_S_REGS     ((1 << mips_s0) | \
31                          (1 << mips_s1) | \
32                          (1 << mips_s2) | \
33                          (1 << mips_s3) | \
34                          (1 << mips_s4) | \
35                          (1 << mips_s5) | \
36                          (1 << mips_s6) | \
37                          (1 << mips_s7) | \
38                          (1 << mips_fp))
39 #define MIPS_A_REGS     ((1 << mips_a0) | \
40                          (1 << mips_a1) | \
41                          (1 << mips_a2) | \
42                          (1 << mips_a3))
43
44 #define mips_temp mips_t8
45
46 #define MONO_ARCH_CALLEE_REGS           (MIPS_T_REGS | MIPS_V_REGS)
47 #define MONO_ARCH_CALLEE_SAVED_REGS     MIPS_S_REGS
48 #define MIPS_ARG_REGS                   MIPS_A_REGS
49
50 #if 0
51 #define MIPS_FP_PAIR(reg)       ((1 << (reg)) | (1 << ((reg)+1)))
52 #else
53 /* Only put the even regs in */
54 #define MIPS_FP_PAIR(reg)       (1 << (reg))
55 #endif
56
57 #define MONO_ARCH_CALLEE_FREGS          (MIPS_FP_PAIR(mips_f0) |        \
58                                          MIPS_FP_PAIR(mips_f2) |        \
59                                          MIPS_FP_PAIR(mips_f4) |        \
60                                          MIPS_FP_PAIR(mips_f6) |        \
61                                          MIPS_FP_PAIR(mips_f8) |        \
62                                          MIPS_FP_PAIR(mips_f10) |       \
63                                          MIPS_FP_PAIR(mips_f12) |       \
64                                          MIPS_FP_PAIR(mips_f14) |       \
65                                          MIPS_FP_PAIR(mips_f16) |       \
66                                          MIPS_FP_PAIR(mips_f18))
67
68 #define MONO_ARCH_CALLEE_SAVED_FREGS    (MIPS_FP_PAIR(mips_f20) |       \
69                                          MIPS_FP_PAIR(mips_f22) |       \
70                                          MIPS_FP_PAIR(mips_f24) |       \
71                                          MIPS_FP_PAIR(mips_f26) |       \
72                                          MIPS_FP_PAIR(mips_f28) |       \
73                                          MIPS_FP_PAIR(mips_f30))
74
75 #define mips_ftemp mips_f18
76
77 #define MONO_ARCH_USE_FPSTACK FALSE
78 #define MONO_ARCH_FPSTACK_SIZE 0
79
80 /* Parameters used by the register allocator */
81 #define MONO_ARCH_HAS_XP_LOCAL_REGALLOC
82
83 /* On Mips, for regpairs, the lower-numbered reg is most significant
84  * This is true in both big and little endian
85  */
86
87 #define MONO_ARCH_INST_SREG2_MASK(ins)          (0)
88 #define MONO_ARCH_INST_IS_REGPAIR(desc)         ((desc) == 'V' || (desc) == 'l')
89 #define MONO_ARCH_INST_REGPAIR_REG2(desc,hreg1) (((desc) == 'l') ? ((hreg1) + 1) : (((desc) == 'V') ? ((hreg1) - 1) : -1))
90 #define MONO_ARCH_INST_IS_FLOAT(desc)           ((desc == 'f') || (desc == 'g'))
91
92 // This define is called to get specific dest register as defined
93 // by md file (letter after "dest"). Overwise return -1
94
95 #define MONO_ARCH_INST_FIXED_REG(desc)          (((desc) == '0') ? mips_zero : (((desc) == 'a') ? mips_at : ((((desc) == 'v')) ? mips_v0 : (((desc) == 'V') ? mips_v1 : (((desc) == 'g') ? mips_f0 : -1)))))
96
97 #define MONO_ARCH_FRAME_ALIGNMENT 8
98
99 /* fixme: align to 16byte instead of 32byte (we align to 32byte to get 
100  * reproduceable results for benchmarks */
101 #define MONO_ARCH_CODE_ALIGNMENT 32
102
103 void mips_patch (guint32 *code, guint32 target);
104
105 struct MonoLMF {
106         gpointer    previous_lmf;
107         gpointer    lmf_addr;
108         MonoMethod *method;
109         gulong     ebp;
110         gulong     eip;
111         gulong     iregs [MONO_SAVED_GREGS];
112         gfloat     fregs [MONO_SAVED_FREGS];
113         gulong     pad;
114 };
115
116 /* we define our own structure and we'll copy the data
117  * from sigcontext/ucontext/mach when we need it.
118  * This also makes us save stack space and time when copying
119  * We might also want to add an additional field to propagate
120  * the original context from the signal handler.
121  */
122 typedef struct {
123         gulong sc_pc;
124         gulong sc_regs [MONO_SAVED_GREGS];
125         gfloat sc_fpregs [MONO_SAVED_FREGS];
126 } MonoContext;
127
128 typedef struct MonoCompileArch {
129         guint           iregs_offset;
130         guint           lmf_offset;
131         guint           spillvar_offset;
132         guint           spillvar_offset_float;
133 } MonoCompileArch;
134
135 #define MONO_ARCH_EMULATE_FCONV_TO_I8 1
136 #define MONO_ARCH_EMULATE_LCONV_TO_R8 1
137 #define MONO_ARCH_EMULATE_LCONV_TO_R4 1
138 #define MONO_ARCH_EMULATE_LCONV_TO_R8_UN 1
139 #define MONO_ARCH_EMULATE_FREM 1
140 #define MONO_ARCH_BIGMUL_INTRINS 1
141
142 #define MIPS_RET_ADDR_OFFSET    (-4)
143 #define MIPS_FP_ADDR_OFFSET     (-8)
144 #define MIPS_STACK_ALIGNMENT    16
145 #define MIPS_STACK_PARAM_OFFSET 16              /* from sp to first parameter */
146 #define MIPS_MINIMAL_STACK_SIZE (4*4 + 4*4)
147 #define MIPS_EXTRA_STACK_SIZE   16              /* from last parameter to top of frame */
148 #define MIPS_FIRST_ARG_REG      mips_a0
149 #define MIPS_LAST_ARG_REG       mips_a3
150 #define MIPS_FIRST_FPARG_REG    mips_f12
151 #define MIPS_LAST_FPARG_REG     mips_f14
152
153
154
155 /* XXX - a mystery, but it works */
156 #define MONO_GET_CONTEXT \
157         void *ctx = (void *)(((int)context)+24);
158
159 /* set the next to 0 once inssel-mips.brg is updated */
160 #define MIPS_PASS_STRUCTS_BY_VALUE 1
161 #define MIPS_SMALL_RET_STRUCT_IN_REG 0
162
163 #define MONO_ARCH_USE_SIGACTION
164 #define MONO_ARCH_NEED_DIV_CHECK 1
165
166 #define MIPS_NUM_REG_ARGS (MIPS_LAST_ARG_REG-MIPS_FIRST_ARG_REG+1)
167 #define MIPS_NUM_REG_FPARGS (MIPS_LAST_FPARG_REG-MIPS_FIRST_FPARG_REG+1)
168
169 /* we have the stack pointer, not the base pointer in sigcontext */
170 #define MONO_CONTEXT_SET_IP(ctx,ip) do { (ctx)->sc_pc = (int)ip; } while (0); 
171 #define MONO_CONTEXT_SET_BP(ctx,bp) do { (ctx)->sc_regs[mips_sp] = (int)bp; } while (0); 
172 #define MONO_CONTEXT_SET_SP(ctx,sp) do { (ctx)->sc_regs[mips_sp] = (int)sp; } while (0); 
173
174 #define MONO_CONTEXT_GET_IP(ctx) ((gpointer)((ctx)->sc_pc))
175 #define MONO_CONTEXT_GET_BP(ctx) ((gpointer)((ctx)->sc_regs[mips_sp]))
176 #define MONO_CONTEXT_GET_SP(ctx) ((gpointer)((ctx)->sc_regs[mips_sp]))
177
178 typedef struct {
179         unsigned long zero;
180         unsigned long at; /* assembler temp */
181         unsigned long v0; /* return values */
182         unsigned long v1;
183         unsigned long a0; /* 4 - func arguments */
184         unsigned long a1;
185         unsigned long a2;
186         unsigned long a3;
187         unsigned long t0; /* 8 temporaries */
188         unsigned long t1;
189         unsigned long t2;
190         unsigned long t3;
191         unsigned long t4;
192         unsigned long t5;
193         unsigned long t6;
194         unsigned long t7;
195         unsigned long s0; /* 16 calle saved */
196         unsigned long s1;
197         unsigned long s2;
198         unsigned long s3;
199         unsigned long s4;
200         unsigned long s5;
201         unsigned long s6;
202         unsigned long s7;
203         unsigned long t8; /* 24 temps */
204         unsigned long t9; /* 25 temp / pic call-through register */
205         unsigned long k0; /* 26 kernel-reserved */
206         unsigned long k1;
207         unsigned long gp; /* 28 */
208         unsigned long sp; /* stack pointer */
209         unsigned long fp; /* frame pointer */
210         unsigned long ra; /* return address */
211 } MonoMipsStackFrame;
212
213 #define MONO_INIT_CONTEXT_FROM_FUNC(ctx,func) do {      \
214                 guint32 sp, ra;                                 \
215                 guint32 *code = (guint32 *)(void *)func;        \
216                 short imm;                                      \
217                 memset ((ctx), 0, sizeof (*(ctx)));             \
218                 __asm__ volatile("addu %0,$0,$29" : "=r" (sp)); \
219                 /* Look for adjustment of sp */                 \
220                 while ((*code & 0xffff0000) != 0x27bd0000)      \
221                         ++code;                                 \
222                 imm = (short) (*code & 0xffff);                 \
223                 MONO_CONTEXT_SET_BP ((ctx), sp + (-imm));       \
224                 ra = *(guint32 *)(sp + (-imm) + MIPS_RET_ADDR_OFFSET);  \
225                 MONO_CONTEXT_SET_IP ((ctx),ra); \
226         } while (0)
227
228 #if 1
229 #define mono_find_jit_info mono_arch_find_jit_info
230 #define CUSTOM_STACK_WALK
231 #endif
232
233 /* re-attaches with gdb - sometimes causes executable to hang */
234 #undef HAVE_BACKTRACE_SYMBOLS
235
236 #undef CUSTOM_EXCEPTION_HANDLING
237
238 #define MONO_ZERO_REG           mips_zero
239
240 #define MONO_EMIT_NEW_BRANCH_UNREG_LABEL(cfg,op,sr1,label) do { \
241                 MonoInst *inst; \
242                 inst = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
243                 inst->opcode = op;      \
244                 inst->sreg1 = sr1;      \
245                 inst->inst_i0 = label;  \
246                 inst->flags = MONO_INST_BRLABEL;        \
247                 mono_bblock_add_inst ((cfg)->cbb, inst); \
248         } while (0)
249
250 #define MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg,op,sr1,sr2,label) do {     \
251                 MonoInst *inst; \
252                 inst = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
253                 inst->opcode = op;      \
254                 inst->sreg1 = sr1;      \
255                 inst->sreg2 = sr2;      \
256                 inst->inst_i0 = label;  \
257                 inst->flags = MONO_INST_BRLABEL;        \
258                 mono_bblock_add_inst ((cfg)->cbb, inst); \
259         } while (0)
260
261 #define MONO_EMIT_NEW_BRANCH_NONZERO_LABEL(cfg,op,sr1,targetbb) do {    \
262                 MonoInst *inst; \
263                 MonoInst *target_label; \
264                 target_label = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
265                 target_label->opcode = OP_LABEL;        \
266                 target_label->next = (targetbb)->code; \
267                 target_label->inst_c0 = (targetbb)->native_offset; \
268                 (targetbb)->code = target_label; \
269                 inst = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
270                 inst->opcode = op;      \
271                 (inst)->sreg1 = sr1; \
272                 (inst)->sreg2 = sr2; \
273                 inst->inst_i0 = target_label;   \
274                 inst->flags = MONO_INST_BRLABEL;        \
275                 mono_bblock_add_inst ((cfg)->cbb, inst); \
276         } while (0)
277
278 #define MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK(cfg,op,sr1,sr2,targetbb) do {        \
279                 MonoInst *inst; \
280                 MonoInst *target_label; \
281                 target_label = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
282                 target_label->opcode = OP_LABEL;        \
283                 target_label->next = (targetbb)->code; \
284                 target_label->inst_c0 = (targetbb)->native_offset; \
285                 (targetbb)->code = target_label; \
286                 inst = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
287                 inst->opcode = op;      \
288                 (inst)->sreg1 = sr1; \
289                 (inst)->sreg2 = sr2; \
290                 inst->inst_i0 = target_label;   \
291                 inst->flags = MONO_INST_BRLABEL;        \
292                 mono_bblock_add_inst ((cfg)->cbb, inst); \
293         } while (0)
294
295 #ifndef MONO_EMIT_NEW_COMPARE_BRANCH_LABEL
296 #define MONO_EMIT_NEW_COMPARE_BRANCH_LABEL(cfg, cmp_op, sreg1, sreg2, label) \
297         do { \
298                 switch (cmp_op) { \
299                 case CEE_BEQ: \
300                         MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BEQ, sreg1, sreg2, label); \
301                         break; \
302                 case CEE_BNE_UN: \
303                         MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BNE, sreg1, sreg2, label); \
304                         break; \
305                 case CEE_BGE: \
306                         MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLT, mips_at, sreg1, sreg2); \
307                         MONO_EMIT_NEW_BIALU_IMM (s, OP_MIPS_XORI, mips_at, mips_at, 1); \
308                         MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BNE, mips_at, mips_zero, label); \
309                         break; \
310                 case CEE_BGE_UN: \
311                         MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, mips_at, sreg1, sreg2); \
312                         MONO_EMIT_NEW_BIALU_IMM (s, OP_MIPS_XORI, mips_at, mips_at, 1); \
313                         MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BNE, mips_at, mips_zero, label); \
314                         break; \
315                 case CEE_BGT: \
316                         MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLT, mips_at, sreg2, sreg1); \
317                         MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BNE, mips_at, mips_zero, label); \
318                         break; \
319                 case CEE_BGT_UN: \
320                         MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, mips_at, sreg2, sreg1); \
321                         MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BNE, mips_at, mips_zero, label); \
322                         break; \
323                 case CEE_BLT: \
324                         MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLT, mips_at, sreg1, sreg2); \
325                         MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BNE, mips_at, mips_zero, label); \
326                         break; \
327                 case CEE_BLT_UN: \
328                         MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, mips_at, sreg1, sreg2); \
329                         MONO_EMIT_NEW_BRANCH_BIREG_LABEL(cfg, OP_MIPS_BNE, mips_at, mips_zero, label); \
330                         break; \
331                 default: \
332                         g_assert_not_reached(); \
333                 } \
334         } while (0)
335 #endif
336
337 #ifndef MONO_EMIT_NEW_COMPARE_IMM_BRANCH_LABEL
338 #define MONO_EMIT_NEW_COMPARE_IMM_BRANCH_LABEL(cfg, cmp_op, sreg1, imm, label) \
339         do { \
340                 guint32 cmp_reg; \
341                 if (!(imm)) { \
342                         cmp_reg = mips_zero; \
343                 } \
344                 else { \
345                         cmp_reg = mips_at; \
346                         MONO_EMIT_NEW_ICONST (cfg, cmp_reg, (imm)); \
347                 } \
348                 MONO_EMIT_NEW_COMPARE_BRANCH_LABEL(cfg, cmp_op, sreg1, cmp_reg, label); \
349         } while (0)
350 #endif
351
352 #ifndef MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK
353 #define MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK(cfg, cmp_op, sreg1, sreg2, block) \
354         do { \
355                 switch (cmp_op) { \
356                 case CEE_BEQ: \
357                         MONO_EMIT_NEW_BRANCH_BIREG_BLOCK(cfg, OP_MIPS_BEQ, sreg1, sreg2, block); \
358                         break; \
359                 case CEE_BNE_UN: \
360                         MONO_EMIT_NEW_BRANCH_BIREG_BLOCK(cfg, OP_MIPS_BNE, sreg1, sreg2, block); \
361                         break; \
362                 case CEE_BLT_UN: \
363                         MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, mips_at, sreg1, sreg2); \
364                         MONO_EMIT_NEW_BRANCH_BIREG_BLOCK(cfg, OP_MIPS_BNE, mips_at, mips_zero, block); \
365                         break; \
366                 default: \
367                         g_assert_not_reached(); \
368                 } \
369         } while (0)
370 #endif
371
372 #ifndef MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK
373 #define MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK(cfg, cmp_op, sreg1, imm, block) \
374         do { \
375                 guint32 cmp_reg; \
376                 if (!(imm)) { \
377                         cmp_reg = mips_zero; \
378                 } \
379                 else { \
380                         cmp_reg = mips_at; \
381                         MONO_EMIT_NEW_ICONST (cfg, cmp_reg, (imm)); \
382                 } \
383                 MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK(cfg, cmp_op, sreg1, cmp_reg, block); \
384         } while (0)
385 #endif
386
387 typedef struct {
388         gint8 reg;
389         gint8 size;
390         int vtsize;
391         int offset;
392 } MonoMIPSArgInfo;
393
394 #endif /* __MONO_MINI_MIPS_H__ */