diff mbox series

[v2,04/21] target/riscv: Introduce DisasExtend and new helpers

Message ID 20210817211803.283639-5-richard.henderson@linaro.org
State Superseded
Headers show
Series target/riscv: Use tcg_constant_* | expand

Commit Message

Richard Henderson Aug. 17, 2021, 9:17 p.m. UTC
Introduce get_gpr, dest_gpr, temp_new -- new helpers that do not force
tcg globals into temps, returning a constant 0 for $zero as source and
a new temp for $zero as destination.

Introduce ctx->w for simplifying word operations, such as addw.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

---
 target/riscv/translate.c | 102 +++++++++++++++++++++++++++++++--------
 1 file changed, 82 insertions(+), 20 deletions(-)

-- 
2.25.1

Comments

Bin Meng Aug. 18, 2021, 10:58 a.m. UTC | #1
On Wed, Aug 18, 2021 at 5:22 AM Richard Henderson
<richard.henderson@linaro.org> wrote:
>

> Introduce get_gpr, dest_gpr, temp_new -- new helpers that do not force

> tcg globals into temps, returning a constant 0 for $zero as source and

> a new temp for $zero as destination.

>

> Introduce ctx->w for simplifying word operations, such as addw.

>

> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

> ---

>  target/riscv/translate.c | 102 +++++++++++++++++++++++++++++++--------

>  1 file changed, 82 insertions(+), 20 deletions(-)

>

> diff --git a/target/riscv/translate.c b/target/riscv/translate.c

> index d540c85a1a..d5cf5e5826 100644

> --- a/target/riscv/translate.c

> +++ b/target/riscv/translate.c

> @@ -39,15 +39,25 @@ static TCGv load_val;

>

>  #include "exec/gen-icount.h"

>

> +/*

> + * If an operation is being performed on less than TARGET_LONG_BITS,

> + * it may require the inputs to be sign- or zero-extended; which will

> + * depend on the exact operation being performed.

> + */

> +typedef enum {

> +    EXT_NONE,

> +    EXT_SIGN,

> +    EXT_ZERO,

> +} DisasExtend;

> +

>  typedef struct DisasContext {

>      DisasContextBase base;

>      /* pc_succ_insn points to the instruction following base.pc_next */

>      target_ulong pc_succ_insn;

>      target_ulong priv_ver;

> -    bool virt_enabled;

> +    target_ulong misa;

>      uint32_t opcode;

>      uint32_t mstatus_fs;

> -    target_ulong misa;

>      uint32_t mem_idx;

>      /* Remember the rounding mode encoded in the previous fp instruction,

>         which we have already installed into env->fp_status.  Or -1 for

> @@ -55,6 +65,8 @@ typedef struct DisasContext {

>         to any system register, which includes CSR_FRM, so we do not have

>         to reset this known value.  */

>      int frm;

> +    bool w;

> +    bool virt_enabled;

>      bool ext_ifencei;

>      bool hlsx;

>      /* vector extension */

> @@ -64,7 +76,10 @@ typedef struct DisasContext {

>      uint16_t vlen;

>      uint16_t mlen;

>      bool vl_eq_vlmax;

> +    uint8_t ntemp;

>      CPUState *cs;

> +    TCGv zero;

> +    TCGv temp[4];


Why is 4? Is it enough? Perhaps a comment here is needed here?

>  } DisasContext;

>

>  static inline bool has_ext(DisasContext *ctx, uint32_t ext)

> @@ -172,27 +187,64 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)

>      }

>  }

>

> -/* Wrapper for getting reg values - need to check of reg is zero since

> - * cpu_gpr[0] is not actually allocated

> +/*

> + * Wrappers for getting reg values.

> + *

> + * The $zero register does not have cpu_gpr[0] allocated -- we supply the

> + * constant zero as a source, and an uninitialized sink as destination.

> + *

> + * Further, we may provide an extension for word operations.

>   */

> -static void gen_get_gpr(DisasContext *ctx, TCGv t, int reg_num)

> +static TCGv temp_new(DisasContext *ctx)

>  {

> -    if (reg_num == 0) {

> -        tcg_gen_movi_tl(t, 0);

> -    } else {

> -        tcg_gen_mov_tl(t, cpu_gpr[reg_num]);

> -    }

> +    assert(ctx->ntemp < ARRAY_SIZE(ctx->temp));

> +    return ctx->temp[ctx->ntemp++] = tcg_temp_new();

>  }

