2008-08-29 Geoff Norton <gnorton@novell.com>
[mono.git] / mono / mini / inssel-mips.brg
1 /*
2  * inssel-mips.brg: burg file for special mips instructions
3  *
4  * Author:
5  *   Mark Mason (mason@broadcom.com)
6  *
7  * Based on inssel-ppc.brg by
8  *   Dietmar Maurer (dietmar@ximian.com)
9  *   Paolo Molaro (lupus@ximian.com)
10  *
11  * (C) 2006 Broadcom
12  * (C) 2002 Ximian, Inc.
13  */
14
15 /* override the arch independant versions with fast mips versions */
16
17 #undef MONO_EMIT_BOUNDS_CHECK
18 #undef MONO_EMIT_BOUNDS_CHECK_IMM
19
20 #define MONO_EMIT_BOUNDS_CHECK(cfg, array_reg, array_type, array_length_field, index_reg) do { \
21         } while (0)
22
23 #define MONO_EMIT_BOUNDS_CHECK_IMM(cfg, array_reg, array_type, array_length_field, index_imm) do { \
24         } while (0)
25 %%
26
27
28 # reg: OP_CEQ (OP_COMPARE(reg, reg)),
29 # reg: OP_CLT (OP_COMPARE(reg, reg)),
30 # reg: OP_CLT_UN (OP_COMPARE(reg, reg)),
31 # reg: OP_CGT (OP_COMPARE(reg, reg)),
32 # reg: OP_CGT_UN (OP_COMPARE(reg, reg)) {       
33 #       tree->dreg = state->reg1;
34 #       mono_bblock_add_inst (s->cbb, tree);
35 #}
36
37 reg: OP_CEQ (OP_COMPARE(reg, reg)) {
38         MONO_EMIT_NEW_BIALU (s, CEE_XOR, mips_at,
39                                 state->left->left->reg1,
40                                 state->left->right->reg1);
41         MONO_EMIT_BIALU_IMM (s, tree, OP_MIPS_SLTIU, state->reg1, mips_at, 1);
42 }
43
44 reg: OP_CEQ (OP_COMPARE(reg, OP_ICONST)) {
45         if (state->left->right->tree->inst_c0) {
46                 if (mips_is_imm16(state->left->right->tree->inst_c0)) {
47                         MONO_EMIT_NEW_BIALU_IMM (s, OP_MIPS_XORI, mips_at,
48                                 state->left->left->reg1, state->left->right->tree->inst_c0);
49                 }
50                 else {
51                         MONO_EMIT_NEW_ICONST (s, mips_at, state->left->right->tree->inst_c0);
52                         MONO_EMIT_NEW_BIALU (s, CEE_XOR, mips_at, state->left->left->reg1, mips_at);
53                 }
54                 MONO_EMIT_BIALU_IMM (s, tree, OP_MIPS_SLTIU, state->reg1, mips_at, 1);
55         }
56         else {
57                 /* If state->left->left->reg1 is zero, return 1, else return 0 */
58                 MONO_EMIT_BIALU_IMM (s, tree, OP_MIPS_SLTIU, state->reg1, state->left->left->reg1, 1);
59         }
60 }
61
62 reg: OP_CGT (OP_COMPARE(reg, reg)) {    
63         tree->opcode = OP_MIPS_SLT;
64         tree->dreg = state->reg1;
65         tree->sreg1 = state->left->right->reg1;
66         tree->sreg2 = state->left->left->reg1;
67         mono_bblock_add_inst (s->cbb, tree);
68 }
69
70 reg: OP_CGT_UN (OP_COMPARE(reg, reg)) { 
71         tree->opcode = OP_MIPS_SLTU;
72         tree->dreg = state->reg1;
73         tree->sreg1 = state->left->right->reg1;
74         tree->sreg2 = state->left->left->reg1;
75         mono_bblock_add_inst (s->cbb, tree);
76 }
77
78 reg: OP_CLT (OP_COMPARE(reg, reg)) {    
79         tree->opcode = OP_MIPS_SLT;
80         tree->dreg = state->reg1;
81         tree->sreg1 = state->left->left->reg1;
82         tree->sreg2 = state->left->right->reg1;
83         mono_bblock_add_inst (s->cbb, tree);
84 }
85
86 reg: OP_CLT_UN (OP_COMPARE(reg, reg)) { 
87         tree->opcode = OP_MIPS_SLTU;
88         tree->dreg = state->reg1;
89         tree->sreg1 = state->left->left->reg1;
90         tree->sreg2 = state->left->right->reg1;
91         mono_bblock_add_inst (s->cbb, tree);
92 }
93
94 stmt: CEE_BEQ (OP_COMPARE(reg, reg)) "0" {
95         tree->opcode = OP_MIPS_BEQ;
96         tree->sreg1 = state->left->left->reg1;
97         tree->sreg2 = state->left->right->reg1;
98         tree->inst_offset = state->left->left->tree->inst_offset;
99         mono_bblock_add_inst (s->cbb, tree);
100 }
101
102 # stmt: CEE_BEQ (OP_COMPARE(reg, OP_ICONST)) "0" {
103 #       guint32 sreg2 = mips_zero;
104
105 #       if (state->left->right->tree->inst_c0) {
106 #               MONO_EMIT_NEW_UNALU (s, OP_ICONST, mips_at,
107 #                                       state->left->right->tree->inst_c0);
108 #               sreg2 = mips_at;
109 #       }
110 #       tree->opcode = OP_MIPS_BEQ;
111 #       tree->sreg1 = state->left->left->tree->dreg;
112 #       tree->sreg2 = sreg2;
113 #       tree->inst_offset = state->left->left->tree->inst_offset;
114 #       mono_bblock_add_inst (s->cbb, tree);
115 # }
116
117 # stmt: CEE_BEQ(OP_COMPARE (CEE_LDIND_REF (OP_REGVAR), OP_ICONST)),
118 # stmt: CEE_BEQ(OP_COMPARE (CEE_LDIND_I (OP_REGVAR), OP_ICONST)),
119 # stmt: CEE_BEQ(OP_COMPARE (CEE_LDIND_I4 (OP_REGVAR), OP_ICONST)),
120 # stmt: CEE_BEQ(OP_COMPARE (CEE_LDIND_U4 (OP_REGVAR), OP_ICONST)) "0" {
121 #       guint32 sreg2 = mips_zero;
122
123 #       if (state->left->right->tree->inst_c0) {
124 #               MONO_EMIT_NEW_UNALU (s, OP_ICONST, mips_at, state->left->right->tree->inst_c0);
125 #               sreg2 = mips_at;
126 #       }
127 #       tree->opcode = OP_MIPS_BEQ;
128 #       tree->sreg1 = state->left->left->left->tree->dreg;
129 #       tree->sreg2 = sreg2;
130 #       mono_bblock_add_inst (s->cbb, tree);
131 # }
132
133 # stmt: CEE_BEQ(OP_COMPARE (CEE_LDIND_REF (reg), OP_ICONST)),
134 # stmt: CEE_BEQ(OP_COMPARE (CEE_LDIND_I (reg), OP_ICONST)),
135 # stmt: CEE_BEQ(OP_COMPARE (CEE_LDIND_I4 (reg), OP_ICONST)),
136 # stmt: CEE_BEQ(OP_COMPARE (CEE_LDIND_U4 (reg), OP_ICONST)) "0" {
137 #       guint32 sreg2 = mips_zero;
138
139 #       if (state->left->right->tree->inst_c0) {
140 #               MONO_EMIT_NEW_UNALU (s, OP_ICONST, mips_at, state->left->right->tree->inst_c0);
141 #               sreg2 = mips_at;
142 #       }
143 #       tree->opcode = OP_MIPS_BEQ;
144 #       tree->sreg1 = state->left->left->left->tree->dreg;
145 #       tree->sreg2 = sreg2;
146 #       mono_bblock_add_inst (s->cbb, tree);
147 # }
148
149 stmt: CEE_BNE_UN (OP_COMPARE(reg, reg)) "0" {
150         tree->opcode = OP_MIPS_BNE;
151         tree->sreg1 = state->left->left->reg1;
152         tree->sreg2 = state->left->right->reg1;
153         tree->inst_offset = state->left->left->tree->inst_offset;
154         mono_bblock_add_inst (s->cbb, tree);
155 }
156
157 # stmt: CEE_BNE_UN (OP_COMPARE(reg, OP_ICONST)) "0" {
158 #       guint32 sreg2 = mips_zero;
159
160 #       if (state->left->right->tree->inst_c0) {
161 #               MONO_EMIT_NEW_UNALU (s, OP_ICONST, mips_at,
162 #                                       state->left->right->tree->inst_c0);
163 #               sreg2 = mips_at;
164 #       }
165 #       tree->opcode = OP_MIPS_BNE;
166 #       tree->sreg1 = state->left->left->reg1;
167 #       tree->sreg2 = sreg2;
168 #       tree->inst_offset = state->left->left->tree->inst_offset;
169 #       mono_bblock_add_inst (s->cbb, tree);
170 # }
171
172 stmt: CEE_BGE (OP_COMPARE(reg, reg)) {
173         MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, state->left->left->reg1, state->left->right->reg1);
174         tree->opcode = OP_MIPS_BEQ;
175         tree->sreg1 = mips_at;
176         tree->sreg2 = mips_zero;
177         tree->inst_offset = state->left->left->tree->inst_offset;
178         mono_bblock_add_inst (s->cbb, tree);
179 }
180
181 stmt: CEE_BGE_UN (OP_COMPARE(reg, reg)) {
182         MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, state->left->left->reg1, state->left->right->reg1);
183         tree->opcode = OP_MIPS_BEQ;
184         tree->sreg1 = mips_at;
185         tree->sreg2 = mips_zero;
186         tree->inst_offset = state->left->left->tree->inst_offset;
187         mono_bblock_add_inst (s->cbb, tree);
188 }
189
190 stmt: CEE_BGT (OP_COMPARE(reg, reg)) {
191         MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, state->left->right->reg1, state->left->left->reg1);
192         tree->opcode = OP_MIPS_BNE;
193         tree->sreg1 = mips_at;
194         tree->sreg2 = mips_zero;
195         tree->inst_offset = state->left->left->tree->inst_offset;
196         mono_bblock_add_inst (s->cbb, tree);
197 }
198
199 stmt: CEE_BGT_UN (OP_COMPARE(reg, reg)) {
200         MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, state->left->right->reg1, state->left->left->reg1);
201         tree->opcode = OP_MIPS_BNE;
202         tree->sreg1 = mips_at;
203         tree->sreg2 = mips_zero;
204         tree->inst_offset = state->left->left->tree->inst_offset;
205         mono_bblock_add_inst (s->cbb, tree);
206 }
207
208 stmt: CEE_BLE (OP_COMPARE(reg, reg)) {
209         MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, state->left->right->reg1, state->left->left->reg1);
210         tree->opcode = OP_MIPS_BEQ;
211         tree->sreg1 = mips_at;
212         tree->sreg2 = mips_zero;
213         tree->inst_offset = state->left->left->tree->inst_offset;
214         mono_bblock_add_inst (s->cbb, tree);
215 }
216
217 stmt: CEE_BLE_UN (OP_COMPARE(reg, reg)) {
218         MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, state->left->right->reg1, state->left->left->reg1);
219         tree->opcode = OP_MIPS_BEQ;
220         tree->sreg1 = mips_at;
221         tree->sreg2 = mips_zero;
222         tree->inst_offset = state->left->left->tree->inst_offset;
223         mono_bblock_add_inst (s->cbb, tree);
224 }
225
226 stmt: CEE_BLT (OP_COMPARE(reg, reg)) {
227         MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, state->left->left->reg1, state->left->right->reg1);
228         tree->opcode = OP_MIPS_BNE;
229         tree->sreg1 = mips_at;
230         tree->sreg2 = mips_zero;
231         tree->inst_offset = state->left->left->tree->inst_offset;
232         mono_bblock_add_inst (s->cbb, tree);
233 }
234
235 stmt: CEE_BLT_UN (OP_COMPARE(reg, reg)) {
236         MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, state->left->left->reg1, state->left->right->reg1);
237         tree->opcode = OP_MIPS_BNE;
238         tree->sreg1 = mips_at;
239         tree->sreg2 = mips_zero;
240         tree->inst_offset = state->left->left->tree->inst_offset;
241         mono_bblock_add_inst (s->cbb, tree);
242 }
243
244 #
245 #
246 #
247 #
248 #
249 #
250 #
251
252
253 stmt: OP_START_HANDLER {
254         MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region);
255         /*MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, spvar->inst_basereg, spvar->inst_offset, mips_sp);
256         */
257         tree->inst_left = spvar;
258         mono_bblock_add_inst (s->cbb, tree);
259 }
260
261 stmt: OP_ENDFINALLY {
262         MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region);
263         tree->inst_left = spvar;
264         mono_bblock_add_inst (s->cbb, tree);
265 }
266
267 stmt: OP_ENDFILTER (reg) {
268         MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region);
269         tree->inst_left = spvar;
270         tree->sreg1 = state->left->reg1;
271         mono_bblock_add_inst (s->cbb, tree);
272 }
273
274 stmt: OP_SWITCH (reg) {
275         MonoInst *label;
276         int n = GPOINTER_TO_INT (tree->klass);
277         
278         MONO_NEW_LABEL (s, label);
279
280         if (mips_is_imm16 (n))
281                 MONO_EMIT_NEW_BIALU_IMM (s, OP_MIPS_SLTIU, mips_at, state->left->reg1, n);
282         else {
283                 MONO_EMIT_NEW_UNALU (s, OP_ICONST, mips_at, n);
284                 MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, state->left->reg1, mips_at);
285         }
286         MONO_EMIT_NEW_BIALU_IMM (s, OP_MIPS_XORI, mips_at, mips_at, 1);
287         MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_many_bb [n]);
288         mono_bblock_add_inst (s->cbb, label);
289         mono_create_jump_table (s, label, tree->inst_many_bb, n);
290
291         /* the backend code will deal with aot vs normal case */
292         tree->sreg1 = state->left->reg1;
293         mono_bblock_add_inst (s->cbb, tree);
294 }
295
296 stmt: CEE_STIND_I8 (OP_REGVAR, lreg) {
297         /* this should only happen for methods returning a long */
298         if (G_BYTE_ORDER == G_LITTLE_ENDIAN) {
299                 MONO_EMIT_NEW_UNALU (s, OP_MOVE, mips_v0, state->right->reg2);
300                 MONO_EMIT_NEW_UNALU (s, OP_MOVE, mips_v1, state->right->reg1);
301         } else {
302                 MONO_EMIT_NEW_UNALU (s, OP_MOVE, mips_v0, state->right->reg1);
303                 MONO_EMIT_NEW_UNALU (s, OP_MOVE, mips_v1, state->right->reg2);
304         }
305 }
306
307 freg: OP_LCONV_TO_R8 (lreg) {
308         tree->dreg = state->reg1;
309         tree->sreg1 = state->left->reg1;
310         tree->sreg2 = state->left->reg2;
311         mono_bblock_add_inst (s->cbb, tree);
312 }
313
314 freg: OP_LCONV_TO_R4 (lreg) {
315         tree->dreg = state->reg1;
316         tree->sreg1 = state->left->reg1;
317         tree->sreg2 = state->left->reg2;
318         mono_bblock_add_inst (s->cbb, tree);
319 }
320
321 freg: CEE_CONV_R_UN (reg) {
322         tree->dreg = state->reg1;
323         tree->sreg1 = state->left->reg1;
324         mono_bblock_add_inst (s->cbb, tree);
325 }
326
327 reg: OP_LOCALLOC (OP_ICONST) {
328         /* microcoded in mini-mips.c */
329         tree->sreg1 = mono_regstate_next_int (s->rs);
330         tree->dreg = state->reg1;
331         MONO_EMIT_NEW_ICONST (s, tree->sreg1, state->left->tree->inst_c0);
332         mono_bblock_add_inst (s->cbb, tree);
333 }
334
335 reg: OP_LOCALLOC (reg) {
336         tree->dreg = state->reg1;
337         tree->sreg1 = state->left->reg1;
338         mono_bblock_add_inst (s->cbb, tree);
339 }
340
341 stmt: OP_SETRET (reg) {
342         tree->opcode = OP_MOVE;
343         tree->sreg1 = state->left->reg1;
344         tree->dreg = mips_v0;
345         mono_bblock_add_inst (s->cbb, tree);
346 }
347
348 stmt: OP_SETRET (lreg) {
349         tree->opcode = OP_SETLRET;
350         if (G_BYTE_ORDER == G_LITTLE_ENDIAN) {
351                 tree->sreg1 = state->left->reg2;
352                 tree->sreg2 = state->left->reg1;
353         } else {
354                 tree->sreg1 = state->left->reg1;
355                 tree->sreg2 = state->left->reg2;
356         }
357         tree->dreg = mips_v0;
358         mono_bblock_add_inst (s->cbb, tree);
359 }
360
361 stmt: OP_SETRET (freg) {
362         if (mono_method_signature (s->method)->ret->type == MONO_TYPE_R4) {
363                 tree->opcode = OP_MIPS_CVTSD;
364         } else {
365                 tree->opcode = OP_FMOVE;
366         }
367         tree->sreg1 = state->left->reg1;
368         tree->dreg = mips_f0;
369         mono_bblock_add_inst (s->cbb, tree);
370 }
371
372 stmt: OP_SETRET (OP_ICONST) {
373         tree->opcode = OP_ICONST;
374         tree->inst_c0 = state->left->tree->inst_c0;
375         tree->dreg = mips_v0;
376         mono_bblock_add_inst (s->cbb, tree);
377 }
378
379 stmt: CEE_STIND_I (OP_REGVAR, CEE_SUB (CEE_LDIND_I (OP_REGVAR), OP_ICONST)),
380 stmt: CEE_STIND_I4 (OP_REGVAR, CEE_SUB (CEE_LDIND_I4 (OP_REGVAR), OP_ICONST)),
381 stmt: CEE_STIND_I (OP_REGVAR, CEE_ADD (CEE_LDIND_I (OP_REGVAR), OP_ICONST)),
382 stmt: CEE_STIND_I4 (OP_REGVAR, CEE_ADD (CEE_LDIND_I4 (OP_REGVAR), OP_ICONST)) {
383         int con = state->right->right->tree->inst_c0;
384         int dreg = state->left->tree->dreg;
385         int sreg = state->right->left->left->tree->dreg;
386
387         if (state->right->op == CEE_ADD)
388                 tree->opcode = OP_ADD_IMM;
389         else if (state->right->op == CEE_SUB)
390                 tree->opcode = OP_SUB_IMM;
391         else
392                 g_assert_not_reached ();
393         tree->inst_imm = con;
394         tree->sreg1 = sreg;
395         tree->dreg = dreg;
396         mono_bblock_add_inst (s->cbb, tree);
397 }
398
399 stmt: OP_OUTARG_MEMBASE (reg) {
400         MonoMIPSArgInfo *ai = tree->backend.data;
401         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, mips_sp, ai->offset, state->left->reg1);
402 }
403
404 stmt: OP_OUTARG_MEMBASE (OP_REGVAR) {
405         MonoMIPSArgInfo *ai = tree->backend.data;
406         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, mips_sp, ai->offset, state->left->tree->dreg);
407 }
408
409 stmt: OP_OUTARG_MEMBASE (lreg) {
410         MonoMIPSArgInfo *ai = tree->backend.data;
411         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, mips_sp, ai->offset + MINI_MS_WORD_OFFSET, state->left->reg2);
412         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, mips_sp, ai->offset + MINI_LS_WORD_OFFSET, state->left->reg1);
413 }
414
415 stmt: OP_OUTARG_MEMBASE (OP_ICONST) {
416         MonoMIPSArgInfo *ai = tree->backend.data;
417         MONO_EMIT_NEW_STORE_MEMBASE_IMM (s, OP_STORE_MEMBASE_IMM, mips_sp, ai->offset, state->left->tree->inst_c0);
418 }
419
420 stmt: OP_OUTARG_MEMBASE (CEE_LDIND_REF (OP_REGVAR)) {
421         MonoMIPSArgInfo *ai = tree->backend.data;
422         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, mips_sp, ai->offset, state->left->left->tree->dreg);
423 }
424
425 stmt: OP_OUTARG_MEMBASE (freg) {
426         MonoMIPSArgInfo *ai = tree->backend.data;
427         int opcode = ai->size  == 4? OP_STORER4_MEMBASE_REG: OP_STORER8_MEMBASE_REG;
428
429         MONO_EMIT_NEW_STORE_MEMBASE (s, opcode, mips_sp, ai->offset, state->left->reg1);
430 }
431
432 stmt: OP_OUTARG (reg) {
433         MonoCallInst *call = tree->inst_call;
434
435         tree->opcode = OP_MOVE;
436         tree->dreg = mono_regstate_next_int (s->rs);
437         tree->sreg1 = state->left->reg1;
438         mono_bblock_add_inst (s->cbb, tree);
439         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE);
440 }
441
442 stmt: OP_OUTARG (OP_REGVAR) {
443         MonoCallInst *call = tree->inst_call;
444
445         tree->opcode = OP_MOVE;
446         tree->dreg = mono_regstate_next_int (s->rs);
447         tree->sreg1 = state->left->tree->dreg;
448         mono_bblock_add_inst (s->cbb, tree);
449         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE);
450 }
451
452 stmt: OP_OUTARG (lreg) {
453         MonoCallInst *call = tree->inst_call;
454         int tdreg = mono_regstate_next_int (s->rs);
455
456         if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
457                 MONO_EMIT_NEW_UNALU (s, OP_MOVE, tdreg, state->left->reg1);
458         else
459                 MONO_EMIT_NEW_UNALU (s, OP_MOVE, tdreg, state->left->reg2);
460         mono_call_inst_add_outarg_reg (s, call, tdreg, tree->backend.reg3, FALSE);
461         tree->opcode = OP_MOVE;
462         tree->dreg = mono_regstate_next_int (s->rs);
463         if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
464                 tree->sreg1 = state->left->reg2;
465         else
466                 tree->sreg1 = state->left->reg1;
467         mono_bblock_add_inst (s->cbb, tree);
468         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3 + 1, FALSE);
469 }
470
471 stmt: OP_OUTARG (OP_ICONST) {
472         MonoCallInst *call = tree->inst_call;
473
474         tree->opcode = OP_ICONST;
475         tree->dreg = mono_regstate_next_int (s->rs);
476         tree->inst_c0 = state->left->tree->inst_c0;
477         mono_bblock_add_inst (s->cbb, tree);
478         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE);
479 }
480
481 stmt: OP_OUTARG (CEE_LDIND_REF (OP_REGVAR)) {
482         MonoCallInst *call = tree->inst_call;
483
484         tree->opcode = OP_MOVE;
485         tree->dreg = mono_regstate_next_int (s->rs);
486         tree->sreg1 = state->left->left->tree->dreg;
487         mono_bblock_add_inst (s->cbb, tree);
488         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE);
489 }
490
491 #
492 # FP calculation being passed in GP registers
493 # Need to get FP bit pattern out in GP regs w/o conversion
494 #
495 stmt: OP_OUTARG_R8 (freg),
496 stmt: OP_OUTARG (freg) {
497         MonoCallInst *call = tree->inst_call;
498
499         /* If we're passing it out as a 4-byte quantity - need to down-convert it first */
500         /* MONO_EMIT_NEW_UNALU (s, OP_FCONV_TO_R4, mips_ftemp, state->left->reg1); */
501         /* MONO_EMIT_NEW_UNALU (s, OP_MIPS_MFC1S, tree->unused & 0xff, mips_ftemp); */
502
503         tree->opcode = OP_FMOVE;
504         tree->dreg = mono_regstate_next_float (s->rs);
505         tree->sreg1 = state->left->reg1;
506         mono_bblock_add_inst (s->cbb, tree);
507         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, TRUE);
508 }
509
510 stmt: OP_OUTARG_R8 (CEE_LDOBJ (base)) {
511         /* small struct with fp value goes in a fp register */
512         MonoInst *vt = state->left->left->tree;
513         int tmpr, soffset, dreg;
514         MonoCallInst *call = tree->inst_call;
515
516         soffset = vt->inst_offset;
517         tmpr = mono_regstate_next_float (s->rs);
518         MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_LOADR4_MEMBASE, tmpr, vt->inst_basereg, soffset);
519         dreg = mono_regstate_next_float (s->rs);
520         MONO_EMIT_NEW_UNALU (s, OP_FMOVE, dreg, tmpr);
521         mono_call_inst_add_outarg_reg (s, call, dreg, tree->backend.reg3, TRUE);
522 }
523
524 #
525 # Single-precision FP passed on stack
526 #
527 stmt: OP_OUTARG_MEMBASE (CEE_LDIND_R4 (base)) {
528         MonoMIPSArgInfo *ai = tree->backend.data;
529         int opcode = ai->size == 4? OP_STORER4_MEMBASE_REG: OP_STORER8_MEMBASE_REG;
530
531         MONO_EMIT_NEW_LOAD_MEMBASE_OP(s, OP_LOADR4_MEMBASE, state->left->reg1, state->left->left->tree->inst_basereg, state->left->left->tree->inst_offset);
532         MONO_EMIT_NEW_STORE_MEMBASE (s, opcode, mips_sp, ai->offset, state->left->reg1);
533 }
534
535 #
536 # Single-precision FP passed in register
537 #
538 stmt: OP_OUTARG (CEE_LDIND_R4 (base)) {
539         MonoCallInst *call = tree->inst_call;
540
541         tree->opcode = OP_LOADI4_MEMBASE;
542         tree->dreg = mono_regstate_next_float (s->rs);
543         tree->inst_basereg = state->left->left->tree->inst_basereg;
544         tree->inst_offset = state->left->left->tree->inst_offset;
545         mono_bblock_add_inst (s->cbb, tree);
546         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, TRUE);
547 }
548
549 #
550 # Load directly into dest float register w/o conversion to DP
551 #
552
553 stmt: OP_OUTARG_R4 (CEE_LDIND_R4 (base)) {
554         MonoCallInst *call = tree->inst_call;
555
556         tree->opcode = OP_MIPS_LWC1;
557         tree->dreg = mono_regstate_next_float (s->rs);
558         tree->inst_basereg = state->left->left->tree->inst_basereg;
559         tree->inst_offset = state->left->left->tree->inst_offset;
560         mono_bblock_add_inst (s->cbb, tree);
561         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, TRUE);
562 }
563
564 #
565 # single precision float value passed in FP reg, as a single-precision float
566 # incoming value is in double format.
567 #
568 stmt: OP_OUTARG_R4 (freg) {
569         MonoCallInst *call = tree->inst_call;
570
571         tree->opcode = OP_MIPS_CVTSD;
572         tree->sreg1 = state->left->reg1;
573         tree->dreg = mono_regstate_next_float (s->rs);
574         mono_bblock_add_inst (s->cbb, tree);
575         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, TRUE);
576 }
577
578 #stmt: OP_OUTARG_R4 (OP_R4CONST) {
579 #       MonoCallInst *call = tree->inst_call;
580 #       int tdreg = mono_regstate_next_float (s->rs);
581 #
582 #       tree->opcode = OP_MIPS_LWC1;
583 #       tree->inst_p0 = state->left->tree->inst_p0;
584 #       tree->dreg = mono_regstate_next_float (s->rs);
585 #       mono_bblock_add_inst (s->cbb, tree);
586 #       mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, TRUE);
587 #}
588
589 #
590 # single-precision floating point constant in a gp register.
591 #
592 stmt: OP_OUTARG (OP_R4CONST) {
593         MonoCallInst *call = tree->inst_call;
594         int tdreg = mono_regstate_next_int (s->rs);
595
596         MONO_EMIT_NEW_ICONST (s, tdreg, *(guint32 *) state->left->tree->inst_p0);
597         mono_call_inst_add_outarg_reg (s, call, tdreg, tree->backend.reg3, FALSE);
598 }
599
600 stmt: OP_OUTARG_MEMBASE (OP_R4CONST) {
601         MonoMIPSArgInfo *ai = tree->backend.data;
602         int reg = mips_at;
603
604         if (*(guint32 *) state->left->tree->inst_p0)
605                 MONO_EMIT_NEW_ICONST (s, mips_at, *(guint32 *) state->left->tree->inst_p0);
606         else
607                 reg = mips_zero;
608         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, mips_sp, ai->offset, reg);
609 }
610
611 stmt: OP_OUTARG_VT (CEE_LDOBJ (base)) {
612         MonoCallInst *call = tree->inst_call;
613         MonoMIPSArgInfo *ai = tree->backend.data;
614         MonoInst *vt = state->left->left->tree;
615         int start_reg = ai->reg;
616         int nregs = ai->size;
617         int ovf_size = ai->vtsize;
618         int i, dreg;
619         int size = 0;
620         int soffset = vt->inst_offset;
621         int doffset = ai->offset;
622
623         //g_printf ("OP_OUTARG_VT: LDOBJ\n");
624         for (i = 0; i < nregs; ++i) {
625                 dreg = mono_regstate_next_int (s->rs);
626                 MONO_EMIT_NEW_LOAD_MEMBASE (s, dreg, vt->inst_basereg, soffset);
627                 mono_call_inst_add_outarg_reg (s, call, dreg, start_reg + i, FALSE);
628                 soffset += sizeof (gpointer);
629         }
630         //g_printf ("vt size: %d at R%d + %d\n", ai->offset, vt->inst_basereg, vt->inst_offset);
631         if (ovf_size != 0) {
632                 mini_emit_memcpy (s, mips_sp, doffset, vt->inst_basereg, soffset, ovf_size * sizeof (gpointer), 0);
633         }
634 }
635
636 stmt: OP_OUTARG_VT (OP_ICONST) {
637         MonoCallInst *call = tree->inst_call;
638         MonoMIPSArgInfo *ai = tree->backend.data;
639         int start_reg = ai->reg;
640         int nregs = ai->size;
641
642         //g_printf ("OP_OUTARG_VT: ICONST\n");
643         if (nregs) {
644                 tree->opcode = OP_ICONST;
645                 tree->dreg = mono_regstate_next_int (s->rs);
646                 tree->inst_c0 = state->left->tree->inst_c0;
647                 mono_bblock_add_inst (s->cbb, tree);
648                 mono_call_inst_add_outarg_reg (s, call, tree->dreg, start_reg, FALSE);
649         } else {
650                 g_assert_not_reached ();
651         }
652 }
653
654 stmt: OP_OUTARG_VT (reg) {
655         MonoCallInst *call = tree->inst_call;
656         MonoMIPSArgInfo *ai = tree->backend.data;
657         int start_reg = ai->reg;
658         int nregs = ai->size;
659
660         //g_printf ("OP_OUTARG_VT: reg\n");
661         if (nregs) {
662                 tree->opcode = OP_MOVE;
663                 tree->dreg = mono_regstate_next_int (s->rs);
664                 tree->sreg1 = state->left->reg1;
665                 mono_bblock_add_inst (s->cbb, tree);
666                 mono_call_inst_add_outarg_reg (s, call, tree->dreg, start_reg, FALSE);
667         } else {
668                 g_assert_not_reached ();
669         }
670 }
671
672 stmt: CEE_STIND_R8 (OP_REGVAR, freg) {
673         /* nothing to do: the value is already on the FP stack */
674 }
675
676 stmt: CEE_BEQ (OP_COMPARE (freg, freg)) {
677         tree->opcode = OP_FBEQ;
678         tree->sreg1 = state->left->left->reg1;
679         tree->sreg2 = state->left->right->reg1;
680         mono_bblock_add_inst (s->cbb, tree);
681 }
682
683 stmt: CEE_BNE_UN (OP_COMPARE (freg, freg)) {
684         tree->opcode = OP_FBNE_UN;
685         tree->sreg1 = state->left->left->reg1;
686         tree->sreg2 = state->left->right->reg1;
687         mono_bblock_add_inst (s->cbb, tree);
688 }
689
690 stmt: CEE_BLT (OP_COMPARE (freg, freg)) {
691         tree->opcode = OP_FBLT;
692         tree->sreg1 = state->left->left->reg1;
693         tree->sreg2 = state->left->right->reg1;
694         mono_bblock_add_inst (s->cbb, tree);
695 }
696
697 stmt: CEE_BLT_UN (OP_COMPARE (freg, freg)) {
698         tree->opcode = OP_FBLT_UN;
699         tree->sreg1 = state->left->left->reg1;
700         tree->sreg2 = state->left->right->reg1;
701         mono_bblock_add_inst (s->cbb, tree);
702 }
703
704 stmt: CEE_BGT (OP_COMPARE (freg, freg)) {
705         tree->opcode = OP_FBGT;
706         tree->sreg1 = state->left->left->reg1;
707         tree->sreg2 = state->left->right->reg1;
708         mono_bblock_add_inst (s->cbb, tree);
709 }
710
711 stmt: CEE_BGT_UN (OP_COMPARE (freg, freg)) {
712         tree->opcode = OP_FBGT_UN;
713         tree->sreg1 = state->left->left->reg1;
714         tree->sreg2 = state->left->right->reg1;
715         mono_bblock_add_inst (s->cbb, tree);
716 }
717
718 stmt: CEE_BGE  (OP_COMPARE (freg, freg)) {
719         tree->opcode = OP_FBGE;
720         tree->sreg1 = state->left->left->reg1;
721         tree->sreg2 = state->left->right->reg1;
722         mono_bblock_add_inst (s->cbb, tree);
723 }
724
725 stmt: CEE_BGE_UN (OP_COMPARE (freg, freg)) {
726         tree->opcode = OP_FBGE_UN;
727         tree->sreg1 = state->left->left->reg1;
728         tree->sreg2 = state->left->right->reg1;
729         mono_bblock_add_inst (s->cbb, tree);
730 }
731
732 stmt: CEE_BLE  (OP_COMPARE (freg, freg)) {
733         tree->opcode = OP_FBLE;
734         tree->sreg1 = state->left->left->reg1;
735         tree->sreg2 = state->left->right->reg1;
736         mono_bblock_add_inst (s->cbb, tree);
737 }
738
739 stmt: CEE_BLE_UN (OP_COMPARE (freg, freg)) {
740         tree->opcode = OP_FBLE_UN;
741         tree->sreg1 = state->left->left->reg1;
742         tree->sreg2 = state->left->right->reg1;
743         mono_bblock_add_inst (s->cbb, tree);
744 }
745
746 stmt: CEE_POP (freg) "0" {
747         /* nothing to do */
748 }     
749
750 freg: OP_LCONV_TO_R8 (lreg) {
751         /* nothing to do - emulated */
752 }
753
754 freg: OP_LCONV_TO_R4 (lreg) {
755         /* nothing to do - emulated */
756 }
757
758 freg: OP_LCONV_TO_R_UN (lreg) {
759         /* nothing to do - emulated */
760 }
761
762 freg: OP_FREM (freg, freg) {
763         /* nothing to do - emulated */
764 }
765
766 reg: OP_CEQ (OP_COMPARE (freg, freg)) { 
767         MONO_EMIT_BIALU (s, tree, OP_FCEQ, state->reg1, state->left->left->reg1,
768                          state->left->right->reg1);
769 }
770
771 reg: OP_CLT (OP_COMPARE (freg, freg)) { 
772         MONO_EMIT_BIALU (s, tree, OP_FCLT, state->reg1, state->left->left->reg1,
773                          state->left->right->reg1);
774 }
775
776 reg: OP_CLT_UN (OP_COMPARE (freg, freg)) {      
777         MONO_EMIT_BIALU (s, tree, OP_FCLT_UN, state->reg1, state->left->left->reg1,
778                          state->left->right->reg1);
779 }
780
781 reg: OP_CGT (OP_COMPARE (freg, freg)) { 
782         MONO_EMIT_BIALU (s, tree, OP_FCGT, state->reg1, state->left->left->reg1,
783                          state->left->right->reg1);
784 }
785
786 reg: OP_CGT_UN (OP_COMPARE (freg, freg)) {      
787         MONO_EMIT_BIALU (s, tree, OP_FCGT_UN, state->reg1, state->left->left->reg1,
788                          state->left->right->reg1);
789 }
790
791 reg: CEE_ADD_OVF (reg, reg) "0" {
792         int tmp1 = mono_regstate_next_int (s->rs);
793         int tmp2 = mono_regstate_next_int (s->rs);
794         int tmp3 = mono_regstate_next_int (s->rs);
795         int tmp4 = mono_regstate_next_int (s->rs);
796         int tmp5 = mono_regstate_next_int (s->rs);
797
798         /* add the operands */
799
800         MONO_EMIT_NEW_BIALU (s, CEE_ADD, state->reg1, state->left->reg1, state->right->reg1);
801
802         /* Overflow happens if
803          *      neg + neg = pos    or
804          *      pos + pos = neg
805          *
806          * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
807          * XOR of the high bit returns 0 if the signs match
808          * XOR of that with the high bit of the result return 1 if overflow.
809          */
810
811         /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
812         MONO_EMIT_NEW_BIALU (s, CEE_XOR, tmp1, state->left->reg1, state->right->reg1);
813
814         /* set tmp2 = 0 if bit31 of results matches is different than the operands */
815         MONO_EMIT_NEW_BIALU (s, CEE_XOR, tmp2, state->reg1, state->right->reg1);
816         MONO_EMIT_NEW_UNALU (s, CEE_NOT, tmp3, tmp2);
817
818         /* OR(tmp1, tmp2) = 0 if both conditions are true */
819         MONO_EMIT_NEW_BIALU (s, CEE_OR, tmp4, tmp3, tmp1);
820
821         MONO_EMIT_NEW_BIALU_IMM (s, OP_SHR_IMM, tmp5, tmp4, 31);
822
823         /* Now, if (tmp4 == 0) then overflow */
824         MONO_EMIT_NEW_COMPARE_EXC (s, EQ, tmp5, mips_zero, "OverflowException");
825 }
826
827 reg: CEE_ADD_OVF_UN (reg, reg) "0" {
828         int tmp1 = mono_regstate_next_int (s->rs);
829
830         MONO_EMIT_NEW_BIALU (s, CEE_ADD, state->reg1, state->left->reg1, state->right->reg1);
831         MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, tmp1, state->reg1, state->left->reg1);
832 /*      MONO_EMIT_NEW_COMPARE_EXC (s, NE_UN, tmp1, mips_zero, "OverflowException"); */
833 }
834
835 reg: CEE_SUB_OVF (reg, reg) "0" {
836         int tmp1 = mono_regstate_next_int (s->rs);
837         int tmp2 = mono_regstate_next_int (s->rs);
838         int tmp3 = mono_regstate_next_int (s->rs);
839         int tmp4 = mono_regstate_next_int (s->rs);
840         int tmp5 = mono_regstate_next_int (s->rs);
841
842         MONO_EMIT_NEW_BIALU (s, CEE_SUB, state->reg1, state->left->reg1, state->right->reg1);
843
844         /* Overflow happens if
845          *      neg - pos = pos    or
846          *      pos - neg = neg
847          * XOR of bit31 of the lhs & rhs = 1 if the signs are different
848          *
849          * tmp1 = (lhs ^ rhs)
850          * tmp2 = (lhs ^ result)
851          * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
852          */
853
854         /* tmp3 = 1 if the signs of the two inputs differ */
855         MONO_EMIT_NEW_BIALU (s, CEE_XOR, tmp1, state->left->reg1, state->right->reg1);
856         MONO_EMIT_NEW_BIALU (s, CEE_XOR, tmp2, state->left->reg1, state->reg1);
857         MONO_EMIT_NEW_BIALU_IMM (s, OP_MIPS_SLTI, tmp3, tmp1, 0);
858         MONO_EMIT_NEW_BIALU_IMM (s, OP_MIPS_SLTI, tmp4, tmp2, 0);
859         MONO_EMIT_NEW_BIALU (s, CEE_AND, tmp5, tmp4, tmp3);
860
861         MONO_EMIT_NEW_COMPARE_EXC (s, NE_UN, tmp5, mips_zero, "OverflowException");
862 }
863
864 reg: CEE_SUB_OVF_UN (reg, reg) "0" {
865         int tmp1 = mono_regstate_next_int (s->rs);
866
867         MONO_EMIT_NEW_BIALU (s, CEE_SUB, state->reg1, state->left->reg1, state->right->reg1);
868         MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, tmp1, state->left->reg1, state->reg1);
869         MONO_EMIT_NEW_COMPARE_EXC (s, NE_UN, tmp1, mips_zero, "OverflowException");
870 }
871
872
873 %%