summary refs log tree commit diff stats
path: root/target/hexagon/genptr.c
diff options
context:
space:
mode:
authorTaylor Simpson <tsimpson@quicinc.com>2022-11-10 09:49:35 -0800
committerTaylor Simpson <tsimpson@quicinc.com>2022-12-16 10:10:28 -0800
commit564b2040a683bfc7169f14f75ac7a753378fbd8f (patch)
treef5f3204eadc26fedb59bfa5571618667b34615b8 /target/hexagon/genptr.c
parent1b9a7f2a1384d14dbb82862a612188797d398fe0 (diff)
downloadfocaccia-qemu-564b2040a683bfc7169f14f75ac7a753378fbd8f.tar.gz
focaccia-qemu-564b2040a683bfc7169f14f75ac7a753378fbd8f.zip
Hexagon (target/hexagon) Use direct block chaining for tight loops
Direct block chaining is documented here
https://qemu.readthedocs.io/en/latest/devel/tcg.html#direct-block-chaining

Hexagon inner loops end with the endloop0 instruction
To go back to the beginning of the loop, this instructions writes to PC
from register SA0 (start address 0).  To use direct block chaining, we
have to assign PC with a constant value.  So, we specialize the code
generation when the start of the translation block is equal to SA0.

When this is the case, we defer the compare/branch from endloop0 to
gen_end_tb.  When this is done, we can assign the start address of the TB
to PC.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Taylor Simpson <tsimpson@quicinc.com>
Message-Id: <20221108162906.3166-12-tsimpson@quicinc.com>
Diffstat (limited to 'target/hexagon/genptr.c')
-rw-r--r--target/hexagon/genptr.c84
1 files changed, 84 insertions, 0 deletions
diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index ee0f86fab2..a4a79c8454 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -497,6 +497,33 @@ static void gen_write_new_pc_pcrel(DisasContext *ctx, int pc_off,
     }
 }
 
+static void gen_set_usr_field(int field, TCGv val)
+{
+    tcg_gen_deposit_tl(hex_new_value[HEX_REG_USR], hex_new_value[HEX_REG_USR],
+                       val,
+                       reg_field_info[field].offset,
+                       reg_field_info[field].width);
+}
+
+static void gen_set_usr_fieldi(int field, int x)
+{
+    if (reg_field_info[field].width == 1) {
+        target_ulong bit = 1 << reg_field_info[field].offset;
+        if ((x & 1) == 1) {
+            tcg_gen_ori_tl(hex_new_value[HEX_REG_USR],
+                           hex_new_value[HEX_REG_USR],
+                           bit);
+        } else {
+            tcg_gen_andi_tl(hex_new_value[HEX_REG_USR],
+                            hex_new_value[HEX_REG_USR],
+                            ~bit);
+        }
+    } else {
+        TCGv val = tcg_constant_tl(x);
+        gen_set_usr_field(field, val);
+    }
+}
+
 static void gen_compare(TCGCond cond, TCGv res, TCGv arg1, TCGv arg2)
 {
     TCGv one = tcg_constant_tl(0xff);
@@ -636,6 +663,63 @@ static void gen_cond_call(DisasContext *ctx, TCGv pred,
     gen_set_label(skip);
 }
 
+static void gen_endloop0(DisasContext *ctx)
+{
+    TCGv lpcfg = tcg_temp_local_new();
+
+    GET_USR_FIELD(USR_LPCFG, lpcfg);
+
+    /*
+     *    if (lpcfg == 1) {
+     *        hex_new_pred_value[3] = 0xff;
+     *        hex_pred_written |= 1 << 3;
+     *    }
+     */
+    TCGLabel *label1 = gen_new_label();
+    tcg_gen_brcondi_tl(TCG_COND_NE, lpcfg, 1, label1);
+    {
+        tcg_gen_movi_tl(hex_new_pred_value[3], 0xff);
+        tcg_gen_ori_tl(hex_pred_written, hex_pred_written, 1 << 3);
+    }
+    gen_set_label(label1);
+
+    /*
+     *    if (lpcfg) {
+     *        SET_USR_FIELD(USR_LPCFG, lpcfg - 1);
+     *    }
+     */
+    TCGLabel *label2 = gen_new_label();
+    tcg_gen_brcondi_tl(TCG_COND_EQ, lpcfg, 0, label2);
+    {
+        tcg_gen_subi_tl(lpcfg, lpcfg, 1);
+        SET_USR_FIELD(USR_LPCFG, lpcfg);
+    }
+    gen_set_label(label2);
+
+    /*
+     * If we're in a tight loop, we'll do this at the end of the TB to take
+     * advantage of direct block chaining.
+     */
+    if (!ctx->is_tight_loop) {
+        /*
+         *    if (hex_gpr[HEX_REG_LC0] > 1) {
+         *        PC = hex_gpr[HEX_REG_SA0];
+         *        hex_new_value[HEX_REG_LC0] = hex_gpr[HEX_REG_LC0] - 1;
+         *    }
+         */
+        TCGLabel *label3 = gen_new_label();
+        tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC0], 1, label3);
+        {
+            gen_jumpr(ctx, hex_gpr[HEX_REG_SA0]);
+            tcg_gen_subi_tl(hex_new_value[HEX_REG_LC0],
+                            hex_gpr[HEX_REG_LC0], 1);
+        }
+        gen_set_label(label3);
+    }
+
+    tcg_temp_free(lpcfg);
+}
+
 static void gen_cmp_jumpnv(DisasContext *ctx,
                            TCGCond cond, TCGv val, TCGv src, int pc_off)
 {