>

> -/* Wrapper for setting reg values - need to check of reg is zero since

> - * cpu_gpr[0] is not actually allocated. this is more for safety purposes,

> - * since we usually avoid calling the OP_TYPE_gen function if we see a write to

> - * $zero

> - */

> -static void gen_set_gpr(DisasContext *ctx, int reg_num_dst, TCGv t)

> +static TCGv get_gpr(DisasContext *ctx, int reg_num, DisasExtend ext)

>  {

> -    if (reg_num_dst != 0) {

> -        tcg_gen_mov_tl(cpu_gpr[reg_num_dst], t);

> +    TCGv t;

> +

> +    if (reg_num == 0) {

> +        return ctx->zero;

> +    }

> +

> +    switch (ctx->w ? ext : EXT_NONE) {

> +    case EXT_NONE:

> +        return cpu_gpr[reg_num];

> +    case EXT_SIGN:

> +        t = temp_new(ctx);

> +        tcg_gen_ext32s_tl(t, cpu_gpr[reg_num]);

> +        return t;

> +    case EXT_ZERO:

> +        t = temp_new(ctx);

> +        tcg_gen_ext32u_tl(t, cpu_gpr[reg_num]);

> +        return t;

> +    }

> +    g_assert_not_reached();

> +}

> +

> +static void gen_get_gpr(DisasContext *ctx, TCGv t, int reg_num)

> +{

> +    tcg_gen_mov_tl(t, get_gpr(ctx, reg_num, EXT_NONE));

> +}

> +

> +static TCGv __attribute__((unused)) dest_gpr(DisasContext *ctx, int reg_num)

> +{

> +    if (reg_num == 0 || ctx->w) {

> +        return temp_new(ctx);

> +    }

> +    return cpu_gpr[reg_num];

> +}

> +

> +static void gen_set_gpr(DisasContext *ctx, int reg_num, TCGv t)

> +{

> +    if (reg_num != 0) {

> +        if (ctx->w) {

> +            tcg_gen_ext32s_tl(cpu_gpr[reg_num], t);


What about zero extension?

> +        } else {

> +            tcg_gen_mov_tl(cpu_gpr[reg_num], t);

> +        }

>      }

>  }

>

> @@ -927,8 +979,11 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)

>      ctx->cs = cs;

>  }

>

> -static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu)

> +static void riscv_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu)

>  {

> +    DisasContext *ctx = container_of(dcbase, DisasContext, base);

> +

> +    ctx->zero = tcg_constant_tl(0);


This is better to be done in riscv_tr_init_disas_context() where ctx
members are initialized.

>  }

>

>  static void riscv_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)

> @@ -946,6 +1001,13 @@ static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)

>

>      decode_opc(env, ctx, opcode16);

>      ctx->base.pc_next = ctx->pc_succ_insn;

> +    ctx->w = false;

> +

> +    for (int i = ctx->ntemp - 1; i >= 0; --i) {

> +        tcg_temp_free(ctx->temp[i]);

> +        ctx->temp[i] = NULL;

> +    }

> +    ctx->ntemp = 0;

>

