[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 2/2] tcg: Fix allocation of indirect_base registers
From: |
Richard Henderson |
Subject: |
[Qemu-devel] [PATCH 2/2] tcg: Fix allocation of indirect_base registers |
Date: |
Fri, 17 Jun 2016 22:03:27 -0700 |
When the number of available registers is low, we need to be
prepared for TS to overlap MEM_BASE.
This fixes the Sparc64 OpenBIOS boot on i686.
Signed-off-by: Richard Henderson <address@hidden>
---
tcg/tcg.c | 68 +++++++++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 47 insertions(+), 21 deletions(-)
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 154ffe8..6c26ee4 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -1743,32 +1743,71 @@ static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet
desired_regs,
tcg_abort();
}
+/* Mark a temporary as dead. */
+static void temp_dead(TCGContext *s, TCGTemp *ts)
+{
+ if (ts->fixed_reg) {
+ return;
+ }
+ if (ts->val_type == TEMP_VAL_REG) {
+ s->reg_to_temp[ts->reg] = NULL;
+ }
+ ts->val_type = (temp_idx(s, ts) < s->nb_globals || ts->temp_local
+ ? TEMP_VAL_MEM : TEMP_VAL_DEAD);
+}
+
/* Make sure the temporary is in a register. If needed, allocate the register
from DESIRED while avoiding ALLOCATED. */
static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
TCGRegSet allocated_regs)
{
- TCGReg reg;
+ TCGReg reg, base_reg;
+ TCGTemp *base;
switch (ts->val_type) {
case TEMP_VAL_REG:
return;
+
case TEMP_VAL_CONST:
reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
ts->indirect_base);
tcg_out_movi(s, ts->type, reg, ts->val);
ts->mem_coherent = 0;
break;
+
case TEMP_VAL_MEM:
- reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
ts->indirect_base);
- if (ts->indirect_reg) {
- tcg_regset_set_reg(allocated_regs, reg);
- temp_load(s, ts->mem_base,
- tcg_target_available_regs[TCG_TYPE_PTR],
- allocated_regs);
+ base = ts->mem_base;
+ base_reg = base->reg;
+ if (ts->indirect_reg && base->val_type != TEMP_VAL_REG) {
+ TCGRegSet reg_avail = desired_regs & ~allocated_regs;
+ TCGRegSet base_avail = (tcg_target_available_regs[TCG_TYPE_PTR]
+ & ~allocated_regs);
+ if (is_power_of_2(reg_avail)) {
+ /* There is only one register available for TS. If there are
+ other available registers for BASE, make sure we pick one
+ of them. Otherwise BASE and TS will share a reg. */
+ TCGRegSet avail = base_avail & ~reg_avail;
+ if (avail) {
+ base_avail = avail;
+ }
+ temp_load(s, base, base_avail, allocated_regs);
+ base_reg = base->reg;
+ } else {
+ temp_load(s, base, base_avail, allocated_regs);
+ base_reg = base->reg;
+ tcg_regset_reset_reg(allocated_regs, base_reg);
+ }
}
- tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
+
+ reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
ts->indirect_base);
+ tcg_out_ld(s, ts->type, reg, base_reg, ts->mem_offset);
ts->mem_coherent = 1;
+
+ /* If the registers overlap, zap the info from BASE. */
+ if (reg == base_reg) {
+ temp_dead(s, base);
+ }
break;
+
case TEMP_VAL_DEAD:
default:
tcg_abort();
@@ -1778,19 +1817,6 @@ static void temp_load(TCGContext *s, TCGTemp *ts,
TCGRegSet desired_regs,
s->reg_to_temp[reg] = ts;
}
-/* mark a temporary as dead. */
-static inline void temp_dead(TCGContext *s, TCGTemp *ts)
-{
- if (ts->fixed_reg) {
- return;
- }
- if (ts->val_type == TEMP_VAL_REG) {
- s->reg_to_temp[ts->reg] = NULL;
- }
- ts->val_type = (temp_idx(s, ts) < s->nb_globals || ts->temp_local
- ? TEMP_VAL_MEM : TEMP_VAL_DEAD);
-}
-
/* sync a temporary to memory. 'allocated_regs' is used in case a
temporary registers needs to be allocated to store a constant. */
static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs)
--
2.5.5