diff mbox

[v11,24/29] target/arm: [tcg, a64] Port to translate_insn

Message ID 149865801156.17063.15618379976159104550.stgit@frigg.lan
State New
Headers show

Commit Message

Lluís Vilanova June 28, 2017, 1:53 p.m. UTC
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(-)

Comments

Richard Henderson July 2, 2017, 1:42 a.m. UTC | #1
On 06/28/2017 06:53 AM, Lluís Vilanova wrote:
> 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 9c870f6d07..586a01a2de 100644
> --- a/target/arm/translate-a64.c
> +++ b/target/arm/translate-a64.c
> @@ -11244,6 +11244,9 @@ static void aarch64_trblock_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;

I think a better solution for a fixed-length ISA is to adjust max_insns. 
Perhaps the init_disas_context hook should be able to modify it?

And, while I'm thinking of it -- why is the init_globals hook separate? 
There's nothing in between the two hook calls, and the more modern target front 
ends won't need it.


r~
Lluís Vilanova July 7, 2017, 11:18 a.m. UTC | #2
Richard Henderson writes:

> On 06/28/2017 06:53 AM, Lluís Vilanova wrote:
>> 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 9c870f6d07..586a01a2de 100644
>> --- a/target/arm/translate-a64.c
>> +++ b/target/arm/translate-a64.c
>> @@ -11244,6 +11244,9 @@ static void aarch64_trblock_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;

> I think a better solution for a fixed-length ISA is to adjust max_insns. Perhaps
> the init_disas_context hook should be able to modify it?

ARM has the thumb instructions, so it really isn't a fixed-length ISA.


> And, while I'm thinking of it -- why is the init_globals hook separate? There's
> nothing in between the two hook calls, and the more modern target front ends
> won't need it.

You mean merging init_disas_context and init_globals? I wanted to keep
semantically different code on separate hooks, but I can pull the init_globals
code into init_disas_context (hoping that as targets get modernized, they won't
initialize any global there).


Thanks,
  Lluis
Richard Henderson July 7, 2017, 3:46 p.m. UTC | #3
On 07/07/2017 01:18 AM, Lluís Vilanova wrote:
>>> diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
>>> index 9c870f6d07..586a01a2de 100644
>>> --- a/target/arm/translate-a64.c
>>> +++ b/target/arm/translate-a64.c
>>> @@ -11244,6 +11244,9 @@ static void aarch64_trblock_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;
> 
>> I think a better solution for a fixed-length ISA is to adjust max_insns. Perhaps
>> the init_disas_context hook should be able to modify it?
> 
> ARM has the thumb instructions, so it really isn't a fixed-length ISA.

 From the filename above we're talking about AArch64 here.
Whcih is most definitely a fixed-width ISA.


That said, even for AArch32 we know by the TB flags whether or not we're going 
to be generating arm or thumb code.  I think that these hooks will allow arm 
and thumb mode to finally be split apart cleanly, instead of the tangle that 
they are now.

I see arm's gen_intermediate_code eventually looking like

   const TranslatorOps *ops = &arm_translator_ops;
   if (ARM_TBFLAG_THUMB(tb->flags)) {
     ops = &thumb_translator_ops;
   }
#ifdef TARGET_AARCH64
   if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
     ops = &aarch64_translator_ops;
   }
#endif
   translator_loop(ops, &dc.base, cpu, tb);

There would certainly be some amount of shared code, but it would also allow 
quite a few of the existing dc->thumb checks to be eliminated.


>> And, while I'm thinking of it -- why is the init_globals hook separate? There's
>> nothing in between the two hook calls, and the more modern target front ends
>> won't need it.
> 
> You mean merging init_disas_context and init_globals? I wanted to keep
> semantically different code on separate hooks, but I can pull the init_globals
> code into init_disas_context (hoping that as targets get modernized, they won't
> initialize any global there).

I suppose you can leave the two hooks separate for now.  It doesn't hurt, and 
it's kind of a reminder of things that need cleaning up.

I do wonder if we should provide a generic empty hook, so that a target that 
does not need a particular hook need not define an empty function.  It could 
just put e.g. "translator_noop" into the structure.  Ok, maybe a better name 
than that...


r~
Emilio Cota July 7, 2017, 4:19 p.m. UTC | #4
On Fri, Jul 07, 2017 at 05:46:19 -1000, Richard Henderson wrote:
> I do wonder if we should provide a generic empty hook, so that a target that
> does not need a particular hook need not define an empty function.  It could
> just put e.g. "translator_noop" into the structure.  Ok, maybe a better name
> than that...

NULL would serve that purpose well. The subsequent "if (hook)" branch
would be essentially free because it'd be trivially predicted.

		E.
Lluís Vilanova July 7, 2017, 5:32 p.m. UTC | #5
Richard Henderson writes:

> On 07/07/2017 01:18 AM, Lluís Vilanova wrote:
>>>> diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
>>>> index 9c870f6d07..586a01a2de 100644
>>>> --- a/target/arm/translate-a64.c
>>>> +++ b/target/arm/translate-a64.c
>>>> @@ -11244,6 +11244,9 @@ static void aarch64_trblock_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;
>> 
>>> I think a better solution for a fixed-length ISA is to adjust max_insns. Perhaps
>>> the init_disas_context hook should be able to modify it?
>> 
>> ARM has the thumb instructions, so it really isn't a fixed-length ISA.

