tcg: Synchronize with qemu

This commit is contained in:
Lioncash 2019-04-26 08:40:45 -04:00
parent 006a13026a
commit 3996153514
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7

View file

@ -2159,104 +2159,109 @@ static void liveness_pass_1(TCGContext *s)
goto do_not_remove; goto do_not_remove;
} }
} }
do_remove: goto do_remove;
tcg_op_remove(s, op); }
} else { goto do_not_remove;
do_not_remove:
/* output args are dead */
for (i = 0; i < nb_oargs; i++) {
ts = arg_temp(op->args[i]);
/* Remember the preference of the uses that followed. */ do_remove:
op->output_pref[i] = *la_temp_pref(ts); tcg_op_remove(s, op);
break;
/* Output args are dead. */ do_not_remove:
if (ts->state & TS_DEAD) { for (i = 0; i < nb_oargs; i++) {
arg_life |= DEAD_ARG << i; ts = arg_temp(op->args[i]);
}
if (ts->state & TS_MEM) { /* Remember the preference of the uses that followed. */
arg_life |= SYNC_ARG << i; op->output_pref[i] = *la_temp_pref(ts);
}
ts->state = TS_DEAD; /* Output args are dead. */
la_reset_pref(s, ts); if (ts->state & TS_DEAD) {
arg_life |= DEAD_ARG << i;
} }
if (ts->state & TS_MEM) {
/* If end of basic block, update. */ arg_life |= SYNC_ARG << i;
if (def->flags & TCG_OPF_BB_END) {
// Unicorn: do not optimize dead temps on brcond,
// this causes problem because check_exit_request() inserts
// brcond instruction in the middle of the TB,
// which incorrectly flags end-of-block
if (opc != INDEX_op_brcond_i32) {
la_bb_end(s, nb_globals, nb_temps);
} else {
// Unicorn: we do not touch dead temps for brcond,
// but we should refresh TCG globals In-Memory states,
// otherwise, important CPU states(especially conditional flags) might be forgotten,
// result in wrongly generated host code that run into wrong branch.
// Refer to https://github.com/unicorn-engine/unicorn/issues/287 for further information
tcg_la_br_end(s);
}
} else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
la_global_sync(s, nb_globals);
if (def->flags & TCG_OPF_CALL_CLOBBER) {
la_cross_call(s, nb_temps);
}
} }
ts->state = TS_DEAD;
la_reset_pref(s, ts);
}
/* Record arguments that die in this opcode. */ /* If end of basic block, update. */
if (def->flags & TCG_OPF_BB_EXIT) {
la_func_end(s, nb_globals, nb_temps);
} else if (def->flags & TCG_OPF_BB_END) {
// Unicorn: do not optimize dead temps on brcond,
// this causes problem because check_exit_request() inserts
// brcond instruction in the middle of the TB,
// which incorrectly flags end-of-block
if (opc != INDEX_op_brcond_i32) {
la_bb_end(s, nb_globals, nb_temps);
} else {
// Unicorn: we do not touch dead temps for brcond,
// but we should refresh TCG globals In-Memory states,
// otherwise, important CPU states(especially conditional flags) might be forgotten,
// result in wrongly generated host code that run into wrong branch.
// Refer to https://github.com/unicorn-engine/unicorn/issues/287 for further information
tcg_la_br_end(s);
}
} else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
la_global_sync(s, nb_globals);
if (def->flags & TCG_OPF_CALL_CLOBBER) {
la_cross_call(s, nb_temps);
}
}
/* Record arguments that die in this opcode. */
for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
ts = arg_temp(op->args[i]);
if (ts->state & TS_DEAD) {
arg_life |= DEAD_ARG << i;
}
}
/* Input arguments are live for preceding opcodes. */
for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
ts = arg_temp(op->args[i]);
if (ts->state & TS_DEAD) {
/* For operands that were dead, initially allow
all regs for the type. */
*la_temp_pref(ts) = s->tcg_target_available_regs[ts->type];
ts->state &= ~TS_DEAD;
}
}
/* Incorporate constraints for this operand. */
switch (opc) {
case INDEX_op_mov_i32:
case INDEX_op_mov_i64:
/* Note that these are TCG_OPF_NOT_PRESENT and do not
have proper constraints. That said, special case
moves to propagate preferences backward. */
if (IS_DEAD_ARG(1)) {
*la_temp_pref(arg_temp(op->args[0]))
= *la_temp_pref(arg_temp(op->args[1]));
}
break;
default:
for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
const TCGArgConstraint *ct = &def->args_ct[i];
TCGRegSet set, *pset;
ts = arg_temp(op->args[i]); ts = arg_temp(op->args[i]);
if (ts->state & TS_DEAD) { pset = la_temp_pref(ts);
arg_life |= DEAD_ARG << i; set = *pset;
set &= ct->u.regs;
if (ct->ct & TCG_CT_IALIAS) {
set &= op->output_pref[ct->alias_index];
} }
/* If the combination is not possible, restart. */
if (set == 0) {
set = ct->u.regs;
}
*pset = set;
} }
/* Input arguments are live for preceding opcodes. */ break;
for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
ts = arg_temp(op->args[i]);
if (ts->state & TS_DEAD) {
/* For operands that were dead, initially allow
all regs for the type. */
*la_temp_pref(ts) = s->tcg_target_available_regs[ts->type];
ts->state &= ~TS_DEAD;
}
}
/* Incorporate constraints for this operand. */
switch (opc) {
case INDEX_op_mov_i32:
case INDEX_op_mov_i64:
/* Note that these are TCG_OPF_NOT_PRESENT and do not
have proper constraints. That said, special case
moves to propagate preferences backward. */
if (IS_DEAD_ARG(1)) {
*la_temp_pref(arg_temp(op->args[0]))
= *la_temp_pref(arg_temp(op->args[1]));
}
break;
default:
for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
const TCGArgConstraint *ct = &def->args_ct[i];
TCGRegSet set, *pset;
ts = arg_temp(op->args[i]);
pset = la_temp_pref(ts);
set = *pset;
set &= ct->u.regs;
if (ct->ct & TCG_CT_IALIAS) {
set &= op->output_pref[ct->alias_index];
}
/* If the combination is not possible, restart. */
if (set == 0) {
set = ct->u.regs;
}
*pset = set;
}
break;
}
} }
break; break;
} }