Commit 13d43bdcb6 for qemu.org

commit 13d43bdcb6fb14d4f1ad43d6cc98f19688395a33
Author: Brian Cain <brian.cain@oss.qualcomm.com>
Date:   Wed Oct 7 17:37:01 2026 -0700

    target/hexagon: Allow temporary HVX write and future write

    HVX packets with Vx.tmp/Vx reg writes were incorrectly rejected.

    Cc: Taylor Simpson <ltaylorsimpson@gmail.com>
    Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
    Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
    Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>

diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py
index 02c5450614..d344284e8a 100755
--- a/target/hexagon/hex_common.py
+++ b/target/hexagon/hex_common.py
@@ -1069,8 +1069,10 @@ def helper_hvx_desc(self, f):
             /* {self.reg_tcg()} is *(MMQReg *)({self.helper_arg_name()}) */
         """))
     def analyze_write(self, f, tag, regno):
+        predicated = "true" if is_predicated(tag) else "false"
         f.write(code_fmt(f"""\
-            ctx_log_qreg_write(ctx, {self.reg_num}, insn_has_hvx_helper);
+            ctx_log_qreg_write(ctx, {self.reg_num}, {predicated},
+                               insn_has_hvx_helper);
         """))

 class QRegSource(Register, Hvx, OldSource):
@@ -1117,8 +1119,10 @@ def analyze_read(self, f, regno):
             ctx_log_qreg_read(ctx, {self.reg_num}, insn_has_hvx_helper);
         """))
     def analyze_write(self, f, tag, regno):
+        predicated = "true" if is_predicated(tag) else "false"
         f.write(code_fmt(f"""\
-            ctx_log_qreg_write(ctx, {self.reg_num}, insn_has_hvx_helper);
+            ctx_log_qreg_write(ctx, {self.reg_num}, {predicated},
+                               insn_has_hvx_helper);
         """))

 class GuestRegister(Register):
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index 1b7427f748..6715758bfa 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -608,6 +608,7 @@ static void clear_pkt_ctx(DisasContext *ctx)
     bitmap_zero(ctx->predicated_tmp_vregs, NUM_VREGS);
     bitmap_zero(ctx->qregs_written, NUM_QREGS);
     bitmap_zero(ctx->qregs_multi_write, NUM_QREGS);
