target-xtensa: record available window in TB flags

Record last valid 4-register window pane number in TB flags so that a
window overflow exception throw point is known at the translation time.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Reviewed-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
Max Filippov 2014-10-30 18:07:47 +03:00
parent 85d36377e4
commit 2db59a76c4
4 changed files with 42 additions and 62 deletions

View File

@ -497,6 +497,8 @@ static inline int cpu_mmu_index(CPUXtensaState *env)
#define XTENSA_TBFLAG_CPENABLE_MASK 0x3fc0 #define XTENSA_TBFLAG_CPENABLE_MASK 0x3fc0
#define XTENSA_TBFLAG_CPENABLE_SHIFT 6 #define XTENSA_TBFLAG_CPENABLE_SHIFT 6
#define XTENSA_TBFLAG_EXCEPTION 0x4000 #define XTENSA_TBFLAG_EXCEPTION 0x4000
#define XTENSA_TBFLAG_WINDOW_MASK 0x18000
#define XTENSA_TBFLAG_WINDOW_SHIFT 15
static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc, static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc,
target_ulong *cs_base, int *flags) target_ulong *cs_base, int *flags)
@ -528,6 +530,16 @@ static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc,
if (cs->singlestep_enabled && env->exception_taken) { if (cs->singlestep_enabled && env->exception_taken) {
*flags |= XTENSA_TBFLAG_EXCEPTION; *flags |= XTENSA_TBFLAG_EXCEPTION;
} }
if (xtensa_option_enabled(env->config, XTENSA_OPTION_WINDOWED_REGISTER) &&
(env->sregs[PS] & (PS_WOE | PS_EXCM)) == PS_WOE) {
uint32_t windowstart = xtensa_replicate_windowstart(env) >>
(env->sregs[WINDOW_BASE] + 1);
uint32_t w = ctz32(windowstart | 0x8);
*flags |= w << XTENSA_TBFLAG_WINDOW_SHIFT;
} else {
*flags |= 3 << XTENSA_TBFLAG_WINDOW_SHIFT;
}
} }
#include "exec/cpu-all.h" #include "exec/cpu-all.h"

View File

@ -9,7 +9,7 @@ DEF_HELPER_2(wsr_windowbase, void, env, i32)
DEF_HELPER_4(entry, void, env, i32, i32, i32) DEF_HELPER_4(entry, void, env, i32, i32, i32)
DEF_HELPER_2(retw, i32, env, i32) DEF_HELPER_2(retw, i32, env, i32)
DEF_HELPER_2(rotw, void, env, i32) DEF_HELPER_2(rotw, void, env, i32)
DEF_HELPER_3(window_check, void, env, i32, i32) DEF_HELPER_3(window_check, noreturn, env, i32, i32)
DEF_HELPER_1(restore_owb, void, env) DEF_HELPER_1(restore_owb, void, env)
DEF_HELPER_2(movsp, void, env, i32) DEF_HELPER_2(movsp, void, env, i32)
DEF_HELPER_2(wsr_lbeg, void, env, i32) DEF_HELPER_2(wsr_lbeg, void, env, i32)

View File

