dc226b8a4172e44715fc70883795202fe60e41db
[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_SETREGIMM, 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_SETREGIMM, 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_SETREGIMM, 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_SETREGIMM, 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_SETREGIMM, 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         MONO_EMIT_NEW_UNALU (s, OP_MOVE, mips_v0, state->right->reg1);
299         MONO_EMIT_NEW_UNALU (s, OP_MOVE, mips_v1, state->right->reg2);
300 }
301
302 freg: OP_LCONV_TO_R8 (lreg) {
303         tree->dreg = state->reg1;
304         tree->sreg1 = state->left->reg1;
305         tree->sreg2 = state->left->reg2;
306         mono_bblock_add_inst (s->cbb, tree);
307 }
308
309 freg: OP_LCONV_TO_R4 (lreg) {
310         tree->dreg = state->reg1;
311         tree->sreg1 = state->left->reg1;
312         tree->sreg2 = state->left->reg2;
313         mono_bblock_add_inst (s->cbb, tree);
314 }
315
316 freg: CEE_CONV_R_UN (reg) {
317         tree->dreg = state->reg1;
318         tree->sreg1 = state->left->reg1;
319         mono_bblock_add_inst (s->cbb, tree);
320 }
321
322 reg: OP_LOCALLOC (OP_ICONST) {
323         /* microcoded in mini-mips.c */
324         tree->sreg1 = mono_regstate_next_int (s->rs);
325         tree->dreg = state->reg1;
326         MONO_EMIT_NEW_ICONST (s, tree->sreg1, state->left->tree->inst_c0);
327         mono_bblock_add_inst (s->cbb, tree);
328 }
329
330 reg: OP_LOCALLOC (reg) {
331         tree->dreg = state->reg1;
332         tree->sreg1 = state->left->reg1;
333         mono_bblock_add_inst (s->cbb, tree);
334 }
335
336 stmt: OP_SETRET (reg) {
337         tree->opcode = OP_MOVE;
338         tree->sreg1 = state->left->reg1;
339         tree->dreg = mips_v0;
340         mono_bblock_add_inst (s->cbb, tree);
341 }
342
343 stmt: OP_SETRET (lreg) {
344         tree->opcode = OP_SETLRET;
345         tree->sreg1 = state->left->reg1;
346         tree->sreg2 = state->left->reg2;
347         tree->dreg = mips_v0;
348         mono_bblock_add_inst (s->cbb, tree);
349 }
350
351 stmt: OP_SETRET (freg) {
352         tree->opcode = OP_FMOVE;
353         tree->sreg1 = state->left->reg1;
354         tree->dreg = mips_f0;
355         mono_bblock_add_inst (s->cbb, tree);
356 }
357
358 stmt: OP_SETRET (OP_ICONST) {
359         tree->opcode = OP_ICONST;
360         tree->inst_c0 = state->left->tree->inst_c0;
361         tree->dreg = mips_v0;
362         mono_bblock_add_inst (s->cbb, tree);
363 }
364
365 stmt: CEE_STIND_I (OP_REGVAR, CEE_SUB (CEE_LDIND_I (OP_REGVAR), OP_ICONST)),
366 stmt: CEE_STIND_I4 (OP_REGVAR, CEE_SUB (CEE_LDIND_I4 (OP_REGVAR), OP_ICONST)),
367 stmt: CEE_STIND_I (OP_REGVAR, CEE_ADD (CEE_LDIND_I (OP_REGVAR), OP_ICONST)),
368 stmt: CEE_STIND_I4 (OP_REGVAR, CEE_ADD (CEE_LDIND_I4 (OP_REGVAR), OP_ICONST)) {
369         int con = state->right->right->tree->inst_c0;
370         int dreg = state->left->tree->dreg;
371         int sreg = state->right->left->left->tree->dreg;
372
373         if (state->right->op == CEE_ADD)
374                 tree->opcode = OP_ADD_IMM;
375         else if (state->right->op == CEE_SUB)
376                 tree->opcode = OP_SUB_IMM;
377         else
378                 g_assert_not_reached ();
379         tree->inst_imm = con;
380         tree->sreg1 = sreg;
381         tree->dreg = dreg;
382         mono_bblock_add_inst (s->cbb, tree);
383 }
384
385 stmt: OP_OUTARG_MEMBASE (reg) {
386         MonoMIPSArgInfo *ai = tree->backend.data;
387         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, mips_sp, ai->offset, state->left->reg1);
388 }
389
390 stmt: OP_OUTARG_MEMBASE (OP_REGVAR) {
391         MonoMIPSArgInfo *ai = tree->backend.data;
392         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, mips_sp, ai->offset, state->left->tree->dreg);
393 }
394
395 stmt: OP_OUTARG_MEMBASE (lreg) {
396         MonoMIPSArgInfo *ai = tree->backend.data;
397         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, mips_sp, ai->offset + MINI_MS_WORD_OFFSET, state->left->reg2);
398         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, mips_sp, ai->offset + MINI_LS_WORD_OFFSET, state->left->reg1);
399 }
400
401 stmt: OP_OUTARG_MEMBASE (OP_ICONST) {
402         MonoMIPSArgInfo *ai = tree->backend.data;
403         MONO_EMIT_NEW_STORE_MEMBASE_IMM (s, OP_STORE_MEMBASE_IMM, mips_sp, ai->offset, state->left->tree->inst_c0);
404 }
405
406 stmt: OP_OUTARG_MEMBASE (CEE_LDIND_REF (OP_REGVAR)) {
407         MonoMIPSArgInfo *ai = tree->backend.data;
408         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, mips_sp, ai->offset, state->left->left->tree->dreg);
409 }
410
411 stmt: OP_OUTARG_MEMBASE (freg) {
412         MonoMIPSArgInfo *ai = tree->backend.data;
413         int opcode = ai->size  == 4? OP_STORER4_MEMBASE_REG: OP_STORER8_MEMBASE_REG;
414
415         MONO_EMIT_NEW_STORE_MEMBASE (s, opcode, mips_sp, ai->offset, state->left->reg1);
416 }
417
418 stmt: OP_OUTARG (reg) {
419         MonoCallInst *call = tree->inst_call;
420
421         tree->opcode = OP_SETREG;
422         tree->dreg = mono_regstate_next_int (s->rs);
423         tree->sreg1 = state->left->reg1;
424         mono_bblock_add_inst (s->cbb, tree);
425         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE);
426 }
427
428 stmt: OP_OUTARG (OP_REGVAR) {
429         MonoCallInst *call = tree->inst_call;
430
431         tree->opcode = OP_SETREG;
432         tree->dreg = mono_regstate_next_int (s->rs);
433         tree->sreg1 = state->left->tree->dreg;
434         mono_bblock_add_inst (s->cbb, tree);
435         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE);
436 }
437
438 stmt: OP_OUTARG (lreg) {
439         MonoCallInst *call = tree->inst_call;
440         int tdreg = mono_regstate_next_int (s->rs);
441
442         MONO_EMIT_NEW_UNALU (s, OP_SETREG, tdreg, state->left->reg2);
443         mono_call_inst_add_outarg_reg (s, call, tdreg, tree->backend.reg3, FALSE);
444         tree->opcode = OP_SETREG;
445         tree->dreg = mono_regstate_next_int (s->rs);
446         tree->sreg1 = state->left->reg1;
447         mono_bblock_add_inst (s->cbb, tree);
448         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3 + 1, FALSE);
449 }
450
451 stmt: OP_OUTARG (OP_ICONST) {
452         MonoCallInst *call = tree->inst_call;
453
454         tree->opcode = OP_SETREGIMM;
455         tree->dreg = mono_regstate_next_int (s->rs);
456         tree->inst_c0 = state->left->tree->inst_c0;
457         mono_bblock_add_inst (s->cbb, tree);
458         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE);
459 }
460
461 stmt: OP_OUTARG (CEE_LDIND_REF (OP_REGVAR)) {
462         MonoCallInst *call = tree->inst_call;
463
464         tree->opcode = OP_SETREG;
465         tree->dreg = mono_regstate_next_int (s->rs);
466         tree->sreg1 = state->left->left->tree->dreg;
467         mono_bblock_add_inst (s->cbb, tree);
468         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE);
469 }
470
471 stmt: OP_OUTARG (CEE_LDIND_REF (OP_REGVAR)) {
472         MonoCallInst *call = tree->inst_call;
473
474         tree->opcode = OP_SETREG;
475         tree->sreg1 = state->left->left->tree->dreg;
476         tree->dreg = mono_regstate_next_int (s->rs);
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
482 #
483 # FP calculation being passed in GP registers
484 # Need to get FP bit pattern out in GP regs w/o conversion
485 #
486 stmt: OP_OUTARG_R8 (freg),
487 stmt: OP_OUTARG (freg) {
488         MonoCallInst *call = tree->inst_call;
489
490         /* If we're passing it out as a 4-byte quantity - need to down-convert it first */
491         /* MONO_EMIT_NEW_UNALU (s, OP_FCONV_TO_R4, mips_ftemp, state->left->reg1); */
492         /* MONO_EMIT_NEW_UNALU (s, OP_MIPS_MFC1S, tree->unused & 0xff, mips_ftemp); */
493
494         tree->opcode = OP_SETFREG;
495         tree->dreg = mono_regstate_next_float (s->rs);
496         tree->sreg1 = state->left->reg1;
497         mono_bblock_add_inst (s->cbb, tree);
498         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, TRUE);
499 }
500
501 stmt: OP_OUTARG_R8 (CEE_LDOBJ (base)) {
502         /* small struct with fp value goes in a fp register */
503         MonoInst *vt = state->left->left->tree;
504         int tmpr, soffset, dreg;
505         MonoCallInst *call = tree->inst_call;
506
507         soffset = vt->inst_offset;
508         tmpr = mono_regstate_next_float (s->rs);
509         MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_LOADR4_MEMBASE, tmpr, vt->inst_basereg, soffset);
510         dreg = mono_regstate_next_float (s->rs);
511         MONO_EMIT_NEW_UNALU (s, OP_SETFREG, dreg, tmpr);
512         mono_call_inst_add_outarg_reg (s, call, dreg, tree->backend.reg3, TRUE);
513 }
514
515 #
516 # Single-precision FP passed on stack
517 #
518 stmt: OP_OUTARG_MEMBASE (CEE_LDIND_R4 (base)) {
519         MonoMIPSArgInfo *ai = tree->backend.data;
520         MonoCallInst *call = tree->inst_call;
521         int opcode = (tree->backend.arg_info & 0xff00) == 0x0400? OP_STORER4_MEMBASE_REG: OP_STORER8_MEMBASE_REG;
522
523         MONO_EMIT_NEW_STORE_MEMBASE (s, opcode, mips_sp, ai->offset, state->left->reg1);
524 }
525
526 #
527 # Single-precision FP passed in register
528 #
529 stmt: OP_OUTARG (CEE_LDIND_R4 (base)) {
530         MonoCallInst *call = tree->inst_call;
531
532         tree->opcode = OP_LOADI4_MEMBASE;
533         tree->dreg = mono_regstate_next_float (s->rs);
534         tree->inst_basereg = state->left->left->tree->inst_basereg;
535         tree->inst_offset = state->left->left->tree->inst_offset;
536         mono_bblock_add_inst (s->cbb, tree);
537         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, TRUE);
538 }
539
540 #
541 # Load directly into dest float register w/o conversion to DP
542 #
543
544 stmt: OP_OUTARG_R4 (CEE_LDIND_R4 (base)) {
545         MonoCallInst *call = tree->inst_call;
546
547         tree->opcode = OP_MIPS_LWC1;
548         tree->dreg = mono_regstate_next_float (s->rs);
549         tree->inst_basereg = state->left->left->tree->inst_basereg;
550         tree->inst_offset = state->left->left->tree->inst_offset;
551         mono_bblock_add_inst (s->cbb, tree);
552         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, TRUE);
553 }
554
555 #
556 # single precision float value passed in FP reg, as a single-precision float
557 # incoming value is in double format.
558 #
559 stmt: OP_OUTARG_R4 (freg) {
560         MonoCallInst *call = tree->inst_call;
561
562         tree->opcode = OP_MIPS_CVTSD;
563         tree->sreg1 = state->left->reg1;
564         tree->dreg = mono_regstate_next_float (s->rs);
565         mono_bblock_add_inst (s->cbb, tree);
566         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, TRUE);
567 }
568
569 #stmt: OP_OUTARG_R4 (OP_R4CONST) {
570 #       MonoCallInst *call = tree->inst_call;
571 #       int tdreg = mono_regstate_next_float (s->rs);
572 #
573 #       tree->opcode = OP_MIPS_LWC1;
574 #       tree->inst_p0 = state->left->tree->inst_p0;
575 #       tree->dreg = mono_regstate_next_float (s->rs);
576 #       mono_bblock_add_inst (s->cbb, tree);
577 #       mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, TRUE);
578 #}
579
580 stmt: OP_OUTARG_MEMBASE (CEE_LDIND_R4 (base)) {
581         MonoMIPSArgInfo *ai = tree->backend.data;
582         int opcode = (tree->backend.arg_info & 0xff00) == 0x0400? OP_STORER4_MEMBASE_REG: OP_STORER8_MEMBASE_REG;
583
584         MONO_EMIT_NEW_STORE_MEMBASE (s, opcode, mips_sp, ai->offset, state->left->reg1);
585 }
586
587 #
588 # single-precision floating point constant in a gp register.
589 #
590 stmt: OP_OUTARG (OP_R4CONST) {
591         MonoCallInst *call = tree->inst_call;
592         int tdreg = mono_regstate_next_int (s->rs);
593
594         MONO_EMIT_NEW_ICONST (s, tdreg, *(guint32 *) state->left->tree->inst_p0);
595         mono_call_inst_add_outarg_reg (s, call, tdreg, tree->backend.reg3, FALSE);
596 }
597
598 stmt: OP_OUTARG_MEMBASE (OP_R4CONST) {
599         MonoMIPSArgInfo *ai = tree->backend.data;
600         int reg = mips_at;
601
602         if (*(guint32 *) state->left->tree->inst_p0)
603                 MONO_EMIT_NEW_ICONST (s, mips_at, *(guint32 *) state->left->tree->inst_p0);
604         else
605                 reg = mips_zero;
606         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, mips_sp, ai->offset, reg);
607 }
608
609 stmt: OP_OUTARG_VT (CEE_LDOBJ (base)) {
610         MonoCallInst *call = tree->inst_call;
611         MonoMIPSArgInfo *ai = tree->backend.data;
612         MonoInst *vt = state->left->left->tree;
613         int start_reg = ai->reg;
614         int nregs = ai->size;
615         int ovf_size = ai->vtsize;
616         int i, dreg;
617         int size = 0;
618         int soffset = vt->inst_offset;
619         int doffset = ai->offset;
620
621         //g_printf ("OP_OUTARG_VT: LDOBJ\n");
622         for (i = 0; i < nregs; ++i) {
623                 dreg = mono_regstate_next_int (s->rs);
624                 MONO_EMIT_NEW_LOAD_MEMBASE (s, dreg, vt->inst_basereg, soffset);
625                 mono_call_inst_add_outarg_reg (s, call, dreg, start_reg + i, FALSE);
626                 soffset += sizeof (gpointer);
627                 doffset += sizeof (gpointer);
628         }
629         //g_printf ("vt size: %d at R%d + %d\n", ai->offset, vt->inst_basereg, vt->inst_offset);
630         if (ovf_size != 0) {
631                 mini_emit_memcpy (s, vt->inst_basereg, doffset, vt->inst_basereg, soffset, ovf_size * sizeof (gpointer), 0);
632         }
633 }
634
635 stmt: OP_OUTARG_VT (OP_ICONST) {
636         MonoCallInst *call = tree->inst_call;
637         MonoMIPSArgInfo *ai = tree->backend.data;
638         int start_reg = ai->reg;
639         int nregs = ai->size;
640
641         //g_printf ("OP_OUTARG_VT: ICONST\n");
642         if (nregs) {
643                 tree->opcode = OP_SETREGIMM;
644                 tree->dreg = mono_regstate_next_int (s->rs);
645                 tree->inst_c0 = state->left->tree->inst_c0;
646                 mono_bblock_add_inst (s->cbb, tree);
647                 mono_call_inst_add_outarg_reg (s, call, tree->dreg, start_reg, FALSE);
648         } else {
649                 g_assert_not_reached ();
650         }
651 }
652
653 stmt: OP_OUTARG_VT (reg) {
654         MonoCallInst *call = tree->inst_call;
655         MonoMIPSArgInfo *ai = tree->backend.data;
656         int start_reg = ai->reg;
657         int nregs = ai->size;
658
659         //g_printf ("OP_OUTARG_VT: reg\n");
660         if (nregs) {
661                 tree->opcode = OP_SETREG;
662                 tree->dreg = mono_regstate_next_int (s->rs);
663                 tree->sreg1 = state->left->reg1;
664                 mono_bblock_add_inst (s->cbb, tree);
665                 mono_call_inst_add_outarg_reg (s, call, tree->dreg, start_reg, FALSE);
666         } else {
667                 g_assert_not_reached ();
668         }
669 }
670
671 stmt: CEE_STIND_R8 (OP_REGVAR, freg) {
672         /* nothing to do: the value is already on the FP stack */
673 }
674
675 stmt: CEE_BEQ (OP_COMPARE (freg, freg)) {
676         tree->opcode = OP_FBEQ;
677         tree->sreg1 = state->left->left->reg1;
678         tree->sreg2 = state->left->right->reg1;
679         mono_bblock_add_inst (s->cbb, tree);
680 }
681
682 stmt: CEE_BNE_UN (OP_COMPARE (freg, freg)) {
683         tree->opcode = OP_FBNE_UN;
684         tree->sreg1 = state->left->left->reg1;
685         tree->sreg2 = state->left->right->reg1;
686         mono_bblock_add_inst (s->cbb, tree);
687 }
688
689 stmt: CEE_BLT (OP_COMPARE (freg, freg)) {
690         tree->opcode = OP_FBLT;
691         tree->sreg1 = state->left->left->reg1;
692         tree->sreg2 = state->left->right->reg1;
693         mono_bblock_add_inst (s->cbb, tree);
694 }
695
696 stmt: CEE_BLT_UN (OP_COMPARE (freg, freg)) {
697         tree->opcode = OP_FBLT_UN;
698         tree->sreg1 = state->left->left->reg1;
699         tree->sreg2 = state->left->right->reg1;
700         mono_bblock_add_inst (s->cbb, tree);
701 }
702
703 stmt: CEE_BGT (OP_COMPARE (freg, freg)) {
704         tree->opcode = OP_FBGT;
705         tree->sreg1 = state->left->left->reg1;
706         tree->sreg2 = state->left->right->reg1;
707         mono_bblock_add_inst (s->cbb, tree);
708 }
709
710 stmt: CEE_BGT_UN (OP_COMPARE (freg, freg)) {
711         tree->opcode = OP_FBGT_UN;
712         tree->sreg1 = state->left->left->reg1;
713         tree->sreg2 = state->left->right->reg1;
714         mono_bblock_add_inst (s->cbb, tree);
715 }
716
717 stmt: CEE_BGE  (OP_COMPARE (freg, freg)) {
718         tree->opcode = OP_FBGE;
719         tree->sreg1 = state->left->left->reg1;
720         tree->sreg2 = state->left->right->reg1;
721         mono_bblock_add_inst (s->cbb, tree);
722 }
723
724 stmt: CEE_BGE_UN (OP_COMPARE (freg, freg)) {
725         tree->opcode = OP_FBGE_UN;
726         tree->sreg1 = state->left->left->reg1;
727         tree->sreg2 = state->left->right->reg1;
728         mono_bblock_add_inst (s->cbb, tree);
729 }
730
731 stmt: CEE_BLE  (OP_COMPARE (freg, freg)) {
732         tree->opcode = OP_FBLE;
733         tree->sreg1 = state->left->left->reg1;
734         tree->sreg2 = state->left->right->reg1;
735         mono_bblock_add_inst (s->cbb, tree);
736 }
737
738 stmt: CEE_BLE_UN (OP_COMPARE (freg, freg)) {
739         tree->opcode = OP_FBLE_UN;
740         tree->sreg1 = state->left->left->reg1;
741         tree->sreg2 = state->left->right->reg1;
742         mono_bblock_add_inst (s->cbb, tree);
743 }
744
745 stmt: CEE_POP (freg) "0" {
746         /* nothing to do */
747 }     
748
749 freg: OP_LCONV_TO_R8 (lreg) {
750         /* nothing to do - emulated */
751 }
752
753 freg: OP_LCONV_TO_R4 (lreg) {
754         /* nothing to do - emulated */
755 }
756
757 freg: OP_LCONV_TO_R_UN (lreg) {
758         /* nothing to do - emulated */
759 }
760
761 freg: OP_FREM (freg, freg) {
762         /* nothing to do - emulated */
763 }
764
765 reg: OP_CEQ (OP_COMPARE (freg, freg)) { 
766         MONO_EMIT_BIALU (s, tree, OP_FCEQ, state->reg1, state->left->left->reg1,
767                          state->left->right->reg1);
768 }
769
770 reg: OP_CLT (OP_COMPARE (freg, freg)) { 
771         MONO_EMIT_BIALU (s, tree, OP_FCLT, state->reg1, state->left->left->reg1,
772                          state->left->right->reg1);
773 }
774
775 reg: OP_CLT_UN (OP_COMPARE (freg, freg)) {      
776         MONO_EMIT_BIALU (s, tree, OP_FCLT_UN, state->reg1, state->left->left->reg1,
777                          state->left->right->reg1);
778 }
779
780 reg: OP_CGT (OP_COMPARE (freg, freg)) { 
781         MONO_EMIT_BIALU (s, tree, OP_FCGT, state->reg1, state->left->left->reg1,
782                          state->left->right->reg1);
783 }
784
785 reg: OP_CGT_UN (OP_COMPARE (freg, freg)) {      
786         MONO_EMIT_BIALU (s, tree, OP_FCGT_UN, state->reg1, state->left->left->reg1,
787                          state->left->right->reg1);
788 }
789
790 reg: CEE_ADD_OVF (reg, reg) "0" {
791         int tmp1 = mono_regstate_next_int (s->rs);
792         int tmp2 = mono_regstate_next_int (s->rs);
793         int tmp3 = mono_regstate_next_int (s->rs);
794         int tmp4 = mono_regstate_next_int (s->rs);
795         int tmp5 = mono_regstate_next_int (s->rs);
796
797         /* add the operands */
798
799         MONO_EMIT_NEW_BIALU (s, CEE_ADD, state->reg1, state->left->reg1, state->right->reg1);
800
801         /* Overflow happens if
802          *      neg + neg = pos    or
803          *      pos + pos = neg
804          *
805          * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
806          * XOR of the high bit returns 0 if the signs match
807          * XOR of that with the high bit of the result return 1 if overflow.
808          */
809
810         /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
811         MONO_EMIT_NEW_BIALU (s, CEE_XOR, tmp1, state->left->reg1, state->right->reg1);
812
813         /* set tmp2 = 0 if bit31 of results matches is different than the operands */
814         MONO_EMIT_NEW_BIALU (s, CEE_XOR, tmp2, state->reg1, state->right->reg1);
815         MONO_EMIT_NEW_UNALU (s, CEE_NOT, tmp3, tmp2);
816
817         /* OR(tmp1, tmp2) = 0 if both conditions are true */
818         MONO_EMIT_NEW_BIALU (s, CEE_OR, tmp4, tmp3, tmp1);
819
820         MONO_EMIT_NEW_BIALU_IMM (s, OP_SHR_IMM, tmp5, tmp4, 31);
821
822         /* Now, if (tmp4 == 0) then overflow */
823         MONO_EMIT_NEW_COMPARE_EXC (s, EQ, tmp5, mips_zero, "OverflowException");
824 }
825
826 reg: CEE_ADD_OVF_UN (reg, reg) "0" {
827         int tmp1 = mono_regstate_next_int (s->rs);
828
829         MONO_EMIT_NEW_BIALU (s, CEE_ADD, state->reg1, state->left->reg1, state->right->reg1);
830         MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, tmp1, state->reg1, state->left->reg1);
831 /*      MONO_EMIT_NEW_COMPARE_EXC (s, NE_UN, tmp1, mips_zero, "OverflowException"); */
832 }
833
834 reg: CEE_SUB_OVF (reg, reg) "0" {
835         int tmp1 = mono_regstate_next_int (s->rs);
836         int tmp2 = mono_regstate_next_int (s->rs);
837         int tmp3 = mono_regstate_next_int (s->rs);
838         int tmp4 = mono_regstate_next_int (s->rs);
839         int tmp5 = mono_regstate_next_int (s->rs);
840
841         MONO_EMIT_NEW_BIALU (s, CEE_SUB, state->reg1, state->left->reg1, state->right->reg1);
842
843         /* Overflow happens if
844          *      neg - pos = pos    or
845          *      pos - neg = neg
846          * XOR of bit31 of the lhs & rhs = 1 if the signs are different
847          *
848          * tmp1 = (lhs ^ rhs)
849          * tmp2 = (lhs ^ result)
850          * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
851          */
852
853         /* tmp3 = 1 if the signs of the two inputs differ */
854         MONO_EMIT_NEW_BIALU (s, CEE_XOR, tmp1, state->left->reg1, state->right->reg1);
855         MONO_EMIT_NEW_BIALU (s, CEE_XOR, tmp2, state->left->reg1, state->reg1);
856         MONO_EMIT_NEW_BIALU_IMM (s, OP_MIPS_SLTI, tmp3, tmp1, 0);
857         MONO_EMIT_NEW_BIALU_IMM (s, OP_MIPS_SLTI, tmp4, tmp2, 0);
858         MONO_EMIT_NEW_BIALU (s, CEE_AND, tmp5, tmp4, tmp3);
859
860         MONO_EMIT_NEW_COMPARE_EXC (s, NE_UN, tmp5, mips_zero, "OverflowException");
861 }
862
863 reg: CEE_SUB_OVF_UN (reg, reg) "0" {
864         int tmp1 = mono_regstate_next_int (s->rs);
865
866         MONO_EMIT_NEW_BIALU (s, CEE_SUB, state->reg1, state->left->reg1, state->right->reg1);
867         MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, tmp1, state->left->reg1, state->reg1);
868         MONO_EMIT_NEW_COMPARE_EXC (s, NE_UN, tmp1, mips_zero, "OverflowException");
869 }
870
871
872 %%