+    bitmap_zero(ctx->qregs_uncond, NUM_QREGS);
     ctx->qreg_log_idx = 0;
     for (i = 0; i < STORES_MAX; i++) {
         ctx->store_width[i] = 0;
@@ -625,7 +626,6 @@ static void clear_pkt_ctx(DisasContext *ctx)
 static bool pkt_has_write_conflict(DisasContext *ctx)
 {
     DECLARE_BITMAP(gpr_conflict, TOTAL_PER_THREAD_REGS);
-    DECLARE_BITMAP(vregs_conflict, NUM_VREGS);

     bitmap_and(gpr_conflict, ctx->gpr_multi_write, ctx->gpr_uncond,
                TOTAL_PER_THREAD_REGS);
@@ -633,16 +633,6 @@ static bool pkt_has_write_conflict(DisasContext *ctx)
         return true;
     }

-    bitmap_and(vregs_conflict, ctx->vregs_multi_write, ctx->vregs_uncond,
-               NUM_VREGS);
-    if (!bitmap_empty(vregs_conflict, NUM_VREGS)) {
-        return true;
-    }
-
-    if (!bitmap_empty(ctx->qregs_multi_write, NUM_QREGS)) {
-        return true;
-    }
-
 #ifndef CONFIG_USER_ONLY
     if (!bitmap_empty(ctx->gregs_multi_write, NUM_GREGS)) {
         return true;
@@ -656,6 +646,19 @@ static bool pkt_has_write_conflict(DisasContext *ctx)
     return false;
 }

+static bool pkt_has_hvx_write_conflict(DisasContext *ctx)
+{
+    DECLARE_BITMAP(vregs_conflict, NUM_VREGS);
+    DECLARE_BITMAP(qregs_conflict, NUM_QREGS);
+
+    bitmap_and(vregs_conflict, ctx->vregs_multi_write, ctx->vregs_uncond,
+               NUM_VREGS);
+    bitmap_and(qregs_conflict, ctx->qregs_multi_write, ctx->qregs_uncond,
+               NUM_QREGS);
+    return !bitmap_empty(vregs_conflict, NUM_VREGS) ||
+           !bitmap_empty(qregs_conflict, NUM_QREGS);
+}
+
 static void analyze_packet(DisasContext *ctx)
 {
     ctx->read_after_write = false;
@@ -1277,6 +1280,12 @@ static void decode_and_translate_packet(CPUHexagonState *env, DisasContext *ctx)
         clear_pkt_ctx(ctx);
         analyze_packet(ctx);

+        if (pkt_has_hvx_write_conflict(ctx)) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "multiple HVX register writes at PC 0x" TARGET_FMT_lx
+                          "\n", ctx->pkt.pc);
+        }
+
         if (pkt_has_write_conflict(ctx)) {
             gen_exception_decode_fail(ctx, words_read,
                                       HEX_CAUSE_REG_WRITE_CONFLICT);
diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h
index 3fb3b550c9..2d1ed5208b 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -81,6 +81,7 @@ typedef struct DisasContext {
     int qreg_log_idx;
     DECLARE_BITMAP(qregs_written, NUM_QREGS);
     DECLARE_BITMAP(qregs_multi_write, NUM_QREGS);
+    DECLARE_BITMAP(qregs_uncond, NUM_QREGS);
     DECLARE_BITMAP(insn_qregs_written, NUM_QREGS);
     DECLARE_BITMAP(insn_qregs_read, NUM_QREGS);
     bool pre_commit;
@@ -236,12 +237,13 @@ static inline void ctx_log_vreg_write(DisasContext *ctx,
             ctx->has_hvx_overlap = true;
         }
     }
-    if (!test_bit(rnum, ctx->vregs_written)) {
-        set_bit(rnum, ctx->vregs_written);
-    } else {
-        set_bit(rnum, ctx->vregs_multi_write);
-    }
+
     if (type != EXT_TMP) {
+        if (!test_bit(rnum, ctx->vregs_written)) {
+            set_bit(rnum, ctx->vregs_written);
+        } else {
+            set_bit(rnum, ctx->vregs_multi_write);
+        }
         if (!test_bit(rnum, ctx->vregs_updated)) {
             ctx->vreg_log[ctx->vreg_log_idx] = rnum;
             ctx->vreg_log_idx++;
@@ -262,8 +264,6 @@ static inline void ctx_log_vreg_write(DisasContext *ctx,
         set_bit(rnum, ctx->vregs_updated_tmp);
         if (is_predicated) {
             set_bit(rnum, ctx->predicated_tmp_vregs);
-        } else {
-            set_bit(rnum, ctx->vregs_uncond);
         }
     }
 }
@@ -316,7 +316,8 @@ static inline void ctx_log_vreg_read_pair(DisasContext *ctx, int rnum,
 }

 static inline void ctx_log_qreg_write(DisasContext *ctx,
-                                      int rnum, bool has_helper)
+                                       int rnum, bool predicated,
+                                       bool has_helper)
 {
     if (has_helper) {
         set_bit(rnum, ctx->insn_qregs_written);
@@ -329,6 +330,9 @@ static inline void ctx_log_qreg_write(DisasContext *ctx,
     } else {
         set_bit(rnum, ctx->qregs_multi_write);
     }
+    if (!predicated) {
+        set_bit(rnum, ctx->qregs_uncond);
+    }
     ctx->qreg_log[ctx->qreg_log_idx] = rnum;
     ctx->qreg_log_idx++;
 }