/* * inssel-mips.brg: burg file for special mips instructions * * Author: * Mark Mason (mason@broadcom.com) * * Based on inssel-ppc.brg by * Dietmar Maurer (dietmar@ximian.com) * Paolo Molaro (lupus@ximian.com) * * (C) 2006 Broadcom * (C) 2002 Ximian, Inc. */ /* override the arch independant versions with fast mips versions */ #undef MONO_EMIT_BOUNDS_CHECK #undef MONO_EMIT_BOUNDS_CHECK_IMM #define MONO_EMIT_BOUNDS_CHECK(cfg, array_reg, array_type, array_length_field, index_reg) do { \ } while (0) #define MONO_EMIT_BOUNDS_CHECK_IMM(cfg, array_reg, array_type, array_length_field, index_imm) do { \ } while (0) %% # reg: OP_CEQ (OP_COMPARE(reg, reg)), # reg: OP_CLT (OP_COMPARE(reg, reg)), # reg: OP_CLT_UN (OP_COMPARE(reg, reg)), # reg: OP_CGT (OP_COMPARE(reg, reg)), # reg: OP_CGT_UN (OP_COMPARE(reg, reg)) { # tree->dreg = state->reg1; # mono_bblock_add_inst (s->cbb, tree); #} reg: OP_CEQ (OP_COMPARE(reg, reg)) { MONO_EMIT_NEW_BIALU (s, CEE_XOR, mips_at, state->left->left->reg1, state->left->right->reg1); MONO_EMIT_BIALU_IMM (s, tree, OP_MIPS_SLTIU, state->reg1, mips_at, 1); } reg: OP_CEQ (OP_COMPARE(reg, OP_ICONST)) { if (state->left->right->tree->inst_c0) { if (mips_is_imm16(state->left->right->tree->inst_c0)) { MONO_EMIT_NEW_BIALU_IMM (s, OP_MIPS_XORI, mips_at, state->left->left->reg1, state->left->right->tree->inst_c0); } else { MONO_EMIT_NEW_ICONST (s, mips_at, state->left->right->tree->inst_c0); MONO_EMIT_NEW_BIALU (s, CEE_XOR, mips_at, state->left->left->reg1, mips_at); } MONO_EMIT_BIALU_IMM (s, tree, OP_MIPS_SLTIU, state->reg1, mips_at, 1); } else { /* If state->left->left->reg1 is zero, return 1, else return 0 */ MONO_EMIT_BIALU_IMM (s, tree, OP_MIPS_SLTIU, state->reg1, state->left->left->reg1, 1); } } reg: OP_CGT (OP_COMPARE(reg, reg)) { tree->opcode = OP_MIPS_SLT; tree->dreg = state->reg1; tree->sreg1 = state->left->right->reg1; tree->sreg2 = state->left->left->reg1; mono_bblock_add_inst (s->cbb, tree); } reg: OP_CGT_UN (OP_COMPARE(reg, reg)) { tree->opcode = OP_MIPS_SLTU; tree->dreg = state->reg1; tree->sreg1 = state->left->right->reg1; tree->sreg2 = state->left->left->reg1; mono_bblock_add_inst (s->cbb, tree); } reg: OP_CLT (OP_COMPARE(reg, reg)) { tree->opcode = OP_MIPS_SLT; tree->dreg = state->reg1; tree->sreg1 = state->left->left->reg1; tree->sreg2 = state->left->right->reg1; mono_bblock_add_inst (s->cbb, tree); } reg: OP_CLT_UN (OP_COMPARE(reg, reg)) { tree->opcode = OP_MIPS_SLTU; tree->dreg = state->reg1; tree->sreg1 = state->left->left->reg1; tree->sreg2 = state->left->right->reg1; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BEQ (OP_COMPARE(reg, reg)) "0" { tree->opcode = OP_MIPS_BEQ; tree->sreg1 = state->left->left->reg1; tree->sreg2 = state->left->right->reg1; tree->inst_offset = state->left->left->tree->inst_offset; mono_bblock_add_inst (s->cbb, tree); } # stmt: CEE_BEQ (OP_COMPARE(reg, OP_ICONST)) "0" { # guint32 sreg2 = mips_zero; # # if (state->left->right->tree->inst_c0) { # MONO_EMIT_NEW_UNALU (s, OP_ICONST, mips_at, # state->left->right->tree->inst_c0); # sreg2 = mips_at; # } # tree->opcode = OP_MIPS_BEQ; # tree->sreg1 = state->left->left->tree->dreg; # tree->sreg2 = sreg2; # tree->inst_offset = state->left->left->tree->inst_offset; # mono_bblock_add_inst (s->cbb, tree); # } # # stmt: CEE_BEQ(OP_COMPARE (CEE_LDIND_REF (OP_REGVAR), OP_ICONST)), # stmt: CEE_BEQ(OP_COMPARE (CEE_LDIND_I (OP_REGVAR), OP_ICONST)), # stmt: CEE_BEQ(OP_COMPARE (CEE_LDIND_I4 (OP_REGVAR), OP_ICONST)), # stmt: CEE_BEQ(OP_COMPARE (CEE_LDIND_U4 (OP_REGVAR), OP_ICONST)) "0" { # guint32 sreg2 = mips_zero; # # if (state->left->right->tree->inst_c0) { # MONO_EMIT_NEW_UNALU (s, OP_ICONST, mips_at, state->left->right->tree->inst_c0); # sreg2 = mips_at; # } # tree->opcode = OP_MIPS_BEQ; # tree->sreg1 = state->left->left->left->tree->dreg; # tree->sreg2 = sreg2; # mono_bblock_add_inst (s->cbb, tree); # } # # stmt: CEE_BEQ(OP_COMPARE (CEE_LDIND_REF (reg), OP_ICONST)), # stmt: CEE_BEQ(OP_COMPARE (CEE_LDIND_I (reg), OP_ICONST)), # stmt: CEE_BEQ(OP_COMPARE (CEE_LDIND_I4 (reg), OP_ICONST)), # stmt: CEE_BEQ(OP_COMPARE (CEE_LDIND_U4 (reg), OP_ICONST)) "0" { # guint32 sreg2 = mips_zero; # # if (state->left->right->tree->inst_c0) { # MONO_EMIT_NEW_UNALU (s, OP_ICONST, mips_at, state->left->right->tree->inst_c0); # sreg2 = mips_at; # } # tree->opcode = OP_MIPS_BEQ; # tree->sreg1 = state->left->left->left->tree->dreg; # tree->sreg2 = sreg2; # mono_bblock_add_inst (s->cbb, tree); # } stmt: CEE_BNE_UN (OP_COMPARE(reg, reg)) "0" { tree->opcode = OP_MIPS_BNE; tree->sreg1 = state->left->left->reg1; tree->sreg2 = state->left->right->reg1; tree->inst_offset = state->left->left->tree->inst_offset; mono_bblock_add_inst (s->cbb, tree); } # stmt: CEE_BNE_UN (OP_COMPARE(reg, OP_ICONST)) "0" { # guint32 sreg2 = mips_zero; # # if (state->left->right->tree->inst_c0) { # MONO_EMIT_NEW_UNALU (s, OP_ICONST, mips_at, # state->left->right->tree->inst_c0); # sreg2 = mips_at; # } # tree->opcode = OP_MIPS_BNE; # tree->sreg1 = state->left->left->reg1; # tree->sreg2 = sreg2; # tree->inst_offset = state->left->left->tree->inst_offset; # mono_bblock_add_inst (s->cbb, tree); # } stmt: CEE_BGE (OP_COMPARE(reg, reg)) { MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, state->left->left->reg1, state->left->right->reg1); tree->opcode = OP_MIPS_BEQ; tree->sreg1 = mips_at; tree->sreg2 = mips_zero; tree->inst_offset = state->left->left->tree->inst_offset; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BGE_UN (OP_COMPARE(reg, reg)) { MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, state->left->left->reg1, state->left->right->reg1); tree->opcode = OP_MIPS_BEQ; tree->sreg1 = mips_at; tree->sreg2 = mips_zero; tree->inst_offset = state->left->left->tree->inst_offset; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BGT (OP_COMPARE(reg, reg)) { MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, state->left->right->reg1, state->left->left->reg1); tree->opcode = OP_MIPS_BNE; tree->sreg1 = mips_at; tree->sreg2 = mips_zero; tree->inst_offset = state->left->left->tree->inst_offset; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BGT_UN (OP_COMPARE(reg, reg)) { MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, state->left->right->reg1, state->left->left->reg1); tree->opcode = OP_MIPS_BNE; tree->sreg1 = mips_at; tree->sreg2 = mips_zero; tree->inst_offset = state->left->left->tree->inst_offset; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BLE (OP_COMPARE(reg, reg)) { MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, state->left->right->reg1, state->left->left->reg1); tree->opcode = OP_MIPS_BEQ; tree->sreg1 = mips_at; tree->sreg2 = mips_zero; tree->inst_offset = state->left->left->tree->inst_offset; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BLE_UN (OP_COMPARE(reg, reg)) { MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, state->left->right->reg1, state->left->left->reg1); tree->opcode = OP_MIPS_BEQ; tree->sreg1 = mips_at; tree->sreg2 = mips_zero; tree->inst_offset = state->left->left->tree->inst_offset; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BLT (OP_COMPARE(reg, reg)) { MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, state->left->left->reg1, state->left->right->reg1); tree->opcode = OP_MIPS_BNE; tree->sreg1 = mips_at; tree->sreg2 = mips_zero; tree->inst_offset = state->left->left->tree->inst_offset; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BLT_UN (OP_COMPARE(reg, reg)) { MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, state->left->left->reg1, state->left->right->reg1); tree->opcode = OP_MIPS_BNE; tree->sreg1 = mips_at; tree->sreg2 = mips_zero; tree->inst_offset = state->left->left->tree->inst_offset; mono_bblock_add_inst (s->cbb, tree); } # # # # # # # stmt: OP_START_HANDLER { MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region); /*MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, spvar->inst_basereg, spvar->inst_offset, mips_sp); */ tree->inst_left = spvar; mono_bblock_add_inst (s->cbb, tree); } stmt: OP_ENDFINALLY { MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region); tree->inst_left = spvar; mono_bblock_add_inst (s->cbb, tree); } stmt: OP_ENDFILTER (reg) { MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region); tree->inst_left = spvar; tree->sreg1 = state->left->reg1; mono_bblock_add_inst (s->cbb, tree); } stmt: OP_SWITCH (reg) { MonoInst *label; int n = GPOINTER_TO_INT (tree->klass); MONO_NEW_LABEL (s, label); if (mips_is_imm16 (n)) MONO_EMIT_NEW_BIALU_IMM (s, OP_MIPS_SLTIU, mips_at, state->left->reg1, n); else { MONO_EMIT_NEW_UNALU (s, OP_ICONST, mips_at, n); MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, state->left->reg1, mips_at); } MONO_EMIT_NEW_BIALU_IMM (s, OP_MIPS_XORI, mips_at, mips_at, 1); MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_many_bb [n]); mono_bblock_add_inst (s->cbb, label); mono_create_jump_table (s, label, tree->inst_many_bb, n); /* the backend code will deal with aot vs normal case */ tree->sreg1 = state->left->reg1; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_STIND_I8 (OP_REGVAR, lreg) { /* this should only happen for methods returning a long */ if (G_BYTE_ORDER == G_LITTLE_ENDIAN) { MONO_EMIT_NEW_UNALU (s, OP_MOVE, mips_v0, state->right->reg2); MONO_EMIT_NEW_UNALU (s, OP_MOVE, mips_v1, state->right->reg1); } else { MONO_EMIT_NEW_UNALU (s, OP_MOVE, mips_v0, state->right->reg1); MONO_EMIT_NEW_UNALU (s, OP_MOVE, mips_v1, state->right->reg2); } } freg: OP_LCONV_TO_R8 (lreg) { tree->dreg = state->reg1; tree->sreg1 = state->left->reg1; tree->sreg2 = state->left->reg2; mono_bblock_add_inst (s->cbb, tree); } freg: OP_LCONV_TO_R4 (lreg) { tree->dreg = state->reg1; tree->sreg1 = state->left->reg1; tree->sreg2 = state->left->reg2; mono_bblock_add_inst (s->cbb, tree); } freg: CEE_CONV_R_UN (reg) { tree->dreg = state->reg1; tree->sreg1 = state->left->reg1; mono_bblock_add_inst (s->cbb, tree); } reg: OP_LOCALLOC (OP_ICONST) { /* microcoded in mini-mips.c */ tree->sreg1 = mono_regstate_next_int (s->rs); tree->dreg = state->reg1; MONO_EMIT_NEW_ICONST (s, tree->sreg1, state->left->tree->inst_c0); mono_bblock_add_inst (s->cbb, tree); } reg: OP_LOCALLOC (reg) { tree->dreg = state->reg1; tree->sreg1 = state->left->reg1; mono_bblock_add_inst (s->cbb, tree); } stmt: OP_SETRET (reg) { tree->opcode = OP_MOVE; tree->sreg1 = state->left->reg1; tree->dreg = mips_v0; mono_bblock_add_inst (s->cbb, tree); } stmt: OP_SETRET (lreg) { tree->opcode = OP_SETLRET; if (G_BYTE_ORDER == G_LITTLE_ENDIAN) { tree->sreg1 = state->left->reg2; tree->sreg2 = state->left->reg1; } else { tree->sreg1 = state->left->reg1; tree->sreg2 = state->left->reg2; } tree->dreg = mips_v0; mono_bblock_add_inst (s->cbb, tree); } stmt: OP_SETRET (freg) { if (mono_method_signature (s->method)->ret->type == MONO_TYPE_R4) { tree->opcode = OP_MIPS_CVTSD; } else { tree->opcode = OP_FMOVE; } tree->sreg1 = state->left->reg1; tree->dreg = mips_f0; mono_bblock_add_inst (s->cbb, tree); } stmt: OP_SETRET (OP_ICONST) { tree->opcode = OP_ICONST; tree->inst_c0 = state->left->tree->inst_c0; tree->dreg = mips_v0; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_STIND_I (OP_REGVAR, CEE_SUB (CEE_LDIND_I (OP_REGVAR), OP_ICONST)), stmt: CEE_STIND_I4 (OP_REGVAR, CEE_SUB (CEE_LDIND_I4 (OP_REGVAR), OP_ICONST)), stmt: CEE_STIND_I (OP_REGVAR, CEE_ADD (CEE_LDIND_I (OP_REGVAR), OP_ICONST)), stmt: CEE_STIND_I4 (OP_REGVAR, CEE_ADD (CEE_LDIND_I4 (OP_REGVAR), OP_ICONST)) { int con = state->right->right->tree->inst_c0; int dreg = state->left->tree->dreg; int sreg = state->right->left->left->tree->dreg; if (state->right->op == CEE_ADD) tree->opcode = OP_ADD_IMM; else if (state->right->op == CEE_SUB) tree->opcode = OP_SUB_IMM; else g_assert_not_reached (); tree->inst_imm = con; tree->sreg1 = sreg; tree->dreg = dreg; mono_bblock_add_inst (s->cbb, tree); } stmt: OP_OUTARG_MEMBASE (reg) { MonoMIPSArgInfo *ai = tree->backend.data; MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, mips_sp, ai->offset, state->left->reg1); } stmt: OP_OUTARG_MEMBASE (OP_REGVAR) { MonoMIPSArgInfo *ai = tree->backend.data; MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, mips_sp, ai->offset, state->left->tree->dreg); } stmt: OP_OUTARG_MEMBASE (lreg) { MonoMIPSArgInfo *ai = tree->backend.data; MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, mips_sp, ai->offset + MINI_MS_WORD_OFFSET, state->left->reg2); MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, mips_sp, ai->offset + MINI_LS_WORD_OFFSET, state->left->reg1); } stmt: OP_OUTARG_MEMBASE (OP_ICONST) { MonoMIPSArgInfo *ai = tree->backend.data; MONO_EMIT_NEW_STORE_MEMBASE_IMM (s, OP_STORE_MEMBASE_IMM, mips_sp, ai->offset, state->left->tree->inst_c0); } stmt: OP_OUTARG_MEMBASE (CEE_LDIND_REF (OP_REGVAR)) { MonoMIPSArgInfo *ai = tree->backend.data; MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, mips_sp, ai->offset, state->left->left->tree->dreg); } stmt: OP_OUTARG_MEMBASE (freg) { MonoMIPSArgInfo *ai = tree->backend.data; int opcode = ai->size == 4? OP_STORER4_MEMBASE_REG: OP_STORER8_MEMBASE_REG; MONO_EMIT_NEW_STORE_MEMBASE (s, opcode, mips_sp, ai->offset, state->left->reg1); } stmt: OP_OUTARG (reg) { MonoCallInst *call = tree->inst_call; tree->opcode = OP_MOVE; tree->dreg = mono_regstate_next_int (s->rs); tree->sreg1 = state->left->reg1; mono_bblock_add_inst (s->cbb, tree); mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE); } stmt: OP_OUTARG (OP_REGVAR) { MonoCallInst *call = tree->inst_call; tree->opcode = OP_MOVE; tree->dreg = mono_regstate_next_int (s->rs); tree->sreg1 = state->left->tree->dreg; mono_bblock_add_inst (s->cbb, tree); mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE); } stmt: OP_OUTARG (lreg) { MonoCallInst *call = tree->inst_call; int tdreg = mono_regstate_next_int (s->rs); if (G_BYTE_ORDER == G_LITTLE_ENDIAN) MONO_EMIT_NEW_UNALU (s, OP_MOVE, tdreg, state->left->reg1); else MONO_EMIT_NEW_UNALU (s, OP_MOVE, tdreg, state->left->reg2); mono_call_inst_add_outarg_reg (s, call, tdreg, tree->backend.reg3, FALSE); tree->opcode = OP_MOVE; tree->dreg = mono_regstate_next_int (s->rs); if (G_BYTE_ORDER == G_LITTLE_ENDIAN) tree->sreg1 = state->left->reg2; else tree->sreg1 = state->left->reg1; mono_bblock_add_inst (s->cbb, tree); mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3 + 1, FALSE); } stmt: OP_OUTARG (OP_ICONST) { MonoCallInst *call = tree->inst_call; tree->opcode = OP_ICONST; tree->dreg = mono_regstate_next_int (s->rs); tree->inst_c0 = state->left->tree->inst_c0; mono_bblock_add_inst (s->cbb, tree); mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE); } stmt: OP_OUTARG (CEE_LDIND_REF (OP_REGVAR)) { MonoCallInst *call = tree->inst_call; tree->opcode = OP_MOVE; tree->dreg = mono_regstate_next_int (s->rs); tree->sreg1 = state->left->left->tree->dreg; mono_bblock_add_inst (s->cbb, tree); mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE); } # # FP calculation being passed in GP registers # Need to get FP bit pattern out in GP regs w/o conversion # stmt: OP_OUTARG_R8 (freg), stmt: OP_OUTARG (freg) { MonoCallInst *call = tree->inst_call; /* If we're passing it out as a 4-byte quantity - need to down-convert it first */ /* MONO_EMIT_NEW_UNALU (s, OP_FCONV_TO_R4, mips_ftemp, state->left->reg1); */ /* MONO_EMIT_NEW_UNALU (s, OP_MIPS_MFC1S, tree->unused & 0xff, mips_ftemp); */ tree->opcode = OP_FMOVE; tree->dreg = mono_regstate_next_float (s->rs); tree->sreg1 = state->left->reg1; mono_bblock_add_inst (s->cbb, tree); mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, TRUE); } stmt: OP_OUTARG_R8 (CEE_LDOBJ (base)) { /* small struct with fp value goes in a fp register */ MonoInst *vt = state->left->left->tree; int tmpr, soffset, dreg; MonoCallInst *call = tree->inst_call; soffset = vt->inst_offset; tmpr = mono_regstate_next_float (s->rs); MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_LOADR4_MEMBASE, tmpr, vt->inst_basereg, soffset); dreg = mono_regstate_next_float (s->rs); MONO_EMIT_NEW_UNALU (s, OP_FMOVE, dreg, tmpr); mono_call_inst_add_outarg_reg (s, call, dreg, tree->backend.reg3, TRUE); } # # Single-precision FP passed on stack # stmt: OP_OUTARG_MEMBASE (CEE_LDIND_R4 (base)) { MonoMIPSArgInfo *ai = tree->backend.data; int opcode = ai->size == 4? OP_STORER4_MEMBASE_REG: OP_STORER8_MEMBASE_REG; 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); MONO_EMIT_NEW_STORE_MEMBASE (s, opcode, mips_sp, ai->offset, state->left->reg1); } # # Single-precision FP passed in register # stmt: OP_OUTARG (CEE_LDIND_R4 (base)) { MonoCallInst *call = tree->inst_call; tree->opcode = OP_LOADI4_MEMBASE; tree->dreg = mono_regstate_next_float (s->rs); tree->inst_basereg = state->left->left->tree->inst_basereg; tree->inst_offset = state->left->left->tree->inst_offset; mono_bblock_add_inst (s->cbb, tree); mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, TRUE); } # # Load directly into dest float register w/o conversion to DP # stmt: OP_OUTARG_R4 (CEE_LDIND_R4 (base)) { MonoCallInst *call = tree->inst_call; tree->opcode = OP_MIPS_LWC1; tree->dreg = mono_regstate_next_float (s->rs); tree->inst_basereg = state->left->left->tree->inst_basereg; tree->inst_offset = state->left->left->tree->inst_offset; mono_bblock_add_inst (s->cbb, tree); mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, TRUE); } # # single precision float value passed in FP reg, as a single-precision float # incoming value is in double format. # stmt: OP_OUTARG_R4 (freg) { MonoCallInst *call = tree->inst_call; tree->opcode = OP_MIPS_CVTSD; tree->sreg1 = state->left->reg1; tree->dreg = mono_regstate_next_float (s->rs); mono_bblock_add_inst (s->cbb, tree); mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, TRUE); } #stmt: OP_OUTARG_R4 (OP_R4CONST) { # MonoCallInst *call = tree->inst_call; # int tdreg = mono_regstate_next_float (s->rs); # # tree->opcode = OP_MIPS_LWC1; # tree->inst_p0 = state->left->tree->inst_p0; # tree->dreg = mono_regstate_next_float (s->rs); # mono_bblock_add_inst (s->cbb, tree); # mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, TRUE); #} # # single-precision floating point constant in a gp register. # stmt: OP_OUTARG (OP_R4CONST) { MonoCallInst *call = tree->inst_call; int tdreg = mono_regstate_next_int (s->rs); MONO_EMIT_NEW_ICONST (s, tdreg, *(guint32 *) state->left->tree->inst_p0); mono_call_inst_add_outarg_reg (s, call, tdreg, tree->backend.reg3, FALSE); } stmt: OP_OUTARG_MEMBASE (OP_R4CONST) { MonoMIPSArgInfo *ai = tree->backend.data; int reg = mips_at; if (*(guint32 *) state->left->tree->inst_p0) MONO_EMIT_NEW_ICONST (s, mips_at, *(guint32 *) state->left->tree->inst_p0); else reg = mips_zero; MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, mips_sp, ai->offset, reg); } stmt: OP_OUTARG_VT (CEE_LDOBJ (base)) { MonoCallInst *call = tree->inst_call; MonoMIPSArgInfo *ai = tree->backend.data; MonoInst *vt = state->left->left->tree; int start_reg = ai->reg; int nregs = ai->size; int ovf_size = ai->vtsize; int i, dreg; int size = 0; int soffset = vt->inst_offset; int doffset = ai->offset; //g_printf ("OP_OUTARG_VT: LDOBJ\n"); for (i = 0; i < nregs; ++i) { dreg = mono_regstate_next_int (s->rs); MONO_EMIT_NEW_LOAD_MEMBASE (s, dreg, vt->inst_basereg, soffset); mono_call_inst_add_outarg_reg (s, call, dreg, start_reg + i, FALSE); soffset += sizeof (gpointer); } //g_printf ("vt size: %d at R%d + %d\n", ai->offset, vt->inst_basereg, vt->inst_offset); if (ovf_size != 0) { mini_emit_memcpy (s, mips_sp, doffset, vt->inst_basereg, soffset, ovf_size * sizeof (gpointer), 0); } } stmt: OP_OUTARG_VT (OP_ICONST) { MonoCallInst *call = tree->inst_call; MonoMIPSArgInfo *ai = tree->backend.data; int start_reg = ai->reg; int nregs = ai->size; //g_printf ("OP_OUTARG_VT: ICONST\n"); if (nregs) { tree->opcode = OP_ICONST; tree->dreg = mono_regstate_next_int (s->rs); tree->inst_c0 = state->left->tree->inst_c0; mono_bblock_add_inst (s->cbb, tree); mono_call_inst_add_outarg_reg (s, call, tree->dreg, start_reg, FALSE); } else { g_assert_not_reached (); } } stmt: OP_OUTARG_VT (reg) { MonoCallInst *call = tree->inst_call; MonoMIPSArgInfo *ai = tree->backend.data; int start_reg = ai->reg; int nregs = ai->size; //g_printf ("OP_OUTARG_VT: reg\n"); if (nregs) { tree->opcode = OP_MOVE; tree->dreg = mono_regstate_next_int (s->rs); tree->sreg1 = state->left->reg1; mono_bblock_add_inst (s->cbb, tree); mono_call_inst_add_outarg_reg (s, call, tree->dreg, start_reg, FALSE); } else { g_assert_not_reached (); } } stmt: CEE_STIND_R8 (OP_REGVAR, freg) { /* nothing to do: the value is already on the FP stack */ } stmt: CEE_BEQ (OP_COMPARE (freg, freg)) { tree->opcode = OP_FBEQ; tree->sreg1 = state->left->left->reg1; tree->sreg2 = state->left->right->reg1; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BNE_UN (OP_COMPARE (freg, freg)) { tree->opcode = OP_FBNE_UN; tree->sreg1 = state->left->left->reg1; tree->sreg2 = state->left->right->reg1; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BLT (OP_COMPARE (freg, freg)) { tree->opcode = OP_FBLT; tree->sreg1 = state->left->left->reg1; tree->sreg2 = state->left->right->reg1; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BLT_UN (OP_COMPARE (freg, freg)) { tree->opcode = OP_FBLT_UN; tree->sreg1 = state->left->left->reg1; tree->sreg2 = state->left->right->reg1; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BGT (OP_COMPARE (freg, freg)) { tree->opcode = OP_FBGT; tree->sreg1 = state->left->left->reg1; tree->sreg2 = state->left->right->reg1; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BGT_UN (OP_COMPARE (freg, freg)) { tree->opcode = OP_FBGT_UN; tree->sreg1 = state->left->left->reg1; tree->sreg2 = state->left->right->reg1; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BGE (OP_COMPARE (freg, freg)) { tree->opcode = OP_FBGE; tree->sreg1 = state->left->left->reg1; tree->sreg2 = state->left->right->reg1; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BGE_UN (OP_COMPARE (freg, freg)) { tree->opcode = OP_FBGE_UN; tree->sreg1 = state->left->left->reg1; tree->sreg2 = state->left->right->reg1; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BLE (OP_COMPARE (freg, freg)) { tree->opcode = OP_FBLE; tree->sreg1 = state->left->left->reg1; tree->sreg2 = state->left->right->reg1; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BLE_UN (OP_COMPARE (freg, freg)) { tree->opcode = OP_FBLE_UN; tree->sreg1 = state->left->left->reg1; tree->sreg2 = state->left->right->reg1; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_POP (freg) "0" { /* nothing to do */ } freg: OP_LCONV_TO_R8 (lreg) { /* nothing to do - emulated */ } freg: OP_LCONV_TO_R4 (lreg) { /* nothing to do - emulated */ } freg: OP_LCONV_TO_R_UN (lreg) { /* nothing to do - emulated */ } freg: OP_FREM (freg, freg) { /* nothing to do - emulated */ } reg: OP_CEQ (OP_COMPARE (freg, freg)) { MONO_EMIT_BIALU (s, tree, OP_FCEQ, state->reg1, state->left->left->reg1, state->left->right->reg1); } reg: OP_CLT (OP_COMPARE (freg, freg)) { MONO_EMIT_BIALU (s, tree, OP_FCLT, state->reg1, state->left->left->reg1, state->left->right->reg1); } reg: OP_CLT_UN (OP_COMPARE (freg, freg)) { MONO_EMIT_BIALU (s, tree, OP_FCLT_UN, state->reg1, state->left->left->reg1, state->left->right->reg1); } reg: OP_CGT (OP_COMPARE (freg, freg)) { MONO_EMIT_BIALU (s, tree, OP_FCGT, state->reg1, state->left->left->reg1, state->left->right->reg1); } reg: OP_CGT_UN (OP_COMPARE (freg, freg)) { MONO_EMIT_BIALU (s, tree, OP_FCGT_UN, state->reg1, state->left->left->reg1, state->left->right->reg1); } reg: CEE_ADD_OVF (reg, reg) "0" { int tmp1 = mono_regstate_next_int (s->rs); int tmp2 = mono_regstate_next_int (s->rs); int tmp3 = mono_regstate_next_int (s->rs); int tmp4 = mono_regstate_next_int (s->rs); int tmp5 = mono_regstate_next_int (s->rs); /* add the operands */ MONO_EMIT_NEW_BIALU (s, CEE_ADD, state->reg1, state->left->reg1, state->right->reg1); /* Overflow happens if * neg + neg = pos or * pos + pos = neg * * (bit31s of operands match) AND (bit31 of operand != bit31 of result) * XOR of the high bit returns 0 if the signs match * XOR of that with the high bit of the result return 1 if overflow. */ /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */ MONO_EMIT_NEW_BIALU (s, CEE_XOR, tmp1, state->left->reg1, state->right->reg1); /* set tmp2 = 0 if bit31 of results matches is different than the operands */ MONO_EMIT_NEW_BIALU (s, CEE_XOR, tmp2, state->reg1, state->right->reg1); MONO_EMIT_NEW_UNALU (s, CEE_NOT, tmp3, tmp2); /* OR(tmp1, tmp2) = 0 if both conditions are true */ MONO_EMIT_NEW_BIALU (s, CEE_OR, tmp4, tmp3, tmp1); MONO_EMIT_NEW_BIALU_IMM (s, OP_SHR_IMM, tmp5, tmp4, 31); /* Now, if (tmp4 == 0) then overflow */ MONO_EMIT_NEW_COMPARE_EXC (s, EQ, tmp5, mips_zero, "OverflowException"); } reg: CEE_ADD_OVF_UN (reg, reg) "0" { int tmp1 = mono_regstate_next_int (s->rs); MONO_EMIT_NEW_BIALU (s, CEE_ADD, state->reg1, state->left->reg1, state->right->reg1); MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, tmp1, state->reg1, state->left->reg1); /* MONO_EMIT_NEW_COMPARE_EXC (s, NE_UN, tmp1, mips_zero, "OverflowException"); */ } reg: CEE_SUB_OVF (reg, reg) "0" { int tmp1 = mono_regstate_next_int (s->rs); int tmp2 = mono_regstate_next_int (s->rs); int tmp3 = mono_regstate_next_int (s->rs); int tmp4 = mono_regstate_next_int (s->rs); int tmp5 = mono_regstate_next_int (s->rs); MONO_EMIT_NEW_BIALU (s, CEE_SUB, state->reg1, state->left->reg1, state->right->reg1); /* Overflow happens if * neg - pos = pos or * pos - neg = neg * XOR of bit31 of the lhs & rhs = 1 if the signs are different * * tmp1 = (lhs ^ rhs) * tmp2 = (lhs ^ result) * if ((tmp1 < 0) & (tmp2 < 0)) then overflow */ /* tmp3 = 1 if the signs of the two inputs differ */ MONO_EMIT_NEW_BIALU (s, CEE_XOR, tmp1, state->left->reg1, state->right->reg1); MONO_EMIT_NEW_BIALU (s, CEE_XOR, tmp2, state->left->reg1, state->reg1); MONO_EMIT_NEW_BIALU_IMM (s, OP_MIPS_SLTI, tmp3, tmp1, 0); MONO_EMIT_NEW_BIALU_IMM (s, OP_MIPS_SLTI, tmp4, tmp2, 0); MONO_EMIT_NEW_BIALU (s, CEE_AND, tmp5, tmp4, tmp3); MONO_EMIT_NEW_COMPARE_EXC (s, NE_UN, tmp5, mips_zero, "OverflowException"); } reg: CEE_SUB_OVF_UN (reg, reg) "0" { int tmp1 = mono_regstate_next_int (s->rs); MONO_EMIT_NEW_BIALU (s, CEE_SUB, state->reg1, state->left->reg1, state->right->reg1); MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, tmp1, state->left->reg1, state->reg1); MONO_EMIT_NEW_COMPARE_EXC (s, NE_UN, tmp1, mips_zero, "OverflowException"); } %%