Skip to content

Commit

Permalink
Hexagon (target/hexagon) Analyze packet before generating TCG
Browse files Browse the repository at this point in the history
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 written.  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>
  • Loading branch information
taylorsimpson committed Jan 10, 2023
1 parent da49112 commit 3340e9a
Show file tree
Hide file tree
Showing 8 changed files with 437 additions and 107 deletions.
11 changes: 8 additions & 3 deletions target/hexagon/README
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ header files in <BUILD_DIR>/target/hexagon
gen_tcg_funcs.py -> tcg_funcs_generated.c.inc
gen_tcg_func_table.py -> tcg_func_table_generated.c.inc
gen_helper_funcs.py -> helper_funcs_generated.c.inc
gen_analyze_funcs.py -> analyze_funcs_generated.c.inc
gen_analyze_func_table.py -> analyze_func_table.c.inc

Qemu helper functions have 3 parts
DEF_HELPER declaration indicates the signature of the helper
Expand Down Expand Up @@ -82,7 +84,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);
}

Expand Down Expand Up @@ -156,7 +157,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);
ctx_log_vreg_write(ctx, VdN, EXT_DFL);
tcg_temp_free_ptr(VdV);
tcg_temp_free_ptr(VuV);
tcg_temp_free_ptr(VvV);
Expand Down Expand Up @@ -189,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);
ctx_log_vreg_write(ctx, VdN, EXT_DFL);
}

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
Expand Down
52 changes: 52 additions & 0 deletions target/hexagon/gen_analyze_func_table.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/usr/bin/env python3

##
## Copyright(c) 2022 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

def main():
hex_common.read_semantics_file(sys.argv[1])
hex_common.read_attribs_file(sys.argv[2])
hex_common.calculate_attribs()
tagregs = hex_common.get_tagregs()
tagimms = hex_common.get_tagimms()

with open(sys.argv[3], 'w') as f:
f.write("#ifndef HEXAGON_ANALYZE_TABLE_H\n")
f.write("#define HEXAGON_ANALYZE_TABLE_H\n\n")

f.write("static const AnalyzeInsn opcode_analyze[XX_LAST_OPCODE] = {\n")
for tag in hex_common.tags:
## Skip the diag instructions
if ( tag == "Y6_diag" ) :
continue
if ( tag == "Y6_diag0" ) :
continue
if ( tag == "Y6_diag1" ) :
continue

f.write(" [%s] = analyze_%s,\n" % (tag, tag))
f.write("};\n\n")

f.write("#endif /* HEXAGON_ANALYZE_TABLE_H */\n")

if __name__ == "__main__":
main()
239 changes: 239 additions & 0 deletions target/hexagon/gen_analyze_funcs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
#!/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 gen_def_analyze_func(f, tag, tagregs, tagimms):
regs = tagregs[tag]
imms = tagimms[tag]

gen_analyze_func(f, tag, regs, imms)

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:
## Skip the diag instructions
if ( tag == "Y6_diag" ) :
continue
if ( tag == "Y6_diag0" ) :
continue
if ( tag == "Y6_diag1" ) :
continue

gen_def_analyze_func(f, tag, tagregs, tagimms)

f.write("#endif /* HEXAGON_TCG_FUNCS_H */\n")

if __name__ == "__main__":
main()
20 changes: 0 additions & 20 deletions target/hexagon/gen_tcg_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,6 @@ def genptr_decl_pair_writable(f, tag, regtype, regid, 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")
f.write(" tcg_gen_concat_i32_i64(%s%sV, hex_new_value[%s], " % \
(regtype, regid, regN))
f.write("hex_new_value[%s + 1]);\n" % (regN))
Expand All @@ -70,11 +62,6 @@ def genptr_decl_writable(f, tag, regtype, regid, regno):
else:
f.write(" TCGv %s%sV = tcg_temp_local_new();\n" % \
(regtype, regid))
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)
Expand Down Expand Up @@ -615,8 +602,6 @@ def gen_helper_free_imm(f,immlett):
def genptr_dst_write_pair(f, tag, regtype, regid):
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"):
Expand All @@ -625,16 +610,12 @@ def genptr_dst_write(f, tag, regtype, regid):
elif (regid in {"d", "e", "x", "y"}):
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"):
Expand Down Expand Up @@ -733,7 +714,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);
## }
##
Expand Down
Loading

0 comments on commit 3340e9a

Please sign in to comment.