%% # # inssel-alpha.brg: burg file for special Alpha instructions # # Author: # Sergey Tikhonov (tsv@solvo.ru) # # Derived work from other arches # # stmt: OP_OUTARG_REG (reg) { 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_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_SETRET (reg) { tree->opcode = OP_MOVE; tree->sreg1 = state->left->reg1; tree->dreg = alpha_r0; mono_bblock_add_inst (s->cbb, tree); } stmt: OP_SETRET (freg) { tree->opcode = OP_FMOVE; tree->sreg1 = state->left->reg1; tree->dreg = alpha_f0; mono_bblock_add_inst (s->cbb, tree); } reg: OP_LOCALLOC (OP_ICONST) { /* microcoded in mini-arm.c */ tree->sreg1 = mono_regstate_next_int (s->rs); tree->dreg = state->reg1; if (tree->flags & MONO_INST_INIT) tree->sreg2 = mono_regstate_next_int (s->rs); 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; if (tree->flags & MONO_INST_INIT) tree->sreg2 = mono_regstate_next_int (s->rs); mono_bblock_add_inst (s->cbb, tree); } # 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_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) { /* FIXME: Move this to inssel.brg or inssel-long.brg */ MonoCallInst *call = (MonoCallInst*)tree->inst_right; tree->opcode = OP_I8CONST; 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 (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_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_OUTARG (reg) { MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI8_MEMBASE_REG, alpha_sp, tree->dreg, state->left->reg1); } stmt: OP_OUTARG (freg) { MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORER8_MEMBASE_REG, alpha_sp, tree->dreg, state->left->reg1); } stmt: OP_OUTARG_R4 (freg) { MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORER4_MEMBASE_REG, alpha_sp, tree->dreg, state->left->reg1); } stmt: OP_OUTARG_R8 (freg) { MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORER8_MEMBASE_REG, alpha_sp, tree->dreg, state->left->reg1); } 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 { MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region); 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 offset_reg = mono_regstate_next_int (s->rs); int target_reg = mono_regstate_next_int (s->rs); int n = GPOINTER_TO_INT (tree->klass); MONO_NEW_LABEL (s, label); MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->reg1, n); MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BGE_UN, tree->inst_many_bb [n]); if (sizeof (gpointer) == 8) MONO_EMIT_NEW_BIALU_IMM (s, OP_SHL_IMM, offset_reg, state->left->reg1, 3); else MONO_EMIT_NEW_BIALU_IMM (s, OP_SHL_IMM, offset_reg, state->left->reg1, 2); mono_bblock_add_inst (s->cbb, label); if (s->compile_aot) { int table_reg = mono_regstate_next_int (s->rs); int sum_reg = mono_regstate_next_int (s->rs); MonoJumpInfoBBTable *table; table = mono_mempool_alloc (s->mempool, sizeof (MonoJumpInfoBBTable)); table->table = tree->inst_many_bb; table->table_size = n; MONO_EMIT_NEW_AOTCONST (s, table_reg, table, MONO_PATCH_INFO_SWITCH); MONO_EMIT_NEW_BIALU (s, CEE_ADD, sum_reg, table_reg, offset_reg); MONO_EMIT_NEW_LOAD_MEMBASE (s, target_reg, sum_reg, 0); } else { mono_create_jump_table (s, label, tree->inst_many_bb, n); /* On Alpha GP points to the beginning of procedure. Here is a sequence: unop lda at, offset(gp) br ... skip two longs 2 longs = jump table address addq at, offset_reg, dest_reg br_reg dest_reg */ MONO_EMIT_NEW_UNALU(s, OP_MOVE, alpha_at, alpha_at); MONO_EMIT_NEW_UNALU(s, OP_MOVE, alpha_at, alpha_at); MONO_EMIT_NEW_UNALU(s, OP_MOVE, alpha_at, alpha_at); MONO_EMIT_NEW_UNALU(s, OP_MOVE, alpha_at, alpha_at); MONO_EMIT_NEW_UNALU(s, OP_MOVE, alpha_at, alpha_at); MONO_EMIT_NEW_UNALU(s, OP_MOVE, alpha_at, alpha_at); MONO_EMIT_NEW_BIALU (s, CEE_ADD, target_reg, alpha_at, offset_reg); MONO_EMIT_NEW_LOAD_MEMBASE (s, target_reg, target_reg, 0); /* the backend must patch the address. we use 0xf0f0f0f0 to avoid the usage * of special (short) opcodes on x86 if (sizeof (gpointer) == 8) MONO_EMIT_NEW_LOAD_MEMBASE (s, target_reg, offset_reg, (long)0xf0f0f0f0f0f0f0f1LL); else MONO_EMIT_NEW_LOAD_MEMBASE (s, target_reg, offset_reg, 0xf0f0f0f0); */ } MONO_EMIT_UNALU (s, tree, OP_BR_REG, -1, target_reg); } 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 (OP_LCOMPARE(reg, OP_I8CONST)) { # printf("Found match for CEE_BEQ (OP_LCOMPARE(reg, OP_I8CONST))\n"); #} # Compare floats sequences (comments from Zoltan Varga) # # non-un comparisions should return false if the arguments are not # comparable, ie. 1.0 < nan is false. The un comparisions are needed # to implement the opposite of normal comparisions, i.e. # (a < b) is bl, while !(a < b) is translated into bge.un. This is # because fp comparirions can return 4 values, not just three: lesser, # greater, equal or unordered stmt: CEE_BLT_UN (OP_COMPARE (freg, freg)) { MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_UN_SU, (alpha_at+1), state->left->left->reg1, state->left->right->reg1); MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_LT_SU, alpha_at, state->left->left->reg1, state->left->right->reg1); MONO_EMIT_NEW_UNALU (s, OP_ALPHA_TRAPB, -1, -1); MONO_EMIT_UNALU (s, tree, OP_FBLT_UN, -1, -1); } stmt: CEE_BLT (OP_COMPARE (freg, freg)) { MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_UN_SU, (alpha_at+1), state->left->left->reg1, state->left->right->reg1); MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_LT_SU, alpha_at, state->left->left->reg1, state->left->right->reg1); MONO_EMIT_NEW_UNALU (s, OP_ALPHA_TRAPB, -1, -1); MONO_EMIT_UNALU (s, tree, OP_FBLT, -1, -1); } stmt: CEE_BLE_UN (OP_COMPARE (freg, freg)) { MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_UN_SU, (alpha_at+1), state->left->left->reg1, state->left->right->reg1); MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_LE_SU, alpha_at, state->left->left->reg1, state->left->right->reg1); MONO_EMIT_NEW_UNALU (s, OP_ALPHA_TRAPB, -1, -1); MONO_EMIT_UNALU (s, tree, OP_FBLE_UN, -1, -1); } stmt: CEE_BLE (OP_COMPARE (freg, freg)) { MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_UN_SU, (alpha_at+1), state->left->left->reg1, state->left->right->reg1); MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_LE_SU, alpha_at, state->left->left->reg1, state->left->right->reg1); MONO_EMIT_NEW_UNALU (s, OP_ALPHA_TRAPB, -1, -1); MONO_EMIT_UNALU (s, tree, OP_FBLE, -1, -1); } stmt: CEE_BGT_UN (OP_COMPARE (freg, freg)) { MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_UN_SU, (alpha_at+1), state->left->left->reg1, state->left->right->reg1); MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_LE_SU, alpha_at, state->left->left->reg1, state->left->right->reg1); MONO_EMIT_NEW_UNALU (s, OP_ALPHA_TRAPB, -1, -1); MONO_EMIT_UNALU (s, tree, OP_FBGT_UN, -1, -1); } stmt: CEE_BGT (OP_COMPARE (freg, freg)) { MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_UN_SU, (alpha_at+1), state->left->left->reg1, state->left->right->reg1); MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_LE_SU, alpha_at, state->left->left->reg1, state->left->right->reg1); MONO_EMIT_NEW_UNALU (s, OP_ALPHA_TRAPB, -1, -1); MONO_EMIT_UNALU (s, tree, OP_FBGT, -1, -1); } stmt: CEE_BGE_UN (OP_COMPARE (freg, freg)) { MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_UN_SU, (alpha_at+1), state->left->left->reg1, state->left->right->reg1); MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_LT_SU, alpha_at, state->left->left->reg1, state->left->right->reg1); MONO_EMIT_NEW_UNALU (s, OP_ALPHA_TRAPB, -1, -1); MONO_EMIT_UNALU (s, tree, OP_FBGE_UN, -1, -1); } stmt: CEE_BGE (OP_COMPARE (freg, freg)) { MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_UN_SU, (alpha_at+1), state->left->left->reg1, state->left->right->reg1); MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_LT_SU, alpha_at, state->left->left->reg1, state->left->right->reg1); MONO_EMIT_NEW_UNALU (s, OP_ALPHA_TRAPB, -1, -1); MONO_EMIT_UNALU (s, tree, OP_FBGE, -1, -1); } reg: OP_CEQ (OP_COMPARE (freg, freg)) { MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_EQ_SU, alpha_at, state->left->left->reg1, state->left->right->reg1); MONO_EMIT_NEW_UNALU (s, OP_ALPHA_TRAPB, -1, -1); tree->dreg = state->reg1; tree->opcode = OP_FCEQ; mono_bblock_add_inst (s->cbb, tree); } reg: OP_CLT (OP_COMPARE (freg, freg)) { MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_LT_SU, alpha_at, state->left->left->reg1, state->left->right->reg1); MONO_EMIT_NEW_UNALU (s, OP_ALPHA_TRAPB, -1, -1); tree->dreg = state->reg1; tree->opcode = OP_FCLT; mono_bblock_add_inst (s->cbb, tree); } reg: OP_CLT_UN (OP_COMPARE (freg, freg)) { MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_UN_SU, (alpha_at+1), state->left->right->reg1, state->left->left->reg1); MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_LT_SU, alpha_at, state->left->left->reg1, state->left->right->reg1); MONO_EMIT_NEW_UNALU (s, OP_ALPHA_TRAPB, -1, -1); tree->dreg = state->reg1; tree->opcode = OP_FCLT_UN; mono_bblock_add_inst (s->cbb, tree); } reg: OP_CGT (OP_COMPARE (freg, freg)) { // Same as CLT_n (OP_COMPARE) - just exchange parameters MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_LT_SU, alpha_at, // state->left->left->reg1, state->left->right->reg1); state->left->right->reg1, state->left->left->reg1); MONO_EMIT_NEW_UNALU (s, OP_ALPHA_TRAPB, -1, -1); // tree->opcode = OP_FCGT; tree->dreg = state->reg1; tree->opcode = OP_FCLT; mono_bblock_add_inst (s->cbb, tree); } reg: OP_CGT_UN (OP_COMPARE (freg, freg)) { // Same as above MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_UN_SU, (alpha_at+1), state->left->right->reg1, state->left->left->reg1); MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_LT_SU, alpha_at, state->left->right->reg1, state->left->left->reg1); MONO_EMIT_NEW_UNALU (s, OP_ALPHA_TRAPB, -1, -1); tree->dreg = state->reg1; tree->opcode = OP_FCLT_UN; mono_bblock_add_inst (s->cbb, tree); } stmt: CEE_BEQ (OP_COMPARE (freg, freg)) { MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_EQ_SU, alpha_at, state->left->left->reg1, state->left->right->reg1); MONO_EMIT_NEW_UNALU (s, OP_ALPHA_TRAPB, -1, -1); MONO_EMIT_UNALU (s, tree, OP_FBEQ, -1, -1); } stmt: CEE_BNE_UN (OP_COMPARE (freg, freg)) { MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_UN_SU, (alpha_at+1), state->left->left->reg1, state->left->right->reg1); MONO_EMIT_NEW_BIALU (s, OP_ALPHA_CMPT_EQ_SU, alpha_at, state->left->left->reg1, state->left->right->reg1); MONO_EMIT_NEW_UNALU (s, OP_ALPHA_TRAPB, -1, -1); MONO_EMIT_UNALU (s, tree, OP_FBNE_UN, -1, -1); } 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); } reg: OP_LCONV_TO_I4 (reg) "0" { /* Sign extend the value in the lower word into the upper word */ MONO_EMIT_BIALU_IMM (s, tree, CEE_CONV_I4, state->reg1, state->left->reg1, 0); } reg: OP_LCONV_TO_U4 (reg) "0" { /* Clean out the upper word */ MONO_EMIT_BIALU_IMM (s, tree, CEE_CONV_U4, state->reg1, state->left->reg1, 0); } 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); } 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; }