Hexagon (target/hexagon) Analyze packet before generating TCG
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> Reviewed-by: Anton Johansson <anjo@rev.ng> Message-Id: <20230307025828.1612809-6-tsimpson@quicinc.com>
This commit is contained in:
parent
dae386b80f
commit
10849c2623
|
@ -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);
|
||||
}
|
||||
|
||||
helper_funcs_generated.c.inc
|
||||
|
@ -160,7 +160,6 @@ istruction.
|
|||
TCGv slot = tcg_constant_tl(insn->slot);
|
||||
gen_helper_V6_vaddw(cpu_env, VdV, VuV, VvV, slot);
|
||||
gen_log_vreg_write(ctx, VdV_off, VdN, EXT_DFL, insn->slot, false);
|
||||
ctx_log_vreg_write(ctx, VdN, EXT_DFL, false);
|
||||
}
|
||||
|
||||
Notice that we also generate a variable named <operand>_off for each operand of
|
||||
|
@ -190,9 +189,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
|
||||
|
|
|
@ -0,0 +1,237 @@
|
|||
#!/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 G_GNUC_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 G_GNUC_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])
|
||||
## Whether or not idef-parser is enabled is
|
||||
## determined by the number of arguments to
|
||||
## this script:
|
||||
##
|
||||
## 5 args. -> not enabled,
|
||||
## 6 args. -> idef-parser enabled.
|
||||
##
|
||||
## The 6:th arg. then holds a list of the successfully
|
||||
## parsed instructions.
|
||||
is_idef_parser_enabled = len(sys.argv) > 6
|
||||
if is_idef_parser_enabled:
|
||||
hex_common.read_idef_parser_enabled_file(sys.argv[5])
|
||||
hex_common.calculate_attribs()
|
||||
tagregs = hex_common.get_tagregs()
|
||||
tagimms = hex_common.get_tagimms()
|
||||
|
||||
with open(sys.argv[-1], '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()
|
|
@ -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
|
||||
|
@ -37,15 +37,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)
|
||||
|
@ -56,11 +47,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)
|
||||
|
@ -391,8 +377,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"):
|
||||
|
@ -406,16 +390,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"):
|
||||
|
@ -507,7 +487,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);
|
||||
## }
|
||||
##
|
||||
## where <GEN> depends on hex_common.skip_qemu_helper(tag)
|
||||
|
|
|
@ -180,6 +180,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);
|
||||
}
|
||||
|
||||
static inline void gen_read_p3_0(TCGv control_reg)
|
||||
|
@ -256,7 +257,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -274,7 +274,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;
|
||||
}
|
||||
|
@ -296,10 +295,8 @@ static inline void gen_write_ctrl_reg_pair(DisasContext *ctx, int reg_num,
|
|||
gen_write_p3_0(ctx, val32);
|
||||
tcg_gen_extrh_i64_i32(val32, val);
|
||||
gen_log_reg_write(reg_num + 1, 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;
|
||||
|
|
|
@ -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
|
||||
|
@ -1320,10 +1320,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");
|
||||
}
|
||||
|
||||
void gen_assign(Context *c,
|
||||
|
@ -1723,7 +1719,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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -276,4 +276,13 @@ tcg_funcs_generated = custom_target(
|
|||
)
|
||||
hexagon_ss.add(tcg_funcs_generated)
|
||||
|
||||
analyze_funcs_generated = custom_target(
|
||||
'analyze_funcs_generated.c.inc',
|
||||
output: 'analyze_funcs_generated.c.inc',
|
||||
depends: helper_dep,
|
||||
depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h],
|
||||
command: [python, files('gen_analyze_funcs.py'), helper_in, '@OUTPUT@'],
|
||||
)
|
||||
hexagon_ss.add(analyze_funcs_generated)
|
||||
|
||||
target_arch += {'hexagon': hexagon_ss}
|
||||
|
|
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -265,6 +274,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;
|
||||
|
@ -275,6 +354,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;
|
||||
|
@ -291,6 +371,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);
|
||||
|
@ -313,6 +401,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);
|
||||
|
@ -336,66 +434,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;
|
||||
|
@ -423,9 +461,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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
if (test_bit(rnum, ctx->regs_written)) {
|
||||
HEX_DEBUG_LOG("WARNING: Multiple writes to r%d\n", rnum);
|
||||
}
|
||||
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)
|
||||
{
|
||||
ctx->preg_log[ctx->preg_log_idx] = pnum;
|
||||
ctx->preg_log_idx++;
|
||||
set_bit(pnum, ctx->pregs_written);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool is_preloaded(DisasContext *ctx, int num)
|
||||
static inline void ctx_log_reg_write(DisasContext *ctx, int rnum,
|
||||
bool is_predicated)
|
||||
{
|
||||
return test_bit(num, ctx->regs_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 void ctx_log_reg_write_pair(DisasContext *ctx, int rnum,
|
||||
bool is_predicated)
|
||||
{
|
||||
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)
|
||||
|
|
Loading…
Reference in New Issue