tcg: Fix indirect lowering vs TCG_OPF_COND_BRANCH

With TCG_OPF_COND_BRANCH, we extended the lifetimes of
globals across extended basic blocks.  This means that
the liveness computed in pass 1 does not kill globals
in the same way as normal temps.

Introduce TYPE_EBB to match this lifetime, so that we
get correct register allocation for the temps that we
introduce during the indirect lowering pass.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Fixes: b4cb76e620 ("tcg: Do not kill globals at conditional branches")
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2022-03-16 09:34:18 -07:00
parent 55d71e0b78
commit c74824389e
2 changed files with 29 additions and 7 deletions

View File

@ -433,6 +433,8 @@ typedef enum TCGTempVal {
typedef enum TCGTempKind { typedef enum TCGTempKind {
/* Temp is dead at the end of all basic blocks. */ /* Temp is dead at the end of all basic blocks. */
TEMP_NORMAL, TEMP_NORMAL,
/* Temp is live across conditional branch, but dead otherwise. */
TEMP_EBB,
/* Temp is saved across basic blocks but dead at the end of TBs. */ /* Temp is saved across basic blocks but dead at the end of TBs. */
TEMP_LOCAL, TEMP_LOCAL,
/* Temp is saved across both basic blocks and translation blocks. */ /* Temp is saved across both basic blocks and translation blocks. */

View File

@ -1024,9 +1024,18 @@ void tcg_temp_free_internal(TCGTemp *ts)
TCGContext *s = tcg_ctx; TCGContext *s = tcg_ctx;
int k, idx; int k, idx;
/* In order to simplify users of tcg_constant_*, silently ignore free. */ switch (ts->kind) {
if (ts->kind == TEMP_CONST) { case TEMP_CONST:
/*
* In order to simplify users of tcg_constant_*,
* silently ignore free.
*/
return; return;
case TEMP_NORMAL:
case TEMP_LOCAL:
break;
default:
g_assert_not_reached();
} }
#if defined(CONFIG_DEBUG_TCG) #if defined(CONFIG_DEBUG_TCG)
@ -1036,7 +1045,6 @@ void tcg_temp_free_internal(TCGTemp *ts)
} }
#endif #endif
tcg_debug_assert(ts->kind < TEMP_GLOBAL);
tcg_debug_assert(ts->temp_allocated != 0); tcg_debug_assert(ts->temp_allocated != 0);
ts->temp_allocated = 0; ts->temp_allocated = 0;
@ -1674,6 +1682,7 @@ static void tcg_reg_alloc_start(TCGContext *s)
case TEMP_GLOBAL: case TEMP_GLOBAL:
break; break;
case TEMP_NORMAL: case TEMP_NORMAL:
case TEMP_EBB:
val = TEMP_VAL_DEAD; val = TEMP_VAL_DEAD;
/* fall through */ /* fall through */
case TEMP_LOCAL: case TEMP_LOCAL:
@ -1701,6 +1710,9 @@ static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size,
case TEMP_LOCAL: case TEMP_LOCAL:
snprintf(buf, buf_size, "loc%d", idx - s->nb_globals); snprintf(buf, buf_size, "loc%d", idx - s->nb_globals);
break; break;
case TEMP_EBB:
snprintf(buf, buf_size, "ebb%d", idx - s->nb_globals);
break;
case TEMP_NORMAL: case TEMP_NORMAL:
snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals); snprintf(buf, buf_size, "tmp%d", idx - s->nb_globals);
break; break;
@ -2378,6 +2390,7 @@ static void la_bb_end(TCGContext *s, int ng, int nt)
state = TS_DEAD | TS_MEM; state = TS_DEAD | TS_MEM;
break; break;
case TEMP_NORMAL: case TEMP_NORMAL:
case TEMP_EBB:
case TEMP_CONST: case TEMP_CONST:
state = TS_DEAD; state = TS_DEAD;
break; break;
@ -2405,8 +2418,9 @@ static void la_global_sync(TCGContext *s, int ng)
} }
/* /*
* liveness analysis: conditional branch: all temps are dead, * liveness analysis: conditional branch: all temps are dead unless
* globals and local temps should be synced. * explicitly live-across-conditional-branch, globals and local temps
* should be synced.
*/ */
static void la_bb_sync(TCGContext *s, int ng, int nt) static void la_bb_sync(TCGContext *s, int ng, int nt)
{ {
@ -2427,6 +2441,7 @@ static void la_bb_sync(TCGContext *s, int ng, int nt)
case TEMP_NORMAL: case TEMP_NORMAL:
s->temps[i].state = TS_DEAD; s->temps[i].state = TS_DEAD;
break; break;
case TEMP_EBB:
case TEMP_CONST: case TEMP_CONST:
continue; continue;
default: default:
@ -2797,6 +2812,7 @@ static bool liveness_pass_2(TCGContext *s)
TCGTemp *dts = tcg_temp_alloc(s); TCGTemp *dts = tcg_temp_alloc(s);
dts->type = its->type; dts->type = its->type;
dts->base_type = its->base_type; dts->base_type = its->base_type;
dts->kind = TEMP_EBB;
its->state_ptr = dts; its->state_ptr = dts;
} else { } else {
its->state_ptr = NULL; its->state_ptr = NULL;
@ -3107,6 +3123,7 @@ static void temp_free_or_dead(TCGContext *s, TCGTemp *ts, int free_or_dead)
new_type = TEMP_VAL_MEM; new_type = TEMP_VAL_MEM;
break; break;
case TEMP_NORMAL: case TEMP_NORMAL:
case TEMP_EBB:
new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD; new_type = free_or_dead < 0 ? TEMP_VAL_MEM : TEMP_VAL_DEAD;
break; break;
case TEMP_CONST: case TEMP_CONST:
@ -3353,6 +3370,7 @@ static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
temp_save(s, ts, allocated_regs); temp_save(s, ts, allocated_regs);
break; break;
case TEMP_NORMAL: case TEMP_NORMAL:
case TEMP_EBB:
/* The liveness analysis already ensures that temps are dead. /* The liveness analysis already ensures that temps are dead.
Keep an tcg_debug_assert for safety. */ Keep an tcg_debug_assert for safety. */
tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
@ -3370,8 +3388,9 @@ static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
} }
/* /*
* At a conditional branch, we assume all temporaries are dead and * At a conditional branch, we assume all temporaries are dead unless
* all globals and local temps are synced to their location. * explicitly live-across-conditional-branch; all globals and local
* temps are synced to their location.
*/ */
static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs) static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
{ {
@ -3390,6 +3409,7 @@ static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs)
case TEMP_NORMAL: case TEMP_NORMAL:
tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD); tcg_debug_assert(ts->val_type == TEMP_VAL_DEAD);
break; break;
case TEMP_EBB:
case TEMP_CONST: case TEMP_CONST:
break; break;
default: default: