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}
         """))

Reply via email to