int size_to_ia64_load_u_membase_inc (int size); int size_to_store_membase_reg (int size); int size_to_ia64_store_membase_inc_reg (int size); %% # # inssel-ia64.brg: burg file for special IA64 instructions # # Author: # Zoltan Varga (vargaz@gmail.com) # # (C) 2002 Ximian, Inc. # reg: CEE_LDIND_I8 (OP_REGVAR) { state->reg1 = state->left->tree->dreg; } stmt: CEE_STIND_I8 (OP_REGVAR, reg) { MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->left->tree->dreg, state->right->reg1); } reg: CEE_LDIND_I1 (OP_REGVAR) { MONO_EMIT_UNALU (s, tree, OP_SEXT_I1, state->reg1, state->left->tree->dreg);} reg: CEE_LDIND_I2 (OP_REGVAR) { MONO_EMIT_UNALU (s, tree, OP_SEXT_I2, state->reg1, state->left->tree->dreg);} stmt: CEE_BEQ (fpcflags) { tree->opcode = OP_FBEQ; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BNE_UN (fpcflags) { tree->opcode = OP_FBNE_UN; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BLT (fpcflags) { tree->opcode = OP_FBLT; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BLT_UN (fpcflags) { tree->opcode = OP_FBLT_UN; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BGT (fpcflags) { tree->opcode = OP_FBGT; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BGT_UN (fpcflags) { tree->opcode = OP_FBGT_UN; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BGE (fpcflags) { tree->opcode = OP_FBGE; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BGE_UN (fpcflags) { tree->opcode = OP_FBGE_UN; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BLE (fpcflags) { tree->opcode = OP_FBLE; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BLE_UN (fpcflags) { tree->opcode = OP_FBLE_UN; mono_bblock_add_inst (s->cbb, tree); } fpcflags: OP_COMPARE (freg, freg) { tree->opcode = OP_FCOMPARE; mono_bblock_add_inst (s->cbb, tree); } reg: OP_CEQ (fpcflags) { tree->dreg = state->reg1; tree->opcode = OP_FCEQ; mono_bblock_add_inst (s->cbb, tree); } reg: OP_CLT (fpcflags) { tree->dreg = state->reg1; tree->opcode = OP_FCLT; mono_bblock_add_inst (s->cbb, tree); } reg: OP_CLT_UN (fpcflags) { tree->dreg = state->reg1; tree->opcode = OP_FCLT_UN; mono_bblock_add_inst (s->cbb, tree); } reg: OP_CGT (fpcflags) { tree->dreg = state->reg1; tree->opcode = OP_FCGT; mono_bblock_add_inst (s->cbb, tree); } reg: OP_CGT_UN (fpcflags) { tree->dreg = state->reg1; tree->opcode = OP_FCGT_UN; mono_bblock_add_inst (s->cbb, tree); } freg: OP_LCONV_TO_R8 (reg) { /* FIXME: Move this inssel-long.brg */ tree->sreg1 = state->left->reg1; tree->dreg = state->reg1; mono_bblock_add_inst (s->cbb, tree); } freg: OP_LCONV_TO_R4 (reg) { /* FIXME: Move this inssel-long.brg */ tree->sreg1 = state->left->reg1; tree->dreg = state->reg1; mono_bblock_add_inst (s->cbb, tree); } stmt: OP_OUTARG_REG (reg) { /* FIXME: Move this to inssel.brg */ MonoCallInst *call = (MonoCallInst*)tree->inst_right; tree->opcode = OP_MOVE; tree->sreg1 = state->left->reg1; tree->dreg = mono_regstate_next_int (s->rs); mono_bblock_add_inst (s->cbb, tree); mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE); } stmt: OP_OUTARG_REG (CEE_LDIND_I (base)), stmt: OP_OUTARG_REG (CEE_LDIND_REF (base)), stmt: OP_OUTARG_REG (CEE_LDIND_I1 (base)), stmt: OP_OUTARG_REG (CEE_LDIND_U1 (base)), stmt: OP_OUTARG_REG (CEE_LDIND_I2 (base)), stmt: OP_OUTARG_REG (CEE_LDIND_U2 (base)), stmt: OP_OUTARG_REG (CEE_LDIND_I4 (base)), stmt: OP_OUTARG_REG (CEE_LDIND_U4 (base)), stmt: OP_OUTARG_REG (CEE_LDIND_I8 (base)) { /* FIXME: Move this to inssel.brg or inssel-long.brg */ MonoCallInst *call = (MonoCallInst*)tree->inst_right; guint32 dreg; MonoInst *base = state->left->left->tree; dreg = mono_regstate_next_int (s->rs); MONO_EMIT_LOAD_MEMBASE_OP (s, tree, ldind_to_load_membase (state->left->tree->opcode), dreg, base->inst_basereg, base->inst_offset); mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE); } stmt: OP_OUTARG_REG (OP_I8CONST), stmt: OP_OUTARG_REG (OP_ICONST) { /* FIXME: Move this to inssel.brg or inssel-long.brg */ MonoCallInst *call = (MonoCallInst*)tree->inst_right; tree->opcode = OP_ICONST; tree->inst_c0 = state->left->tree->inst_c0; tree->dreg = mono_regstate_next_int (s->rs); mono_bblock_add_inst (s->cbb, tree); mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE); } stmt: OP_OUTARG_REG (CEE_LDIND_I (OP_REGVAR)), stmt: OP_OUTARG_REG (CEE_LDIND_I8 (OP_REGVAR)), stmt: OP_OUTARG_REG (CEE_LDIND_I4 (OP_REGVAR)), stmt: OP_OUTARG_REG (CEE_LDIND_U4 (OP_REGVAR)), stmt: OP_OUTARG_REG (CEE_LDIND_REF (OP_REGVAR)) { MonoCallInst *call = (MonoCallInst*)tree->inst_right; tree->opcode = OP_MOVE; tree->sreg1 = state->left->left->tree->dreg; tree->dreg = mono_regstate_next_int (s->rs); mono_bblock_add_inst (s->cbb, tree); mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE); } stmt: OP_OUTARG_FREG (freg) { MonoCallInst *call = (MonoCallInst*)tree->inst_right; tree->opcode = OP_FMOVE; 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 (reg) { MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI8_MEMBASE_REG, IA64_SP, tree->inst_imm, state->left->reg1); } stmt: OP_OUTARG (freg) { MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORER8_MEMBASE_REG, IA64_SP, tree->inst_imm, state->left->reg1); } stmt: OP_OUTARG_R4 (freg) { MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORER4_MEMBASE_REG, IA64_SP, tree->inst_imm, state->left->reg1); } stmt: OP_OUTARG_REG (OP_LDADDR (OP_REGOFFSET)), stmt: OP_OUTARG_REG (CEE_LDOBJ (OP_REGOFFSET)) { /* FIXME: Move this to inssel.brg */ MonoCallInst *call = (MonoCallInst*)tree->inst_right; tree->opcode = OP_ADD_IMM; tree->sreg1 = state->left->left->tree->inst_basereg; tree->inst_imm = state->left->left->tree->inst_offset; tree->dreg = mono_regstate_next_int (s->rs); mono_bblock_add_inst (s->cbb, tree); mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE); } stmt: OP_SETRET (reg) { tree->opcode = OP_MOVE; tree->sreg1 = state->left->reg1; tree->dreg = MONO_ARCH_RETREG1; mono_bblock_add_inst (s->cbb, tree); } stmt: OP_SETRET (freg) { tree->opcode = OP_FMOVE; tree->sreg1 = state->left->reg1; tree->dreg = MONO_ARCH_FRETREG1; mono_bblock_add_inst (s->cbb, tree); } # Optimized call instructions reg: OP_LCALL_REG (OP_ICONST), reg: OP_LCALL_REG (OP_I8CONST) { /* FIXME: Move this to inssel-long.brg */ tree->opcode = OP_LCALL; ((MonoCallInst*)tree)->fptr = state->left->tree->inst_p0; tree->dreg = state->reg1; mono_bblock_add_inst (s->cbb, tree); } stmt: OP_OUTARG_VT (CEE_LDOBJ (base), base) { MonoInst *vt = state->left->left->tree; MonoInst *stack_addr = state->right->tree; int sz = stack_addr->inst_imm; if (!sz) return; mini_emit_memcpy (s, stack_addr->inst_basereg, stack_addr->inst_offset, vt->inst_basereg, vt->inst_offset, sz, 0); } # This handles trees like outarg_vt (refanytype) stmt: OP_OUTARG_VT (reg, base) { MonoInst *stack_addr = state->right->tree; MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI8_MEMBASE_REG, stack_addr->inst_basereg, stack_addr->inst_offset, state->left->reg1); } stmt: OP_START_HANDLER { mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_ENDFINALLY { mono_bblock_add_inst (s->cbb, tree); } stmt: OP_ENDFILTER (reg) { tree->sreg1 = state->left->reg1; mono_bblock_add_inst (s->cbb, tree); } reg: OP_LOCALLOC (reg) { tree->sreg1 = state->left->reg1; tree->dreg = state->reg1; mono_bblock_add_inst (s->cbb, tree); } reg: CEE_LDIND_REF (OP_REGVAR), reg: CEE_LDIND_I (OP_REGVAR), reg: CEE_LDIND_I8 (OP_REGVAR), reg: CEE_LDIND_I4 (OP_REGVAR), reg: CEE_LDIND_U4 (OP_REGVAR) "0" { state->reg1 = state->left->tree->dreg; tree->dreg = state->reg1; } reg: OP_ATOMIC_ADD_NEW_I4 (base, OP_ICONST), reg: OP_ATOMIC_ADD_NEW_I8 (base, OP_ICONST) { tree->opcode = tree->opcode == OP_ATOMIC_ADD_NEW_I4 ? OP_ATOMIC_ADD_IMM_NEW_I4 : OP_ATOMIC_ADD_IMM_NEW_I8; tree->dreg = state->reg1; tree->inst_imm = state->right->tree->inst_imm; tree->inst_basereg = state->left->tree->inst_basereg; tree->inst_offset = state->left->tree->inst_offset; mono_bblock_add_inst (s->cbb, tree); } cost { int imm = state->right->tree->inst_imm; MBCOND (imm == 1 || imm == 4 || imm == 8 || imm == 16 || imm == -1 || imm == -4 || imm == -8 || imm == -16); return 1; } reg: OP_ATOMIC_EXCHANGE_I4 (base, reg), reg: OP_ATOMIC_EXCHANGE_I8 (base, reg), reg: OP_ATOMIC_ADD_NEW_I4 (base, reg), reg: OP_ATOMIC_ADD_NEW_I8 (base, reg) { tree->opcode = tree->opcode; tree->dreg = state->reg1; tree->sreg2 = state->right->reg1; tree->inst_basereg = state->left->tree->inst_basereg; tree->inst_offset = state->left->tree->inst_offset; mono_bblock_add_inst (s->cbb, tree); } reg: OP_ATOMIC_ADD_IMM_NEW_I4 (base), reg: OP_ATOMIC_ADD_IMM_NEW_I8 (base) { tree->opcode = tree->opcode; tree->dreg = state->reg1; tree->inst_basereg = state->left->tree->inst_basereg; tree->inst_offset = state->left->tree->inst_offset; mono_bblock_add_inst (s->cbb, tree); } # Optimized memset implementation stmt: OP_MEMSET (base) "0" { int dest_reg, dest_reg2, val_reg, unit, align; int size = tree->backend.size; dest_reg = mono_regstate_next_int (s->rs); if (state->left->tree->inst_basereg == s->frame_reg) /* Aligned by mono_allocate_stack_slots */ align = 8; else align = 4; if (tree->inst_imm == 0) val_reg = IA64_R0; else { val_reg = mono_regstate_next_int (s->rs); MONO_EMIT_NEW_ICONST (s, val_reg, tree->inst_imm); } MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, dest_reg, state->left->tree->inst_basereg, state->left->tree->inst_offset); for (unit = align; unit >= 1; unit = unit >> 1) { dest_reg2 = mono_regstate_next_int (s->rs); /* Use two destination regs to increase paralellism */ if (size >= 2 * unit) { int diff = (size / (2 * unit)) * unit; MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, dest_reg2, state->left->tree->inst_basereg, state->left->tree->inst_offset + diff); while (size >= (2 * unit)) { MONO_EMIT_NEW_STORE_MEMBASE (s, size_to_ia64_store_membase_inc_reg (unit), dest_reg, 0, val_reg); MONO_EMIT_NEW_STORE_MEMBASE (s, size_to_ia64_store_membase_inc_reg (unit), dest_reg2, 0, val_reg); size -= 2 * unit; } if (size > 0) MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, dest_reg, dest_reg, diff); } while (size >= unit) { if (size == unit) MONO_EMIT_NEW_STORE_MEMBASE (s, size_to_store_membase_reg (unit), dest_reg, 0, val_reg); else MONO_EMIT_NEW_STORE_MEMBASE (s, size_to_ia64_store_membase_inc_reg (unit), dest_reg, 0, val_reg); size -= unit; } } } # Optimized memcpy implementation stmt: OP_MEMCPY (base, base) "0" { int cur_reg, src_reg, dest_reg, unit; int size = tree->backend.size; int align; src_reg = mono_regstate_next_int (s->rs); dest_reg = mono_regstate_next_int (s->rs); if ((state->left->tree->inst_basereg == s->frame_reg) && (state->right->tree->inst_basereg == s->frame_reg)) /* Aligned by mono_allocate_stack_slots */ align = 8; else align = 4; MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, dest_reg, state->left->tree->inst_basereg, state->left->tree->inst_offset); MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, src_reg, state->right->tree->inst_basereg, state->right->tree->inst_offset); for (unit = align; unit >= 1; unit = unit >> 1) { while (size >= unit) { cur_reg = mono_regstate_next_int (s->rs); MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, size_to_ia64_load_u_membase_inc (unit), cur_reg, src_reg, 0); MONO_EMIT_NEW_STORE_MEMBASE (s, size_to_ia64_store_membase_inc_reg (unit), dest_reg, 0, cur_reg); size -= unit; } } } %% int size_to_ia64_load_u_membase_inc (int size) { switch (size) { case 1: return OP_IA64_LOADU1_MEMBASE_INC; case 2: return OP_IA64_LOADU2_MEMBASE_INC; case 4: return OP_IA64_LOADU4_MEMBASE_INC; case 8: return OP_IA64_LOADI8_MEMBASE_INC; default: g_assert_not_reached (); return -1; } } int size_to_store_membase_reg (int size) { switch (size) { case 1: return OP_STOREI1_MEMBASE_REG; case 2: return OP_STOREI2_MEMBASE_REG; case 4: return OP_STOREI4_MEMBASE_REG; case 8: return OP_STOREI8_MEMBASE_REG; default: g_assert_not_reached (); return -1; } } int size_to_ia64_store_membase_inc_reg (int size) { switch (size) { case 1: return OP_IA64_STOREI1_MEMBASE_INC_REG; case 2: return OP_IA64_STOREI2_MEMBASE_INC_REG; case 4: return OP_IA64_STOREI4_MEMBASE_INC_REG; case 8: return OP_IA64_STOREI8_MEMBASE_INC_REG; default: g_assert_not_reached (); return -1; } }