We create a new generator that creates an analyze_<tag> function for
each instruction. Currently, these functions record the writes to
R, P, and C registers by calling ctx_log_reg_write[_pair] or
ctx_log_pred_write.
During gen_start_packet, we invoke the analyze_<tag> function for
each instruction in the packet, and we mark the implicit register
and predicate writes.
Doing the analysis up front has several advantages
- We remove calls to ctx_log_* from gen_tcg_funcs.py and genptr.c
- After the analysis is performed, we can initialize hex_new_value
for each of the predicated assignments rather than during TCG
generation for the instructions
- This is a stepping stone for future work where the analysis will
include the set of registers that are read. In cases where
the packet doesn't have an overlap between the registers that are
written and registers that are read, we can avoid the intermediate
step of writing to hex_new_value. Note that other checks will also
be needed (e.g., no instructions can raise an exception).
Signed-off-by: Taylor Simpson <tsimpson@quicinc.com>
---
target/hexagon/translate.h | 46 ++--
target/hexagon/genptr.c | 5 +-
target/hexagon/idef-parser/parser-helpers.c | 7 +-
target/hexagon/translate.c | 160 ++++++++------
target/hexagon/README | 10 +-
target/hexagon/gen_analyze_funcs.py | 225 ++++++++++++++++++++
target/hexagon/gen_tcg_funcs.py | 23 +-
target/hexagon/meson.build | 11 +-
8 files changed, 370 insertions(+), 117 deletions(-)
create mode 100755 target/hexagon/gen_analyze_funcs.py
diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h
index d971f4f095..d45d3a4bb0 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ * Copyright(c) 2019-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -38,6 +38,7 @@ typedef struct DisasContext {
int reg_log[REG_WRITES_MAX];
int reg_log_idx;
DECLARE_BITMAP(regs_written, TOTAL_PER_THREAD_REGS);
+ DECLARE_BITMAP(predicated_regs, TOTAL_PER_THREAD_REGS);
int preg_log[PRED_WRITES_MAX];
int preg_log_idx;
DECLARE_BITMAP(pregs_written, NUM_PREGS);
@@ -62,32 +63,39 @@ typedef struct DisasContext {
bool is_tight_loop;
} DisasContext;
-static inline void ctx_log_reg_write(DisasContext *ctx, int rnum)
+static inline void ctx_log_pred_write(DisasContext *ctx, int pnum)
{
- if (test_bit(rnum, ctx->regs_written)) {
- HEX_DEBUG_LOG("WARNING: Multiple writes to r%d\n", rnum);
+ if (!test_bit(pnum, ctx->pregs_written)) {
+ ctx->preg_log[ctx->preg_log_idx] = pnum;
+ ctx->preg_log_idx++;
+ set_bit(pnum, ctx->pregs_written);
}
- ctx->reg_log[ctx->reg_log_idx] = rnum;
- ctx->reg_log_idx++;
- set_bit(rnum, ctx->regs_written);
-}
-
-static inline void ctx_log_reg_write_pair(DisasContext *ctx, int rnum)
-{
- ctx_log_reg_write(ctx, rnum);
- ctx_log_reg_write(ctx, rnum + 1);
}
-static inline void ctx_log_pred_write(DisasContext *ctx, int pnum)
+static inline void ctx_log_reg_write(DisasContext *ctx, int rnum,
+ bool is_predicated)
{
- ctx->preg_log[ctx->preg_log_idx] = pnum;
- ctx->preg_log_idx++;
- set_bit(pnum, ctx->pregs_written);
+ if (rnum == HEX_REG_P3_0_ALIASED) {
+ for (int i = 0; i < NUM_PREGS; i++) {
+ ctx_log_pred_write(ctx, i);
+ }
+ } else {
+ if (!test_bit(rnum, ctx->regs_written)) {
+ ctx->reg_log[ctx->reg_log_idx] = rnum;
+ ctx->reg_log_idx++;
+ set_bit(rnum, ctx->regs_written);
+ }
+ if (is_predicated) {
+ set_bit(rnum, ctx->predicated_regs);
+ }
+ }
}
-static inline bool is_preloaded(DisasContext *ctx, int num)
+static inline void ctx_log_reg_write_pair(DisasContext *ctx, int rnum,
+ bool is_predicated)
{
- return test_bit(num, ctx->regs_written);
+ ctx_log_reg_write(ctx, rnum, is_predicated);
+ ctx_log_reg_write(ctx, rnum + 1, is_predicated);
}
static inline bool is_vreg_preloaded(DisasContext *ctx, int num)
diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index efd36f760f..67ec3ac551 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -189,6 +189,7 @@ void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val)
hex_new_pred_value[pnum], base_val);
}
tcg_gen_ori_tl(hex_pred_written, hex_pred_written, 1 << pnum);
+ set_bit(pnum, ctx->pregs_written);
tcg_temp_free(base_val);
}
@@ -271,7 +272,6 @@ static void gen_write_p3_0(DisasContext *ctx, TCGv control_reg)
for (int i = 0; i < NUM_PREGS; i++) {
tcg_gen_extract_tl(hex_p8, control_reg, i * 8, 8);
gen_log_pred_write(ctx, i, hex_p8);
- ctx_log_pred_write(ctx, i);
}
tcg_temp_free(hex_p8);
}
@@ -290,7 +290,6 @@ static inline void gen_write_ctrl_reg(DisasContext *ctx, int reg_num,
gen_write_p3_0(ctx, val);
} else {
gen_log_reg_write(reg_num, val);
- ctx_log_reg_write(ctx, reg_num);
if (reg_num == HEX_REG_QEMU_PKT_CNT) {
ctx->num_packets = 0;
}
@@ -313,10 +312,8 @@ static inline void gen_write_ctrl_reg_pair(DisasContext *ctx, int reg_num,
tcg_gen_extrh_i64_i32(val32, val);
gen_log_reg_write(reg_num + 1, val32);
tcg_temp_free(val32);
- ctx_log_reg_write(ctx, reg_num + 1);
} else {
gen_log_reg_write_pair(reg_num, val);
- ctx_log_reg_write_pair(ctx, reg_num);
if (reg_num == HEX_REG_QEMU_PKT_CNT) {
ctx->num_packets = 0;
ctx->num_insns = 0;
diff --git a/target/hexagon/idef-parser/parser-helpers.c b/target/hexagon/idef-parser/parser-helpers.c
index 8110686c51..de9838806b 100644
--- a/target/hexagon/idef-parser/parser-helpers.c
+++ b/target/hexagon/idef-parser/parser-helpers.c
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2019-2022 rev.ng Labs Srl. All Rights Reserved.
+ * Copyright(c) 2019-2023 rev.ng Labs Srl. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -1438,10 +1438,6 @@ void gen_write_reg(Context *c, YYLTYPE *locp, HexValue *reg, HexValue *value)
locp,
"gen_log_reg_write(", ®->reg.id, ", ",
&value_m, ");\n");
- OUT(c,
- locp,
- "ctx_log_reg_write(ctx, ", ®->reg.id,
- ");\n");
gen_rvalue_free(c, locp, reg);
gen_rvalue_free(c, locp, &value_m);
}
@@ -1894,7 +1890,6 @@ void gen_pred_assign(Context *c, YYLTYPE *locp, HexValue *left_pred,
if (is_direct) {
OUT(c, locp, "gen_log_pred_write(ctx, ", pred_id, ", ", left_pred,
");\n");
- OUT(c, locp, "ctx_log_pred_write(ctx, ", pred_id, ");\n");
gen_rvalue_free(c, locp, left_pred);
}
/* Free temporary value */
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index 5be24102aa..8f3436d69a 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -29,6 +29,15 @@
#include "translate.h"
#include "printinsn.h"
+#include "analyze_funcs_generated.c.inc"
+
+typedef void (*AnalyzeInsn)(DisasContext *ctx);
+static const AnalyzeInsn opcode_analyze[XX_LAST_OPCODE] = {
+#define OPCODE(X) [X] = analyze_##X
+#include "opcodes_def_generated.h.inc"
+#undef OPCODE
+};
+
TCGv hex_gpr[TOTAL_PER_THREAD_REGS];
TCGv hex_pred[NUM_PREGS];
TCGv hex_this_PC;
@@ -264,6 +273,76 @@ static bool need_next_PC(DisasContext *ctx)
return false;
}
+/*
+ * The opcode_analyze functions mark most of the writes in a packet
+ * However, there are some implicit writes marked as attributes
+ * of the applicable instructions.
+ */
+static void mark_implicit_reg_write(DisasContext *ctx, int attrib, int rnum)
+{
+ uint16_t opcode = ctx->insn->opcode;
+ if (GET_ATTRIB(opcode, attrib)) {
+ /*
+ * USR is used to set overflow and FP exceptions,
+ * so treat it as conditional
+ */
+ bool is_predicated = GET_ATTRIB(opcode, A_CONDEXEC) ||
+ rnum == HEX_REG_USR;
+
+ /* LC0/LC1 is conditionally written by endloop instructions */
+ if ((rnum == HEX_REG_LC0 || rnum == HEX_REG_LC1) &&
+ (opcode == J2_endloop0 ||
+ opcode == J2_endloop1 ||
+ opcode == J2_endloop01)) {
+ is_predicated = true;
+ }
+
+ ctx_log_reg_write(ctx, rnum, is_predicated);
+ }
+}
+
+static void mark_implicit_reg_writes(DisasContext *ctx)
+{
+ mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_FP, HEX_REG_FP);
+ mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_SP, HEX_REG_SP);
+ mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_LR, HEX_REG_LR);
+ mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_LC0, HEX_REG_LC0);
+ mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_SA0, HEX_REG_SA0);
+ mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_LC1, HEX_REG_LC1);
+ mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_SA1, HEX_REG_SA1);
+ mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_USR, HEX_REG_USR);
+ mark_implicit_reg_write(ctx, A_FPOP, HEX_REG_USR);
+}
+
+static void mark_implicit_pred_write(DisasContext *ctx, int attrib, int pnum)
+{
+ if (GET_ATTRIB(ctx->insn->opcode, attrib)) {
+ ctx_log_pred_write(ctx, pnum);
+ }
+}
+
+static void mark_implicit_pred_writes(DisasContext *ctx)
+{
+ mark_implicit_pred_write(ctx, A_IMPLICIT_WRITES_P0, 0);
+ mark_implicit_pred_write(ctx, A_IMPLICIT_WRITES_P1, 1);
+ mark_implicit_pred_write(ctx, A_IMPLICIT_WRITES_P2, 2);
+ mark_implicit_pred_write(ctx, A_IMPLICIT_WRITES_P3, 3);
+}
+
+static void analyze_packet(DisasContext *ctx)
+{
+ Packet *pkt = ctx->pkt;
+ for (int i = 0; i < pkt->num_insns; i++) {
+ Insn *insn = &pkt->insn[i];
+ ctx->insn = insn;
+ if (opcode_analyze[insn->opcode]) {
+ opcode_analyze[insn->opcode](ctx);
+ }
+ mark_implicit_reg_writes(ctx);
+ mark_implicit_pred_writes(ctx);
+ }
+}
+
static void gen_start_packet(DisasContext *ctx)
{
Packet *pkt = ctx->pkt;
@@ -274,6 +353,7 @@ static void gen_start_packet(DisasContext *ctx)
ctx->next_PC = next_PC;
ctx->reg_log_idx = 0;
bitmap_zero(ctx->regs_written, TOTAL_PER_THREAD_REGS);
+ bitmap_zero(ctx->predicated_regs, TOTAL_PER_THREAD_REGS);
ctx->preg_log_idx = 0;
bitmap_zero(ctx->pregs_written, NUM_PREGS);
ctx->future_vregs_idx = 0;
@@ -289,6 +369,14 @@ static void gen_start_packet(DisasContext *ctx)
ctx->s1_store_processed = false;
ctx->pre_commit = true;
+ analyze_packet(ctx);
+
+ /*
+ * pregs_written is used both in the analyze phase as well as the code
+ * gen phase, so clear it again.
+ */
+ bitmap_zero(ctx->pregs_written, NUM_PREGS);
+
if (HEX_DEBUG) {
/* Handy place to set a breakpoint before the packet executes */
gen_helper_debug_start_packet(cpu_env);
@@ -311,6 +399,16 @@ static void gen_start_packet(DisasContext *ctx)
tcg_gen_movi_tl(hex_pred_written, 0);
}
+ /* Preload the predicated registers into hex_new_value[i] */
+ if (!bitmap_empty(ctx->predicated_regs, TOTAL_PER_THREAD_REGS)) {
+ int i = find_first_bit(ctx->predicated_regs, TOTAL_PER_THREAD_REGS);
+ while (i < TOTAL_PER_THREAD_REGS) {
+ tcg_gen_mov_tl(hex_new_value[i], hex_gpr[i]);
+ i = find_next_bit(ctx->predicated_regs, TOTAL_PER_THREAD_REGS,
+ i + 1);
+ }
+ }
+
if (pkt->pkt_has_hvx) {
tcg_gen_movi_tl(hex_VRegs_updated, 0);
tcg_gen_movi_tl(hex_QRegs_updated, 0);
@@ -334,66 +432,6 @@ bool is_gather_store_insn(DisasContext *ctx)
return false;
}
-/*
- * The LOG_*_WRITE macros mark most of the writes in a packet
- * However, there are some implicit writes marked as attributes
- * of the applicable instructions.
- */
-static void mark_implicit_reg_write(DisasContext *ctx, int attrib, int rnum)
-{
- uint16_t opcode = ctx->insn->opcode;
- if (GET_ATTRIB(opcode, attrib)) {
- /*
- * USR is used to set overflow and FP exceptions,
- * so treat it as conditional
- */
- bool is_predicated = GET_ATTRIB(opcode, A_CONDEXEC) ||
- rnum == HEX_REG_USR;
-
- /* LC0/LC1 is conditionally written by endloop instructions */
- if ((rnum == HEX_REG_LC0 || rnum == HEX_REG_LC1) &&
- (opcode == J2_endloop0 ||
- opcode == J2_endloop1 ||
- opcode == J2_endloop01)) {
- is_predicated = true;
- }
-
- if (is_predicated && !is_preloaded(ctx, rnum)) {
- tcg_gen_mov_tl(hex_new_value[rnum], hex_gpr[rnum]);
- }
-
- ctx_log_reg_write(ctx, rnum);
- }
-}
-
-static void mark_implicit_pred_write(DisasContext *ctx, int attrib, int pnum)
-{
- if (GET_ATTRIB(ctx->insn->opcode, attrib)) {
- ctx_log_pred_write(ctx, pnum);
- }
-}
-
-static void mark_implicit_reg_writes(DisasContext *ctx)
-{
- mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_FP, HEX_REG_FP);
- mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_SP, HEX_REG_SP);
- mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_LR, HEX_REG_LR);
- mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_LC0, HEX_REG_LC0);
- mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_SA0, HEX_REG_SA0);
- mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_LC1, HEX_REG_LC1);
- mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_SA1, HEX_REG_SA1);
- mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_USR, HEX_REG_USR);
- mark_implicit_reg_write(ctx, A_FPOP, HEX_REG_USR);
-}
-
-static void mark_implicit_pred_writes(DisasContext *ctx)
-{
- mark_implicit_pred_write(ctx, A_IMPLICIT_WRITES_P0, 0);
- mark_implicit_pred_write(ctx, A_IMPLICIT_WRITES_P1, 1);
- mark_implicit_pred_write(ctx, A_IMPLICIT_WRITES_P2, 2);
- mark_implicit_pred_write(ctx, A_IMPLICIT_WRITES_P3, 3);
-}
-
static void mark_store_width(DisasContext *ctx)
{
uint16_t opcode = ctx->insn->opcode;
@@ -421,9 +459,7 @@ static void mark_store_width(DisasContext *ctx)
static void gen_insn(DisasContext *ctx)
{
if (ctx->insn->generate) {
- mark_implicit_reg_writes(ctx);
ctx->insn->generate(ctx);
- mark_implicit_pred_writes(ctx);
mark_store_width(ctx);
} else {
gen_exception_end_tb(ctx, HEX_EXCP_INVALID_OPCODE);
diff --git a/target/hexagon/README b/target/hexagon/README
index 6cb5affddb..d92731e346 100644
--- a/target/hexagon/README
+++ b/target/hexagon/README
@@ -52,6 +52,7 @@ header files in <BUILD_DIR>/target/hexagon
gen_tcg_func_table.py -> tcg_func_table_generated.c.inc
gen_helper_funcs.py -> helper_funcs_generated.c.inc
gen_idef_parser_funcs.py -> idef_parser_input.h
+ gen_analyze_funcs.py -> analyze_funcs_generated.c.inc
Qemu helper functions have 3 parts
DEF_HELPER declaration indicates the signature of the helper
@@ -87,7 +88,6 @@ tcg_funcs_generated.c.inc
TCGv RtV = hex_gpr[insn->regno[2]];
gen_helper_A2_add(RdV, cpu_env, RsV, RtV);
gen_log_reg_write(RdN, RdV);
- ctx_log_reg_write(ctx, RdN);
tcg_temp_free(RdV);
}
@@ -162,7 +162,6 @@ istruction.
gen_helper_V6_vaddw(cpu_env, VdV, VuV, VvV, slot);
tcg_temp_free(slot);
gen_log_vreg_write(ctx, VdV_off, VdN, EXT_DFL, insn->slot, false);
- ctx_log_vreg_write(ctx, VdN, EXT_DFL, false);
tcg_temp_free_ptr(VdV);
tcg_temp_free_ptr(VuV);
tcg_temp_free_ptr(VvV);
@@ -195,9 +194,14 @@ when the override is present.
vreg_src_off(ctx, VvN);
fGEN_TCG_V6_vaddw({ fHIDE(int i;) fVFOREACH(32, i) { VdV.w[i] = VuV.w[i] + VvV.w[i] ; } });
gen_log_vreg_write(ctx, VdV_off, VdN, EXT_DFL, insn->slot, false);
- ctx_log_vreg_write(ctx, VdN, EXT_DFL, false);
}
+We also generate an analyze_<tag> function for each instruction. Currently,
+these functions record the writes to registers by calling ctx_log_*. During
+gen_start_packet, we invoke the analyze_<tag> function for each instruction in
+the packet, and we mark the implicit writes. After the analysis is performed,
+we initialize hex_new_value for each of the predicated assignments.
+
In addition to instruction semantics, we use a generator to create the decode
tree. This generation is also a two step process. The first step is to run
target/hexagon/gen_dectree_import.c to produce
diff --git a/target/hexagon/gen_analyze_funcs.py b/target/hexagon/gen_analyze_funcs.py
new file mode 100755
index 0000000000..67a8e5e5e2
--- /dev/null
+++ b/target/hexagon/gen_analyze_funcs.py
@@ -0,0 +1,225 @@
+#!/usr/bin/env python3
+
+##
+## Copyright(c) 2022-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+##
+
+import sys
+import re
+import string
+import hex_common
+
+##
+## Helpers for gen_analyze_func
+##
+def is_predicated(tag):
+ return 'A_CONDEXEC' in hex_common.attribdict[tag]
+
+def analyze_opn_old(f, tag, regtype, regid, regno):
+ regN = "%s%sN" % (regtype, regid)
+ predicated = "true" if is_predicated(tag) else "false"
+ if (regtype == "R"):
+ if (regid in {"ss", "tt"}):
+ f.write("// const int %s = insn->regno[%d];\n" % \
+ (regN, regno))
+ elif (regid in {"dd", "ee", "xx", "yy"}):
+ f.write(" const int %s = insn->regno[%d];\n" % (regN, regno))
+ f.write(" ctx_log_reg_write_pair(ctx, %s, %s);\n" % \
+ (regN, predicated))
+ elif (regid in {"s", "t", "u", "v"}):
+ f.write("// const int %s = insn->regno[%d];\n" % \
+ (regN, regno))
+ elif (regid in {"d", "e", "x", "y"}):
+ f.write(" const int %s = insn->regno[%d];\n" % (regN, regno))
+ f.write(" ctx_log_reg_write(ctx, %s, %s);\n" % \
+ (regN, predicated))
+ else:
+ print("Bad register parse: ", regtype, regid)
+ elif (regtype == "P"):
+ if (regid in {"s", "t", "u", "v"}):
+ f.write("// const int %s = insn->regno[%d];\n" % \
+ (regN, regno))
+ elif (regid in {"d", "e", "x"}):
+ f.write(" const int %s = insn->regno[%d];\n" % (regN, regno))
+ f.write(" ctx_log_pred_write(ctx, %s);\n" % (regN))
+ else:
+ print("Bad register parse: ", regtype, regid)
+ elif (regtype == "C"):
+ if (regid == "ss"):
+ f.write("// const int %s = insn->regno[%d] + HEX_REG_SA0;\n" % \
+ (regN, regno))
+ elif (regid == "dd"):
+ f.write(" const int %s = insn->regno[%d] + HEX_REG_SA0;\n" % \
+ (regN, regno))
+ f.write(" ctx_log_reg_write_pair(ctx, %s, %s);\n" % \
+ (regN, predicated))
+ elif (regid == "s"):
+ f.write("// const int %s = insn->regno[%d] + HEX_REG_SA0;\n" % \
+ (regN, regno))
+ elif (regid == "d"):
+ f.write(" const int %s = insn->regno[%d] + HEX_REG_SA0;\n" % \
+ (regN, regno))
+ f.write(" ctx_log_reg_write(ctx, %s, %s);\n" % \
+ (regN, predicated))
+ else:
+ print("Bad register parse: ", regtype, regid)
+ elif (regtype == "M"):
+ if (regid == "u"):
+ f.write("// const int %s = insn->regno[%d];\n"% \
+ (regN, regno))
+ else:
+ print("Bad register parse: ", regtype, regid)
+ elif (regtype == "V"):
+ if (regid in {"dd", "xx"}):
+ f.write("// const int %s = insn->regno[%d];\n" %\
+ (regN, regno))
+ elif (regid in {"uu", "vv"}):
+ f.write("// const int %s = insn->regno[%d];\n" % \
+ (regN, regno))
+ elif (regid in {"s", "u", "v", "w"}):
+ f.write("// const int %s = insn->regno[%d];\n" % \
+ (regN, regno))
+ elif (regid in {"d", "x", "y"}):
+ f.write("// const int %s = insn->regno[%d];\n" % \
+ (regN, regno))
+ else:
+ print("Bad register parse: ", regtype, regid)
+ elif (regtype == "Q"):
+ if (regid in {"d", "e", "x"}):
+ f.write("// const int %s = insn->regno[%d];\n" % \
+ (regN, regno))
+ elif (regid in {"s", "t", "u", "v"}):
+ f.write("// const int %s = insn->regno[%d];\n" % \
+ (regN, regno))
+ else:
+ print("Bad register parse: ", regtype, regid)
+ elif (regtype == "G"):
+ if (regid in {"dd"}):
+ f.write("// const int %s = insn->regno[%d];\n" % \
+ (regN, regno))
+ elif (regid in {"d"}):
+ f.write("// const int %s = insn->regno[%d];\n" % \
+ (regN, regno))
+ elif (regid in {"ss"}):
+ f.write("// const int %s = insn->regno[%d];\n" % \
+ (regN, regno))
+ elif (regid in {"s"}):
+ f.write("// const int %s = insn->regno[%d];\n" % \
+ (regN, regno))
+ else:
+ print("Bad register parse: ", regtype, regid)
+ elif (regtype == "S"):
+ if (regid in {"dd"}):
+ f.write("// const int %s = insn->regno[%d];\n" % \
+ (regN, regno))
+ elif (regid in {"d"}):
+ f.write("// const int %s = insn->regno[%d];\n" % \
+ (regN, regno))
+ elif (regid in {"ss"}):
+ f.write("// const int %s = insn->regno[%d];\n" % \
+ (regN, regno))
+ elif (regid in {"s"}):
+ f.write("// const int %s = insn->regno[%d];\n" % \
+ (regN, regno))
+ else:
+ print("Bad register parse: ", regtype, regid)
+ else:
+ print("Bad register parse: ", regtype, regid)
+
+def analyze_opn_new(f, tag, regtype, regid, regno):
+ regN = "%s%sN" % (regtype, regid)
+ if (regtype == "N"):
+ if (regid in {"s", "t"}):
+ f.write("// const int %s = insn->regno[%d];\n" % \
+ (regN, regno))
+ else:
+ print("Bad register parse: ", regtype, regid)
+ elif (regtype == "P"):
+ if (regid in {"t", "u", "v"}):
+ f.write("// const int %s = insn->regno[%d];\n" % \
+ (regN, regno))
+ else:
+ print("Bad register parse: ", regtype, regid)
+ elif (regtype == "O"):
+ if (regid == "s"):
+ f.write("// const int %s = insn->regno[%d];\n" % \
+ (regN, regno))
+ else:
+ print("Bad register parse: ", regtype, regid)
+ else:
+ print("Bad register parse: ", regtype, regid)
+
+def analyze_opn(f, tag, regtype, regid, toss, numregs, i):
+ if (hex_common.is_pair(regid)):
+ analyze_opn_old(f, tag, regtype, regid, i)
+ elif (hex_common.is_single(regid)):
+ if hex_common.is_old_val(regtype, regid, tag):
+ analyze_opn_old(f,tag, regtype, regid, i)
+ elif hex_common.is_new_val(regtype, regid, tag):
+ analyze_opn_new(f, tag, regtype, regid, i)
+ else:
+ print("Bad register parse: ", regtype, regid, toss, numregs)
+ else:
+ print("Bad register parse: ", regtype, regid, toss, numregs)
+
+##
+## Generate the code to analyze the instruction
+## For A2_add: Rd32=add(Rs32,Rt32), { RdV=RsV+RtV;}
+## We produce:
+## static void analyze_A2_add(DisasContext *ctx)
+## {
+## Insn *insn __attribute__((unused)) = ctx->insn;
+## const int RdN = insn->regno[0];
+## ctx_log_reg_write(ctx, RdN, false);
+## // const int RsN = insn->regno[1];
+## // const int RtN = insn->regno[2];
+## }
+##
+def gen_analyze_func(f, tag, regs, imms):
+ f.write("static void analyze_%s(DisasContext *ctx)\n" %tag)
+ f.write('{\n')
+
+ f.write(" Insn *insn __attribute__((unused)) = ctx->insn;\n")
+
+ i=0
+ ## Analyze all the registers
+ for regtype, regid, toss, numregs in regs:
+ analyze_opn(f, tag, regtype, regid, toss, numregs, i)
+ i += 1
+
+
+ f.write("}\n\n")
+
+def main():
+ hex_common.read_semantics_file(sys.argv[1])
+ hex_common.read_attribs_file(sys.argv[2])
+ hex_common.read_overrides_file(sys.argv[3])
+ hex_common.read_overrides_file(sys.argv[4])
+ hex_common.calculate_attribs()
+ tagregs = hex_common.get_tagregs()
+ tagimms = hex_common.get_tagimms()
+
+ with open(sys.argv[5], 'w') as f:
+ f.write("#ifndef HEXAGON_TCG_FUNCS_H\n")
+ f.write("#define HEXAGON_TCG_FUNCS_H\n\n")
+
+ for tag in hex_common.tags:
+ gen_analyze_func(f, tag, tagregs[tag], tagimms[tag])
+
+ f.write("#endif /* HEXAGON_TCG_FUNCS_H */\n")
+
+if __name__ == "__main__":
+ main()
diff --git a/target/hexagon/gen_tcg_funcs.py b/target/hexagon/gen_tcg_funcs.py
index 7e8ba17ca2..5d686ebcf1 100755
--- a/target/hexagon/gen_tcg_funcs.py
+++ b/target/hexagon/gen_tcg_funcs.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
##
-## Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
+## Copyright(c) 2019-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
@@ -44,15 +44,6 @@ def genptr_decl_pair_writable(f, tag, regtype, regid, regno):
(regN, regno))
else:
f.write(" const int %s = insn->regno[%d];\n" % (regN, regno))
- if ('A_CONDEXEC' in hex_common.attribdict[tag]):
- f.write(" if (!is_preloaded(ctx, %s)) {\n" % regN)
- f.write(" tcg_gen_mov_tl(hex_new_value[%s], hex_gpr[%s]);\n" % \
- (regN, regN))
- f.write(" }\n")
- f.write(" if (!is_preloaded(ctx, %s + 1)) {\n" % regN)
- f.write(" tcg_gen_mov_tl(hex_new_value[%s + 1], hex_gpr[%s + 1]);\n" % \
- (regN, regN))
- f.write(" }\n")
def genptr_decl_writable(f, tag, regtype, regid, regno):
regN="%s%sN" % (regtype,regid)
@@ -63,11 +54,6 @@ def genptr_decl_writable(f, tag, regtype, regid, regno):
(regN, regno))
else:
f.write(" const int %s = insn->regno[%d];\n" % (regN, regno))
- if ('A_CONDEXEC' in hex_common.attribdict[tag]):
- f.write(" if (!is_preloaded(ctx, %s)) {\n" % regN)
- f.write(" tcg_gen_mov_tl(hex_new_value[%s], hex_gpr[%s]);\n" % \
- (regN, regN))
- f.write(" }\n")
def genptr_decl(f, tag, regtype, regid, regno):
regN="%s%sN" % (regtype,regid)
@@ -465,8 +451,6 @@ def genptr_dst_write_pair(f, tag, regtype, regid):
else:
f.write(" gen_log_reg_write_pair(%s%sN, %s%sV);\n" % \
(regtype, regid, regtype, regid))
- f.write(" ctx_log_reg_write_pair(ctx, %s%sN);\n" % \
- (regtype, regid))
def genptr_dst_write(f, tag, regtype, regid):
if (regtype == "R"):
@@ -480,16 +464,12 @@ def genptr_dst_write(f, tag, regtype, regid):
else:
f.write(" gen_log_reg_write(%s%sN, %s%sV);\n" % \
(regtype, regid, regtype, regid))
- f.write(" ctx_log_reg_write(ctx, %s%sN);\n" % \
- (regtype, regid))
else:
print("Bad register parse: ", regtype, regid)
elif (regtype == "P"):
if (regid in {"d", "e", "x"}):
f.write(" gen_log_pred_write(ctx, %s%sN, %s%sV);\n" % \
(regtype, regid, regtype, regid))
- f.write(" ctx_log_pred_write(ctx, %s%sN);\n" % \
- (regtype, regid))
else:
print("Bad register parse: ", regtype, regid)
elif (regtype == "C"):
@@ -581,7 +561,6 @@ def genptr_dst_write_opn(f,regtype, regid, tag):
## TCGv RtV = hex_gpr[insn->regno[2]];
## <GEN>
## gen_log_reg_write(RdN, RdV);
-## ctx_log_reg_write(ctx, RdN);
## tcg_temp_free(RdV);
## }
##
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index c9d31d095c..bd91f727de 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -1,5 +1,5 @@
##
-## Copyright(c) 2020-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
+## Copyright(c) 2020-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
@@ -67,6 +67,15 @@ tcg_func_table_generated = custom_target(
)
hexagon_ss.add(tcg_func_table_generated)
+analyze_funcs_generated = custom_target(
+ 'analyze_funcs_generated.c.inc',
+ output: 'analyze_funcs_generated.c.inc',
+ depends: [semantics_generated],
+ depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h],
+ command: [python, files('gen_analyze_funcs.py'), semantics_generated, attribs_def, gen_tcg_h, gen_tcg_hvx_h, '@OUTPUT@'],
+)
+hexagon_ss.add(analyze_funcs_generated)
+
printinsn_generated = custom_target(
'printinsn_generated.h.inc',
output: 'printinsn_generated.h.inc',
--
2.17.1
© 2016 - 2024 Red Hat, Inc.