@ -251,34 +251,27 @@ void HELPER(entry)(CPUXtensaState *env, uint32_t pc, uint32_t s, uint32_t imm)
void HELPER(window_check)(CPUXtensaState *env, uint32_t pc, uint32_t w) void HELPER(window_check)(CPUXtensaState *env, uint32_t pc, uint32_t w)
{ {
uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env); uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env);
uint32_t windowstart = env->sregs[WINDOW_START]; uint32_t windowstart = xtensa_replicate_windowstart(env) >>
uint32_t m, n; (env->sregs[WINDOW_BASE] + 1);
uint32_t n = ctz32(windowstart) + 1;
if ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) { assert(n <= w);
return;
}
for (n = 1; ; ++n) {
if (n > w) {
return;
}
if (windowstart & windowstart_bit(windowbase + n, env)) {
break;
}
}
m = windowbase_bound(windowbase + n, env);
rotate_window(env, n); rotate_window(env, n);
env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) | env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) |
(windowbase << PS_OWB_SHIFT) | PS_EXCM; (windowbase << PS_OWB_SHIFT) | PS_EXCM;
env->sregs[EPC1] = env->pc = pc; env->sregs[EPC1] = env->pc = pc;
if (windowstart & windowstart_bit(m + 1, env)) { switch (ctz32(windowstart >> n)) {
case 0:
HELPER(exception)(env, EXC_WINDOW_OVERFLOW4); HELPER(exception)(env, EXC_WINDOW_OVERFLOW4);
} else if (windowstart & windowstart_bit(m + 2, env)) { break;
case 1:
HELPER(exception)(env, EXC_WINDOW_OVERFLOW8); HELPER(exception)(env, EXC_WINDOW_OVERFLOW8);
} else { break;
default:
HELPER(exception)(env, EXC_WINDOW_OVERFLOW12); HELPER(exception)(env, EXC_WINDOW_OVERFLOW12);
break;
} }
} }

View File

