diff --git a/target/hexagon/gen_decodetree.py b/target/hexagon/gen_decodetree.py
index ce703af41d..3aa2979a1f 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 45da1b7b5d..93125bdfe4 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 a4807bed7b..091c1bf7ef 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