All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework
@ 2017-07-07 11:40 Lluís Vilanova
  2017-07-07 11:44 ` [Qemu-devel] [PATCH v12 01/27] Pass generic CPUState to gen_intermediate_code() Lluís Vilanova
                   ` (27 more replies)
  0 siblings, 28 replies; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 11:40 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini

This series proposes a generic (target-agnostic) instruction translation
framework.

It basically provides a generic main loop for instruction disassembly, which
calls target-specific functions when necessary. This generalization makes
inserting new code in the main loop easier, and helps in keeping all targets in
synch as to the contents of it.

This series also paves the way towards adding events to trace guest code
execution (BBLs and instructions).

I've ported i386/x86-64 and arm/aarch64 as an example to see how it fits in the
current organization, but will port the rest when this series gets merged.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
---

Changes in v12
==============

* Do not rename cs -> cpu when using CPUState arg in gen_intermediate_code().
* Avoid merge conflicts with queued patches.
* Fix documentation typos.
* Rename translate_block -> translator_loop.
* Fix misplaced changes (wrong patch).
* Rename _trblock_ -> _tr_.
* Drop DISAS_SS and DISAS_PAGE_CROSS from arm targets.
* Refactor calculation of TranslatorOps in arm targets.
* Merge init_globals() into init_disas_context().
* Minor cosmetic changes.


Changes in v11
==============

* Convert gen_intermediate_code_a64 [Emilio G. Cota].
* Replace "cpu_env" argument in icount functions with "tcg_ctx.cpu_env"
  [Emilio G. Cota].
* Drop QTAILQ_FOREACH_CONTINUE and cpu_breakpoint_get in favour of an explicit
  breakpoint traversal [Richard Henderson].
* Rename translate-block.[ch] into translator.[ch] [Emilio G. Cota].
* Revert DJ_* names into DISAS_*, and provide generic DISAS_TARGET_* enum values
  instead of defining them as integers on each target.
* Do not use DisasContextBase directly in target code (helps the compiler's
  alias analysis) [Richard Henderson].
* Make all generic translator hooks mandatory [Richard Henderson].
* Rename TranslatorOps::disas_insn as TranslatorOps::translate_insn
  [Richard Henderson].
* Generalize TranslatorOps::disas_flags into TranslatorOps::disas_log to support
  future targets [Richard Henderson].
* Split arm and aarch64 changes in different patches [Emilio G. Cota].
* Make translator op structs constant [Richard Henderson].
* Write a single entry point for both arm and aarch64 translation
  [Richard Henderson].
* Change format of commit titles [Emilio G. Cota].
* Remove cross-page check from generic code (it's already embedded in more
  complex, and mandatory, checks in most targets).


Changes in v10
==============

* Rebase on 931892e8a6.
* Fix build errors for hppa, nios2 and openrisc.


Changes in v9
=============

* Further increase inter-mail sleep time during sending.


Changes in v8
=============

* Increase inter-mail sleep time during sending (list keeps refusing some emails
  due to an excessive send rate).


Changes in v7
=============

* Change BreakpointHitType (BH_*) for BreakpointCheckType (BC_*).
* Move target-specific translation functions to a struct (TranslatorOps).
* Split target-specific changes into multiple patches.
* Rebase on edf8bc9842.


Changes in v6
=============

* Rebase on upstream master (64175afc69).
* Reorder fields in DisasContextBase to minimize padding [Richard Henderson].


Changes in v5
=============

* Remove stray uses of "restrict" keyword.


Changes in v4
=============

* Document new macro QTAILQ_FOREACH_CONTINUE [Peter Maydell].
* Fix coding style errors reported by checkpatch.
* Remove use of "restrict" in added functions; it makes older gcc versions barf
  about compilation errors.


Changes in v3
=============

* Rebase on 0737f32daf.


Changes in v2
=============

* Port ARM and AARCH64 targets.
* Fold single-stepping checks into "max_insns" [Richard Henderson].
* Move instruction start marks to target code [Richard Henderson].
* Add target hook for TB start.
* Check for TCG temporary leaks.
* Move instruction disassembly into a target hook.
* Make breakpoint_hit() return an enum to accomodate target's needs (ARM).


Lluís Vilanova (27):
      Pass generic CPUState to gen_intermediate_code()
      cpu-exec: Avoid global variables in icount-related functions
      target: [tcg] Use a generic enum for DISAS_ values
      target: [tcg] Add generic translation framework
      target/i386: [tcg] Port to DisasContextBase
      target/i386: [tcg] Port to init_disas_context
      target/i386: [tcg] Port to insn_start
      target/i386: [tcg] Port to breakpoint_check
      target/i386: [tcg] Port to translate_insn
      target/i386: [tcg] Port to tb_stop
      target/i386: [tcg] Port to disas_log
      target/i386: [tcg] Port to generic translation framework
      target/arm: [tcg] Port to DisasContextBase
      target/arm: [tcg] Port to init_disas_context
      target/arm: [tcg,a64] Port to init_disas_context
      target/arm: [tcg] Port to tb_start
      target/arm: [tcg] Port to insn_start
      target/arm: [tcg,a64] Port to insn_start
      target/arm: [tcg] Port to breakpoint_check
      target/arm: [tcg,a64] Port to breakpoint_check
      target/arm: [tcg] Port to translate_insn
      target/arm: [tcg,a64] Port to translate_insn
      target/arm: [tcg] Port to tb_stop
      target/arm: [tcg,a64] Port to tb_stop
      target/arm: [tcg] Port to disas_log
      target/arm: [tcg,a64] Port to disas_log
      target/arm: [tcg] Port to generic translation framework


 accel/tcg/Makefile.objs       |    1 
 accel/tcg/translate-all.c     |    2 
 accel/tcg/translator.c        |  152 +++++++++++++++
 include/exec/exec-all.h       |    8 -
 include/exec/gen-icount.h     |   12 +
 include/exec/translator.h     |  138 +++++++++++++
 target/alpha/translate.c      |    5 
 target/arm/translate-a64.c    |  275 +++++++++++++--------------
 target/arm/translate.c        |  420 +++++++++++++++++++++--------------------
 target/arm/translate.h        |   39 ++--
 target/cris/translate.c       |   14 +
 target/hppa/translate.c       |    5 
 target/i386/translate.c       |  300 +++++++++++++++--------------
 target/lm32/translate.c       |   10 +
 target/m68k/translate.c       |   12 +
 target/microblaze/translate.c |   10 +
 target/mips/translate.c       |    5 
 target/moxie/translate.c      |    4 
 target/nios2/translate.c      |   11 +
 target/openrisc/translate.c   |   10 +
 target/ppc/translate.c        |    5 
 target/s390x/translate.c      |    8 -
 target/sh4/translate.c        |    5 
 target/sparc/translate.c      |    5 
 target/tilegx/translate.c     |    5 
 target/tricore/translate.c    |    5 
 target/unicore32/translate.c  |   12 +
 target/xtensa/translate.c     |    9 +
 28 files changed, 899 insertions(+), 588 deletions(-)
 create mode 100644 accel/tcg/translator.c
 create mode 100644 include/exec/translator.h


To: qemu-devel@nongnu.org
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Peter Crosthwaite <crosthwaite.peter@gmail.com>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Alex Bennée <alex.bennee@linaro.org>
Cc: Emilio G. Cota <cota@braap.org>

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 01/27] Pass generic CPUState to gen_intermediate_code()
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
@ 2017-07-07 11:44 ` Lluís Vilanova
  2017-07-11 19:22   ` Alex Bennée
  2017-07-07 11:48 ` [Qemu-devel] [PATCH v12 02/27] cpu-exec: Avoid global variables in icount-related functions Lluís Vilanova
                   ` (26 subsequent siblings)
  27 siblings, 1 reply; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 11:44 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Peter Maydell,
	Edgar E. Iglesias, Eduardo Habkost, Michael Walle,
	Laurent Vivier, Aurelien Jarno, Yongbok Kim, Anthony Green,
	Chris Wulff, Marek Vasut, Stafford Horne, David Gibson,
	Alexander Graf, Mark Cave-Ayland, Artyom Tarasenko,
	Bastian Koppelmann, Guan Xuetao, Max Filippov, open list:ARM,
	open list:PowerPC

Needed to implement a target-agnostic gen_intermediate_code() in the
future.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 accel/tcg/translate-all.c     |    2 +-
 include/exec/exec-all.h       |    2 +-
 target/alpha/translate.c      |    5 ++---
 target/arm/translate-a64.c    |    6 +++---
 target/arm/translate.c        |    6 +++---
 target/arm/translate.h        |    4 ++--
 target/cris/translate.c       |    7 +++----
 target/hppa/translate.c       |    5 ++---
 target/i386/translate.c       |    5 ++---
 target/lm32/translate.c       |    4 ++--
 target/m68k/translate.c       |    5 ++---
 target/microblaze/translate.c |    4 ++--
 target/mips/translate.c       |    5 ++---
 target/moxie/translate.c      |    4 ++--
 target/nios2/translate.c      |    5 ++---
 target/openrisc/translate.c   |    4 ++--
 target/ppc/translate.c        |    5 ++---
 target/s390x/translate.c      |    5 ++---
 target/sh4/translate.c        |    5 ++---
 target/sparc/translate.c      |    5 ++---
 target/tilegx/translate.c     |    5 ++---
 target/tricore/translate.c    |    5 ++---
 target/unicore32/translate.c  |    5 ++---
 target/xtensa/translate.c     |    5 ++---
 24 files changed, 49 insertions(+), 64 deletions(-)

diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index f6ad46b613..2dc93f420a 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -1299,7 +1299,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
     tcg_func_start(&tcg_ctx);
 
     tcg_ctx.cpu = ENV_GET_CPU(env);
-    gen_intermediate_code(env, tb);
+    gen_intermediate_code(cpu, tb);
     tcg_ctx.cpu = NULL;
 
     trace_translate_block(tb, tb->pc, tb->tc_ptr);
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 724ec73dce..0826894ec5 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -43,7 +43,7 @@ typedef ram_addr_t tb_page_addr_t;
 
 #include "qemu/log.h"
 
-void gen_intermediate_code(CPUArchState *env, struct TranslationBlock *tb);
+void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb);
 void restore_state_to_opc(CPUArchState *env, struct TranslationBlock *tb,
                           target_ulong *data);
 
diff --git a/target/alpha/translate.c b/target/alpha/translate.c
index 232af9e177..7b39101053 100644
--- a/target/alpha/translate.c
+++ b/target/alpha/translate.c
@@ -2911,10 +2911,9 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
     return ret;
 }
 
-void gen_intermediate_code(CPUAlphaState *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
 {
-    AlphaCPU *cpu = alpha_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUAlphaState *env = cs->env_ptr;
     DisasContext ctx, *ctxp = &ctx;
     target_ulong pc_start;
     target_ulong pc_mask;
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index e55547d95d..f9bd1a9679 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -11190,10 +11190,10 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
     free_tmp_a64(s);
 }
 
-void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock *tb)
+void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
 {
-    CPUState *cs = CPU(cpu);
-    CPUARMState *env = &cpu->env;
+    CPUARMState *env = cs->env_ptr;
+    ARMCPU *cpu = arm_env_get_cpu(env);
     DisasContext dc1, *dc = &dc1;
     target_ulong pc_start;
     target_ulong next_page_start;
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 0862f9e4aa..e80cc357c1 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -11787,10 +11787,10 @@ static bool insn_crosses_page(CPUARMState *env, DisasContext *s)
 }
 
 /* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
 {
+    CPUARMState *env = cs->env_ptr;
     ARMCPU *cpu = arm_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
     DisasContext dc1, *dc = &dc1;
     target_ulong pc_start;
     target_ulong next_page_start;
@@ -11804,7 +11804,7 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
      * the A32/T32 complexity to do with conditional execution/IT blocks/etc.
      */
     if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
-        gen_intermediate_code_a64(cpu, tb);
+        gen_intermediate_code_a64(cs, tb);
         return;
     }
 
diff --git a/target/arm/translate.h b/target/arm/translate.h
index 15d383d9af..e5da614db5 100644
--- a/target/arm/translate.h
+++ b/target/arm/translate.h
@@ -146,7 +146,7 @@ static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
 
 #ifdef TARGET_AARCH64
 void a64_translate_init(void);
-void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock *tb);
+void gen_intermediate_code_a64(CPUState *cpu, TranslationBlock *tb);
 void gen_a64_set_pc_im(uint64_t val);
 void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
                             fprintf_function cpu_fprintf, int flags);
@@ -155,7 +155,7 @@ static inline void a64_translate_init(void)
 {
 }
 
-static inline void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock *tb)
+static inline void gen_intermediate_code_a64(CPUState *cpu, TranslationBlock *tb)
 {
 }
 
diff --git a/target/cris/translate.c b/target/cris/translate.c
index 0ee05ca02d..12b96eb68f 100644
--- a/target/cris/translate.c
+++ b/target/cris/translate.c
@@ -3080,10 +3080,9 @@ static unsigned int crisv32_decoder(CPUCRISState *env, DisasContext *dc)
  */
 
 /* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPUCRISState *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
 {
-    CRISCPU *cpu = cris_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUCRISState *env = cs->env_ptr;
     uint32_t pc_start;
     unsigned int insn_len;
     struct DisasContext ctx;
@@ -3105,7 +3104,7 @@ void gen_intermediate_code(CPUCRISState *env, struct TranslationBlock *tb)
      * delayslot, like in real hw.
      */
     pc_start = tb->pc & ~1;
-    dc->cpu = cpu;
+    dc->cpu = cris_env_get_cpu(env);
     dc->tb = tb;
 
     dc->is_jmp = DISAS_NEXT;
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index e10abc5e04..900870cd5a 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -3740,10 +3740,9 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
     return gen_illegal(ctx);
 }
 
-void gen_intermediate_code(CPUHPPAState *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
 {
-    HPPACPU *cpu = hppa_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUHPPAState *env = cs->env_ptr;
     DisasContext ctx;
     ExitStatus ret;
     int num_insns, max_insns, i;
diff --git a/target/i386/translate.c b/target/i386/translate.c
index ed3b896db4..cab9e32f91 100644
--- a/target/i386/translate.c
+++ b/target/i386/translate.c
@@ -8378,10 +8378,9 @@ void tcg_x86_init(void)
 }
 
 /* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPUX86State *env, TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
 {
-    X86CPU *cpu = x86_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUX86State *env = cs->env_ptr;
     DisasContext dc1, *dc = &dc1;
     target_ulong pc_ptr;
     uint32_t flags;
diff --git a/target/lm32/translate.c b/target/lm32/translate.c
index 692882f447..f68f372f15 100644
--- a/target/lm32/translate.c
+++ b/target/lm32/translate.c
@@ -1044,10 +1044,10 @@ static inline void decode(DisasContext *dc, uint32_t ir)
 }
 
 /* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPULM32State *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
 {
+    CPULM32State *env = cs->env_ptr;
     LM32CPU *cpu = lm32_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
     struct DisasContext ctx, *dc = &ctx;
     uint32_t pc_start;
     uint32_t next_page_start;
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 7aa0fdc238..af19872e0b 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -5369,10 +5369,9 @@ static void disas_m68k_insn(CPUM68KState * env, DisasContext *s)
 }
 
 /* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
 {
-    M68kCPU *cpu = m68k_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUM68KState *env = cs->env_ptr;
     DisasContext dc1, *dc = &dc1;
     target_ulong pc_start;
     int pc_offset;
diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c
index 0bb609513c..a180bc78ae 100644
--- a/target/microblaze/translate.c
+++ b/target/microblaze/translate.c
@@ -1594,10 +1594,10 @@ static inline void decode(DisasContext *dc, uint32_t ir)
 }
 
 /* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
 {
+    CPUMBState *env = cs->env_ptr;
     MicroBlazeCPU *cpu = mb_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
     uint32_t pc_start;
     struct DisasContext ctx;
     struct DisasContext *dc = &ctx;
diff --git a/target/mips/translate.c b/target/mips/translate.c
index 559f8fed89..97314e470a 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -19878,10 +19878,9 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
     }
 }
 
-void gen_intermediate_code(CPUMIPSState *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
 {
-    MIPSCPU *cpu = mips_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUMIPSState *env = cs->env_ptr;
     DisasContext ctx;
     target_ulong pc_start;
     target_ulong next_page_start;
diff --git a/target/moxie/translate.c b/target/moxie/translate.c
index 0660b44c08..3cfd232558 100644
--- a/target/moxie/translate.c
+++ b/target/moxie/translate.c
@@ -822,10 +822,10 @@ static int decode_opc(MoxieCPU *cpu, DisasContext *ctx)
 }
 
 /* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPUMoxieState *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
 {
+    CPUMoxieState *env = cs->env_ptr;
     MoxieCPU *cpu = moxie_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
     DisasContext ctx;
     target_ulong pc_start;
     int num_insns, max_insns;
diff --git a/target/nios2/translate.c b/target/nios2/translate.c
index 2f3c2e5dfb..8b97d6585f 100644
--- a/target/nios2/translate.c
+++ b/target/nios2/translate.c
@@ -799,10 +799,9 @@ static void gen_exception(DisasContext *dc, uint32_t excp)
 }
 
 /* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPUNios2State *env, TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
 {
-    Nios2CPU *cpu = nios2_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUNios2State *env = cs->env_ptr;
     DisasContext dc1, *dc = &dc1;
     int num_insns;
     int max_insns;
diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c
index e49518e893..a01413113b 100644
--- a/target/openrisc/translate.c
+++ b/target/openrisc/translate.c
@@ -1518,10 +1518,10 @@ static void disas_openrisc_insn(DisasContext *dc, OpenRISCCPU *cpu)
     }
 }
 
-void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
 {
+    CPUOpenRISCState *env = cs->env_ptr;
     OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
     struct DisasContext ctx, *dc = &ctx;
     uint32_t pc_start;
     uint32_t next_page_start;
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index c0cd64d927..acb6e881ad 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -7203,10 +7203,9 @@ void ppc_cpu_dump_statistics(CPUState *cs, FILE*f,
 }
 
 /*****************************************************************************/
-void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
 {
-    PowerPCCPU *cpu = ppc_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = cs->env_ptr;
     DisasContext ctx, *ctxp = &ctx;
     opc_handler_t **table, *handler;
     target_ulong pc_start;
diff --git a/target/s390x/translate.c b/target/s390x/translate.c
index 592d6b0f38..cd8c38d6d5 100644
--- a/target/s390x/translate.c
+++ b/target/s390x/translate.c
@@ -5764,10 +5764,9 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s)
     return ret;
 }
 
-void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
 {
-    S390CPU *cpu = s390_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUS390XState *env = cs->env_ptr;
     DisasContext dc;
     target_ulong pc_start;
     uint64_t next_page_start;
diff --git a/target/sh4/translate.c b/target/sh4/translate.c
index 8bc132b27b..1a5ca39cd6 100644
--- a/target/sh4/translate.c
+++ b/target/sh4/translate.c
@@ -1815,10 +1815,9 @@ static void decode_opc(DisasContext * ctx)
     }
 }
 
-void gen_intermediate_code(CPUSH4State * env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
 {
-    SuperHCPU *cpu = sh_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUSH4State *env = cs->env_ptr;
     DisasContext ctx;
     target_ulong pc_start;
     int num_insns;
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index aa6734d54e..293b9c65ea 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -5747,10 +5747,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
     }
 }
 
-void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
+void gen_intermediate_code(CPUState *cs, TranslationBlock * tb)
 {
-    SPARCCPU *cpu = sparc_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUSPARCState *env = cs->env_ptr;
     target_ulong pc_start, last_pc;
     DisasContext dc1, *dc = &dc1;
     int num_insns;
diff --git a/target/tilegx/translate.c b/target/tilegx/translate.c
index ff2ef7b63d..ace2830a84 100644
--- a/target/tilegx/translate.c
+++ b/target/tilegx/translate.c
@@ -2370,12 +2370,11 @@ static void translate_one_bundle(DisasContext *dc, uint64_t bundle)
     }
 }
 
-void gen_intermediate_code(CPUTLGState *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
 {
-    TileGXCPU *cpu = tilegx_env_get_cpu(env);
+    CPUTLGState *env = cs->env_ptr;
     DisasContext ctx;
     DisasContext *dc = &ctx;
-    CPUState *cs = CPU(cpu);
     uint64_t pc_start = tb->pc;
     uint64_t next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
     int num_insns = 0;
diff --git a/target/tricore/translate.c b/target/tricore/translate.c
index ddd2dd07dd..4e4198e887 100644
--- a/target/tricore/translate.c
+++ b/target/tricore/translate.c
@@ -8782,10 +8782,9 @@ static void decode_opc(CPUTriCoreState *env, DisasContext *ctx, int *is_branch)
     }
 }
 
-void gen_intermediate_code(CPUTriCoreState *env, struct TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
 {
-    TriCoreCPU *cpu = tricore_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUTriCoreState *env = cs->env_ptr;
     DisasContext ctx;
     target_ulong pc_start;
     int num_insns, max_insns;
diff --git a/target/unicore32/translate.c b/target/unicore32/translate.c
index 666a2016a8..8f30cff932 100644
--- a/target/unicore32/translate.c
+++ b/target/unicore32/translate.c
@@ -1869,10 +1869,9 @@ static void disas_uc32_insn(CPUUniCore32State *env, DisasContext *s)
 }
 
 /* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPUUniCore32State *env, TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
 {
-    UniCore32CPU *cpu = uc32_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUUniCore32State *env = cs->env_ptr;
     DisasContext dc1, *dc = &dc1;
     target_ulong pc_start;
     uint32_t next_page_start;
diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
index 263002486c..f3f0ff589c 100644
--- a/target/xtensa/translate.c
+++ b/target/xtensa/translate.c
@@ -3117,10 +3117,9 @@ static void gen_ibreak_check(CPUXtensaState *env, DisasContext *dc)
     }
 }
 
-void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
 {
-    XtensaCPU *cpu = xtensa_env_get_cpu(env);
-    CPUState *cs = CPU(cpu);
+    CPUXtensaState *env = cs->env_ptr;
     DisasContext dc;
     int insn_count = 0;
     int max_insns = tb->cflags & CF_COUNT_MASK;

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 02/27] cpu-exec: Avoid global variables in icount-related functions
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
  2017-07-07 11:44 ` [Qemu-devel] [PATCH v12 01/27] Pass generic CPUState to gen_intermediate_code() Lluís Vilanova
@ 2017-07-07 11:48 ` Lluís Vilanova
  2017-07-11 19:25   ` Alex Bennée
  2017-07-07 11:52 ` [Qemu-devel] [PATCH v12 03/27] target: [tcg] Use a generic enum for DISAS_ values Lluís Vilanova
                   ` (25 subsequent siblings)
  27 siblings, 1 reply; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 11:48 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
---
 include/exec/gen-icount.h |   10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h
index 62d462e494..6c28ef59c3 100644
--- a/include/exec/gen-icount.h
+++ b/include/exec/gen-icount.h
@@ -19,7 +19,7 @@ static inline void gen_tb_start(TranslationBlock *tb)
         count = tcg_temp_new_i32();
     }
 
-    tcg_gen_ld_i32(count, cpu_env,
+    tcg_gen_ld_i32(count, tcg_ctx.tcg_env,
                    -ENV_OFFSET + offsetof(CPUState, icount_decr.u32));
 
     if (tb->cflags & CF_USE_ICOUNT) {
@@ -37,7 +37,7 @@ static inline void gen_tb_start(TranslationBlock *tb)
     tcg_gen_brcondi_i32(TCG_COND_LT, count, 0, exitreq_label);
 
     if (tb->cflags & CF_USE_ICOUNT) {
-        tcg_gen_st16_i32(count, cpu_env,
+        tcg_gen_st16_i32(count, tcg_ctx.tcg_env,
                          -ENV_OFFSET + offsetof(CPUState, icount_decr.u16.low));
     }
 
@@ -62,14 +62,16 @@ static void gen_tb_end(TranslationBlock *tb, int num_insns)
 static inline void gen_io_start(void)
 {
     TCGv_i32 tmp = tcg_const_i32(1);
-    tcg_gen_st_i32(tmp, cpu_env, -ENV_OFFSET + offsetof(CPUState, can_do_io));
+    tcg_gen_st_i32(tmp, tcg_ctx.tcg_env,
+                   -ENV_OFFSET + offsetof(CPUState, can_do_io));
     tcg_temp_free_i32(tmp);
 }
 
 static inline void gen_io_end(void)
 {
     TCGv_i32 tmp = tcg_const_i32(0);
-    tcg_gen_st_i32(tmp, cpu_env, -ENV_OFFSET + offsetof(CPUState, can_do_io));
+    tcg_gen_st_i32(tmp, tcg_ctx.tcg_env,
+                   -ENV_OFFSET + offsetof(CPUState, can_do_io));
     tcg_temp_free_i32(tmp);
 }
 

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 03/27] target: [tcg] Use a generic enum for DISAS_ values
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
  2017-07-07 11:44 ` [Qemu-devel] [PATCH v12 01/27] Pass generic CPUState to gen_intermediate_code() Lluís Vilanova
  2017-07-07 11:48 ` [Qemu-devel] [PATCH v12 02/27] cpu-exec: Avoid global variables in icount-related functions Lluís Vilanova
@ 2017-07-07 11:52 ` Lluís Vilanova
  2017-07-12  9:10   ` Alex Bennée
  2017-07-07 11:56 ` [Qemu-devel] [PATCH v12 04/27] target: [tcg] Add generic translation framework Lluís Vilanova
                   ` (24 subsequent siblings)
  27 siblings, 1 reply; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 11:52 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Peter Maydell,
	Edgar E. Iglesias, Eduardo Habkost, Michael Walle,
	Laurent Vivier, Chris Wulff, Marek Vasut, Stafford Horne,
	Alexander Graf, Guan Xuetao, Max Filippov, open list:ARM

Used later. An enum makes expected values explicit and bounds the value space of
switches.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 include/exec/exec-all.h       |    6 ------
 include/exec/translator.h     |   39 +++++++++++++++++++++++++++++++++++++++
 target/arm/translate.h        |   26 ++++++++++++++++----------
 target/cris/translate.c       |    7 ++++++-
 target/i386/translate.c       |    4 ++++
 target/lm32/translate.c       |    6 ++++++
 target/m68k/translate.c       |    7 ++++++-
 target/microblaze/translate.c |    6 ++++++
 target/nios2/translate.c      |    6 ++++++
 target/openrisc/translate.c   |    6 ++++++
 target/s390x/translate.c      |    3 ++-
 target/unicore32/translate.c  |    7 ++++++-
 target/xtensa/translate.c     |    4 ++++
 13 files changed, 107 insertions(+), 20 deletions(-)
 create mode 100644 include/exec/translator.h

diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 0826894ec5..27498cf740 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -35,12 +35,6 @@ typedef abi_ulong tb_page_addr_t;
 typedef ram_addr_t tb_page_addr_t;
 #endif
 
-/* is_jmp field values */
-#define DISAS_NEXT    0 /* next instruction can be analyzed */
-#define DISAS_JUMP    1 /* only pc was modified dynamically */
-#define DISAS_UPDATE  2 /* cpu state was modified dynamically */
-#define DISAS_TB_JUMP 3 /* only pc was modified statically */
-
 #include "qemu/log.h"
 
 void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb);
diff --git a/include/exec/translator.h b/include/exec/translator.h
new file mode 100644
index 0000000000..1f9697dd31
--- /dev/null
+++ b/include/exec/translator.h
@@ -0,0 +1,39 @@
+/*
+ * Generic intermediate code generation.
+ *
+ * Copyright (C) 2016-2017 Lluís Vilanova <vilanova@ac.upc.edu>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef EXEC__TRANSLATOR_H
+#define EXEC__TRANSLATOR_H
+
+/**
+ * DisasJumpType:
+ * @DISAS_NEXT: Next instruction in program order.
+ * @DISAS_TOO_MANY: Too many instructions translated.
+ * @DISAS_TARGET: Start of target-specific conditions.
+ *
+ * What instruction to disassemble next.
+ */
+typedef enum DisasJumpType {
+    DISAS_NEXT,
+    DISAS_TOO_MANY,
+    DISAS_TARGET_0,
+    DISAS_TARGET_1,
+    DISAS_TARGET_2,
+    DISAS_TARGET_3,
+    DISAS_TARGET_4,
+    DISAS_TARGET_5,
+    DISAS_TARGET_6,
+    DISAS_TARGET_7,
+    DISAS_TARGET_8,
+    DISAS_TARGET_9,
+    DISAS_TARGET_10,
+    DISAS_TARGET_11,
+    DISAS_TARGET_12,
+} DisasJumpType;
+
+#endif  /* EXEC__TRANSLATOR_H */
diff --git a/target/arm/translate.h b/target/arm/translate.h
index e5da614db5..aba3f44c9f 100644
--- a/target/arm/translate.h
+++ b/target/arm/translate.h
@@ -1,6 +1,9 @@
 #ifndef TARGET_ARM_TRANSLATE_H
 #define TARGET_ARM_TRANSLATE_H
 
+#include "exec/translator.h"
+
+
 /* internal defines */
 typedef struct DisasContext {
     target_ulong pc;
@@ -119,30 +122,33 @@ static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
     s->insn_start_idx = 0;
 }
 
-/* target-specific extra values for is_jmp */
+/* is_jmp field values */
+#define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
+#define DISAS_UPDATE  DISAS_TARGET_1 /* cpu state was modified dynamically */
+#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
 /* These instructions trap after executing, so the A32/T32 decoder must
  * defer them until after the conditional execution state has been updated.
  * WFI also needs special handling when single-stepping.
  */
-#define DISAS_WFI 4
-#define DISAS_SWI 5
+#define DISAS_WFI DISAS_TARGET_3
+#define DISAS_SWI DISAS_TARGET_4
 /* For instructions which unconditionally cause an exception we can skip
  * emitting unreachable code at the end of the TB in the A64 decoder
  */
-#define DISAS_EXC 6
+#define DISAS_EXC DISAS_TARGET_5
 /* WFE */
-#define DISAS_WFE 7
-#define DISAS_HVC 8
-#define DISAS_SMC 9
-#define DISAS_YIELD 10
+#define DISAS_WFE DISAS_TARGET_6
+#define DISAS_HVC DISAS_TARGET_7
+#define DISAS_SMC DISAS_TARGET_8
+#define DISAS_YIELD DISAS_TARGET_9
 /* M profile branch which might be an exception return (and so needs
  * custom end-of-TB code)
  */
-#define DISAS_BX_EXCRET 11
+#define DISAS_BX_EXCRET DISAS_TARGET_10
 /* For instructions which want an immediate exit to the main loop,
  * as opposed to attempting to use lookup_and_goto_ptr.
  */
-#define DISAS_EXIT 12
+#define DISAS_EXIT DISAS_TARGET_11
 
 #ifdef TARGET_AARCH64
 void a64_translate_init(void);
diff --git a/target/cris/translate.c b/target/cris/translate.c
index 12b96eb68f..38a999e6f1 100644
--- a/target/cris/translate.c
+++ b/target/cris/translate.c
@@ -31,6 +31,7 @@
 #include "exec/helper-proto.h"
 #include "mmu.h"
 #include "exec/cpu_ldst.h"
+#include "exec/translator.h"
 #include "crisv32-decode.h"
 
 #include "exec/helper-gen.h"
@@ -50,7 +51,11 @@
 #define BUG() (gen_BUG(dc, __FILE__, __LINE__))
 #define BUG_ON(x) ({if (x) BUG();})
 
-#define DISAS_SWI 5
+/* is_jmp field values */
+#define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
+#define DISAS_UPDATE  DISAS_TARGET_1 /* cpu state was modified dynamically */
+#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
+#define DISAS_SWI     DISAS_TARGET_3
 
 /* Used by the decoder.  */
 #define EXTRACT_FIELD(src, start, end) \
diff --git a/target/i386/translate.c b/target/i386/translate.c
index cab9e32f91..b118fcb834 100644
--- a/target/i386/translate.c
+++ b/target/i386/translate.c
@@ -24,6 +24,7 @@
 #include "exec/exec-all.h"
 #include "tcg-op.h"
 #include "exec/cpu_ldst.h"
+#include "exec/translator.h"
 
 #include "exec/helper-proto.h"
 #include "exec/helper-gen.h"
@@ -71,6 +72,9 @@
 
 //#define MACRO_TEST   1
 
+/* is_jmp field values */
+#define DISAS_TB_JUMP DISAS_TARGET_0 /* only pc was modified statically */
+
 /* global register indexes */
 static TCGv_env cpu_env;
 static TCGv cpu_A0;
diff --git a/target/lm32/translate.c b/target/lm32/translate.c
index f68f372f15..65bc9c0bf6 100644
--- a/target/lm32/translate.c
+++ b/target/lm32/translate.c
@@ -22,6 +22,7 @@
 #include "disas/disas.h"
 #include "exec/helper-proto.h"
 #include "exec/exec-all.h"
+#include "exec/translator.h"
 #include "tcg-op.h"
 
 #include "exec/cpu_ldst.h"
@@ -47,6 +48,11 @@
 
 #define MEM_INDEX 0
 
+/* is_jmp field values */
+#define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
+#define DISAS_UPDATE  DISAS_TARGET_1 /* cpu state was modified dynamically */
+#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
+
 static TCGv_env cpu_env;
 static TCGv cpu_R[32];
 static TCGv cpu_pc;
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index af19872e0b..af08a5c959 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -25,6 +25,7 @@
 #include "tcg-op.h"
 #include "qemu/log.h"
 #include "exec/cpu_ldst.h"
+#include "exec/translator.h"
 
 #include "exec/helper-proto.h"
 #include "exec/helper-gen.h"
@@ -173,7 +174,11 @@ static void do_writebacks(DisasContext *s)
     }
 }
 
-#define DISAS_JUMP_NEXT 4
+/* is_jmp field values */
+#define DISAS_JUMP      DISAS_TARGET_0 /* only pc was modified dynamically */
+#define DISAS_UPDATE    DISAS_TARGET_1 /* cpu state was modified dynamically */
+#define DISAS_TB_JUMP   DISAS_TARGET_2 /* only pc was modified statically */
+#define DISAS_JUMP_NEXT DISAS_TARGET_3
 
 #if defined(CONFIG_USER_ONLY)
 #define IS_USER(s) 1
diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c
index a180bc78ae..e050c694d8 100644
--- a/target/microblaze/translate.c
+++ b/target/microblaze/translate.c
@@ -27,6 +27,7 @@
 #include "microblaze-decode.h"
 #include "exec/cpu_ldst.h"
 #include "exec/helper-gen.h"
+#include "exec/translator.h"
 
 #include "trace-tcg.h"
 #include "exec/log.h"
@@ -46,6 +47,11 @@
 #define EXTRACT_FIELD(src, start, end) \
             (((src) >> start) & ((1 << (end - start + 1)) - 1))
 
+/* is_jmp field values */
+#define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
+#define DISAS_UPDATE  DISAS_TARGET_1 /* cpu state was modified dynamically */
+#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
+
 static TCGv env_debug;
 static TCGv_env cpu_env;
 static TCGv cpu_R[32];
diff --git a/target/nios2/translate.c b/target/nios2/translate.c
index 8b97d6585f..6b0961837d 100644
--- a/target/nios2/translate.c
+++ b/target/nios2/translate.c
@@ -29,6 +29,12 @@
 #include "exec/helper-gen.h"
 #include "exec/log.h"
 #include "exec/cpu_ldst.h"
+#include "exec/translator.h"
+
+/* is_jmp field values */
+#define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
+#define DISAS_UPDATE  DISAS_TARGET_1 /* cpu state was modified dynamically */
+#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
 
 #define INSTRUCTION_FLG(func, flags) { (func), (flags) }
 #define INSTRUCTION(func)                  \
diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c
index a01413113b..112db1ad0f 100644
--- a/target/openrisc/translate.c
+++ b/target/openrisc/translate.c
@@ -27,6 +27,7 @@
 #include "qemu/log.h"
 #include "qemu/bitops.h"
 #include "exec/cpu_ldst.h"
+#include "exec/translator.h"
 
 #include "exec/helper-proto.h"
 #include "exec/helper-gen.h"
@@ -37,6 +38,11 @@
 #define LOG_DIS(str, ...) \
     qemu_log_mask(CPU_LOG_TB_IN_ASM, "%08x: " str, dc->pc, ## __VA_ARGS__)
 
+/* is_jmp field values */
+#define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
+#define DISAS_UPDATE  DISAS_TARGET_1 /* cpu state was modified dynamically */
+#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
+
 typedef struct DisasContext {
     TranslationBlock *tb;
     target_ulong pc;
diff --git a/target/s390x/translate.c b/target/s390x/translate.c
index cd8c38d6d5..6ed38371a1 100644
--- a/target/s390x/translate.c
+++ b/target/s390x/translate.c
@@ -76,7 +76,8 @@ typedef struct {
     } u;
 } DisasCompare;
 
-#define DISAS_EXCP 4
+/* is_jmp field values */
+#define DISAS_EXCP DISAS_TARGET_0
 
 #ifdef DEBUG_INLINE_BRANCHES
 static uint64_t inline_branch_hit[CC_OP_MAX];
diff --git a/target/unicore32/translate.c b/target/unicore32/translate.c
index 8f30cff932..6c094d59d7 100644
--- a/target/unicore32/translate.c
+++ b/target/unicore32/translate.c
@@ -16,6 +16,7 @@
 #include "tcg-op.h"
 #include "qemu/log.h"
 #include "exec/cpu_ldst.h"
+#include "exec/translator.h"
 
 #include "exec/helper-proto.h"
 #include "exec/helper-gen.h"
@@ -45,9 +46,13 @@ typedef struct DisasContext {
 #define IS_USER(s)      1
 #endif
 
+/* is_jmp field values */
+#define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
+#define DISAS_UPDATE  DISAS_TARGET_1 /* cpu state was modified dynamically */
+#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
 /* These instructions trap after executing, so defer them until after the
    conditional executions state has been updated.  */
-#define DISAS_SYSCALL 5
+#define DISAS_SYSCALL DISAS_TARGET_3
 
 static TCGv_env cpu_env;
 static TCGv_i32 cpu_R[32];
diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
index f3f0ff589c..d7bf07e8e6 100644
--- a/target/xtensa/translate.c
+++ b/target/xtensa/translate.c
@@ -38,6 +38,7 @@
 #include "sysemu/sysemu.h"
 #include "exec/cpu_ldst.h"
 #include "exec/semihost.h"
+#include "exec/translator.h"
 
 #include "exec/helper-proto.h"
 #include "exec/helper-gen.h"
@@ -46,6 +47,9 @@
 #include "exec/log.h"
 
 
+/* is_jmp field values */
+#define DISAS_UPDATE  DISAS_TARGET_0 /* cpu state was modified dynamically */
+
 typedef struct DisasContext {
     const XtensaConfig *config;
     TranslationBlock *tb;

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 04/27] target: [tcg] Add generic translation framework
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (2 preceding siblings ...)
  2017-07-07 11:52 ` [Qemu-devel] [PATCH v12 03/27] target: [tcg] Use a generic enum for DISAS_ values Lluís Vilanova
@ 2017-07-07 11:56 ` Lluís Vilanova
  2017-07-07 18:42   ` Richard Henderson
  2017-07-11 18:17   ` Alex Bennée
  2017-07-07 12:00 ` [Qemu-devel] [PATCH v12 05/27] target/i386: [tcg] Port to DisasContextBase Lluís Vilanova
                   ` (23 subsequent siblings)
  27 siblings, 2 replies; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 11:56 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
---
 accel/tcg/Makefile.objs   |    1 
 accel/tcg/translator.c    |  152 +++++++++++++++++++++++++++++++++++++++++++++
 include/exec/gen-icount.h |    2 -
 include/exec/translator.h |   99 +++++++++++++++++++++++++++++
 4 files changed, 253 insertions(+), 1 deletion(-)
 create mode 100644 accel/tcg/translator.c

diff --git a/accel/tcg/Makefile.objs b/accel/tcg/Makefile.objs
index f173cd5397..3a5da5357c 100644
--- a/accel/tcg/Makefile.objs
+++ b/accel/tcg/Makefile.objs
@@ -1,3 +1,4 @@
 obj-$(CONFIG_SOFTMMU) += tcg-all.o
 obj-$(CONFIG_SOFTMMU) += cputlb.o
 obj-y += cpu-exec.o cpu-exec-common.o translate-all.o translate-common.o
+obj-y += translator.o
diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
new file mode 100644
index 0000000000..9e0343cbb1
--- /dev/null
+++ b/accel/tcg/translator.c
@@ -0,0 +1,152 @@
+/*
+ * Generic intermediate code generation.
+ *
+ * Copyright (C) 2016-2017 Lluís Vilanova <vilanova@ac.upc.edu>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/error-report.h"
+#include "cpu.h"
+#include "tcg/tcg.h"
+#include "tcg/tcg-op.h"
+#include "exec/exec-all.h"
+#include "exec/gen-icount.h"
+#include "exec/log.h"
+#include "exec/translator.h"
+
+
+static inline void translate_block_tcg_check(const DisasContextBase *db)
+{
+    if (tcg_check_temp_count()) {
+        error_report("warning: TCG temporary leaks before "TARGET_FMT_lx,
+                     db->pc_next);
+    }
+}
+
+void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
+                     CPUState *cpu, TranslationBlock *tb)
+{
+    int max_insns;
+
+    /* Initialize DisasContext */
+    db->tb = tb;
+    db->pc_first = tb->pc;
+    db->pc_next = db->pc_first;
+    db->is_jmp = DISAS_NEXT;
+    db->num_insns = 0;
+    db->singlestep_enabled = cpu->singlestep_enabled;
+    ops->init_disas_context(db, cpu);
+
+    /* Initialize globals */
+    tcg_clear_temp_count();
+
+    /* Instruction counting */
+    max_insns = db->tb->cflags & CF_COUNT_MASK;
+    if (max_insns == 0) {
+        max_insns = CF_COUNT_MASK;
+    }
+    if (max_insns > TCG_MAX_INSNS) {
+        max_insns = TCG_MAX_INSNS;
+    }
+    if (db->singlestep_enabled || singlestep) {
+        max_insns = 1;
+    }
+
+    /* Start translating */
+    gen_tb_start(db->tb);
+    ops->tb_start(db, cpu);
+
+    while (true) {
+        db->num_insns++;
+        ops->insn_start(db, cpu);
+
+        /* Early exit before breakpoint checks */
+        if (unlikely(db->is_jmp != DISAS_NEXT)) {
+            break;
+        }
+
+        /* Pass breakpoint hits to target for further processing */
+        if (unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
+            CPUBreakpoint *bp;
+            QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
+                if (bp->pc == db->pc_next) {
+                    BreakpointCheckType bp_check =
+                        ops->breakpoint_check(db, cpu, bp);
+                    switch (bp_check) {
+                    case BC_MISS:
+                        /* Target ignored this breakpoint, go to next */
+                        break;
+                    case BC_HIT_INSN:
+                        /* Hit, keep translating */
+                        /*
+                         * TODO: if we're never going to have more than one
+                         *       BP in a single address, we can simply use a
+                         *       bool here.
+                         */
+                        goto done_breakpoints;
+                    case BC_HIT_TB:
+                        /* Hit, end TB */
+                        goto done_generating;
+                    default:
+                        g_assert_not_reached();
+                    }
+                }
+            }
+        }
+    done_breakpoints:
+
+        /* Accept I/O on last instruction */
+        if (db->num_insns == max_insns && (db->tb->cflags & CF_LAST_IO)) {
+            gen_io_start();
+        }
+
+        /* Disassemble one instruction */
+        db->pc_next = ops->translate_insn(db, cpu);
+
+        /**************************************************/
+        /* Conditions to stop translation                 */
+        /**************************************************/
+
+        /* Target-specific conditions set by disassembly */
+        if (db->is_jmp != DISAS_NEXT) {
+            break;
+        }
+
+        /* Too many instructions */
+        if (tcg_op_buf_full() || db->num_insns >= max_insns) {
+            db->is_jmp = DISAS_TOO_MANY;
+            break;
+        }
+
+        translate_block_tcg_check(db);
+    }
+
+    ops->tb_stop(db, cpu);
+
+    if (db->tb->cflags & CF_LAST_IO) {
+        gen_io_end();
+    }
+
+done_generating:
+    gen_tb_end(db->tb, db->num_insns);
+
+    translate_block_tcg_check(db);
+
+#ifdef DEBUG_DISAS
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
+        && qemu_log_in_addr_range(db->pc_first)) {
+        qemu_log_lock();
+        qemu_log("----------------\n");
+        ops->disas_log(db, cpu);
+        qemu_log("\n");
+        qemu_log_unlock();
+    }
+#endif
+
+    db->tb->size = db->pc_next - db->pc_first;
+    db->tb->icount = db->num_insns;
+}
diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h
index 6c28ef59c3..9b3cb14dfa 100644
--- a/include/exec/gen-icount.h
+++ b/include/exec/gen-icount.h
@@ -44,7 +44,7 @@ static inline void gen_tb_start(TranslationBlock *tb)
     tcg_temp_free_i32(count);
 }
 
-static void gen_tb_end(TranslationBlock *tb, int num_insns)
+static inline void gen_tb_end(TranslationBlock *tb, int num_insns)
 {
     if (tb->cflags & CF_USE_ICOUNT) {
         /* Update the num_insn immediate parameter now that we know
diff --git a/include/exec/translator.h b/include/exec/translator.h
index 1f9697dd31..f96b66f2bf 100644
--- a/include/exec/translator.h
+++ b/include/exec/translator.h
@@ -10,6 +10,38 @@
 #ifndef EXEC__TRANSLATOR_H
 #define EXEC__TRANSLATOR_H
 
+/*
+ * Include this header from a target-specific file, and add a
+ *
+ *     DisasContextBase base;
+ *
+ * member in your target-specific DisasContext.
+ */
+
+
+#include "exec/exec-all.h"
+#include "tcg/tcg.h"
+
+
+/**
+ * BreakpointCheckType:
+ * @BC_MISS: No hit
+ * @BC_HIT_INSN: Hit, but continue translating TB
+ * @BC_HIT_TB: Hit, stop translating TB
+ *
+ * How to react to a breakpoint. A hit means no more breakpoints will be checked
+ * for the current instruction.
+ *
+ * Not all breakpoints associated to an address are necessarily raised by
+ * targets (e.g., due to conditions encoded in their flags), so they can decide
+ * that a breakpoint missed the address (@BP_MISS).
+ */
+typedef enum BreakpointCheckType {
+    BC_MISS,
+    BC_HIT_INSN,
+    BC_HIT_TB,
+} BreakpointCheckType;
+
 /**
  * DisasJumpType:
  * @DISAS_NEXT: Next instruction in program order.
@@ -36,4 +68,71 @@ typedef enum DisasJumpType {
     DISAS_TARGET_12,
 } DisasJumpType;
 
+/**
+ * DisasContextBase:
+ * @tb: Translation block for this disassembly.
+ * @pc_first: Address of first guest instruction in this TB.
+ * @pc_next: Address of next guest instruction in this TB (current during
+ *           disassembly).
+ * @is_jmp: What instruction to disassemble next.
+ * @num_insns: Number of translated instructions (including current).
+ * @singlestep_enabled: "Hardware" single stepping enabled.
+ *
+ * Architecture-agnostic disassembly context.
+ */
+typedef struct DisasContextBase {
+    TranslationBlock *tb;
+    target_ulong pc_first;
+    target_ulong pc_next;
+    DisasJumpType is_jmp;
+    unsigned int num_insns;
+    bool singlestep_enabled;
+} DisasContextBase;
+
+/**
+ * TranslatorOps:
+ * @init_disas_context: Initialize a DisasContext struct (DisasContextBase has
+ *                      already been initialized).
+ * @tb_start: Start translating a new TB.
+ * @insn_start: Start translating a new instruction.
+ * @breakpoint_check: Check if a breakpoint did hit. When called, the breakpoint
+ *                    has already been checked to match the PC.
+ * @translate_insn: Disassemble one instruction and return the PC for the next
+ *                  one. Can set db->is_jmp to DISAS_TARGET or above to stop
+ *                  translation.
+ * @tb_stop: Stop translating a TB.
+ * @disas_log: Print instruction disassembly to log.
+ *
+ * Target-specific operations for the generic translator loop.
+ */
+typedef struct TranslatorOps {
+    void (*init_disas_context)(DisasContextBase *db, CPUState *cpu);
+    void (*tb_start)(DisasContextBase *db, CPUState *cpu);
+    void (*insn_start)(DisasContextBase *db, CPUState *cpu);
+    BreakpointCheckType (*breakpoint_check)(DisasContextBase *db, CPUState *cpu,
+                                            const CPUBreakpoint *bp);
+    target_ulong (*translate_insn)(DisasContextBase *db, CPUState *cpu);
+    void (*tb_stop)(DisasContextBase *db, CPUState *cpu);
+    void (*disas_log)(const DisasContextBase *db, CPUState *cpu);
+} TranslatorOps;
+
+/**
+ * translator_loop:
+ * @ops: Target-specific operations.
+ * @db: Disassembly context.
+ * @cpu: Target vCPU.
+ * @tb: Translation block.
+ *
+ * Generic translator loop.
+ *
+ * Translation will stop in the following cases (in order):
+ * - When set by #TranslatorOps::insn_start.
+ * - When set by #TranslatorOps::translate_insn.
+ * - When the TCG operation buffer is full.
+ * - When single-stepping is enabled (system-wide or on the current vCPU).
+ * - When too many instructions have been translated.
+ */
+void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
+                     CPUState *cpu, TranslationBlock *tb);
+
 #endif  /* EXEC__TRANSLATOR_H */

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 05/27] target/i386: [tcg] Port to DisasContextBase
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (3 preceding siblings ...)
  2017-07-07 11:56 ` [Qemu-devel] [PATCH v12 04/27] target: [tcg] Add generic translation framework Lluís Vilanova
@ 2017-07-07 12:00 ` Lluís Vilanova
  2017-07-12  9:18   ` Alex Bennée
  2017-07-07 12:04 ` [Qemu-devel] [PATCH v12 06/27] target/i386: [tcg] Port to init_disas_context Lluís Vilanova
                   ` (22 subsequent siblings)
  27 siblings, 1 reply; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 12:00 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Eduardo Habkost

Incrementally paves the way towards using the generic instruction translation
loop.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target/i386/translate.c |  142 +++++++++++++++++++++++------------------------
 1 file changed, 70 insertions(+), 72 deletions(-)

diff --git a/target/i386/translate.c b/target/i386/translate.c
index b118fcb834..f61f5c7227 100644
--- a/target/i386/translate.c
+++ b/target/i386/translate.c
@@ -99,6 +99,8 @@ static int x86_64_hregs;
 #endif
 
 typedef struct DisasContext {
+    DisasContextBase base;
+
     /* current insn context */
     int override; /* -1 if no override */
     int prefix;
@@ -106,8 +108,6 @@ typedef struct DisasContext {
     TCGMemOp dflag;
     target_ulong pc_start;
     target_ulong pc; /* pc = eip + cs_base */
-    int is_jmp; /* 1 = means jump (stop translation), 2 means CPU
-                   static state change (stop translation) */
     /* current block context */
     target_ulong cs_base; /* base of CS segment */
     int pe;     /* protected mode */
@@ -128,12 +128,10 @@ typedef struct DisasContext {
     int cpl;
     int iopl;
     int tf;     /* TF cpu flag */
-    int singlestep_enabled; /* "hardware" single step enabled */
     int jmp_opt; /* use direct block chaining for direct jumps */
     int repz_opt; /* optimize jumps within repz instructions */
     int mem_index; /* select memory access functions */
     uint64_t flags; /* all execution flags */
-    struct TranslationBlock *tb;
     int popl_esp_hack; /* for correct popl with esp base handling */
     int rip_offset; /* only used in x86_64, but left for simplicity */
     int cpuid_features;
@@ -1123,7 +1121,7 @@ static void gen_bpt_io(DisasContext *s, TCGv_i32 t_port, int ot)
 
 static inline void gen_ins(DisasContext *s, TCGMemOp ot)
 {
-    if (s->tb->cflags & CF_USE_ICOUNT) {
+    if (s->base.tb->cflags & CF_USE_ICOUNT) {
         gen_io_start();
     }
     gen_string_movl_A0_EDI(s);
@@ -1138,14 +1136,14 @@ static inline void gen_ins(DisasContext *s, TCGMemOp ot)
     gen_op_movl_T0_Dshift(ot);
     gen_op_add_reg_T0(s->aflag, R_EDI);
     gen_bpt_io(s, cpu_tmp2_i32, ot);
-    if (s->tb->cflags & CF_USE_ICOUNT) {
+    if (s->base.tb->cflags & CF_USE_ICOUNT) {
         gen_io_end();
     }
 }
 
 static inline void gen_outs(DisasContext *s, TCGMemOp ot)
 {
-    if (s->tb->cflags & CF_USE_ICOUNT) {
+    if (s->base.tb->cflags & CF_USE_ICOUNT) {
         gen_io_start();
     }
     gen_string_movl_A0_ESI(s);
@@ -1158,7 +1156,7 @@ static inline void gen_outs(DisasContext *s, TCGMemOp ot)
     gen_op_movl_T0_Dshift(ot);
     gen_op_add_reg_T0(s->aflag, R_ESI);
     gen_bpt_io(s, cpu_tmp2_i32, ot);
-    if (s->tb->cflags & CF_USE_ICOUNT) {
+    if (s->base.tb->cflags & CF_USE_ICOUNT) {
         gen_io_end();
     }
 }
@@ -2141,7 +2139,7 @@ static inline int insn_const_size(TCGMemOp ot)
 static inline bool use_goto_tb(DisasContext *s, target_ulong pc)
 {
 #ifndef CONFIG_USER_ONLY
-    return (pc & TARGET_PAGE_MASK) == (s->tb->pc & TARGET_PAGE_MASK) ||
+    return (pc & TARGET_PAGE_MASK) == (s->base.tb->pc & TARGET_PAGE_MASK) ||
            (pc & TARGET_PAGE_MASK) == (s->pc_start & TARGET_PAGE_MASK);
 #else
     return true;
@@ -2156,7 +2154,7 @@ static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip)
         /* jump to same page: we can use a direct jump */
         tcg_gen_goto_tb(tb_num);
         gen_jmp_im(eip);
-        tcg_gen_exit_tb((uintptr_t)s->tb + tb_num);
+        tcg_gen_exit_tb((uintptr_t)s->base.tb + tb_num);
     } else {
         /* jump to another page */
         gen_jmp_im(eip);
@@ -2177,7 +2175,7 @@ static inline void gen_jcc(DisasContext *s, int b,
 
         gen_set_label(l1);
         gen_goto_tb(s, 1, val);
-        s->is_jmp = DISAS_TB_JUMP;
+        s->base.is_jmp = DISAS_TB_JUMP;
     } else {
         l1 = gen_new_label();
         l2 = gen_new_label();
@@ -2248,11 +2246,11 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg)
            stop as a special handling must be done to disable hardware
            interrupts for the next instruction */
         if (seg_reg == R_SS || (s->code32 && seg_reg < R_FS))
-            s->is_jmp = DISAS_TB_JUMP;
+            s->base.is_jmp = DISAS_TB_JUMP;
     } else {
         gen_op_movl_seg_T0_vm(seg_reg);
         if (seg_reg == R_SS)
-            s->is_jmp = DISAS_TB_JUMP;
+            s->base.is_jmp = DISAS_TB_JUMP;
     }
 }
 
@@ -2424,7 +2422,7 @@ static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip)
     gen_update_cc_op(s);
     gen_jmp_im(cur_eip);
     gen_helper_raise_exception(cpu_env, tcg_const_i32(trapno));
-    s->is_jmp = DISAS_TB_JUMP;
+    s->base.is_jmp = DISAS_TB_JUMP;
 }
 
 /* Generate #UD for the current instruction.  The assumption here is that
@@ -2462,7 +2460,7 @@ static void gen_interrupt(DisasContext *s, int intno,
     gen_jmp_im(cur_eip);
     gen_helper_raise_interrupt(cpu_env, tcg_const_i32(intno),
                                tcg_const_i32(next_eip - cur_eip));
-    s->is_jmp = DISAS_TB_JUMP;
+    s->base.is_jmp = DISAS_TB_JUMP;
 }
 
 static void gen_debug(DisasContext *s, target_ulong cur_eip)
@@ -2470,7 +2468,7 @@ static void gen_debug(DisasContext *s, target_ulong cur_eip)
     gen_update_cc_op(s);
     gen_jmp_im(cur_eip);
     gen_helper_debug(cpu_env);
-    s->is_jmp = DISAS_TB_JUMP;
+    s->base.is_jmp = DISAS_TB_JUMP;
 }
 
 static void gen_set_hflag(DisasContext *s, uint32_t mask)
@@ -2526,10 +2524,10 @@ do_gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf, TCGv jr)
         gen_reset_hflag(s, HF_INHIBIT_IRQ_MASK);
     }
 
-    if (s->tb->flags & HF_RF_MASK) {
+    if (s->base.tb->flags & HF_RF_MASK) {
         gen_helper_reset_rf(cpu_env);
     }
-    if (s->singlestep_enabled) {
+    if (s->base.singlestep_enabled) {
         gen_helper_debug(cpu_env);
     } else if (recheck_tf) {
         gen_helper_rechecking_single_step(cpu_env);
@@ -2545,7 +2543,7 @@ do_gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf, TCGv jr)
     } else {
         tcg_gen_exit_tb(0);
     }
-    s->is_jmp = DISAS_TB_JUMP;
+    s->base.is_jmp = DISAS_TB_JUMP;
 }
 
 static inline void
@@ -2584,7 +2582,7 @@ static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num)
     set_cc_op(s, CC_OP_DYNAMIC);
     if (s->jmp_opt) {
         gen_goto_tb(s, tb_num, eip);
-        s->is_jmp = DISAS_TB_JUMP;
+        s->base.is_jmp = DISAS_TB_JUMP;
     } else {
         gen_jmp_im(eip);
         gen_eob(s);
@@ -4419,7 +4417,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
     }
 }
 
-/* convert one instruction. s->is_jmp is set if the translation must
+/* convert one instruction. s->base.is_jmp is set if the translation must
    be stopped. Return the next pc value */
 static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
                                target_ulong pc_start)
@@ -5379,7 +5377,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
         gen_movl_seg_T0(s, reg);
         gen_pop_update(s, ot);
         /* Note that reg == R_SS in gen_movl_seg_T0 always sets is_jmp.  */
-        if (s->is_jmp) {
+        if (s->base.is_jmp) {
             gen_jmp_im(s->pc - s->cs_base);
             if (reg == R_SS) {
                 s->tf = 0;
@@ -5394,7 +5392,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
         ot = gen_pop_T0(s);
         gen_movl_seg_T0(s, (b >> 3) & 7);
         gen_pop_update(s, ot);
-        if (s->is_jmp) {
+        if (s->base.is_jmp) {
             gen_jmp_im(s->pc - s->cs_base);
             gen_eob(s);
         }
@@ -5445,7 +5443,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
         gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
         gen_movl_seg_T0(s, reg);
         /* Note that reg == R_SS in gen_movl_seg_T0 always sets is_jmp.  */
-        if (s->is_jmp) {
+        if (s->base.is_jmp) {
             gen_jmp_im(s->pc - s->cs_base);
             if (reg == R_SS) {
                 s->tf = 0;
@@ -5654,7 +5652,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
         gen_movl_seg_T0(s, op);
         /* then put the data */
         gen_op_mov_reg_v(ot, reg, cpu_T1);
-        if (s->is_jmp) {
+        if (s->base.is_jmp) {
             gen_jmp_im(s->pc - s->cs_base);
             gen_eob(s);
         }
@@ -6310,7 +6308,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
             gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
         } else {
             gen_ins(s, ot);
-            if (s->tb->cflags & CF_USE_ICOUNT) {
+            if (s->base.tb->cflags & CF_USE_ICOUNT) {
                 gen_jmp(s, s->pc - s->cs_base);
             }
         }
@@ -6325,7 +6323,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
             gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
         } else {
             gen_outs(s, ot);
-            if (s->tb->cflags & CF_USE_ICOUNT) {
+            if (s->base.tb->cflags & CF_USE_ICOUNT) {
                 gen_jmp(s, s->pc - s->cs_base);
             }
         }
@@ -6341,14 +6339,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
         tcg_gen_movi_tl(cpu_T0, val);
         gen_check_io(s, ot, pc_start - s->cs_base,
                      SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
-        if (s->tb->cflags & CF_USE_ICOUNT) {
+        if (s->base.tb->cflags & CF_USE_ICOUNT) {
             gen_io_start();
 	}
         tcg_gen_movi_i32(cpu_tmp2_i32, val);
         gen_helper_in_func(ot, cpu_T1, cpu_tmp2_i32);
         gen_op_mov_reg_v(ot, R_EAX, cpu_T1);
         gen_bpt_io(s, cpu_tmp2_i32, ot);
-        if (s->tb->cflags & CF_USE_ICOUNT) {
+        if (s->base.tb->cflags & CF_USE_ICOUNT) {
             gen_io_end();
             gen_jmp(s, s->pc - s->cs_base);
         }
@@ -6362,14 +6360,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
                      svm_is_rep(prefixes));
         gen_op_mov_v_reg(ot, cpu_T1, R_EAX);
 
-        if (s->tb->cflags & CF_USE_ICOUNT) {
+        if (s->base.tb->cflags & CF_USE_ICOUNT) {
             gen_io_start();
 	}
         tcg_gen_movi_i32(cpu_tmp2_i32, val);
         tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T1);
         gen_helper_out_func(ot, cpu_tmp2_i32, cpu_tmp3_i32);
         gen_bpt_io(s, cpu_tmp2_i32, ot);
-        if (s->tb->cflags & CF_USE_ICOUNT) {
+        if (s->base.tb->cflags & CF_USE_ICOUNT) {
             gen_io_end();
             gen_jmp(s, s->pc - s->cs_base);
         }
@@ -6380,14 +6378,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
         tcg_gen_ext16u_tl(cpu_T0, cpu_regs[R_EDX]);
         gen_check_io(s, ot, pc_start - s->cs_base,
                      SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
-        if (s->tb->cflags & CF_USE_ICOUNT) {
+        if (s->base.tb->cflags & CF_USE_ICOUNT) {
             gen_io_start();
 	}
         tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T0);
         gen_helper_in_func(ot, cpu_T1, cpu_tmp2_i32);
         gen_op_mov_reg_v(ot, R_EAX, cpu_T1);
         gen_bpt_io(s, cpu_tmp2_i32, ot);
-        if (s->tb->cflags & CF_USE_ICOUNT) {
+        if (s->base.tb->cflags & CF_USE_ICOUNT) {
             gen_io_end();
             gen_jmp(s, s->pc - s->cs_base);
         }
@@ -6400,14 +6398,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
                      svm_is_rep(prefixes));
         gen_op_mov_v_reg(ot, cpu_T1, R_EAX);
 
-        if (s->tb->cflags & CF_USE_ICOUNT) {
+        if (s->base.tb->cflags & CF_USE_ICOUNT) {
             gen_io_start();
 	}
         tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T0);
         tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T1);
         gen_helper_out_func(ot, cpu_tmp2_i32, cpu_tmp3_i32);
         gen_bpt_io(s, cpu_tmp2_i32, ot);
-        if (s->tb->cflags & CF_USE_ICOUNT) {
+        if (s->base.tb->cflags & CF_USE_ICOUNT) {
             gen_io_end();
             gen_jmp(s, s->pc - s->cs_base);
         }
@@ -6946,7 +6944,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
             gen_update_cc_op(s);
             gen_jmp_im(pc_start - s->cs_base);
             gen_helper_pause(cpu_env, tcg_const_i32(s->pc - pc_start));
-            s->is_jmp = DISAS_TB_JUMP;
+            s->base.is_jmp = DISAS_TB_JUMP;
         }
         break;
     case 0x9b: /* fwait */
@@ -7115,11 +7113,11 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
     case 0x131: /* rdtsc */
         gen_update_cc_op(s);
         gen_jmp_im(pc_start - s->cs_base);
-        if (s->tb->cflags & CF_USE_ICOUNT) {
+        if (s->base.tb->cflags & CF_USE_ICOUNT) {
             gen_io_start();
 	}
         gen_helper_rdtsc(cpu_env);
-        if (s->tb->cflags & CF_USE_ICOUNT) {
+        if (s->base.tb->cflags & CF_USE_ICOUNT) {
             gen_io_end();
             gen_jmp(s, s->pc - s->cs_base);
         }
@@ -7191,7 +7189,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
             gen_update_cc_op(s);
             gen_jmp_im(pc_start - s->cs_base);
             gen_helper_hlt(cpu_env, tcg_const_i32(s->pc - pc_start));
-            s->is_jmp = DISAS_TB_JUMP;
+            s->base.is_jmp = DISAS_TB_JUMP;
         }
         break;
     case 0x100:
@@ -7374,7 +7372,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
             gen_helper_vmrun(cpu_env, tcg_const_i32(s->aflag - 1),
                              tcg_const_i32(s->pc - pc_start));
             tcg_gen_exit_tb(0);
-            s->is_jmp = DISAS_TB_JUMP;
+            s->base.is_jmp = DISAS_TB_JUMP;
             break;
 
         case 0xd9: /* VMMCALL */
@@ -7574,11 +7572,11 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
             }
             gen_update_cc_op(s);
             gen_jmp_im(pc_start - s->cs_base);
-            if (s->tb->cflags & CF_USE_ICOUNT) {
+            if (s->base.tb->cflags & CF_USE_ICOUNT) {
                 gen_io_start();
             }
             gen_helper_rdtscp(cpu_env);
-            if (s->tb->cflags & CF_USE_ICOUNT) {
+            if (s->base.tb->cflags & CF_USE_ICOUNT) {
                 gen_io_end();
                 gen_jmp(s, s->pc - s->cs_base);
             }
@@ -7943,24 +7941,24 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
                 gen_update_cc_op(s);
                 gen_jmp_im(pc_start - s->cs_base);
                 if (b & 2) {
-                    if (s->tb->cflags & CF_USE_ICOUNT) {
+                    if (s->base.tb->cflags & CF_USE_ICOUNT) {
                         gen_io_start();
                     }
                     gen_op_mov_v_reg(ot, cpu_T0, rm);
                     gen_helper_write_crN(cpu_env, tcg_const_i32(reg),
                                          cpu_T0);
-                    if (s->tb->cflags & CF_USE_ICOUNT) {
+                    if (s->base.tb->cflags & CF_USE_ICOUNT) {
                         gen_io_end();
                     }
                     gen_jmp_im(s->pc - s->cs_base);
                     gen_eob(s);
                 } else {
-                    if (s->tb->cflags & CF_USE_ICOUNT) {
+                    if (s->base.tb->cflags & CF_USE_ICOUNT) {
                         gen_io_start();
                     }
                     gen_helper_read_crN(cpu_T0, cpu_env, tcg_const_i32(reg));
                     gen_op_mov_reg_v(ot, rm, cpu_T0);
-                    if (s->tb->cflags & CF_USE_ICOUNT) {
+                    if (s->base.tb->cflags & CF_USE_ICOUNT) {
                         gen_io_end();
                     }
                 }
@@ -8386,15 +8384,13 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
 {
     CPUX86State *env = cs->env_ptr;
     DisasContext dc1, *dc = &dc1;
-    target_ulong pc_ptr;
     uint32_t flags;
-    target_ulong pc_start;
     target_ulong cs_base;
     int num_insns;
     int max_insns;
 
     /* generate intermediate code */
-    pc_start = tb->pc;
+    dc->base.pc_first = tb->pc;
     cs_base = tb->cs_base;
     flags = tb->flags;
 
@@ -8407,11 +8403,11 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
     dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
     dc->iopl = (flags >> IOPL_SHIFT) & 3;
     dc->tf = (flags >> TF_SHIFT) & 1;
-    dc->singlestep_enabled = cs->singlestep_enabled;
+    dc->base.singlestep_enabled = cs->singlestep_enabled;
     dc->cc_op = CC_OP_DYNAMIC;
     dc->cc_op_dirty = false;
     dc->cs_base = cs_base;
-    dc->tb = tb;
+    dc->base.tb = tb;
     dc->popl_esp_hack = 0;
     /* select memory access functions */
     dc->mem_index = 0;
@@ -8461,8 +8457,8 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
     cpu_ptr1 = tcg_temp_new_ptr();
     cpu_cc_srcT = tcg_temp_local_new();
 
-    dc->is_jmp = DISAS_NEXT;
-    pc_ptr = pc_start;
+    dc->base.is_jmp = DISAS_NEXT;
+    dc->base.pc_next = dc->base.pc_first;
     num_insns = 0;
     max_insns = tb->cflags & CF_COUNT_MASK;
     if (max_insns == 0) {
@@ -8474,37 +8470,38 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
 
     gen_tb_start(tb);
     for(;;) {
-        tcg_gen_insn_start(pc_ptr, dc->cc_op);
+        tcg_gen_insn_start(dc->base.pc_next, dc->cc_op);
         num_insns++;
 
         /* If RF is set, suppress an internally generated breakpoint.  */
-        if (unlikely(cpu_breakpoint_test(cs, pc_ptr,
+        if (unlikely(cpu_breakpoint_test(cs, dc->base.pc_next,
                                          tb->flags & HF_RF_MASK
                                          ? BP_GDB : BP_ANY))) {
-            gen_debug(dc, pc_ptr - dc->cs_base);
+            gen_debug(dc, dc->base.pc_next - dc->cs_base);
             /* The address covered by the breakpoint must be included in
                [tb->pc, tb->pc + tb->size) in order to for it to be
                properly cleared -- thus we increment the PC here so that
                the logic setting tb->size below does the right thing.  */
-            pc_ptr += 1;
+            dc->base.pc_next += 1;
             goto done_generating;
         }
         if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
             gen_io_start();
         }
 
-        pc_ptr = disas_insn(env, dc, pc_ptr);
+        dc->base.pc_next = disas_insn(env, dc, dc->base.pc_next);
         /* stop translation if indicated */
-        if (dc->is_jmp)
+        if (dc->base.is_jmp) {
             break;
+        }
         /* if single step mode, we generate only one instruction and
            generate an exception */
         /* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
            the flag and abort the translation to give the irqs a
            change to be happen */
-        if (dc->tf || dc->singlestep_enabled ||
+        if (dc->tf || dc->base.singlestep_enabled ||
             (flags & HF_INHIBIT_IRQ_MASK)) {
-            gen_jmp_im(pc_ptr - dc->cs_base);
+            gen_jmp_im(dc->base.pc_next - dc->cs_base);
             gen_eob(dc);
             break;
         }
@@ -8515,23 +8512,23 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
            because an exception hasn't stopped this code.
          */
         if ((tb->cflags & CF_USE_ICOUNT)
-            && ((pc_ptr & TARGET_PAGE_MASK)
-                != ((pc_ptr + TARGET_MAX_INSN_SIZE - 1) & TARGET_PAGE_MASK)
-                || (pc_ptr & ~TARGET_PAGE_MASK) == 0)) {
-            gen_jmp_im(pc_ptr - dc->cs_base);
+            && ((dc->base.pc_next & TARGET_PAGE_MASK)
+                != ((dc->base.pc_next + TARGET_MAX_INSN_SIZE - 1) & TARGET_PAGE_MASK)
+                || (dc->base.pc_next & ~TARGET_PAGE_MASK) == 0)) {
+            gen_jmp_im(dc->base.pc_next - dc->cs_base);
             gen_eob(dc);
             break;
         }
         /* if too long translation, stop generation too */
         if (tcg_op_buf_full() ||
-            (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32) ||
+            (dc->base.pc_next - dc->base.pc_first) >= (TARGET_PAGE_SIZE - 32) ||
             num_insns >= max_insns) {
-            gen_jmp_im(pc_ptr - dc->cs_base);
+            gen_jmp_im(dc->base.pc_next - dc->cs_base);
             gen_eob(dc);
             break;
         }
         if (singlestep) {
-            gen_jmp_im(pc_ptr - dc->cs_base);
+            gen_jmp_im(dc->base.pc_next - dc->cs_base);
             gen_eob(dc);
             break;
         }
@@ -8543,24 +8540,25 @@ done_generating:
 
 #ifdef DEBUG_DISAS
     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
-        && qemu_log_in_addr_range(pc_start)) {
+        && qemu_log_in_addr_range(dc->base.pc_first)) {
         int disas_flags;
         qemu_log_lock();
         qemu_log("----------------\n");
-        qemu_log("IN: %s\n", lookup_symbol(pc_start));
+        qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
 #ifdef TARGET_X86_64
         if (dc->code64)
             disas_flags = 2;
         else
 #endif
             disas_flags = !dc->code32;
-        log_target_disas(cs, pc_start, pc_ptr - pc_start, disas_flags);
+        log_target_disas(cs, dc->base.pc_first, dc->base.pc_next - dc->base.pc_first,
+                         disas_flags);
         qemu_log("\n");
         qemu_log_unlock();
     }
 #endif
 
-    tb->size = pc_ptr - pc_start;
+    tb->size = dc->base.pc_next - dc->base.pc_first;
     tb->icount = num_insns;
 }
 

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 06/27] target/i386: [tcg] Port to init_disas_context
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (4 preceding siblings ...)
  2017-07-07 12:00 ` [Qemu-devel] [PATCH v12 05/27] target/i386: [tcg] Port to DisasContextBase Lluís Vilanova
@ 2017-07-07 12:04 ` Lluís Vilanova
  2017-07-12  9:20   ` Alex Bennée
  2017-07-07 12:08 ` [Qemu-devel] [PATCH v12 07/27] target/i386: [tcg] Port to insn_start Lluís Vilanova
                   ` (21 subsequent siblings)
  27 siblings, 1 reply; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 12:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Eduardo Habkost

Incrementally paves the way towards using the generic instruction translation
loop.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target/i386/translate.c |   41 +++++++++++++++++++++++------------------
 1 file changed, 23 insertions(+), 18 deletions(-)

diff --git a/target/i386/translate.c b/target/i386/translate.c
index f61f5c7227..7819545e37 100644
--- a/target/i386/translate.c
+++ b/target/i386/translate.c
@@ -8379,20 +8379,12 @@ void tcg_x86_init(void)
     }
 }
 
-/* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
+static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
 {
-    CPUX86State *env = cs->env_ptr;
-    DisasContext dc1, *dc = &dc1;
-    uint32_t flags;
-    target_ulong cs_base;
-    int num_insns;
-    int max_insns;
-
-    /* generate intermediate code */
-    dc->base.pc_first = tb->pc;
-    cs_base = tb->cs_base;
-    flags = tb->flags;
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+    CPUX86State *env = cpu->env_ptr;
+    uint32_t flags = dc->base.tb->flags;
+    target_ulong cs_base = dc->base.tb->cs_base;
 
     dc->pe = (flags >> HF_PE_SHIFT) & 1;
     dc->code32 = (flags >> HF_CS32_SHIFT) & 1;
@@ -8403,11 +8395,9 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
     dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
     dc->iopl = (flags >> IOPL_SHIFT) & 3;
     dc->tf = (flags >> TF_SHIFT) & 1;
-    dc->base.singlestep_enabled = cs->singlestep_enabled;
     dc->cc_op = CC_OP_DYNAMIC;
     dc->cc_op_dirty = false;
     dc->cs_base = cs_base;
-    dc->base.tb = tb;
     dc->popl_esp_hack = 0;
     /* select memory access functions */
     dc->mem_index = 0;
@@ -8425,7 +8415,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
     dc->code64 = (flags >> HF_CS64_SHIFT) & 1;
 #endif
     dc->flags = flags;
-    dc->jmp_opt = !(dc->tf || cs->singlestep_enabled ||
+    dc->jmp_opt = !(dc->tf || dc->base.singlestep_enabled ||
                     (flags & HF_INHIBIT_IRQ_MASK));
     /* Do not optimize repz jumps at all in icount mode, because
        rep movsS instructions are execured with different paths
@@ -8437,7 +8427,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
        record/replay modes and there will always be an
        additional step for ecx=0 when icount is enabled.
      */
-    dc->repz_opt = !dc->jmp_opt && !(tb->cflags & CF_USE_ICOUNT);
+    dc->repz_opt = !dc->jmp_opt && !(dc->base.tb->cflags & CF_USE_ICOUNT);
 #if 0
     /* check addseg logic */
     if (!dc->addseg && (dc->vm86 || !dc->pe || !dc->code32))
@@ -8456,9 +8446,24 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
     cpu_ptr0 = tcg_temp_new_ptr();
     cpu_ptr1 = tcg_temp_new_ptr();
     cpu_cc_srcT = tcg_temp_local_new();
+}
 
+/* generate intermediate code for basic block 'tb'.  */
+void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
+{
+    CPUX86State *env = cs->env_ptr;
+    DisasContext dc1, *dc = &dc1;
+    int num_insns;
+    int max_insns;
+
+    /* generate intermediate code */
+    dc->base.singlestep_enabled = cs->singlestep_enabled;
+    dc->base.tb = tb;
     dc->base.is_jmp = DISAS_NEXT;
+    dc->base.pc_first = tb->pc;
     dc->base.pc_next = dc->base.pc_first;
+    i386_tr_init_disas_context(&dc->base, cs);
+
     num_insns = 0;
     max_insns = tb->cflags & CF_COUNT_MASK;
     if (max_insns == 0) {
@@ -8500,7 +8505,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
            the flag and abort the translation to give the irqs a
            change to be happen */
         if (dc->tf || dc->base.singlestep_enabled ||
-            (flags & HF_INHIBIT_IRQ_MASK)) {
+            (dc->base.tb->flags & HF_INHIBIT_IRQ_MASK)) {
             gen_jmp_im(dc->base.pc_next - dc->cs_base);
             gen_eob(dc);
             break;

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 07/27] target/i386: [tcg] Port to insn_start
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (5 preceding siblings ...)
  2017-07-07 12:04 ` [Qemu-devel] [PATCH v12 06/27] target/i386: [tcg] Port to init_disas_context Lluís Vilanova
@ 2017-07-07 12:08 ` Lluís Vilanova
  2017-07-12  9:21   ` Alex Bennée
  2017-07-07 12:13 ` [Qemu-devel] [PATCH v12 08/27] target/i386: [tcg] Port to breakpoint_check Lluís Vilanova
                   ` (20 subsequent siblings)
  27 siblings, 1 reply; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 12:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Eduardo Habkost

Incrementally paves the way towards using the generic instruction translation
loop.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target/i386/translate.c |    9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/target/i386/translate.c b/target/i386/translate.c
index 7819545e37..a4b9e5628f 100644
--- a/target/i386/translate.c
+++ b/target/i386/translate.c
@@ -8448,6 +8448,13 @@ static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
     cpu_cc_srcT = tcg_temp_local_new();
 }
 
+static void i386_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
+{
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+
+    tcg_gen_insn_start(dc->base.pc_next, dc->cc_op);
+}
+
 /* generate intermediate code for basic block 'tb'.  */
 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
 {
@@ -8475,7 +8482,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
 
     gen_tb_start(tb);
     for(;;) {
-        tcg_gen_insn_start(dc->base.pc_next, dc->cc_op);
+        i386_tr_insn_start(&dc->base, cs);
         num_insns++;
 
         /* If RF is set, suppress an internally generated breakpoint.  */

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 08/27] target/i386: [tcg] Port to breakpoint_check
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (6 preceding siblings ...)
  2017-07-07 12:08 ` [Qemu-devel] [PATCH v12 07/27] target/i386: [tcg] Port to insn_start Lluís Vilanova
@ 2017-07-07 12:13 ` Lluís Vilanova
  2017-07-07 12:17 ` [Qemu-devel] [PATCH v12 09/27] target/i386: [tcg] Port to translate_insn Lluís Vilanova
                   ` (19 subsequent siblings)
  27 siblings, 0 replies; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 12:13 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Eduardo Habkost

Incrementally paves the way towards using the generic instruction translation
loop.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Reviewed-by: Emilio G. Cota <cota@braap.org>
---
 target/i386/translate.c |   58 ++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 47 insertions(+), 11 deletions(-)

diff --git a/target/i386/translate.c b/target/i386/translate.c
index a4b9e5628f..d39e65e5b0 100644
--- a/target/i386/translate.c
+++ b/target/i386/translate.c
@@ -8455,6 +8455,25 @@ static void i386_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
     tcg_gen_insn_start(dc->base.pc_next, dc->cc_op);
 }
 
+static BreakpointCheckType i386_tr_breakpoint_check(
+    DisasContextBase *dcbase, CPUState *cpu, const CPUBreakpoint *bp)
+{
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+    /* If RF is set, suppress an internally generated breakpoint.  */
+    int flags = dc->base.tb->flags & HF_RF_MASK ? BP_GDB : BP_ANY;
+    if (bp->flags & flags) {
+        gen_debug(dc, dc->base.pc_next - dc->cs_base);
+        /* The address covered by the breakpoint must be included in
+           [tb->pc, tb->pc + tb->size) in order to for it to be
+           properly cleared -- thus we increment the PC here so that
+           the logic setting tb->size below does the right thing.  */
+        dc->base.pc_next += 1;
+        return BC_HIT_TB;
+    } else {
+        return BC_MISS;
+    }
+}
+
 /* generate intermediate code for basic block 'tb'.  */
 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
 {
@@ -8485,18 +8504,35 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
         i386_tr_insn_start(&dc->base, cs);
         num_insns++;
 
-        /* If RF is set, suppress an internally generated breakpoint.  */
-        if (unlikely(cpu_breakpoint_test(cs, dc->base.pc_next,
-                                         tb->flags & HF_RF_MASK
-                                         ? BP_GDB : BP_ANY))) {
-            gen_debug(dc, dc->base.pc_next - dc->cs_base);
-            /* The address covered by the breakpoint must be included in
-               [tb->pc, tb->pc + tb->size) in order to for it to be
-               properly cleared -- thus we increment the PC here so that
-               the logic setting tb->size below does the right thing.  */
-            dc->base.pc_next += 1;
-            goto done_generating;
+        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
+            CPUBreakpoint *bp;
+            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
+                if (bp->pc == dc->base.pc_next) {
+                    BreakpointCheckType bp_check =
+                        i386_tr_breakpoint_check(&dc->base, cs, bp);
+                    switch (bp_check) {
+                    case BC_MISS:
+                        /* Target ignored this breakpoint, go to next */
+                        break;
+                    case BC_HIT_INSN:
+                        /* Hit, keep translating */
+                        /*
+                         * TODO: if we're never going to have more than one
+                         *       BP in a single address, we can simply use a
+                         *       bool here.
+                         */
+                        goto done_breakpoints;
+                    case BC_HIT_TB:
+                        /* Hit, end TB */
+                        goto done_generating;
+                    default:
+                        g_assert_not_reached();
+                    }
+                }
+            }
         }
+    done_breakpoints:
+
         if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
             gen_io_start();
         }

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 09/27] target/i386: [tcg] Port to translate_insn
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (7 preceding siblings ...)
  2017-07-07 12:13 ` [Qemu-devel] [PATCH v12 08/27] target/i386: [tcg] Port to breakpoint_check Lluís Vilanova
@ 2017-07-07 12:17 ` Lluís Vilanova
  2017-07-07 12:21 ` [Qemu-devel] [PATCH v12 10/27] target/i386: [tcg] Port to tb_stop Lluís Vilanova
                   ` (18 subsequent siblings)
  27 siblings, 0 replies; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 12:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Eduardo Habkost

Incrementally paves the way towards using the generic instruction translation
loop.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Reviewed-by: Emilio G. Cota <cota@braap.org>
---
 target/i386/translate.c |   72 +++++++++++++++++++++++++++++++----------------
 1 file changed, 48 insertions(+), 24 deletions(-)

diff --git a/target/i386/translate.c b/target/i386/translate.c
index d39e65e5b0..18447b88b2 100644
--- a/target/i386/translate.c
+++ b/target/i386/translate.c
@@ -4419,15 +4419,17 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
 
 /* convert one instruction. s->base.is_jmp is set if the translation must
    be stopped. Return the next pc value */
-static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
-                               target_ulong pc_start)
+static target_ulong disas_insn(DisasContextBase *dcbase, CPUState *cpu)
 {
+    DisasContext *s = container_of(dcbase, DisasContext, base);
+    CPUX86State *env = cpu->env_ptr;
     int b, prefixes;
     int shift;
     TCGMemOp ot, aflag, dflag;
     int modrm, reg, rm, mod, op, opreg, val;
     target_ulong next_eip, tval;
     int rex_w, rex_r;
+    target_ulong pc_start = s->base.pc_next;
 
     s->pc_start = s->pc = pc_start;
     prefixes = 0;
@@ -8474,10 +8476,51 @@ static BreakpointCheckType i386_tr_breakpoint_check(
     }
 }
 
+static target_ulong i386_tr_translate_insn(DisasContextBase *dcbase,
+                                           CPUState *cpu)
+{
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+    target_ulong pc_next = disas_insn(&dc->base, cpu);
+
+    if (dc->base.is_jmp) {
+        return pc_next;
+    }
+
+    if (dc->tf || (dc->base.tb->flags & HF_INHIBIT_IRQ_MASK)) {
+        /* if single step mode, we generate only one instruction and
+           generate an exception */
+        /* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
+           the flag and abort the translation to give the irqs a
+           chance to happen */
+        gen_jmp_im(pc_next - dc->cs_base);
+        gen_eob(dc);
+        dc->base.is_jmp = DISAS_TOO_MANY;
+    } else if ((dc->base.tb->cflags & CF_USE_ICOUNT)
+               && ((dc->base.pc_next & TARGET_PAGE_MASK)
+                   != ((dc->base.pc_next + TARGET_MAX_INSN_SIZE - 1)
+                       & TARGET_PAGE_MASK)
+                   || (dc->base.pc_next & ~TARGET_PAGE_MASK) == 0)) {
+        /* Do not cross the boundary of the pages in icount mode,
+           it can cause an exception. Do it only when boundary is
+           crossed by the first instruction in the block.
+           If current instruction already crossed the bound - it's ok,
+           because an exception hasn't stopped this code.
+         */
+        gen_jmp_im(pc_next - dc->cs_base);
+        gen_eob(dc);
+        dc->base.is_jmp = DISAS_TOO_MANY;
+    } else if ((pc_next - dc->base.pc_first) >= (TARGET_PAGE_SIZE - 32)) {
+        gen_jmp_im(pc_next - dc->cs_base);
+        gen_eob(dc);
+        dc->base.is_jmp = DISAS_TOO_MANY;
+    }
+
+    return pc_next;
+}
+
 /* generate intermediate code for basic block 'tb'.  */
 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
 {
-    CPUX86State *env = cs->env_ptr;
     DisasContext dc1, *dc = &dc1;
     int num_insns;
     int max_insns;
@@ -8537,39 +8580,20 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
             gen_io_start();
         }
 
-        dc->base.pc_next = disas_insn(env, dc, dc->base.pc_next);
+        dc->base.pc_next = i386_tr_translate_insn(&dc->base, cs);
         /* stop translation if indicated */
         if (dc->base.is_jmp) {
             break;
         }
         /* if single step mode, we generate only one instruction and
            generate an exception */
-        /* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
-           the flag and abort the translation to give the irqs a
-           change to be happen */
-        if (dc->tf || dc->base.singlestep_enabled ||
-            (dc->base.tb->flags & HF_INHIBIT_IRQ_MASK)) {
-            gen_jmp_im(dc->base.pc_next - dc->cs_base);
-            gen_eob(dc);
-            break;
-        }
-        /* Do not cross the boundary of the pages in icount mode,
-           it can cause an exception. Do it only when boundary is
-           crossed by the first instruction in the block.
-           If current instruction already crossed the bound - it's ok,
-           because an exception hasn't stopped this code.
-         */
-        if ((tb->cflags & CF_USE_ICOUNT)
-            && ((dc->base.pc_next & TARGET_PAGE_MASK)
-                != ((dc->base.pc_next + TARGET_MAX_INSN_SIZE - 1) & TARGET_PAGE_MASK)
-                || (dc->base.pc_next & ~TARGET_PAGE_MASK) == 0)) {
+        if (dc->base.singlestep_enabled) {
             gen_jmp_im(dc->base.pc_next - dc->cs_base);
             gen_eob(dc);
             break;
         }
         /* if too long translation, stop generation too */
         if (tcg_op_buf_full() ||
-            (dc->base.pc_next - dc->base.pc_first) >= (TARGET_PAGE_SIZE - 32) ||
             num_insns >= max_insns) {
             gen_jmp_im(dc->base.pc_next - dc->cs_base);
             gen_eob(dc);

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 10/27] target/i386: [tcg] Port to tb_stop
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (8 preceding siblings ...)
  2017-07-07 12:17 ` [Qemu-devel] [PATCH v12 09/27] target/i386: [tcg] Port to translate_insn Lluís Vilanova
@ 2017-07-07 12:21 ` Lluís Vilanova
  2017-07-07 12:25 ` [Qemu-devel] [PATCH v12 11/27] target/i386: [tcg] Port to disas_log Lluís Vilanova
                   ` (17 subsequent siblings)
  27 siblings, 0 replies; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 12:21 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Eduardo Habkost

Incrementally paves the way towards using the generic instruction translation
loop.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target/i386/translate.c |   26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/target/i386/translate.c b/target/i386/translate.c
index 18447b88b2..586f5740ec 100644
--- a/target/i386/translate.c
+++ b/target/i386/translate.c
@@ -8492,8 +8492,6 @@ static target_ulong i386_tr_translate_insn(DisasContextBase *dcbase,
         /* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
            the flag and abort the translation to give the irqs a
            chance to happen */
-        gen_jmp_im(pc_next - dc->cs_base);
-        gen_eob(dc);
         dc->base.is_jmp = DISAS_TOO_MANY;
     } else if ((dc->base.tb->cflags & CF_USE_ICOUNT)
                && ((dc->base.pc_next & TARGET_PAGE_MASK)
@@ -8506,18 +8504,24 @@ static target_ulong i386_tr_translate_insn(DisasContextBase *dcbase,
            If current instruction already crossed the bound - it's ok,
            because an exception hasn't stopped this code.
          */
-        gen_jmp_im(pc_next - dc->cs_base);
-        gen_eob(dc);
         dc->base.is_jmp = DISAS_TOO_MANY;
     } else if ((pc_next - dc->base.pc_first) >= (TARGET_PAGE_SIZE - 32)) {
-        gen_jmp_im(pc_next - dc->cs_base);
-        gen_eob(dc);
         dc->base.is_jmp = DISAS_TOO_MANY;
     }
 
     return pc_next;
 }
 
+static void i386_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
+{
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+
+    if (dc->base.is_jmp == DISAS_TOO_MANY) {
+        gen_jmp_im(dc->base.pc_next - dc->cs_base);
+        gen_eob(dc);
+    }
+}
+
 /* generate intermediate code for basic block 'tb'.  */
 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
 {
@@ -8588,23 +8592,21 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
         /* if single step mode, we generate only one instruction and
            generate an exception */
         if (dc->base.singlestep_enabled) {
-            gen_jmp_im(dc->base.pc_next - dc->cs_base);
-            gen_eob(dc);
+            dc->base.is_jmp = DISAS_TOO_MANY;
             break;
         }
         /* if too long translation, stop generation too */
         if (tcg_op_buf_full() ||
             num_insns >= max_insns) {
-            gen_jmp_im(dc->base.pc_next - dc->cs_base);
-            gen_eob(dc);
+            dc->base.is_jmp = DISAS_TOO_MANY;
             break;
         }
         if (singlestep) {
-            gen_jmp_im(dc->base.pc_next - dc->cs_base);
-            gen_eob(dc);
+            dc->base.is_jmp = DISAS_TOO_MANY;
             break;
         }
     }
+    i386_tr_tb_stop(&dc->base, cs);
     if (tb->cflags & CF_LAST_IO)
         gen_io_end();
 done_generating:

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 11/27] target/i386: [tcg] Port to disas_log
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (9 preceding siblings ...)
  2017-07-07 12:21 ` [Qemu-devel] [PATCH v12 10/27] target/i386: [tcg] Port to tb_stop Lluís Vilanova
@ 2017-07-07 12:25 ` Lluís Vilanova
  2017-07-07 12:29 ` [Qemu-devel] [PATCH v12 12/27] target/i386: [tcg] Port to generic translation framework Lluís Vilanova
                   ` (16 subsequent siblings)
  27 siblings, 0 replies; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 12:25 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Eduardo Habkost

Incrementally paves the way towards using the generic instruction translation
loop.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: Emilio G. Cota <cota@braap.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target/i386/translate.c |   28 ++++++++++++++++++----------
 1 file changed, 18 insertions(+), 10 deletions(-)

diff --git a/target/i386/translate.c b/target/i386/translate.c
index 586f5740ec..94b09e0f6d 100644
--- a/target/i386/translate.c
+++ b/target/i386/translate.c
@@ -8522,6 +8522,23 @@ static void i386_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
     }
 }
 
+static void i386_tr_disas_log(const DisasContextBase *dcbase,
+                              CPUState *cpu)
+{
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+    int disas_flags = !dc->code32;
+
+    qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
+#ifdef TARGET_X86_64
+    if (dc->code64) {
+        disas_flags = 2;
+    }
+#endif
+    log_target_disas(cpu, dc->base.pc_first, dc->base.pc_next - dc->base.pc_first,
+                     disas_flags);
+
+}
+
 /* generate intermediate code for basic block 'tb'.  */
 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
 {
@@ -8615,18 +8632,9 @@ done_generating:
 #ifdef DEBUG_DISAS
     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
         && qemu_log_in_addr_range(dc->base.pc_first)) {
-        int disas_flags;
         qemu_log_lock();
         qemu_log("----------------\n");
-        qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
-#ifdef TARGET_X86_64
-        if (dc->code64)
-            disas_flags = 2;
-        else
-#endif
-            disas_flags = !dc->code32;
-        log_target_disas(cs, dc->base.pc_first, dc->base.pc_next - dc->base.pc_first,
-                         disas_flags);
+        i386_tr_disas_log(&dc->base, cs);
         qemu_log("\n");
         qemu_log_unlock();
     }

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 12/27] target/i386: [tcg] Port to generic translation framework
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (10 preceding siblings ...)
  2017-07-07 12:25 ` [Qemu-devel] [PATCH v12 11/27] target/i386: [tcg] Port to disas_log Lluís Vilanova
@ 2017-07-07 12:29 ` Lluís Vilanova
  2017-07-07 12:33 ` [Qemu-devel] [PATCH v12 13/27] target/arm: [tcg] Port to DisasContextBase Lluís Vilanova
                   ` (15 subsequent siblings)
  27 siblings, 0 replies; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 12:29 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Eduardo Habkost

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Reviewed-by: Emilio G. Cota <cota@braap.org>
Tested-by: Emilio G. Cota <cota@braap.org>
---
 target/i386/translate.c |  121 +++++++----------------------------------------
 1 file changed, 19 insertions(+), 102 deletions(-)

diff --git a/target/i386/translate.c b/target/i386/translate.c
index 94b09e0f6d..22a22aea8d 100644
--- a/target/i386/translate.c
+++ b/target/i386/translate.c
@@ -8450,6 +8450,10 @@ static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
     cpu_cc_srcT = tcg_temp_local_new();
 }
 
+static void i386_tr_tb_start(DisasContextBase *db, CPUState *cpu)
+{
+}
+
 static void i386_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
 {
     DisasContext *dc = container_of(dcbase, DisasContext, base);
@@ -8468,7 +8472,7 @@ static BreakpointCheckType i386_tr_breakpoint_check(
         /* The address covered by the breakpoint must be included in
            [tb->pc, tb->pc + tb->size) in order to for it to be
            properly cleared -- thus we increment the PC here so that
-           the logic setting tb->size below does the right thing.  */
+           the generic logic setting tb->size later does the right thing.  */
         dc->base.pc_next += 1;
         return BC_HIT_TB;
     } else {
@@ -8539,109 +8543,22 @@ static void i386_tr_disas_log(const DisasContextBase *dcbase,
 
 }
 
-/* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
-{
-    DisasContext dc1, *dc = &dc1;
-    int num_insns;
-    int max_insns;
-
-    /* generate intermediate code */
-    dc->base.singlestep_enabled = cs->singlestep_enabled;
-    dc->base.tb = tb;
-    dc->base.is_jmp = DISAS_NEXT;
-    dc->base.pc_first = tb->pc;
-    dc->base.pc_next = dc->base.pc_first;
-    i386_tr_init_disas_context(&dc->base, cs);
-
-    num_insns = 0;
-    max_insns = tb->cflags & CF_COUNT_MASK;
-    if (max_insns == 0) {
-        max_insns = CF_COUNT_MASK;
-    }
-    if (max_insns > TCG_MAX_INSNS) {
-        max_insns = TCG_MAX_INSNS;
-    }
-
-    gen_tb_start(tb);
-    for(;;) {
-        i386_tr_insn_start(&dc->base, cs);
-        num_insns++;
-
-        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
-            CPUBreakpoint *bp;
-            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
-                if (bp->pc == dc->base.pc_next) {
-                    BreakpointCheckType bp_check =
-                        i386_tr_breakpoint_check(&dc->base, cs, bp);
-                    switch (bp_check) {
-                    case BC_MISS:
-                        /* Target ignored this breakpoint, go to next */
-                        break;
-                    case BC_HIT_INSN:
-                        /* Hit, keep translating */
-                        /*
-                         * TODO: if we're never going to have more than one
-                         *       BP in a single address, we can simply use a
-                         *       bool here.
-                         */
-                        goto done_breakpoints;
-                    case BC_HIT_TB:
-                        /* Hit, end TB */
-                        goto done_generating;
-                    default:
-                        g_assert_not_reached();
-                    }
-                }
-            }
-        }
-    done_breakpoints:
-
-        if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
-            gen_io_start();
-        }
-
-        dc->base.pc_next = i386_tr_translate_insn(&dc->base, cs);
-        /* stop translation if indicated */
-        if (dc->base.is_jmp) {
-            break;
-        }
-        /* if single step mode, we generate only one instruction and
-           generate an exception */
-        if (dc->base.singlestep_enabled) {
-            dc->base.is_jmp = DISAS_TOO_MANY;
-            break;
-        }
-        /* if too long translation, stop generation too */
-        if (tcg_op_buf_full() ||
-            num_insns >= max_insns) {
-            dc->base.is_jmp = DISAS_TOO_MANY;
-            break;
-        }
-        if (singlestep) {
-            dc->base.is_jmp = DISAS_TOO_MANY;
-            break;
-        }
-    }
-    i386_tr_tb_stop(&dc->base, cs);
-    if (tb->cflags & CF_LAST_IO)
-        gen_io_end();
-done_generating:
-    gen_tb_end(tb, num_insns);
+static const TranslatorOps i386_tr_ops = {
+    .init_disas_context = i386_tr_init_disas_context,
+    .tb_start           = i386_tr_tb_start,
+    .insn_start         = i386_tr_insn_start,
+    .breakpoint_check   = i386_tr_breakpoint_check,
+    .translate_insn     = i386_tr_translate_insn,
+    .tb_stop            = i386_tr_tb_stop,
+    .disas_log          = i386_tr_disas_log,
+};
 
-#ifdef DEBUG_DISAS
-    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
-        && qemu_log_in_addr_range(dc->base.pc_first)) {
-        qemu_log_lock();
-        qemu_log("----------------\n");
-        i386_tr_disas_log(&dc->base, cs);
-        qemu_log("\n");
-        qemu_log_unlock();
-    }
-#endif
+/* generate intermediate code for basic block 'tb'.  */
+void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
+{
+    DisasContext dc;
 
-    tb->size = dc->base.pc_next - dc->base.pc_first;
-    tb->icount = num_insns;
+    translator_loop(&i386_tr_ops, &dc.base, cpu, tb);
 }
 
 void restore_state_to_opc(CPUX86State *env, TranslationBlock *tb,

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 13/27] target/arm: [tcg] Port to DisasContextBase
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (11 preceding siblings ...)
  2017-07-07 12:29 ` [Qemu-devel] [PATCH v12 12/27] target/i386: [tcg] Port to generic translation framework Lluís Vilanova
@ 2017-07-07 12:33 ` Lluís Vilanova
  2017-07-12  9:25   ` Alex Bennée
  2017-07-07 12:37 ` [Qemu-devel] [PATCH v12 14/27] target/arm: [tcg] Port to init_disas_context Lluís Vilanova
                   ` (14 subsequent siblings)
  27 siblings, 1 reply; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 12:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Peter Maydell, open list:ARM

Incrementally paves the way towards using the generic instruction translation
loop.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target/arm/translate-a64.c |  119 ++++++++++++++++++++++----------------------
 target/arm/translate.c     |  114 +++++++++++++++++++++---------------------
 target/arm/translate.h     |   11 ++--
 3 files changed, 121 insertions(+), 123 deletions(-)

diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index f9bd1a9679..4270ac3847 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -304,7 +304,7 @@ static void gen_exception_internal_insn(DisasContext *s, int offset, int excp)
 {
     gen_a64_set_pc_im(s->pc - offset);
     gen_exception_internal(excp);
-    s->is_jmp = DISAS_EXC;
+    s->base.is_jmp = DISAS_EXC;
 }
 
 static void gen_exception_insn(DisasContext *s, int offset, int excp,
@@ -312,7 +312,7 @@ static void gen_exception_insn(DisasContext *s, int offset, int excp,
 {
     gen_a64_set_pc_im(s->pc - offset);
     gen_exception(excp, syndrome, target_el);
-    s->is_jmp = DISAS_EXC;
+    s->base.is_jmp = DISAS_EXC;
 }
 
 static void gen_ss_advance(DisasContext *s)
@@ -340,7 +340,7 @@ static void gen_step_complete_exception(DisasContext *s)
     gen_ss_advance(s);
     gen_exception(EXCP_UDEF, syn_swstep(s->ss_same_el, 1, s->is_ldex),
                   default_exception_el(s));
-    s->is_jmp = DISAS_EXC;
+    s->base.is_jmp = DISAS_EXC;
 }
 
 static inline bool use_goto_tb(DisasContext *s, int n, uint64_t dest)
@@ -348,13 +348,13 @@ static inline bool use_goto_tb(DisasContext *s, int n, uint64_t dest)
     /* No direct tb linking with singlestep (either QEMU's or the ARM
      * debug architecture kind) or deterministic io
      */
-    if (s->singlestep_enabled || s->ss_active || (s->tb->cflags & CF_LAST_IO)) {
+    if (s->base.singlestep_enabled || s->ss_active || (s->base.tb->cflags & CF_LAST_IO)) {
         return false;
     }
 
 #ifndef CONFIG_USER_ONLY
     /* Only link tbs from inside the same guest page */
-    if ((s->tb->pc & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
+    if ((s->base.tb->pc & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
         return false;
     }
 #endif
@@ -366,21 +366,21 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
 {
     TranslationBlock *tb;
 
-    tb = s->tb;
+    tb = s->base.tb;
     if (use_goto_tb(s, n, dest)) {
         tcg_gen_goto_tb(n);
         gen_a64_set_pc_im(dest);
         tcg_gen_exit_tb((intptr_t)tb + n);
-        s->is_jmp = DISAS_TB_JUMP;
+        s->base.is_jmp = DISAS_TB_JUMP;
     } else {
         gen_a64_set_pc_im(dest);
         if (s->ss_active) {
             gen_step_complete_exception(s);
-        } else if (s->singlestep_enabled) {
+        } else if (s->base.singlestep_enabled) {
             gen_exception_internal(EXCP_DEBUG);
         } else {
             tcg_gen_lookup_and_goto_ptr(cpu_pc);
-            s->is_jmp = DISAS_TB_JUMP;
+            s->base.is_jmp = DISAS_TB_JUMP;
         }
     }
 }
@@ -1331,16 +1331,16 @@ static void handle_hint(DisasContext *s, uint32_t insn,
     case 0: /* NOP */
         return;
     case 3: /* WFI */
-        s->is_jmp = DISAS_WFI;
+        s->base.is_jmp = DISAS_WFI;
         return;
     case 1: /* YIELD */
         if (!parallel_cpus) {
-            s->is_jmp = DISAS_YIELD;
+            s->base.is_jmp = DISAS_YIELD;
         }
         return;
     case 2: /* WFE */
         if (!parallel_cpus) {
-            s->is_jmp = DISAS_WFE;
+            s->base.is_jmp = DISAS_WFE;
         }
         return;
     case 4: /* SEV */
@@ -1393,7 +1393,7 @@ static void handle_sync(DisasContext *s, uint32_t insn,
          * a self-modified code correctly and also to take
          * any pending interrupts immediately.
          */
-        s->is_jmp = DISAS_UPDATE;
+        s->base.is_jmp = DISAS_UPDATE;
         return;
     default:
         unallocated_encoding(s);
@@ -1424,7 +1424,7 @@ static void handle_msr_i(DisasContext *s, uint32_t insn,
         tcg_temp_free_i32(tcg_op);
         /* For DAIFClear, exit the cpu loop to re-evaluate pending IRQs.  */
         gen_a64_set_pc_im(s->pc);
-        s->is_jmp = (op == 0x1f ? DISAS_EXIT : DISAS_JUMP);
+        s->base.is_jmp = (op == 0x1f ? DISAS_EXIT : DISAS_JUMP);
         break;
     }
     default:
@@ -1559,7 +1559,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
         break;
     }
 
-    if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
+    if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
         gen_io_start();
     }
 
@@ -1590,16 +1590,16 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
         }
     }
 
-    if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
+    if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
         /* I/O operations must end the TB here (whether read or write) */
         gen_io_end();
-        s->is_jmp = DISAS_UPDATE;
+        s->base.is_jmp = DISAS_UPDATE;
     } else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {
         /* We default to ending the TB on a coprocessor register write,
          * but allow this to be suppressed by the register definition
          * (usually only necessary to work around guest bugs).
          */
-        s->is_jmp = DISAS_UPDATE;
+        s->base.is_jmp = DISAS_UPDATE;
     }
 }
 
@@ -1788,7 +1788,7 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
             return;
         }
         gen_helper_exception_return(cpu_env);
-        s->is_jmp = DISAS_JUMP;
+        s->base.is_jmp = DISAS_JUMP;
         return;
     case 5: /* DRPS */
         if (rn != 0x1f) {
@@ -1802,7 +1802,7 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
         return;
     }
 
-    s->is_jmp = DISAS_JUMP;
+    s->base.is_jmp = DISAS_JUMP;
 }
 
 /* C3.2 Branches, exception generating and system instructions */
@@ -11190,23 +11190,23 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
     free_tmp_a64(s);
 }
 
-void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
+void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
+                               TranslationBlock *tb)
 {
     CPUARMState *env = cs->env_ptr;
     ARMCPU *cpu = arm_env_get_cpu(env);
-    DisasContext dc1, *dc = &dc1;
-    target_ulong pc_start;
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
     target_ulong next_page_start;
-    int num_insns;
     int max_insns;
 
-    pc_start = tb->pc;
+    dc->base.tb = tb;
+    dc->base.pc_first = dc->base.tb->pc;
+    dc->base.pc_next = dc->base.pc_first;
+    dc->base.is_jmp = DISAS_NEXT;
+    dc->base.num_insns = 0;
+    dc->base.singlestep_enabled = cs->singlestep_enabled;
 
-    dc->tb = tb;
-
-    dc->is_jmp = DISAS_NEXT;
-    dc->pc = pc_start;
-    dc->singlestep_enabled = cs->singlestep_enabled;
+    dc->pc = dc->base.pc_first;
     dc->condjmp = 0;
 
     dc->aarch64 = 1;
@@ -11217,17 +11217,17 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
                                !arm_el_is_aa64(env, 3);
     dc->thumb = 0;
     dc->sctlr_b = 0;
-    dc->be_data = ARM_TBFLAG_BE_DATA(tb->flags) ? MO_BE : MO_LE;
+    dc->be_data = ARM_TBFLAG_BE_DATA(dc->base.tb->flags) ? MO_BE : MO_LE;
     dc->condexec_mask = 0;
     dc->condexec_cond = 0;
-    dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(tb->flags));
-    dc->tbi0 = ARM_TBFLAG_TBI0(tb->flags);
-    dc->tbi1 = ARM_TBFLAG_TBI1(tb->flags);
+    dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(dc->base.tb->flags));
+    dc->tbi0 = ARM_TBFLAG_TBI0(dc->base.tb->flags);
+    dc->tbi1 = ARM_TBFLAG_TBI1(dc->base.tb->flags);
     dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
 #if !defined(CONFIG_USER_ONLY)
     dc->user = (dc->current_el == 0);
 #endif
-    dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(tb->flags);
+    dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(dc->base.tb->flags);
     dc->vec_len = 0;
     dc->vec_stride = 0;
     dc->cp_regs = cpu->cp_regs;
@@ -11248,16 +11248,15 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
      *   emit code to generate a software step exception
      *   end the TB
      */
-    dc->ss_active = ARM_TBFLAG_SS_ACTIVE(tb->flags);
-    dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(tb->flags);
+    dc->ss_active = ARM_TBFLAG_SS_ACTIVE(dc->base.tb->flags);
+    dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(dc->base.tb->flags);
     dc->is_ldex = false;
     dc->ss_same_el = (arm_debug_target_el(env) == dc->current_el);
 
     init_tmp_a64_array(dc);
 
-    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
-    num_insns = 0;
-    max_insns = tb->cflags & CF_COUNT_MASK;
+    next_page_start = (dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+    max_insns = dc->base.tb->cflags & CF_COUNT_MASK;
     if (max_insns == 0) {
         max_insns = CF_COUNT_MASK;
     }
@@ -11270,9 +11269,9 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
     tcg_clear_temp_count();
 
     do {
+        dc->base.num_insns++;
         dc->insn_start_idx = tcg_op_buf_count();
         tcg_gen_insn_start(dc->pc, 0, 0);
-        num_insns++;
 
         if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
             CPUBreakpoint *bp;
@@ -11282,14 +11281,14 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
                         gen_a64_set_pc_im(dc->pc);
                         gen_helper_check_breakpoints(cpu_env);
                         /* End the TB early; it likely won't be executed */
-                        dc->is_jmp = DISAS_UPDATE;
+                        dc->base.is_jmp = DISAS_UPDATE;
                     } else {
                         gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
                         /* The address covered by the breakpoint must be
-                           included in [tb->pc, tb->pc + tb->size) in order
+                           included in [dc->base.tb->pc, dc->base.tb->pc + dc->base.tb->size) in order
                            to for it to be properly cleared -- thus we
                            increment the PC here so that the logic setting
-                           tb->size below does the right thing.  */
+                           dc->base.tb->size below does the right thing.  */
                         dc->pc += 4;
                         goto done_generating;
                     }
@@ -11298,7 +11297,7 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
             }
         }
 
-        if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
+        if (dc->base.num_insns == max_insns && (dc->base.tb->cflags & CF_LAST_IO)) {
             gen_io_start();
         }
 
@@ -11313,10 +11312,10 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
              * "did not step an insn" case, and so the syndrome ISV and EX
              * bits should be zero.
              */
-            assert(num_insns == 1);
+            assert(dc->base.num_insns == 1);
             gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
                           default_exception_el(dc));
-            dc->is_jmp = DISAS_EXC;
+            dc->base.is_jmp = DISAS_EXC;
             break;
         }
 
@@ -11332,26 +11331,26 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
          * Also stop translation when a page boundary is reached.  This
          * ensures prefetch aborts occur at the right place.
          */
-    } while (!dc->is_jmp && !tcg_op_buf_full() &&
+    } while (!dc->base.is_jmp && !tcg_op_buf_full() &&
              !cs->singlestep_enabled &&
              !singlestep &&
              !dc->ss_active &&
              dc->pc < next_page_start &&
-             num_insns < max_insns);
+             dc->base.num_insns < max_insns);
 
-    if (tb->cflags & CF_LAST_IO) {
+    if (dc->base.tb->cflags & CF_LAST_IO) {
         gen_io_end();
     }
 
     if (unlikely(cs->singlestep_enabled || dc->ss_active)
-        && dc->is_jmp != DISAS_EXC) {
+        && dc->base.is_jmp != DISAS_EXC) {
         /* Note that this means single stepping WFI doesn't halt the CPU.
          * For conditional branch insns this is harmless unreachable code as
          * gen_goto_tb() has already handled emitting the debug exception
          * (and thus a tb-jump is not possible when singlestepping).
          */
-        assert(dc->is_jmp != DISAS_TB_JUMP);
-        if (dc->is_jmp != DISAS_JUMP) {
+        assert(dc->base.is_jmp != DISAS_TB_JUMP);
+        if (dc->base.is_jmp != DISAS_JUMP) {
             gen_a64_set_pc_im(dc->pc);
         }
         if (cs->singlestep_enabled) {
@@ -11360,7 +11359,7 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
             gen_step_complete_exception(dc);
         }
     } else {
-        switch (dc->is_jmp) {
+        switch (dc->base.is_jmp) {
         case DISAS_NEXT:
             gen_goto_tb(dc, 1, dc->pc);
             break;
@@ -11401,20 +11400,20 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
     }
 
 done_generating:
-    gen_tb_end(tb, num_insns);
+    gen_tb_end(tb, dc->base.num_insns);
 
 #ifdef DEBUG_DISAS
     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) &&
-        qemu_log_in_addr_range(pc_start)) {
+        qemu_log_in_addr_range(dc->base.pc_first)) {
         qemu_log_lock();
         qemu_log("----------------\n");
-        qemu_log("IN: %s\n", lookup_symbol(pc_start));
-        log_target_disas(cs, pc_start, dc->pc - pc_start,
+        qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
+        log_target_disas(cs, dc->base.pc_first, dc->pc - dc->base.pc_first,
                          4 | (bswap_code(dc->sctlr_b) ? 2 : 0));
         qemu_log("\n");
         qemu_log_unlock();
     }
 #endif
-    tb->size = dc->pc - pc_start;
-    tb->icount = num_insns;
+    dc->base.tb->size = dc->pc - dc->base.pc_first;
+    dc->base.tb->icount = dc->base.num_insns;
 }
diff --git a/target/arm/translate.c b/target/arm/translate.c
index e80cc357c1..15b4fcb417 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -224,7 +224,7 @@ static void store_reg(DisasContext *s, int reg, TCGv_i32 var)
          * We choose to ignore [1:0] in ARM mode for all architecture versions.
          */
         tcg_gen_andi_i32(var, var, s->thumb ? ~1 : ~3);
-        s->is_jmp = DISAS_JUMP;
+        s->base.is_jmp = DISAS_JUMP;
     }
     tcg_gen_mov_i32(cpu_R[reg], var);
     tcg_temp_free_i32(var);
@@ -297,7 +297,7 @@ static void gen_step_complete_exception(DisasContext *s)
     gen_ss_advance(s);
     gen_exception(EXCP_UDEF, syn_swstep(s->ss_same_el, 1, s->is_ldex),
                   default_exception_el(s));
-    s->is_jmp = DISAS_EXC;
+    s->base.is_jmp = DISAS_EXC;
 }
 
 static void gen_singlestep_exception(DisasContext *s)
@@ -321,7 +321,7 @@ static inline bool is_singlestepping(DisasContext *s)
      * misnamed as it only means "one instruction per TB" and doesn't
      * affect the code we generate.
      */
-    return s->singlestep_enabled || s->ss_active;
+    return s->base.singlestep_enabled || s->ss_active;
 }
 
 static void gen_smul_dual(TCGv_i32 a, TCGv_i32 b)
@@ -928,7 +928,7 @@ static inline void gen_bx_im(DisasContext *s, uint32_t addr)
 {
     TCGv_i32 tmp;
 
-    s->is_jmp = DISAS_JUMP;
+    s->base.is_jmp = DISAS_JUMP;
     if (s->thumb != (addr & 1)) {
         tmp = tcg_temp_new_i32();
         tcg_gen_movi_i32(tmp, addr & 1);
@@ -941,7 +941,7 @@ static inline void gen_bx_im(DisasContext *s, uint32_t addr)
 /* Set PC and Thumb state from var.  var is marked as dead.  */
 static inline void gen_bx(DisasContext *s, TCGv_i32 var)
 {
-    s->is_jmp = DISAS_JUMP;
+    s->base.is_jmp = DISAS_JUMP;
     tcg_gen_andi_i32(cpu_R[15], var, ~1);
     tcg_gen_andi_i32(var, var, 1);
     store_cpu_field(var, thumb);
@@ -955,11 +955,11 @@ static inline void gen_bx(DisasContext *s, TCGv_i32 var)
 static inline void gen_bx_excret(DisasContext *s, TCGv_i32 var)
 {
     /* Generate the same code here as for a simple bx, but flag via
-     * s->is_jmp that we need to do the rest of the work later.
+     * s->base.is_jmp that we need to do the rest of the work later.
      */
     gen_bx(s, var);
     if (s->v7m_handler_mode && arm_dc_feature(s, ARM_FEATURE_M)) {
-        s->is_jmp = DISAS_BX_EXCRET;
+        s->base.is_jmp = DISAS_BX_EXCRET;
     }
 }
 
@@ -1159,7 +1159,7 @@ static inline void gen_hvc(DisasContext *s, int imm16)
      */
     s->svc_imm = imm16;
     gen_set_pc_im(s, s->pc);
-    s->is_jmp = DISAS_HVC;
+    s->base.is_jmp = DISAS_HVC;
 }
 
 static inline void gen_smc(DisasContext *s)
@@ -1174,7 +1174,7 @@ static inline void gen_smc(DisasContext *s)
     gen_helper_pre_smc(cpu_env, tmp);
     tcg_temp_free_i32(tmp);
     gen_set_pc_im(s, s->pc);
-    s->is_jmp = DISAS_SMC;
+    s->base.is_jmp = DISAS_SMC;
 }
 
 static void gen_exception_internal_insn(DisasContext *s, int offset, int excp)
@@ -1182,7 +1182,7 @@ static void gen_exception_internal_insn(DisasContext *s, int offset, int excp)
     gen_set_condexec(s);
     gen_set_pc_im(s, s->pc - offset);
     gen_exception_internal(excp);
-    s->is_jmp = DISAS_EXC;
+    s->base.is_jmp = DISAS_EXC;
 }
 
 static void gen_exception_insn(DisasContext *s, int offset, int excp,
@@ -1191,14 +1191,14 @@ static void gen_exception_insn(DisasContext *s, int offset, int excp,
     gen_set_condexec(s);
     gen_set_pc_im(s, s->pc - offset);
     gen_exception(excp, syn, target_el);
-    s->is_jmp = DISAS_EXC;
+    s->base.is_jmp = DISAS_EXC;
 }
 
 /* Force a TB lookup after an instruction that changes the CPU state.  */
 static inline void gen_lookup_tb(DisasContext *s)
 {
     tcg_gen_movi_i32(cpu_R[15], s->pc & ~1);
-    s->is_jmp = DISAS_EXIT;
+    s->base.is_jmp = DISAS_EXIT;
 }
 
 static inline void gen_hlt(DisasContext *s, int imm)
@@ -4143,7 +4143,7 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
 static inline bool use_goto_tb(DisasContext *s, target_ulong dest)
 {
 #ifndef CONFIG_USER_ONLY
-    return (s->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) ||
+    return (s->base.tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) ||
            ((s->pc - 1) & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
 #else
     return true;
@@ -4163,7 +4163,7 @@ static void gen_goto_tb(DisasContext *s, int n, target_ulong dest)
     if (use_goto_tb(s, dest)) {
         tcg_gen_goto_tb(n);
         gen_set_pc_im(s, dest);
-        tcg_gen_exit_tb((uintptr_t)s->tb + n);
+        tcg_gen_exit_tb((uintptr_t)s->base.tb + n);
     } else {
         gen_set_pc_im(s, dest);
         gen_goto_ptr();
@@ -4179,7 +4179,7 @@ static inline void gen_jmp (DisasContext *s, uint32_t dest)
         gen_bx_im(s, dest);
     } else {
         gen_goto_tb(s, 0, dest);
-        s->is_jmp = DISAS_TB_JUMP;
+        s->base.is_jmp = DISAS_TB_JUMP;
     }
 }
 
@@ -4430,7 +4430,7 @@ static void gen_msr_banked(DisasContext *s, int r, int sysm, int rn)
     tcg_temp_free_i32(tcg_tgtmode);
     tcg_temp_free_i32(tcg_regno);
     tcg_temp_free_i32(tcg_reg);
-    s->is_jmp = DISAS_UPDATE;
+    s->base.is_jmp = DISAS_UPDATE;
 }
 
 static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn)
@@ -4452,7 +4452,7 @@ static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn)
     tcg_temp_free_i32(tcg_tgtmode);
     tcg_temp_free_i32(tcg_regno);
     store_reg(s, rn, tcg_reg);
-    s->is_jmp = DISAS_UPDATE;
+    s->base.is_jmp = DISAS_UPDATE;
 }
 
 /* Store value to PC as for an exception return (ie don't
@@ -4475,7 +4475,7 @@ static void gen_rfe(DisasContext *s, TCGv_i32 pc, TCGv_i32 cpsr)
      */
     gen_helper_cpsr_write_eret(cpu_env, cpsr);
     tcg_temp_free_i32(cpsr);
-    s->is_jmp = DISAS_JUMP;
+    s->base.is_jmp = DISAS_JUMP;
 }
 
 /* Generate an old-style exception return. Marks pc as dead. */
@@ -4498,17 +4498,17 @@ static void gen_nop_hint(DisasContext *s, int val)
     case 1: /* yield */
         if (!parallel_cpus) {
             gen_set_pc_im(s, s->pc);
-            s->is_jmp = DISAS_YIELD;
+            s->base.is_jmp = DISAS_YIELD;
         }
         break;
     case 3: /* wfi */
         gen_set_pc_im(s, s->pc);
-        s->is_jmp = DISAS_WFI;
+        s->base.is_jmp = DISAS_WFI;
         break;
     case 2: /* wfe */
         if (!parallel_cpus) {
             gen_set_pc_im(s, s->pc);
-            s->is_jmp = DISAS_WFE;
+            s->base.is_jmp = DISAS_WFE;
         }
         break;
     case 4: /* sev */
@@ -7647,13 +7647,13 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
                 return 1;
             }
             gen_set_pc_im(s, s->pc);
-            s->is_jmp = DISAS_WFI;
+            s->base.is_jmp = DISAS_WFI;
             return 0;
         default:
             break;
         }
 
-        if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
+        if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
             gen_io_start();
         }
 
@@ -7744,7 +7744,7 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
             }
         }
 
-        if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
+        if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
             /* I/O operations must end the TB here (whether read or write) */
             gen_io_end();
             gen_lookup_tb(s);
@@ -8058,7 +8058,7 @@ static void gen_srs(DisasContext *s,
         tcg_temp_free_i32(tmp);
     }
     tcg_temp_free_i32(addr);
-    s->is_jmp = DISAS_UPDATE;
+    s->base.is_jmp = DISAS_UPDATE;
 }
 
 static void disas_arm_insn(DisasContext *s, unsigned int insn)
@@ -8146,7 +8146,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
             /* setend */
             if (((insn >> 9) & 1) != !!(s->be_data == MO_BE)) {
                 gen_helper_setend(cpu_env);
-                s->is_jmp = DISAS_UPDATE;
+                s->base.is_jmp = DISAS_UPDATE;
             }
             return;
         } else if ((insn & 0x0fffff00) == 0x057ff000) {
@@ -9519,7 +9519,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
                     tmp = load_cpu_field(spsr);
                     gen_helper_cpsr_write_eret(cpu_env, tmp);
                     tcg_temp_free_i32(tmp);
-                    s->is_jmp = DISAS_JUMP;
+                    s->base.is_jmp = DISAS_JUMP;
                 }
             }
             break;
@@ -9557,7 +9557,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
             /* swi */
             gen_set_pc_im(s, s->pc);
             s->svc_imm = extract32(insn, 0, 24);
-            s->is_jmp = DISAS_SWI;
+            s->base.is_jmp = DISAS_SWI;
             break;
         default:
         illegal_op:
@@ -11619,7 +11619,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
                 ARCH(6);
                 if (((insn >> 3) & 1) != !!(s->be_data == MO_BE)) {
                     gen_helper_setend(cpu_env);
-                    s->is_jmp = DISAS_UPDATE;
+                    s->base.is_jmp = DISAS_UPDATE;
                 }
                 break;
             case 3:
@@ -11713,7 +11713,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
             /* swi */
             gen_set_pc_im(s, s->pc);
             s->svc_imm = extract32(insn, 0, 8);
-            s->is_jmp = DISAS_SWI;
+            s->base.is_jmp = DISAS_SWI;
             break;
         }
         /* generate a conditional jump to next instruction */
@@ -11792,9 +11792,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
     CPUARMState *env = cs->env_ptr;
     ARMCPU *cpu = arm_env_get_cpu(env);
     DisasContext dc1, *dc = &dc1;
-    target_ulong pc_start;
     target_ulong next_page_start;
-    int num_insns;
     int max_insns;
     bool end_of_page;
 
@@ -11804,17 +11802,18 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
      * the A32/T32 complexity to do with conditional execution/IT blocks/etc.
      */
     if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
-        gen_intermediate_code_a64(cs, tb);
+        gen_intermediate_code_a64(&dc->base, cs, tb);
         return;
     }
 
-    pc_start = tb->pc;
+    dc->base.tb = tb;
+    dc->base.pc_first = tb->pc;
+    dc->base.pc_next = dc->base.pc_first;
+    dc->base.is_jmp = DISAS_NEXT;
+    dc->base.num_insns = 0;
+    dc->base.singlestep_enabled = cs->singlestep_enabled;
 
-    dc->tb = tb;
-
-    dc->is_jmp = DISAS_NEXT;
-    dc->pc = pc_start;
-    dc->singlestep_enabled = cs->singlestep_enabled;
+    dc->pc = dc->base.pc_first;
     dc->condjmp = 0;
 
     dc->aarch64 = 0;
@@ -11871,8 +11870,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
     cpu_V1 = cpu_F1d;
     /* FIXME: cpu_M0 can probably be the same as cpu_V0.  */
     cpu_M0 = tcg_temp_new_i64();
-    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
-    num_insns = 0;
+    next_page_start = (dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
     max_insns = tb->cflags & CF_COUNT_MASK;
     if (max_insns == 0) {
         max_insns = CF_COUNT_MASK;
@@ -11924,11 +11922,11 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
         store_cpu_field(tmp, condexec_bits);
       }
     do {
+        dc->base.num_insns++;
         dc->insn_start_idx = tcg_op_buf_count();
         tcg_gen_insn_start(dc->pc,
                            (dc->condexec_cond << 4) | (dc->condexec_mask >> 1),
                            0);
-        num_insns++;
 
 #ifdef CONFIG_USER_ONLY
         /* Intercept jump to the magic kernel page.  */
@@ -11936,7 +11934,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
             /* We always get here via a jump, so know we are not in a
                conditional execution block.  */
             gen_exception_internal(EXCP_KERNEL_TRAP);
-            dc->is_jmp = DISAS_EXC;
+            dc->base.is_jmp = DISAS_EXC;
             break;
         }
 #endif
@@ -11950,7 +11948,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
                         gen_set_pc_im(dc, dc->pc);
                         gen_helper_check_breakpoints(cpu_env);
                         /* End the TB early; it's likely not going to be executed */
-                        dc->is_jmp = DISAS_UPDATE;
+                        dc->base.is_jmp = DISAS_UPDATE;
                     } else {
                         gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
                         /* The address covered by the breakpoint must be
@@ -11968,7 +11966,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
             }
         }
 
-        if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
+        if (dc->base.num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
             gen_io_start();
         }
 
@@ -11983,7 +11981,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
              * "did not step an insn" case, and so the syndrome ISV and EX
              * bits should be zero.
              */
-            assert(num_insns == 1);
+            assert(dc->base.num_insns == 1);
             gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
                           default_exception_el(dc));
             goto done_generating;
@@ -12005,7 +12003,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
             disas_arm_insn(dc, insn);
         }
 
-        if (dc->condjmp && !dc->is_jmp) {
+        if (dc->condjmp && !dc->base.is_jmp) {
             gen_set_label(dc->condlabel);
             dc->condjmp = 0;
         }
@@ -12032,11 +12030,11 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
         end_of_page = (dc->pc >= next_page_start) ||
             ((dc->pc >= next_page_start - 3) && insn_crosses_page(env, dc));
 
-    } while (!dc->is_jmp && !tcg_op_buf_full() &&
+    } while (!dc->base.is_jmp && !tcg_op_buf_full() &&
              !is_singlestepping(dc) &&
              !singlestep &&
              !end_of_page &&
-             num_insns < max_insns);
+             dc->base.num_insns < max_insns);
 
     if (tb->cflags & CF_LAST_IO) {
         if (dc->condjmp) {
@@ -12051,7 +12049,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
        instruction was a conditional branch or trap, and the PC has
        already been written.  */
     gen_set_condexec(dc);
-    if (dc->is_jmp == DISAS_BX_EXCRET) {
+    if (dc->base.is_jmp == DISAS_BX_EXCRET) {
         /* Exception return branches need some special case code at the
          * end of the TB, which is complex enough that it has to
          * handle the single-step vs not and the condition-failed
@@ -12060,7 +12058,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
         gen_bx_excret_final_code(dc);
     } else if (unlikely(is_singlestepping(dc))) {
         /* Unconditional and "condition passed" instruction codepath. */
-        switch (dc->is_jmp) {
+        switch (dc->base.is_jmp) {
         case DISAS_SWI:
             gen_ss_advance(dc);
             gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb),
@@ -12091,7 +12089,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
             - Hardware watchpoints.
            Hardware breakpoints have already been handled and skip this code.
          */
-        switch(dc->is_jmp) {
+        switch(dc->base.is_jmp) {
         case DISAS_NEXT:
             gen_goto_tb(dc, 1, dc->pc);
             break;
@@ -12148,22 +12146,22 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
     }
 
 done_generating:
-    gen_tb_end(tb, num_insns);
+    gen_tb_end(tb, dc->base.num_insns);
 
 #ifdef DEBUG_DISAS
     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) &&
-        qemu_log_in_addr_range(pc_start)) {
+        qemu_log_in_addr_range(dc->base.pc_first)) {
         qemu_log_lock();
         qemu_log("----------------\n");
-        qemu_log("IN: %s\n", lookup_symbol(pc_start));
-        log_target_disas(cs, pc_start, dc->pc - pc_start,
+        qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
+        log_target_disas(cs, dc->base.pc_first, dc->pc - dc->base.pc_first,
                          dc->thumb | (dc->sctlr_b << 1));
         qemu_log("\n");
         qemu_log_unlock();
     }
 #endif
-    tb->size = dc->pc - pc_start;
-    tb->icount = num_insns;
+    tb->size = dc->pc - dc->base.pc_first;
+    tb->icount = dc->base.num_insns;
 }
 
 static const char *cpu_mode_names[16] = {
diff --git a/target/arm/translate.h b/target/arm/translate.h
index aba3f44c9f..6fe40a344a 100644
--- a/target/arm/translate.h
+++ b/target/arm/translate.h
@@ -6,9 +6,10 @@
 
 /* internal defines */
 typedef struct DisasContext {
+    DisasContextBase base;
+
     target_ulong pc;
     uint32_t insn;
-    int is_jmp;
     /* Nonzero if this instruction has been conditionally skipped.  */
     int condjmp;
     /* The label that will be jumped to when the instruction is skipped.  */
@@ -16,8 +17,6 @@ typedef struct DisasContext {
     /* Thumb-2 conditional execution bits.  */
     int condexec_mask;
     int condexec_cond;
-    struct TranslationBlock *tb;
-    int singlestep_enabled;
     int thumb;
     int sctlr_b;
     TCGMemOp be_data;
@@ -152,7 +151,8 @@ static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
 
 #ifdef TARGET_AARCH64
 void a64_translate_init(void);
-void gen_intermediate_code_a64(CPUState *cpu, TranslationBlock *tb);
+void gen_intermediate_code_a64(DisasContextBase *db, CPUState *cpu,
+                               TranslationBlock *tb);
 void gen_a64_set_pc_im(uint64_t val);
 void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
                             fprintf_function cpu_fprintf, int flags);
@@ -161,7 +161,8 @@ static inline void a64_translate_init(void)
 {
 }
 
-static inline void gen_intermediate_code_a64(CPUState *cpu, TranslationBlock *tb)
+static inline void gen_intermediate_code_a64(DisasContextBase *db, CPUState *cpu,
+                                             TranslationBlock *tb)
 {
 }
 

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 14/27] target/arm: [tcg] Port to init_disas_context
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (12 preceding siblings ...)
  2017-07-07 12:33 ` [Qemu-devel] [PATCH v12 13/27] target/arm: [tcg] Port to DisasContextBase Lluís Vilanova
@ 2017-07-07 12:37 ` Lluís Vilanova
  2017-07-12  9:27   ` Alex Bennée
  2017-07-07 12:41 ` [Qemu-devel] [PATCH v12 15/27] target/arm: [tcg, a64] " Lluís Vilanova
                   ` (13 subsequent siblings)
  27 siblings, 1 reply; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 12:37 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Peter Maydell, open list:ARM

Incrementally paves the way towards using the generic instruction translation
loop.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target/arm/translate.c |   86 +++++++++++++++++++++++++++---------------------
 1 file changed, 48 insertions(+), 38 deletions(-)

diff --git a/target/arm/translate.c b/target/arm/translate.c
index 15b4fcb417..0179b1ce79 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -11786,32 +11786,12 @@ static bool insn_crosses_page(CPUARMState *env, DisasContext *s)
     return false;
 }
 
-/* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
+static void arm_tr_init_disas_context(DisasContextBase *dcbase,
+                                           CPUState *cs)
 {
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
     CPUARMState *env = cs->env_ptr;
     ARMCPU *cpu = arm_env_get_cpu(env);
-    DisasContext dc1, *dc = &dc1;
-    target_ulong next_page_start;
-    int max_insns;
-    bool end_of_page;
-
-    /* generate intermediate code */
-
-    /* The A64 decoder has its own top level loop, because it doesn't need
-     * the A32/T32 complexity to do with conditional execution/IT blocks/etc.
-     */
-    if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
-        gen_intermediate_code_a64(&dc->base, cs, tb);
-        return;
-    }
-
-    dc->base.tb = tb;
-    dc->base.pc_first = tb->pc;
-    dc->base.pc_next = dc->base.pc_first;
-    dc->base.is_jmp = DISAS_NEXT;
-    dc->base.num_insns = 0;
-    dc->base.singlestep_enabled = cs->singlestep_enabled;
 
     dc->pc = dc->base.pc_first;
     dc->condjmp = 0;
@@ -11822,23 +11802,23 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
      */
     dc->secure_routed_to_el3 = arm_feature(env, ARM_FEATURE_EL3) &&
                                !arm_el_is_aa64(env, 3);
-    dc->thumb = ARM_TBFLAG_THUMB(tb->flags);
-    dc->sctlr_b = ARM_TBFLAG_SCTLR_B(tb->flags);
-    dc->be_data = ARM_TBFLAG_BE_DATA(tb->flags) ? MO_BE : MO_LE;
-    dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1;
-    dc->condexec_cond = ARM_TBFLAG_CONDEXEC(tb->flags) >> 4;
-    dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(tb->flags));
+    dc->thumb = ARM_TBFLAG_THUMB(dc->base.tb->flags);
+    dc->sctlr_b = ARM_TBFLAG_SCTLR_B(dc->base.tb->flags);
+    dc->be_data = ARM_TBFLAG_BE_DATA(dc->base.tb->flags) ? MO_BE : MO_LE;
+    dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(dc->base.tb->flags) & 0xf) << 1;
+    dc->condexec_cond = ARM_TBFLAG_CONDEXEC(dc->base.tb->flags) >> 4;
+    dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(dc->base.tb->flags));
     dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
 #if !defined(CONFIG_USER_ONLY)
     dc->user = (dc->current_el == 0);
 #endif
-    dc->ns = ARM_TBFLAG_NS(tb->flags);
-    dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(tb->flags);
-    dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
-    dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags);
-    dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
-    dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(tb->flags);
-    dc->v7m_handler_mode = ARM_TBFLAG_HANDLER(tb->flags);
+    dc->ns = ARM_TBFLAG_NS(dc->base.tb->flags);
+    dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(dc->base.tb->flags);
+    dc->vfp_enabled = ARM_TBFLAG_VFPEN(dc->base.tb->flags);
+    dc->vec_len = ARM_TBFLAG_VECLEN(dc->base.tb->flags);
+    dc->vec_stride = ARM_TBFLAG_VECSTRIDE(dc->base.tb->flags);
+    dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(dc->base.tb->flags);
+    dc->v7m_handler_mode = ARM_TBFLAG_HANDLER(dc->base.tb->flags);
     dc->cp_regs = cpu->cp_regs;
     dc->features = env->features;
 
@@ -11857,11 +11837,12 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
      *   emit code to generate a software step exception
      *   end the TB
      */
-    dc->ss_active = ARM_TBFLAG_SS_ACTIVE(tb->flags);
-    dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(tb->flags);
+    dc->ss_active = ARM_TBFLAG_SS_ACTIVE(dc->base.tb->flags);
+    dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(dc->base.tb->flags);
     dc->is_ldex = false;
     dc->ss_same_el = false; /* Can't be true since EL_d must be AArch64 */
 
+
     cpu_F0s = tcg_temp_new_i32();
     cpu_F1s = tcg_temp_new_i32();
     cpu_F0d = tcg_temp_new_i64();
@@ -11870,6 +11851,35 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
     cpu_V1 = cpu_F1d;
     /* FIXME: cpu_M0 can probably be the same as cpu_V0.  */
     cpu_M0 = tcg_temp_new_i64();
+}
+
+/* generate intermediate code for basic block 'tb'.  */
+void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
+{
+    CPUARMState *env = cs->env_ptr;
+    DisasContext dc1, *dc = &dc1;
+    target_ulong next_page_start;
+    int max_insns;
+    bool end_of_page;
+
+    /* generate intermediate code */
+
+    /* The A64 decoder has its own top level loop, because it doesn't need
+     * the A32/T32 complexity to do with conditional execution/IT blocks/etc.
+     */
+    if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
+        gen_intermediate_code_a64(&dc->base, cs, tb);
+        return;
+    }
+
+    dc->base.tb = tb;
+    dc->base.pc_first = dc->base.tb->pc;
+    dc->base.pc_next = dc->base.pc_first;
+    dc->base.is_jmp = DISAS_NEXT;
+    dc->base.num_insns = 0;
+    dc->base.singlestep_enabled = cs->singlestep_enabled;
+    arm_tr_init_disas_context(&dc->base, cs);
+
     next_page_start = (dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
     max_insns = tb->cflags & CF_COUNT_MASK;
     if (max_insns == 0) {

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 15/27] target/arm: [tcg, a64] Port to init_disas_context
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (13 preceding siblings ...)
  2017-07-07 12:37 ` [Qemu-devel] [PATCH v12 14/27] target/arm: [tcg] Port to init_disas_context Lluís Vilanova
@ 2017-07-07 12:41 ` Lluís Vilanova
  2017-07-12  9:30   ` Alex Bennée
  2017-07-07 12:46 ` [Qemu-devel] [PATCH v12 16/27] target/arm: [tcg] Port to tb_start Lluís Vilanova
                   ` (12 subsequent siblings)
  27 siblings, 1 reply; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 12:41 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Peter Maydell, open list:ARM

Incrementally paves the way towards using the generic instruction translation
loop.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target/arm/translate-a64.c |   36 ++++++++++++++++++++++--------------
 1 file changed, 22 insertions(+), 14 deletions(-)

diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 4270ac3847..5c04ff3d8b 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -11190,21 +11190,12 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
     free_tmp_a64(s);
 }
 
-void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
-                               TranslationBlock *tb)
+static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
+                                               CPUState *cpu)
 {
-    CPUARMState *env = cs->env_ptr;
-    ARMCPU *cpu = arm_env_get_cpu(env);
     DisasContext *dc = container_of(dcbase, DisasContext, base);
-    target_ulong next_page_start;
-    int max_insns;
-
-    dc->base.tb = tb;
-    dc->base.pc_first = dc->base.tb->pc;
-    dc->base.pc_next = dc->base.pc_first;
-    dc->base.is_jmp = DISAS_NEXT;
-    dc->base.num_insns = 0;
-    dc->base.singlestep_enabled = cs->singlestep_enabled;
+    CPUARMState *env = cpu->env_ptr;
+    ARMCPU *arm_cpu = arm_env_get_cpu(env);
 
     dc->pc = dc->base.pc_first;
     dc->condjmp = 0;
@@ -11230,7 +11221,7 @@ void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
     dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(dc->base.tb->flags);
     dc->vec_len = 0;
     dc->vec_stride = 0;
-    dc->cp_regs = cpu->cp_regs;
+    dc->cp_regs = arm_cpu->cp_regs;
     dc->features = env->features;
 
     /* Single step state. The code-generation logic here is:
@@ -11254,6 +11245,23 @@ void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
     dc->ss_same_el = (arm_debug_target_el(env) == dc->current_el);
 
     init_tmp_a64_array(dc);
+}
+
+void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
+                               TranslationBlock *tb)
+{
+    CPUARMState *env = cs->env_ptr;
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+    target_ulong next_page_start;
+    int max_insns;
+
+    dc->base.tb = tb;
+    dc->base.pc_first = dc->base.tb->pc;
+    dc->base.pc_next = dc->base.pc_first;
+    dc->base.is_jmp = DISAS_NEXT;
+    dc->base.num_insns = 0;
+    dc->base.singlestep_enabled = cs->singlestep_enabled;
+    aarch64_tr_init_disas_context(&dc->base, cs);
 
     next_page_start = (dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
     max_insns = dc->base.tb->cflags & CF_COUNT_MASK;

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 16/27] target/arm: [tcg] Port to tb_start
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (14 preceding siblings ...)
  2017-07-07 12:41 ` [Qemu-devel] [PATCH v12 15/27] target/arm: [tcg, a64] " Lluís Vilanova
@ 2017-07-07 12:46 ` Lluís Vilanova
  2017-07-12  9:31   ` Alex Bennée
  2017-07-07 12:50 ` [Qemu-devel] [PATCH v12 17/27] target/arm: [tcg] Port to insn_start Lluís Vilanova
                   ` (11 subsequent siblings)
  27 siblings, 1 reply; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 12:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Peter Maydell, open list:ARM

Incrementally paves the way towards using the generic instruction translation
loop.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target/arm/translate.c |   82 ++++++++++++++++++++++++++----------------------
 1 file changed, 44 insertions(+), 38 deletions(-)

diff --git a/target/arm/translate.c b/target/arm/translate.c
index 0179b1ce79..22af4e372a 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -11853,6 +11853,49 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase,
     cpu_M0 = tcg_temp_new_i64();
 }
 
+static void arm_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu)
+{
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+
+    /* A note on handling of the condexec (IT) bits:
+     *
+     * We want to avoid the overhead of having to write the updated condexec
+     * bits back to the CPUARMState for every instruction in an IT block. So:
+     * (1) if the condexec bits are not already zero then we write
+     * zero back into the CPUARMState now. This avoids complications trying
+     * to do it at the end of the block. (For example if we don't do this
+     * it's hard to identify whether we can safely skip writing condexec
+     * at the end of the TB, which we definitely want to do for the case
+     * where a TB doesn't do anything with the IT state at all.)
+     * (2) if we are going to leave the TB then we call gen_set_condexec()
+     * which will write the correct value into CPUARMState if zero is wrong.
+     * This is done both for leaving the TB at the end, and for leaving
+     * it because of an exception we know will happen, which is done in
+     * gen_exception_insn(). The latter is necessary because we need to
+     * leave the TB with the PC/IT state just prior to execution of the
+     * instruction which caused the exception.
+     * (3) if we leave the TB unexpectedly (eg a data abort on a load)
+     * then the CPUARMState will be wrong and we need to reset it.
+     * This is handled in the same way as restoration of the
+     * PC in these situations; we save the value of the condexec bits
+     * for each PC via tcg_gen_insn_start(), and restore_state_to_opc()
+     * then uses this to restore them after an exception.
+     *
+     * Note that there are no instructions which can read the condexec
+     * bits, and none which can write non-static values to them, so
+     * we don't need to care about whether CPUARMState is correct in the
+     * middle of a TB.
+     */
+
+    /* Reset the conditional execution bits immediately. This avoids
+       complications trying to do it at the end of the block.  */
+    if (dc->condexec_mask || dc->condexec_cond) {
+        TCGv_i32 tmp = tcg_temp_new_i32();
+        tcg_gen_movi_i32(tmp, 0);
+        store_cpu_field(tmp, condexec_bits);
+    }
+}
+
 /* generate intermediate code for basic block 'tb'.  */
 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
 {
@@ -11892,45 +11935,8 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
     gen_tb_start(tb);
 
     tcg_clear_temp_count();
+    arm_tr_tb_start(&dc->base, cs);
 
-    /* A note on handling of the condexec (IT) bits:
-     *
-     * We want to avoid the overhead of having to write the updated condexec
-     * bits back to the CPUARMState for every instruction in an IT block. So:
-     * (1) if the condexec bits are not already zero then we write
-     * zero back into the CPUARMState now. This avoids complications trying
-     * to do it at the end of the block. (For example if we don't do this
-     * it's hard to identify whether we can safely skip writing condexec
-     * at the end of the TB, which we definitely want to do for the case
-     * where a TB doesn't do anything with the IT state at all.)
-     * (2) if we are going to leave the TB then we call gen_set_condexec()
-     * which will write the correct value into CPUARMState if zero is wrong.
-     * This is done both for leaving the TB at the end, and for leaving
-     * it because of an exception we know will happen, which is done in
-     * gen_exception_insn(). The latter is necessary because we need to
-     * leave the TB with the PC/IT state just prior to execution of the
-     * instruction which caused the exception.
-     * (3) if we leave the TB unexpectedly (eg a data abort on a load)
-     * then the CPUARMState will be wrong and we need to reset it.
-     * This is handled in the same way as restoration of the
-     * PC in these situations; we save the value of the condexec bits
-     * for each PC via tcg_gen_insn_start(), and restore_state_to_opc()
-     * then uses this to restore them after an exception.
-     *
-     * Note that there are no instructions which can read the condexec
-     * bits, and none which can write non-static values to them, so
-     * we don't need to care about whether CPUARMState is correct in the
-     * middle of a TB.
-     */
-
-    /* Reset the conditional execution bits immediately. This avoids
-       complications trying to do it at the end of the block.  */
-    if (dc->condexec_mask || dc->condexec_cond)
-      {
-        TCGv_i32 tmp = tcg_temp_new_i32();
-        tcg_gen_movi_i32(tmp, 0);
-        store_cpu_field(tmp, condexec_bits);
-      }
     do {
         dc->base.num_insns++;
         dc->insn_start_idx = tcg_op_buf_count();

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 17/27] target/arm: [tcg] Port to insn_start
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (15 preceding siblings ...)
  2017-07-07 12:46 ` [Qemu-devel] [PATCH v12 16/27] target/arm: [tcg] Port to tb_start Lluís Vilanova
@ 2017-07-07 12:50 ` Lluís Vilanova
  2017-07-12  9:32   ` Alex Bennée
  2017-07-07 12:54 ` [Qemu-devel] [PATCH v12 18/27] target/arm: [tcg, a64] " Lluís Vilanova
                   ` (10 subsequent siblings)
  27 siblings, 1 reply; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 12:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Peter Maydell, open list:ARM

Incrementally paves the way towards using the generic instruction translation
loop.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target/arm/translate.c |   36 +++++++++++++++++++++---------------
 1 file changed, 21 insertions(+), 15 deletions(-)

diff --git a/target/arm/translate.c b/target/arm/translate.c
index 22af4e372a..7a1935d4d7 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -11896,6 +11896,26 @@ static void arm_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu)
     }
 }
 
+static void arm_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
+{
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+
+    dc->insn_start_idx = tcg_op_buf_count();
+    tcg_gen_insn_start(dc->pc,
+                       (dc->condexec_cond << 4) | (dc->condexec_mask >> 1),
+                       0);
+
+#ifdef CONFIG_USER_ONLY
+    /* Intercept jump to the magic kernel page.  */
+    if (dc->pc >= 0xffff0000) {
+        /* We always get here via a jump, so know we are not in a
+           conditional execution block.  */
+        gen_exception_internal(EXCP_KERNEL_TRAP);
+        dc->base.is_jmp = DISAS_EXC;
+    }
+#endif
+}
+
 /* generate intermediate code for basic block 'tb'.  */
 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
 {
@@ -11939,21 +11959,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
 
     do {
         dc->base.num_insns++;
-        dc->insn_start_idx = tcg_op_buf_count();
-        tcg_gen_insn_start(dc->pc,
-                           (dc->condexec_cond << 4) | (dc->condexec_mask >> 1),
-                           0);
-
-#ifdef CONFIG_USER_ONLY
-        /* Intercept jump to the magic kernel page.  */
-        if (dc->pc >= 0xffff0000) {
-            /* We always get here via a jump, so know we are not in a
-               conditional execution block.  */
-            gen_exception_internal(EXCP_KERNEL_TRAP);
-            dc->base.is_jmp = DISAS_EXC;
-            break;
-        }
-#endif
+        arm_tr_insn_start(&dc->base, cs);
 
         if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
             CPUBreakpoint *bp;

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 18/27] target/arm: [tcg, a64] Port to insn_start
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (16 preceding siblings ...)
  2017-07-07 12:50 ` [Qemu-devel] [PATCH v12 17/27] target/arm: [tcg] Port to insn_start Lluís Vilanova
@ 2017-07-07 12:54 ` Lluís Vilanova
  2017-07-12  9:32   ` Alex Bennée
  2017-07-07 12:58 ` [Qemu-devel] [PATCH v12 19/27] target/arm: [tcg] Port to breakpoint_check Lluís Vilanova
                   ` (9 subsequent siblings)
  27 siblings, 1 reply; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 12:54 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Peter Maydell, open list:ARM

Incrementally paves the way towards using the generic instruction translation
loop.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target/arm/translate-a64.c |   11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 5c04ff3d8b..dc91661df0 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -11247,6 +11247,14 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
     init_tmp_a64_array(dc);
 }
 
+static void aarch64_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
+{
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+
+    dc->insn_start_idx = tcg_op_buf_count();
+    tcg_gen_insn_start(dc->pc, 0, 0);
+}
+
 void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
                                TranslationBlock *tb)
 {
@@ -11278,8 +11286,7 @@ void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
 
     do {
         dc->base.num_insns++;
-        dc->insn_start_idx = tcg_op_buf_count();
-        tcg_gen_insn_start(dc->pc, 0, 0);
+        aarch64_tr_insn_start(&dc->base, cs);
 
         if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
             CPUBreakpoint *bp;

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 19/27] target/arm: [tcg] Port to breakpoint_check
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (17 preceding siblings ...)
  2017-07-07 12:54 ` [Qemu-devel] [PATCH v12 18/27] target/arm: [tcg, a64] " Lluís Vilanova
@ 2017-07-07 12:58 ` Lluís Vilanova
  2017-07-07 13:02 ` [Qemu-devel] [PATCH v12 20/27] target/arm: [tcg, a64] " Lluís Vilanova
                   ` (8 subsequent siblings)
  27 siblings, 0 replies; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 12:58 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Peter Maydell, open list:ARM

Incrementally paves the way towards using the generic instruction translation
loop.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target/arm/translate.c |   64 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 46 insertions(+), 18 deletions(-)

diff --git a/target/arm/translate.c b/target/arm/translate.c
index 7a1935d4d7..29428b2920 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -11916,6 +11916,32 @@ static void arm_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
 #endif
 }
 
+static BreakpointCheckType arm_tr_breakpoint_check(
+    DisasContextBase *dcbase, CPUState *cpu, const CPUBreakpoint *bp)
+{
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+
+    if (bp->flags & BP_CPU) {
+        gen_set_condexec(dc);
+        gen_set_pc_im(dc, dc->pc);
+        gen_helper_check_breakpoints(cpu_env);
+        /* End the TB early; it's likely not going to be executed */
+        dc->base.is_jmp = DISAS_UPDATE;
+        return BC_HIT_INSN;
+    } else {
+        gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
+        /* The address covered by the breakpoint must be
+           included in [tb->pc, tb->pc + tb->size) in order
+           to for it to be properly cleared -- thus we
+           increment the PC here so that the logic setting
+           tb->size below does the right thing.  */
+        /* TODO: Advance PC by correct instruction length to
+         * avoid disassembler error messages */
+        dc->pc += 2;
+        return BC_HIT_TB;
+    }
+}
+
 /* generate intermediate code for basic block 'tb'.  */
 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
 {
@@ -11964,29 +11990,31 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
         if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
             CPUBreakpoint *bp;
             QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
-                if (bp->pc == dc->pc) {
-                    if (bp->flags & BP_CPU) {
-                        gen_set_condexec(dc);
-                        gen_set_pc_im(dc, dc->pc);
-                        gen_helper_check_breakpoints(cpu_env);
-                        /* End the TB early; it's likely not going to be executed */
-                        dc->base.is_jmp = DISAS_UPDATE;
-                    } else {
-                        gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
-                        /* The address covered by the breakpoint must be
-                           included in [tb->pc, tb->pc + tb->size) in order
-                           to for it to be properly cleared -- thus we
-                           increment the PC here so that the logic setting
-                           tb->size below does the right thing.  */
-                        /* TODO: Advance PC by correct instruction length to
-                         * avoid disassembler error messages */
-                        dc->pc += 2;
+                if (bp->pc == dc->base.pc_next) {
+                    BreakpointCheckType bp_check =
+                        arm_tr_breakpoint_check(&dc->base, cs, bp);
+                    switch (bp_check) {
+                    case BC_MISS:
+                        /* Target ignored this breakpoint, go to next */
+                        break;
+                    case BC_HIT_INSN:
+                        /* Hit, keep translating */
+                        /*
+                         * TODO: if we're never going to have more than one
+                         *       BP in a single address, we can simply use a
+                         *       bool here.
+                         */
+                        goto done_breakpoints;
+                    case BC_HIT_TB:
+                        /* Hit, end TB */
                         goto done_generating;
+                    default:
+                        g_assert_not_reached();
                     }
-                    break;
                 }
             }
         }
+    done_breakpoints:
 
         if (dc->base.num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
             gen_io_start();

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 20/27] target/arm: [tcg, a64] Port to breakpoint_check
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (18 preceding siblings ...)
  2017-07-07 12:58 ` [Qemu-devel] [PATCH v12 19/27] target/arm: [tcg] Port to breakpoint_check Lluís Vilanova
@ 2017-07-07 13:02 ` Lluís Vilanova
  2017-07-07 13:06 ` [Qemu-devel] [PATCH v12 21/27] target/arm: [tcg] Port to translate_insn Lluís Vilanova
                   ` (7 subsequent siblings)
  27 siblings, 0 replies; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 13:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Peter Maydell, open list:ARM

Incrementally paves the way towards using the generic instruction translation
loop.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target/arm/translate-a64.c |   58 +++++++++++++++++++++++++++++++++-----------
 1 file changed, 43 insertions(+), 15 deletions(-)

diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index dc91661df0..a32f07f4bd 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -11255,6 +11255,29 @@ static void aarch64_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
     tcg_gen_insn_start(dc->pc, 0, 0);
 }
 
+static BreakpointCheckType aarch64_tr_breakpoint_check(
+    DisasContextBase *dcbase, CPUState *cpu, const CPUBreakpoint *bp)
+{
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+
+    if (bp->flags & BP_CPU) {
+        gen_a64_set_pc_im(dc->pc);
+        gen_helper_check_breakpoints(cpu_env);
+        /* End the TB early; it likely won't be executed */
+        dc->base.is_jmp = DISAS_UPDATE;
+        return BC_HIT_INSN;
+    } else {
+        gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
+        /* The address covered by the breakpoint must be
+           included in [tb->pc, tb->pc + tb->size) in order
+           to for it to be properly cleared -- thus we
+           increment the PC here so that the logic setting
+           tb->size below does the right thing.  */
+        dc->pc += 4;
+        return BC_HIT_TB;
+    }
+}
+
 void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
                                TranslationBlock *tb)
 {
@@ -11291,26 +11314,31 @@ void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
         if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
             CPUBreakpoint *bp;
             QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
-                if (bp->pc == dc->pc) {
-                    if (bp->flags & BP_CPU) {
-                        gen_a64_set_pc_im(dc->pc);
-                        gen_helper_check_breakpoints(cpu_env);
-                        /* End the TB early; it likely won't be executed */
-                        dc->base.is_jmp = DISAS_UPDATE;
-                    } else {
-                        gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
-                        /* The address covered by the breakpoint must be
-                           included in [dc->base.tb->pc, dc->base.tb->pc + dc->base.tb->size) in order
-                           to for it to be properly cleared -- thus we
-                           increment the PC here so that the logic setting
-                           dc->base.tb->size below does the right thing.  */
-                        dc->pc += 4;
+                if (bp->pc == dc->base.pc_next) {
+                    BreakpointCheckType bp_check =
+                        aarch64_tr_breakpoint_check(&dc->base, cs, bp);
+                    switch (bp_check) {
+                    case BC_MISS:
+                        /* Target ignored this breakpoint, go to next */
+                        break;
+                    case BC_HIT_INSN:
+                        /* Hit, keep translating */
+                        /*
+                         * TODO: if we're never going to have more than one
+                         *       BP in a single address, we can simply use a
+                         *       bool here.
+                         */
+                        goto done_breakpoints;
+                    case BC_HIT_TB:
+                        /* Hit, end TB */
                         goto done_generating;
+                    default:
+                        g_assert_not_reached();
                     }
-                    break;
                 }
             }
         }
+    done_breakpoints:
 
         if (dc->base.num_insns == max_insns && (dc->base.tb->cflags & CF_LAST_IO)) {
             gen_io_start();

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 21/27] target/arm: [tcg] Port to translate_insn
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (19 preceding siblings ...)
  2017-07-07 13:02 ` [Qemu-devel] [PATCH v12 20/27] target/arm: [tcg, a64] " Lluís Vilanova
@ 2017-07-07 13:06 ` Lluís Vilanova
  2017-07-12  9:39   ` Alex Bennée
  2017-07-07 13:10 ` [Qemu-devel] [PATCH v12 22/27] target/arm: [tcg, a64] " Lluís Vilanova
                   ` (6 subsequent siblings)
  27 siblings, 1 reply; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 13:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Peter Maydell, open list:ARM

Incrementally paves the way towards using the generic instruction translation
loop.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
---
 target/arm/translate.c |  148 ++++++++++++++++++++++++++++--------------------
 target/arm/translate.h |    2 +
 2 files changed, 87 insertions(+), 63 deletions(-)

diff --git a/target/arm/translate.c b/target/arm/translate.c
index 29428b2920..9d033f2fb7 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -11842,6 +11842,9 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase,
     dc->is_ldex = false;
     dc->ss_same_el = false; /* Can't be true since EL_d must be AArch64 */
 
+    dc->next_page_start =
+        (dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+
 
     cpu_F0s = tcg_temp_new_i32();
     cpu_F1s = tcg_temp_new_i32();
@@ -11942,14 +11945,83 @@ static BreakpointCheckType arm_tr_breakpoint_check(
     }
 }
 
+static target_ulong arm_tr_translate_insn(DisasContextBase *dcbase,
+                                               CPUState *cpu)
+{
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+    CPUARMState *env = cpu->env_ptr;
+
+    if (dc->ss_active && !dc->pstate_ss) {
+        /* Singlestep state is Active-pending.
+         * If we're in this state at the start of a TB then either
+         *  a) we just took an exception to an EL which is being debugged
+         *     and this is the first insn in the exception handler
+         *  b) debug exceptions were masked and we just unmasked them
+         *     without changing EL (eg by clearing PSTATE.D)
+         * In either case we're going to take a swstep exception in the
+         * "did not step an insn" case, and so the syndrome ISV and EX
+         * bits should be zero.
+         */
+        assert(dc->base.num_insns == 1);
+        gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
+                      default_exception_el(dc));
+        dc->base.is_jmp = DISAS_SKIP;
+        return dc->pc;
+    }
+
+    if (dc->thumb) {
+        disas_thumb_insn(env, dc);
+        if (dc->condexec_mask) {
+            dc->condexec_cond = (dc->condexec_cond & 0xe)
+                | ((dc->condexec_mask >> 4) & 1);
+            dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f;
+            if (dc->condexec_mask == 0) {
+                dc->condexec_cond = 0;
+            }
+        }
+    } else {
+        unsigned int insn = arm_ldl_code(env, dc->pc, dc->sctlr_b);
+        dc->pc += 4;
+        disas_arm_insn(dc, insn);
+    }
+
+    if (dc->condjmp && !dc->base.is_jmp) {
+        gen_set_label(dc->condlabel);
+        dc->condjmp = 0;
+    }
+
+    if (dc->base.is_jmp == DISAS_NEXT) {
+        /* Translation stops when a conditional branch is encountered.
+         * Otherwise the subsequent code could get translated several times.
+         * Also stop translation when a page boundary is reached.  This
+         * ensures prefetch aborts occur at the right place.  */
+
+        if (is_singlestepping(dc)) {
+            dc->base.is_jmp = DISAS_TOO_MANY;
+        } else if ((dc->pc >= dc->next_page_start) ||
+                   ((dc->pc >= dc->next_page_start - 3) &&
+                    insn_crosses_page(env, dc))) {
+            /* We want to stop the TB if the next insn starts in a new page,
+             * or if it spans between this page and the next. This means that
+             * if we're looking at the last halfword in the page we need to
+             * see if it's a 16-bit Thumb insn (which will fit in this TB)
+             * or a 32-bit Thumb insn (which won't).
+             * This is to avoid generating a silly TB with a single 16-bit insn
+             * in it at the end of this page (which would execute correctly
+             * but isn't very efficient).
+             */
+            dc->base.is_jmp = DISAS_TOO_MANY;
+        }
+    }
+
+    return dc->pc;
+}
+
 /* generate intermediate code for basic block 'tb'.  */
 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
 {
-    CPUARMState *env = cs->env_ptr;
     DisasContext dc1, *dc = &dc1;
-    target_ulong next_page_start;
     int max_insns;
-    bool end_of_page;
 
     /* generate intermediate code */
 
@@ -11969,7 +12041,6 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
     dc->base.singlestep_enabled = cs->singlestep_enabled;
     arm_tr_init_disas_context(&dc->base, cs);
 
-    next_page_start = (dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
     max_insns = tb->cflags & CF_COUNT_MASK;
     if (max_insns == 0) {
         max_insns = CF_COUNT_MASK;
@@ -12020,72 +12091,20 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
             gen_io_start();
         }
 
-        if (dc->ss_active && !dc->pstate_ss) {
-            /* Singlestep state is Active-pending.
-             * If we're in this state at the start of a TB then either
-             *  a) we just took an exception to an EL which is being debugged
-             *     and this is the first insn in the exception handler
-             *  b) debug exceptions were masked and we just unmasked them
-             *     without changing EL (eg by clearing PSTATE.D)
-             * In either case we're going to take a swstep exception in the
-             * "did not step an insn" case, and so the syndrome ISV and EX
-             * bits should be zero.
-             */
-            assert(dc->base.num_insns == 1);
-            gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
-                          default_exception_el(dc));
-            goto done_generating;
-        }
-
-        if (dc->thumb) {
-            disas_thumb_insn(env, dc);
-            if (dc->condexec_mask) {
-                dc->condexec_cond = (dc->condexec_cond & 0xe)
-                                   | ((dc->condexec_mask >> 4) & 1);
-                dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f;
-                if (dc->condexec_mask == 0) {
-                    dc->condexec_cond = 0;
-                }
-            }
-        } else {
-            unsigned int insn = arm_ldl_code(env, dc->pc, dc->sctlr_b);
-            dc->pc += 4;
-            disas_arm_insn(dc, insn);
-        }
-
-        if (dc->condjmp && !dc->base.is_jmp) {
-            gen_set_label(dc->condlabel);
-            dc->condjmp = 0;
-        }
+        dc->base.pc_next = arm_tr_translate_insn(&dc->base, cs);
 
         if (tcg_check_temp_count()) {
             fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
                     dc->pc);
         }
 
-        /* Translation stops when a conditional branch is encountered.
-         * Otherwise the subsequent code could get translated several times.
-         * Also stop translation when a page boundary is reached.  This
-         * ensures prefetch aborts occur at the right place.  */
-
-        /* We want to stop the TB if the next insn starts in a new page,
-         * or if it spans between this page and the next. This means that
-         * if we're looking at the last halfword in the page we need to
-         * see if it's a 16-bit Thumb insn (which will fit in this TB)
-         * or a 32-bit Thumb insn (which won't).
-         * This is to avoid generating a silly TB with a single 16-bit insn
-         * in it at the end of this page (which would execute correctly
-         * but isn't very efficient).
-         */
-        end_of_page = (dc->pc >= next_page_start) ||
-            ((dc->pc >= next_page_start - 3) && insn_crosses_page(env, dc));
-
-    } while (!dc->base.is_jmp && !tcg_op_buf_full() &&
-             !is_singlestepping(dc) &&
-             !singlestep &&
-             !end_of_page &&
-             dc->base.num_insns < max_insns);
+        if (!dc->base.is_jmp && (tcg_op_buf_full() || singlestep ||
+                            dc->base.num_insns >= max_insns)) {
+            dc->base.is_jmp = DISAS_TOO_MANY;
+        }
+    } while (!dc->base.is_jmp);
 
+    if (dc->base.is_jmp != DISAS_SKIP) {
     if (tb->cflags & CF_LAST_IO) {
         if (dc->condjmp) {
             /* FIXME:  This can theoretically happen with self-modifying
@@ -12123,6 +12142,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
             gen_exception(EXCP_SMC, syn_aa32_smc(), 3);
             break;
         case DISAS_NEXT:
+        case DISAS_TOO_MANY:
         case DISAS_UPDATE:
             gen_set_pc_im(dc, dc->pc);
             /* fall through */
@@ -12141,6 +12161,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
          */
         switch(dc->base.is_jmp) {
         case DISAS_NEXT:
+        case DISAS_TOO_MANY:
             gen_goto_tb(dc, 1, dc->pc);
             break;
         case DISAS_UPDATE:
@@ -12194,6 +12215,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
             gen_goto_tb(dc, 1, dc->pc);
         }
     }
+    }
 
 done_generating:
     gen_tb_end(tb, dc->base.num_insns);
diff --git a/target/arm/translate.h b/target/arm/translate.h
index 6fe40a344a..83e56dcb08 100644
--- a/target/arm/translate.h
+++ b/target/arm/translate.h
@@ -9,6 +9,7 @@ typedef struct DisasContext {
     DisasContextBase base;
 
     target_ulong pc;
+    target_ulong next_page_start;
     uint32_t insn;
     /* Nonzero if this instruction has been conditionally skipped.  */
     int condjmp;
@@ -148,6 +149,7 @@ static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
  * as opposed to attempting to use lookup_and_goto_ptr.
  */
 #define DISAS_EXIT DISAS_TARGET_11
+#define DISAS_SKIP DISAS_TARGET_12
 
 #ifdef TARGET_AARCH64
 void a64_translate_init(void);

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 22/27] target/arm: [tcg, a64] Port to translate_insn
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (20 preceding siblings ...)
  2017-07-07 13:06 ` [Qemu-devel] [PATCH v12 21/27] target/arm: [tcg] Port to translate_insn Lluís Vilanova
@ 2017-07-07 13:10 ` Lluís Vilanova
  2017-07-07 13:14 ` [Qemu-devel] [PATCH v12 23/27] target/arm: [tcg] Port to tb_stop Lluís Vilanova
                   ` (5 subsequent siblings)
  27 siblings, 0 replies; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 13:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Peter Maydell, open list:ARM

Incrementally paves the way towards using the generic instruction translation
loop.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
---
 target/arm/translate-a64.c |   74 +++++++++++++++++++++++++++-----------------
 1 file changed, 46 insertions(+), 28 deletions(-)

diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index a32f07f4bd..c4cb9afb02 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -11244,6 +11244,9 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
     dc->is_ldex = false;
     dc->ss_same_el = (arm_debug_target_el(env) == dc->current_el);
 
+    dc->next_page_start =
+        (dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+
     init_tmp_a64_array(dc);
 }
 
@@ -11278,12 +11281,45 @@ static BreakpointCheckType aarch64_tr_breakpoint_check(
     }
 }
 
+static target_ulong aarch64_tr_translate_insn(DisasContextBase *dcbase,
+                                                   CPUState *cpu)
+{
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+    CPUARMState *env = cpu->env_ptr;
+
+
+    if (dc->ss_active && !dc->pstate_ss) {
+        /* Singlestep state is Active-pending.
+         * If we're in this state at the start of a TB then either
+         *  a) we just took an exception to an EL which is being debugged
+         *     and this is the first insn in the exception handler
+         *  b) debug exceptions were masked and we just unmasked them
+         *     without changing EL (eg by clearing PSTATE.D)
+         * In either case we're going to take a swstep exception in the
+         * "did not step an insn" case, and so the syndrome ISV and EX
+         * bits should be zero.
+         */
+        assert(dc->base.num_insns == 1);
+        gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
+                      default_exception_el(dc));
+        dc->base.is_jmp = DISAS_EXC;
+    } else {
+        disas_a64_insn(env, dc);
+    }
+
+    if (dc->base.is_jmp == DISAS_NEXT) {
+        if (dc->ss_active || dc->pc >= dc->next_page_start) {
+            dc->base.is_jmp = DISAS_TOO_MANY;
+        }
+    }
+
+    return dc->pc;
+}
+
 void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
                                TranslationBlock *tb)
 {
-    CPUARMState *env = cs->env_ptr;
     DisasContext *dc = container_of(dcbase, DisasContext, base);
-    target_ulong next_page_start;
     int max_insns;
 
     dc->base.tb = tb;
@@ -11294,7 +11330,6 @@ void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
     dc->base.singlestep_enabled = cs->singlestep_enabled;
     aarch64_tr_init_disas_context(&dc->base, cs);
 
-    next_page_start = (dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
     max_insns = dc->base.tb->cflags & CF_COUNT_MASK;
     if (max_insns == 0) {
         max_insns = CF_COUNT_MASK;
@@ -11344,42 +11379,24 @@ void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
             gen_io_start();
         }
 
-        if (dc->ss_active && !dc->pstate_ss) {
-            /* Singlestep state is Active-pending.
-             * If we're in this state at the start of a TB then either
-             *  a) we just took an exception to an EL which is being debugged
-             *     and this is the first insn in the exception handler
-             *  b) debug exceptions were masked and we just unmasked them
-             *     without changing EL (eg by clearing PSTATE.D)
-             * In either case we're going to take a swstep exception in the
-             * "did not step an insn" case, and so the syndrome ISV and EX
-             * bits should be zero.
-             */
-            assert(dc->base.num_insns == 1);
-            gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
-                          default_exception_el(dc));
-            dc->base.is_jmp = DISAS_EXC;
-            break;
-        }
-
-        disas_a64_insn(env, dc);
+        dc->base.pc_next = aarch64_tr_translate_insn(&dc->base, cs);
 
         if (tcg_check_temp_count()) {
             fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
                     dc->pc);
         }
 
+        if (!dc->base.is_jmp && (tcg_op_buf_full() || cs->singlestep_enabled ||
+                            singlestep || dc->base.num_insns >= max_insns)) {
+            dc->base.is_jmp = DISAS_TOO_MANY;
+        }
+
         /* Translation stops when a conditional branch is encountered.
          * Otherwise the subsequent code could get translated several times.
          * Also stop translation when a page boundary is reached.  This
          * ensures prefetch aborts occur at the right place.
          */
-    } while (!dc->base.is_jmp && !tcg_op_buf_full() &&
-             !cs->singlestep_enabled &&
-             !singlestep &&
-             !dc->ss_active &&
-             dc->pc < next_page_start &&
-             dc->base.num_insns < max_insns);
+    } while (!dc->base.is_jmp);
 
     if (dc->base.tb->cflags & CF_LAST_IO) {
         gen_io_end();
@@ -11404,6 +11421,7 @@ void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
     } else {
         switch (dc->base.is_jmp) {
         case DISAS_NEXT:
+        case DISAS_TOO_MANY:
             gen_goto_tb(dc, 1, dc->pc);
             break;
         default:

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 23/27] target/arm: [tcg] Port to tb_stop
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (21 preceding siblings ...)
  2017-07-07 13:10 ` [Qemu-devel] [PATCH v12 22/27] target/arm: [tcg, a64] " Lluís Vilanova
@ 2017-07-07 13:14 ` Lluís Vilanova
  2017-07-07 13:18 ` [Qemu-devel] [PATCH v12 24/27] target/arm: [tcg, a64] " Lluís Vilanova
                   ` (4 subsequent siblings)
  27 siblings, 0 replies; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 13:14 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Peter Maydell, open list:ARM

Incrementally paves the way towards using the generic instruction translation
loop.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
---
 target/arm/translate.c |  191 +++++++++++++++++++++++++-----------------------
 1 file changed, 101 insertions(+), 90 deletions(-)

diff --git a/target/arm/translate.c b/target/arm/translate.c
index 9d033f2fb7..00cac01d66 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -12017,101 +12017,17 @@ static target_ulong arm_tr_translate_insn(DisasContextBase *dcbase,
     return dc->pc;
 }
 
-/* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
+static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
 {
-    DisasContext dc1, *dc = &dc1;
-    int max_insns;
-
-    /* generate intermediate code */
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
 
-    /* The A64 decoder has its own top level loop, because it doesn't need
-     * the A32/T32 complexity to do with conditional execution/IT blocks/etc.
-     */
-    if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
-        gen_intermediate_code_a64(&dc->base, cs, tb);
+    if (dc->base.is_jmp == DISAS_SKIP) {
         return;
     }
 
-    dc->base.tb = tb;
-    dc->base.pc_first = dc->base.tb->pc;
-    dc->base.pc_next = dc->base.pc_first;
-    dc->base.is_jmp = DISAS_NEXT;
-    dc->base.num_insns = 0;
-    dc->base.singlestep_enabled = cs->singlestep_enabled;
-    arm_tr_init_disas_context(&dc->base, cs);
-
-    max_insns = tb->cflags & CF_COUNT_MASK;
-    if (max_insns == 0) {
-        max_insns = CF_COUNT_MASK;
-    }
-    if (max_insns > TCG_MAX_INSNS) {
-        max_insns = TCG_MAX_INSNS;
-    }
-
-    gen_tb_start(tb);
-
-    tcg_clear_temp_count();
-    arm_tr_tb_start(&dc->base, cs);
-
-    do {
-        dc->base.num_insns++;
-        arm_tr_insn_start(&dc->base, cs);
-
-        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
-            CPUBreakpoint *bp;
-            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
-                if (bp->pc == dc->base.pc_next) {
-                    BreakpointCheckType bp_check =
-                        arm_tr_breakpoint_check(&dc->base, cs, bp);
-                    switch (bp_check) {
-                    case BC_MISS:
-                        /* Target ignored this breakpoint, go to next */
-                        break;
-                    case BC_HIT_INSN:
-                        /* Hit, keep translating */
-                        /*
-                         * TODO: if we're never going to have more than one
-                         *       BP in a single address, we can simply use a
-                         *       bool here.
-                         */
-                        goto done_breakpoints;
-                    case BC_HIT_TB:
-                        /* Hit, end TB */
-                        goto done_generating;
-                    default:
-                        g_assert_not_reached();
-                    }
-                }
-            }
-        }
-    done_breakpoints:
-
-        if (dc->base.num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
-            gen_io_start();
-        }
-
-        dc->base.pc_next = arm_tr_translate_insn(&dc->base, cs);
-
-        if (tcg_check_temp_count()) {
-            fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
-                    dc->pc);
-        }
-
-        if (!dc->base.is_jmp && (tcg_op_buf_full() || singlestep ||
-                            dc->base.num_insns >= max_insns)) {
-            dc->base.is_jmp = DISAS_TOO_MANY;
-        }
-    } while (!dc->base.is_jmp);
-
-    if (dc->base.is_jmp != DISAS_SKIP) {
-    if (tb->cflags & CF_LAST_IO) {
-        if (dc->condjmp) {
-            /* FIXME:  This can theoretically happen with self-modifying
-               code.  */
-            cpu_abort(cs, "IO on conditional branch instruction");
-        }
-        gen_io_end();
+    if (dc->base.tb->cflags & CF_LAST_IO && dc->condjmp) {
+        /* FIXME: This can theoretically happen with self-modifying code. */
+        cpu_abort(cpu, "IO on conditional branch instruction");
     }
 
     /* At this stage dc->condjmp will only be set when the skipped
@@ -12215,6 +12131,101 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
             gen_goto_tb(dc, 1, dc->pc);
         }
     }
+}
+
+/* generate intermediate code for basic block 'tb'.  */
+void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
+{
+    DisasContext dc1, *dc = &dc1;
+    int max_insns;
+
+    /* generate intermediate code */
+
+    /* The A64 decoder has its own top level loop, because it doesn't need
+     * the A32/T32 complexity to do with conditional execution/IT blocks/etc.
+     */
+    if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
+        gen_intermediate_code_a64(&dc->base, cs, tb);
+        return;
+    }
+
+    dc->base.tb = tb;
+    dc->base.pc_first = dc->base.tb->pc;
+    dc->base.pc_next = dc->base.pc_first;
+    dc->base.is_jmp = DISAS_NEXT;
+    dc->base.num_insns = 0;
+    dc->base.singlestep_enabled = cs->singlestep_enabled;
+    arm_tr_init_disas_context(&dc->base, cs);
+
+
+    arm_tr_init_globals(&dc->base, cs);
+    max_insns = tb->cflags & CF_COUNT_MASK;
+    if (max_insns == 0) {
+        max_insns = CF_COUNT_MASK;
+    }
+    if (max_insns > TCG_MAX_INSNS) {
+        max_insns = TCG_MAX_INSNS;
+    }
+
+    gen_tb_start(tb);
+
+    tcg_clear_temp_count();
+    arm_tr_tb_start(&dc->base, cs);
+
+    do {
+        dc->base.num_insns++;
+        arm_tr_insn_start(&dc->base, cs);
+
+        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
+            CPUBreakpoint *bp;
+            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
+                if (bp->pc == dc->base.pc_next) {
+                    BreakpointCheckType bp_check =
+                        arm_tr_breakpoint_check(&dc->base, cs, bp);
+                    switch (bp_check) {
+                    case BC_MISS:
+                        /* Target ignored this breakpoint, go to next */
+                        break;
+                    case BC_HIT_INSN:
+                        /* Hit, keep translating */
+                        /*
+                         * TODO: if we're never going to have more than one
+                         *       BP in a single address, we can simply use a
+                         *       bool here.
+                         */
+                        goto done_breakpoints;
+                    case BC_HIT_TB:
+                        /* Hit, end TB */
+                        goto done_generating;
+                    default:
+                        g_assert_not_reached();
+                    }
+                }
+            }
+        }
+    done_breakpoints:
+
+        if (dc->base.num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
+            gen_io_start();
+        }
+
+        dc->base.pc_next = arm_tr_translate_insn(&dc->base, cs);
+
+        if (tcg_check_temp_count()) {
+            fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
+                    dc->pc);
+        }
+
+        if (!dc->base.is_jmp && (tcg_op_buf_full() || singlestep ||
+                            dc->base.num_insns >= max_insns)) {
+            dc->base.is_jmp = DISAS_TOO_MANY;
+        }
+    } while (!dc->base.is_jmp);
+
+    arm_tr_tb_stop(&dc->base, cs);
+
+    if (dc->base.tb->cflags & CF_LAST_IO) {
+        gen_io_end();
     }
 
 done_generating:

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 24/27] target/arm: [tcg, a64] Port to tb_stop
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (22 preceding siblings ...)
  2017-07-07 13:14 ` [Qemu-devel] [PATCH v12 23/27] target/arm: [tcg] Port to tb_stop Lluís Vilanova
@ 2017-07-07 13:18 ` Lluís Vilanova
  2017-07-07 13:23 ` [Qemu-devel] [PATCH v12 25/27] target/arm: [tcg] Port to disas_log Lluís Vilanova
                   ` (3 subsequent siblings)
  27 siblings, 0 replies; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 13:18 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Peter Maydell, open list:ARM

Incrementally paves the way towards using the generic instruction translation
loop.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target/arm/translate-a64.c |  123 +++++++++++++++++++++++---------------------
 1 file changed, 65 insertions(+), 58 deletions(-)

diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index c4cb9afb02..cead9d382c 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -11316,6 +11316,69 @@ static target_ulong aarch64_tr_translate_insn(DisasContextBase *dcbase,
     return dc->pc;
 }
 
+static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
+{
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+
+    if (unlikely(dc->base.singlestep_enabled || dc->ss_active)
+        && dc->base.is_jmp != DISAS_EXC) {
+        /* Note that this means single stepping WFI doesn't halt the CPU.
+         * For conditional branch insns this is harmless unreachable code as
+         * gen_goto_tb() has already handled emitting the debug exception
+         * (and thus a tb-jump is not possible when singlestepping).
+         */
+        assert(dc->base.is_jmp != DISAS_TB_JUMP);
+        if (dc->base.is_jmp != DISAS_JUMP) {
+            gen_a64_set_pc_im(dc->pc);
+        }
+        if (dc->base.singlestep_enabled) {
+            gen_exception_internal(EXCP_DEBUG);
+        } else {
+            gen_step_complete_exception(dc);
+        }
+    } else {
+        switch (dc->base.is_jmp) {
+        case DISAS_NEXT:
+        case DISAS_TOO_MANY:
+            gen_goto_tb(dc, 1, dc->pc);
+            break;
+        default:
+        case DISAS_UPDATE:
+            gen_a64_set_pc_im(dc->pc);
+            /* fall through */
+        case DISAS_JUMP:
+            tcg_gen_lookup_and_goto_ptr(cpu_pc);
+            break;
+        case DISAS_EXIT:
+            tcg_gen_exit_tb(0);
+            break;
+        case DISAS_TB_JUMP:
+        case DISAS_EXC:
+        case DISAS_SWI:
+            break;
+        case DISAS_WFE:
+            gen_a64_set_pc_im(dc->pc);
+            gen_helper_wfe(cpu_env);
+            break;
+        case DISAS_YIELD:
+            gen_a64_set_pc_im(dc->pc);
+            gen_helper_yield(cpu_env);
+            break;
+        case DISAS_WFI:
+            /* This is a special case because we don't want to just halt the CPU
+             * if trying to debug across a WFI.
+             */
+            gen_a64_set_pc_im(dc->pc);
+            gen_helper_wfi(cpu_env);
+            /* The helper doesn't necessarily throw an exception, but we
+             * must go back to the main loop to check for interrupts anyway.
+             */
+            tcg_gen_exit_tb(0);
+            break;
+        }
+    }
+}
+
 void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
                                TranslationBlock *tb)
 {
@@ -11398,68 +11461,12 @@ void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
          */
     } while (!dc->base.is_jmp);
 
+    aarch64_tr_tb_stop(&dc->base, cs);
+
     if (dc->base.tb->cflags & CF_LAST_IO) {
         gen_io_end();
     }
 
-    if (unlikely(cs->singlestep_enabled || dc->ss_active)
-        && dc->base.is_jmp != DISAS_EXC) {
-        /* Note that this means single stepping WFI doesn't halt the CPU.
-         * For conditional branch insns this is harmless unreachable code as
-         * gen_goto_tb() has already handled emitting the debug exception
-         * (and thus a tb-jump is not possible when singlestepping).
-         */
-        assert(dc->base.is_jmp != DISAS_TB_JUMP);
-        if (dc->base.is_jmp != DISAS_JUMP) {
-            gen_a64_set_pc_im(dc->pc);
-        }
-        if (cs->singlestep_enabled) {
-            gen_exception_internal(EXCP_DEBUG);
-        } else {
-            gen_step_complete_exception(dc);
-        }
-    } else {
-        switch (dc->base.is_jmp) {
-        case DISAS_NEXT:
-        case DISAS_TOO_MANY:
-            gen_goto_tb(dc, 1, dc->pc);
-            break;
-        default:
-        case DISAS_UPDATE:
-            gen_a64_set_pc_im(dc->pc);
-            /* fall through */
-        case DISAS_JUMP:
-            tcg_gen_lookup_and_goto_ptr(cpu_pc);
-            break;
-        case DISAS_EXIT:
-            tcg_gen_exit_tb(0);
-            break;
-        case DISAS_TB_JUMP:
-        case DISAS_EXC:
-        case DISAS_SWI:
-            break;
-        case DISAS_WFE:
-            gen_a64_set_pc_im(dc->pc);
-            gen_helper_wfe(cpu_env);
-            break;
-        case DISAS_YIELD:
-            gen_a64_set_pc_im(dc->pc);
-            gen_helper_yield(cpu_env);
-            break;
-        case DISAS_WFI:
-            /* This is a special case because we don't want to just halt the CPU
-             * if trying to debug across a WFI.
-             */
-            gen_a64_set_pc_im(dc->pc);
-            gen_helper_wfi(cpu_env);
-            /* The helper doesn't necessarily throw an exception, but we
-             * must go back to the main loop to check for interrupts anyway.
-             */
-            tcg_gen_exit_tb(0);
-            break;
-        }
-    }
-
 done_generating:
     gen_tb_end(tb, dc->base.num_insns);
 

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 25/27] target/arm: [tcg] Port to disas_log
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (23 preceding siblings ...)
  2017-07-07 13:18 ` [Qemu-devel] [PATCH v12 24/27] target/arm: [tcg, a64] " Lluís Vilanova
@ 2017-07-07 13:23 ` Lluís Vilanova
  2017-07-12  9:41   ` Alex Bennée
  2017-07-07 13:27 ` [Qemu-devel] [PATCH v12 26/27] target/arm: [tcg, a64] " Lluís Vilanova
                   ` (2 subsequent siblings)
  27 siblings, 1 reply; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 13:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Peter Maydell, open list:ARM

Incrementally paves the way towards using the generic instruction translation
loop.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target/arm/translate.c |   13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/target/arm/translate.c b/target/arm/translate.c
index 00cac01d66..5db381491f 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -12133,6 +12133,15 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
     }
 }
 
+static void arm_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu)
+{
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+
+    qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
+    log_target_disas(cpu, dc->base.pc_first, dc->pc - dc->base.pc_first,
+                     dc->thumb | (dc->sctlr_b << 1));
+}
+
 /* generate intermediate code for basic block 'tb'.  */
 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
 {
@@ -12236,9 +12245,7 @@ done_generating:
         qemu_log_in_addr_range(dc->base.pc_first)) {
         qemu_log_lock();
         qemu_log("----------------\n");
-        qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
-        log_target_disas(cs, dc->base.pc_first, dc->pc - dc->base.pc_first,
-                         dc->thumb | (dc->sctlr_b << 1));
+        arm_tr_disas_log(&dc->base, cs);
         qemu_log("\n");
         qemu_log_unlock();
     }

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 26/27] target/arm: [tcg, a64] Port to disas_log
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (24 preceding siblings ...)
  2017-07-07 13:23 ` [Qemu-devel] [PATCH v12 25/27] target/arm: [tcg] Port to disas_log Lluís Vilanova
@ 2017-07-07 13:27 ` Lluís Vilanova
  2017-07-07 13:31 ` [Qemu-devel] [PATCH v12 27/27] target/arm: [tcg] Port to generic translation framework Lluís Vilanova
  2017-07-12  9:47 ` [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic " Alex Bennée
  27 siblings, 0 replies; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 13:27 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Peter Maydell, open list:ARM

Incrementally paves the way towards using the generic instruction translation
loop.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target/arm/translate-a64.c |   14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index cead9d382c..ea60d43a95 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -11379,6 +11379,16 @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
     }
 }
 
+static void aarch64_tr_disas_log(const DisasContextBase *dcbase,
+                                      CPUState *cpu)
+{
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+
+    qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
+    log_target_disas(cpu, dc->base.pc_first, dc->pc - dc->base.pc_first,
+                     4 | (bswap_code(dc->sctlr_b) ? 2 : 0));
+}
+
 void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
                                TranslationBlock *tb)
 {
@@ -11475,9 +11485,7 @@ done_generating:
         qemu_log_in_addr_range(dc->base.pc_first)) {
         qemu_log_lock();
         qemu_log("----------------\n");
-        qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
-        log_target_disas(cs, dc->base.pc_first, dc->pc - dc->base.pc_first,
-                         4 | (bswap_code(dc->sctlr_b) ? 2 : 0));
+        aarch64_tr_disas_log(&dc->base, cs);
         qemu_log("\n");
         qemu_log_unlock();
     }

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [Qemu-devel] [PATCH v12 27/27] target/arm: [tcg] Port to generic translation framework
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (25 preceding siblings ...)
  2017-07-07 13:27 ` [Qemu-devel] [PATCH v12 26/27] target/arm: [tcg, a64] " Lluís Vilanova
@ 2017-07-07 13:31 ` Lluís Vilanova
  2017-07-12  9:47 ` [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic " Alex Bennée
  27 siblings, 0 replies; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-07 13:31 UTC (permalink / raw)
  To: qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Richard Henderson,
	Peter Crosthwaite, Paolo Bonzini, Peter Maydell, open list:ARM

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
---
 target/arm/translate-a64.c |  120 ++++++-------------------------------------
 target/arm/translate.c     |  124 +++++++-------------------------------------
 target/arm/translate.h     |    8 ---
 3 files changed, 37 insertions(+), 215 deletions(-)

diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index ea60d43a95..b569144ed9 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -11250,6 +11250,10 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
     init_tmp_a64_array(dc);
 }
 
+static void aarch64_tr_tb_start(DisasContextBase *db, CPUState *cpu)
+{
+}
+
 static void aarch64_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
 {
     DisasContext *dc = container_of(dcbase, DisasContext, base);
@@ -11377,6 +11381,9 @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
             break;
         }
     }
+
+    /* Functions above can change dc->pc, so re-align db->pc_next */
+    dc->base.pc_next = dc->pc;
 }
 
 static void aarch64_tr_disas_log(const DisasContextBase *dcbase,
@@ -11389,107 +11396,12 @@ static void aarch64_tr_disas_log(const DisasContextBase *dcbase,
                      4 | (bswap_code(dc->sctlr_b) ? 2 : 0));
 }
 
-void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
-                               TranslationBlock *tb)
-{
-    DisasContext *dc = container_of(dcbase, DisasContext, base);
-    int max_insns;
-
-    dc->base.tb = tb;
-    dc->base.pc_first = dc->base.tb->pc;
-    dc->base.pc_next = dc->base.pc_first;
-    dc->base.is_jmp = DISAS_NEXT;
-    dc->base.num_insns = 0;
-    dc->base.singlestep_enabled = cs->singlestep_enabled;
-    aarch64_tr_init_disas_context(&dc->base, cs);
-
-    max_insns = dc->base.tb->cflags & CF_COUNT_MASK;
-    if (max_insns == 0) {
-        max_insns = CF_COUNT_MASK;
-    }
-    if (max_insns > TCG_MAX_INSNS) {
-        max_insns = TCG_MAX_INSNS;
-    }
-
-    gen_tb_start(tb);
-
-    tcg_clear_temp_count();
-
-    do {
-        dc->base.num_insns++;
-        aarch64_tr_insn_start(&dc->base, cs);
-
-        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
-            CPUBreakpoint *bp;
-            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
-                if (bp->pc == dc->base.pc_next) {
-                    BreakpointCheckType bp_check =
-                        aarch64_tr_breakpoint_check(&dc->base, cs, bp);
-                    switch (bp_check) {
-                    case BC_MISS:
-                        /* Target ignored this breakpoint, go to next */
-                        break;
-                    case BC_HIT_INSN:
-                        /* Hit, keep translating */
-                        /*
-                         * TODO: if we're never going to have more than one
-                         *       BP in a single address, we can simply use a
-                         *       bool here.
-                         */
-                        goto done_breakpoints;
-                    case BC_HIT_TB:
-                        /* Hit, end TB */
-                        goto done_generating;
-                    default:
-                        g_assert_not_reached();
-                    }
-                }
-            }
-        }
-    done_breakpoints:
-
-        if (dc->base.num_insns == max_insns && (dc->base.tb->cflags & CF_LAST_IO)) {
-            gen_io_start();
-        }
-
-        dc->base.pc_next = aarch64_tr_translate_insn(&dc->base, cs);
-
-        if (tcg_check_temp_count()) {
-            fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
-                    dc->pc);
-        }
-
-        if (!dc->base.is_jmp && (tcg_op_buf_full() || cs->singlestep_enabled ||
-                            singlestep || dc->base.num_insns >= max_insns)) {
-            dc->base.is_jmp = DISAS_TOO_MANY;
-        }
-
-        /* Translation stops when a conditional branch is encountered.
-         * Otherwise the subsequent code could get translated several times.
-         * Also stop translation when a page boundary is reached.  This
-         * ensures prefetch aborts occur at the right place.
-         */
-    } while (!dc->base.is_jmp);
-
-    aarch64_tr_tb_stop(&dc->base, cs);
-
-    if (dc->base.tb->cflags & CF_LAST_IO) {
-        gen_io_end();
-    }
-
-done_generating:
-    gen_tb_end(tb, dc->base.num_insns);
-
-#ifdef DEBUG_DISAS
-    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) &&
-        qemu_log_in_addr_range(dc->base.pc_first)) {
-        qemu_log_lock();
-        qemu_log("----------------\n");
-        aarch64_tr_disas_log(&dc->base, cs);
-        qemu_log("\n");
-        qemu_log_unlock();
-    }
-#endif
-    dc->base.tb->size = dc->pc - dc->base.pc_first;
-    dc->base.tb->icount = dc->base.num_insns;
-}
+const TranslatorOps aarch64_translator_ops = {
+    .init_disas_context = aarch64_tr_init_disas_context,
+    .tb_start = aarch64_tr_tb_start,
+    .insn_start = aarch64_tr_insn_start,
+    .breakpoint_check = aarch64_tr_breakpoint_check,
+    .translate_insn = aarch64_tr_translate_insn,
+    .tb_stop = aarch64_tr_tb_stop,
+    .disas_log = aarch64_tr_disas_log,
+};
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 5db381491f..bb6be76696 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -12131,6 +12131,9 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
             gen_goto_tb(dc, 1, dc->pc);
         }
     }
+
+    /* Functions above can change dc->pc, so re-align db->pc_next */
+    dc->base.pc_next = dc->pc;
 }
 
 static void arm_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu)
@@ -12142,116 +12145,29 @@ static void arm_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu)
                      dc->thumb | (dc->sctlr_b << 1));
 }
 
+static const TranslatorOps arm_translator_ops = {
+    .init_disas_context = arm_tr_init_disas_context,
+    .tb_start = arm_tr_tb_start,
+    .insn_start = arm_tr_insn_start,
+    .breakpoint_check = arm_tr_breakpoint_check,
+    .translate_insn = arm_tr_translate_insn,
+    .tb_stop = arm_tr_tb_stop,
+    .disas_log = arm_tr_disas_log,
+};
+
 /* generate intermediate code for basic block 'tb'.  */
-void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
 {
-    DisasContext dc1, *dc = &dc1;
-    int max_insns;
+    DisasContext dc;
+    const TranslatorOps *ops = &arm_translator_ops;
 
-    /* generate intermediate code */
-
-    /* The A64 decoder has its own top level loop, because it doesn't need
-     * the A32/T32 complexity to do with conditional execution/IT blocks/etc.
-     */
+#ifdef TARGET_AARCH64
     if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
-        gen_intermediate_code_a64(&dc->base, cs, tb);
-        return;
-    }
-
-    dc->base.tb = tb;
-    dc->base.pc_first = dc->base.tb->pc;
-    dc->base.pc_next = dc->base.pc_first;
-    dc->base.is_jmp = DISAS_NEXT;
-    dc->base.num_insns = 0;
-    dc->base.singlestep_enabled = cs->singlestep_enabled;
-    arm_tr_init_disas_context(&dc->base, cs);
-
-
-    arm_tr_init_globals(&dc->base, cs);
-    max_insns = tb->cflags & CF_COUNT_MASK;
-    if (max_insns == 0) {
-        max_insns = CF_COUNT_MASK;
-    }
-    if (max_insns > TCG_MAX_INSNS) {
-        max_insns = TCG_MAX_INSNS;
-    }
-
-    gen_tb_start(tb);
-
-    tcg_clear_temp_count();
-    arm_tr_tb_start(&dc->base, cs);
-
-    do {
-        dc->base.num_insns++;
-        arm_tr_insn_start(&dc->base, cs);
-
-        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
-            CPUBreakpoint *bp;
-            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
-                if (bp->pc == dc->base.pc_next) {
-                    BreakpointCheckType bp_check =
-                        arm_tr_breakpoint_check(&dc->base, cs, bp);
-                    switch (bp_check) {
-                    case BC_MISS:
-                        /* Target ignored this breakpoint, go to next */
-                        break;
-                    case BC_HIT_INSN:
-                        /* Hit, keep translating */
-                        /*
-                         * TODO: if we're never going to have more than one
-                         *       BP in a single address, we can simply use a
-                         *       bool here.
-                         */
-                        goto done_breakpoints;
-                    case BC_HIT_TB:
-                        /* Hit, end TB */
-                        goto done_generating;
-                    default:
-                        g_assert_not_reached();
-                    }
-                }
-            }
-        }
-    done_breakpoints:
-
-        if (dc->base.num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
-            gen_io_start();
-        }
-
-        dc->base.pc_next = arm_tr_translate_insn(&dc->base, cs);
-
-        if (tcg_check_temp_count()) {
-            fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
-                    dc->pc);
-        }
-
-        if (!dc->base.is_jmp && (tcg_op_buf_full() || singlestep ||
-                            dc->base.num_insns >= max_insns)) {
-            dc->base.is_jmp = DISAS_TOO_MANY;
-        }
-    } while (!dc->base.is_jmp);
-
-    arm_tr_tb_stop(&dc->base, cs);
-
-    if (dc->base.tb->cflags & CF_LAST_IO) {
-        gen_io_end();
-    }
-
-done_generating:
-    gen_tb_end(tb, dc->base.num_insns);
-
-#ifdef DEBUG_DISAS
-    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) &&
-        qemu_log_in_addr_range(dc->base.pc_first)) {
-        qemu_log_lock();
-        qemu_log("----------------\n");
-        arm_tr_disas_log(&dc->base, cs);
-        qemu_log("\n");
-        qemu_log_unlock();
+        ops = &aarch64_translator_ops;
     }
 #endif
-    tb->size = dc->pc - dc->base.pc_first;
-    tb->icount = dc->base.num_insns;
+
+    translator_loop(ops, &dc.base, cpu, tb);
 }
 
 static const char *cpu_mode_names[16] = {
diff --git a/target/arm/translate.h b/target/arm/translate.h
index 83e56dcb08..69d4b2f082 100644
--- a/target/arm/translate.h
+++ b/target/arm/translate.h
@@ -153,21 +153,15 @@ static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
 
 #ifdef TARGET_AARCH64
 void a64_translate_init(void);
-void gen_intermediate_code_a64(DisasContextBase *db, CPUState *cpu,
-                               TranslationBlock *tb);
 void gen_a64_set_pc_im(uint64_t val);
 void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
                             fprintf_function cpu_fprintf, int flags);
+extern const TranslatorOps aarch64_translator_ops;
 #else
 static inline void a64_translate_init(void)
 {
 }
 
-static inline void gen_intermediate_code_a64(DisasContextBase *db, CPUState *cpu,
-                                             TranslationBlock *tb)
-{
-}
-
 static inline void gen_a64_set_pc_im(uint64_t val)
 {
 }

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 04/27] target: [tcg] Add generic translation framework
  2017-07-07 11:56 ` [Qemu-devel] [PATCH v12 04/27] target: [tcg] Add generic translation framework Lluís Vilanova
@ 2017-07-07 18:42   ` Richard Henderson
  2017-07-11 16:40     ` Lluís Vilanova
  2017-07-11 18:17   ` Alex Bennée
  1 sibling, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2017-07-07 18:42 UTC (permalink / raw)
  To: Lluís Vilanova, qemu-devel
  Cc: Emilio G. Cota, Alex Bennée, Peter Crosthwaite, Paolo Bonzini

On 07/07/2017 01:56 AM, Lluís Vilanova wrote:
> +void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
> +                     CPUState *cpu, TranslationBlock *tb)
> +{
> +    int max_insns;
> +
> +    /* Initialize DisasContext */
> +    db->tb = tb;
> +    db->pc_first = tb->pc;
> +    db->pc_next = db->pc_first;
> +    db->is_jmp = DISAS_NEXT;
> +    db->num_insns = 0;
> +    db->singlestep_enabled = cpu->singlestep_enabled;
> +    ops->init_disas_context(db, cpu);
> +
> +    /* Initialize globals */
> +    tcg_clear_temp_count();

The comment is out of date.  But perhaps just expand a bit,

   Now that globals are created, reset the temp count so that
   we can identify leaks.

> +
> +    /* Instruction counting */
> +    max_insns = db->tb->cflags & CF_COUNT_MASK;
> +    if (max_insns == 0) {
> +        max_insns = CF_COUNT_MASK;
> +    }
> +    if (max_insns > TCG_MAX_INSNS) {
> +        max_insns = TCG_MAX_INSNS;
> +    }
> +    if (db->singlestep_enabled || singlestep) {
> +        max_insns = 1;
> +    }
> +
> +    /* Start translating */
> +    gen_tb_start(db->tb);
> +    ops->tb_start(db, cpu);

As I mentioned, we need some way to modify max_insns before the loop start.

(For the ultimate in max_insns modifying needs, see the sh4 patch set I posted 
this morning, wherein I may *extend* max_insns in order to force it to cover a 
region to be executed atomically within one TB, within the lock held by 
cpu_exec_step_atomic.)

Based on that, I recommend

     DisasJumpType status;
     status = ops->tb_start(db, cpu, &max_insns);

Because in my sh4 case, tb_start might itself decide that the only way to 
handle the code is to raise the EXCP_ATOMIC exception and try again within 
cpu_exec_step_atomic.  Which means that we would not enter the while loop at 
all.  Thus,

> +    while (true) {

     while (status == DISAS_NEXT) {

> +        db->num_insns++;
> +        ops->insn_start(db, cpu);
> +
> +        /* Early exit before breakpoint checks */

Better comment maybe?  "The insn_start hook may request early exit..."

And, indeed, perhaps

     status = ops->insn_start(db, cpu);
     if (unlikely(status != DISAS_NEXT)) {
         break;
     }

> +        if (unlikely(db->is_jmp != DISAS_NEXT)) {
> +            break;
> +        }
> +
> +        /* Pass breakpoint hits to target for further processing */
> +        if (unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
> +            CPUBreakpoint *bp;
> +            QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
> +                if (bp->pc == db->pc_next) {
> +                    BreakpointCheckType bp_check =
> +                        ops->breakpoint_check(db, cpu, bp);
> +                    switch (bp_check) {
> +                    case BC_MISS:
> +                        /* Target ignored this breakpoint, go to next */
> +                        break;
> +                    case BC_HIT_INSN:
> +                        /* Hit, keep translating */
> +                        /*
> +                         * TODO: if we're never going to have more than one
> +                         *       BP in a single address, we can simply use a
> +                         *       bool here.
> +                         */
> +                        goto done_breakpoints;
> +                    case BC_HIT_TB:
> +                        /* Hit, end TB */
> +                        goto done_generating;
> +                    default:
> +                        g_assert_not_reached();
> +                    }
> +                }
> +            }
> +        }
> +    done_breakpoints:
> +
> +        /* Accept I/O on last instruction */
> +        if (db->num_insns == max_insns && (db->tb->cflags & CF_LAST_IO)) {
> +            gen_io_start();
> +        }
> +
> +        /* Disassemble one instruction */
> +        db->pc_next = ops->translate_insn(db, cpu);

I think it would be better to assign to pc_next within the hook.  We don't use 
the value otherwise within the rest of the loop.

But we do use is_jmp, immediately.  So maybe better to follow the changes to 
tb_start and insn_start above.

> +    }
> +
> +    ops->tb_stop(db, cpu);
> +
> +    if (db->tb->cflags & CF_LAST_IO) {
> +        gen_io_end();
> +    }

You can't place this after tb_stop, as it'll never be executed.  We will have 
for certain emitted the exit_tb for all paths by now.

Just place it before tb_stop where it usually resides.  In the case where some 
is_jmp value implies unreached code, and we're using icount, we'll accept the 
dead code.  But in all other cases it will get executed.


r~

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 04/27] target: [tcg] Add generic translation framework
  2017-07-07 18:42   ` Richard Henderson
@ 2017-07-11 16:40     ` Lluís Vilanova
  2017-07-11 17:21       ` Richard Henderson
  0 siblings, 1 reply; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-11 16:40 UTC (permalink / raw)
  To: Richard Henderson
  Cc: qemu-devel, Emilio G. Cota, Alex Bennée, Peter Crosthwaite,
	Paolo Bonzini

Richard Henderson writes:

> On 07/07/2017 01:56 AM, Lluís Vilanova wrote:
[...]
>> +
>> +    /* Instruction counting */
>> +    max_insns = db->tb->cflags & CF_COUNT_MASK;
>> +    if (max_insns == 0) {
>> +        max_insns = CF_COUNT_MASK;
>> +    }
>> +    if (max_insns > TCG_MAX_INSNS) {
>> +        max_insns = TCG_MAX_INSNS;
>> +    }
>> +    if (db->singlestep_enabled || singlestep) {
>> +        max_insns = 1;
>> +    }
>> +
>> +    /* Start translating */
>> +    gen_tb_start(db->tb);
>> +    ops->tb_start(db, cpu);

> As I mentioned, we need some way to modify max_insns before the loop start.

> (For the ultimate in max_insns modifying needs, see the sh4 patch set I posted
> this morning, wherein I may *extend* max_insns in order to force it to cover a
> region to be executed atomically within one TB, within the lock held by
> cpu_exec_step_atomic.)

> Based on that, I recommend

>     DisasJumpType status;
>     status = ops->tb_start(db, cpu, &max_insns);

> Because in my sh4 case, tb_start might itself decide that the only way to handle
> the code is to raise the EXCP_ATOMIC exception and try again within
> cpu_exec_step_atomic.  Which means that we would not enter the while loop at
> all.  Thus,

>> +    while (true) {

>     while (status == DISAS_NEXT) {

>> +        db->num_insns++;
>> +        ops->insn_start(db, cpu);
>> +
>> +        /* Early exit before breakpoint checks */

> Better comment maybe?  "The insn_start hook may request early exit..."

> And, indeed, perhaps

>     status = ops->insn_start(db, cpu);
>     if (unlikely(status != DISAS_NEXT)) {
>         break;
>     }

Since other hooks can set db->is_jmp and return values (breakpoint_check), I'll
stick with db->is_jmp instead. Then tb_start can return max_insns, and generic
code can refine it with checks like single-stepping.


>> +        if (unlikely(db->is_jmp != DISAS_NEXT)) {
>> +            break;
>> +        }
>> +
>> +        /* Pass breakpoint hits to target for further processing */
>> +        if (unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
>> +            CPUBreakpoint *bp;
>> +            QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
>> +                if (bp->pc == db->pc_next) {
>> +                    BreakpointCheckType bp_check =
>> +                        ops->breakpoint_check(db, cpu, bp);
>> +                    switch (bp_check) {
>> +                    case BC_MISS:
>> +                        /* Target ignored this breakpoint, go to next */
>> +                        break;
>> +                    case BC_HIT_INSN:
>> +                        /* Hit, keep translating */
>> +                        /*
>> +                         * TODO: if we're never going to have more than one
>> +                         *       BP in a single address, we can simply use a
>> +                         *       bool here.
>> +                         */
>> +                        goto done_breakpoints;
>> +                    case BC_HIT_TB:
>> +                        /* Hit, end TB */
>> +                        goto done_generating;
>> +                    default:
>> +                        g_assert_not_reached();
>> +                    }
>> +                }
>> +            }
>> +        }
>> +    done_breakpoints:
>> +
>> +        /* Accept I/O on last instruction */
>> +        if (db->num_insns == max_insns && (db->tb->cflags & CF_LAST_IO)) {
>> +            gen_io_start();
>> +        }
>> +
>> +        /* Disassemble one instruction */
>> +        db->pc_next = ops->translate_insn(db, cpu);

> I think it would be better to assign to pc_next within the hook.  We don't use
> the value otherwise within the rest of the loop.

> But we do use is_jmp, immediately.  So maybe better to follow the changes to
> tb_start and insn_start above.

As before, for consistency I prefer to set is_jmp instead of returning it on
hooks, since breakpoint_check() already has a return value and can set is_jmp.

Then, a future series adding tracing events to this loop uses db->pc_next in the
generic loop, so it is going to be used.


>> +    }
>> +
>> +    ops->tb_stop(db, cpu);
>> +
>> +    if (db->tb->cflags & CF_LAST_IO) {
>> +        gen_io_end();
>> +    }

> You can't place this after tb_stop, as it'll never be executed.  We will have
> for certain emitted the exit_tb for all paths by now.

> Just place it before tb_stop where it usually resides.  In the case where some
> is_jmp value implies unreached code, and we're using icount, we'll accept the
> dead code.  But in all other cases it will get executed.

Ok!


Thanks,
  Lluis

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 04/27] target: [tcg] Add generic translation framework
  2017-07-11 16:40     ` Lluís Vilanova
@ 2017-07-11 17:21       ` Richard Henderson
  2017-07-12  8:50         ` Lluís Vilanova
  0 siblings, 1 reply; 57+ messages in thread
From: Richard Henderson @ 2017-07-11 17:21 UTC (permalink / raw)
  To: qemu-devel, Emilio G. Cota, Alex Bennée, Peter Crosthwaite,
	Paolo Bonzini

On 07/11/2017 06:40 AM, Lluís Vilanova wrote:
> Since other hooks can set db->is_jmp and return values (breakpoint_check), I'll
> stick with db->is_jmp instead. Then tb_start can return max_insns, and generic
> code can refine it with checks like single-stepping.

No, you misunderstand.  For SH4 I need to override single-stepping, icount, and 
anything else that produces a TB smaller than the atomic region.


r~

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 04/27] target: [tcg] Add generic translation framework
  2017-07-07 11:56 ` [Qemu-devel] [PATCH v12 04/27] target: [tcg] Add generic translation framework Lluís Vilanova
  2017-07-07 18:42   ` Richard Henderson
@ 2017-07-11 18:17   ` Alex Bennée
  2017-07-12  8:59     ` Lluís Vilanova
  1 sibling, 1 reply; 57+ messages in thread
From: Alex Bennée @ 2017-07-11 18:17 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Emilio G. Cota, Richard Henderson, Peter Crosthwaite,
	Paolo Bonzini


Lluís Vilanova <vilanova@ac.upc.edu> writes:

> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> ---
>  accel/tcg/Makefile.objs   |    1
>  accel/tcg/translator.c    |  152 +++++++++++++++++++++++++++++++++++++++++++++
>  include/exec/gen-icount.h |    2 -
>  include/exec/translator.h |   99 +++++++++++++++++++++++++++++
>  4 files changed, 253 insertions(+), 1 deletion(-)
>  create mode 100644 accel/tcg/translator.c
>
> diff --git a/accel/tcg/Makefile.objs b/accel/tcg/Makefile.objs
> index f173cd5397..3a5da5357c 100644
> --- a/accel/tcg/Makefile.objs
> +++ b/accel/tcg/Makefile.objs
> @@ -1,3 +1,4 @@
>  obj-$(CONFIG_SOFTMMU) += tcg-all.o
>  obj-$(CONFIG_SOFTMMU) += cputlb.o
>  obj-y += cpu-exec.o cpu-exec-common.o translate-all.o translate-common.o
> +obj-y += translator.o

There is a merge conflict here with the current master.

> diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
> new file mode 100644
> index 0000000000..9e0343cbb1
> --- /dev/null
> +++ b/accel/tcg/translator.c
> @@ -0,0 +1,152 @@
> +/*
> + * Generic intermediate code generation.
> + *
> + * Copyright (C) 2016-2017 Lluís Vilanova <vilanova@ac.upc.edu>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu-common.h"
> +#include "qemu/error-report.h"
> +#include "cpu.h"
> +#include "tcg/tcg.h"
> +#include "tcg/tcg-op.h"
> +#include "exec/exec-all.h"
> +#include "exec/gen-icount.h"
> +#include "exec/log.h"
> +#include "exec/translator.h"
> +
> +
> +static inline void translate_block_tcg_check(const DisasContextBase *db)
> +{
> +    if (tcg_check_temp_count()) {
> +        error_report("warning: TCG temporary leaks before "TARGET_FMT_lx,
> +                     db->pc_next);
> +    }
> +}
> +
> +void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
> +                     CPUState *cpu, TranslationBlock *tb)
> +{
> +    int max_insns;
> +
> +    /* Initialize DisasContext */
> +    db->tb = tb;
> +    db->pc_first = tb->pc;
> +    db->pc_next = db->pc_first;
> +    db->is_jmp = DISAS_NEXT;
> +    db->num_insns = 0;
> +    db->singlestep_enabled = cpu->singlestep_enabled;
> +    ops->init_disas_context(db, cpu);
> +
> +    /* Initialize globals */
> +    tcg_clear_temp_count();
> +
> +    /* Instruction counting */
> +    max_insns = db->tb->cflags & CF_COUNT_MASK;
> +    if (max_insns == 0) {
> +        max_insns = CF_COUNT_MASK;
> +    }
> +    if (max_insns > TCG_MAX_INSNS) {
> +        max_insns = TCG_MAX_INSNS;
> +    }
> +    if (db->singlestep_enabled || singlestep) {
> +        max_insns = 1;
> +    }
> +
> +    /* Start translating */
> +    gen_tb_start(db->tb);
> +    ops->tb_start(db, cpu);
> +
> +    while (true) {
> +        db->num_insns++;
> +        ops->insn_start(db, cpu);
> +
> +        /* Early exit before breakpoint checks */
> +        if (unlikely(db->is_jmp != DISAS_NEXT)) {
> +            break;
> +        }
> +
> +        /* Pass breakpoint hits to target for further processing */
> +        if (unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
> +            CPUBreakpoint *bp;
> +            QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
> +                if (bp->pc == db->pc_next) {
> +                    BreakpointCheckType bp_check =
> +                        ops->breakpoint_check(db, cpu, bp);
> +                    switch (bp_check) {
> +                    case BC_MISS:
> +                        /* Target ignored this breakpoint, go to next */
> +                        break;
> +                    case BC_HIT_INSN:
> +                        /* Hit, keep translating */
> +                        /*
> +                         * TODO: if we're never going to have more than one
> +                         *       BP in a single address, we can simply use a
> +                         *       bool here.
> +                         */
> +                        goto done_breakpoints;
> +                    case BC_HIT_TB:
> +                        /* Hit, end TB */
> +                        goto done_generating;
> +                    default:
> +                        g_assert_not_reached();
> +                    }
> +                }
> +            }
> +        }
> +    done_breakpoints:

For the sake of keeping the core loop easy to follow maybe it would be
better to have a helper function for the breakpoint handling? Really
there is only one result from the helper which is do we continue the
loop or jump to done_generating.

> +
> +        /* Accept I/O on last instruction */
> +        if (db->num_insns == max_insns && (db->tb->cflags & CF_LAST_IO)) {
> +            gen_io_start();
> +        }
> +
> +        /* Disassemble one instruction */
> +        db->pc_next = ops->translate_insn(db, cpu);
> +
> +        /**************************************************/
> +        /* Conditions to stop translation                 */
> +        /**************************************************/
> +
> +        /* Target-specific conditions set by disassembly */
> +        if (db->is_jmp != DISAS_NEXT) {
> +            break;
> +        }
> +
> +        /* Too many instructions */
> +        if (tcg_op_buf_full() || db->num_insns >= max_insns) {
> +            db->is_jmp = DISAS_TOO_MANY;
> +            break;
> +        }
> +
> +        translate_block_tcg_check(db);
> +    }

This may be a personal taste thing but having while(true) {} and breaks
is harder to follow than do { stuff } while (!done);

> +
> +    ops->tb_stop(db, cpu);
> +
> +    if (db->tb->cflags & CF_LAST_IO) {
> +        gen_io_end();
> +    }
> +
> +done_generating:
> +    gen_tb_end(db->tb, db->num_insns);
> +
> +    translate_block_tcg_check(db);
> +
> +#ifdef DEBUG_DISAS
> +    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
> +        && qemu_log_in_addr_range(db->pc_first)) {
> +        qemu_log_lock();
> +        qemu_log("----------------\n");
> +        ops->disas_log(db, cpu);
> +        qemu_log("\n");
> +        qemu_log_unlock();
> +    }
> +#endif
> +
> +    db->tb->size = db->pc_next - db->pc_first;
> +    db->tb->icount = db->num_insns;
> +}
> diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h
> index 6c28ef59c3..9b3cb14dfa 100644
> --- a/include/exec/gen-icount.h
> +++ b/include/exec/gen-icount.h
> @@ -44,7 +44,7 @@ static inline void gen_tb_start(TranslationBlock *tb)
>      tcg_temp_free_i32(count);
>  }
>
> -static void gen_tb_end(TranslationBlock *tb, int num_insns)
> +static inline void gen_tb_end(TranslationBlock *tb, int num_insns)
>  {
>      if (tb->cflags & CF_USE_ICOUNT) {
>          /* Update the num_insn immediate parameter now that we know
> diff --git a/include/exec/translator.h b/include/exec/translator.h
> index 1f9697dd31..f96b66f2bf 100644
> --- a/include/exec/translator.h
> +++ b/include/exec/translator.h
> @@ -10,6 +10,38 @@
>  #ifndef EXEC__TRANSLATOR_H
>  #define EXEC__TRANSLATOR_H
>
> +/*
> + * Include this header from a target-specific file, and add a
> + *
> + *     DisasContextBase base;
> + *
> + * member in your target-specific DisasContext.
> + */
> +
> +
> +#include "exec/exec-all.h"
> +#include "tcg/tcg.h"
> +
> +
> +/**
> + * BreakpointCheckType:
> + * @BC_MISS: No hit
> + * @BC_HIT_INSN: Hit, but continue translating TB
> + * @BC_HIT_TB: Hit, stop translating TB
> + *
> + * How to react to a breakpoint. A hit means no more breakpoints will be checked
> + * for the current instruction.
> + *
> + * Not all breakpoints associated to an address are necessarily raised by
> + * targets (e.g., due to conditions encoded in their flags), so they can decide
> + * that a breakpoint missed the address (@BP_MISS).
> + */
> +typedef enum BreakpointCheckType {
> +    BC_MISS,
> +    BC_HIT_INSN,
> +    BC_HIT_TB,
> +} BreakpointCheckType;
> +
>  /**
>   * DisasJumpType:
>   * @DISAS_NEXT: Next instruction in program order.
> @@ -36,4 +68,71 @@ typedef enum DisasJumpType {
>      DISAS_TARGET_12,
>  } DisasJumpType;
>
> +/**
> + * DisasContextBase:
> + * @tb: Translation block for this disassembly.
> + * @pc_first: Address of first guest instruction in this TB.
> + * @pc_next: Address of next guest instruction in this TB (current during
> + *           disassembly).
> + * @is_jmp: What instruction to disassemble next.
> + * @num_insns: Number of translated instructions (including current).
> + * @singlestep_enabled: "Hardware" single stepping enabled.
> + *
> + * Architecture-agnostic disassembly context.
> + */
> +typedef struct DisasContextBase {
> +    TranslationBlock *tb;
> +    target_ulong pc_first;
> +    target_ulong pc_next;
> +    DisasJumpType is_jmp;
> +    unsigned int num_insns;
> +    bool singlestep_enabled;
> +} DisasContextBase;
> +
> +/**
> + * TranslatorOps:
> + * @init_disas_context: Initialize a DisasContext struct (DisasContextBase has
> + *                      already been initialized).
> + * @tb_start: Start translating a new TB.
> + * @insn_start: Start translating a new instruction.
> + * @breakpoint_check: Check if a breakpoint did hit. When called, the breakpoint
> + *                    has already been checked to match the PC.
> + * @translate_insn: Disassemble one instruction and return the PC for the next
> + *                  one. Can set db->is_jmp to DISAS_TARGET or above to stop
> + *                  translation.
> + * @tb_stop: Stop translating a TB.
> + * @disas_log: Print instruction disassembly to log.
> + *
> + * Target-specific operations for the generic translator loop.
> + */
> +typedef struct TranslatorOps {
> +    void (*init_disas_context)(DisasContextBase *db, CPUState *cpu);
> +    void (*tb_start)(DisasContextBase *db, CPUState *cpu);
> +    void (*insn_start)(DisasContextBase *db, CPUState *cpu);
> +    BreakpointCheckType (*breakpoint_check)(DisasContextBase *db, CPUState *cpu,
> +                                            const CPUBreakpoint *bp);
> +    target_ulong (*translate_insn)(DisasContextBase *db, CPUState *cpu);
> +    void (*tb_stop)(DisasContextBase *db, CPUState *cpu);
> +    void (*disas_log)(const DisasContextBase *db, CPUState *cpu);
> +} TranslatorOps;
> +
> +/**
> + * translator_loop:
> + * @ops: Target-specific operations.
> + * @db: Disassembly context.
> + * @cpu: Target vCPU.
> + * @tb: Translation block.
> + *
> + * Generic translator loop.
> + *
> + * Translation will stop in the following cases (in order):
> + * - When set by #TranslatorOps::insn_start.
> + * - When set by #TranslatorOps::translate_insn.
> + * - When the TCG operation buffer is full.
> + * - When single-stepping is enabled (system-wide or on the current vCPU).
> + * - When too many instructions have been translated.
> + */
> +void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
> +                     CPUState *cpu, TranslationBlock *tb);
> +
>  #endif  /* EXEC__TRANSLATOR_H */


--
Alex Bennée

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 01/27] Pass generic CPUState to gen_intermediate_code()
  2017-07-07 11:44 ` [Qemu-devel] [PATCH v12 01/27] Pass generic CPUState to gen_intermediate_code() Lluís Vilanova
@ 2017-07-11 19:22   ` Alex Bennée
  0 siblings, 0 replies; 57+ messages in thread
From: Alex Bennée @ 2017-07-11 19:22 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Emilio G. Cota, Richard Henderson, Peter Crosthwaite,
	Paolo Bonzini, Peter Maydell, Edgar E. Iglesias, Eduardo Habkost,
	Michael Walle, Laurent Vivier, Aurelien Jarno, Yongbok Kim,
	Anthony Green, Chris Wulff, Marek Vasut, Stafford Horne,
	David Gibson, Alexander Graf, Mark Cave-Ayland, Artyom Tarasenko,
	Bastian Koppelmann, Guan Xuetao, Max Filippov, open list:ARM,
	open list:PowerPC


Lluís Vilanova <vilanova@ac.upc.edu> writes:

> Needed to implement a target-agnostic gen_intermediate_code() in the
> future.
>
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
> Reviewed-by: Richard Henderson <rth@twiddle.net>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  accel/tcg/translate-all.c     |    2 +-
>  include/exec/exec-all.h       |    2 +-
>  target/alpha/translate.c      |    5 ++---
>  target/arm/translate-a64.c    |    6 +++---
>  target/arm/translate.c        |    6 +++---
>  target/arm/translate.h        |    4 ++--
>  target/cris/translate.c       |    7 +++----
>  target/hppa/translate.c       |    5 ++---
>  target/i386/translate.c       |    5 ++---
>  target/lm32/translate.c       |    4 ++--
>  target/m68k/translate.c       |    5 ++---
>  target/microblaze/translate.c |    4 ++--
>  target/mips/translate.c       |    5 ++---
>  target/moxie/translate.c      |    4 ++--
>  target/nios2/translate.c      |    5 ++---
>  target/openrisc/translate.c   |    4 ++--
>  target/ppc/translate.c        |    5 ++---
>  target/s390x/translate.c      |    5 ++---
>  target/sh4/translate.c        |    5 ++---
>  target/sparc/translate.c      |    5 ++---
>  target/tilegx/translate.c     |    5 ++---
>  target/tricore/translate.c    |    5 ++---
>  target/unicore32/translate.c  |    5 ++---
>  target/xtensa/translate.c     |    5 ++---
>  24 files changed, 49 insertions(+), 64 deletions(-)
>
> diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
> index f6ad46b613..2dc93f420a 100644
> --- a/accel/tcg/translate-all.c
> +++ b/accel/tcg/translate-all.c
> @@ -1299,7 +1299,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
>      tcg_func_start(&tcg_ctx);
>
>      tcg_ctx.cpu = ENV_GET_CPU(env);
> -    gen_intermediate_code(env, tb);
> +    gen_intermediate_code(cpu, tb);
>      tcg_ctx.cpu = NULL;
>
>      trace_translate_block(tb, tb->pc, tb->tc_ptr);
> diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
> index 724ec73dce..0826894ec5 100644
> --- a/include/exec/exec-all.h
> +++ b/include/exec/exec-all.h
> @@ -43,7 +43,7 @@ typedef ram_addr_t tb_page_addr_t;
>
>  #include "qemu/log.h"
>
> -void gen_intermediate_code(CPUArchState *env, struct TranslationBlock *tb);
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb);
>  void restore_state_to_opc(CPUArchState *env, struct TranslationBlock *tb,
>                            target_ulong *data);
>
> diff --git a/target/alpha/translate.c b/target/alpha/translate.c
> index 232af9e177..7b39101053 100644
> --- a/target/alpha/translate.c
> +++ b/target/alpha/translate.c
> @@ -2911,10 +2911,9 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
>      return ret;
>  }
>
> -void gen_intermediate_code(CPUAlphaState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
>  {
> -    AlphaCPU *cpu = alpha_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUAlphaState *env = cs->env_ptr;
>      DisasContext ctx, *ctxp = &ctx;
>      target_ulong pc_start;
>      target_ulong pc_mask;
> diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
> index e55547d95d..f9bd1a9679 100644
> --- a/target/arm/translate-a64.c
> +++ b/target/arm/translate-a64.c
> @@ -11190,10 +11190,10 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
>      free_tmp_a64(s);
>  }
>
> -void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock *tb)
> +void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
>  {
> -    CPUState *cs = CPU(cpu);
> -    CPUARMState *env = &cpu->env;
> +    CPUARMState *env = cs->env_ptr;
> +    ARMCPU *cpu = arm_env_get_cpu(env);
>      DisasContext dc1, *dc = &dc1;
>      target_ulong pc_start;
>      target_ulong next_page_start;
> diff --git a/target/arm/translate.c b/target/arm/translate.c
> index 0862f9e4aa..e80cc357c1 100644
> --- a/target/arm/translate.c
> +++ b/target/arm/translate.c
> @@ -11787,10 +11787,10 @@ static bool insn_crosses_page(CPUARMState *env, DisasContext *s)
>  }
>
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>  {
> +    CPUARMState *env = cs->env_ptr;
>      ARMCPU *cpu = arm_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
>      DisasContext dc1, *dc = &dc1;
>      target_ulong pc_start;
>      target_ulong next_page_start;
> @@ -11804,7 +11804,7 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
>       * the A32/T32 complexity to do with conditional execution/IT blocks/etc.
>       */
>      if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
> -        gen_intermediate_code_a64(cpu, tb);
> +        gen_intermediate_code_a64(cs, tb);
>          return;
>      }
>
> diff --git a/target/arm/translate.h b/target/arm/translate.h
> index 15d383d9af..e5da614db5 100644
> --- a/target/arm/translate.h
> +++ b/target/arm/translate.h
> @@ -146,7 +146,7 @@ static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
>
>  #ifdef TARGET_AARCH64
>  void a64_translate_init(void);
> -void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock *tb);
> +void gen_intermediate_code_a64(CPUState *cpu, TranslationBlock *tb);
>  void gen_a64_set_pc_im(uint64_t val);
>  void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
>                              fprintf_function cpu_fprintf, int flags);
> @@ -155,7 +155,7 @@ static inline void a64_translate_init(void)
>  {
>  }
>
> -static inline void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock *tb)
> +static inline void gen_intermediate_code_a64(CPUState *cpu, TranslationBlock *tb)
>  {
>  }
>
> diff --git a/target/cris/translate.c b/target/cris/translate.c
> index 0ee05ca02d..12b96eb68f 100644
> --- a/target/cris/translate.c
> +++ b/target/cris/translate.c
> @@ -3080,10 +3080,9 @@ static unsigned int crisv32_decoder(CPUCRISState *env, DisasContext *dc)
>   */
>
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUCRISState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
>  {
> -    CRISCPU *cpu = cris_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUCRISState *env = cs->env_ptr;
>      uint32_t pc_start;
>      unsigned int insn_len;
>      struct DisasContext ctx;
> @@ -3105,7 +3104,7 @@ void gen_intermediate_code(CPUCRISState *env, struct TranslationBlock *tb)
>       * delayslot, like in real hw.
>       */
>      pc_start = tb->pc & ~1;
> -    dc->cpu = cpu;
> +    dc->cpu = cris_env_get_cpu(env);
>      dc->tb = tb;
>
>      dc->is_jmp = DISAS_NEXT;
> diff --git a/target/hppa/translate.c b/target/hppa/translate.c
> index e10abc5e04..900870cd5a 100644
> --- a/target/hppa/translate.c
> +++ b/target/hppa/translate.c
> @@ -3740,10 +3740,9 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
>      return gen_illegal(ctx);
>  }
>
> -void gen_intermediate_code(CPUHPPAState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
>  {
> -    HPPACPU *cpu = hppa_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUHPPAState *env = cs->env_ptr;
>      DisasContext ctx;
>      ExitStatus ret;
>      int num_insns, max_insns, i;
> diff --git a/target/i386/translate.c b/target/i386/translate.c
> index ed3b896db4..cab9e32f91 100644
> --- a/target/i386/translate.c
> +++ b/target/i386/translate.c
> @@ -8378,10 +8378,9 @@ void tcg_x86_init(void)
>  }
>
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUX86State *env, TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>  {
> -    X86CPU *cpu = x86_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUX86State *env = cs->env_ptr;
>      DisasContext dc1, *dc = &dc1;
>      target_ulong pc_ptr;
>      uint32_t flags;
> diff --git a/target/lm32/translate.c b/target/lm32/translate.c
> index 692882f447..f68f372f15 100644
> --- a/target/lm32/translate.c
> +++ b/target/lm32/translate.c
> @@ -1044,10 +1044,10 @@ static inline void decode(DisasContext *dc, uint32_t ir)
>  }
>
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPULM32State *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
>  {
> +    CPULM32State *env = cs->env_ptr;
>      LM32CPU *cpu = lm32_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
>      struct DisasContext ctx, *dc = &ctx;
>      uint32_t pc_start;
>      uint32_t next_page_start;
> diff --git a/target/m68k/translate.c b/target/m68k/translate.c
> index 7aa0fdc238..af19872e0b 100644
> --- a/target/m68k/translate.c
> +++ b/target/m68k/translate.c
> @@ -5369,10 +5369,9 @@ static void disas_m68k_insn(CPUM68KState * env, DisasContext *s)
>  }
>
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>  {
> -    M68kCPU *cpu = m68k_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUM68KState *env = cs->env_ptr;
>      DisasContext dc1, *dc = &dc1;
>      target_ulong pc_start;
>      int pc_offset;
> diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c
> index 0bb609513c..a180bc78ae 100644
> --- a/target/microblaze/translate.c
> +++ b/target/microblaze/translate.c
> @@ -1594,10 +1594,10 @@ static inline void decode(DisasContext *dc, uint32_t ir)
>  }
>
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
>  {
> +    CPUMBState *env = cs->env_ptr;
>      MicroBlazeCPU *cpu = mb_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
>      uint32_t pc_start;
>      struct DisasContext ctx;
>      struct DisasContext *dc = &ctx;
> diff --git a/target/mips/translate.c b/target/mips/translate.c
> index 559f8fed89..97314e470a 100644
> --- a/target/mips/translate.c
> +++ b/target/mips/translate.c
> @@ -19878,10 +19878,9 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
>      }
>  }
>
> -void gen_intermediate_code(CPUMIPSState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
>  {
> -    MIPSCPU *cpu = mips_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUMIPSState *env = cs->env_ptr;
>      DisasContext ctx;
>      target_ulong pc_start;
>      target_ulong next_page_start;
> diff --git a/target/moxie/translate.c b/target/moxie/translate.c
> index 0660b44c08..3cfd232558 100644
> --- a/target/moxie/translate.c
> +++ b/target/moxie/translate.c
> @@ -822,10 +822,10 @@ static int decode_opc(MoxieCPU *cpu, DisasContext *ctx)
>  }
>
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUMoxieState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
>  {
> +    CPUMoxieState *env = cs->env_ptr;
>      MoxieCPU *cpu = moxie_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
>      DisasContext ctx;
>      target_ulong pc_start;
>      int num_insns, max_insns;
> diff --git a/target/nios2/translate.c b/target/nios2/translate.c
> index 2f3c2e5dfb..8b97d6585f 100644
> --- a/target/nios2/translate.c
> +++ b/target/nios2/translate.c
> @@ -799,10 +799,9 @@ static void gen_exception(DisasContext *dc, uint32_t excp)
>  }
>
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUNios2State *env, TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>  {
> -    Nios2CPU *cpu = nios2_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUNios2State *env = cs->env_ptr;
>      DisasContext dc1, *dc = &dc1;
>      int num_insns;
>      int max_insns;
> diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c
> index e49518e893..a01413113b 100644
> --- a/target/openrisc/translate.c
> +++ b/target/openrisc/translate.c
> @@ -1518,10 +1518,10 @@ static void disas_openrisc_insn(DisasContext *dc, OpenRISCCPU *cpu)
>      }
>  }
>
> -void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
>  {
> +    CPUOpenRISCState *env = cs->env_ptr;
>      OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
>      struct DisasContext ctx, *dc = &ctx;
>      uint32_t pc_start;
>      uint32_t next_page_start;
> diff --git a/target/ppc/translate.c b/target/ppc/translate.c
> index c0cd64d927..acb6e881ad 100644
> --- a/target/ppc/translate.c
> +++ b/target/ppc/translate.c
> @@ -7203,10 +7203,9 @@ void ppc_cpu_dump_statistics(CPUState *cs, FILE*f,
>  }
>
>  /*****************************************************************************/
> -void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
>  {
> -    PowerPCCPU *cpu = ppc_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUPPCState *env = cs->env_ptr;
>      DisasContext ctx, *ctxp = &ctx;
>      opc_handler_t **table, *handler;
>      target_ulong pc_start;
> diff --git a/target/s390x/translate.c b/target/s390x/translate.c
> index 592d6b0f38..cd8c38d6d5 100644
> --- a/target/s390x/translate.c
> +++ b/target/s390x/translate.c
> @@ -5764,10 +5764,9 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s)
>      return ret;
>  }
>
> -void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
>  {
> -    S390CPU *cpu = s390_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUS390XState *env = cs->env_ptr;
>      DisasContext dc;
>      target_ulong pc_start;
>      uint64_t next_page_start;
> diff --git a/target/sh4/translate.c b/target/sh4/translate.c
> index 8bc132b27b..1a5ca39cd6 100644
> --- a/target/sh4/translate.c
> +++ b/target/sh4/translate.c
> @@ -1815,10 +1815,9 @@ static void decode_opc(DisasContext * ctx)
>      }
>  }
>
> -void gen_intermediate_code(CPUSH4State * env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
>  {
> -    SuperHCPU *cpu = sh_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUSH4State *env = cs->env_ptr;
>      DisasContext ctx;
>      target_ulong pc_start;
>      int num_insns;
> diff --git a/target/sparc/translate.c b/target/sparc/translate.c
> index aa6734d54e..293b9c65ea 100644
> --- a/target/sparc/translate.c
> +++ b/target/sparc/translate.c
> @@ -5747,10 +5747,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
>      }
>  }
>
> -void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
> +void gen_intermediate_code(CPUState *cs, TranslationBlock * tb)
>  {
> -    SPARCCPU *cpu = sparc_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUSPARCState *env = cs->env_ptr;
>      target_ulong pc_start, last_pc;
>      DisasContext dc1, *dc = &dc1;
>      int num_insns;
> diff --git a/target/tilegx/translate.c b/target/tilegx/translate.c
> index ff2ef7b63d..ace2830a84 100644
> --- a/target/tilegx/translate.c
> +++ b/target/tilegx/translate.c
> @@ -2370,12 +2370,11 @@ static void translate_one_bundle(DisasContext *dc, uint64_t bundle)
>      }
>  }
>
> -void gen_intermediate_code(CPUTLGState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
>  {
> -    TileGXCPU *cpu = tilegx_env_get_cpu(env);
> +    CPUTLGState *env = cs->env_ptr;
>      DisasContext ctx;
>      DisasContext *dc = &ctx;
> -    CPUState *cs = CPU(cpu);
>      uint64_t pc_start = tb->pc;
>      uint64_t next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
>      int num_insns = 0;
> diff --git a/target/tricore/translate.c b/target/tricore/translate.c
> index ddd2dd07dd..4e4198e887 100644
> --- a/target/tricore/translate.c
> +++ b/target/tricore/translate.c
> @@ -8782,10 +8782,9 @@ static void decode_opc(CPUTriCoreState *env, DisasContext *ctx, int *is_branch)
>      }
>  }
>
> -void gen_intermediate_code(CPUTriCoreState *env, struct TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
>  {
> -    TriCoreCPU *cpu = tricore_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUTriCoreState *env = cs->env_ptr;
>      DisasContext ctx;
>      target_ulong pc_start;
>      int num_insns, max_insns;
> diff --git a/target/unicore32/translate.c b/target/unicore32/translate.c
> index 666a2016a8..8f30cff932 100644
> --- a/target/unicore32/translate.c
> +++ b/target/unicore32/translate.c
> @@ -1869,10 +1869,9 @@ static void disas_uc32_insn(CPUUniCore32State *env, DisasContext *s)
>  }
>
>  /* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUUniCore32State *env, TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>  {
> -    UniCore32CPU *cpu = uc32_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUUniCore32State *env = cs->env_ptr;
>      DisasContext dc1, *dc = &dc1;
>      target_ulong pc_start;
>      uint32_t next_page_start;
> diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
> index 263002486c..f3f0ff589c 100644
> --- a/target/xtensa/translate.c
> +++ b/target/xtensa/translate.c
> @@ -3117,10 +3117,9 @@ static void gen_ibreak_check(CPUXtensaState *env, DisasContext *dc)
>      }
>  }
>
> -void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
> +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>  {
> -    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> -    CPUState *cs = CPU(cpu);
> +    CPUXtensaState *env = cs->env_ptr;
>      DisasContext dc;
>      int insn_count = 0;
>      int max_insns = tb->cflags & CF_COUNT_MASK;


--
Alex Bennée

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 02/27] cpu-exec: Avoid global variables in icount-related functions
  2017-07-07 11:48 ` [Qemu-devel] [PATCH v12 02/27] cpu-exec: Avoid global variables in icount-related functions Lluís Vilanova
@ 2017-07-11 19:25   ` Alex Bennée
  2017-07-12  8:42     ` Lluís Vilanova
  0 siblings, 1 reply; 57+ messages in thread
From: Alex Bennée @ 2017-07-11 19:25 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Emilio G. Cota, Richard Henderson, Peter Crosthwaite,
	Paolo Bonzini


Lluís Vilanova <vilanova@ac.upc.edu> writes:

> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>

I guess. I assume this is also something Emilio is targeting with his
multi-threaded translation work.

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  include/exec/gen-icount.h |   10 ++++++----
>  1 file changed, 6 insertions(+), 4 deletions(-)
>
> diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h
> index 62d462e494..6c28ef59c3 100644
> --- a/include/exec/gen-icount.h
> +++ b/include/exec/gen-icount.h
> @@ -19,7 +19,7 @@ static inline void gen_tb_start(TranslationBlock *tb)
>          count = tcg_temp_new_i32();
>      }
>
> -    tcg_gen_ld_i32(count, cpu_env,
> +    tcg_gen_ld_i32(count, tcg_ctx.tcg_env,
>                     -ENV_OFFSET + offsetof(CPUState, icount_decr.u32));
>
>      if (tb->cflags & CF_USE_ICOUNT) {
> @@ -37,7 +37,7 @@ static inline void gen_tb_start(TranslationBlock *tb)
>      tcg_gen_brcondi_i32(TCG_COND_LT, count, 0, exitreq_label);
>
>      if (tb->cflags & CF_USE_ICOUNT) {
> -        tcg_gen_st16_i32(count, cpu_env,
> +        tcg_gen_st16_i32(count, tcg_ctx.tcg_env,
>                           -ENV_OFFSET + offsetof(CPUState, icount_decr.u16.low));
>      }
>
> @@ -62,14 +62,16 @@ static void gen_tb_end(TranslationBlock *tb, int num_insns)
>  static inline void gen_io_start(void)
>  {
>      TCGv_i32 tmp = tcg_const_i32(1);
> -    tcg_gen_st_i32(tmp, cpu_env, -ENV_OFFSET + offsetof(CPUState, can_do_io));
> +    tcg_gen_st_i32(tmp, tcg_ctx.tcg_env,
> +                   -ENV_OFFSET + offsetof(CPUState, can_do_io));
>      tcg_temp_free_i32(tmp);
>  }
>
>  static inline void gen_io_end(void)
>  {
>      TCGv_i32 tmp = tcg_const_i32(0);
> -    tcg_gen_st_i32(tmp, cpu_env, -ENV_OFFSET + offsetof(CPUState, can_do_io));
> +    tcg_gen_st_i32(tmp, tcg_ctx.tcg_env,
> +                   -ENV_OFFSET + offsetof(CPUState, can_do_io));
>      tcg_temp_free_i32(tmp);
>  }
>


--
Alex Bennée

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 02/27] cpu-exec: Avoid global variables in icount-related functions
  2017-07-11 19:25   ` Alex Bennée
@ 2017-07-12  8:42     ` Lluís Vilanova
  2017-07-12 22:06       ` Emilio G. Cota
  0 siblings, 1 reply; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-12  8:42 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Paolo Bonzini, Peter Crosthwaite, Emilio G. Cota, qemu-devel,
	Richard Henderson

Alex Bennée writes:

> Lluís Vilanova <vilanova@ac.upc.edu> writes:

>> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>

> I guess. I assume this is also something Emilio is targeting with his
> multi-threaded translation work.

Yes, Emilio suggested to format this patch in a way that won't conflict with his
changes.

Thanks,
  Lluis

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 04/27] target: [tcg] Add generic translation framework
  2017-07-11 17:21       ` Richard Henderson
@ 2017-07-12  8:50         ` Lluís Vilanova
  0 siblings, 0 replies; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-12  8:50 UTC (permalink / raw)
  To: Richard Henderson
  Cc: qemu-devel, Emilio G. Cota, Alex Bennée, Peter Crosthwaite,
	Paolo Bonzini

Richard Henderson writes:

> On 07/11/2017 06:40 AM, Lluís Vilanova wrote:
>> Since other hooks can set db->is_jmp and return values (breakpoint_check), I'll
>> stick with db->is_jmp instead. Then tb_start can return max_insns, and generic
>> code can refine it with checks like single-stepping.

> No, you misunderstand.  For SH4 I need to override single-stepping, icount, and
> anything else that produces a TB smaller than the atomic region.

I see, ok.

Cheers,
  Lluis

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 04/27] target: [tcg] Add generic translation framework
  2017-07-11 18:17   ` Alex Bennée
@ 2017-07-12  8:59     ` Lluís Vilanova
  2017-07-12  9:13       ` Alex Bennée
  0 siblings, 1 reply; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-12  8:59 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Paolo Bonzini, Peter Crosthwaite, Emilio G. Cota, qemu-devel,
	Richard Henderson

Alex Bennée writes:

> Lluís Vilanova <vilanova@ac.upc.edu> writes:

>> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
>> ---
>> accel/tcg/Makefile.objs   |    1
>> accel/tcg/translator.c    |  152 +++++++++++++++++++++++++++++++++++++++++++++
>> include/exec/gen-icount.h |    2 -
>> include/exec/translator.h |   99 +++++++++++++++++++++++++++++
>> 4 files changed, 253 insertions(+), 1 deletion(-)
>> create mode 100644 accel/tcg/translator.c
>> 
>> diff --git a/accel/tcg/Makefile.objs b/accel/tcg/Makefile.objs
>> index f173cd5397..3a5da5357c 100644
>> --- a/accel/tcg/Makefile.objs
>> +++ b/accel/tcg/Makefile.objs
>> @@ -1,3 +1,4 @@
>> obj-$(CONFIG_SOFTMMU) += tcg-all.o
>> obj-$(CONFIG_SOFTMMU) += cputlb.o
>> obj-y += cpu-exec.o cpu-exec-common.o translate-all.o translate-common.o
>> +obj-y += translator.o

> There is a merge conflict here with the current master.

I'll rebase for v13.


>> diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
>> new file mode 100644
>> index 0000000000..9e0343cbb1
>> --- /dev/null
>> +++ b/accel/tcg/translator.c
>> @@ -0,0 +1,152 @@
>> +/*
>> + * Generic intermediate code generation.
>> + *
>> + * Copyright (C) 2016-2017 Lluís Vilanova <vilanova@ac.upc.edu>
>> + *
>> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
>> + * See the COPYING file in the top-level directory.
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "qemu-common.h"
>> +#include "qemu/error-report.h"
>> +#include "cpu.h"
>> +#include "tcg/tcg.h"
>> +#include "tcg/tcg-op.h"
>> +#include "exec/exec-all.h"
>> +#include "exec/gen-icount.h"
>> +#include "exec/log.h"
>> +#include "exec/translator.h"
>> +
>> +
>> +static inline void translate_block_tcg_check(const DisasContextBase *db)
>> +{
>> +    if (tcg_check_temp_count()) {
>> +        error_report("warning: TCG temporary leaks before "TARGET_FMT_lx,
>> +                     db->pc_next);
>> +    }
>> +}
>> +
>> +void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
>> +                     CPUState *cpu, TranslationBlock *tb)
>> +{
>> +    int max_insns;
>> +
>> +    /* Initialize DisasContext */
>> +    db->tb = tb;
>> +    db->pc_first = tb->pc;
>> +    db->pc_next = db->pc_first;
>> +    db->is_jmp = DISAS_NEXT;
>> +    db->num_insns = 0;
>> +    db->singlestep_enabled = cpu->singlestep_enabled;
>> +    ops->init_disas_context(db, cpu);
>> +
>> +    /* Initialize globals */
>> +    tcg_clear_temp_count();
>> +
>> +    /* Instruction counting */
>> +    max_insns = db->tb->cflags & CF_COUNT_MASK;
>> +    if (max_insns == 0) {
>> +        max_insns = CF_COUNT_MASK;
>> +    }
>> +    if (max_insns > TCG_MAX_INSNS) {
>> +        max_insns = TCG_MAX_INSNS;
>> +    }
>> +    if (db->singlestep_enabled || singlestep) {
>> +        max_insns = 1;
>> +    }
>> +
>> +    /* Start translating */
>> +    gen_tb_start(db->tb);
>> +    ops->tb_start(db, cpu);
>> +
>> +    while (true) {
>> +        db->num_insns++;
>> +        ops->insn_start(db, cpu);
>> +
>> +        /* Early exit before breakpoint checks */
>> +        if (unlikely(db->is_jmp != DISAS_NEXT)) {
>> +            break;
>> +        }
>> +
>> +        /* Pass breakpoint hits to target for further processing */
>> +        if (unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
>> +            CPUBreakpoint *bp;
>> +            QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
>> +                if (bp->pc == db->pc_next) {
>> +                    BreakpointCheckType bp_check =
>> +                        ops->breakpoint_check(db, cpu, bp);
>> +                    switch (bp_check) {
>> +                    case BC_MISS:
>> +                        /* Target ignored this breakpoint, go to next */
>> +                        break;
>> +                    case BC_HIT_INSN:
>> +                        /* Hit, keep translating */
>> +                        /*
>> +                         * TODO: if we're never going to have more than one
>> +                         *       BP in a single address, we can simply use a
>> +                         *       bool here.
>> +                         */
>> +                        goto done_breakpoints;
>> +                    case BC_HIT_TB:
>> +                        /* Hit, end TB */
>> +                        goto done_generating;
>> +                    default:
>> +                        g_assert_not_reached();
>> +                    }
>> +                }
>> +            }
>> +        }
>> +    done_breakpoints:

> For the sake of keeping the core loop easy to follow maybe it would be
> better to have a helper function for the breakpoint handling? Really
> there is only one result from the helper which is do we continue the
> loop or jump to done_generating.

The new v13 has a much simpler loop that will hopefully address your concerns.

>> +
>> +        /* Accept I/O on last instruction */
>> +        if (db->num_insns == max_insns && (db->tb->cflags & CF_LAST_IO)) {
>> +            gen_io_start();
>> +        }
>> +
>> +        /* Disassemble one instruction */
>> +        db->pc_next = ops->translate_insn(db, cpu);
>> +
>> +        /**************************************************/
>> +        /* Conditions to stop translation                 */
>> +        /**************************************************/
>> +
>> +        /* Target-specific conditions set by disassembly */
>> +        if (db->is_jmp != DISAS_NEXT) {
>> +            break;
>> +        }
>> +
>> +        /* Too many instructions */
>> +        if (tcg_op_buf_full() || db->num_insns >= max_insns) {
>> +            db->is_jmp = DISAS_TOO_MANY;
>> +            break;
>> +        }
>> +
>> +        translate_block_tcg_check(db);
>> +    }

> This may be a personal taste thing but having while(true) {} and breaks
> is harder to follow than do { stuff } while (!done);

I think it is. I prefer to see the loop condition up-front, unless a do-while
makes the condition logic substantially simpler.


Thanks,
  Lluis

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 03/27] target: [tcg] Use a generic enum for DISAS_ values
  2017-07-07 11:52 ` [Qemu-devel] [PATCH v12 03/27] target: [tcg] Use a generic enum for DISAS_ values Lluís Vilanova
@ 2017-07-12  9:10   ` Alex Bennée
  2017-07-12 10:56     ` Lluís Vilanova
  2017-07-12 16:53     ` Richard Henderson
  0 siblings, 2 replies; 57+ messages in thread
From: Alex Bennée @ 2017-07-12  9:10 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Emilio G. Cota, Richard Henderson, Peter Crosthwaite,
	Paolo Bonzini, Peter Maydell, Edgar E. Iglesias, Eduardo Habkost,
	Michael Walle, Laurent Vivier, Chris Wulff, Marek Vasut,
	Stafford Horne, Alexander Graf, Guan Xuetao, Max Filippov,
	open list:ARM


Lluís Vilanova <vilanova@ac.upc.edu> writes:

> Used later. An enum makes expected values explicit and bounds the value space of
> switches.
>
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> Reviewed-by: Emilio G. Cota <cota@braap.org>
> Reviewed-by: Richard Henderson <rth@twiddle.net>
> ---
>  include/exec/exec-all.h       |    6 ------
>  include/exec/translator.h     |   39 +++++++++++++++++++++++++++++++++++++++
>  target/arm/translate.h        |   26 ++++++++++++++++----------
>  target/cris/translate.c       |    7 ++++++-
>  target/i386/translate.c       |    4 ++++
>  target/lm32/translate.c       |    6 ++++++
>  target/m68k/translate.c       |    7 ++++++-
>  target/microblaze/translate.c |    6 ++++++
>  target/nios2/translate.c      |    6 ++++++
>  target/openrisc/translate.c   |    6 ++++++
>  target/s390x/translate.c      |    3 ++-
>  target/unicore32/translate.c  |    7 ++++++-
>  target/xtensa/translate.c     |    4 ++++
>  13 files changed, 107 insertions(+), 20 deletions(-)
>  create mode 100644 include/exec/translator.h
>
> diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
> index 0826894ec5..27498cf740 100644
> --- a/include/exec/exec-all.h
> +++ b/include/exec/exec-all.h
> @@ -35,12 +35,6 @@ typedef abi_ulong tb_page_addr_t;
>  typedef ram_addr_t tb_page_addr_t;
>  #endif
>
> -/* is_jmp field values */
> -#define DISAS_NEXT    0 /* next instruction can be analyzed */
> -#define DISAS_JUMP    1 /* only pc was modified dynamically */
> -#define DISAS_UPDATE  2 /* cpu state was modified dynamically */
> -#define DISAS_TB_JUMP 3 /* only pc was modified statically */
> -
>  #include "qemu/log.h"
>
>  void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb);
> diff --git a/include/exec/translator.h b/include/exec/translator.h
> new file mode 100644
> index 0000000000..1f9697dd31
> --- /dev/null
> +++ b/include/exec/translator.h
> @@ -0,0 +1,39 @@
> +/*
> + * Generic intermediate code generation.
> + *
> + * Copyright (C) 2016-2017 Lluís Vilanova <vilanova@ac.upc.edu>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#ifndef EXEC__TRANSLATOR_H
> +#define EXEC__TRANSLATOR_H
> +
> +/**
> + * DisasJumpType:
> + * @DISAS_NEXT: Next instruction in program order.
> + * @DISAS_TOO_MANY: Too many instructions translated.
> + * @DISAS_TARGET: Start of target-specific conditions.
> + *
> + * What instruction to disassemble next.
> + */
> +typedef enum DisasJumpType {
> +    DISAS_NEXT,
> +    DISAS_TOO_MANY,

Is DISAS_TOO_MANY really a useful distinction. Sure we have ended the
loop because of an instruction limit but the more important information
is what it means for the epilogue code and how we go to the next block.

The recent work on fixing eret on ARM[1] has had me thinking about the
semantics of exit conditions and how much commonality we have across the
translators. I don't think we'll ever have a comprehensive DisasJumpType
that all translators will only use the common exits but I think we could
stand to have a few more.

I think the cases we want to cover are:

  DISAS_JUMP - the block ends with a jump to the next block (either
               computed via PC or hard-coded with patched branch to next TB)

  DISAS_NORETURN - the block exits via a helper or some other mechanism
                  (for example cpu_loop_exit from helper)

  DISAS_EXIT_LOOP - we need to return to the main loop before we enter
                    again (typically to deal with IRQ issues)


[1] https://lists.nongnu.org/archive/html/qemu-devel/2017-07/msg02963.html

> +    DISAS_TARGET_0,
> +    DISAS_TARGET_1,
> +    DISAS_TARGET_2,
> +    DISAS_TARGET_3,
> +    DISAS_TARGET_4,
> +    DISAS_TARGET_5,
> +    DISAS_TARGET_6,
> +    DISAS_TARGET_7,
> +    DISAS_TARGET_8,
> +    DISAS_TARGET_9,
> +    DISAS_TARGET_10,
> +    DISAS_TARGET_11,
> +    DISAS_TARGET_12,
> +} DisasJumpType;
> +
> +#endif  /* EXEC__TRANSLATOR_H */
> diff --git a/target/arm/translate.h b/target/arm/translate.h
> index e5da614db5..aba3f44c9f 100644
> --- a/target/arm/translate.h
> +++ b/target/arm/translate.h
> @@ -1,6 +1,9 @@
>  #ifndef TARGET_ARM_TRANSLATE_H
>  #define TARGET_ARM_TRANSLATE_H
>
> +#include "exec/translator.h"
> +
> +
>  /* internal defines */
>  typedef struct DisasContext {
>      target_ulong pc;
> @@ -119,30 +122,33 @@ static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
>      s->insn_start_idx = 0;
>  }
>
> -/* target-specific extra values for is_jmp */
> +/* is_jmp field values */
> +#define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
> +#define DISAS_UPDATE  DISAS_TARGET_1 /* cpu state was modified dynamically */
> +#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
>  /* These instructions trap after executing, so the A32/T32 decoder must
>   * defer them until after the conditional execution state has been updated.
>   * WFI also needs special handling when single-stepping.
>   */
> -#define DISAS_WFI 4
> -#define DISAS_SWI 5

So in the new model for example we only really need the special handling
for things like WFI/SWI onwards.

> +#define DISAS_WFI DISAS_TARGET_3
> +#define DISAS_SWI DISAS_TARGET_4
>  /* For instructions which unconditionally cause an exception we can skip
>   * emitting unreachable code at the end of the TB in the A64 decoder
>   */
> -#define DISAS_EXC 6
> +#define DISAS_EXC DISAS_TARGET_5
>  /* WFE */
> -#define DISAS_WFE 7
> -#define DISAS_HVC 8
> -#define DISAS_SMC 9
> -#define DISAS_YIELD 10
> +#define DISAS_WFE DISAS_TARGET_6
> +#define DISAS_HVC DISAS_TARGET_7
> +#define DISAS_SMC DISAS_TARGET_8
> +#define DISAS_YIELD DISAS_TARGET_9
>  /* M profile branch which might be an exception return (and so needs
>   * custom end-of-TB code)
>   */
> -#define DISAS_BX_EXCRET 11
> +#define DISAS_BX_EXCRET DISAS_TARGET_10
>  /* For instructions which want an immediate exit to the main loop,
>   * as opposed to attempting to use lookup_and_goto_ptr.
>   */
> -#define DISAS_EXIT 12
> +#define DISAS_EXIT DISAS_TARGET_11
>
>  #ifdef TARGET_AARCH64
>  void a64_translate_init(void);
> diff --git a/target/cris/translate.c b/target/cris/translate.c
> index 12b96eb68f..38a999e6f1 100644
> --- a/target/cris/translate.c
> +++ b/target/cris/translate.c
> @@ -31,6 +31,7 @@
>  #include "exec/helper-proto.h"
>  #include "mmu.h"
>  #include "exec/cpu_ldst.h"
> +#include "exec/translator.h"
>  #include "crisv32-decode.h"
>
>  #include "exec/helper-gen.h"
> @@ -50,7 +51,11 @@
>  #define BUG() (gen_BUG(dc, __FILE__, __LINE__))
>  #define BUG_ON(x) ({if (x) BUG();})
>
> -#define DISAS_SWI 5
> +/* is_jmp field values */
> +#define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
> +#define DISAS_UPDATE  DISAS_TARGET_1 /* cpu state was modified dynamically */
> +#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
> +#define DISAS_SWI     DISAS_TARGET_3
>
>  /* Used by the decoder.  */
>  #define EXTRACT_FIELD(src, start, end) \
> diff --git a/target/i386/translate.c b/target/i386/translate.c
> index cab9e32f91..b118fcb834 100644
> --- a/target/i386/translate.c
> +++ b/target/i386/translate.c
> @@ -24,6 +24,7 @@
>  #include "exec/exec-all.h"
>  #include "tcg-op.h"
>  #include "exec/cpu_ldst.h"
> +#include "exec/translator.h"
>
>  #include "exec/helper-proto.h"
>  #include "exec/helper-gen.h"
> @@ -71,6 +72,9 @@
>
>  //#define MACRO_TEST   1
>
> +/* is_jmp field values */
> +#define DISAS_TB_JUMP DISAS_TARGET_0 /* only pc was modified statically */
> +
>  /* global register indexes */
>  static TCGv_env cpu_env;
>  static TCGv cpu_A0;
> diff --git a/target/lm32/translate.c b/target/lm32/translate.c
> index f68f372f15..65bc9c0bf6 100644
> --- a/target/lm32/translate.c
> +++ b/target/lm32/translate.c
> @@ -22,6 +22,7 @@
>  #include "disas/disas.h"
>  #include "exec/helper-proto.h"
>  #include "exec/exec-all.h"
> +#include "exec/translator.h"
>  #include "tcg-op.h"
>
>  #include "exec/cpu_ldst.h"
> @@ -47,6 +48,11 @@
>
>  #define MEM_INDEX 0
>
> +/* is_jmp field values */
> +#define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
> +#define DISAS_UPDATE  DISAS_TARGET_1 /* cpu state was modified dynamically */
> +#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
> +
>  static TCGv_env cpu_env;
>  static TCGv cpu_R[32];
>  static TCGv cpu_pc;
> diff --git a/target/m68k/translate.c b/target/m68k/translate.c
> index af19872e0b..af08a5c959 100644
> --- a/target/m68k/translate.c
> +++ b/target/m68k/translate.c
> @@ -25,6 +25,7 @@
>  #include "tcg-op.h"
>  #include "qemu/log.h"
>  #include "exec/cpu_ldst.h"
> +#include "exec/translator.h"
>
>  #include "exec/helper-proto.h"
>  #include "exec/helper-gen.h"
> @@ -173,7 +174,11 @@ static void do_writebacks(DisasContext *s)
>      }
>  }
>
> -#define DISAS_JUMP_NEXT 4
> +/* is_jmp field values */
> +#define DISAS_JUMP      DISAS_TARGET_0 /* only pc was modified dynamically */
> +#define DISAS_UPDATE    DISAS_TARGET_1 /* cpu state was modified dynamically */
> +#define DISAS_TB_JUMP   DISAS_TARGET_2 /* only pc was modified statically */
> +#define DISAS_JUMP_NEXT DISAS_TARGET_3
>
>  #if defined(CONFIG_USER_ONLY)
>  #define IS_USER(s) 1
> diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c
> index a180bc78ae..e050c694d8 100644
> --- a/target/microblaze/translate.c
> +++ b/target/microblaze/translate.c
> @@ -27,6 +27,7 @@
>  #include "microblaze-decode.h"
>  #include "exec/cpu_ldst.h"
>  #include "exec/helper-gen.h"
> +#include "exec/translator.h"
>
>  #include "trace-tcg.h"
>  #include "exec/log.h"
> @@ -46,6 +47,11 @@
>  #define EXTRACT_FIELD(src, start, end) \
>              (((src) >> start) & ((1 << (end - start + 1)) - 1))
>
> +/* is_jmp field values */
> +#define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
> +#define DISAS_UPDATE  DISAS_TARGET_1 /* cpu state was modified dynamically */
> +#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
> +
>  static TCGv env_debug;
>  static TCGv_env cpu_env;
>  static TCGv cpu_R[32];
> diff --git a/target/nios2/translate.c b/target/nios2/translate.c
> index 8b97d6585f..6b0961837d 100644
> --- a/target/nios2/translate.c
> +++ b/target/nios2/translate.c
> @@ -29,6 +29,12 @@
>  #include "exec/helper-gen.h"
>  #include "exec/log.h"
>  #include "exec/cpu_ldst.h"
> +#include "exec/translator.h"
> +
> +/* is_jmp field values */
> +#define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
> +#define DISAS_UPDATE  DISAS_TARGET_1 /* cpu state was modified dynamically */
> +#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
>
>  #define INSTRUCTION_FLG(func, flags) { (func), (flags) }
>  #define INSTRUCTION(func)                  \
> diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c
> index a01413113b..112db1ad0f 100644
> --- a/target/openrisc/translate.c
> +++ b/target/openrisc/translate.c
> @@ -27,6 +27,7 @@
>  #include "qemu/log.h"
>  #include "qemu/bitops.h"
>  #include "exec/cpu_ldst.h"
> +#include "exec/translator.h"
>
>  #include "exec/helper-proto.h"
>  #include "exec/helper-gen.h"
> @@ -37,6 +38,11 @@
>  #define LOG_DIS(str, ...) \
>      qemu_log_mask(CPU_LOG_TB_IN_ASM, "%08x: " str, dc->pc, ## __VA_ARGS__)
>
> +/* is_jmp field values */
> +#define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
> +#define DISAS_UPDATE  DISAS_TARGET_1 /* cpu state was modified dynamically */
> +#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
> +
>  typedef struct DisasContext {
>      TranslationBlock *tb;
>      target_ulong pc;
> diff --git a/target/s390x/translate.c b/target/s390x/translate.c
> index cd8c38d6d5..6ed38371a1 100644
> --- a/target/s390x/translate.c
> +++ b/target/s390x/translate.c
> @@ -76,7 +76,8 @@ typedef struct {
>      } u;
>  } DisasCompare;
>
> -#define DISAS_EXCP 4
> +/* is_jmp field values */
> +#define DISAS_EXCP DISAS_TARGET_0
>
>  #ifdef DEBUG_INLINE_BRANCHES
>  static uint64_t inline_branch_hit[CC_OP_MAX];
> diff --git a/target/unicore32/translate.c b/target/unicore32/translate.c
> index 8f30cff932..6c094d59d7 100644
> --- a/target/unicore32/translate.c
> +++ b/target/unicore32/translate.c
> @@ -16,6 +16,7 @@
>  #include "tcg-op.h"
>  #include "qemu/log.h"
>  #include "exec/cpu_ldst.h"
> +#include "exec/translator.h"
>
>  #include "exec/helper-proto.h"
>  #include "exec/helper-gen.h"
> @@ -45,9 +46,13 @@ typedef struct DisasContext {
>  #define IS_USER(s)      1
>  #endif
>
> +/* is_jmp field values */
> +#define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
> +#define DISAS_UPDATE  DISAS_TARGET_1 /* cpu state was modified dynamically */
> +#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
>  /* These instructions trap after executing, so defer them until after the
>     conditional executions state has been updated.  */
> -#define DISAS_SYSCALL 5
> +#define DISAS_SYSCALL DISAS_TARGET_3
>
>  static TCGv_env cpu_env;
>  static TCGv_i32 cpu_R[32];
> diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
> index f3f0ff589c..d7bf07e8e6 100644
> --- a/target/xtensa/translate.c
> +++ b/target/xtensa/translate.c
> @@ -38,6 +38,7 @@
>  #include "sysemu/sysemu.h"
>  #include "exec/cpu_ldst.h"
>  #include "exec/semihost.h"
> +#include "exec/translator.h"
>
>  #include "exec/helper-proto.h"
>  #include "exec/helper-gen.h"
> @@ -46,6 +47,9 @@
>  #include "exec/log.h"
>
>
> +/* is_jmp field values */
> +#define DISAS_UPDATE  DISAS_TARGET_0 /* cpu state was modified dynamically */
> +
>  typedef struct DisasContext {
>      const XtensaConfig *config;
>      TranslationBlock *tb;


--
Alex Bennée

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 04/27] target: [tcg] Add generic translation framework
  2017-07-12  8:59     ` Lluís Vilanova
@ 2017-07-12  9:13       ` Alex Bennée
  0 siblings, 0 replies; 57+ messages in thread
From: Alex Bennée @ 2017-07-12  9:13 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: Paolo Bonzini, Peter Crosthwaite, Emilio G. Cota, qemu-devel,
	Richard Henderson


Lluís Vilanova <vilanova@ac.upc.edu> writes:

> Alex Bennée writes:
>
>> Lluís Vilanova <vilanova@ac.upc.edu> writes:
>
>>> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
<snip>
>>> +
>>> +        translate_block_tcg_check(db);
>>> +    }
>
>> This may be a personal taste thing but having while(true) {} and breaks
>> is harder to follow than do { stuff } while (!done);
>
> I think it is. I prefer to see the loop condition up-front, unless a do-while
> makes the condition logic substantially simpler.

Yes but in this case the condition is "go forever" unless we break (or
goto) out. I'd be happy with the while at the top if it was an actual
condition.

--
Alex Bennée

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 05/27] target/i386: [tcg] Port to DisasContextBase
  2017-07-07 12:00 ` [Qemu-devel] [PATCH v12 05/27] target/i386: [tcg] Port to DisasContextBase Lluís Vilanova
@ 2017-07-12  9:18   ` Alex Bennée
  2017-07-12 11:00     ` Lluís Vilanova
  0 siblings, 1 reply; 57+ messages in thread
From: Alex Bennée @ 2017-07-12  9:18 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Emilio G. Cota, Richard Henderson, Peter Crosthwaite,
	Paolo Bonzini, Eduardo Habkost


Lluís Vilanova <vilanova@ac.upc.edu> writes:

> Incrementally paves the way towards using the generic instruction translation
> loop.
>
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> Reviewed-by: Emilio G. Cota <cota@braap.org>
> Reviewed-by: Richard Henderson <rth@twiddle.net>
> ---
>  target/i386/translate.c |  142 +++++++++++++++++++++++------------------------
>  1 file changed, 70 insertions(+), 72 deletions(-)
>
> diff --git a/target/i386/translate.c b/target/i386/translate.c
> index b118fcb834..f61f5c7227 100644
> --- a/target/i386/translate.c
> +++ b/target/i386/translate.c
> @@ -99,6 +99,8 @@ static int x86_64_hregs;
>  #endif
>
>  typedef struct DisasContext {
> +    DisasContextBase base;
> +
>      /* current insn context */
>      int override; /* -1 if no override */
>      int prefix;
> @@ -106,8 +108,6 @@ typedef struct DisasContext {
>      TCGMemOp dflag;
>      target_ulong pc_start;
>      target_ulong pc; /* pc = eip + cs_base */
> -    int is_jmp; /* 1 = means jump (stop translation), 2 means CPU
> -                   static state change (stop translation) */
>      /* current block context */
>      target_ulong cs_base; /* base of CS segment */
>      int pe;     /* protected mode */
> @@ -128,12 +128,10 @@ typedef struct DisasContext {
>      int cpl;
>      int iopl;
>      int tf;     /* TF cpu flag */
> -    int singlestep_enabled; /* "hardware" single step enabled */
>      int jmp_opt; /* use direct block chaining for direct jumps */
>      int repz_opt; /* optimize jumps within repz instructions */
>      int mem_index; /* select memory access functions */
>      uint64_t flags; /* all execution flags */
> -    struct TranslationBlock *tb;
>      int popl_esp_hack; /* for correct popl with esp base handling */
>      int rip_offset; /* only used in x86_64, but left for simplicity */
>      int cpuid_features;
> @@ -1123,7 +1121,7 @@ static void gen_bpt_io(DisasContext *s, TCGv_i32 t_port, int ot)
>
>  static inline void gen_ins(DisasContext *s, TCGMemOp ot)
>  {
> -    if (s->tb->cflags & CF_USE_ICOUNT) {
> +    if (s->base.tb->cflags & CF_USE_ICOUNT) {
>          gen_io_start();
>      }
>      gen_string_movl_A0_EDI(s);
> @@ -1138,14 +1136,14 @@ static inline void gen_ins(DisasContext *s, TCGMemOp ot)
>      gen_op_movl_T0_Dshift(ot);
>      gen_op_add_reg_T0(s->aflag, R_EDI);
>      gen_bpt_io(s, cpu_tmp2_i32, ot);
> -    if (s->tb->cflags & CF_USE_ICOUNT) {
> +    if (s->base.tb->cflags & CF_USE_ICOUNT) {
>          gen_io_end();
>      }
>  }
>
>  static inline void gen_outs(DisasContext *s, TCGMemOp ot)
>  {
> -    if (s->tb->cflags & CF_USE_ICOUNT) {
> +    if (s->base.tb->cflags & CF_USE_ICOUNT) {
>          gen_io_start();
>      }
>      gen_string_movl_A0_ESI(s);
> @@ -1158,7 +1156,7 @@ static inline void gen_outs(DisasContext *s, TCGMemOp ot)
>      gen_op_movl_T0_Dshift(ot);
>      gen_op_add_reg_T0(s->aflag, R_ESI);
>      gen_bpt_io(s, cpu_tmp2_i32, ot);
> -    if (s->tb->cflags & CF_USE_ICOUNT) {
> +    if (s->base.tb->cflags & CF_USE_ICOUNT) {
>          gen_io_end();
>      }
>  }
> @@ -2141,7 +2139,7 @@ static inline int insn_const_size(TCGMemOp ot)
>  static inline bool use_goto_tb(DisasContext *s, target_ulong pc)
>  {
>  #ifndef CONFIG_USER_ONLY
> -    return (pc & TARGET_PAGE_MASK) == (s->tb->pc & TARGET_PAGE_MASK) ||
> +    return (pc & TARGET_PAGE_MASK) == (s->base.tb->pc & TARGET_PAGE_MASK) ||
>             (pc & TARGET_PAGE_MASK) == (s->pc_start & TARGET_PAGE_MASK);
>  #else
>      return true;
> @@ -2156,7 +2154,7 @@ static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip)
>          /* jump to same page: we can use a direct jump */
>          tcg_gen_goto_tb(tb_num);
>          gen_jmp_im(eip);
> -        tcg_gen_exit_tb((uintptr_t)s->tb + tb_num);
> +        tcg_gen_exit_tb((uintptr_t)s->base.tb + tb_num);
>      } else {
>          /* jump to another page */
>          gen_jmp_im(eip);
> @@ -2177,7 +2175,7 @@ static inline void gen_jcc(DisasContext *s, int b,
>
>          gen_set_label(l1);
>          gen_goto_tb(s, 1, val);
> -        s->is_jmp = DISAS_TB_JUMP;
> +        s->base.is_jmp = DISAS_TB_JUMP;
>      } else {
>          l1 = gen_new_label();
>          l2 = gen_new_label();
> @@ -2248,11 +2246,11 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg)
>             stop as a special handling must be done to disable hardware
>             interrupts for the next instruction */
>          if (seg_reg == R_SS || (s->code32 && seg_reg < R_FS))
> -            s->is_jmp = DISAS_TB_JUMP;
> +            s->base.is_jmp = DISAS_TB_JUMP;
>      } else {
>          gen_op_movl_seg_T0_vm(seg_reg);
>          if (seg_reg == R_SS)
> -            s->is_jmp = DISAS_TB_JUMP;
> +            s->base.is_jmp = DISAS_TB_JUMP;
>      }
>  }
>
> @@ -2424,7 +2422,7 @@ static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip)
>      gen_update_cc_op(s);
>      gen_jmp_im(cur_eip);
>      gen_helper_raise_exception(cpu_env, tcg_const_i32(trapno));
> -    s->is_jmp = DISAS_TB_JUMP;
> +    s->base.is_jmp = DISAS_TB_JUMP;
>  }
>
>  /* Generate #UD for the current instruction.  The assumption here is that
> @@ -2462,7 +2460,7 @@ static void gen_interrupt(DisasContext *s, int intno,
>      gen_jmp_im(cur_eip);
>      gen_helper_raise_interrupt(cpu_env, tcg_const_i32(intno),
>                                 tcg_const_i32(next_eip - cur_eip));
> -    s->is_jmp = DISAS_TB_JUMP;
> +    s->base.is_jmp = DISAS_TB_JUMP;
>  }
>
>  static void gen_debug(DisasContext *s, target_ulong cur_eip)
> @@ -2470,7 +2468,7 @@ static void gen_debug(DisasContext *s, target_ulong cur_eip)
>      gen_update_cc_op(s);
>      gen_jmp_im(cur_eip);
>      gen_helper_debug(cpu_env);
> -    s->is_jmp = DISAS_TB_JUMP;
> +    s->base.is_jmp = DISAS_TB_JUMP;
>  }
>
>  static void gen_set_hflag(DisasContext *s, uint32_t mask)
> @@ -2526,10 +2524,10 @@ do_gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf, TCGv jr)
>          gen_reset_hflag(s, HF_INHIBIT_IRQ_MASK);
>      }
>
> -    if (s->tb->flags & HF_RF_MASK) {
> +    if (s->base.tb->flags & HF_RF_MASK) {
>          gen_helper_reset_rf(cpu_env);
>      }
> -    if (s->singlestep_enabled) {
> +    if (s->base.singlestep_enabled) {
>          gen_helper_debug(cpu_env);
>      } else if (recheck_tf) {
>          gen_helper_rechecking_single_step(cpu_env);
> @@ -2545,7 +2543,7 @@ do_gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf, TCGv jr)
>      } else {
>          tcg_gen_exit_tb(0);
>      }
> -    s->is_jmp = DISAS_TB_JUMP;
> +    s->base.is_jmp = DISAS_TB_JUMP;
>  }
>
>  static inline void
> @@ -2584,7 +2582,7 @@ static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num)
>      set_cc_op(s, CC_OP_DYNAMIC);
>      if (s->jmp_opt) {
>          gen_goto_tb(s, tb_num, eip);
> -        s->is_jmp = DISAS_TB_JUMP;
> +        s->base.is_jmp = DISAS_TB_JUMP;
>      } else {
>          gen_jmp_im(eip);
>          gen_eob(s);
> @@ -4419,7 +4417,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
>      }
>  }
>
> -/* convert one instruction. s->is_jmp is set if the translation must
> +/* convert one instruction. s->base.is_jmp is set if the translation must
>     be stopped. Return the next pc value */
>  static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>                                 target_ulong pc_start)
> @@ -5379,7 +5377,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>          gen_movl_seg_T0(s, reg);
>          gen_pop_update(s, ot);
>          /* Note that reg == R_SS in gen_movl_seg_T0 always sets is_jmp.  */
> -        if (s->is_jmp) {
> +        if (s->base.is_jmp) {
>              gen_jmp_im(s->pc - s->cs_base);
>              if (reg == R_SS) {
>                  s->tf = 0;
> @@ -5394,7 +5392,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>          ot = gen_pop_T0(s);
>          gen_movl_seg_T0(s, (b >> 3) & 7);
>          gen_pop_update(s, ot);
> -        if (s->is_jmp) {
> +        if (s->base.is_jmp) {
>              gen_jmp_im(s->pc - s->cs_base);
>              gen_eob(s);
>          }
> @@ -5445,7 +5443,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>          gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
>          gen_movl_seg_T0(s, reg);
>          /* Note that reg == R_SS in gen_movl_seg_T0 always sets is_jmp.  */
> -        if (s->is_jmp) {
> +        if (s->base.is_jmp) {
>              gen_jmp_im(s->pc - s->cs_base);
>              if (reg == R_SS) {
>                  s->tf = 0;
> @@ -5654,7 +5652,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>          gen_movl_seg_T0(s, op);
>          /* then put the data */
>          gen_op_mov_reg_v(ot, reg, cpu_T1);
> -        if (s->is_jmp) {
> +        if (s->base.is_jmp) {
>              gen_jmp_im(s->pc - s->cs_base);
>              gen_eob(s);
>          }
> @@ -6310,7 +6308,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>              gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
>          } else {
>              gen_ins(s, ot);
> -            if (s->tb->cflags & CF_USE_ICOUNT) {
> +            if (s->base.tb->cflags & CF_USE_ICOUNT) {
>                  gen_jmp(s, s->pc - s->cs_base);
>              }
>          }
> @@ -6325,7 +6323,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>              gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
>          } else {
>              gen_outs(s, ot);
> -            if (s->tb->cflags & CF_USE_ICOUNT) {
> +            if (s->base.tb->cflags & CF_USE_ICOUNT) {
>                  gen_jmp(s, s->pc - s->cs_base);
>              }
>          }
> @@ -6341,14 +6339,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>          tcg_gen_movi_tl(cpu_T0, val);
>          gen_check_io(s, ot, pc_start - s->cs_base,
>                       SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
> -        if (s->tb->cflags & CF_USE_ICOUNT) {
> +        if (s->base.tb->cflags & CF_USE_ICOUNT) {
>              gen_io_start();
>  	}
>          tcg_gen_movi_i32(cpu_tmp2_i32, val);
>          gen_helper_in_func(ot, cpu_T1, cpu_tmp2_i32);
>          gen_op_mov_reg_v(ot, R_EAX, cpu_T1);
>          gen_bpt_io(s, cpu_tmp2_i32, ot);
> -        if (s->tb->cflags & CF_USE_ICOUNT) {
> +        if (s->base.tb->cflags & CF_USE_ICOUNT) {
>              gen_io_end();
>              gen_jmp(s, s->pc - s->cs_base);
>          }
> @@ -6362,14 +6360,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>                       svm_is_rep(prefixes));
>          gen_op_mov_v_reg(ot, cpu_T1, R_EAX);
>
> -        if (s->tb->cflags & CF_USE_ICOUNT) {
> +        if (s->base.tb->cflags & CF_USE_ICOUNT) {
>              gen_io_start();
>  	}
>          tcg_gen_movi_i32(cpu_tmp2_i32, val);
>          tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T1);
>          gen_helper_out_func(ot, cpu_tmp2_i32, cpu_tmp3_i32);
>          gen_bpt_io(s, cpu_tmp2_i32, ot);
> -        if (s->tb->cflags & CF_USE_ICOUNT) {
> +        if (s->base.tb->cflags & CF_USE_ICOUNT) {
>              gen_io_end();
>              gen_jmp(s, s->pc - s->cs_base);
>          }
> @@ -6380,14 +6378,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>          tcg_gen_ext16u_tl(cpu_T0, cpu_regs[R_EDX]);
>          gen_check_io(s, ot, pc_start - s->cs_base,
>                       SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
> -        if (s->tb->cflags & CF_USE_ICOUNT) {
> +        if (s->base.tb->cflags & CF_USE_ICOUNT) {
>              gen_io_start();
>  	}
>          tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T0);
>          gen_helper_in_func(ot, cpu_T1, cpu_tmp2_i32);
>          gen_op_mov_reg_v(ot, R_EAX, cpu_T1);
>          gen_bpt_io(s, cpu_tmp2_i32, ot);
> -        if (s->tb->cflags & CF_USE_ICOUNT) {
> +        if (s->base.tb->cflags & CF_USE_ICOUNT) {
>              gen_io_end();
>              gen_jmp(s, s->pc - s->cs_base);
>          }
> @@ -6400,14 +6398,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>                       svm_is_rep(prefixes));
>          gen_op_mov_v_reg(ot, cpu_T1, R_EAX);
>
> -        if (s->tb->cflags & CF_USE_ICOUNT) {
> +        if (s->base.tb->cflags & CF_USE_ICOUNT) {
>              gen_io_start();
>  	}
>          tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T0);
>          tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T1);
>          gen_helper_out_func(ot, cpu_tmp2_i32, cpu_tmp3_i32);
>          gen_bpt_io(s, cpu_tmp2_i32, ot);
> -        if (s->tb->cflags & CF_USE_ICOUNT) {
> +        if (s->base.tb->cflags & CF_USE_ICOUNT) {
>              gen_io_end();
>              gen_jmp(s, s->pc - s->cs_base);
>          }
> @@ -6946,7 +6944,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>              gen_update_cc_op(s);
>              gen_jmp_im(pc_start - s->cs_base);
>              gen_helper_pause(cpu_env, tcg_const_i32(s->pc - pc_start));
> -            s->is_jmp = DISAS_TB_JUMP;
> +            s->base.is_jmp = DISAS_TB_JUMP;
>          }
>          break;
>      case 0x9b: /* fwait */
> @@ -7115,11 +7113,11 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>      case 0x131: /* rdtsc */
>          gen_update_cc_op(s);
>          gen_jmp_im(pc_start - s->cs_base);
> -        if (s->tb->cflags & CF_USE_ICOUNT) {
> +        if (s->base.tb->cflags & CF_USE_ICOUNT) {
>              gen_io_start();
>  	}
>          gen_helper_rdtsc(cpu_env);
> -        if (s->tb->cflags & CF_USE_ICOUNT) {
> +        if (s->base.tb->cflags & CF_USE_ICOUNT) {
>              gen_io_end();
>              gen_jmp(s, s->pc - s->cs_base);
>          }
> @@ -7191,7 +7189,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>              gen_update_cc_op(s);
>              gen_jmp_im(pc_start - s->cs_base);
>              gen_helper_hlt(cpu_env, tcg_const_i32(s->pc - pc_start));
> -            s->is_jmp = DISAS_TB_JUMP;
> +            s->base.is_jmp = DISAS_TB_JUMP;
>          }
>          break;
>      case 0x100:
> @@ -7374,7 +7372,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>              gen_helper_vmrun(cpu_env, tcg_const_i32(s->aflag - 1),
>                               tcg_const_i32(s->pc - pc_start));
>              tcg_gen_exit_tb(0);
> -            s->is_jmp = DISAS_TB_JUMP;
> +            s->base.is_jmp = DISAS_TB_JUMP;
>              break;
>
>          case 0xd9: /* VMMCALL */
> @@ -7574,11 +7572,11 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>              }
>              gen_update_cc_op(s);
>              gen_jmp_im(pc_start - s->cs_base);
> -            if (s->tb->cflags & CF_USE_ICOUNT) {
> +            if (s->base.tb->cflags & CF_USE_ICOUNT) {
>                  gen_io_start();
>              }
>              gen_helper_rdtscp(cpu_env);
> -            if (s->tb->cflags & CF_USE_ICOUNT) {
> +            if (s->base.tb->cflags & CF_USE_ICOUNT) {
>                  gen_io_end();
>                  gen_jmp(s, s->pc - s->cs_base);
>              }
> @@ -7943,24 +7941,24 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>                  gen_update_cc_op(s);
>                  gen_jmp_im(pc_start - s->cs_base);
>                  if (b & 2) {
> -                    if (s->tb->cflags & CF_USE_ICOUNT) {
> +                    if (s->base.tb->cflags & CF_USE_ICOUNT) {
>                          gen_io_start();
>                      }
>                      gen_op_mov_v_reg(ot, cpu_T0, rm);
>                      gen_helper_write_crN(cpu_env, tcg_const_i32(reg),
>                                           cpu_T0);
> -                    if (s->tb->cflags & CF_USE_ICOUNT) {
> +                    if (s->base.tb->cflags & CF_USE_ICOUNT) {
>                          gen_io_end();
>                      }
>                      gen_jmp_im(s->pc - s->cs_base);
>                      gen_eob(s);
>                  } else {
> -                    if (s->tb->cflags & CF_USE_ICOUNT) {
> +                    if (s->base.tb->cflags & CF_USE_ICOUNT) {
>                          gen_io_start();
>                      }
>                      gen_helper_read_crN(cpu_T0, cpu_env, tcg_const_i32(reg));
>                      gen_op_mov_reg_v(ot, rm, cpu_T0);
> -                    if (s->tb->cflags & CF_USE_ICOUNT) {
> +                    if (s->base.tb->cflags & CF_USE_ICOUNT) {
>                          gen_io_end();
>                      }
>                  }
> @@ -8386,15 +8384,13 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>  {
>      CPUX86State *env = cs->env_ptr;
>      DisasContext dc1, *dc = &dc1;
> -    target_ulong pc_ptr;
>      uint32_t flags;
> -    target_ulong pc_start;
>      target_ulong cs_base;
>      int num_insns;
>      int max_insns;
>
>      /* generate intermediate code */
> -    pc_start = tb->pc;
> +    dc->base.pc_first = tb->pc;
>      cs_base = tb->cs_base;
>      flags = tb->flags;
>
> @@ -8407,11 +8403,11 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>      dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
>      dc->iopl = (flags >> IOPL_SHIFT) & 3;
>      dc->tf = (flags >> TF_SHIFT) & 1;
> -    dc->singlestep_enabled = cs->singlestep_enabled;
> +    dc->base.singlestep_enabled = cs->singlestep_enabled;
>      dc->cc_op = CC_OP_DYNAMIC;
>      dc->cc_op_dirty = false;
>      dc->cs_base = cs_base;
> -    dc->tb = tb;
> +    dc->base.tb = tb;
>      dc->popl_esp_hack = 0;
>      /* select memory access functions */
>      dc->mem_index = 0;
> @@ -8461,8 +8457,8 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>      cpu_ptr1 = tcg_temp_new_ptr();
>      cpu_cc_srcT = tcg_temp_local_new();
>
> -    dc->is_jmp = DISAS_NEXT;
> -    pc_ptr = pc_start;
> +    dc->base.is_jmp = DISAS_NEXT;
> +    dc->base.pc_next = dc->base.pc_first;

Given the point of the DisasContextBase is it should be common
boilerplate it might be worth having a:

   init_dcbase(dc->base, tb, cs->singlestep_enabled)

So we can keep this all in one place rather than in each targets
preamble code.

>      num_insns = 0;
>      max_insns = tb->cflags & CF_COUNT_MASK;
>      if (max_insns == 0) {
> @@ -8474,37 +8470,38 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>
>      gen_tb_start(tb);
>      for(;;) {
> -        tcg_gen_insn_start(pc_ptr, dc->cc_op);
> +        tcg_gen_insn_start(dc->base.pc_next, dc->cc_op);
>          num_insns++;
>
>          /* If RF is set, suppress an internally generated breakpoint.  */
> -        if (unlikely(cpu_breakpoint_test(cs, pc_ptr,
> +        if (unlikely(cpu_breakpoint_test(cs, dc->base.pc_next,
>                                           tb->flags & HF_RF_MASK
>                                           ? BP_GDB : BP_ANY))) {
> -            gen_debug(dc, pc_ptr - dc->cs_base);
> +            gen_debug(dc, dc->base.pc_next - dc->cs_base);
>              /* The address covered by the breakpoint must be included in
>                 [tb->pc, tb->pc + tb->size) in order to for it to be
>                 properly cleared -- thus we increment the PC here so that
>                 the logic setting tb->size below does the right thing.  */
> -            pc_ptr += 1;
> +            dc->base.pc_next += 1;
>              goto done_generating;
>          }
>          if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
>              gen_io_start();
>          }
>
> -        pc_ptr = disas_insn(env, dc, pc_ptr);
> +        dc->base.pc_next = disas_insn(env, dc, dc->base.pc_next);
>          /* stop translation if indicated */
> -        if (dc->is_jmp)
> +        if (dc->base.is_jmp) {
>              break;
> +        }
>          /* if single step mode, we generate only one instruction and
>             generate an exception */
>          /* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
>             the flag and abort the translation to give the irqs a
>             change to be happen */
> -        if (dc->tf || dc->singlestep_enabled ||
> +        if (dc->tf || dc->base.singlestep_enabled ||
>              (flags & HF_INHIBIT_IRQ_MASK)) {
> -            gen_jmp_im(pc_ptr - dc->cs_base);
> +            gen_jmp_im(dc->base.pc_next - dc->cs_base);
>              gen_eob(dc);
>              break;
>          }
> @@ -8515,23 +8512,23 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>             because an exception hasn't stopped this code.
>           */
>          if ((tb->cflags & CF_USE_ICOUNT)
> -            && ((pc_ptr & TARGET_PAGE_MASK)
> -                != ((pc_ptr + TARGET_MAX_INSN_SIZE - 1) & TARGET_PAGE_MASK)
> -                || (pc_ptr & ~TARGET_PAGE_MASK) == 0)) {
> -            gen_jmp_im(pc_ptr - dc->cs_base);
> +            && ((dc->base.pc_next & TARGET_PAGE_MASK)
> +                != ((dc->base.pc_next + TARGET_MAX_INSN_SIZE - 1) & TARGET_PAGE_MASK)
> +                || (dc->base.pc_next & ~TARGET_PAGE_MASK) == 0)) {
> +            gen_jmp_im(dc->base.pc_next - dc->cs_base);
>              gen_eob(dc);
>              break;
>          }
>          /* if too long translation, stop generation too */
>          if (tcg_op_buf_full() ||
> -            (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32) ||
> +            (dc->base.pc_next - dc->base.pc_first) >= (TARGET_PAGE_SIZE - 32) ||
>              num_insns >= max_insns) {
> -            gen_jmp_im(pc_ptr - dc->cs_base);
> +            gen_jmp_im(dc->base.pc_next - dc->cs_base);
>              gen_eob(dc);
>              break;
>          }
>          if (singlestep) {
> -            gen_jmp_im(pc_ptr - dc->cs_base);
> +            gen_jmp_im(dc->base.pc_next - dc->cs_base);
>              gen_eob(dc);
>              break;
>          }
> @@ -8543,24 +8540,25 @@ done_generating:
>
>  #ifdef DEBUG_DISAS
>      if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
> -        && qemu_log_in_addr_range(pc_start)) {
> +        && qemu_log_in_addr_range(dc->base.pc_first)) {
>          int disas_flags;
>          qemu_log_lock();
>          qemu_log("----------------\n");
> -        qemu_log("IN: %s\n", lookup_symbol(pc_start));
> +        qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
>  #ifdef TARGET_X86_64
>          if (dc->code64)
>              disas_flags = 2;
>          else
>  #endif
>              disas_flags = !dc->code32;
> -        log_target_disas(cs, pc_start, pc_ptr - pc_start, disas_flags);
> +        log_target_disas(cs, dc->base.pc_first, dc->base.pc_next - dc->base.pc_first,
> +                         disas_flags);
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
>  #endif
>
> -    tb->size = pc_ptr - pc_start;
> +    tb->size = dc->base.pc_next - dc->base.pc_first;
>      tb->icount = num_insns;
>  }
>

That said:

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

--
Alex Bennée

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 06/27] target/i386: [tcg] Port to init_disas_context
  2017-07-07 12:04 ` [Qemu-devel] [PATCH v12 06/27] target/i386: [tcg] Port to init_disas_context Lluís Vilanova
@ 2017-07-12  9:20   ` Alex Bennée
  0 siblings, 0 replies; 57+ messages in thread
From: Alex Bennée @ 2017-07-12  9:20 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Emilio G. Cota, Richard Henderson, Peter Crosthwaite,
	Paolo Bonzini, Eduardo Habkost


Lluís Vilanova <vilanova@ac.upc.edu> writes:

> Incrementally paves the way towards using the generic instruction translation
> loop.
>
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> Reviewed-by: Richard Henderson <rth@twiddle.net>

Hah, I see now ;-)

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/i386/translate.c |   41 +++++++++++++++++++++++------------------
>  1 file changed, 23 insertions(+), 18 deletions(-)
>
> diff --git a/target/i386/translate.c b/target/i386/translate.c
> index f61f5c7227..7819545e37 100644
> --- a/target/i386/translate.c
> +++ b/target/i386/translate.c
> @@ -8379,20 +8379,12 @@ void tcg_x86_init(void)
>      }
>  }
>
> -/* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
> +static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
>  {
> -    CPUX86State *env = cs->env_ptr;
> -    DisasContext dc1, *dc = &dc1;
> -    uint32_t flags;
> -    target_ulong cs_base;
> -    int num_insns;
> -    int max_insns;
> -
> -    /* generate intermediate code */
> -    dc->base.pc_first = tb->pc;
> -    cs_base = tb->cs_base;
> -    flags = tb->flags;
> +    DisasContext *dc = container_of(dcbase, DisasContext, base);
> +    CPUX86State *env = cpu->env_ptr;
> +    uint32_t flags = dc->base.tb->flags;
> +    target_ulong cs_base = dc->base.tb->cs_base;
>
>      dc->pe = (flags >> HF_PE_SHIFT) & 1;
>      dc->code32 = (flags >> HF_CS32_SHIFT) & 1;
> @@ -8403,11 +8395,9 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>      dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
>      dc->iopl = (flags >> IOPL_SHIFT) & 3;
>      dc->tf = (flags >> TF_SHIFT) & 1;
> -    dc->base.singlestep_enabled = cs->singlestep_enabled;
>      dc->cc_op = CC_OP_DYNAMIC;
>      dc->cc_op_dirty = false;
>      dc->cs_base = cs_base;
> -    dc->base.tb = tb;
>      dc->popl_esp_hack = 0;
>      /* select memory access functions */
>      dc->mem_index = 0;
> @@ -8425,7 +8415,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>      dc->code64 = (flags >> HF_CS64_SHIFT) & 1;
>  #endif
>      dc->flags = flags;
> -    dc->jmp_opt = !(dc->tf || cs->singlestep_enabled ||
> +    dc->jmp_opt = !(dc->tf || dc->base.singlestep_enabled ||
>                      (flags & HF_INHIBIT_IRQ_MASK));
>      /* Do not optimize repz jumps at all in icount mode, because
>         rep movsS instructions are execured with different paths
> @@ -8437,7 +8427,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>         record/replay modes and there will always be an
>         additional step for ecx=0 when icount is enabled.
>       */
> -    dc->repz_opt = !dc->jmp_opt && !(tb->cflags & CF_USE_ICOUNT);
> +    dc->repz_opt = !dc->jmp_opt && !(dc->base.tb->cflags & CF_USE_ICOUNT);
>  #if 0
>      /* check addseg logic */
>      if (!dc->addseg && (dc->vm86 || !dc->pe || !dc->code32))
> @@ -8456,9 +8446,24 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>      cpu_ptr0 = tcg_temp_new_ptr();
>      cpu_ptr1 = tcg_temp_new_ptr();
>      cpu_cc_srcT = tcg_temp_local_new();
> +}
>
> +/* generate intermediate code for basic block 'tb'.  */
> +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
> +{
> +    CPUX86State *env = cs->env_ptr;
> +    DisasContext dc1, *dc = &dc1;
> +    int num_insns;
> +    int max_insns;
> +
> +    /* generate intermediate code */
> +    dc->base.singlestep_enabled = cs->singlestep_enabled;
> +    dc->base.tb = tb;
>      dc->base.is_jmp = DISAS_NEXT;
> +    dc->base.pc_first = tb->pc;
>      dc->base.pc_next = dc->base.pc_first;
> +    i386_tr_init_disas_context(&dc->base, cs);
> +
>      num_insns = 0;
>      max_insns = tb->cflags & CF_COUNT_MASK;
>      if (max_insns == 0) {
> @@ -8500,7 +8505,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>             the flag and abort the translation to give the irqs a
>             change to be happen */
>          if (dc->tf || dc->base.singlestep_enabled ||
> -            (flags & HF_INHIBIT_IRQ_MASK)) {
> +            (dc->base.tb->flags & HF_INHIBIT_IRQ_MASK)) {
>              gen_jmp_im(dc->base.pc_next - dc->cs_base);
>              gen_eob(dc);
>              break;


--
Alex Bennée

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 07/27] target/i386: [tcg] Port to insn_start
  2017-07-07 12:08 ` [Qemu-devel] [PATCH v12 07/27] target/i386: [tcg] Port to insn_start Lluís Vilanova
@ 2017-07-12  9:21   ` Alex Bennée
  0 siblings, 0 replies; 57+ messages in thread
From: Alex Bennée @ 2017-07-12  9:21 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Emilio G. Cota, Richard Henderson, Peter Crosthwaite,
	Paolo Bonzini, Eduardo Habkost


Lluís Vilanova <vilanova@ac.upc.edu> writes:

> Incrementally paves the way towards using the generic instruction translation
> loop.
>
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> Reviewed-by: Emilio G. Cota <cota@braap.org>
> Reviewed-by: Richard Henderson <rth@twiddle.net>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/i386/translate.c |    9 ++++++++-
>  1 file changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/target/i386/translate.c b/target/i386/translate.c
> index 7819545e37..a4b9e5628f 100644
> --- a/target/i386/translate.c
> +++ b/target/i386/translate.c
> @@ -8448,6 +8448,13 @@ static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
>      cpu_cc_srcT = tcg_temp_local_new();
>  }
>
> +static void i386_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
> +{
> +    DisasContext *dc = container_of(dcbase, DisasContext, base);
> +
> +    tcg_gen_insn_start(dc->base.pc_next, dc->cc_op);
> +}
> +
>  /* generate intermediate code for basic block 'tb'.  */
>  void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>  {
> @@ -8475,7 +8482,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>
>      gen_tb_start(tb);
>      for(;;) {
> -        tcg_gen_insn_start(dc->base.pc_next, dc->cc_op);
> +        i386_tr_insn_start(&dc->base, cs);
>          num_insns++;
>
>          /* If RF is set, suppress an internally generated breakpoint.  */


--
Alex Bennée

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 13/27] target/arm: [tcg] Port to DisasContextBase
  2017-07-07 12:33 ` [Qemu-devel] [PATCH v12 13/27] target/arm: [tcg] Port to DisasContextBase Lluís Vilanova
@ 2017-07-12  9:25   ` Alex Bennée
  0 siblings, 0 replies; 57+ messages in thread
From: Alex Bennée @ 2017-07-12  9:25 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Emilio G. Cota, Richard Henderson, Peter Crosthwaite,
	Paolo Bonzini, Peter Maydell, open list:ARM


Lluís Vilanova <vilanova@ac.upc.edu> writes:

> Incrementally paves the way towards using the generic instruction translation
> loop.
>
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> Reviewed-by: Richard Henderson <rth@twiddle.net>

Heads up there will be some clashes with the eret patches but hopefully
simple to fix. Otherwise looks OK to me:

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/arm/translate-a64.c |  119 ++++++++++++++++++++++----------------------
>  target/arm/translate.c     |  114 +++++++++++++++++++++---------------------
>  target/arm/translate.h     |   11 ++--
>  3 files changed, 121 insertions(+), 123 deletions(-)
>
> diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
> index f9bd1a9679..4270ac3847 100644
> --- a/target/arm/translate-a64.c
> +++ b/target/arm/translate-a64.c
> @@ -304,7 +304,7 @@ static void gen_exception_internal_insn(DisasContext *s, int offset, int excp)
>  {
>      gen_a64_set_pc_im(s->pc - offset);
>      gen_exception_internal(excp);
> -    s->is_jmp = DISAS_EXC;
> +    s->base.is_jmp = DISAS_EXC;
>  }
>
>  static void gen_exception_insn(DisasContext *s, int offset, int excp,
> @@ -312,7 +312,7 @@ static void gen_exception_insn(DisasContext *s, int offset, int excp,
>  {
>      gen_a64_set_pc_im(s->pc - offset);
>      gen_exception(excp, syndrome, target_el);
> -    s->is_jmp = DISAS_EXC;
> +    s->base.is_jmp = DISAS_EXC;
>  }
>
>  static void gen_ss_advance(DisasContext *s)
> @@ -340,7 +340,7 @@ static void gen_step_complete_exception(DisasContext *s)
>      gen_ss_advance(s);
>      gen_exception(EXCP_UDEF, syn_swstep(s->ss_same_el, 1, s->is_ldex),
>                    default_exception_el(s));
> -    s->is_jmp = DISAS_EXC;
> +    s->base.is_jmp = DISAS_EXC;
>  }
>
>  static inline bool use_goto_tb(DisasContext *s, int n, uint64_t dest)
> @@ -348,13 +348,13 @@ static inline bool use_goto_tb(DisasContext *s, int n, uint64_t dest)
>      /* No direct tb linking with singlestep (either QEMU's or the ARM
>       * debug architecture kind) or deterministic io
>       */
> -    if (s->singlestep_enabled || s->ss_active || (s->tb->cflags & CF_LAST_IO)) {
> +    if (s->base.singlestep_enabled || s->ss_active || (s->base.tb->cflags & CF_LAST_IO)) {
>          return false;
>      }
>
>  #ifndef CONFIG_USER_ONLY
>      /* Only link tbs from inside the same guest page */
> -    if ((s->tb->pc & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
> +    if ((s->base.tb->pc & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
>          return false;
>      }
>  #endif
> @@ -366,21 +366,21 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
>  {
>      TranslationBlock *tb;
>
> -    tb = s->tb;
> +    tb = s->base.tb;
>      if (use_goto_tb(s, n, dest)) {
>          tcg_gen_goto_tb(n);
>          gen_a64_set_pc_im(dest);
>          tcg_gen_exit_tb((intptr_t)tb + n);
> -        s->is_jmp = DISAS_TB_JUMP;
> +        s->base.is_jmp = DISAS_TB_JUMP;
>      } else {
>          gen_a64_set_pc_im(dest);
>          if (s->ss_active) {
>              gen_step_complete_exception(s);
> -        } else if (s->singlestep_enabled) {
> +        } else if (s->base.singlestep_enabled) {
>              gen_exception_internal(EXCP_DEBUG);
>          } else {
>              tcg_gen_lookup_and_goto_ptr(cpu_pc);
> -            s->is_jmp = DISAS_TB_JUMP;
> +            s->base.is_jmp = DISAS_TB_JUMP;
>          }
>      }
>  }
> @@ -1331,16 +1331,16 @@ static void handle_hint(DisasContext *s, uint32_t insn,
>      case 0: /* NOP */
>          return;
>      case 3: /* WFI */
> -        s->is_jmp = DISAS_WFI;
> +        s->base.is_jmp = DISAS_WFI;
>          return;
>      case 1: /* YIELD */
>          if (!parallel_cpus) {
> -            s->is_jmp = DISAS_YIELD;
> +            s->base.is_jmp = DISAS_YIELD;
>          }
>          return;
>      case 2: /* WFE */
>          if (!parallel_cpus) {
> -            s->is_jmp = DISAS_WFE;
> +            s->base.is_jmp = DISAS_WFE;
>          }
>          return;
>      case 4: /* SEV */
> @@ -1393,7 +1393,7 @@ static void handle_sync(DisasContext *s, uint32_t insn,
>           * a self-modified code correctly and also to take
>           * any pending interrupts immediately.
>           */
> -        s->is_jmp = DISAS_UPDATE;
> +        s->base.is_jmp = DISAS_UPDATE;
>          return;
>      default:
>          unallocated_encoding(s);
> @@ -1424,7 +1424,7 @@ static void handle_msr_i(DisasContext *s, uint32_t insn,
>          tcg_temp_free_i32(tcg_op);
>          /* For DAIFClear, exit the cpu loop to re-evaluate pending IRQs.  */
>          gen_a64_set_pc_im(s->pc);
> -        s->is_jmp = (op == 0x1f ? DISAS_EXIT : DISAS_JUMP);
> +        s->base.is_jmp = (op == 0x1f ? DISAS_EXIT : DISAS_JUMP);
>          break;
>      }
>      default:
> @@ -1559,7 +1559,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
>          break;
>      }
>
> -    if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
> +    if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
>          gen_io_start();
>      }
>
> @@ -1590,16 +1590,16 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
>          }
>      }
>
> -    if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
> +    if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
>          /* I/O operations must end the TB here (whether read or write) */
>          gen_io_end();
> -        s->is_jmp = DISAS_UPDATE;
> +        s->base.is_jmp = DISAS_UPDATE;
>      } else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {
>          /* We default to ending the TB on a coprocessor register write,
>           * but allow this to be suppressed by the register definition
>           * (usually only necessary to work around guest bugs).
>           */
> -        s->is_jmp = DISAS_UPDATE;
> +        s->base.is_jmp = DISAS_UPDATE;
>      }
>  }
>
> @@ -1788,7 +1788,7 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
>              return;
>          }
>          gen_helper_exception_return(cpu_env);
> -        s->is_jmp = DISAS_JUMP;
> +        s->base.is_jmp = DISAS_JUMP;
>          return;
>      case 5: /* DRPS */
>          if (rn != 0x1f) {
> @@ -1802,7 +1802,7 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
>          return;
>      }
>
> -    s->is_jmp = DISAS_JUMP;
> +    s->base.is_jmp = DISAS_JUMP;
>  }
>
>  /* C3.2 Branches, exception generating and system instructions */
> @@ -11190,23 +11190,23 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
>      free_tmp_a64(s);
>  }
>
> -void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
> +void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
> +                               TranslationBlock *tb)
>  {
>      CPUARMState *env = cs->env_ptr;
>      ARMCPU *cpu = arm_env_get_cpu(env);
> -    DisasContext dc1, *dc = &dc1;
> -    target_ulong pc_start;
> +    DisasContext *dc = container_of(dcbase, DisasContext, base);
>      target_ulong next_page_start;
> -    int num_insns;
>      int max_insns;
>
> -    pc_start = tb->pc;
> +    dc->base.tb = tb;
> +    dc->base.pc_first = dc->base.tb->pc;
> +    dc->base.pc_next = dc->base.pc_first;
> +    dc->base.is_jmp = DISAS_NEXT;
> +    dc->base.num_insns = 0;
> +    dc->base.singlestep_enabled = cs->singlestep_enabled;
>
> -    dc->tb = tb;
> -
> -    dc->is_jmp = DISAS_NEXT;
> -    dc->pc = pc_start;
> -    dc->singlestep_enabled = cs->singlestep_enabled;
> +    dc->pc = dc->base.pc_first;
>      dc->condjmp = 0;
>
>      dc->aarch64 = 1;
> @@ -11217,17 +11217,17 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
>                                 !arm_el_is_aa64(env, 3);
>      dc->thumb = 0;
>      dc->sctlr_b = 0;
> -    dc->be_data = ARM_TBFLAG_BE_DATA(tb->flags) ? MO_BE : MO_LE;
> +    dc->be_data = ARM_TBFLAG_BE_DATA(dc->base.tb->flags) ? MO_BE : MO_LE;
>      dc->condexec_mask = 0;
>      dc->condexec_cond = 0;
> -    dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(tb->flags));
> -    dc->tbi0 = ARM_TBFLAG_TBI0(tb->flags);
> -    dc->tbi1 = ARM_TBFLAG_TBI1(tb->flags);
> +    dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(dc->base.tb->flags));
> +    dc->tbi0 = ARM_TBFLAG_TBI0(dc->base.tb->flags);
> +    dc->tbi1 = ARM_TBFLAG_TBI1(dc->base.tb->flags);
>      dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
>  #if !defined(CONFIG_USER_ONLY)
>      dc->user = (dc->current_el == 0);
>  #endif
> -    dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(tb->flags);
> +    dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(dc->base.tb->flags);
>      dc->vec_len = 0;
>      dc->vec_stride = 0;
>      dc->cp_regs = cpu->cp_regs;
> @@ -11248,16 +11248,15 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
>       *   emit code to generate a software step exception
>       *   end the TB
>       */
> -    dc->ss_active = ARM_TBFLAG_SS_ACTIVE(tb->flags);
> -    dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(tb->flags);
> +    dc->ss_active = ARM_TBFLAG_SS_ACTIVE(dc->base.tb->flags);
> +    dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(dc->base.tb->flags);
>      dc->is_ldex = false;
>      dc->ss_same_el = (arm_debug_target_el(env) == dc->current_el);
>
>      init_tmp_a64_array(dc);
>
> -    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
> -    num_insns = 0;
> -    max_insns = tb->cflags & CF_COUNT_MASK;
> +    next_page_start = (dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
> +    max_insns = dc->base.tb->cflags & CF_COUNT_MASK;
>      if (max_insns == 0) {
>          max_insns = CF_COUNT_MASK;
>      }
> @@ -11270,9 +11269,9 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
>      tcg_clear_temp_count();
>
>      do {
> +        dc->base.num_insns++;
>          dc->insn_start_idx = tcg_op_buf_count();
>          tcg_gen_insn_start(dc->pc, 0, 0);
> -        num_insns++;
>
>          if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
>              CPUBreakpoint *bp;
> @@ -11282,14 +11281,14 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
>                          gen_a64_set_pc_im(dc->pc);
>                          gen_helper_check_breakpoints(cpu_env);
>                          /* End the TB early; it likely won't be executed */
> -                        dc->is_jmp = DISAS_UPDATE;
> +                        dc->base.is_jmp = DISAS_UPDATE;
>                      } else {
>                          gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
>                          /* The address covered by the breakpoint must be
> -                           included in [tb->pc, tb->pc + tb->size) in order
> +                           included in [dc->base.tb->pc, dc->base.tb->pc + dc->base.tb->size) in order
>                             to for it to be properly cleared -- thus we
>                             increment the PC here so that the logic setting
> -                           tb->size below does the right thing.  */
> +                           dc->base.tb->size below does the right thing.  */
>                          dc->pc += 4;
>                          goto done_generating;
>                      }
> @@ -11298,7 +11297,7 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
>              }
>          }
>
> -        if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
> +        if (dc->base.num_insns == max_insns && (dc->base.tb->cflags & CF_LAST_IO)) {
>              gen_io_start();
>          }
>
> @@ -11313,10 +11312,10 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
>               * "did not step an insn" case, and so the syndrome ISV and EX
>               * bits should be zero.
>               */
> -            assert(num_insns == 1);
> +            assert(dc->base.num_insns == 1);
>              gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
>                            default_exception_el(dc));
> -            dc->is_jmp = DISAS_EXC;
> +            dc->base.is_jmp = DISAS_EXC;
>              break;
>          }
>
> @@ -11332,26 +11331,26 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
>           * Also stop translation when a page boundary is reached.  This
>           * ensures prefetch aborts occur at the right place.
>           */
> -    } while (!dc->is_jmp && !tcg_op_buf_full() &&
> +    } while (!dc->base.is_jmp && !tcg_op_buf_full() &&
>               !cs->singlestep_enabled &&
>               !singlestep &&
>               !dc->ss_active &&
>               dc->pc < next_page_start &&
> -             num_insns < max_insns);
> +             dc->base.num_insns < max_insns);
>
> -    if (tb->cflags & CF_LAST_IO) {
> +    if (dc->base.tb->cflags & CF_LAST_IO) {
>          gen_io_end();
>      }
>
>      if (unlikely(cs->singlestep_enabled || dc->ss_active)
> -        && dc->is_jmp != DISAS_EXC) {
> +        && dc->base.is_jmp != DISAS_EXC) {
>          /* Note that this means single stepping WFI doesn't halt the CPU.
>           * For conditional branch insns this is harmless unreachable code as
>           * gen_goto_tb() has already handled emitting the debug exception
>           * (and thus a tb-jump is not possible when singlestepping).
>           */
> -        assert(dc->is_jmp != DISAS_TB_JUMP);
> -        if (dc->is_jmp != DISAS_JUMP) {
> +        assert(dc->base.is_jmp != DISAS_TB_JUMP);
> +        if (dc->base.is_jmp != DISAS_JUMP) {
>              gen_a64_set_pc_im(dc->pc);
>          }
>          if (cs->singlestep_enabled) {
> @@ -11360,7 +11359,7 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
>              gen_step_complete_exception(dc);
>          }
>      } else {
> -        switch (dc->is_jmp) {
> +        switch (dc->base.is_jmp) {
>          case DISAS_NEXT:
>              gen_goto_tb(dc, 1, dc->pc);
>              break;
> @@ -11401,20 +11400,20 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
>      }
>
>  done_generating:
> -    gen_tb_end(tb, num_insns);
> +    gen_tb_end(tb, dc->base.num_insns);
>
>  #ifdef DEBUG_DISAS
>      if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) &&
> -        qemu_log_in_addr_range(pc_start)) {
> +        qemu_log_in_addr_range(dc->base.pc_first)) {
>          qemu_log_lock();
>          qemu_log("----------------\n");
> -        qemu_log("IN: %s\n", lookup_symbol(pc_start));
> -        log_target_disas(cs, pc_start, dc->pc - pc_start,
> +        qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
> +        log_target_disas(cs, dc->base.pc_first, dc->pc - dc->base.pc_first,
>                           4 | (bswap_code(dc->sctlr_b) ? 2 : 0));
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
>  #endif
> -    tb->size = dc->pc - pc_start;
> -    tb->icount = num_insns;
> +    dc->base.tb->size = dc->pc - dc->base.pc_first;
> +    dc->base.tb->icount = dc->base.num_insns;
>  }
> diff --git a/target/arm/translate.c b/target/arm/translate.c
> index e80cc357c1..15b4fcb417 100644
> --- a/target/arm/translate.c
> +++ b/target/arm/translate.c
> @@ -224,7 +224,7 @@ static void store_reg(DisasContext *s, int reg, TCGv_i32 var)
>           * We choose to ignore [1:0] in ARM mode for all architecture versions.
>           */
>          tcg_gen_andi_i32(var, var, s->thumb ? ~1 : ~3);
> -        s->is_jmp = DISAS_JUMP;
> +        s->base.is_jmp = DISAS_JUMP;
>      }
>      tcg_gen_mov_i32(cpu_R[reg], var);
>      tcg_temp_free_i32(var);
> @@ -297,7 +297,7 @@ static void gen_step_complete_exception(DisasContext *s)
>      gen_ss_advance(s);
>      gen_exception(EXCP_UDEF, syn_swstep(s->ss_same_el, 1, s->is_ldex),
>                    default_exception_el(s));
> -    s->is_jmp = DISAS_EXC;
> +    s->base.is_jmp = DISAS_EXC;
>  }
>
>  static void gen_singlestep_exception(DisasContext *s)
> @@ -321,7 +321,7 @@ static inline bool is_singlestepping(DisasContext *s)
>       * misnamed as it only means "one instruction per TB" and doesn't
>       * affect the code we generate.
>       */
> -    return s->singlestep_enabled || s->ss_active;
> +    return s->base.singlestep_enabled || s->ss_active;
>  }
>
>  static void gen_smul_dual(TCGv_i32 a, TCGv_i32 b)
> @@ -928,7 +928,7 @@ static inline void gen_bx_im(DisasContext *s, uint32_t addr)
>  {
>      TCGv_i32 tmp;
>
> -    s->is_jmp = DISAS_JUMP;
> +    s->base.is_jmp = DISAS_JUMP;
>      if (s->thumb != (addr & 1)) {
>          tmp = tcg_temp_new_i32();
>          tcg_gen_movi_i32(tmp, addr & 1);
> @@ -941,7 +941,7 @@ static inline void gen_bx_im(DisasContext *s, uint32_t addr)
>  /* Set PC and Thumb state from var.  var is marked as dead.  */
>  static inline void gen_bx(DisasContext *s, TCGv_i32 var)
>  {
> -    s->is_jmp = DISAS_JUMP;
> +    s->base.is_jmp = DISAS_JUMP;
>      tcg_gen_andi_i32(cpu_R[15], var, ~1);
>      tcg_gen_andi_i32(var, var, 1);
>      store_cpu_field(var, thumb);
> @@ -955,11 +955,11 @@ static inline void gen_bx(DisasContext *s, TCGv_i32 var)
>  static inline void gen_bx_excret(DisasContext *s, TCGv_i32 var)
>  {
>      /* Generate the same code here as for a simple bx, but flag via
> -     * s->is_jmp that we need to do the rest of the work later.
> +     * s->base.is_jmp that we need to do the rest of the work later.
>       */
>      gen_bx(s, var);
>      if (s->v7m_handler_mode && arm_dc_feature(s, ARM_FEATURE_M)) {
> -        s->is_jmp = DISAS_BX_EXCRET;
> +        s->base.is_jmp = DISAS_BX_EXCRET;
>      }
>  }
>
> @@ -1159,7 +1159,7 @@ static inline void gen_hvc(DisasContext *s, int imm16)
>       */
>      s->svc_imm = imm16;
>      gen_set_pc_im(s, s->pc);
> -    s->is_jmp = DISAS_HVC;
> +    s->base.is_jmp = DISAS_HVC;
>  }
>
>  static inline void gen_smc(DisasContext *s)
> @@ -1174,7 +1174,7 @@ static inline void gen_smc(DisasContext *s)
>      gen_helper_pre_smc(cpu_env, tmp);
>      tcg_temp_free_i32(tmp);
>      gen_set_pc_im(s, s->pc);
> -    s->is_jmp = DISAS_SMC;
> +    s->base.is_jmp = DISAS_SMC;
>  }
>
>  static void gen_exception_internal_insn(DisasContext *s, int offset, int excp)
> @@ -1182,7 +1182,7 @@ static void gen_exception_internal_insn(DisasContext *s, int offset, int excp)
>      gen_set_condexec(s);
>      gen_set_pc_im(s, s->pc - offset);
>      gen_exception_internal(excp);
> -    s->is_jmp = DISAS_EXC;
> +    s->base.is_jmp = DISAS_EXC;
>  }
>
>  static void gen_exception_insn(DisasContext *s, int offset, int excp,
> @@ -1191,14 +1191,14 @@ static void gen_exception_insn(DisasContext *s, int offset, int excp,
>      gen_set_condexec(s);
>      gen_set_pc_im(s, s->pc - offset);
>      gen_exception(excp, syn, target_el);
> -    s->is_jmp = DISAS_EXC;
> +    s->base.is_jmp = DISAS_EXC;
>  }
>
>  /* Force a TB lookup after an instruction that changes the CPU state.  */
>  static inline void gen_lookup_tb(DisasContext *s)
>  {
>      tcg_gen_movi_i32(cpu_R[15], s->pc & ~1);
> -    s->is_jmp = DISAS_EXIT;
> +    s->base.is_jmp = DISAS_EXIT;
>  }
>
>  static inline void gen_hlt(DisasContext *s, int imm)
> @@ -4143,7 +4143,7 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
>  static inline bool use_goto_tb(DisasContext *s, target_ulong dest)
>  {
>  #ifndef CONFIG_USER_ONLY
> -    return (s->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) ||
> +    return (s->base.tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) ||
>             ((s->pc - 1) & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
>  #else
>      return true;
> @@ -4163,7 +4163,7 @@ static void gen_goto_tb(DisasContext *s, int n, target_ulong dest)
>      if (use_goto_tb(s, dest)) {
>          tcg_gen_goto_tb(n);
>          gen_set_pc_im(s, dest);
> -        tcg_gen_exit_tb((uintptr_t)s->tb + n);
> +        tcg_gen_exit_tb((uintptr_t)s->base.tb + n);
>      } else {
>          gen_set_pc_im(s, dest);
>          gen_goto_ptr();
> @@ -4179,7 +4179,7 @@ static inline void gen_jmp (DisasContext *s, uint32_t dest)
>          gen_bx_im(s, dest);
>      } else {
>          gen_goto_tb(s, 0, dest);
> -        s->is_jmp = DISAS_TB_JUMP;
> +        s->base.is_jmp = DISAS_TB_JUMP;
>      }
>  }
>
> @@ -4430,7 +4430,7 @@ static void gen_msr_banked(DisasContext *s, int r, int sysm, int rn)
>      tcg_temp_free_i32(tcg_tgtmode);
>      tcg_temp_free_i32(tcg_regno);
>      tcg_temp_free_i32(tcg_reg);
> -    s->is_jmp = DISAS_UPDATE;
> +    s->base.is_jmp = DISAS_UPDATE;
>  }
>
>  static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn)
> @@ -4452,7 +4452,7 @@ static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn)
>      tcg_temp_free_i32(tcg_tgtmode);
>      tcg_temp_free_i32(tcg_regno);
>      store_reg(s, rn, tcg_reg);
> -    s->is_jmp = DISAS_UPDATE;
> +    s->base.is_jmp = DISAS_UPDATE;
>  }
>
>  /* Store value to PC as for an exception return (ie don't
> @@ -4475,7 +4475,7 @@ static void gen_rfe(DisasContext *s, TCGv_i32 pc, TCGv_i32 cpsr)
>       */
>      gen_helper_cpsr_write_eret(cpu_env, cpsr);
>      tcg_temp_free_i32(cpsr);
> -    s->is_jmp = DISAS_JUMP;
> +    s->base.is_jmp = DISAS_JUMP;
>  }
>
>  /* Generate an old-style exception return. Marks pc as dead. */
> @@ -4498,17 +4498,17 @@ static void gen_nop_hint(DisasContext *s, int val)
>      case 1: /* yield */
>          if (!parallel_cpus) {
>              gen_set_pc_im(s, s->pc);
> -            s->is_jmp = DISAS_YIELD;
> +            s->base.is_jmp = DISAS_YIELD;
>          }
>          break;
>      case 3: /* wfi */
>          gen_set_pc_im(s, s->pc);
> -        s->is_jmp = DISAS_WFI;
> +        s->base.is_jmp = DISAS_WFI;
>          break;
>      case 2: /* wfe */
>          if (!parallel_cpus) {
>              gen_set_pc_im(s, s->pc);
> -            s->is_jmp = DISAS_WFE;
> +            s->base.is_jmp = DISAS_WFE;
>          }
>          break;
>      case 4: /* sev */
> @@ -7647,13 +7647,13 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
>                  return 1;
>              }
>              gen_set_pc_im(s, s->pc);
> -            s->is_jmp = DISAS_WFI;
> +            s->base.is_jmp = DISAS_WFI;
>              return 0;
>          default:
>              break;
>          }
>
> -        if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
> +        if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
>              gen_io_start();
>          }
>
> @@ -7744,7 +7744,7 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
>              }
>          }
>
> -        if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
> +        if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
>              /* I/O operations must end the TB here (whether read or write) */
>              gen_io_end();
>              gen_lookup_tb(s);
> @@ -8058,7 +8058,7 @@ static void gen_srs(DisasContext *s,
>          tcg_temp_free_i32(tmp);
>      }
>      tcg_temp_free_i32(addr);
> -    s->is_jmp = DISAS_UPDATE;
> +    s->base.is_jmp = DISAS_UPDATE;
>  }
>
>  static void disas_arm_insn(DisasContext *s, unsigned int insn)
> @@ -8146,7 +8146,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
>              /* setend */
>              if (((insn >> 9) & 1) != !!(s->be_data == MO_BE)) {
>                  gen_helper_setend(cpu_env);
> -                s->is_jmp = DISAS_UPDATE;
> +                s->base.is_jmp = DISAS_UPDATE;
>              }
>              return;
>          } else if ((insn & 0x0fffff00) == 0x057ff000) {
> @@ -9519,7 +9519,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
>                      tmp = load_cpu_field(spsr);
>                      gen_helper_cpsr_write_eret(cpu_env, tmp);
>                      tcg_temp_free_i32(tmp);
> -                    s->is_jmp = DISAS_JUMP;
> +                    s->base.is_jmp = DISAS_JUMP;
>                  }
>              }
>              break;
> @@ -9557,7 +9557,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
>              /* swi */
>              gen_set_pc_im(s, s->pc);
>              s->svc_imm = extract32(insn, 0, 24);
> -            s->is_jmp = DISAS_SWI;
> +            s->base.is_jmp = DISAS_SWI;
>              break;
>          default:
>          illegal_op:
> @@ -11619,7 +11619,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
>                  ARCH(6);
>                  if (((insn >> 3) & 1) != !!(s->be_data == MO_BE)) {
>                      gen_helper_setend(cpu_env);
> -                    s->is_jmp = DISAS_UPDATE;
> +                    s->base.is_jmp = DISAS_UPDATE;
>                  }
>                  break;
>              case 3:
> @@ -11713,7 +11713,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
>              /* swi */
>              gen_set_pc_im(s, s->pc);
>              s->svc_imm = extract32(insn, 0, 8);
> -            s->is_jmp = DISAS_SWI;
> +            s->base.is_jmp = DISAS_SWI;
>              break;
>          }
>          /* generate a conditional jump to next instruction */
> @@ -11792,9 +11792,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>      CPUARMState *env = cs->env_ptr;
>      ARMCPU *cpu = arm_env_get_cpu(env);
>      DisasContext dc1, *dc = &dc1;
> -    target_ulong pc_start;
>      target_ulong next_page_start;
> -    int num_insns;
>      int max_insns;
>      bool end_of_page;
>
> @@ -11804,17 +11802,18 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>       * the A32/T32 complexity to do with conditional execution/IT blocks/etc.
>       */
>      if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
> -        gen_intermediate_code_a64(cs, tb);
> +        gen_intermediate_code_a64(&dc->base, cs, tb);
>          return;
>      }
>
> -    pc_start = tb->pc;
> +    dc->base.tb = tb;
> +    dc->base.pc_first = tb->pc;
> +    dc->base.pc_next = dc->base.pc_first;
> +    dc->base.is_jmp = DISAS_NEXT;
> +    dc->base.num_insns = 0;
> +    dc->base.singlestep_enabled = cs->singlestep_enabled;
>
> -    dc->tb = tb;
> -
> -    dc->is_jmp = DISAS_NEXT;
> -    dc->pc = pc_start;
> -    dc->singlestep_enabled = cs->singlestep_enabled;
> +    dc->pc = dc->base.pc_first;
>      dc->condjmp = 0;
>
>      dc->aarch64 = 0;
> @@ -11871,8 +11870,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>      cpu_V1 = cpu_F1d;
>      /* FIXME: cpu_M0 can probably be the same as cpu_V0.  */
>      cpu_M0 = tcg_temp_new_i64();
> -    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
> -    num_insns = 0;
> +    next_page_start = (dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
>      max_insns = tb->cflags & CF_COUNT_MASK;
>      if (max_insns == 0) {
>          max_insns = CF_COUNT_MASK;
> @@ -11924,11 +11922,11 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>          store_cpu_field(tmp, condexec_bits);
>        }
>      do {
> +        dc->base.num_insns++;
>          dc->insn_start_idx = tcg_op_buf_count();
>          tcg_gen_insn_start(dc->pc,
>                             (dc->condexec_cond << 4) | (dc->condexec_mask >> 1),
>                             0);
> -        num_insns++;
>
>  #ifdef CONFIG_USER_ONLY
>          /* Intercept jump to the magic kernel page.  */
> @@ -11936,7 +11934,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>              /* We always get here via a jump, so know we are not in a
>                 conditional execution block.  */
>              gen_exception_internal(EXCP_KERNEL_TRAP);
> -            dc->is_jmp = DISAS_EXC;
> +            dc->base.is_jmp = DISAS_EXC;
>              break;
>          }
>  #endif
> @@ -11950,7 +11948,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>                          gen_set_pc_im(dc, dc->pc);
>                          gen_helper_check_breakpoints(cpu_env);
>                          /* End the TB early; it's likely not going to be executed */
> -                        dc->is_jmp = DISAS_UPDATE;
> +                        dc->base.is_jmp = DISAS_UPDATE;
>                      } else {
>                          gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
>                          /* The address covered by the breakpoint must be
> @@ -11968,7 +11966,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>              }
>          }
>
> -        if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
> +        if (dc->base.num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
>              gen_io_start();
>          }
>
> @@ -11983,7 +11981,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>               * "did not step an insn" case, and so the syndrome ISV and EX
>               * bits should be zero.
>               */
> -            assert(num_insns == 1);
> +            assert(dc->base.num_insns == 1);
>              gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
>                            default_exception_el(dc));
>              goto done_generating;
> @@ -12005,7 +12003,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>              disas_arm_insn(dc, insn);
>          }
>
> -        if (dc->condjmp && !dc->is_jmp) {
> +        if (dc->condjmp && !dc->base.is_jmp) {
>              gen_set_label(dc->condlabel);
>              dc->condjmp = 0;
>          }
> @@ -12032,11 +12030,11 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>          end_of_page = (dc->pc >= next_page_start) ||
>              ((dc->pc >= next_page_start - 3) && insn_crosses_page(env, dc));
>
> -    } while (!dc->is_jmp && !tcg_op_buf_full() &&
> +    } while (!dc->base.is_jmp && !tcg_op_buf_full() &&
>               !is_singlestepping(dc) &&
>               !singlestep &&
>               !end_of_page &&
> -             num_insns < max_insns);
> +             dc->base.num_insns < max_insns);
>
>      if (tb->cflags & CF_LAST_IO) {
>          if (dc->condjmp) {
> @@ -12051,7 +12049,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>         instruction was a conditional branch or trap, and the PC has
>         already been written.  */
>      gen_set_condexec(dc);
> -    if (dc->is_jmp == DISAS_BX_EXCRET) {
> +    if (dc->base.is_jmp == DISAS_BX_EXCRET) {
>          /* Exception return branches need some special case code at the
>           * end of the TB, which is complex enough that it has to
>           * handle the single-step vs not and the condition-failed
> @@ -12060,7 +12058,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>          gen_bx_excret_final_code(dc);
>      } else if (unlikely(is_singlestepping(dc))) {
>          /* Unconditional and "condition passed" instruction codepath. */
> -        switch (dc->is_jmp) {
> +        switch (dc->base.is_jmp) {
>          case DISAS_SWI:
>              gen_ss_advance(dc);
>              gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb),
> @@ -12091,7 +12089,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>              - Hardware watchpoints.
>             Hardware breakpoints have already been handled and skip this code.
>           */
> -        switch(dc->is_jmp) {
> +        switch(dc->base.is_jmp) {
>          case DISAS_NEXT:
>              gen_goto_tb(dc, 1, dc->pc);
>              break;
> @@ -12148,22 +12146,22 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>      }
>
>  done_generating:
> -    gen_tb_end(tb, num_insns);
> +    gen_tb_end(tb, dc->base.num_insns);
>
>  #ifdef DEBUG_DISAS
>      if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) &&
> -        qemu_log_in_addr_range(pc_start)) {
> +        qemu_log_in_addr_range(dc->base.pc_first)) {
>          qemu_log_lock();
>          qemu_log("----------------\n");
> -        qemu_log("IN: %s\n", lookup_symbol(pc_start));
> -        log_target_disas(cs, pc_start, dc->pc - pc_start,
> +        qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
> +        log_target_disas(cs, dc->base.pc_first, dc->pc - dc->base.pc_first,
>                           dc->thumb | (dc->sctlr_b << 1));
>          qemu_log("\n");
>          qemu_log_unlock();
>      }
>  #endif
> -    tb->size = dc->pc - pc_start;
> -    tb->icount = num_insns;
> +    tb->size = dc->pc - dc->base.pc_first;
> +    tb->icount = dc->base.num_insns;
>  }
>
>  static const char *cpu_mode_names[16] = {
> diff --git a/target/arm/translate.h b/target/arm/translate.h
> index aba3f44c9f..6fe40a344a 100644
> --- a/target/arm/translate.h
> +++ b/target/arm/translate.h
> @@ -6,9 +6,10 @@
>
>  /* internal defines */
>  typedef struct DisasContext {
> +    DisasContextBase base;
> +
>      target_ulong pc;
>      uint32_t insn;
> -    int is_jmp;
>      /* Nonzero if this instruction has been conditionally skipped.  */
>      int condjmp;
>      /* The label that will be jumped to when the instruction is skipped.  */
> @@ -16,8 +17,6 @@ typedef struct DisasContext {
>      /* Thumb-2 conditional execution bits.  */
>      int condexec_mask;
>      int condexec_cond;
> -    struct TranslationBlock *tb;
> -    int singlestep_enabled;
>      int thumb;
>      int sctlr_b;
>      TCGMemOp be_data;
> @@ -152,7 +151,8 @@ static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
>
>  #ifdef TARGET_AARCH64
>  void a64_translate_init(void);
> -void gen_intermediate_code_a64(CPUState *cpu, TranslationBlock *tb);
> +void gen_intermediate_code_a64(DisasContextBase *db, CPUState *cpu,
> +                               TranslationBlock *tb);
>  void gen_a64_set_pc_im(uint64_t val);
>  void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
>                              fprintf_function cpu_fprintf, int flags);
> @@ -161,7 +161,8 @@ static inline void a64_translate_init(void)
>  {
>  }
>
> -static inline void gen_intermediate_code_a64(CPUState *cpu, TranslationBlock *tb)
> +static inline void gen_intermediate_code_a64(DisasContextBase *db, CPUState *cpu,
> +                                             TranslationBlock *tb)
>  {
>  }
>


--
Alex Bennée

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 14/27] target/arm: [tcg] Port to init_disas_context
  2017-07-07 12:37 ` [Qemu-devel] [PATCH v12 14/27] target/arm: [tcg] Port to init_disas_context Lluís Vilanova
@ 2017-07-12  9:27   ` Alex Bennée
  0 siblings, 0 replies; 57+ messages in thread
From: Alex Bennée @ 2017-07-12  9:27 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Emilio G. Cota, Richard Henderson, Peter Crosthwaite,
	Paolo Bonzini, Peter Maydell, open list:ARM


Lluís Vilanova <vilanova@ac.upc.edu> writes:

> Incrementally paves the way towards using the generic instruction translation
> loop.
>
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> Reviewed-by: Richard Henderson <rth@twiddle.net>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/arm/translate.c |   86 +++++++++++++++++++++++++++---------------------
>  1 file changed, 48 insertions(+), 38 deletions(-)
>
> diff --git a/target/arm/translate.c b/target/arm/translate.c
> index 15b4fcb417..0179b1ce79 100644
> --- a/target/arm/translate.c
> +++ b/target/arm/translate.c
> @@ -11786,32 +11786,12 @@ static bool insn_crosses_page(CPUARMState *env, DisasContext *s)
>      return false;
>  }
>
> -/* generate intermediate code for basic block 'tb'.  */
> -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
> +static void arm_tr_init_disas_context(DisasContextBase *dcbase,
> +                                           CPUState *cs)
>  {
> +    DisasContext *dc = container_of(dcbase, DisasContext, base);
>      CPUARMState *env = cs->env_ptr;
>      ARMCPU *cpu = arm_env_get_cpu(env);
> -    DisasContext dc1, *dc = &dc1;
> -    target_ulong next_page_start;
> -    int max_insns;
> -    bool end_of_page;
> -
> -    /* generate intermediate code */
> -
> -    /* The A64 decoder has its own top level loop, because it doesn't need
> -     * the A32/T32 complexity to do with conditional execution/IT blocks/etc.
> -     */
> -    if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
> -        gen_intermediate_code_a64(&dc->base, cs, tb);
> -        return;
> -    }
> -
> -    dc->base.tb = tb;
> -    dc->base.pc_first = tb->pc;
> -    dc->base.pc_next = dc->base.pc_first;
> -    dc->base.is_jmp = DISAS_NEXT;
> -    dc->base.num_insns = 0;
> -    dc->base.singlestep_enabled = cs->singlestep_enabled;
>
>      dc->pc = dc->base.pc_first;
>      dc->condjmp = 0;
> @@ -11822,23 +11802,23 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>       */
>      dc->secure_routed_to_el3 = arm_feature(env, ARM_FEATURE_EL3) &&
>                                 !arm_el_is_aa64(env, 3);
> -    dc->thumb = ARM_TBFLAG_THUMB(tb->flags);
> -    dc->sctlr_b = ARM_TBFLAG_SCTLR_B(tb->flags);
> -    dc->be_data = ARM_TBFLAG_BE_DATA(tb->flags) ? MO_BE : MO_LE;
> -    dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1;
> -    dc->condexec_cond = ARM_TBFLAG_CONDEXEC(tb->flags) >> 4;
> -    dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(tb->flags));
> +    dc->thumb = ARM_TBFLAG_THUMB(dc->base.tb->flags);
> +    dc->sctlr_b = ARM_TBFLAG_SCTLR_B(dc->base.tb->flags);
> +    dc->be_data = ARM_TBFLAG_BE_DATA(dc->base.tb->flags) ? MO_BE : MO_LE;
> +    dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(dc->base.tb->flags) & 0xf) << 1;
> +    dc->condexec_cond = ARM_TBFLAG_CONDEXEC(dc->base.tb->flags) >> 4;
> +    dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(dc->base.tb->flags));
>      dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
>  #if !defined(CONFIG_USER_ONLY)
>      dc->user = (dc->current_el == 0);
>  #endif
> -    dc->ns = ARM_TBFLAG_NS(tb->flags);
> -    dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(tb->flags);
> -    dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
> -    dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags);
> -    dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
> -    dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(tb->flags);
> -    dc->v7m_handler_mode = ARM_TBFLAG_HANDLER(tb->flags);
> +    dc->ns = ARM_TBFLAG_NS(dc->base.tb->flags);
> +    dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(dc->base.tb->flags);
> +    dc->vfp_enabled = ARM_TBFLAG_VFPEN(dc->base.tb->flags);
> +    dc->vec_len = ARM_TBFLAG_VECLEN(dc->base.tb->flags);
> +    dc->vec_stride = ARM_TBFLAG_VECSTRIDE(dc->base.tb->flags);
> +    dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(dc->base.tb->flags);
> +    dc->v7m_handler_mode = ARM_TBFLAG_HANDLER(dc->base.tb->flags);
>      dc->cp_regs = cpu->cp_regs;
>      dc->features = env->features;
>
> @@ -11857,11 +11837,12 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>       *   emit code to generate a software step exception
>       *   end the TB
>       */
> -    dc->ss_active = ARM_TBFLAG_SS_ACTIVE(tb->flags);
> -    dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(tb->flags);
> +    dc->ss_active = ARM_TBFLAG_SS_ACTIVE(dc->base.tb->flags);
> +    dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(dc->base.tb->flags);
>      dc->is_ldex = false;
>      dc->ss_same_el = false; /* Can't be true since EL_d must be AArch64 */
>
> +
>      cpu_F0s = tcg_temp_new_i32();
>      cpu_F1s = tcg_temp_new_i32();
>      cpu_F0d = tcg_temp_new_i64();
> @@ -11870,6 +11851,35 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>      cpu_V1 = cpu_F1d;
>      /* FIXME: cpu_M0 can probably be the same as cpu_V0.  */
>      cpu_M0 = tcg_temp_new_i64();
> +}
> +
> +/* generate intermediate code for basic block 'tb'.  */
> +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
> +{
> +    CPUARMState *env = cs->env_ptr;
> +    DisasContext dc1, *dc = &dc1;
> +    target_ulong next_page_start;
> +    int max_insns;
> +    bool end_of_page;
> +
> +    /* generate intermediate code */
> +
> +    /* The A64 decoder has its own top level loop, because it doesn't need
> +     * the A32/T32 complexity to do with conditional execution/IT blocks/etc.
> +     */
> +    if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
> +        gen_intermediate_code_a64(&dc->base, cs, tb);
> +        return;
> +    }
> +
> +    dc->base.tb = tb;
> +    dc->base.pc_first = dc->base.tb->pc;
> +    dc->base.pc_next = dc->base.pc_first;
> +    dc->base.is_jmp = DISAS_NEXT;
> +    dc->base.num_insns = 0;
> +    dc->base.singlestep_enabled = cs->singlestep_enabled;
> +    arm_tr_init_disas_context(&dc->base, cs);
> +
>      next_page_start = (dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
>      max_insns = tb->cflags & CF_COUNT_MASK;
>      if (max_insns == 0) {


--
Alex Bennée

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 15/27] target/arm: [tcg, a64] Port to init_disas_context
  2017-07-07 12:41 ` [Qemu-devel] [PATCH v12 15/27] target/arm: [tcg, a64] " Lluís Vilanova
@ 2017-07-12  9:30   ` Alex Bennée
  0 siblings, 0 replies; 57+ messages in thread
From: Alex Bennée @ 2017-07-12  9:30 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Emilio G. Cota, Richard Henderson, Peter Crosthwaite,
	Paolo Bonzini, Peter Maydell, open list:ARM


Lluís Vilanova <vilanova@ac.upc.edu> writes:

> Incrementally paves the way towards using the generic instruction translation
> loop.
>
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> Reviewed-by: Richard Henderson <rth@twiddle.net>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/arm/translate-a64.c |   36 ++++++++++++++++++++++--------------
>  1 file changed, 22 insertions(+), 14 deletions(-)
>
> diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
> index 4270ac3847..5c04ff3d8b 100644
> --- a/target/arm/translate-a64.c
> +++ b/target/arm/translate-a64.c
> @@ -11190,21 +11190,12 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
>      free_tmp_a64(s);
>  }
>
> -void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
> -                               TranslationBlock *tb)
> +static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
> +                                               CPUState *cpu)
>  {
> -    CPUARMState *env = cs->env_ptr;
> -    ARMCPU *cpu = arm_env_get_cpu(env);
>      DisasContext *dc = container_of(dcbase, DisasContext, base);
> -    target_ulong next_page_start;
> -    int max_insns;
> -
> -    dc->base.tb = tb;
> -    dc->base.pc_first = dc->base.tb->pc;
> -    dc->base.pc_next = dc->base.pc_first;
> -    dc->base.is_jmp = DISAS_NEXT;
> -    dc->base.num_insns = 0;
> -    dc->base.singlestep_enabled = cs->singlestep_enabled;
> +    CPUARMState *env = cpu->env_ptr;
> +    ARMCPU *arm_cpu = arm_env_get_cpu(env);
>
>      dc->pc = dc->base.pc_first;
>      dc->condjmp = 0;
> @@ -11230,7 +11221,7 @@ void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
>      dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(dc->base.tb->flags);
>      dc->vec_len = 0;
>      dc->vec_stride = 0;
> -    dc->cp_regs = cpu->cp_regs;
> +    dc->cp_regs = arm_cpu->cp_regs;
>      dc->features = env->features;
>
>      /* Single step state. The code-generation logic here is:
> @@ -11254,6 +11245,23 @@ void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
>      dc->ss_same_el = (arm_debug_target_el(env) == dc->current_el);
>
>      init_tmp_a64_array(dc);
> +}
> +
> +void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
> +                               TranslationBlock *tb)
> +{
> +    CPUARMState *env = cs->env_ptr;
> +    DisasContext *dc = container_of(dcbase, DisasContext, base);
> +    target_ulong next_page_start;
> +    int max_insns;
> +
> +    dc->base.tb = tb;
> +    dc->base.pc_first = dc->base.tb->pc;
> +    dc->base.pc_next = dc->base.pc_first;
> +    dc->base.is_jmp = DISAS_NEXT;
> +    dc->base.num_insns = 0;
> +    dc->base.singlestep_enabled = cs->singlestep_enabled;
> +    aarch64_tr_init_disas_context(&dc->base, cs);
>
>      next_page_start = (dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
>      max_insns = dc->base.tb->cflags & CF_COUNT_MASK;


--
Alex Bennée

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 16/27] target/arm: [tcg] Port to tb_start
  2017-07-07 12:46 ` [Qemu-devel] [PATCH v12 16/27] target/arm: [tcg] Port to tb_start Lluís Vilanova
@ 2017-07-12  9:31   ` Alex Bennée
  0 siblings, 0 replies; 57+ messages in thread
From: Alex Bennée @ 2017-07-12  9:31 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Emilio G. Cota, Richard Henderson, Peter Crosthwaite,
	Paolo Bonzini, Peter Maydell, open list:ARM


Lluís Vilanova <vilanova@ac.upc.edu> writes:

> Incrementally paves the way towards using the generic instruction translation
> loop.
>
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> Reviewed-by: Richard Henderson <rth@twiddle.net>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/arm/translate.c |   82 ++++++++++++++++++++++++++----------------------
>  1 file changed, 44 insertions(+), 38 deletions(-)
>
> diff --git a/target/arm/translate.c b/target/arm/translate.c
> index 0179b1ce79..22af4e372a 100644
> --- a/target/arm/translate.c
> +++ b/target/arm/translate.c
> @@ -11853,6 +11853,49 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase,
>      cpu_M0 = tcg_temp_new_i64();
>  }
>
> +static void arm_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu)
> +{
> +    DisasContext *dc = container_of(dcbase, DisasContext, base);
> +
> +    /* A note on handling of the condexec (IT) bits:
> +     *
> +     * We want to avoid the overhead of having to write the updated condexec
> +     * bits back to the CPUARMState for every instruction in an IT block. So:
> +     * (1) if the condexec bits are not already zero then we write
> +     * zero back into the CPUARMState now. This avoids complications trying
> +     * to do it at the end of the block. (For example if we don't do this
> +     * it's hard to identify whether we can safely skip writing condexec
> +     * at the end of the TB, which we definitely want to do for the case
> +     * where a TB doesn't do anything with the IT state at all.)
> +     * (2) if we are going to leave the TB then we call gen_set_condexec()
> +     * which will write the correct value into CPUARMState if zero is wrong.
> +     * This is done both for leaving the TB at the end, and for leaving
> +     * it because of an exception we know will happen, which is done in
> +     * gen_exception_insn(). The latter is necessary because we need to
> +     * leave the TB with the PC/IT state just prior to execution of the
> +     * instruction which caused the exception.
> +     * (3) if we leave the TB unexpectedly (eg a data abort on a load)
> +     * then the CPUARMState will be wrong and we need to reset it.
> +     * This is handled in the same way as restoration of the
> +     * PC in these situations; we save the value of the condexec bits
> +     * for each PC via tcg_gen_insn_start(), and restore_state_to_opc()
> +     * then uses this to restore them after an exception.
> +     *
> +     * Note that there are no instructions which can read the condexec
> +     * bits, and none which can write non-static values to them, so
> +     * we don't need to care about whether CPUARMState is correct in the
> +     * middle of a TB.
> +     */
> +
> +    /* Reset the conditional execution bits immediately. This avoids
> +       complications trying to do it at the end of the block.  */
> +    if (dc->condexec_mask || dc->condexec_cond) {
> +        TCGv_i32 tmp = tcg_temp_new_i32();
> +        tcg_gen_movi_i32(tmp, 0);
> +        store_cpu_field(tmp, condexec_bits);
> +    }
> +}
> +
>  /* generate intermediate code for basic block 'tb'.  */
>  void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>  {
> @@ -11892,45 +11935,8 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>      gen_tb_start(tb);
>
>      tcg_clear_temp_count();
> +    arm_tr_tb_start(&dc->base, cs);
>
> -    /* A note on handling of the condexec (IT) bits:
> -     *
> -     * We want to avoid the overhead of having to write the updated condexec
> -     * bits back to the CPUARMState for every instruction in an IT block. So:
> -     * (1) if the condexec bits are not already zero then we write
> -     * zero back into the CPUARMState now. This avoids complications trying
> -     * to do it at the end of the block. (For example if we don't do this
> -     * it's hard to identify whether we can safely skip writing condexec
> -     * at the end of the TB, which we definitely want to do for the case
> -     * where a TB doesn't do anything with the IT state at all.)
> -     * (2) if we are going to leave the TB then we call gen_set_condexec()
> -     * which will write the correct value into CPUARMState if zero is wrong.
> -     * This is done both for leaving the TB at the end, and for leaving
> -     * it because of an exception we know will happen, which is done in
> -     * gen_exception_insn(). The latter is necessary because we need to
> -     * leave the TB with the PC/IT state just prior to execution of the
> -     * instruction which caused the exception.
> -     * (3) if we leave the TB unexpectedly (eg a data abort on a load)
> -     * then the CPUARMState will be wrong and we need to reset it.
> -     * This is handled in the same way as restoration of the
> -     * PC in these situations; we save the value of the condexec bits
> -     * for each PC via tcg_gen_insn_start(), and restore_state_to_opc()
> -     * then uses this to restore them after an exception.
> -     *
> -     * Note that there are no instructions which can read the condexec
> -     * bits, and none which can write non-static values to them, so
> -     * we don't need to care about whether CPUARMState is correct in the
> -     * middle of a TB.
> -     */
> -
> -    /* Reset the conditional execution bits immediately. This avoids
> -       complications trying to do it at the end of the block.  */
> -    if (dc->condexec_mask || dc->condexec_cond)
> -      {
> -        TCGv_i32 tmp = tcg_temp_new_i32();
> -        tcg_gen_movi_i32(tmp, 0);
> -        store_cpu_field(tmp, condexec_bits);
> -      }
>      do {
>          dc->base.num_insns++;
>          dc->insn_start_idx = tcg_op_buf_count();


--
Alex Bennée

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 17/27] target/arm: [tcg] Port to insn_start
  2017-07-07 12:50 ` [Qemu-devel] [PATCH v12 17/27] target/arm: [tcg] Port to insn_start Lluís Vilanova
@ 2017-07-12  9:32   ` Alex Bennée
  0 siblings, 0 replies; 57+ messages in thread
From: Alex Bennée @ 2017-07-12  9:32 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Emilio G. Cota, Richard Henderson, Peter Crosthwaite,
	Paolo Bonzini, Peter Maydell, open list:ARM


Lluís Vilanova <vilanova@ac.upc.edu> writes:

> Incrementally paves the way towards using the generic instruction translation
> loop.
>
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> Reviewed-by: Richard Henderson <rth@twiddle.net>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>


> ---
>  target/arm/translate.c |   36 +++++++++++++++++++++---------------
>  1 file changed, 21 insertions(+), 15 deletions(-)
>
> diff --git a/target/arm/translate.c b/target/arm/translate.c
> index 22af4e372a..7a1935d4d7 100644
> --- a/target/arm/translate.c
> +++ b/target/arm/translate.c
> @@ -11896,6 +11896,26 @@ static void arm_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu)
>      }
>  }
>
> +static void arm_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
> +{
> +    DisasContext *dc = container_of(dcbase, DisasContext, base);
> +
> +    dc->insn_start_idx = tcg_op_buf_count();
> +    tcg_gen_insn_start(dc->pc,
> +                       (dc->condexec_cond << 4) | (dc->condexec_mask >> 1),
> +                       0);
> +
> +#ifdef CONFIG_USER_ONLY
> +    /* Intercept jump to the magic kernel page.  */
> +    if (dc->pc >= 0xffff0000) {
> +        /* We always get here via a jump, so know we are not in a
> +           conditional execution block.  */
> +        gen_exception_internal(EXCP_KERNEL_TRAP);
> +        dc->base.is_jmp = DISAS_EXC;
> +    }
> +#endif
> +}
> +
>  /* generate intermediate code for basic block 'tb'.  */
>  void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>  {
> @@ -11939,21 +11959,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>
>      do {
>          dc->base.num_insns++;
> -        dc->insn_start_idx = tcg_op_buf_count();
> -        tcg_gen_insn_start(dc->pc,
> -                           (dc->condexec_cond << 4) | (dc->condexec_mask >> 1),
> -                           0);
> -
> -#ifdef CONFIG_USER_ONLY
> -        /* Intercept jump to the magic kernel page.  */
> -        if (dc->pc >= 0xffff0000) {
> -            /* We always get here via a jump, so know we are not in a
> -               conditional execution block.  */
> -            gen_exception_internal(EXCP_KERNEL_TRAP);
> -            dc->base.is_jmp = DISAS_EXC;
> -            break;
> -        }
> -#endif
> +        arm_tr_insn_start(&dc->base, cs);
>
>          if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
>              CPUBreakpoint *bp;


--
Alex Bennée

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 18/27] target/arm: [tcg, a64] Port to insn_start
  2017-07-07 12:54 ` [Qemu-devel] [PATCH v12 18/27] target/arm: [tcg, a64] " Lluís Vilanova
@ 2017-07-12  9:32   ` Alex Bennée
  0 siblings, 0 replies; 57+ messages in thread
From: Alex Bennée @ 2017-07-12  9:32 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Emilio G. Cota, Richard Henderson, Peter Crosthwaite,
	Paolo Bonzini, Peter Maydell, open list:ARM


Lluís Vilanova <vilanova@ac.upc.edu> writes:

> Incrementally paves the way towards using the generic instruction translation
> loop.
>
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> Reviewed-by: Richard Henderson <rth@twiddle.net>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/arm/translate-a64.c |   11 +++++++++--
>  1 file changed, 9 insertions(+), 2 deletions(-)
>
> diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
> index 5c04ff3d8b..dc91661df0 100644
> --- a/target/arm/translate-a64.c
> +++ b/target/arm/translate-a64.c
> @@ -11247,6 +11247,14 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
>      init_tmp_a64_array(dc);
>  }
>
> +static void aarch64_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
> +{
> +    DisasContext *dc = container_of(dcbase, DisasContext, base);
> +
> +    dc->insn_start_idx = tcg_op_buf_count();
> +    tcg_gen_insn_start(dc->pc, 0, 0);
> +}
> +
>  void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
>                                 TranslationBlock *tb)
>  {
> @@ -11278,8 +11286,7 @@ void gen_intermediate_code_a64(DisasContextBase *dcbase, CPUState *cs,
>
>      do {
>          dc->base.num_insns++;
> -        dc->insn_start_idx = tcg_op_buf_count();
> -        tcg_gen_insn_start(dc->pc, 0, 0);
> +        aarch64_tr_insn_start(&dc->base, cs);
>
>          if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
>              CPUBreakpoint *bp;


--
Alex Bennée

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 21/27] target/arm: [tcg] Port to translate_insn
  2017-07-07 13:06 ` [Qemu-devel] [PATCH v12 21/27] target/arm: [tcg] Port to translate_insn Lluís Vilanova
@ 2017-07-12  9:39   ` Alex Bennée
  2017-07-12 11:05     ` Lluís Vilanova
  0 siblings, 1 reply; 57+ messages in thread
From: Alex Bennée @ 2017-07-12  9:39 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Emilio G. Cota, Richard Henderson, Peter Crosthwaite,
	Paolo Bonzini, Peter Maydell, open list:ARM


Lluís Vilanova <vilanova@ac.upc.edu> writes:

> Incrementally paves the way towards using the generic instruction translation
> loop.
>
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> ---
>  target/arm/translate.c |  148 ++++++++++++++++++++++++++++--------------------
>  target/arm/translate.h |    2 +
>  2 files changed, 87 insertions(+), 63 deletions(-)
>
> diff --git a/target/arm/translate.c b/target/arm/translate.c
> index 29428b2920..9d033f2fb7 100644
> --- a/target/arm/translate.c
> +++ b/target/arm/translate.c
> @@ -11842,6 +11842,9 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase,
>      dc->is_ldex = false;
>      dc->ss_same_el = false; /* Can't be true since EL_d must be AArch64 */
>
> +    dc->next_page_start =
> +        (dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
> +
>
>      cpu_F0s = tcg_temp_new_i32();
>      cpu_F1s = tcg_temp_new_i32();
> @@ -11942,14 +11945,83 @@ static BreakpointCheckType arm_tr_breakpoint_check(
>      }
>  }
>
> +static target_ulong arm_tr_translate_insn(DisasContextBase *dcbase,
> +                                               CPUState *cpu)
> +{
> +    DisasContext *dc = container_of(dcbase, DisasContext, base);
> +    CPUARMState *env = cpu->env_ptr;
> +
> +    if (dc->ss_active && !dc->pstate_ss) {
> +        /* Singlestep state is Active-pending.
> +         * If we're in this state at the start of a TB then either
> +         *  a) we just took an exception to an EL which is being debugged
> +         *     and this is the first insn in the exception handler
> +         *  b) debug exceptions were masked and we just unmasked them
> +         *     without changing EL (eg by clearing PSTATE.D)
> +         * In either case we're going to take a swstep exception in the
> +         * "did not step an insn" case, and so the syndrome ISV and EX
> +         * bits should be zero.
> +         */
> +        assert(dc->base.num_insns == 1);
> +        gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
> +                      default_exception_el(dc));
> +        dc->base.is_jmp = DISAS_SKIP;
> +        return dc->pc;
> +    }
> +
> +    if (dc->thumb) {
> +        disas_thumb_insn(env, dc);
> +        if (dc->condexec_mask) {
> +            dc->condexec_cond = (dc->condexec_cond & 0xe)
> +                | ((dc->condexec_mask >> 4) & 1);
> +            dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f;
> +            if (dc->condexec_mask == 0) {
> +                dc->condexec_cond = 0;
> +            }
> +        }
> +    } else {
> +        unsigned int insn = arm_ldl_code(env, dc->pc, dc->sctlr_b);
> +        dc->pc += 4;
> +        disas_arm_insn(dc, insn);
> +    }
> +
> +    if (dc->condjmp && !dc->base.is_jmp) {
> +        gen_set_label(dc->condlabel);
> +        dc->condjmp = 0;
> +    }
> +
> +    if (dc->base.is_jmp == DISAS_NEXT) {
> +        /* Translation stops when a conditional branch is encountered.
> +         * Otherwise the subsequent code could get translated several times.
> +         * Also stop translation when a page boundary is reached.  This
> +         * ensures prefetch aborts occur at the right place.  */
> +
> +        if (is_singlestepping(dc)) {
> +            dc->base.is_jmp = DISAS_TOO_MANY;
> +        } else if ((dc->pc >= dc->next_page_start) ||
> +                   ((dc->pc >= dc->next_page_start - 3) &&
> +                    insn_crosses_page(env, dc))) {
> +            /* We want to stop the TB if the next insn starts in a new page,
> +             * or if it spans between this page and the next. This means that
> +             * if we're looking at the last halfword in the page we need to
> +             * see if it's a 16-bit Thumb insn (which will fit in this TB)
> +             * or a 32-bit Thumb insn (which won't).
> +             * This is to avoid generating a silly TB with a single 16-bit insn
> +             * in it at the end of this page (which would execute correctly
> +             * but isn't very efficient).
> +             */
> +            dc->base.is_jmp = DISAS_TOO_MANY;
> +        }
> +    }
> +
> +    return dc->pc;
> +}
> +
>  /* generate intermediate code for basic block 'tb'.  */
>  void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>  {
> -    CPUARMState *env = cs->env_ptr;
>      DisasContext dc1, *dc = &dc1;
> -    target_ulong next_page_start;
>      int max_insns;
> -    bool end_of_page;
>
>      /* generate intermediate code */
>
> @@ -11969,7 +12041,6 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>      dc->base.singlestep_enabled = cs->singlestep_enabled;
>      arm_tr_init_disas_context(&dc->base, cs);
>
> -    next_page_start = (dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
>      max_insns = tb->cflags & CF_COUNT_MASK;
>      if (max_insns == 0) {
>          max_insns = CF_COUNT_MASK;
> @@ -12020,72 +12091,20 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>              gen_io_start();
>          }
>
> -        if (dc->ss_active && !dc->pstate_ss) {
> -            /* Singlestep state is Active-pending.
> -             * If we're in this state at the start of a TB then either
> -             *  a) we just took an exception to an EL which is being debugged
> -             *     and this is the first insn in the exception handler
> -             *  b) debug exceptions were masked and we just unmasked them
> -             *     without changing EL (eg by clearing PSTATE.D)
> -             * In either case we're going to take a swstep exception in the
> -             * "did not step an insn" case, and so the syndrome ISV and EX
> -             * bits should be zero.
> -             */
> -            assert(dc->base.num_insns == 1);
> -            gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
> -                          default_exception_el(dc));
> -            goto done_generating;
> -        }
> -
> -        if (dc->thumb) {
> -            disas_thumb_insn(env, dc);
> -            if (dc->condexec_mask) {
> -                dc->condexec_cond = (dc->condexec_cond & 0xe)
> -                                   | ((dc->condexec_mask >> 4) & 1);
> -                dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f;
> -                if (dc->condexec_mask == 0) {
> -                    dc->condexec_cond = 0;
> -                }
> -            }
> -        } else {
> -            unsigned int insn = arm_ldl_code(env, dc->pc, dc->sctlr_b);
> -            dc->pc += 4;
> -            disas_arm_insn(dc, insn);
> -        }
> -
> -        if (dc->condjmp && !dc->base.is_jmp) {
> -            gen_set_label(dc->condlabel);
> -            dc->condjmp = 0;
> -        }
> +        dc->base.pc_next = arm_tr_translate_insn(&dc->base, cs);
>
>          if (tcg_check_temp_count()) {
>              fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
>                      dc->pc);
>          }
>
> -        /* Translation stops when a conditional branch is encountered.
> -         * Otherwise the subsequent code could get translated several times.
> -         * Also stop translation when a page boundary is reached.  This
> -         * ensures prefetch aborts occur at the right place.  */
> -
> -        /* We want to stop the TB if the next insn starts in a new page,
> -         * or if it spans between this page and the next. This means that
> -         * if we're looking at the last halfword in the page we need to
> -         * see if it's a 16-bit Thumb insn (which will fit in this TB)
> -         * or a 32-bit Thumb insn (which won't).
> -         * This is to avoid generating a silly TB with a single 16-bit insn
> -         * in it at the end of this page (which would execute correctly
> -         * but isn't very efficient).
> -         */
> -        end_of_page = (dc->pc >= next_page_start) ||
> -            ((dc->pc >= next_page_start - 3) && insn_crosses_page(env, dc));
> -
> -    } while (!dc->base.is_jmp && !tcg_op_buf_full() &&
> -             !is_singlestepping(dc) &&
> -             !singlestep &&
> -             !end_of_page &&
> -             dc->base.num_insns < max_insns);
> +        if (!dc->base.is_jmp && (tcg_op_buf_full() || singlestep ||
> +                            dc->base.num_insns >= max_insns)) {
> +            dc->base.is_jmp = DISAS_TOO_MANY;
> +        }
> +    } while (!dc->base.is_jmp);
>
> +    if (dc->base.is_jmp != DISAS_SKIP) {
>      if (tb->cflags & CF_LAST_IO) {
>          if (dc->condjmp) {
>              /* FIXME:  This can theoretically happen with self-modifying
> @@ -12123,6 +12142,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>              gen_exception(EXCP_SMC, syn_aa32_smc(), 3);
>              break;
>          case DISAS_NEXT:
> +        case DISAS_TOO_MANY:
>          case DISAS_UPDATE:
>              gen_set_pc_im(dc, dc->pc);
>              /* fall through */
> @@ -12141,6 +12161,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>           */
>          switch(dc->base.is_jmp) {
>          case DISAS_NEXT:
> +        case DISAS_TOO_MANY:
>              gen_goto_tb(dc, 1, dc->pc);
>              break;
>          case DISAS_UPDATE:
> @@ -12194,6 +12215,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>              gen_goto_tb(dc, 1, dc->pc);
>          }
>      }
> +    }
>
>  done_generating:
>      gen_tb_end(tb, dc->base.num_insns);
> diff --git a/target/arm/translate.h b/target/arm/translate.h
> index 6fe40a344a..83e56dcb08 100644
> --- a/target/arm/translate.h
> +++ b/target/arm/translate.h
> @@ -9,6 +9,7 @@ typedef struct DisasContext {
>      DisasContextBase base;
>
>      target_ulong pc;
> +    target_ulong next_page_start;
>      uint32_t insn;
>      /* Nonzero if this instruction has been conditionally skipped.  */
>      int condjmp;
> @@ -148,6 +149,7 @@ static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
>   * as opposed to attempting to use lookup_and_goto_ptr.
>   */
>  #define DISAS_EXIT DISAS_TARGET_11
> +#define DISAS_SKIP DISAS_TARGET_12

What are the semantics of this new exit condition? This seems a case
that should be covered a well defined common exit condition rather than
yet-another-architecture specific one.

--
Alex Bennée

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 25/27] target/arm: [tcg] Port to disas_log
  2017-07-07 13:23 ` [Qemu-devel] [PATCH v12 25/27] target/arm: [tcg] Port to disas_log Lluís Vilanova
@ 2017-07-12  9:41   ` Alex Bennée
  0 siblings, 0 replies; 57+ messages in thread
From: Alex Bennée @ 2017-07-12  9:41 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Emilio G. Cota, Richard Henderson, Peter Crosthwaite,
	Paolo Bonzini, Peter Maydell, open list:ARM


Lluís Vilanova <vilanova@ac.upc.edu> writes:

> Incrementally paves the way towards using the generic instruction translation
> loop.
>
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> Reviewed-by: Richard Henderson <rth@twiddle.net>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  target/arm/translate.c |   13 ++++++++++---
>  1 file changed, 10 insertions(+), 3 deletions(-)
>
> diff --git a/target/arm/translate.c b/target/arm/translate.c
> index 00cac01d66..5db381491f 100644
> --- a/target/arm/translate.c
> +++ b/target/arm/translate.c
> @@ -12133,6 +12133,15 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
>      }
>  }
>
> +static void arm_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu)
> +{
> +    DisasContext *dc = container_of(dcbase, DisasContext, base);
> +
> +    qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
> +    log_target_disas(cpu, dc->base.pc_first, dc->pc - dc->base.pc_first,
> +                     dc->thumb | (dc->sctlr_b << 1));
> +}
> +
>  /* generate intermediate code for basic block 'tb'.  */
>  void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>  {
> @@ -12236,9 +12245,7 @@ done_generating:
>          qemu_log_in_addr_range(dc->base.pc_first)) {
>          qemu_log_lock();
>          qemu_log("----------------\n");
> -        qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
> -        log_target_disas(cs, dc->base.pc_first, dc->pc - dc->base.pc_first,
> -                         dc->thumb | (dc->sctlr_b << 1));
> +        arm_tr_disas_log(&dc->base, cs);
>          qemu_log("\n");
>          qemu_log_unlock();
>      }


--
Alex Bennée

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework
  2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
                   ` (26 preceding siblings ...)
  2017-07-07 13:31 ` [Qemu-devel] [PATCH v12 27/27] target/arm: [tcg] Port to generic translation framework Lluís Vilanova
@ 2017-07-12  9:47 ` Alex Bennée
  2017-07-12 11:10   ` Lluís Vilanova
  27 siblings, 1 reply; 57+ messages in thread
From: Alex Bennée @ 2017-07-12  9:47 UTC (permalink / raw)
  To: Lluís Vilanova
  Cc: qemu-devel, Emilio G. Cota, Richard Henderson, Peter Crosthwaite,
	Paolo Bonzini


Lluís Vilanova <vilanova@ac.upc.edu> writes:

> This series proposes a generic (target-agnostic) instruction translation
> framework.
>
> It basically provides a generic main loop for instruction disassembly, which
> calls target-specific functions when necessary. This generalization makes
> inserting new code in the main loop easier, and helps in keeping all targets in
> synch as to the contents of it.

As has been mentioned elsewhere I think we need to spend a little time
making sure we have well defined common semantics for the as many of the
translation exit conditions as possible so the others really are just
special conditions for each architecture.

> This series also paves the way towards adding events to trace guest code
> execution (BBLs and instructions).

I'm looking forward to it, it is certainly going in the right direction
and will make instrumentation a lot easier ;-)

> I've ported i386/x86-64 and arm/aarch64 as an example to see how it fits in the
> current organization, but will port the rest when this series gets
> merged.

Are you confident the other architectures will be as amenable to this
port? I guess we want to avoid being in a position of having a partial
port in progress for too long.

Anyway I'm done with my review pass for now, I look forward to future
revisions ;-)


>
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> ---
>
> Changes in v12
> ==============
>
> * Do not rename cs -> cpu when using CPUState arg in gen_intermediate_code().
> * Avoid merge conflicts with queued patches.
> * Fix documentation typos.
> * Rename translate_block -> translator_loop.
> * Fix misplaced changes (wrong patch).
> * Rename _trblock_ -> _tr_.
> * Drop DISAS_SS and DISAS_PAGE_CROSS from arm targets.
> * Refactor calculation of TranslatorOps in arm targets.
> * Merge init_globals() into init_disas_context().
> * Minor cosmetic changes.
>
>
> Changes in v11
> ==============
>
> * Convert gen_intermediate_code_a64 [Emilio G. Cota].
> * Replace "cpu_env" argument in icount functions with "tcg_ctx.cpu_env"
>   [Emilio G. Cota].
> * Drop QTAILQ_FOREACH_CONTINUE and cpu_breakpoint_get in favour of an explicit
>   breakpoint traversal [Richard Henderson].
> * Rename translate-block.[ch] into translator.[ch] [Emilio G. Cota].
> * Revert DJ_* names into DISAS_*, and provide generic DISAS_TARGET_* enum values
>   instead of defining them as integers on each target.
> * Do not use DisasContextBase directly in target code (helps the compiler's
>   alias analysis) [Richard Henderson].
> * Make all generic translator hooks mandatory [Richard Henderson].
> * Rename TranslatorOps::disas_insn as TranslatorOps::translate_insn
>   [Richard Henderson].
> * Generalize TranslatorOps::disas_flags into TranslatorOps::disas_log to support
>   future targets [Richard Henderson].
> * Split arm and aarch64 changes in different patches [Emilio G. Cota].
> * Make translator op structs constant [Richard Henderson].
> * Write a single entry point for both arm and aarch64 translation
>   [Richard Henderson].
> * Change format of commit titles [Emilio G. Cota].
> * Remove cross-page check from generic code (it's already embedded in more
>   complex, and mandatory, checks in most targets).
>
>
> Changes in v10
> ==============
>
> * Rebase on 931892e8a6.
> * Fix build errors for hppa, nios2 and openrisc.
>
>
> Changes in v9
> =============
>
> * Further increase inter-mail sleep time during sending.
>
>
> Changes in v8
> =============
>
> * Increase inter-mail sleep time during sending (list keeps refusing some emails
>   due to an excessive send rate).
>
>
> Changes in v7
> =============
>
> * Change BreakpointHitType (BH_*) for BreakpointCheckType (BC_*).
> * Move target-specific translation functions to a struct (TranslatorOps).
> * Split target-specific changes into multiple patches.
> * Rebase on edf8bc9842.
>
>
> Changes in v6
> =============
>
> * Rebase on upstream master (64175afc69).
> * Reorder fields in DisasContextBase to minimize padding [Richard Henderson].
>
>
> Changes in v5
> =============
>
> * Remove stray uses of "restrict" keyword.
>
>
> Changes in v4
> =============
>
> * Document new macro QTAILQ_FOREACH_CONTINUE [Peter Maydell].
> * Fix coding style errors reported by checkpatch.
> * Remove use of "restrict" in added functions; it makes older gcc versions barf
>   about compilation errors.
>
>
> Changes in v3
> =============
>
> * Rebase on 0737f32daf.
>
>
> Changes in v2
> =============
>
> * Port ARM and AARCH64 targets.
> * Fold single-stepping checks into "max_insns" [Richard Henderson].
> * Move instruction start marks to target code [Richard Henderson].
> * Add target hook for TB start.
> * Check for TCG temporary leaks.
> * Move instruction disassembly into a target hook.
> * Make breakpoint_hit() return an enum to accomodate target's needs (ARM).
>
>
> Lluís Vilanova (27):
>       Pass generic CPUState to gen_intermediate_code()
>       cpu-exec: Avoid global variables in icount-related functions
>       target: [tcg] Use a generic enum for DISAS_ values
>       target: [tcg] Add generic translation framework
>       target/i386: [tcg] Port to DisasContextBase
>       target/i386: [tcg] Port to init_disas_context
>       target/i386: [tcg] Port to insn_start
>       target/i386: [tcg] Port to breakpoint_check
>       target/i386: [tcg] Port to translate_insn
>       target/i386: [tcg] Port to tb_stop
>       target/i386: [tcg] Port to disas_log
>       target/i386: [tcg] Port to generic translation framework
>       target/arm: [tcg] Port to DisasContextBase
>       target/arm: [tcg] Port to init_disas_context
>       target/arm: [tcg,a64] Port to init_disas_context
>       target/arm: [tcg] Port to tb_start
>       target/arm: [tcg] Port to insn_start
>       target/arm: [tcg,a64] Port to insn_start
>       target/arm: [tcg] Port to breakpoint_check
>       target/arm: [tcg,a64] Port to breakpoint_check
>       target/arm: [tcg] Port to translate_insn
>       target/arm: [tcg,a64] Port to translate_insn
>       target/arm: [tcg] Port to tb_stop
>       target/arm: [tcg,a64] Port to tb_stop
>       target/arm: [tcg] Port to disas_log
>       target/arm: [tcg,a64] Port to disas_log
>       target/arm: [tcg] Port to generic translation framework
>
>
>  accel/tcg/Makefile.objs       |    1
>  accel/tcg/translate-all.c     |    2
>  accel/tcg/translator.c        |  152 +++++++++++++++
>  include/exec/exec-all.h       |    8 -
>  include/exec/gen-icount.h     |   12 +
>  include/exec/translator.h     |  138 +++++++++++++
>  target/alpha/translate.c      |    5
>  target/arm/translate-a64.c    |  275 +++++++++++++--------------
>  target/arm/translate.c        |  420 +++++++++++++++++++++--------------------
>  target/arm/translate.h        |   39 ++--
>  target/cris/translate.c       |   14 +
>  target/hppa/translate.c       |    5
>  target/i386/translate.c       |  300 +++++++++++++++--------------
>  target/lm32/translate.c       |   10 +
>  target/m68k/translate.c       |   12 +
>  target/microblaze/translate.c |   10 +
>  target/mips/translate.c       |    5
>  target/moxie/translate.c      |    4
>  target/nios2/translate.c      |   11 +
>  target/openrisc/translate.c   |   10 +
>  target/ppc/translate.c        |    5
>  target/s390x/translate.c      |    8 -
>  target/sh4/translate.c        |    5
>  target/sparc/translate.c      |    5
>  target/tilegx/translate.c     |    5
>  target/tricore/translate.c    |    5
>  target/unicore32/translate.c  |   12 +
>  target/xtensa/translate.c     |    9 +
>  28 files changed, 899 insertions(+), 588 deletions(-)
>  create mode 100644 accel/tcg/translator.c
>  create mode 100644 include/exec/translator.h
>
>
> To: qemu-devel@nongnu.org
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Peter Crosthwaite <crosthwaite.peter@gmail.com>
> Cc: Richard Henderson <rth@twiddle.net>
> Cc: Alex Bennée <alex.bennee@linaro.org>
> Cc: Emilio G. Cota <cota@braap.org>


--
Alex Bennée

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 03/27] target: [tcg] Use a generic enum for DISAS_ values
  2017-07-12  9:10   ` Alex Bennée
@ 2017-07-12 10:56     ` Lluís Vilanova
  2017-07-12 16:53     ` Richard Henderson
  1 sibling, 0 replies; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-12 10:56 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Marek Vasut, Peter Maydell, Eduardo Habkost, Peter Crosthwaite,
	Alexander Graf, Chris Wulff, qemu-devel, Laurent Vivier,
	Max Filippov, Michael Walle, Emilio G. Cota, open list:ARM,
	Edgar E. Iglesias, Paolo Bonzini, Stafford Horne, Guan Xuetao,
	Richard Henderson

Alex Bennée writes:

> Lluís Vilanova <vilanova@ac.upc.edu> writes:

>> Used later. An enum makes expected values explicit and bounds the value space of
>> switches.
>> 
>> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
>> Reviewed-by: Emilio G. Cota <cota@braap.org>
>> Reviewed-by: Richard Henderson <rth@twiddle.net>
>> ---
>> include/exec/exec-all.h       |    6 ------
>> include/exec/translator.h     |   39 +++++++++++++++++++++++++++++++++++++++
>> target/arm/translate.h        |   26 ++++++++++++++++----------
>> target/cris/translate.c       |    7 ++++++-
>> target/i386/translate.c       |    4 ++++
>> target/lm32/translate.c       |    6 ++++++
>> target/m68k/translate.c       |    7 ++++++-
>> target/microblaze/translate.c |    6 ++++++
>> target/nios2/translate.c      |    6 ++++++
>> target/openrisc/translate.c   |    6 ++++++
>> target/s390x/translate.c      |    3 ++-
>> target/unicore32/translate.c  |    7 ++++++-
>> target/xtensa/translate.c     |    4 ++++
>> 13 files changed, 107 insertions(+), 20 deletions(-)
>> create mode 100644 include/exec/translator.h
>> 
>> diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
>> index 0826894ec5..27498cf740 100644
>> --- a/include/exec/exec-all.h
>> +++ b/include/exec/exec-all.h
>> @@ -35,12 +35,6 @@ typedef abi_ulong tb_page_addr_t;
>> typedef ram_addr_t tb_page_addr_t;
>> #endif
>> 
>> -/* is_jmp field values */
>> -#define DISAS_NEXT    0 /* next instruction can be analyzed */
>> -#define DISAS_JUMP    1 /* only pc was modified dynamically */
>> -#define DISAS_UPDATE  2 /* cpu state was modified dynamically */
>> -#define DISAS_TB_JUMP 3 /* only pc was modified statically */
>> -
>> #include "qemu/log.h"
>> 
>> void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb);
>> diff --git a/include/exec/translator.h b/include/exec/translator.h
>> new file mode 100644
>> index 0000000000..1f9697dd31
>> --- /dev/null
>> +++ b/include/exec/translator.h
>> @@ -0,0 +1,39 @@
>> +/*
>> + * Generic intermediate code generation.
>> + *
>> + * Copyright (C) 2016-2017 Lluís Vilanova <vilanova@ac.upc.edu>
>> + *
>> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
>> + * See the COPYING file in the top-level directory.
>> + */
>> +
>> +#ifndef EXEC__TRANSLATOR_H
>> +#define EXEC__TRANSLATOR_H
>> +
>> +/**
>> + * DisasJumpType:
>> + * @DISAS_NEXT: Next instruction in program order.
>> + * @DISAS_TOO_MANY: Too many instructions translated.
>> + * @DISAS_TARGET: Start of target-specific conditions.
>> + *
>> + * What instruction to disassemble next.
>> + */
>> +typedef enum DisasJumpType {
>> +    DISAS_NEXT,
>> +    DISAS_TOO_MANY,

> Is DISAS_TOO_MANY really a useful distinction. Sure we have ended the
> loop because of an instruction limit but the more important information
> is what it means for the epilogue code and how we go to the next block.

You mean this is just the sae as DISAS_NEXT? Could be, I don't know about all
the other targets.

> The recent work on fixing eret on ARM[1] has had me thinking about the
> semantics of exit conditions and how much commonality we have across the
> translators. I don't think we'll ever have a comprehensive DisasJumpType
> that all translators will only use the common exits but I think we could
> stand to have a few more.

> I think the cases we want to cover are:

>   DISAS_JUMP - the block ends with a jump to the next block (either
>                computed via PC or hard-coded with patched branch to next TB)

>   DISAS_NORETURN - the block exits via a helper or some other mechanism
>                   (for example cpu_loop_exit from helper)

>   DISAS_EXIT_LOOP - we need to return to the main loop before we enter
>                     again (typically to deal with IRQ issues)


> [1] https://lists.nongnu.org/archive/html/qemu-devel/2017-07/msg02963.html

Right now (v13 that I will send after this round of reviews) it only has
DISAS_TOO_MANY and DISAS_NORETURN because these are the only ones used in the
generic code.

I'm not that familiar with the internals of the disassembly process of all the
many targets in QEMU, and so I prefer to stick to the bare minimum we clearly
need now, and only later refactor target-specific DISAS_* values into generic
ones.

If you provide me a rename mapping from i386 and arm to the values you're
proposing, I can send it for v13, but would otherwise prefer to stick to the
current state of affairs.


>> +    DISAS_TARGET_0,
>> +    DISAS_TARGET_1,
>> +    DISAS_TARGET_2,
>> +    DISAS_TARGET_3,
>> +    DISAS_TARGET_4,
>> +    DISAS_TARGET_5,
>> +    DISAS_TARGET_6,
>> +    DISAS_TARGET_7,
>> +    DISAS_TARGET_8,
>> +    DISAS_TARGET_9,
>> +    DISAS_TARGET_10,
>> +    DISAS_TARGET_11,
>> +    DISAS_TARGET_12,
>> +} DisasJumpType;
>> +
>> +#endif  /* EXEC__TRANSLATOR_H */
>> diff --git a/target/arm/translate.h b/target/arm/translate.h
>> index e5da614db5..aba3f44c9f 100644
>> --- a/target/arm/translate.h
>> +++ b/target/arm/translate.h
>> @@ -1,6 +1,9 @@
>> #ifndef TARGET_ARM_TRANSLATE_H
>> #define TARGET_ARM_TRANSLATE_H
>> 
>> +#include "exec/translator.h"
>> +
>> +
>> /* internal defines */
>> typedef struct DisasContext {
>> target_ulong pc;
>> @@ -119,30 +122,33 @@ static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
s-> insn_start_idx = 0;
>> }
>> 
>> -/* target-specific extra values for is_jmp */
>> +/* is_jmp field values */
>> +#define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
>> +#define DISAS_UPDATE  DISAS_TARGET_1 /* cpu state was modified dynamically */
>> +#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
>> /* These instructions trap after executing, so the A32/T32 decoder must
>> * defer them until after the conditional execution state has been updated.
>> * WFI also needs special handling when single-stepping.
>> */
>> -#define DISAS_WFI 4
>> -#define DISAS_SWI 5

> So in the new model for example we only really need the special handling
> for things like WFI/SWI onwards.

And how do the previous ones map to the generic ones? And what about the i386
target?


Thanks,
  Lluis

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 05/27] target/i386: [tcg] Port to DisasContextBase
  2017-07-12  9:18   ` Alex Bennée
@ 2017-07-12 11:00     ` Lluís Vilanova
  0 siblings, 0 replies; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-12 11:00 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Eduardo Habkost, Peter Crosthwaite, qemu-devel, Emilio G. Cota,
	Paolo Bonzini, Richard Henderson

Alex Bennée writes:

> Lluís Vilanova <vilanova@ac.upc.edu> writes:

>> Incrementally paves the way towards using the generic instruction translation
>> loop.
>> 
>> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
>> Reviewed-by: Emilio G. Cota <cota@braap.org>
>> Reviewed-by: Richard Henderson <rth@twiddle.net>
>> ---
>> target/i386/translate.c |  142 +++++++++++++++++++++++------------------------
>> 1 file changed, 70 insertions(+), 72 deletions(-)
>> 
>> diff --git a/target/i386/translate.c b/target/i386/translate.c
>> index b118fcb834..f61f5c7227 100644
>> --- a/target/i386/translate.c
>> +++ b/target/i386/translate.c
>> @@ -99,6 +99,8 @@ static int x86_64_hregs;
>> #endif
>> 
>> typedef struct DisasContext {
>> +    DisasContextBase base;
>> +
>> /* current insn context */
>> int override; /* -1 if no override */
>> int prefix;
>> @@ -106,8 +108,6 @@ typedef struct DisasContext {
>> TCGMemOp dflag;
>> target_ulong pc_start;
>> target_ulong pc; /* pc = eip + cs_base */
>> -    int is_jmp; /* 1 = means jump (stop translation), 2 means CPU
>> -                   static state change (stop translation) */
>> /* current block context */
>> target_ulong cs_base; /* base of CS segment */
>> int pe;     /* protected mode */
>> @@ -128,12 +128,10 @@ typedef struct DisasContext {
>> int cpl;
>> int iopl;
>> int tf;     /* TF cpu flag */
>> -    int singlestep_enabled; /* "hardware" single step enabled */
>> int jmp_opt; /* use direct block chaining for direct jumps */
>> int repz_opt; /* optimize jumps within repz instructions */
>> int mem_index; /* select memory access functions */
>> uint64_t flags; /* all execution flags */
>> -    struct TranslationBlock *tb;
>> int popl_esp_hack; /* for correct popl with esp base handling */
>> int rip_offset; /* only used in x86_64, but left for simplicity */
>> int cpuid_features;
>> @@ -1123,7 +1121,7 @@ static void gen_bpt_io(DisasContext *s, TCGv_i32 t_port, int ot)
>> 
>> static inline void gen_ins(DisasContext *s, TCGMemOp ot)
>> {
>> -    if (s->tb->cflags & CF_USE_ICOUNT) {
>> +    if (s->base.tb->cflags & CF_USE_ICOUNT) {
>> gen_io_start();
>> }
>> gen_string_movl_A0_EDI(s);
>> @@ -1138,14 +1136,14 @@ static inline void gen_ins(DisasContext *s, TCGMemOp ot)
>> gen_op_movl_T0_Dshift(ot);
>> gen_op_add_reg_T0(s->aflag, R_EDI);
>> gen_bpt_io(s, cpu_tmp2_i32, ot);
>> -    if (s->tb->cflags & CF_USE_ICOUNT) {
>> +    if (s->base.tb->cflags & CF_USE_ICOUNT) {
>> gen_io_end();
>> }
>> }
>> 
>> static inline void gen_outs(DisasContext *s, TCGMemOp ot)
>> {
>> -    if (s->tb->cflags & CF_USE_ICOUNT) {
>> +    if (s->base.tb->cflags & CF_USE_ICOUNT) {
>> gen_io_start();
>> }
>> gen_string_movl_A0_ESI(s);
>> @@ -1158,7 +1156,7 @@ static inline void gen_outs(DisasContext *s, TCGMemOp ot)
>> gen_op_movl_T0_Dshift(ot);
>> gen_op_add_reg_T0(s->aflag, R_ESI);
>> gen_bpt_io(s, cpu_tmp2_i32, ot);
>> -    if (s->tb->cflags & CF_USE_ICOUNT) {
>> +    if (s->base.tb->cflags & CF_USE_ICOUNT) {
>> gen_io_end();
>> }
>> }
>> @@ -2141,7 +2139,7 @@ static inline int insn_const_size(TCGMemOp ot)
>> static inline bool use_goto_tb(DisasContext *s, target_ulong pc)
>> {
>> #ifndef CONFIG_USER_ONLY
>> -    return (pc & TARGET_PAGE_MASK) == (s->tb->pc & TARGET_PAGE_MASK) ||
>> +    return (pc & TARGET_PAGE_MASK) == (s->base.tb->pc & TARGET_PAGE_MASK) ||
>> (pc & TARGET_PAGE_MASK) == (s->pc_start & TARGET_PAGE_MASK);
>> #else
>> return true;
>> @@ -2156,7 +2154,7 @@ static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip)
>> /* jump to same page: we can use a direct jump */
>> tcg_gen_goto_tb(tb_num);
>> gen_jmp_im(eip);
>> -        tcg_gen_exit_tb((uintptr_t)s->tb + tb_num);
>> +        tcg_gen_exit_tb((uintptr_t)s->base.tb + tb_num);
>> } else {
>> /* jump to another page */
>> gen_jmp_im(eip);
>> @@ -2177,7 +2175,7 @@ static inline void gen_jcc(DisasContext *s, int b,
>> 
>> gen_set_label(l1);
>> gen_goto_tb(s, 1, val);
>> -        s->is_jmp = DISAS_TB_JUMP;
>> +        s->base.is_jmp = DISAS_TB_JUMP;
>> } else {
>> l1 = gen_new_label();
>> l2 = gen_new_label();
>> @@ -2248,11 +2246,11 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg)
>> stop as a special handling must be done to disable hardware
>> interrupts for the next instruction */
>> if (seg_reg == R_SS || (s->code32 && seg_reg < R_FS))
>> -            s->is_jmp = DISAS_TB_JUMP;
>> +            s->base.is_jmp = DISAS_TB_JUMP;
>> } else {
>> gen_op_movl_seg_T0_vm(seg_reg);
>> if (seg_reg == R_SS)
>> -            s->is_jmp = DISAS_TB_JUMP;
>> +            s->base.is_jmp = DISAS_TB_JUMP;
>> }
>> }
>> 
>> @@ -2424,7 +2422,7 @@ static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip)
>> gen_update_cc_op(s);
>> gen_jmp_im(cur_eip);
>> gen_helper_raise_exception(cpu_env, tcg_const_i32(trapno));
>> -    s->is_jmp = DISAS_TB_JUMP;
>> +    s->base.is_jmp = DISAS_TB_JUMP;
>> }
>> 
>> /* Generate #UD for the current instruction.  The assumption here is that
>> @@ -2462,7 +2460,7 @@ static void gen_interrupt(DisasContext *s, int intno,
>> gen_jmp_im(cur_eip);
>> gen_helper_raise_interrupt(cpu_env, tcg_const_i32(intno),
>> tcg_const_i32(next_eip - cur_eip));
>> -    s->is_jmp = DISAS_TB_JUMP;
>> +    s->base.is_jmp = DISAS_TB_JUMP;
>> }
>> 
>> static void gen_debug(DisasContext *s, target_ulong cur_eip)
>> @@ -2470,7 +2468,7 @@ static void gen_debug(DisasContext *s, target_ulong cur_eip)
>> gen_update_cc_op(s);
>> gen_jmp_im(cur_eip);
>> gen_helper_debug(cpu_env);
>> -    s->is_jmp = DISAS_TB_JUMP;
>> +    s->base.is_jmp = DISAS_TB_JUMP;
>> }
>> 
>> static void gen_set_hflag(DisasContext *s, uint32_t mask)
>> @@ -2526,10 +2524,10 @@ do_gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf, TCGv jr)
>> gen_reset_hflag(s, HF_INHIBIT_IRQ_MASK);
>> }
>> 
>> -    if (s->tb->flags & HF_RF_MASK) {
>> +    if (s->base.tb->flags & HF_RF_MASK) {
>> gen_helper_reset_rf(cpu_env);
>> }
>> -    if (s->singlestep_enabled) {
>> +    if (s->base.singlestep_enabled) {
>> gen_helper_debug(cpu_env);
>> } else if (recheck_tf) {
>> gen_helper_rechecking_single_step(cpu_env);
>> @@ -2545,7 +2543,7 @@ do_gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf, TCGv jr)
>> } else {
>> tcg_gen_exit_tb(0);
>> }
>> -    s->is_jmp = DISAS_TB_JUMP;
>> +    s->base.is_jmp = DISAS_TB_JUMP;
>> }
>> 
>> static inline void
>> @@ -2584,7 +2582,7 @@ static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num)
>> set_cc_op(s, CC_OP_DYNAMIC);
>> if (s->jmp_opt) {
>> gen_goto_tb(s, tb_num, eip);
>> -        s->is_jmp = DISAS_TB_JUMP;
>> +        s->base.is_jmp = DISAS_TB_JUMP;
>> } else {
>> gen_jmp_im(eip);
>> gen_eob(s);
>> @@ -4419,7 +4417,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
>> }
>> }
>> 
>> -/* convert one instruction. s->is_jmp is set if the translation must
>> +/* convert one instruction. s->base.is_jmp is set if the translation must
>> be stopped. Return the next pc value */
>> static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>> target_ulong pc_start)
>> @@ -5379,7 +5377,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>> gen_movl_seg_T0(s, reg);
>> gen_pop_update(s, ot);
>> /* Note that reg == R_SS in gen_movl_seg_T0 always sets is_jmp.  */
>> -        if (s->is_jmp) {
>> +        if (s->base.is_jmp) {
>> gen_jmp_im(s->pc - s->cs_base);
>> if (reg == R_SS) {
s-> tf = 0;
>> @@ -5394,7 +5392,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>> ot = gen_pop_T0(s);
>> gen_movl_seg_T0(s, (b >> 3) & 7);
>> gen_pop_update(s, ot);
>> -        if (s->is_jmp) {
>> +        if (s->base.is_jmp) {
>> gen_jmp_im(s->pc - s->cs_base);
>> gen_eob(s);
>> }
>> @@ -5445,7 +5443,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>> gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
>> gen_movl_seg_T0(s, reg);
>> /* Note that reg == R_SS in gen_movl_seg_T0 always sets is_jmp.  */
>> -        if (s->is_jmp) {
>> +        if (s->base.is_jmp) {
>> gen_jmp_im(s->pc - s->cs_base);
>> if (reg == R_SS) {
s-> tf = 0;
>> @@ -5654,7 +5652,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>> gen_movl_seg_T0(s, op);
>> /* then put the data */
>> gen_op_mov_reg_v(ot, reg, cpu_T1);
>> -        if (s->is_jmp) {
>> +        if (s->base.is_jmp) {
>> gen_jmp_im(s->pc - s->cs_base);
>> gen_eob(s);
>> }
>> @@ -6310,7 +6308,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>> gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
>> } else {
>> gen_ins(s, ot);
>> -            if (s->tb->cflags & CF_USE_ICOUNT) {
>> +            if (s->base.tb->cflags & CF_USE_ICOUNT) {
>> gen_jmp(s, s->pc - s->cs_base);
>> }
>> }
>> @@ -6325,7 +6323,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>> gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
>> } else {
>> gen_outs(s, ot);
>> -            if (s->tb->cflags & CF_USE_ICOUNT) {
>> +            if (s->base.tb->cflags & CF_USE_ICOUNT) {
>> gen_jmp(s, s->pc - s->cs_base);
>> }
>> }
>> @@ -6341,14 +6339,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>> tcg_gen_movi_tl(cpu_T0, val);
>> gen_check_io(s, ot, pc_start - s->cs_base,
>> SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
>> -        if (s->tb->cflags & CF_USE_ICOUNT) {
>> +        if (s->base.tb->cflags & CF_USE_ICOUNT) {
>> gen_io_start();
>> }
>> tcg_gen_movi_i32(cpu_tmp2_i32, val);
>> gen_helper_in_func(ot, cpu_T1, cpu_tmp2_i32);
>> gen_op_mov_reg_v(ot, R_EAX, cpu_T1);
>> gen_bpt_io(s, cpu_tmp2_i32, ot);
>> -        if (s->tb->cflags & CF_USE_ICOUNT) {
>> +        if (s->base.tb->cflags & CF_USE_ICOUNT) {
>> gen_io_end();
>> gen_jmp(s, s->pc - s->cs_base);
>> }
>> @@ -6362,14 +6360,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>> svm_is_rep(prefixes));
>> gen_op_mov_v_reg(ot, cpu_T1, R_EAX);
>> 
>> -        if (s->tb->cflags & CF_USE_ICOUNT) {
>> +        if (s->base.tb->cflags & CF_USE_ICOUNT) {
>> gen_io_start();
>> }
>> tcg_gen_movi_i32(cpu_tmp2_i32, val);
>> tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T1);
>> gen_helper_out_func(ot, cpu_tmp2_i32, cpu_tmp3_i32);
>> gen_bpt_io(s, cpu_tmp2_i32, ot);
>> -        if (s->tb->cflags & CF_USE_ICOUNT) {
>> +        if (s->base.tb->cflags & CF_USE_ICOUNT) {
>> gen_io_end();
>> gen_jmp(s, s->pc - s->cs_base);
>> }
>> @@ -6380,14 +6378,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>> tcg_gen_ext16u_tl(cpu_T0, cpu_regs[R_EDX]);
>> gen_check_io(s, ot, pc_start - s->cs_base,
>> SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
>> -        if (s->tb->cflags & CF_USE_ICOUNT) {
>> +        if (s->base.tb->cflags & CF_USE_ICOUNT) {
>> gen_io_start();
>> }
>> tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T0);
>> gen_helper_in_func(ot, cpu_T1, cpu_tmp2_i32);
>> gen_op_mov_reg_v(ot, R_EAX, cpu_T1);
>> gen_bpt_io(s, cpu_tmp2_i32, ot);
>> -        if (s->tb->cflags & CF_USE_ICOUNT) {
>> +        if (s->base.tb->cflags & CF_USE_ICOUNT) {
>> gen_io_end();
>> gen_jmp(s, s->pc - s->cs_base);
>> }
>> @@ -6400,14 +6398,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>> svm_is_rep(prefixes));
>> gen_op_mov_v_reg(ot, cpu_T1, R_EAX);
>> 
>> -        if (s->tb->cflags & CF_USE_ICOUNT) {
>> +        if (s->base.tb->cflags & CF_USE_ICOUNT) {
>> gen_io_start();
>> }
>> tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T0);
>> tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T1);
>> gen_helper_out_func(ot, cpu_tmp2_i32, cpu_tmp3_i32);
>> gen_bpt_io(s, cpu_tmp2_i32, ot);
>> -        if (s->tb->cflags & CF_USE_ICOUNT) {
>> +        if (s->base.tb->cflags & CF_USE_ICOUNT) {
>> gen_io_end();
>> gen_jmp(s, s->pc - s->cs_base);
>> }
>> @@ -6946,7 +6944,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>> gen_update_cc_op(s);
>> gen_jmp_im(pc_start - s->cs_base);
>> gen_helper_pause(cpu_env, tcg_const_i32(s->pc - pc_start));
>> -            s->is_jmp = DISAS_TB_JUMP;
>> +            s->base.is_jmp = DISAS_TB_JUMP;
>> }
>> break;
>> case 0x9b: /* fwait */
>> @@ -7115,11 +7113,11 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>> case 0x131: /* rdtsc */
>> gen_update_cc_op(s);
>> gen_jmp_im(pc_start - s->cs_base);
>> -        if (s->tb->cflags & CF_USE_ICOUNT) {
>> +        if (s->base.tb->cflags & CF_USE_ICOUNT) {
>> gen_io_start();
>> }
>> gen_helper_rdtsc(cpu_env);
>> -        if (s->tb->cflags & CF_USE_ICOUNT) {
>> +        if (s->base.tb->cflags & CF_USE_ICOUNT) {
>> gen_io_end();
>> gen_jmp(s, s->pc - s->cs_base);
>> }
>> @@ -7191,7 +7189,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>> gen_update_cc_op(s);
>> gen_jmp_im(pc_start - s->cs_base);
>> gen_helper_hlt(cpu_env, tcg_const_i32(s->pc - pc_start));
>> -            s->is_jmp = DISAS_TB_JUMP;
>> +            s->base.is_jmp = DISAS_TB_JUMP;
>> }
>> break;
>> case 0x100:
>> @@ -7374,7 +7372,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>> gen_helper_vmrun(cpu_env, tcg_const_i32(s->aflag - 1),
>> tcg_const_i32(s->pc - pc_start));
>> tcg_gen_exit_tb(0);
>> -            s->is_jmp = DISAS_TB_JUMP;
>> +            s->base.is_jmp = DISAS_TB_JUMP;
>> break;
>> 
>> case 0xd9: /* VMMCALL */
>> @@ -7574,11 +7572,11 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>> }
>> gen_update_cc_op(s);
>> gen_jmp_im(pc_start - s->cs_base);
>> -            if (s->tb->cflags & CF_USE_ICOUNT) {
>> +            if (s->base.tb->cflags & CF_USE_ICOUNT) {
>> gen_io_start();
>> }
>> gen_helper_rdtscp(cpu_env);
>> -            if (s->tb->cflags & CF_USE_ICOUNT) {
>> +            if (s->base.tb->cflags & CF_USE_ICOUNT) {
>> gen_io_end();
>> gen_jmp(s, s->pc - s->cs_base);
>> }
>> @@ -7943,24 +7941,24 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>> gen_update_cc_op(s);
>> gen_jmp_im(pc_start - s->cs_base);
>> if (b & 2) {
>> -                    if (s->tb->cflags & CF_USE_ICOUNT) {
>> +                    if (s->base.tb->cflags & CF_USE_ICOUNT) {
>> gen_io_start();
>> }
>> gen_op_mov_v_reg(ot, cpu_T0, rm);
>> gen_helper_write_crN(cpu_env, tcg_const_i32(reg),
>> cpu_T0);
>> -                    if (s->tb->cflags & CF_USE_ICOUNT) {
>> +                    if (s->base.tb->cflags & CF_USE_ICOUNT) {
>> gen_io_end();
>> }
>> gen_jmp_im(s->pc - s->cs_base);
>> gen_eob(s);
>> } else {
>> -                    if (s->tb->cflags & CF_USE_ICOUNT) {
>> +                    if (s->base.tb->cflags & CF_USE_ICOUNT) {
>> gen_io_start();
>> }
>> gen_helper_read_crN(cpu_T0, cpu_env, tcg_const_i32(reg));
>> gen_op_mov_reg_v(ot, rm, cpu_T0);
>> -                    if (s->tb->cflags & CF_USE_ICOUNT) {
>> +                    if (s->base.tb->cflags & CF_USE_ICOUNT) {
>> gen_io_end();
>> }
>> }
>> @@ -8386,15 +8384,13 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>> {
>> CPUX86State *env = cs->env_ptr;
>> DisasContext dc1, *dc = &dc1;
>> -    target_ulong pc_ptr;
>> uint32_t flags;
>> -    target_ulong pc_start;
>> target_ulong cs_base;
>> int num_insns;
>> int max_insns;
>> 
>> /* generate intermediate code */
>> -    pc_start = tb->pc;
>> +    dc->base.pc_first = tb->pc;
>> cs_base = tb->cs_base;
>> flags = tb->flags;
>> 
>> @@ -8407,11 +8403,11 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
dc-> cpl = (flags >> HF_CPL_SHIFT) & 3;
dc-> iopl = (flags >> IOPL_SHIFT) & 3;
dc-> tf = (flags >> TF_SHIFT) & 1;
>> -    dc->singlestep_enabled = cs->singlestep_enabled;
>> +    dc->base.singlestep_enabled = cs->singlestep_enabled;
dc-> cc_op = CC_OP_DYNAMIC;
dc-> cc_op_dirty = false;
dc-> cs_base = cs_base;
>> -    dc->tb = tb;
>> +    dc->base.tb = tb;
dc-> popl_esp_hack = 0;
>> /* select memory access functions */
dc-> mem_index = 0;
>> @@ -8461,8 +8457,8 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>> cpu_ptr1 = tcg_temp_new_ptr();
>> cpu_cc_srcT = tcg_temp_local_new();
>> 
>> -    dc->is_jmp = DISAS_NEXT;
>> -    pc_ptr = pc_start;
>> +    dc->base.is_jmp = DISAS_NEXT;
>> +    dc->base.pc_next = dc->base.pc_first;

> Given the point of the DisasContextBase is it should be common
> boilerplate it might be worth having a:

>    init_dcbase(dc->base, tb, cs->singlestep_enabled)

> So we can keep this all in one place rather than in each targets
> preamble code.

This change is only temporary until the target gets ported to translator_loop(),
where this initalization is handled from a single place (i.e., no need for
init_dcbase()).


[...]

> That said:

> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>


Thanks,
  Lluis

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 21/27] target/arm: [tcg] Port to translate_insn
  2017-07-12  9:39   ` Alex Bennée
@ 2017-07-12 11:05     ` Lluís Vilanova
  0 siblings, 0 replies; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-12 11:05 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Peter Maydell, Peter Crosthwaite, qemu-devel, Emilio G. Cota,
	open list:ARM, Paolo Bonzini, Richard Henderson

Alex Bennée writes:

> Lluís Vilanova <vilanova@ac.upc.edu> writes:

>> Incrementally paves the way towards using the generic instruction translation
>> loop.
>> 
>> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
>> ---
>> target/arm/translate.c |  148 ++++++++++++++++++++++++++++--------------------
>> target/arm/translate.h |    2 +
>> 2 files changed, 87 insertions(+), 63 deletions(-)
>> 
>> diff --git a/target/arm/translate.c b/target/arm/translate.c
>> index 29428b2920..9d033f2fb7 100644
>> --- a/target/arm/translate.c
>> +++ b/target/arm/translate.c
>> @@ -11842,6 +11842,9 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase,
dc-> is_ldex = false;
dc-> ss_same_el = false; /* Can't be true since EL_d must be AArch64 */
>> 
>> +    dc->next_page_start =
>> +        (dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
>> +
>> 
>> cpu_F0s = tcg_temp_new_i32();
>> cpu_F1s = tcg_temp_new_i32();
>> @@ -11942,14 +11945,83 @@ static BreakpointCheckType arm_tr_breakpoint_check(
>> }
>> }
>> 
>> +static target_ulong arm_tr_translate_insn(DisasContextBase *dcbase,
>> +                                               CPUState *cpu)
>> +{
>> +    DisasContext *dc = container_of(dcbase, DisasContext, base);
>> +    CPUARMState *env = cpu->env_ptr;
>> +
>> +    if (dc->ss_active && !dc->pstate_ss) {
>> +        /* Singlestep state is Active-pending.
>> +         * If we're in this state at the start of a TB then either
>> +         *  a) we just took an exception to an EL which is being debugged
>> +         *     and this is the first insn in the exception handler
>> +         *  b) debug exceptions were masked and we just unmasked them
>> +         *     without changing EL (eg by clearing PSTATE.D)
>> +         * In either case we're going to take a swstep exception in the
>> +         * "did not step an insn" case, and so the syndrome ISV and EX
>> +         * bits should be zero.
>> +         */
>> +        assert(dc->base.num_insns == 1);
>> +        gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
>> +                      default_exception_el(dc));
>> +        dc->base.is_jmp = DISAS_SKIP;
>> +        return dc->pc;
>> +    }
>> +
>> +    if (dc->thumb) {
>> +        disas_thumb_insn(env, dc);
>> +        if (dc->condexec_mask) {
>> +            dc->condexec_cond = (dc->condexec_cond & 0xe)
>> +                | ((dc->condexec_mask >> 4) & 1);
>> +            dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f;
>> +            if (dc->condexec_mask == 0) {
>> +                dc->condexec_cond = 0;
>> +            }
>> +        }
>> +    } else {
>> +        unsigned int insn = arm_ldl_code(env, dc->pc, dc->sctlr_b);
>> +        dc->pc += 4;
>> +        disas_arm_insn(dc, insn);
>> +    }
>> +
>> +    if (dc->condjmp && !dc->base.is_jmp) {
>> +        gen_set_label(dc->condlabel);
>> +        dc->condjmp = 0;
>> +    }
>> +
>> +    if (dc->base.is_jmp == DISAS_NEXT) {
>> +        /* Translation stops when a conditional branch is encountered.
>> +         * Otherwise the subsequent code could get translated several times.
>> +         * Also stop translation when a page boundary is reached.  This
>> +         * ensures prefetch aborts occur at the right place.  */
>> +
>> +        if (is_singlestepping(dc)) {
>> +            dc->base.is_jmp = DISAS_TOO_MANY;
>> +        } else if ((dc->pc >= dc->next_page_start) ||
>> +                   ((dc->pc >= dc->next_page_start - 3) &&
>> +                    insn_crosses_page(env, dc))) {
>> +            /* We want to stop the TB if the next insn starts in a new page,
>> +             * or if it spans between this page and the next. This means that
>> +             * if we're looking at the last halfword in the page we need to
>> +             * see if it's a 16-bit Thumb insn (which will fit in this TB)
>> +             * or a 32-bit Thumb insn (which won't).
>> +             * This is to avoid generating a silly TB with a single 16-bit insn
>> +             * in it at the end of this page (which would execute correctly
>> +             * but isn't very efficient).
>> +             */
>> +            dc->base.is_jmp = DISAS_TOO_MANY;
>> +        }
>> +    }
>> +
>> +    return dc->pc;
>> +}
>> +
>> /* generate intermediate code for basic block 'tb'.  */
>> void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>> {
>> -    CPUARMState *env = cs->env_ptr;
>> DisasContext dc1, *dc = &dc1;
>> -    target_ulong next_page_start;
>> int max_insns;
>> -    bool end_of_page;
>> 
>> /* generate intermediate code */
>> 
>> @@ -11969,7 +12041,6 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
dc-> base.singlestep_enabled = cs->singlestep_enabled;
>> arm_tr_init_disas_context(&dc->base, cs);
>> 
>> -    next_page_start = (dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
>> max_insns = tb->cflags & CF_COUNT_MASK;
>> if (max_insns == 0) {
>> max_insns = CF_COUNT_MASK;
>> @@ -12020,72 +12091,20 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>> gen_io_start();
>> }
>> 
>> -        if (dc->ss_active && !dc->pstate_ss) {
>> -            /* Singlestep state is Active-pending.
>> -             * If we're in this state at the start of a TB then either
>> -             *  a) we just took an exception to an EL which is being debugged
>> -             *     and this is the first insn in the exception handler
>> -             *  b) debug exceptions were masked and we just unmasked them
>> -             *     without changing EL (eg by clearing PSTATE.D)
>> -             * In either case we're going to take a swstep exception in the
>> -             * "did not step an insn" case, and so the syndrome ISV and EX
>> -             * bits should be zero.
>> -             */
>> -            assert(dc->base.num_insns == 1);
>> -            gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
>> -                          default_exception_el(dc));
>> -            goto done_generating;
>> -        }
>> -
>> -        if (dc->thumb) {
>> -            disas_thumb_insn(env, dc);
>> -            if (dc->condexec_mask) {
>> -                dc->condexec_cond = (dc->condexec_cond & 0xe)
>> -                                   | ((dc->condexec_mask >> 4) & 1);
>> -                dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f;
>> -                if (dc->condexec_mask == 0) {
>> -                    dc->condexec_cond = 0;
>> -                }
>> -            }
>> -        } else {
>> -            unsigned int insn = arm_ldl_code(env, dc->pc, dc->sctlr_b);
>> -            dc->pc += 4;
>> -            disas_arm_insn(dc, insn);
>> -        }
>> -
>> -        if (dc->condjmp && !dc->base.is_jmp) {
>> -            gen_set_label(dc->condlabel);
>> -            dc->condjmp = 0;
>> -        }
>> +        dc->base.pc_next = arm_tr_translate_insn(&dc->base, cs);
>> 
>> if (tcg_check_temp_count()) {
>> fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
dc-> pc);
>> }
>> 
>> -        /* Translation stops when a conditional branch is encountered.
>> -         * Otherwise the subsequent code could get translated several times.
>> -         * Also stop translation when a page boundary is reached.  This
>> -         * ensures prefetch aborts occur at the right place.  */
>> -
>> -        /* We want to stop the TB if the next insn starts in a new page,
>> -         * or if it spans between this page and the next. This means that
>> -         * if we're looking at the last halfword in the page we need to
>> -         * see if it's a 16-bit Thumb insn (which will fit in this TB)
>> -         * or a 32-bit Thumb insn (which won't).
>> -         * This is to avoid generating a silly TB with a single 16-bit insn
>> -         * in it at the end of this page (which would execute correctly
>> -         * but isn't very efficient).
>> -         */
>> -        end_of_page = (dc->pc >= next_page_start) ||
>> -            ((dc->pc >= next_page_start - 3) && insn_crosses_page(env, dc));
>> -
>> -    } while (!dc->base.is_jmp && !tcg_op_buf_full() &&
>> -             !is_singlestepping(dc) &&
>> -             !singlestep &&
>> -             !end_of_page &&
>> -             dc->base.num_insns < max_insns);
>> +        if (!dc->base.is_jmp && (tcg_op_buf_full() || singlestep ||
>> +                            dc->base.num_insns >= max_insns)) {
>> +            dc->base.is_jmp = DISAS_TOO_MANY;
>> +        }
>> +    } while (!dc->base.is_jmp);
>> 
>> +    if (dc->base.is_jmp != DISAS_SKIP) {
>> if (tb->cflags & CF_LAST_IO) {
>> if (dc->condjmp) {
>> /* FIXME:  This can theoretically happen with self-modifying
>> @@ -12123,6 +12142,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>> gen_exception(EXCP_SMC, syn_aa32_smc(), 3);
>> break;
>> case DISAS_NEXT:
>> +        case DISAS_TOO_MANY:
>> case DISAS_UPDATE:
>> gen_set_pc_im(dc, dc->pc);
>> /* fall through */
>> @@ -12141,6 +12161,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>> */
>> switch(dc->base.is_jmp) {
>> case DISAS_NEXT:
>> +        case DISAS_TOO_MANY:
>> gen_goto_tb(dc, 1, dc->pc);
>> break;
>> case DISAS_UPDATE:
>> @@ -12194,6 +12215,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
>> gen_goto_tb(dc, 1, dc->pc);
>> }
>> }
>> +    }
>> 
>> done_generating:
>> gen_tb_end(tb, dc->base.num_insns);
>> diff --git a/target/arm/translate.h b/target/arm/translate.h
>> index 6fe40a344a..83e56dcb08 100644
>> --- a/target/arm/translate.h
>> +++ b/target/arm/translate.h
>> @@ -9,6 +9,7 @@ typedef struct DisasContext {
>> DisasContextBase base;
>> 
>> target_ulong pc;
>> +    target_ulong next_page_start;
>> uint32_t insn;
>> /* Nonzero if this instruction has been conditionally skipped.  */
>> int condjmp;
>> @@ -148,6 +149,7 @@ static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
>> * as opposed to attempting to use lookup_and_goto_ptr.
>> */
>> #define DISAS_EXIT DISAS_TARGET_11
>> +#define DISAS_SKIP DISAS_TARGET_12

> What are the semantics of this new exit condition? This seems a case
> that should be covered a well defined common exit condition rather than
> yet-another-architecture specific one.

Right. As per Richard's suggestion, this is now the generic DISAS_NORETURN (on
the future v13).

Cheers,
  Lluis

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework
  2017-07-12  9:47 ` [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic " Alex Bennée
@ 2017-07-12 11:10   ` Lluís Vilanova
  0 siblings, 0 replies; 57+ messages in thread
From: Lluís Vilanova @ 2017-07-12 11:10 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Paolo Bonzini, Peter Crosthwaite, Emilio G. Cota, qemu-devel,
	Richard Henderson

Alex Bennée writes:

> Lluís Vilanova <vilanova@ac.upc.edu> writes:

>> This series proposes a generic (target-agnostic) instruction translation
>> framework.
>> 
>> It basically provides a generic main loop for instruction disassembly, which
>> calls target-specific functions when necessary. This generalization makes
>> inserting new code in the main loop easier, and helps in keeping all targets in
>> synch as to the contents of it.

> As has been mentioned elsewhere I think we need to spend a little time
> making sure we have well defined common semantics for the as many of the
> translation exit conditions as possible so the others really are just
> special conditions for each architecture.

>> This series also paves the way towards adding events to trace guest code
>> execution (BBLs and instructions).

> I'm looking forward to it, it is certainly going in the right direction
> and will make instrumentation a lot easier ;-)

>> I've ported i386/x86-64 and arm/aarch64 as an example to see how it fits in the
>> current organization, but will port the rest when this series gets
>> merged.

> Are you confident the other architectures will be as amenable to this
> port? I guess we want to avoid being in a position of having a partial
> port in progress for too long.

> Anyway I'm done with my review pass for now, I look forward to future
> revisions ;-)

I've only skimmed through a few other targets, but there seems to be a pattern
that follows the same type of changes. In fact, most of them are just moving
code around into refactored hooks. But I don't want these to be my "last famous
words" :)


Thanks,
  Lluis

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 03/27] target: [tcg] Use a generic enum for DISAS_ values
  2017-07-12  9:10   ` Alex Bennée
  2017-07-12 10:56     ` Lluís Vilanova
@ 2017-07-12 16:53     ` Richard Henderson
  1 sibling, 0 replies; 57+ messages in thread
From: Richard Henderson @ 2017-07-12 16:53 UTC (permalink / raw)
  To: Alex Bennée, Lluís Vilanova
  Cc: qemu-devel, Emilio G. Cota, Peter Crosthwaite, Paolo Bonzini,
	Peter Maydell, Edgar E. Iglesias, Eduardo Habkost, Michael Walle,
	Laurent Vivier, Chris Wulff, Marek Vasut, Stafford Horne,
	Alexander Graf, Guan Xuetao, Max Filippov, open list:ARM

On 07/11/2017 11:10 PM, Alex Bennée wrote:
>> +typedef enum DisasJumpType {
>> +    DISAS_NEXT,
>> +    DISAS_TOO_MANY,
> 
> Is DISAS_TOO_MANY really a useful distinction. Sure we have ended the
> loop because of an instruction limit but the more important information
> is what it means for the epilogue code and how we go to the next block.

Yes. I think it is.

The reason is that it is the way that the generic loop can tell the target hook 
that it terminated the instruction fetch loop.  There may (or may not) be 
something special that the target needs to do for that specific case.


r~

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Qemu-devel] [PATCH v12 02/27] cpu-exec: Avoid global variables in icount-related functions
  2017-07-12  8:42     ` Lluís Vilanova
@ 2017-07-12 22:06       ` Emilio G. Cota
  0 siblings, 0 replies; 57+ messages in thread
From: Emilio G. Cota @ 2017-07-12 22:06 UTC (permalink / raw)
  To: Alex Bennée, Paolo Bonzini, Peter Crosthwaite, qemu-devel,
	Richard Henderson

On Wed, Jul 12, 2017 at 11:42:57 +0300, Lluís Vilanova wrote:
> Alex Bennée writes:
> 
> > Lluís Vilanova <vilanova@ac.upc.edu> writes:
> 
> >> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> 
> > I guess. I assume this is also something Emilio is targeting with his
> > multi-threaded translation work.
> 
> Yes, Emilio suggested to format this patch in a way that won't conflict with his
> changes.

53f6672bcf57d8 is already in master so you should drop this patch for
your next respin.

BTW the problem for the multi-threaded translation work is the global
"static TCGLabel *exitreq_label."

		Emilio

^ permalink raw reply	[flat|nested] 57+ messages in thread

end of thread, other threads:[~2017-07-12 22:06 UTC | newest]

Thread overview: 57+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-07-07 11:40 [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic translation framework Lluís Vilanova
2017-07-07 11:44 ` [Qemu-devel] [PATCH v12 01/27] Pass generic CPUState to gen_intermediate_code() Lluís Vilanova
2017-07-11 19:22   ` Alex Bennée
2017-07-07 11:48 ` [Qemu-devel] [PATCH v12 02/27] cpu-exec: Avoid global variables in icount-related functions Lluís Vilanova
2017-07-11 19:25   ` Alex Bennée
2017-07-12  8:42     ` Lluís Vilanova
2017-07-12 22:06       ` Emilio G. Cota
2017-07-07 11:52 ` [Qemu-devel] [PATCH v12 03/27] target: [tcg] Use a generic enum for DISAS_ values Lluís Vilanova
2017-07-12  9:10   ` Alex Bennée
2017-07-12 10:56     ` Lluís Vilanova
2017-07-12 16:53     ` Richard Henderson
2017-07-07 11:56 ` [Qemu-devel] [PATCH v12 04/27] target: [tcg] Add generic translation framework Lluís Vilanova
2017-07-07 18:42   ` Richard Henderson
2017-07-11 16:40     ` Lluís Vilanova
2017-07-11 17:21       ` Richard Henderson
2017-07-12  8:50         ` Lluís Vilanova
2017-07-11 18:17   ` Alex Bennée
2017-07-12  8:59     ` Lluís Vilanova
2017-07-12  9:13       ` Alex Bennée
2017-07-07 12:00 ` [Qemu-devel] [PATCH v12 05/27] target/i386: [tcg] Port to DisasContextBase Lluís Vilanova
2017-07-12  9:18   ` Alex Bennée
2017-07-12 11:00     ` Lluís Vilanova
2017-07-07 12:04 ` [Qemu-devel] [PATCH v12 06/27] target/i386: [tcg] Port to init_disas_context Lluís Vilanova
2017-07-12  9:20   ` Alex Bennée
2017-07-07 12:08 ` [Qemu-devel] [PATCH v12 07/27] target/i386: [tcg] Port to insn_start Lluís Vilanova
2017-07-12  9:21   ` Alex Bennée
2017-07-07 12:13 ` [Qemu-devel] [PATCH v12 08/27] target/i386: [tcg] Port to breakpoint_check Lluís Vilanova
2017-07-07 12:17 ` [Qemu-devel] [PATCH v12 09/27] target/i386: [tcg] Port to translate_insn Lluís Vilanova
2017-07-07 12:21 ` [Qemu-devel] [PATCH v12 10/27] target/i386: [tcg] Port to tb_stop Lluís Vilanova
2017-07-07 12:25 ` [Qemu-devel] [PATCH v12 11/27] target/i386: [tcg] Port to disas_log Lluís Vilanova
2017-07-07 12:29 ` [Qemu-devel] [PATCH v12 12/27] target/i386: [tcg] Port to generic translation framework Lluís Vilanova
2017-07-07 12:33 ` [Qemu-devel] [PATCH v12 13/27] target/arm: [tcg] Port to DisasContextBase Lluís Vilanova
2017-07-12  9:25   ` Alex Bennée
2017-07-07 12:37 ` [Qemu-devel] [PATCH v12 14/27] target/arm: [tcg] Port to init_disas_context Lluís Vilanova
2017-07-12  9:27   ` Alex Bennée
2017-07-07 12:41 ` [Qemu-devel] [PATCH v12 15/27] target/arm: [tcg, a64] " Lluís Vilanova
2017-07-12  9:30   ` Alex Bennée
2017-07-07 12:46 ` [Qemu-devel] [PATCH v12 16/27] target/arm: [tcg] Port to tb_start Lluís Vilanova
2017-07-12  9:31   ` Alex Bennée
2017-07-07 12:50 ` [Qemu-devel] [PATCH v12 17/27] target/arm: [tcg] Port to insn_start Lluís Vilanova
2017-07-12  9:32   ` Alex Bennée
2017-07-07 12:54 ` [Qemu-devel] [PATCH v12 18/27] target/arm: [tcg, a64] " Lluís Vilanova
2017-07-12  9:32   ` Alex Bennée
2017-07-07 12:58 ` [Qemu-devel] [PATCH v12 19/27] target/arm: [tcg] Port to breakpoint_check Lluís Vilanova
2017-07-07 13:02 ` [Qemu-devel] [PATCH v12 20/27] target/arm: [tcg, a64] " Lluís Vilanova
2017-07-07 13:06 ` [Qemu-devel] [PATCH v12 21/27] target/arm: [tcg] Port to translate_insn Lluís Vilanova
2017-07-12  9:39   ` Alex Bennée
2017-07-12 11:05     ` Lluís Vilanova
2017-07-07 13:10 ` [Qemu-devel] [PATCH v12 22/27] target/arm: [tcg, a64] " Lluís Vilanova
2017-07-07 13:14 ` [Qemu-devel] [PATCH v12 23/27] target/arm: [tcg] Port to tb_stop Lluís Vilanova
2017-07-07 13:18 ` [Qemu-devel] [PATCH v12 24/27] target/arm: [tcg, a64] " Lluís Vilanova
2017-07-07 13:23 ` [Qemu-devel] [PATCH v12 25/27] target/arm: [tcg] Port to disas_log Lluís Vilanova
2017-07-12  9:41   ` Alex Bennée
2017-07-07 13:27 ` [Qemu-devel] [PATCH v12 26/27] target/arm: [tcg, a64] " Lluís Vilanova
2017-07-07 13:31 ` [Qemu-devel] [PATCH v12 27/27] target/arm: [tcg] Port to generic translation framework Lluís Vilanova
2017-07-12  9:47 ` [Qemu-devel] [PATCH v12 00/27] translate: [tcg] Generic " Alex Bennée
2017-07-12 11:10   ` Lluís Vilanova

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.