> From the filename above we're talking about AArch64 here.
> Whcih is most definitely a fixed-width ISA.


> That said, even for AArch32 we know by the TB flags whether or not we're going
> to be generating arm or thumb code.  I think that these hooks will allow arm and
> thumb mode to finally be split apart cleanly, instead of the tangle that they
> are now.

> I see arm's gen_intermediate_code eventually looking like

>   const TranslatorOps *ops = &arm_translator_ops;
>   if (ARM_TBFLAG_THUMB(tb->flags)) {
>     ops = &thumb_translator_ops;
>   }
> #ifdef TARGET_AARCH64
>   if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
>     ops = &aarch64_translator_ops;
>   }
> #endif
>   translator_loop(ops, &dc.base, cpu, tb);

> There would certainly be some amount of shared code, but it would also allow
> quite a few of the existing dc->thumb checks to be eliminated.

Does this really need to be addressed on this series?


>>> And, while I'm thinking of it -- why is the init_globals hook separate? There's
>>> nothing in between the two hook calls, and the more modern target front ends
>>> won't need it.
>> 
>> You mean merging init_disas_context and init_globals? I wanted to keep
>> semantically different code on separate hooks, but I can pull the init_globals
>> code into init_disas_context (hoping that as targets get modernized, they won't
>> initialize any global there).

> I suppose you can leave the two hooks separate for now.  It doesn't hurt, and
> it's kind of a reminder of things that need cleaning up.

Well, I've sent a (too rushed) v12 that features the merge. Since I'll have to
send a v13, I can split them again if you want.


> I do wonder if we should provide a generic empty hook, so that a target that
> does not need a particular hook need not define an empty function.  It could
> just put e.g. "translator_noop" into the structure.  Ok, maybe a better name
> than that...

I'm not really sure it's worth the effort. The original version trated NULLs as
a "skip this operation" (as Emilio suggests to revive), but after discussing the
approach it was decided that defining an empty function was not too much effort,
so that's what I went for.

I can restore the NULL approach or add a default empty hook implementation
(translator_ignored_op?) if there's a strong feeling to change it.


Cheers,
  Lluis
Lluís Vilanova July 7, 2017, 5:33 p.m. UTC | #6
Emilio G Cota writes:

> On Fri, Jul 07, 2017 at 05:46:19 -1000, Richard Henderson wrote:
>> I do wonder if we should provide a generic empty hook, so that a target that
>> does not need a particular hook need not define an empty function.  It could
>> just put e.g. "translator_noop" into the structure.  Ok, maybe a better name
>> than that...

> NULL would serve that purpose well. The subsequent "if (hook)" branch
> would be essentially free because it'd be trivially predicted.

Someone (Richard? can't remember exactly) already objected to using NULL.


Cheers,
  Lluis
Richard Henderson July 7, 2017, 5:41 p.m. UTC | #7
On 07/07/2017 07:32 AM, Lluís Vilanova wrote:
>> That said, even for AArch32 we know by the TB flags whether or not we're going
>> to be generating arm or thumb code.  I think that these hooks will allow arm and
>> thumb mode to finally be split apart cleanly, instead of the tangle that they
>> are now.
>> 
>> I see arm's gen_intermediate_code eventually looking like
>> 
>>    const TranslatorOps *ops = &arm_translator_ops;
>>    if (ARM_TBFLAG_THUMB(tb->flags)) {
>>      ops = &thumb_translator_ops;
>>    }
>> #ifdef TARGET_AARCH64
>>    if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
>>      ops = &aarch64_translator_ops;
>>    }
>> #endif
>>    translator_loop(ops, &dc.base, cpu, tb);
> 
>> There would certainly be some amount of shared code, but it would also allow
>> quite a few of the existing dc->thumb checks to be eliminated.
> 
> Does this really need to be addressed on this series?

No.  It is quite a tangle and it'll take some time to rectify.

>> I suppose you can leave the two hooks separate for now.  It doesn't hurt, and
>> it's kind of a reminder of things that need cleaning up.
> 
> Well, I've sent a (too rushed) v12 that features the merge. Since I'll have to
> send a v13, I can split them again if you want.

Don't go to any extra trouble if no one else has any strong feelings.

> I can restore the NULL approach or add a default empty hook implementation
> (translator_ignored_op?) if there's a strong feeling to change it.

Ok, we can work that out.


r~
Lluís Vilanova July 11, 2017, 3:56 p.m. UTC | #8
Richard Henderson writes:

> On 07/07/2017 07:32 AM, Lluís Vilanova wrote:
[...]
>> I can restore the NULL approach or add a default empty hook implementation
>> (translator_ignored_op?) if there's a strong feeling to change it.

> Ok, we can work that out.

I'm not sure what you mean. Leave as-is (targets must define all hooks), ignore
NULLs as before, add a default empty implementation for each hook?


Cheers,
  Lluis
diff mbox

Patch

diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 9c870f6d07..586a01a2de 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -11244,6 +11244,9 @@  static void aarch64_trblock_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_trblock_breakpoint_check(
     }
 }
 
+static target_ulong aarch64_trblock_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->ss_active) {
+        dc->base.is_jmp = DISAS_SS;
+    } else if (dc->pc >= dc->next_page_start) {
+        dc->base.is_jmp = DISAS_PAGE_CROSS;
+    }
+
+    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_trblock_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_trblock_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: