2 * inssel-mips.brg: burg file for special mips instructions
5 * Mark Mason (mason@broadcom.com)
7 * Based on inssel-ppc.brg by
8 * Dietmar Maurer (dietmar@ximian.com)
9 * Paolo Molaro (lupus@ximian.com)
12 * (C) 2002 Ximian, Inc.
15 /* override the arch independant versions with fast mips versions */
17 #undef MONO_EMIT_BOUNDS_CHECK
18 #undef MONO_EMIT_BOUNDS_CHECK_IMM
20 #define MONO_EMIT_BOUNDS_CHECK(cfg, array_reg, array_type, array_length_field, index_reg) do { \
23 #define MONO_EMIT_BOUNDS_CHECK_IMM(cfg, array_reg, array_type, array_length_field, index_imm) do { \
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);
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);
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);
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);
54 MONO_EMIT_BIALU_IMM (s, tree, OP_MIPS_SLTIU, state->reg1, mips_at, 1);
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);
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);
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);
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);
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);
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);
102 # stmt: CEE_BEQ (OP_COMPARE(reg, OP_ICONST)) "0" {
103 # guint32 sreg2 = mips_zero;
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);
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);
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;
123 # if (state->left->right->tree->inst_c0) {
124 # MONO_EMIT_NEW_UNALU (s, OP_ICONST, mips_at, state->left->right->tree->inst_c0);
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);
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;
139 # if (state->left->right->tree->inst_c0) {
140 # MONO_EMIT_NEW_UNALU (s, OP_ICONST, mips_at, state->left->right->tree->inst_c0);
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);
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);
157 # stmt: CEE_BNE_UN (OP_COMPARE(reg, OP_ICONST)) "0" {
158 # guint32 sreg2 = mips_zero;
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
257 tree->inst_left = spvar;
258 mono_bblock_add_inst (s->cbb, tree);
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);
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);
274 stmt: OP_SWITCH (reg) {
276 int n = GPOINTER_TO_INT (tree->klass);
278 MONO_NEW_LABEL (s, label);
280 if (mips_is_imm16 (n))
281 MONO_EMIT_NEW_BIALU_IMM (s, OP_MIPS_SLTIU, mips_at, state->left->reg1, n);
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);
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);
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);
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);
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);
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);
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);
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);
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);
335 reg: OP_LOCALLOC (reg) {
336 tree->dreg = state->reg1;
337 tree->sreg1 = state->left->reg1;
338 mono_bblock_add_inst (s->cbb, tree);
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);
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;
354 tree->sreg1 = state->left->reg1;
355 tree->sreg2 = state->left->reg2;
357 tree->dreg = mips_v0;
358 mono_bblock_add_inst (s->cbb, tree);
361 stmt: OP_SETRET (freg) {
362 if (mono_method_signature (s->method)->ret->type == MONO_TYPE_R4) {
363 tree->opcode = OP_MIPS_CVTSD;
365 tree->opcode = OP_FMOVE;
367 tree->sreg1 = state->left->reg1;
368 tree->dreg = mips_f0;
369 mono_bblock_add_inst (s->cbb, tree);
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);
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;
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;
392 g_assert_not_reached ();
393 tree->inst_imm = con;
396 mono_bblock_add_inst (s->cbb, tree);
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);
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);
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);
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);
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);
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;
429 MONO_EMIT_NEW_STORE_MEMBASE (s, opcode, mips_sp, ai->offset, state->left->reg1);
432 stmt: OP_OUTARG (reg) {
433 MonoCallInst *call = tree->inst_call;
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);
442 stmt: OP_OUTARG (OP_REGVAR) {
443 MonoCallInst *call = tree->inst_call;
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);
452 stmt: OP_OUTARG (lreg) {
453 MonoCallInst *call = tree->inst_call;
454 int tdreg = mono_regstate_next_int (s->rs);
456 if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
457 MONO_EMIT_NEW_UNALU (s, OP_MOVE, tdreg, state->left->reg1);
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;
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);
471 stmt: OP_OUTARG (OP_ICONST) {
472 MonoCallInst *call = tree->inst_call;
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);
481 stmt: OP_OUTARG (CEE_LDIND_REF (OP_REGVAR)) {
482 MonoCallInst *call = tree->inst_call;
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);
492 # FP calculation being passed in GP registers
493 # Need to get FP bit pattern out in GP regs w/o conversion
495 stmt: OP_OUTARG_R8 (freg),
496 stmt: OP_OUTARG (freg) {
497 MonoCallInst *call = tree->inst_call;
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); */
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);
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;
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);
525 # Single-precision FP passed on stack
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;
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);
536 # Single-precision FP passed in register
538 stmt: OP_OUTARG (CEE_LDIND_R4 (base)) {
539 MonoCallInst *call = tree->inst_call;
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);
550 # Load directly into dest float register w/o conversion to DP
553 stmt: OP_OUTARG_R4 (CEE_LDIND_R4 (base)) {
554 MonoCallInst *call = tree->inst_call;
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);
565 # single precision float value passed in FP reg, as a single-precision float
566 # incoming value is in double format.
568 stmt: OP_OUTARG_R4 (freg) {
569 MonoCallInst *call = tree->inst_call;
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);
578 #stmt: OP_OUTARG_R4 (OP_R4CONST) {
579 # MonoCallInst *call = tree->inst_call;
580 # int tdreg = mono_regstate_next_float (s->rs);
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);
590 # single-precision floating point constant in a gp register.
592 stmt: OP_OUTARG (OP_R4CONST) {
593 MonoCallInst *call = tree->inst_call;
594 int tdreg = mono_regstate_next_int (s->rs);
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);
600 stmt: OP_OUTARG_MEMBASE (OP_R4CONST) {
601 MonoMIPSArgInfo *ai = tree->backend.data;
604 if (*(guint32 *) state->left->tree->inst_p0)
605 MONO_EMIT_NEW_ICONST (s, mips_at, *(guint32 *) state->left->tree->inst_p0);
608 MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, mips_sp, ai->offset, reg);
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;
620 int soffset = vt->inst_offset;
621 int doffset = ai->offset;
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);
630 //g_printf ("vt size: %d at R%d + %d\n", ai->offset, vt->inst_basereg, vt->inst_offset);
632 mini_emit_memcpy (s, mips_sp, doffset, vt->inst_basereg, soffset, ovf_size * sizeof (gpointer), 0);
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;
642 //g_printf ("OP_OUTARG_VT: ICONST\n");
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);
650 g_assert_not_reached ();
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;
660 //g_printf ("OP_OUTARG_VT: reg\n");
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);
668 g_assert_not_reached ();
672 stmt: CEE_STIND_R8 (OP_REGVAR, freg) {
673 /* nothing to do: the value is already on the FP stack */
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
746 stmt: CEE_POP (freg) "0" {
750 freg: OP_LCONV_TO_R8 (lreg) {
751 /* nothing to do - emulated */
754 freg: OP_LCONV_TO_R4 (lreg) {
755 /* nothing to do - emulated */
758 freg: OP_LCONV_TO_R_UN (lreg) {
759 /* nothing to do - emulated */
762 freg: OP_FREM (freg, freg) {
763 /* nothing to do - emulated */
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);
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);
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);
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);
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);
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);
798 /* add the operands */
800 MONO_EMIT_NEW_BIALU (s, CEE_ADD, state->reg1, state->left->reg1, state->right->reg1);
802 /* Overflow happens if
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.
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);
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);
818 /* OR(tmp1, tmp2) = 0 if both conditions are true */
819 MONO_EMIT_NEW_BIALU (s, CEE_OR, tmp4, tmp3, tmp1);
821 MONO_EMIT_NEW_BIALU_IMM (s, OP_SHR_IMM, tmp5, tmp4, 31);
823 /* Now, if (tmp4 == 0) then overflow */
824 MONO_EMIT_NEW_COMPARE_EXC (s, EQ, tmp5, mips_zero, "OverflowException");
827 reg: CEE_ADD_OVF_UN (reg, reg) "0" {
828 int tmp1 = mono_regstate_next_int (s->rs);
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"); */
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);
842 MONO_EMIT_NEW_BIALU (s, CEE_SUB, state->reg1, state->left->reg1, state->right->reg1);
844 /* Overflow happens if
847 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
850 * tmp2 = (lhs ^ result)
851 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
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);
861 MONO_EMIT_NEW_COMPARE_EXC (s, NE_UN, tmp5, mips_zero, "OverflowException");
864 reg: CEE_SUB_OVF_UN (reg, reg) "0" {
865 int tmp1 = mono_regstate_next_int (s->rs);
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");