>      if (ctx->base.is_jmp == DISAS_NEXT) {

>          target_ulong page_start;

> @@ -997,7 +1059,7 @@ static const TranslatorOps riscv_tr_ops = {

>

>  void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)

>  {

> -    DisasContext ctx;

> +    DisasContext ctx = { };


Why is this change? I believe we should explicitly initialize the ctx
in riscv_tr_init_disas_context()

>

>      translator_loop(&riscv_tr_ops, &ctx.base, cs, tb, max_insns);

>  }

> --


Regards,
Bin
Richard Henderson Aug. 19, 2021, 1:16 a.m. UTC | #2
On 8/18/21 12:58 AM, Bin Meng wrote:
>> +static void gen_set_gpr(DisasContext *ctx, int reg_num, TCGv t)

>> +{

>> +    if (reg_num != 0) {

>> +        if (ctx->w) {

>> +            tcg_gen_ext32s_tl(cpu_gpr[reg_num], t);

> 

> What about zero extension?


All of the RV64 word instructions sign-extend the result.

>>   void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)

>>   {

>> -    DisasContext ctx;

>> +    DisasContext ctx = { };

> 

> Why is this change? I believe we should explicitly initialize the ctx

> in riscv_tr_init_disas_context()


I considered it easier to zero-init the whole thing here.

r~
Richard Henderson Aug. 19, 2021, 2:01 a.m. UTC | #3
On 8/18/21 12:58 AM, Bin Meng wrote:
>> +    TCGv temp[4];

> 

> Why is 4? Is it enough? Perhaps a comment here is needed here?


It's a round number that will cover three operands plus an extra for address computation.

r~
Alistair Francis Aug. 19, 2021, 6:25 a.m. UTC | #4
On Wed, Aug 18, 2021 at 7:23 AM Richard Henderson
<richard.henderson@linaro.org> wrote:
>

> Introduce get_gpr, dest_gpr, temp_new -- new helpers that do not force

> tcg globals into temps, returning a constant 0 for $zero as source and

> a new temp for $zero as destination.

>

> Introduce ctx->w for simplifying word operations, such as addw.

>

> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>


Reviewed-by: Alistair Francis <alistair.francis@wdc.com>


Alistair

> ---

>  target/riscv/translate.c | 102 +++++++++++++++++++++++++++++++--------

>  1 file changed, 82 insertions(+), 20 deletions(-)

>

> diff --git a/target/riscv/translate.c b/target/riscv/translate.c

> index d540c85a1a..d5cf5e5826 100644

> --- a/target/riscv/translate.c

> +++ b/target/riscv/translate.c

> @@ -39,15 +39,25 @@ static TCGv load_val;

>

>  #include "exec/gen-icount.h"

>

> +/*

> + * If an operation is being performed on less than TARGET_LONG_BITS,

> + * it may require the inputs to be sign- or zero-extended; which will

> + * depend on the exact operation being performed.

> + */

> +typedef enum {

> +    EXT_NONE,

> +    EXT_SIGN,

> +    EXT_ZERO,

> +} DisasExtend;

> +

>  typedef struct DisasContext {

>      DisasContextBase base;

>      /* pc_succ_insn points to the instruction following base.pc_next */

>      target_ulong pc_succ_insn;

>      target_ulong priv_ver;

> -    bool virt_enabled;

> +    target_ulong misa;

>      uint32_t opcode;

>      uint32_t mstatus_fs;

> -    target_ulong misa;

>      uint32_t mem_idx;

>      /* Remember the rounding mode encoded in the previous fp instruction,

>         which we have already installed into env->fp_status.  Or -1 for

> @@ -55,6 +65,8 @@ typedef struct DisasContext {

>         to any system register, which includes CSR_FRM, so we do not have

>         to reset this known value.  */

>      int frm;

> +    bool w;

> +    bool virt_enabled;

>      bool ext_ifencei;

>      bool hlsx;

>      /* vector extension */

> @@ -64,7 +76,10 @@ typedef struct DisasContext {

>      uint16_t vlen;

>      uint16_t mlen;

>      bool vl_eq_vlmax;

> +    uint8_t ntemp;

>      CPUState *cs;

> +    TCGv zero;

> +    TCGv temp[4];

>  } DisasContext;

>

>  static inline bool has_ext(DisasContext *ctx, uint32_t ext)

> @@ -172,27 +187,64 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)

>      }

>  }

>

> -/* Wrapper for getting reg values - need to check of reg is zero since

> - * cpu_gpr[0] is not actually allocated

> +/*

> + * Wrappers for getting reg values.

> + *

> + * The $zero register does not have cpu_gpr[0] allocated -- we supply the

> + * constant zero as a source, and an uninitialized sink as destination.

> + *

> + * Further, we may provide an extension for word operations.

>   */

> -static void gen_get_gpr(DisasContext *ctx, TCGv t, int reg_num)

> +static TCGv temp_new(DisasContext *ctx)

>  {

> -    if (reg_num == 0) {

> -        tcg_gen_movi_tl(t, 0);

> -    } else {

> -        tcg_gen_mov_tl(t, cpu_gpr[reg_num]);

> -    }

> +    assert(ctx->ntemp < ARRAY_SIZE(ctx->temp));

> +    return ctx->temp[ctx->ntemp++] = tcg_temp_new();

>  }

>

> -/* Wrapper for setting reg values - need to check of reg is zero since

> - * cpu_gpr[0] is not actually allocated. this is more for safety purposes,

> - * since we usually avoid calling the OP_TYPE_gen function if we see a write to

> - * $zero

> - */

> -static void gen_set_gpr(DisasContext *ctx, int reg_num_dst, TCGv t)

> +static TCGv get_gpr(DisasContext *ctx, int reg_num, DisasExtend ext)

>  {

> -    if (reg_num_dst != 0) {

> -        tcg_gen_mov_tl(cpu_gpr[reg_num_dst], t);

> +    TCGv t;

> +

> +    if (reg_num == 0) {

> +        return ctx->zero;

> +    }

> +

> +    switch (ctx->w ? ext : EXT_NONE) {

> +    case EXT_NONE:

> +        return cpu_gpr[reg_num];

> +    case EXT_SIGN:

> +        t = temp_new(ctx);

> +        tcg_gen_ext32s_tl(t, cpu_gpr[reg_num]);

> +        return t;

> +    case EXT_ZERO:

> +        t = temp_new(ctx);

> +        tcg_gen_ext32u_tl(t, cpu_gpr[reg_num]);

> +        return t;

> +    }

> +    g_assert_not_reached();

> +}

> +

> +static void gen_get_gpr(DisasContext *ctx, TCGv t, int reg_num)

> +{

> +    tcg_gen_mov_tl(t, get_gpr(ctx, reg_num, EXT_NONE));

> +}

> +

> +static TCGv __attribute__((unused)) dest_gpr(DisasContext *ctx, int reg_num)

> +{

> +    if (reg_num == 0 || ctx->w) {

> +        return temp_new(ctx);

> +    }

> +    return cpu_gpr[reg_num];

> +}

> +

> +static void gen_set_gpr(DisasContext *ctx, int reg_num, TCGv t)

> +{

> +    if (reg_num != 0) {

> +        if (ctx->w) {

> +            tcg_gen_ext32s_tl(cpu_gpr[reg_num], t);

> +        } else {

> +            tcg_gen_mov_tl(cpu_gpr[reg_num], t);

> +        }

>      }

>  }

>

> @@ -927,8 +979,11 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)

>      ctx->cs = cs;

>  }

>

> -static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu)

