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_SETREGIMM, 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_SETREGIMM, 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_SETREGIMM, 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_SETREGIMM, 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_SETREGIMM, 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 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);
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);
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);
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);
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);
330 reg: OP_LOCALLOC (reg) {
331 tree->dreg = state->reg1;
332 tree->sreg1 = state->left->reg1;
333 mono_bblock_add_inst (s->cbb, tree);
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);
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);
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);
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);
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;
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;
378 g_assert_not_reached ();
379 tree->inst_imm = con;
382 mono_bblock_add_inst (s->cbb, tree);
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);
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);
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);
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);
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);
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;
415 MONO_EMIT_NEW_STORE_MEMBASE (s, opcode, mips_sp, ai->offset, state->left->reg1);
418 stmt: OP_OUTARG (reg) {
419 MonoCallInst *call = tree->inst_call;
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);
428 stmt: OP_OUTARG (OP_REGVAR) {
429 MonoCallInst *call = tree->inst_call;
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);
438 stmt: OP_OUTARG (lreg) {
439 MonoCallInst *call = tree->inst_call;
440 int tdreg = mono_regstate_next_int (s->rs);
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);
451 stmt: OP_OUTARG (OP_ICONST) {
452 MonoCallInst *call = tree->inst_call;
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);
461 stmt: OP_OUTARG (CEE_LDIND_REF (OP_REGVAR)) {
462 MonoCallInst *call = tree->inst_call;
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);
471 stmt: OP_OUTARG (CEE_LDIND_REF (OP_REGVAR)) {
472 MonoCallInst *call = tree->inst_call;
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);
483 # FP calculation being passed in GP registers
484 # Need to get FP bit pattern out in GP regs w/o conversion
486 stmt: OP_OUTARG_R8 (freg),
487 stmt: OP_OUTARG (freg) {
488 MonoCallInst *call = tree->inst_call;
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); */
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);
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;
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);
516 # Single-precision FP passed on stack
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;
523 MONO_EMIT_NEW_STORE_MEMBASE (s, opcode, mips_sp, ai->offset, state->left->reg1);
527 # Single-precision FP passed in register
529 stmt: OP_OUTARG (CEE_LDIND_R4 (base)) {
530 MonoCallInst *call = tree->inst_call;
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);
541 # Load directly into dest float register w/o conversion to DP
544 stmt: OP_OUTARG_R4 (CEE_LDIND_R4 (base)) {
545 MonoCallInst *call = tree->inst_call;
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);
556 # single precision float value passed in FP reg, as a single-precision float
557 # incoming value is in double format.
559 stmt: OP_OUTARG_R4 (freg) {
560 MonoCallInst *call = tree->inst_call;
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);
569 #stmt: OP_OUTARG_R4 (OP_R4CONST) {
570 # MonoCallInst *call = tree->inst_call;
571 # int tdreg = mono_regstate_next_float (s->rs);
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);
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;
584 MONO_EMIT_NEW_STORE_MEMBASE (s, opcode, mips_sp, ai->offset, state->left->reg1);
588 # single-precision floating point constant in a gp register.
590 stmt: OP_OUTARG (OP_R4CONST) {
591 MonoCallInst *call = tree->inst_call;
592 int tdreg = mono_regstate_next_int (s->rs);
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);
598 stmt: OP_OUTARG_MEMBASE (OP_R4CONST) {
599 MonoMIPSArgInfo *ai = tree->backend.data;
602 if (*(guint32 *) state->left->tree->inst_p0)
603 MONO_EMIT_NEW_ICONST (s, mips_at, *(guint32 *) state->left->tree->inst_p0);
606 MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, mips_sp, ai->offset, reg);
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;
618 int soffset = vt->inst_offset;
619 int doffset = ai->offset;
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);
629 //g_printf ("vt size: %d at R%d + %d\n", ai->offset, vt->inst_basereg, vt->inst_offset);
631 mini_emit_memcpy (s, vt->inst_basereg, doffset, vt->inst_basereg, soffset, ovf_size * sizeof (gpointer), 0);
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;
641 //g_printf ("OP_OUTARG_VT: ICONST\n");
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);
649 g_assert_not_reached ();
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;
659 //g_printf ("OP_OUTARG_VT: reg\n");
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);
667 g_assert_not_reached ();
671 stmt: CEE_STIND_R8 (OP_REGVAR, freg) {
672 /* nothing to do: the value is already on the FP stack */
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
745 stmt: CEE_POP (freg) "0" {
749 freg: OP_LCONV_TO_R8 (lreg) {
750 /* nothing to do - emulated */
753 freg: OP_LCONV_TO_R4 (lreg) {
754 /* nothing to do - emulated */
757 freg: OP_LCONV_TO_R_UN (lreg) {
758 /* nothing to do - emulated */
761 freg: OP_FREM (freg, freg) {
762 /* nothing to do - emulated */
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);
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);
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);
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);
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);
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);
797 /* add the operands */
799 MONO_EMIT_NEW_BIALU (s, CEE_ADD, state->reg1, state->left->reg1, state->right->reg1);
801 /* Overflow happens if
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.
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);
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);
817 /* OR(tmp1, tmp2) = 0 if both conditions are true */
818 MONO_EMIT_NEW_BIALU (s, CEE_OR, tmp4, tmp3, tmp1);
820 MONO_EMIT_NEW_BIALU_IMM (s, OP_SHR_IMM, tmp5, tmp4, 31);
822 /* Now, if (tmp4 == 0) then overflow */
823 MONO_EMIT_NEW_COMPARE_EXC (s, EQ, tmp5, mips_zero, "OverflowException");
826 reg: CEE_ADD_OVF_UN (reg, reg) "0" {
827 int tmp1 = mono_regstate_next_int (s->rs);
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"); */
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);
841 MONO_EMIT_NEW_BIALU (s, CEE_SUB, state->reg1, state->left->reg1, state->right->reg1);
843 /* Overflow happens if
846 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
849 * tmp2 = (lhs ^ result)
850 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
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);
860 MONO_EMIT_NEW_COMPARE_EXC (s, NE_UN, tmp5, mips_zero, "OverflowException");
863 reg: CEE_SUB_OVF_UN (reg, reg) "0" {
864 int tmp1 = mono_regstate_next_int (s->rs);
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");