From: Marco Liebel <[email protected]> Teach the generators about L registers and add support for inline gvec operations.
Signed-off-by: Marco Liebel <[email protected]> Reviewed-by: Brian Cain <[email protected]> Signed-off-by: Brian Cain <[email protected]> --- target/hexagon/gen_decodetree.py | 6 +- target/hexagon/gen_trans_funcs.py | 4 +- target/hexagon/hex_common.py | 606 +++++++++++++++++++++++++++++- 3 files changed, 607 insertions(+), 9 deletions(-) diff --git a/target/hexagon/gen_decodetree.py b/target/hexagon/gen_decodetree.py index ce703af41d4..3aa2979a1f0 100755 --- a/target/hexagon/gen_decodetree.py +++ b/target/hexagon/gen_decodetree.py @@ -33,14 +33,16 @@ } -regre = re.compile(r"((?<!DUP)[MNORCPQXSGVZA])([stuvwxyzdefg]+)([.]?[LlHh]?)(\d+S?)") +regre = re.compile( + r"((?<!DUP)[MNORCPQXSGVZALK])([stuvwxyzdefg]+)([.]?[LlHh]?)(\d+S?)" +) immre = re.compile(r"[#]([rRsSuUm])(\d+)(?:[:](\d+))?") def ordered_unique(l): return sorted(set(l), key=l.index) -num_registers = {"R": 32, "V": 32} +num_registers = {"R": 32, "V": 32, "L": 16} operand_letters = { "P", diff --git a/target/hexagon/gen_trans_funcs.py b/target/hexagon/gen_trans_funcs.py index 45da1b7b5df..93125bdfe48 100755 --- a/target/hexagon/gen_trans_funcs.py +++ b/target/hexagon/gen_trans_funcs.py @@ -33,7 +33,9 @@ } -regre = re.compile(r"((?<!DUP)[MNORCPQXSGVZA])([stuvwxyzdefg]+)([.]?[LlHh]?)(\d+S?)") +regre = re.compile( + r"((?<!DUP)[MNORCPQXSGVZALK])([stuvwxyzdefg]+)([.]?[LlHh]?)(\d+S?)" +) immre = re.compile(r"[#]([rRsSuUm])(\d+)(?:[:](\d+))?") diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index 4749d3e8a88..d64c3fdb310 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -76,10 +76,12 @@ def uniquify(seq): return [x for x in seq if x not in seen and not seen_add(x)] -regre = re.compile(r"((?<!DUP)[MNORCPQXSGVZA])([stuvwxyzdefg]+)([.]?[LlHh]?)(\d+S?)") +regre = re.compile( + r"((?<!DUP)[MNORCPQXSGVZALK])([stuvwxyzdefg]+)([.]?[LlHh]?)(\d+S?)" +) immre = re.compile(r"[#]([rRsSuUm])(\d+)(?:[:](\d+))?") reg_or_immre = re.compile( - r"(((?<!DUP)[MNRCOPQXSGVZA])([stuvwxyzdefg]+)" + r"(((?<!DUP)[MNRCOPQXSGVZALK])([stuvwxyzdefg]+)" r"([.]?[LlHh]?)(\d+S?))|([#]([rRsSuUm])(\d+)[:]?(\d+)?)" ) relimmre = re.compile(r"[#]([rR])(\d+)(?:[:](\d+))?") @@ -305,6 +307,274 @@ def skip_qemu_helper(tag): return tag in overrides.keys() +# HLX instructions that are emitted as inline gvec TCG IR instead of a +# helper call. "size" is the oprsz/maxsz for the gvec calls, one register +# (the default) or a pair. "table" names a descriptor in hlx_gvec_tables.h. +HLX_INLINE_TAGS = { + "LX_add_h": {"op": "add", "vece": "MO_16"}, + "LX_sub_h": {"op": "sub", "vece": "MO_16"}, + "LX_assign": {"op": "mov", "vece": "MO_64"}, + # LX_add_w and LX_sub_w cannot be inlined: the low halfword of each word + # is in the lo register and the high halfword in the hi register, so a + # 32-bit gvec add would lose the carry between them. They use the helper, + # which interleaves the pair first. + "LX_assign_w": {"op": "mov", "vece": "MO_64", + "size": "2 * sizeof(HLXVector)"}, + "LX_combine_w": {"op": "combine_pair", "vece": "MO_64"}, +} + +def is_hlx_inline_tag(tag): + return tag in HLX_INLINE_TAGS + +def gen_hlx_inline(f, tag, regs): + """Emit inline gvec operations, splitting 4096-byte register pairs. + + gvec maxsz is limited to 2048 bytes, so pairs use two calls. + """ + desc = HLX_INLINE_TAGS[tag] + op = desc["op"] + vece = desc["vece"] + sz = desc.get("size", "sizeof(HLXVector)") + pair_dst = (sz == "2 * sizeof(HLXVector)") + single = "sizeof(HLXVector)" + oprsz = single if pair_dst else desc.get("oprsz", sz) + maxsz = single if pair_dst else desc.get("maxsz", sz) + + def reg(i): + regtype, regid, *_ = regs[i] + return f"{regtype}{regid}V" + + if op == "add": + d, a, b = reg(0), reg(1), reg(2) + if pair_dst: + f.write(code_fmt(f"""\ + tcg_gen_gvec_add_var({vece}, + {d}_base, {d}_off, + {a}_base, {a}_off, + {b}_base, {b}_off, + {oprsz}, {maxsz}); + tcg_gen_gvec_add_var({vece}, + {d}_base, {d}_off + sizeof(HLXVector), + {a}_base, {a}_off + sizeof(HLXVector), + {b}_base, {b}_off + sizeof(HLXVector), + {oprsz}, {maxsz}); + """)) + else: + f.write(code_fmt(f"""\ + tcg_gen_gvec_add_var({vece}, + {d}_base, {d}_off, + {a}_base, {a}_off, + {b}_base, {b}_off, + {oprsz}, {maxsz}); + """)) + elif op == "sub": + d, a, b = reg(0), reg(1), reg(2) + if pair_dst: + f.write(code_fmt(f"""\ + tcg_gen_gvec_sub_var({vece}, + {d}_base, {d}_off, + {a}_base, {a}_off, + {b}_base, {b}_off, + {oprsz}, {maxsz}); + tcg_gen_gvec_sub_var({vece}, + {d}_base, {d}_off + sizeof(HLXVector), + {a}_base, {a}_off + sizeof(HLXVector), + {b}_base, {b}_off + sizeof(HLXVector), + {oprsz}, {maxsz}); + """)) + else: + f.write(code_fmt(f"""\ + tcg_gen_gvec_sub_var({vece}, + {d}_base, {d}_off, + {a}_base, {a}_off, + {b}_base, {b}_off, + {oprsz}, {maxsz}); + """)) + elif op == "mov": + d, a = reg(0), reg(1) + if pair_dst: + f.write(code_fmt(f"""\ + tcg_gen_gvec_mov_var({vece}, + {d}_base, {d}_off, + {a}_base, {a}_off, + {oprsz}, {maxsz}); + tcg_gen_gvec_mov_var({vece}, + {d}_base, {d}_off + sizeof(HLXVector), + {a}_base, {a}_off + sizeof(HLXVector), + {oprsz}, {maxsz}); + """)) + else: + f.write(code_fmt(f"""\ + tcg_gen_gvec_mov_var({vece}, + {d}_base, {d}_off, + {a}_base, {a}_off, + {oprsz}, {maxsz}); + """)) + elif op == "dup_imm": + d = reg(0) + imm = desc["imm"] + if pair_dst: + f.write(code_fmt(f"""\ + tcg_gen_gvec_dup_imm_var({vece}, + {d}_base, {d}_off, + {oprsz}, {maxsz}, {imm}); + tcg_gen_gvec_dup_imm_var({vece}, + {d}_base, {d}_off + sizeof(HLXVector), + {oprsz}, {maxsz}, {imm}); + """)) + else: + f.write(code_fmt(f"""\ + tcg_gen_gvec_dup_imm_var({vece}, + {d}_base, {d}_off, + {oprsz}, {maxsz}, {imm}); + """)) + elif op == "gvec3": + d, a, b = reg(0), reg(1), reg(2) + table = desc["table"] + if pair_dst: + f.write(code_fmt(f"""\ + tcg_gen_gvec_3_var({d}_base, {d}_off, + {a}_base, {a}_off, + {b}_base, {b}_off, + {oprsz}, {maxsz}, &{table}); + tcg_gen_gvec_3_var({d}_base, {d}_off + sizeof(HLXVector), + {a}_base, {a}_off + sizeof(HLXVector), + {b}_base, {b}_off + sizeof(HLXVector), + {oprsz}, {maxsz}, &{table}); + """)) + else: + f.write(code_fmt(f"""\ + tcg_gen_gvec_3_var({d}_base, {d}_off, + {a}_base, {a}_off, + {b}_base, {b}_off, + {oprsz}, {maxsz}, &{table}); + """)) + elif op == "gvec3_arr": + # Like gvec3, but table is a GVecGen3[4] indexed by vece. + d, a, b = reg(0), reg(1), reg(2) + table = desc["table"] + if pair_dst: + f.write(code_fmt(f"""\ + tcg_gen_gvec_3_var({d}_base, {d}_off, + {a}_base, {a}_off, + {b}_base, {b}_off, + {oprsz}, {maxsz}, &{table}[{vece}]); + tcg_gen_gvec_3_var({d}_base, {d}_off + sizeof(HLXVector), + {a}_base, {a}_off + sizeof(HLXVector), + {b}_base, {b}_off + sizeof(HLXVector), + {oprsz}, {maxsz}, &{table}[{vece}]); + """)) + else: + f.write(code_fmt(f"""\ + tcg_gen_gvec_3_var({d}_base, {d}_off, + {a}_base, {a}_off, + {b}_base, {b}_off, + {oprsz}, {maxsz}, &{table}[{vece}]); + """)) + elif op == "combine_pair": + dd, u, v = reg(0), reg(1), reg(2) + single = "sizeof(HLXVector)" + f.write(code_fmt(f"""\ + tcg_gen_gvec_mov_var({vece}, + {dd}_base, {dd}_off, + {v}_base, {v}_off, + {single}, {single}); + tcg_gen_gvec_mov_var({vece}, + {dd}_base, + {dd}_off + sizeof(HLXVector), + {u}_base, {u}_off, + {single}, {single}); + """)) + elif op == "gvec2": + # Two-operand op: dest and one source. table is a const GVecGen2. + d, a = reg(0), reg(1) + table = desc["table"] + if pair_dst: + f.write(code_fmt(f"""\ + tcg_gen_gvec_2_var({d}_base, {d}_off, + {a}_base, {a}_off, + {oprsz}, {maxsz}, &{table}); + tcg_gen_gvec_2_var({d}_base, {d}_off + sizeof(HLXVector), + {a}_base, {a}_off + sizeof(HLXVector), + {oprsz}, {maxsz}, &{table}); + """)) + else: + f.write(code_fmt(f"""\ + tcg_gen_gvec_2_var({d}_base, {d}_off, + {a}_base, {a}_off, + {oprsz}, {maxsz}, &{table}); + """)) + elif op == "gvec2_arr": + # Like gvec2, but table is a GVecGen2[4] indexed by vece. + d, a = reg(0), reg(1) + table = desc["table"] + if pair_dst: + f.write(code_fmt(f"""\ + tcg_gen_gvec_2_var({d}_base, {d}_off, + {a}_base, {a}_off, + {oprsz}, {maxsz}, &{table}[{vece}]); + tcg_gen_gvec_2_var({d}_base, {d}_off + sizeof(HLXVector), + {a}_base, {a}_off + sizeof(HLXVector), + {oprsz}, {maxsz}, &{table}[{vece}]); + """)) + else: + f.write(code_fmt(f"""\ + tcg_gen_gvec_2_var({d}_base, {d}_off, + {a}_base, {a}_off, + {oprsz}, {maxsz}, &{table}[{vece}]); + """)) + elif op == "cmp_gt": + # a > b is done as b < a, with the less-than descriptor in "table" + d, a, b = reg(0), reg(1), reg(2) + table = desc["table"] + if pair_dst: + f.write(code_fmt(f"""\ + tcg_gen_gvec_3_var({d}_base, {d}_off, + {b}_base, {b}_off, + {a}_base, {a}_off, + {oprsz}, {maxsz}, &{table}); + tcg_gen_gvec_3_var({d}_base, {d}_off + sizeof(HLXVector), + {b}_base, {b}_off + sizeof(HLXVector), + {a}_base, {a}_off + sizeof(HLXVector), + {oprsz}, {maxsz}, &{table}); + """)) + else: + f.write(code_fmt(f"""\ + tcg_gen_gvec_3_var({d}_base, {d}_off, + {b}_base, {b}_off, + {a}_base, {a}_off, + {oprsz}, {maxsz}, &{table}); + """)) + elif op == "conv_h_to_w_pair": + # lo = the source; hi = zeros (zxt) or the source >> 15 (sxt) + d, a = reg(0), reg(1) + single = "sizeof(HLXVector)" + sign_extend = desc.get("sign_extend", False) + if sign_extend: + table = desc["table"] + f.write(code_fmt(f"""\ + tcg_gen_gvec_mov_var(MO_64, + {d}_base, {d}_off, + {a}_base, {a}_off, + {single}, {single}); + tcg_gen_gvec_2_var({d}_base, {d}_off + sizeof(HLXVector), + {a}_base, {a}_off, + {single}, {single}, &{table}); + """)) + else: + f.write(code_fmt(f"""\ + tcg_gen_gvec_mov_var(MO_64, + {d}_base, {d}_off, + {a}_base, {a}_off, + {single}, {single}); + tcg_gen_gvec_dup_imm_var(MO_64, + {d}_base, {d}_off + sizeof(HLXVector), + {single}, {single}, 0); + """)) + else: + raise Exception(f"unknown HLX inline op {op!r} for tag {tag!r}") + + def is_idef_parser_enabled(tag): return tag in idef_parser_enabled @@ -408,6 +678,8 @@ def is_scalar_reg(self): return True def is_hvx_reg(self): return False + def is_hlx_reg(self): + return False def helper_arg_name(self): return self.reg_tcg() @@ -432,6 +704,8 @@ def is_scalar_reg(self): return False def is_hvx_reg(self): return True + def is_hlx_reg(self): + return False def hvx_off(self): return f"{self.reg_tcg()}_off" def hvx_base(self): @@ -1203,6 +1477,308 @@ def analyze_write(self, f, tag, regno): insn_has_hvx_helper); """)) +# HLX has sixteen 2048-byte L registers. +class Hlx: + def is_scalar_reg(self): + return False + def is_hvx_reg(self): + return False + def is_hlx_reg(self): + return True + def hlx_off(self): + return f"{self.reg_tcg()}_off" + def helper_proto_type(self): + return "ptr" + def helper_arg_type(self): + return "void *" + def helper_arg_name(self): + return f"{self.reg_tcg()}_void" + def decl_reg_num(self, f, regno): + # HLX sources are not logged, so this can be unused. + f.write(code_fmt(f"""\ + const int {self.reg_num} G_GNUC_UNUSED = insn->regno[{regno}]; + """)) + +class LRegDest(Hlx, Register, Single, Dest): + def decl_tcg(self, f, tag, regno): + self.decl_reg_num(f, regno) + if "A_HLX_TMP" in attribdict[tag]: + storage = "tmp_LRegs" + else: + storage = "future_LRegs" + f.write(code_fmt(f"""\ + const intptr_t {self.hlx_off()} = + offsetof(CPUHexagonState, {storage}[{self.reg_num}]); + """)) + if "A_HLX_TMP" in attribdict[tag] and "A_CONDEXEC" in attribdict[tag]: + f.write(code_fmt(f"""\ + gen_helper_hlx_copy_live_to_tmp(tcg_env, + tcg_constant_i32({self.reg_num})); + """)) + if is_hlx_inline_tag(tag): + f.write(code_fmt(f"""\ + TCGv_ptr {self.reg_tcg()}_base = tcg_env; + """)) + elif not skip_qemu_helper(tag): + f.write(code_fmt(f"""\ + TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr(); + tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hlx_off()}); + """)) + def gen_write(self, f, tag): + pass + def helper_hlx_desc(self, f): + desc = f"*(HLXVector *)({self.helper_arg_name()})" + f.write(code_fmt(f"""\ + /* {self.reg_tcg()} is {desc} */ + """)) + def analyze_write(self, f, tag, regno): + if "A_HLX_TMP" in attribdict[tag]: + f.write(code_fmt(f"""\ + ctx_log_lreg_tmp_write(ctx, {self.reg_num}); + """)) + else: + f.write(code_fmt(f"""\ + ctx_log_lreg_write(ctx, {self.reg_num}); + """)) + +class LRegSource(Hlx, Register, Single, OldSource): + def decl_tcg(self, f, tag, regno): + self.decl_reg_num(f, regno) + f.write(code_fmt(f"""\ + TCGv_ptr {self.reg_tcg()}_base; + intptr_t {self.reg_tcg()}_off; + if (test_bit({self.reg_num}, ctx->lregs_updated_tmp)) {{ + {self.reg_tcg()}_base = tcg_env; + {self.reg_tcg()}_off = + offsetof(CPUHexagonState, tmp_LRegs[{self.reg_num}]); + }} else {{ + {self.reg_tcg()}_base = ctx_get_hlx_base(ctx); + {self.reg_tcg()}_off = + offsetof(HexagonHLXContext, LRegs[{self.reg_num}]); + }} + """)) + if not is_hlx_inline_tag(tag): + f.write(code_fmt(f"""\ + TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr(); + tcg_gen_addi_ptr({self.reg_tcg()}, {self.reg_tcg()}_base, + {self.reg_tcg()}_off); + """)) + def helper_hlx_desc(self, f): + desc = f"*(HLXVector *)({self.helper_arg_name()})" + f.write(code_fmt(f"""\ + /* {self.reg_tcg()} is {desc} */ + """)) + def analyze_read(self, f, regno): + pass + +class LRegNewSource(Hlx, Register, Single, NewSource): + def decl_tcg(self, f, tag, regno): + if skip_qemu_helper(tag): + self.decl_reg_num(f, regno) + f.write(code_fmt(f"""\ + const intptr_t {self.hlx_off()} = + offsetof(CPUHexagonState, future_LRegs[{self.reg_num}]); + """)) + else: + # No reg_num variable here, it would clash with the TCGv_ptr + f.write(code_fmt(f"""\ + const intptr_t {self.hlx_off()} = + offsetof(CPUHexagonState, + future_LRegs[insn->regno[{regno}]]); + TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr(); + tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hlx_off()}); + """)) + def helper_hlx_desc(self, f): + desc = f"*(HLXVector *)({self.helper_arg_name()})" + f.write(code_fmt(f"""\ + /* {self.reg_tcg()} is {desc} */ + """)) + def analyze_read(self, f, regno): + pass + +class LRegReadWrite(Hlx, Register, Single, ReadWrite): + def decl_tcg(self, f, tag, regno): + self.decl_reg_num(f, regno) + f.write(code_fmt(f"""\ + const intptr_t {self.hlx_off()} = + offsetof(CPUHexagonState, future_LRegs[{self.reg_num}]); + if (test_bit({self.reg_num}, ctx->lregs_updated_tmp)) {{ + tcg_gen_gvec_mov(MO_64, {self.hlx_off()}, + offsetof(CPUHexagonState, + tmp_LRegs[{self.reg_num}]), + sizeof(HLXVector), sizeof(HLXVector)); + }} else {{ + gen_helper_hlx_copy_live_to_future(tcg_env, + tcg_constant_i32({self.reg_num})); + }} + """)) + if not skip_qemu_helper(tag): + f.write(code_fmt(f"""\ + TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr(); + tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hlx_off()}); + """)) + def gen_write(self, f, tag): + pass + def helper_hlx_desc(self, f): + desc = f"*(HLXVector *)({self.helper_arg_name()})" + f.write(code_fmt(f"""\ + /* {self.reg_tcg()} is {desc} */ + """)) + def analyze_read(self, f, regno): + pass + def analyze_write(self, f, tag, regno): + f.write(code_fmt(f"""\ + ctx_log_lreg_write(ctx, {self.reg_num}); + """)) + +class LRegTmp(Hlx, Register, Single, ReadWrite): + def decl_tcg(self, f, tag, regno): + self.decl_reg_num(f, regno) + f.write(code_fmt(f"""\ + const intptr_t {self.hlx_off()} = + offsetof(CPUHexagonState, tmp_LRegs[{self.reg_num}]); + """)) + if is_hlx_inline_tag(tag): + f.write(code_fmt(f"""\ + TCGv_ptr {self.reg_tcg()}_base = tcg_env; + """)) + elif not skip_qemu_helper(tag): + f.write(code_fmt(f"""\ + TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr(); + tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hlx_off()}); + """)) + def gen_write(self, f, tag): + pass + def helper_hlx_desc(self, f): + desc = f"*(HLXVector *)({self.helper_arg_name()})" + f.write(code_fmt(f"""\ + /* {self.reg_tcg()} is {desc} */ + """)) + def analyze_read(self, f, regno): + pass + def analyze_write(self, f, tag, regno): + f.write(code_fmt(f"""\ + ctx_log_lreg_tmp_write(ctx, {self.reg_num}); + """)) + +# Pair classes expose base and offset for inline tags. +class LRegPairDest(Hlx, Register, Pair, Dest): + def decl_tcg(self, f, tag, regno): + self.decl_reg_num(f, regno) + f.write(code_fmt(f"""\ + const intptr_t {self.hlx_off()} = + offsetof(CPUHexagonState, future_LRegs[{self.reg_num}]); + """)) + if is_hlx_inline_tag(tag): + f.write(code_fmt(f"""\ + TCGv_ptr {self.reg_tcg()}_base = tcg_env; + """)) + elif not skip_qemu_helper(tag): + f.write(code_fmt(f"""\ + TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr(); + tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hlx_off()}); + """)) + def gen_write(self, f, tag): + pass + def helper_hlx_desc(self, f): + f.write(code_fmt(f"""\ + /* + * {self.reg_tcg()} is + * *(HLXVectorPair *)({self.helper_arg_name()}) + */ + """)) + def analyze_write(self, f, tag, regno): + f.write(code_fmt(f"""\ + ctx_log_lreg_write_pair(ctx, {self.reg_num}); + """)) + +class LRegPairSource(Hlx, Register, Pair, OldSource): + def decl_tcg(self, f, tag, regno): + self.decl_reg_num(f, regno) + f.write(code_fmt(f"""\ + TCGv_ptr {self.reg_tcg()}_base; + intptr_t {self.reg_tcg()}_off; + if (test_bit({self.reg_num}, ctx->lregs_updated_tmp) || + test_bit({self.reg_num} + 1, ctx->lregs_updated_tmp)) {{ + /* A pair is contiguous, so load any missing .tmp half. */ + if (!test_bit({self.reg_num}, ctx->lregs_updated_tmp)) {{ + gen_helper_hlx_copy_live_to_tmp(tcg_env, + tcg_constant_i32({self.reg_num})); + }} + if (!test_bit({self.reg_num} + 1, ctx->lregs_updated_tmp)) {{ + gen_helper_hlx_copy_live_to_tmp(tcg_env, + tcg_constant_i32({self.reg_num} + 1)); + }} + {self.reg_tcg()}_base = tcg_env; + {self.reg_tcg()}_off = + offsetof(CPUHexagonState, tmp_LRegs[{self.reg_num}]); + }} else {{ + {self.reg_tcg()}_base = ctx_get_hlx_base(ctx); + {self.reg_tcg()}_off = + offsetof(HexagonHLXContext, LRegs[{self.reg_num}]); + }} + """)) + if not is_hlx_inline_tag(tag): + f.write(code_fmt(f"""\ + TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr(); + tcg_gen_addi_ptr({self.reg_tcg()}, {self.reg_tcg()}_base, + {self.reg_tcg()}_off); + """)) + def helper_hlx_desc(self, f): + f.write(code_fmt(f"""\ + /* + * {self.reg_tcg()} is + * *(HLXVectorPair *)({self.helper_arg_name()}) + */ + """)) + def analyze_read(self, f, regno): + pass + +class LRegPairReadWrite(Hlx, Register, Pair, ReadWrite): + def decl_tcg(self, f, tag, regno): + self.decl_reg_num(f, regno) + f.write(code_fmt(f"""\ + const intptr_t {self.hlx_off()} = + offsetof(CPUHexagonState, future_LRegs[{self.reg_num}]); + /* Use the .tmp value for each updated half. */ + for (int i = 0; i < 2; i++) {{ + if (test_bit({self.reg_num} + i, ctx->lregs_updated_tmp)) {{ + tcg_gen_gvec_mov(MO_64, + {self.hlx_off()} + i * sizeof(HLXVector), + offsetof(CPUHexagonState, + tmp_LRegs[{self.reg_num} + i]), + sizeof(HLXVector), sizeof(HLXVector)); + }} else {{ + gen_helper_hlx_copy_live_to_future(tcg_env, + tcg_constant_i32({self.reg_num} + i)); + }} + }} + """)) + if is_hlx_inline_tag(tag): + f.write(code_fmt(f"""\ + TCGv_ptr {self.reg_tcg()}_base = tcg_env; + """)) + elif not skip_qemu_helper(tag): + f.write(code_fmt(f"""\ + TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr(); + tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hlx_off()}); + """)) + def gen_write(self, f, tag): + pass + def helper_hlx_desc(self, f): + f.write(code_fmt(f"""\ + /* + * {self.reg_tcg()} is + * *(HLXVectorPair *)({self.helper_arg_name()}) + */ + """)) + def analyze_read(self, f, regno): + pass + def analyze_write(self, f, tag, regno): + f.write(code_fmt(f"""\ + ctx_log_lreg_write_pair(ctx, {self.reg_num}); + """)) + class GuestRegister(Register): def gen_check_impl(self, f, regno): if self.is_written(): @@ -1385,6 +1961,20 @@ def init_registers(): QRegSource("Q", "v"), QRegReadWrite("Q", "x"), + # HLX regs + LRegDest("L", "d"), + LRegSource("L", "s"), + LRegSource("L", "u"), + LRegSource("L", "v"), + LRegSource("L", "w"), + LRegReadWrite("L", "x"), + LRegTmp("L", "y"), + LRegPairDest("L", "dd"), + LRegPairSource("L", "uu"), + LRegPairSource("L", "vv"), + LRegPairSource("L", "ss"), + LRegPairReadWrite("L", "xx"), + # system regs GuestDest("G", "d"), GuestSource("G", "s"), @@ -1405,12 +1995,13 @@ def init_registers(): PredNewSource("P", "u"), PredNewSource("P", "v"), VRegNewSource("O", "s"), + LRegNewSource("K", "u"), } for reg in new_regs: new_registers[f"{reg.regtype}{reg.regid}"] = reg def is_new_reg(tag, regid): - if regid[0] in "NO": + if regid[0] in "NOK": return True return regid[0] == "P" and \ f"{regid}N" in semdict[tag] and \ @@ -1457,19 +2048,22 @@ def helper_args(tag, regs, imms): if is_predicated(tag): for regtype, regid in regs: reg = get_register(tag, regtype, regid) - if reg.is_writeonly() and not reg.is_hvx_reg(): + is_vector = reg.is_hvx_reg() or reg.is_hlx_reg() + if reg.is_writeonly() and not is_vector: args.append(reg.helper_arg()) ## Pass the HVX destination registers for regtype, regid in regs: reg = get_register(tag, regtype, regid) - if reg.is_written() and reg.is_hvx_reg(): + if reg.is_written() and (reg.is_hvx_reg() or reg.is_hlx_reg()): args.append(reg.helper_arg()) ## Pass the source registers for regtype, regid in regs: reg = get_register(tag, regtype, regid) - if reg.is_read() and not (reg.is_hvx_reg() and reg.is_readwrite()): + is_vector_readwrite = ((reg.is_hvx_reg() or reg.is_hlx_reg()) and + reg.is_readwrite()) + if reg.is_read() and not is_vector_readwrite: args.append(reg.helper_arg()) ## Pass the immediates -- 2.34.1