> +static void riscv_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu)

>  {

> +    DisasContext *ctx = container_of(dcbase, DisasContext, base);

> +

> +    ctx->zero = tcg_constant_tl(0);

>  }

>

>  static void riscv_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)

> @@ -946,6 +1001,13 @@ static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)

>

>      decode_opc(env, ctx, opcode16);

>      ctx->base.pc_next = ctx->pc_succ_insn;

> +    ctx->w = false;

> +

> +    for (int i = ctx->ntemp - 1; i >= 0; --i) {

> +        tcg_temp_free(ctx->temp[i]);

> +        ctx->temp[i] = NULL;

> +    }

> +    ctx->ntemp = 0;

>

>      if (ctx->base.is_jmp == DISAS_NEXT) {

>          target_ulong page_start;

> @@ -997,7 +1059,7 @@ static const TranslatorOps riscv_tr_ops = {

>

>  void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)

>  {

> -    DisasContext ctx;

> +    DisasContext ctx = { };

>

>      translator_loop(&riscv_tr_ops, &ctx.base, cs, tb, max_insns);

>  }

> --

> 2.25.1

>

>
diff mbox series

Patch

diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index d540c85a1a..d5cf5e5826 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -39,15 +39,25 @@  static TCGv load_val;
 
 #include "exec/gen-icount.h"
 
+/*
+ * If an operation is being performed on less than TARGET_LONG_BITS,
+ * it may require the inputs to be sign- or zero-extended; which will
+ * depend on the exact operation being performed.
+ */
+typedef enum {
+    EXT_NONE,
+    EXT_SIGN,
+    EXT_ZERO,
+} DisasExtend;
+
 typedef struct DisasContext {
     DisasContextBase base;
     /* pc_succ_insn points to the instruction following base.pc_next */
     target_ulong pc_succ_insn;
     target_ulong priv_ver;
-    bool virt_enabled;
+    target_ulong misa;
     uint32_t opcode;
     uint32_t mstatus_fs;
-    target_ulong misa;
     uint32_t mem_idx;
     /* Remember the rounding mode encoded in the previous fp instruction,
        which we have already installed into env->fp_status.  Or -1 for
@@ -55,6 +65,8 @@  typedef struct DisasContext {
        to any system register, which includes CSR_FRM, so we do not have
        to reset this known value.  */
     int frm;
+    bool w;
+    bool virt_enabled;
     bool ext_ifencei;
     bool hlsx;
     /* vector extension */
@@ -64,7 +76,10 @@  typedef struct DisasContext {
     uint16_t vlen;
     uint16_t mlen;
     bool vl_eq_vlmax;
+    uint8_t ntemp;
     CPUState *cs;
+    TCGv zero;
+    TCGv temp[4];
 } DisasContext;
 
 static inline bool has_ext(DisasContext *ctx, uint32_t ext)
@@ -172,27 +187,64 @@  static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
     }
 }
 
