Commit 2db59a76 authored by Max Filippov's avatar Max Filippov
Browse files

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: default avatarMax Filippov <jcmvbkbc@gmail.com>
Reviewed-by: default avatarRichard Henderson <rth@twiddle.net>
parent 85d36377
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -497,6 +497,8 @@ static inline int cpu_mmu_index(CPUXtensaState *env)
#define XTENSA_TBFLAG_CPENABLE_MASK 0x3fc0
#define XTENSA_TBFLAG_CPENABLE_SHIFT 6
#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,
        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) {
        *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"
+1 −1
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@ DEF_HELPER_2(wsr_windowbase, void, env, i32)
DEF_HELPER_4(entry, void, env, i32, i32, i32)
DEF_HELPER_2(retw, i32, 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_2(movsp, void, env, i32)
DEF_HELPER_2(wsr_lbeg, void, env, i32)
+11 −18
Original line number Diff line number Diff line
@@ -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)
{
    uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env);
    uint32_t windowstart = env->sregs[WINDOW_START];
    uint32_t m, n;
    uint32_t windowstart = xtensa_replicate_windowstart(env) >>
        (env->sregs[WINDOW_BASE] + 1);
    uint32_t n = ctz32(windowstart) + 1;

    if ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) {
        return;
    }
    assert(n <= w);

    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);
    env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) |
        (windowbase << PS_OWB_SHIFT) | PS_EXCM;
    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);
    } else if (windowstart & windowstart_bit(m + 2, env)) {
        break;
    case 1:
        HELPER(exception)(env, EXC_WINDOW_OVERFLOW8);
    } else {
        break;
    default:
        HELPER(exception)(env, EXC_WINDOW_OVERFLOW12);
        break;
    }
}

+18 −43
Original line number Diff line number Diff line
@@ -63,7 +63,7 @@ typedef struct DisasContext {
    TCGv_i32 sar_m32;

    uint32_t ccount_delta;
    unsigned used_window;
    unsigned window;

    bool debug;
    bool icount;
@@ -311,26 +311,16 @@ static void gen_left_shift_sar(DisasContext *dc, TCGv_i32 sa)
    tcg_temp_free(tmp);
}

static void gen_advance_ccount_cond(DisasContext *dc)
static void gen_advance_ccount(DisasContext *dc)
{
    if (dc->ccount_delta > 0) {
        TCGv_i32 tmp = tcg_const_i32(dc->ccount_delta);
        gen_helper_advance_ccount(cpu_env, tmp);
        tcg_temp_free(tmp);
    }
}

static void gen_advance_ccount(DisasContext *dc)
{
    gen_advance_ccount_cond(dc);
    dc->ccount_delta = 0;
}

static void reset_used_window(DisasContext *dc)
{
    dc->used_window = 0;
}

static void gen_exception(DisasContext *dc, int 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)
{
    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)
{
    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)
@@ -712,7 +704,6 @@ static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v)
        mask |= PS_RING;
    }
    tcg_gen_andi_i32(cpu_SR[sr], v, mask);
    reset_used_window(dc);
    gen_helper_check_interrupts(cpu_env);
    /* This can change mmu index and tb->flags, so exit tb */
    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)
{
    if (dc->tb->flags & XTENSA_TBFLAG_EXCM) {
        return;
    }
    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;
        tcg_gen_deposit_i32(ws, cpu_SR[WINDOW_START], cpu_SR[WINDOW_START],
                dc->config->nareg / 4, dc->config->nareg / 4);
        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);
        {
    if (r1 / 4 > dc->window) {
        TCGv_i32 pc = tcg_const_i32(dc->pc);
        TCGv_i32 w = tcg_const_i32(r1 / 4);

            gen_advance_ccount_cond(dc);
        gen_advance_ccount(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);
        dc->is_jmp = DISAS_UPDATE;
    }
}

@@ -1370,7 +1342,8 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
                                RRR_T | ((RRR_T & 8) ? 0xfffffff0 : 0));
                        gen_helper_rotw(cpu_env, 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;

@@ -2700,7 +2673,8 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
                    tcg_temp_free(imm);
                    tcg_temp_free(s);
                    tcg_temp_free(pc);
                    reset_used_window(dc);
                    /* This can change tb->flags, so exit tb */
                    gen_jumpi_check_loop_end(dc, -1);
                }
                break;

@@ -3029,10 +3003,11 @@ void gen_intermediate_code_internal(XtensaCPU *cpu,
    dc.icount = tb->flags & XTENSA_TBFLAG_ICOUNT;
    dc.cpenable = (tb->flags & XTENSA_TBFLAG_CPENABLE_MASK) >>
        XTENSA_TBFLAG_CPENABLE_SHIFT;
    dc.window = ((tb->flags & XTENSA_TBFLAG_WINDOW_MASK) >>
                 XTENSA_TBFLAG_WINDOW_SHIFT);

    init_litbase(&dc);
    init_sar_tracker(&dc);
    reset_used_window(&dc);
    if (dc.icount) {
        dc.next_icount = tcg_temp_local_new_i32();
    }