diff mbox

[1/2] target-xtensa: record available window in TB flags

Message ID 1418523683-21756-2-git-send-email-jcmvbkbc@gmail.com
State New
Headers show

Commit Message

Max Filippov Dec. 14, 2014, 2:21 a.m. UTC
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>
---
 target-xtensa/cpu.h       | 12 ++++++++++
 target-xtensa/helper.h    |  2 +-
 target-xtensa/op_helper.c | 29 +++++++++-------------
 target-xtensa/translate.c | 61 ++++++++++++++---------------------------------
 4 files changed, 42 insertions(+), 62 deletions(-)
diff mbox

Patch

diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index ac463f2..a1bfbf7 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -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"
diff --git a/target-xtensa/helper.h b/target-xtensa/helper.h
index ed3af0b..5ea9c5b 100644
--- a/target-xtensa/helper.h
+++ b/target-xtensa/helper.h
@@ -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)
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index c4c9cb7..be657e6 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -265,34 +265,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;
     }
 }
 
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 0265211..18743d5 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -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);
-        {
-            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);
+    if (r1 / 4 > dc->window) {
+        TCGv_i32 pc = tcg_const_i32(dc->pc);
+        TCGv_i32 w = tcg_const_i32(r1 / 4);
 
-            tcg_temp_free(w);
-            tcg_temp_free(pc);
-        }
-        gen_set_label(label);
-        tcg_temp_free(ws);
+        gen_advance_ccount(dc);
+        gen_helper_window_check(cpu_env, pc, w);
+        dc->is_jmp = DISAS_UPDATE;
     }
 }
 
@@ -1358,7 +1330,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;
 
@@ -2692,7 +2665,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;
 
@@ -3015,10 +2989,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();
     }