On 9/30/2026 1:19 PM, Marco Liebel wrote:
On Sat, Sep 26, 2026 at 2:23 PM Brian Cain <[email protected]> wrote:
Signed-off-by: Brian Cain <[email protected]>
---
target/hexagon/mmvec/mmvec.h | 55 ++++++++++++++++++++------------
hw/hexagon/hexagon_hvx_context.c | 5 +++
target/hexagon/hex_common.py | 29 +++++++++++++++++
3 files changed, 68 insertions(+), 21 deletions(-)
diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py
index 02c54506145..55b8a40fe8c 100755
--- a/target/hexagon/hex_common.py
+++ b/target/hexagon/hex_common.py
@@ -448,6 +448,25 @@ def helper_arg_type(self):
return "void *"
def helper_arg_name(self):
return f"{self.reg_tcg()}_void"
+ def gen_clear_ext(self, f):
+ f.write(code_fmt(f"""\
+ tcg_gen_gvec_dup_imm_var(MO_8, {self.hvx_base()},
+ {self.hvx_off()} + offsetof(MMVector, ext),
+ MAX_VEC_SIZE_BYTES / 4, MAX_VEC_SIZE_BYTES / 4,
+ V_EXTENDED_BYTEVAL);
+ """))
+ def gen_clear_ext_pair(self, f):
+ f.write(code_fmt(f"""\
+ tcg_gen_gvec_dup_imm_var(MO_8, {self.hvx_base()},
+ {self.hvx_off()} + offsetof(MMVector, ext),
+ MAX_VEC_SIZE_BYTES / 4, MAX_VEC_SIZE_BYTES / 4,
+ V_EXTENDED_BYTEVAL);
+ tcg_gen_gvec_dup_imm_var(MO_8, {self.hvx_base()},
+ {self.hvx_off()} + sizeof(MMVector)
+ + offsetof(MMVector, ext),
+ MAX_VEC_SIZE_BYTES / 4, MAX_VEC_SIZE_BYTES / 4,
+ V_EXTENDED_BYTEVAL);
+ """))
gen_clear_ext() and gen_clear_ext_pair() currently update the
destination vector’s
extension field even when the instruction predicate is false. The following test
demonstrates the issue:
Thanks for the fix and the test! Will address them.
static void test_ext_bits_preserved_on_false_predicate(void)
{
asm volatile(
"r0 = #0x11111111\n"
"v3 = vsplat(r0)\n"
"v0.x = vsetqfext(v3, r0)\n"
"r2 = #1\n"
"v1 = vsplat(r2)\n"
"r1 = #0\n"
"p0 = cmp.eq(r1, r2)\n"
"{\n"
" if (p0) v0 = v1\n"
"}\n"
"v2 = vgetqfext(v0.x, r0)\n"
"vmemu(%[out]) = v2\n"
:
: [out] "r"(output)
: "r0", "r1", "r2", "v0", "v1", "v2", "v3", "p0", "memory");
for (int i = 0; i < MAX_VEC_SIZE_BYTES / 4; i++) {
expect[0].uw[i] = 0x11111111;
}
check_output_w(__LINE__, 1);
}
The extension reset needs to be predicated as well. For example:
def gen_clear_ext(self, f, tag):
predicate = None
guard = ""
if is_predicated(tag):
for regtype, regid in compute_tag_regs(tag, False):
if regtype == "P":
predicate = get_register(tag, regtype, regid).reg_tcg()
break
assert predicate is not None
cond = "TCG_COND_NE" if "fLSBOLDNOT" in semdict[tag] else "TCG_COND_EQ"
guard = f"""
TCGv {self.reg_tcg()}_ext_pred = tcg_temp_new();
TCGLabel *{self.reg_tcg()}_ext_skip = gen_new_label();
tcg_gen_andi_tl({self.reg_tcg()}_ext_pred, {predicate}, 1);
tcg_gen_brcondi_tl({cond}, {self.reg_tcg()}_ext_pred, 0,
{self.reg_tcg()}_ext_skip);
"""
end_guard = f"""
gen_set_label({self.reg_tcg()}_ext_skip);
"""
else:
end_guard = ""
f.write(code_fmt(f"""\
{guard}
tcg_gen_gvec_dup_imm_var(MO_8, {self.hvx_base()},
{self.hvx_off()} + offsetof(MMVector, ext),
MAX_VEC_SIZE_BYTES / 4, MAX_VEC_SIZE_BYTES / 4,
V_EXTENDED_BYTEVAL);
{end_guard}
"""))
def gen_clear_ext_pair(self, f, tag):
predicate = None
guard = ""
if is_predicated(tag):
for regtype, regid in compute_tag_regs(tag, False):
if regtype == "P":
predicate = get_register(tag, regtype, regid).reg_tcg()
break
assert predicate is not None
cond = "TCG_COND_NE" if "fLSBOLDNOT" in semdict[tag] else "TCG_COND_EQ"
guard = f"""
TCGv {self.reg_tcg()}_ext_pred = tcg_temp_new();
TCGLabel *{self.reg_tcg()}_ext_skip = gen_new_label();
tcg_gen_andi_tl({self.reg_tcg()}_ext_pred, {predicate}, 1);
tcg_gen_brcondi_tl({cond}, {self.reg_tcg()}_ext_pred, 0,
{self.reg_tcg()}_ext_skip);
"""
end_guard = f"""
gen_set_label({self.reg_tcg()}_ext_skip);
"""
else:
end_guard = ""
f.write(code_fmt(f"""\
{guard}
tcg_gen_gvec_dup_imm_var(MO_8, {self.hvx_base()},
{self.hvx_off()} + offsetof(MMVector, ext),
MAX_VEC_SIZE_BYTES / 4, MAX_VEC_SIZE_BYTES / 4,
V_EXTENDED_BYTEVAL);
tcg_gen_gvec_dup_imm_var(MO_8, {self.hvx_base()},
{self.hvx_off()} + sizeof(MMVector)
+ offsetof(MMVector, ext),
MAX_VEC_SIZE_BYTES / 4, MAX_VEC_SIZE_BYTES / 4,
V_EXTENDED_BYTEVAL);
{end_guard}
"""))