-/* Wrapper for getting reg values - need to check of reg is zero since
- * cpu_gpr[0] is not actually allocated
+/*
+ * Wrappers for getting reg values.
+ *
+ * The $zero register does not have cpu_gpr[0] allocated -- we supply the
+ * constant zero as a source, and an uninitialized sink as destination.
+ *
+ * Further, we may provide an extension for word operations.
  */
-static void gen_get_gpr(DisasContext *ctx, TCGv t, int reg_num)
+static TCGv temp_new(DisasContext *ctx)
 {
-    if (reg_num == 0) {
-        tcg_gen_movi_tl(t, 0);
-    } else {
-        tcg_gen_mov_tl(t, cpu_gpr[reg_num]);
-    }
+    assert(ctx->ntemp < ARRAY_SIZE(ctx->temp));
+    return ctx->temp[ctx->ntemp++] = tcg_temp_new();
 }
 
-/* Wrapper for setting reg values - need to check of reg is zero since
- * cpu_gpr[0] is not actually allocated. this is more for safety purposes,
- * since we usually avoid calling the OP_TYPE_gen function if we see a write to
- * $zero
- */
-static void gen_set_gpr(DisasContext *ctx, int reg_num_dst, TCGv t)
+static TCGv get_gpr(DisasContext *ctx, int reg_num, DisasExtend ext)
 {
-    if (reg_num_dst != 0) {
-        tcg_gen_mov_tl(cpu_gpr[reg_num_dst], t);
+    TCGv t;
+
+    if (reg_num == 0) {
+        return ctx->zero;
+    }
+
+    switch (ctx->w ? ext : EXT_NONE) {
+    case EXT_NONE:
+        return cpu_gpr[reg_num];
+    case EXT_SIGN:
+        t = temp_new(ctx);
+        tcg_gen_ext32s_tl(t, cpu_gpr[reg_num]);
+        return t;
+    case EXT_ZERO:
+        t = temp_new(ctx);
+        tcg_gen_ext32u_tl(t, cpu_gpr[reg_num]);
+        return t;
+    }
+    g_assert_not_reached();
+}
+
+static void gen_get_gpr(DisasContext *ctx, TCGv t, int reg_num)
+{
+    tcg_gen_mov_tl(t, get_gpr(ctx, reg_num, EXT_NONE));
+}
+
+static TCGv __attribute__((unused)) dest_gpr(DisasContext *ctx, int reg_num)
+{
+    if (reg_num == 0 || ctx->w) {
+        return temp_new(ctx);
+    }
+    return cpu_gpr[reg_num];
+}
+
+static void gen_set_gpr(DisasContext *ctx, int reg_num, TCGv t)
+{
+    if (reg_num != 0) {
+        if (ctx->w) {
+            tcg_gen_ext32s_tl(cpu_gpr[reg_num], t);
+        } else {
+            tcg_gen_mov_tl(cpu_gpr[reg_num], t);
+        }
     }
 }
 
@@ -927,8 +979,11 @@  static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
     ctx->cs = cs;
 }
 
-static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu)
+static void riscv_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu)
 {
+    DisasContext *ctx = container_of(dcbase, DisasContext, base);
+
+    ctx->zero = tcg_constant_tl(0);
 }
 
 static void riscv_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
@@ -946,6 +1001,13 @@  static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
 
     decode_opc(env, ctx, opcode16);
     ctx->base.pc_next = ctx->pc_succ_insn;
+    ctx->w = false;
+
+    for (int i = ctx->ntemp - 1; i >= 0; --i) {
+        tcg_temp_free(ctx->temp[i]);
+        ctx->temp[i] = NULL;
+    }
+    ctx->ntemp = 0;
 
     if (ctx->base.is_jmp == DISAS_NEXT) {
         target_ulong page_start;
@@ -997,7 +1059,7 @@  static const TranslatorOps riscv_tr_ops = {
 
 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
 {
-    DisasContext ctx;
+    DisasContext ctx = { };
 
     translator_loop(&riscv_tr_ops, &ctx.base, cs, tb, max_insns);
 }