@ -63,7 +63,7 @@ typedef struct DisasContext {
TCGv_i32 sar_m32; TCGv_i32 sar_m32;
uint32_t ccount_delta; uint32_t ccount_delta;
unsigned used_window; unsigned window;
bool debug; bool debug;
bool icount; bool icount;
@ -311,26 +311,16 @@ static void gen_left_shift_sar(DisasContext *dc, TCGv_i32 sa)
tcg_temp_free(tmp); tcg_temp_free(tmp);
} }
static void gen_advance_ccount_cond(DisasContext *dc) static void gen_advance_ccount(DisasContext *dc)
{ {
if (dc->ccount_delta > 0) { if (dc->ccount_delta > 0) {
TCGv_i32 tmp = tcg_const_i32(dc->ccount_delta); TCGv_i32 tmp = tcg_const_i32(dc->ccount_delta);
gen_helper_advance_ccount(cpu_env, tmp); gen_helper_advance_ccount(cpu_env, tmp);
tcg_temp_free(tmp); tcg_temp_free(tmp);
} }
}
static void gen_advance_ccount(DisasContext *dc)
{
gen_advance_ccount_cond(dc);
dc->ccount_delta = 0; dc->ccount_delta = 0;
} }
static void reset_used_window(DisasContext *dc)
{
dc->used_window = 0;
}
static void gen_exception(DisasContext *dc, int excp) static void gen_exception(DisasContext *dc, int excp)
{ {
TCGv_i32 tmp = tcg_const_i32(excp); TCGv_i32 tmp = tcg_const_i32(excp);
@ -597,13 +587,15 @@ static void gen_wsr_acchi(DisasContext *dc, uint32_t sr, TCGv_i32 s)
static void gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v) static void gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{ {
gen_helper_wsr_windowbase(cpu_env, v); gen_helper_wsr_windowbase(cpu_env, v);
reset_used_window(dc); /* This can change tb->flags, so exit tb */
gen_jumpi_check_loop_end(dc, -1);
} }
static void gen_wsr_windowstart(DisasContext *dc, uint32_t sr, TCGv_i32 v) static void gen_wsr_windowstart(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{ {
tcg_gen_andi_i32(cpu_SR[sr], v, (1 << dc->config->nareg / 4) - 1); tcg_gen_andi_i32(cpu_SR[sr], v, (1 << dc->config->nareg / 4) - 1);
reset_used_window(dc); /* This can change tb->flags, so exit tb */
gen_jumpi_check_loop_end(dc, -1);
} }
static void gen_wsr_ptevaddr(DisasContext *dc, uint32_t sr, TCGv_i32 v) static void gen_wsr_ptevaddr(DisasContext *dc, uint32_t sr, TCGv_i32 v)
@ -712,7 +704,6 @@ static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v)
mask |= PS_RING; mask |= PS_RING;
} }
tcg_gen_andi_i32(cpu_SR[sr], v, mask); tcg_gen_andi_i32(cpu_SR[sr], v, mask);
reset_used_window(dc);
gen_helper_check_interrupts(cpu_env); gen_helper_check_interrupts(cpu_env);
/* This can change mmu index and tb->flags, so exit tb */ /* This can change mmu index and tb->flags, so exit tb */
gen_jumpi_check_loop_end(dc, -1); gen_jumpi_check_loop_end(dc, -1);
@ -835,32 +826,13 @@ static void gen_waiti(DisasContext *dc, uint32_t imm4)
static void gen_window_check1(DisasContext *dc, unsigned r1) static void gen_window_check1(DisasContext *dc, unsigned r1)
{ {
if (dc->tb->flags & XTENSA_TBFLAG_EXCM) { if (r1 / 4 > dc->window) {
return; TCGv_i32 pc = tcg_const_i32(dc->pc);
} TCGv_i32 w = tcg_const_i32(r1 / 4);
if (option_enabled(dc, XTENSA_OPTION_WINDOWED_REGISTER) &&
r1 / 4 > dc->used_window) {
int label = gen_new_label();
TCGv_i32 ws = tcg_temp_new_i32();
dc->used_window = r1 / 4; gen_advance_ccount(dc);
tcg_gen_deposit_i32(ws, cpu_SR[WINDOW_START], cpu_SR[WINDOW_START], gen_helper_window_check(cpu_env, pc, w);
dc->config->nareg / 4, dc->config->nareg / 4); dc->is_jmp = DISAS_UPDATE;
tcg_gen_shr_i32(ws, ws, cpu_SR[WINDOW_BASE]);
tcg_gen_andi_i32(ws, ws, (2 << (r1 / 4)) - 2);
tcg_gen_brcondi_i32(TCG_COND_EQ, ws, 0, label);
{
TCGv_i32 pc = tcg_const_i32(dc->pc);
TCGv_i32 w = tcg_const_i32(r1 / 4);
gen_advance_ccount_cond(dc);
gen_helper_window_check(cpu_env, pc, w);
tcg_temp_free(w);
tcg_temp_free(pc);
}
gen_set_label(label);
tcg_temp_free(ws);
} }
} }
@ -1370,7 +1342,8 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
RRR_T | ((RRR_T & 8) ? 0xfffffff0 : 0)); RRR_T | ((RRR_T & 8) ? 0xfffffff0 : 0));
gen_helper_rotw(cpu_env, tmp); gen_helper_rotw(cpu_env, tmp);
tcg_temp_free(tmp); tcg_temp_free(tmp);
reset_used_window(dc); /* This can change tb->flags, so exit tb */
gen_jumpi_check_loop_end(dc, -1);
} }
break; break;
@ -2700,7 +2673,8 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
tcg_temp_free(imm); tcg_temp_free(imm);
tcg_temp_free(s); tcg_temp_free(s);
tcg_temp_free(pc); tcg_temp_free(pc);
reset_used_window(dc); /* This can change tb->flags, so exit tb */
gen_jumpi_check_loop_end(dc, -1);
} }
break; break;
@ -3029,10 +3003,11 @@ void gen_intermediate_code_internal(XtensaCPU *cpu,
dc.icount = tb->flags & XTENSA_TBFLAG_ICOUNT; dc.icount = tb->flags & XTENSA_TBFLAG_ICOUNT;
dc.cpenable = (tb->flags & XTENSA_TBFLAG_CPENABLE_MASK) >> dc.cpenable = (tb->flags & XTENSA_TBFLAG_CPENABLE_MASK) >>
XTENSA_TBFLAG_CPENABLE_SHIFT; XTENSA_TBFLAG_CPENABLE_SHIFT;
dc.window = ((tb->flags & XTENSA_TBFLAG_WINDOW_MASK) >>
XTENSA_TBFLAG_WINDOW_SHIFT);
init_litbase(&dc); init_litbase(&dc);
init_sar_tracker(&dc); init_sar_tracker(&dc);
reset_used_window(&dc);
if (dc.icount) { if (dc.icount) {
dc.next_icount = tcg_temp_local_new_i32(); dc.next_icount = tcg_temp_local_new_i32();
} }