public inbox for qemu-devel@nongnu.org
 help / color / mirror / Atom feed
* [PULL 0/3] hex queue
@ 2026-03-20 14:50 Brian Cain
  2026-03-20 14:50 ` [PULL 1/3] target/hexagon: fix J2_jumptnew/pt predicate check to use LSB Brian Cain
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Brian Cain @ 2026-03-20 14:50 UTC (permalink / raw)
  To: qemu-devel, peter.maydell; +Cc: brian.cain

The following changes since commit 8e711856d7639cbffa51405f2cc2366e3d9e3a23:

  Merge tag 'hppa-fixes-for-v11-pull-request' of https://github.com/hdeller/qemu-hppa into staging (2026-03-20 10:04:48 +0000)

are available in the Git repository at:

  https://github.com/quic/qemu tags/pull-hex-20260320

for you to fetch changes up to 1adf67b3c445f4060900440ea210e7a1e03042f5:

  tests/tcg/hexagon: add test for predicated .new branch LSB evaluation (2026-03-20 07:43:03 -0700)

----------------------------------------------------------------
Fix for J2_jumptnew{,pt} pred-reg misbehavior

----------------------------------------------------------------
Brian Cain (3):
      target/hexagon: fix J2_jumptnew/pt predicate check to use LSB
      target/hexagon: use TCG_COND_TSTEQ/TSTNE for predicate branches
      tests/tcg/hexagon: add test for predicated .new branch LSB evaluation

 target/hexagon/gen_tcg.h                 |  94 ++++-----
 target/hexagon/genptr.c                  |  32 ++-
 target/hexagon/translate.c               |   2 +-
 tests/tcg/hexagon/test_pnew_jump_loads.c | 341 +++++++++++++++++++++++++++++++
 tests/tcg/hexagon/Makefile.target        |   3 +
 5 files changed, 394 insertions(+), 78 deletions(-)
 create mode 100644 tests/tcg/hexagon/test_pnew_jump_loads.c

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PULL 1/3] target/hexagon: fix J2_jumptnew/pt predicate check to use LSB
  2026-03-20 14:50 [PULL 0/3] hex queue Brian Cain
@ 2026-03-20 14:50 ` Brian Cain
  2026-03-20 14:50 ` [PULL 2/3] target/hexagon: use TCG_COND_TSTEQ/TSTNE for predicate branches Brian Cain
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Brian Cain @ 2026-03-20 14:50 UTC (permalink / raw)
  To: qemu-devel, peter.maydell; +Cc: brian.cain, Alexey Karyakin, Taylor Simpson

J2_jumptnew and J2_jumptnewpt passed the raw predicate value to
gen_cond_jump(), checking if the full 8-bit value was non-zero.
Refer to PRM Section 6.1.2 "predicate-consuming instructions examine
only the least-significant bit".

This inconsistency caused if (p0.new) jumps and if (p0.new) loads
within the same packet to disagree when the predicate had values
other than the ones generated by predicate-generating instructions
(e.g. 0x80 or 0xAA where bit 0 is clear but the value is
non-zero): the jump would be taken while the loads were skipped.

Fix by routing both macros through fGEN_TCG_cond_jumpt(fLSBNEW(PuN)),
matching the pattern used by every other predicated jump.

Discovered-by: Alexey Karyakin <akaryaki@qti.qualcomm.com>
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/gen_tcg.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/hexagon/gen_tcg.h b/target/hexagon/gen_tcg.h
index 7b96dab9185..45ccd518883 100644
--- a/target/hexagon/gen_tcg.h
+++ b/target/hexagon/gen_tcg.h
@@ -951,9 +951,9 @@
 #define fGEN_TCG_J2_jumpfpt(SHORTCODE) \
     fGEN_TCG_cond_jumpf(fLSBOLD(PuV))
 #define fGEN_TCG_J2_jumptnew(SHORTCODE) \
-    gen_cond_jump(ctx, TCG_COND_EQ, PuN, riV)
+    fGEN_TCG_cond_jumpt(fLSBNEW(PuN))
 #define fGEN_TCG_J2_jumptnewpt(SHORTCODE) \
-    gen_cond_jump(ctx, TCG_COND_EQ, PuN, riV)
+    fGEN_TCG_cond_jumpt(fLSBNEW(PuN))
 #define fGEN_TCG_J2_jumpfnewpt(SHORTCODE) \
     fGEN_TCG_cond_jumpf(fLSBNEW(PuN))
 #define fGEN_TCG_J2_jumpfnew(SHORTCODE) \
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PULL 2/3] target/hexagon: use TCG_COND_TSTEQ/TSTNE for predicate branches
  2026-03-20 14:50 [PULL 0/3] hex queue Brian Cain
  2026-03-20 14:50 ` [PULL 1/3] target/hexagon: fix J2_jumptnew/pt predicate check to use LSB Brian Cain
@ 2026-03-20 14:50 ` Brian Cain
  2026-03-20 14:50 ` [PULL 3/3] tests/tcg/hexagon: add test for predicated .new branch LSB evaluation Brian Cain
  2026-03-23 12:42 ` [PULL 0/3] hex queue Peter Maydell
  3 siblings, 0 replies; 5+ messages in thread
From: Brian Cain @ 2026-03-20 14:50 UTC (permalink / raw)
  To: qemu-devel, peter.maydell; +Cc: brian.cain, Taylor Simpson

Replace TCG_COND_EQ/NE comparisons against 0 with TCG_COND_TSTEQ/TSTNE
comparisons against 1 for all predicate-conditional branches. This tests
bit 0 of the predicate register directly, eliminating redundant andi
operations that previously extracted the LSB before the comparison.

For predicate-conditional jumps (jumpt, jumpf, jumptnew, etc.) and
jump-register variants (jumprt, jumprf, etc.), pass the raw predicate
value directly instead of going through fLSBOLD/fLSBNEW extraction.
For callers that produce a 0/1 result via setcond (compare-and-jump,
jumprz, etc.), the TSTEQ/TSTNE test on bit 0 is equivalent to the
previous EQ/NE test against 0.

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/gen_tcg.h   | 94 +++++++++++++++-----------------------
 target/hexagon/genptr.c    | 32 +++++--------
 target/hexagon/translate.c |  2 +-
 3 files changed, 50 insertions(+), 78 deletions(-)

diff --git a/target/hexagon/gen_tcg.h b/target/hexagon/gen_tcg.h
index 45ccd518883..1e0cc3b29a8 100644
--- a/target/hexagon/gen_tcg.h
+++ b/target/hexagon/gen_tcg.h
@@ -696,13 +696,13 @@
     gen_callr(ctx, RsV)
 
 #define fGEN_TCG_J2_callt(SHORTCODE) \
-    gen_cond_call(ctx, PuV, TCG_COND_EQ, riV)
+    gen_cond_call(ctx, PuV, TCG_COND_TSTEQ, riV)
 #define fGEN_TCG_J2_callf(SHORTCODE) \
-    gen_cond_call(ctx, PuV, TCG_COND_NE, riV)
+    gen_cond_call(ctx, PuV, TCG_COND_TSTNE, riV)
 #define fGEN_TCG_J2_callrt(SHORTCODE) \
-    gen_cond_callr(ctx, TCG_COND_EQ, PuV, RsV)
+    gen_cond_callr(ctx, TCG_COND_TSTEQ, PuV, RsV)
 #define fGEN_TCG_J2_callrf(SHORTCODE) \
-    gen_cond_callr(ctx, TCG_COND_NE, PuV, RsV)
+    gen_cond_callr(ctx, TCG_COND_TSTNE, PuV, RsV)
 
 #define fGEN_TCG_J2_loop0r(SHORTCODE) \
     gen_loop0r(ctx, RsV, riV)
@@ -893,21 +893,21 @@
     gen_cmpnd_cmp_n1_jmp_f(ctx, 1, TCG_COND_GT, RsV, riV)
 
 #define fGEN_TCG_J4_tstbit0_tp0_jump_nt(SHORTCODE) \
-    gen_cmpnd_tstbit0_jmp(ctx, 0, RsV, TCG_COND_EQ, riV)
+    gen_cmpnd_tstbit0_jmp(ctx, 0, RsV, TCG_COND_TSTEQ, riV)
 #define fGEN_TCG_J4_tstbit0_tp0_jump_t(SHORTCODE) \
-    gen_cmpnd_tstbit0_jmp(ctx, 0, RsV, TCG_COND_EQ, riV)
+    gen_cmpnd_tstbit0_jmp(ctx, 0, RsV, TCG_COND_TSTEQ, riV)
 #define fGEN_TCG_J4_tstbit0_fp0_jump_nt(SHORTCODE) \
-    gen_cmpnd_tstbit0_jmp(ctx, 0, RsV, TCG_COND_NE, riV)
+    gen_cmpnd_tstbit0_jmp(ctx, 0, RsV, TCG_COND_TSTNE, riV)
 #define fGEN_TCG_J4_tstbit0_fp0_jump_t(SHORTCODE) \
-    gen_cmpnd_tstbit0_jmp(ctx, 0, RsV, TCG_COND_NE, riV)
+    gen_cmpnd_tstbit0_jmp(ctx, 0, RsV, TCG_COND_TSTNE, riV)
 #define fGEN_TCG_J4_tstbit0_tp1_jump_nt(SHORTCODE) \
-    gen_cmpnd_tstbit0_jmp(ctx, 1, RsV, TCG_COND_EQ, riV)
+    gen_cmpnd_tstbit0_jmp(ctx, 1, RsV, TCG_COND_TSTEQ, riV)
 #define fGEN_TCG_J4_tstbit0_tp1_jump_t(SHORTCODE) \
-    gen_cmpnd_tstbit0_jmp(ctx, 1, RsV, TCG_COND_EQ, riV)
+    gen_cmpnd_tstbit0_jmp(ctx, 1, RsV, TCG_COND_TSTEQ, riV)
 #define fGEN_TCG_J4_tstbit0_fp1_jump_nt(SHORTCODE) \
-    gen_cmpnd_tstbit0_jmp(ctx, 1, RsV, TCG_COND_NE, riV)
+    gen_cmpnd_tstbit0_jmp(ctx, 1, RsV, TCG_COND_TSTNE, riV)
 #define fGEN_TCG_J4_tstbit0_fp1_jump_t(SHORTCODE) \
-    gen_cmpnd_tstbit0_jmp(ctx, 1, RsV, TCG_COND_NE, riV)
+    gen_cmpnd_tstbit0_jmp(ctx, 1, RsV, TCG_COND_TSTNE, riV)
 
 /* p0 = cmp.eq(r0, #7) */
 #define fGEN_TCG_SA1_cmpeqi(SHORTCODE) \
@@ -933,31 +933,24 @@
     do { \
         TCGv LSB = tcg_temp_new(); \
         COND; \
-        gen_cond_jump(ctx, TCG_COND_EQ, LSB, riV); \
+        gen_cond_jump(ctx, TCG_COND_TSTEQ, LSB, riV); \
     } while (0)
-#define fGEN_TCG_cond_jumpf(COND) \
-    do { \
-        TCGv LSB = tcg_temp_new(); \
-        COND; \
-        gen_cond_jump(ctx, TCG_COND_NE, LSB, riV); \
-    } while (0)
-
 #define fGEN_TCG_J2_jumpt(SHORTCODE) \
-    fGEN_TCG_cond_jumpt(fLSBOLD(PuV))
+    gen_cond_jump(ctx, TCG_COND_TSTEQ, PuV, riV)
 #define fGEN_TCG_J2_jumptpt(SHORTCODE) \
-    fGEN_TCG_cond_jumpt(fLSBOLD(PuV))
+    gen_cond_jump(ctx, TCG_COND_TSTEQ, PuV, riV)
 #define fGEN_TCG_J2_jumpf(SHORTCODE) \
-    fGEN_TCG_cond_jumpf(fLSBOLD(PuV))
+    gen_cond_jump(ctx, TCG_COND_TSTNE, PuV, riV)
 #define fGEN_TCG_J2_jumpfpt(SHORTCODE) \
-    fGEN_TCG_cond_jumpf(fLSBOLD(PuV))
+    gen_cond_jump(ctx, TCG_COND_TSTNE, PuV, riV)
 #define fGEN_TCG_J2_jumptnew(SHORTCODE) \
-    fGEN_TCG_cond_jumpt(fLSBNEW(PuN))
+    gen_cond_jump(ctx, TCG_COND_TSTEQ, PuN, riV)
 #define fGEN_TCG_J2_jumptnewpt(SHORTCODE) \
-    fGEN_TCG_cond_jumpt(fLSBNEW(PuN))
+    gen_cond_jump(ctx, TCG_COND_TSTEQ, PuN, riV)
 #define fGEN_TCG_J2_jumpfnewpt(SHORTCODE) \
-    fGEN_TCG_cond_jumpf(fLSBNEW(PuN))
+    gen_cond_jump(ctx, TCG_COND_TSTNE, PuN, riV)
 #define fGEN_TCG_J2_jumpfnew(SHORTCODE) \
-    fGEN_TCG_cond_jumpf(fLSBNEW(PuN))
+    gen_cond_jump(ctx, TCG_COND_TSTNE, PuN, riV)
 #define fGEN_TCG_J2_jumprz(SHORTCODE) \
     fGEN_TCG_cond_jumpt(tcg_gen_setcondi_tl(TCG_COND_NE, LSB, RsV, 0))
 #define fGEN_TCG_J2_jumprzpt(SHORTCODE) \
@@ -975,35 +968,22 @@
 #define fGEN_TCG_J2_jumprltezpt(SHORTCODE) \
     fGEN_TCG_cond_jumpt(tcg_gen_setcondi_tl(TCG_COND_LE, LSB, RsV, 0))
 
-#define fGEN_TCG_cond_jumprt(COND) \
-    do { \
-        TCGv LSB = tcg_temp_new(); \
-        COND; \
-        gen_cond_jumpr(ctx, RsV, TCG_COND_EQ, LSB); \
-    } while (0)
-#define fGEN_TCG_cond_jumprf(COND) \
-    do { \
-        TCGv LSB = tcg_temp_new(); \
-        COND; \
-        gen_cond_jumpr(ctx, RsV, TCG_COND_NE, LSB); \
-    } while (0)
-
 #define fGEN_TCG_J2_jumprt(SHORTCODE) \
-    fGEN_TCG_cond_jumprt(fLSBOLD(PuV))
+    gen_cond_jumpr(ctx, RsV, TCG_COND_TSTEQ, PuV)
 #define fGEN_TCG_J2_jumprtpt(SHORTCODE) \
-    fGEN_TCG_cond_jumprt(fLSBOLD(PuV))
+    gen_cond_jumpr(ctx, RsV, TCG_COND_TSTEQ, PuV)
 #define fGEN_TCG_J2_jumprf(SHORTCODE) \
-    fGEN_TCG_cond_jumprf(fLSBOLD(PuV))
+    gen_cond_jumpr(ctx, RsV, TCG_COND_TSTNE, PuV)
 #define fGEN_TCG_J2_jumprfpt(SHORTCODE) \
-    fGEN_TCG_cond_jumprf(fLSBOLD(PuV))
+    gen_cond_jumpr(ctx, RsV, TCG_COND_TSTNE, PuV)
 #define fGEN_TCG_J2_jumprtnew(SHORTCODE) \
-    fGEN_TCG_cond_jumprt(fLSBNEW(PuN))
+    gen_cond_jumpr(ctx, RsV, TCG_COND_TSTEQ, PuN)
 #define fGEN_TCG_J2_jumprtnewpt(SHORTCODE) \
-    fGEN_TCG_cond_jumprt(fLSBNEW(PuN))
+    gen_cond_jumpr(ctx, RsV, TCG_COND_TSTEQ, PuN)
 #define fGEN_TCG_J2_jumprfnew(SHORTCODE) \
-    fGEN_TCG_cond_jumprf(fLSBNEW(PuN))
+    gen_cond_jumpr(ctx, RsV, TCG_COND_TSTNE, PuN)
 #define fGEN_TCG_J2_jumprfnewpt(SHORTCODE) \
-    fGEN_TCG_cond_jumprf(fLSBNEW(PuN))
+    gen_cond_jumpr(ctx, RsV, TCG_COND_TSTNE, PuN)
 
 /*
  * New value compare & jump instructions
@@ -1101,13 +1081,13 @@
     gen_cmpi_jumpnv(ctx, TCG_COND_LE, NsN, -1, riV)
 
 #define fGEN_TCG_J4_tstbit0_t_jumpnv_t(SHORTCODE) \
-    gen_testbit0_jumpnv(ctx, NsN, TCG_COND_EQ, riV)
+    gen_testbit0_jumpnv(ctx, NsN, TCG_COND_TSTEQ, riV)
 #define fGEN_TCG_J4_tstbit0_t_jumpnv_nt(SHORTCODE) \
-    gen_testbit0_jumpnv(ctx, NsN, TCG_COND_EQ, riV)
+    gen_testbit0_jumpnv(ctx, NsN, TCG_COND_TSTEQ, riV)
 #define fGEN_TCG_J4_tstbit0_f_jumpnv_t(SHORTCODE) \
-    gen_testbit0_jumpnv(ctx, NsN, TCG_COND_NE, riV)
+    gen_testbit0_jumpnv(ctx, NsN, TCG_COND_TSTNE, riV)
 #define fGEN_TCG_J4_tstbit0_f_jumpnv_nt(SHORTCODE) \
-    gen_testbit0_jumpnv(ctx, NsN, TCG_COND_NE, riV)
+    gen_testbit0_jumpnv(ctx, NsN, TCG_COND_TSTNE, riV)
 
 /* r0 = r1 ; jump address */
 #define fGEN_TCG_J4_jumpsetr(SHORTCODE) \
@@ -1150,14 +1130,14 @@
     gen_jumpr(ctx, hex_gpr[HEX_REG_LR])
 
 #define fGEN_TCG_SL2_jumpr31_t(SHORTCODE) \
-    gen_cond_jumpr31(ctx, TCG_COND_EQ, hex_pred[0])
+    gen_cond_jumpr31(ctx, TCG_COND_TSTEQ, hex_pred[0])
 #define fGEN_TCG_SL2_jumpr31_f(SHORTCODE) \
-    gen_cond_jumpr31(ctx, TCG_COND_NE, hex_pred[0])
+    gen_cond_jumpr31(ctx, TCG_COND_TSTNE, hex_pred[0])
 
 #define fGEN_TCG_SL2_jumpr31_tnew(SHORTCODE) \
-    gen_cond_jumpr31(ctx, TCG_COND_EQ, ctx->new_pred_value[0])
+    gen_cond_jumpr31(ctx, TCG_COND_TSTEQ, ctx->new_pred_value[0])
 #define fGEN_TCG_SL2_jumpr31_fnew(SHORTCODE) \
-    gen_cond_jumpr31(ctx, TCG_COND_NE, ctx->new_pred_value[0])
+    gen_cond_jumpr31(ctx, TCG_COND_TSTNE, ctx->new_pred_value[0])
 
 /* Count trailing zeros/ones */
 #define fGEN_TCG_S2_ct0(SHORTCODE) \
diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index 9eb21da6f3e..c7b9436c8d4 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -455,7 +455,7 @@ static void gen_write_new_pc_addr(DisasContext *ctx, TCGv addr,
     TCGLabel *pred_false = NULL;
     if (cond != TCG_COND_ALWAYS) {
         pred_false = gen_new_label();
-        tcg_gen_brcondi_tl(cond, pred, 0, pred_false);
+        tcg_gen_brcondi_tl(cond, pred, 1, pred_false);
     }
 
     if (ctx->pkt->pkt_has_multi_cof) {
@@ -579,9 +579,7 @@ static void gen_cond_jumpr(DisasContext *ctx, TCGv dst_pc,
 
 static void gen_cond_jumpr31(DisasContext *ctx, TCGCond cond, TCGv pred)
 {
-    TCGv LSB = tcg_temp_new();
-    tcg_gen_andi_tl(LSB, pred, 1);
-    gen_cond_jumpr(ctx, hex_gpr[HEX_REG_LR], cond, LSB);
+    gen_cond_jumpr(ctx, hex_gpr[HEX_REG_LR], cond, pred);
 }
 
 static void gen_cond_jump(DisasContext *ctx, TCGCond cond, TCGv pred,
@@ -609,14 +607,14 @@ static void gen_cmpnd_cmp_jmp_t(DisasContext *ctx,
                                 int pnum, TCGCond cond, TCGv arg1, TCGv arg2,
                                 int pc_off)
 {
-    gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, arg2, TCG_COND_EQ, pc_off);
+    gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, arg2, TCG_COND_TSTEQ, pc_off);
 }
 
 static void gen_cmpnd_cmp_jmp_f(DisasContext *ctx,
                                 int pnum, TCGCond cond, TCGv arg1, TCGv arg2,
                                 int pc_off)
 {
-    gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, arg2, TCG_COND_NE, pc_off);
+    gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, arg2, TCG_COND_TSTNE, pc_off);
 }
 
 static void gen_cmpnd_cmpi_jmp_t(DisasContext *ctx,
@@ -624,7 +622,7 @@ static void gen_cmpnd_cmpi_jmp_t(DisasContext *ctx,
                                  int pc_off)
 {
     TCGv tmp = tcg_constant_tl(arg2);
-    gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, tmp, TCG_COND_EQ, pc_off);
+    gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, tmp, TCG_COND_TSTEQ, pc_off);
 }
 
 static void gen_cmpnd_cmpi_jmp_f(DisasContext *ctx,
@@ -632,7 +630,7 @@ static void gen_cmpnd_cmpi_jmp_f(DisasContext *ctx,
                                  int pc_off)
 {
     TCGv tmp = tcg_constant_tl(arg2);
-    gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, tmp, TCG_COND_NE, pc_off);
+    gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, tmp, TCG_COND_TSTNE, pc_off);
 }
 
 static void gen_cmpnd_cmp_n1_jmp_t(DisasContext *ctx, int pnum, TCGCond cond,
@@ -665,9 +663,7 @@ static void gen_cmpnd_tstbit0_jmp(DisasContext *ctx,
 static void gen_testbit0_jumpnv(DisasContext *ctx,
                                 TCGv arg, TCGCond cond, int pc_off)
 {
-    TCGv pred = tcg_temp_new();
-    tcg_gen_andi_tl(pred, arg, 1);
-    gen_cond_jump(ctx, cond, pred, pc_off);
+    gen_cond_jump(ctx, cond, arg, pc_off);
 }
 
 static void gen_jump(DisasContext *ctx, int pc_off)
@@ -698,11 +694,9 @@ static void gen_cond_call(DisasContext *ctx, TCGv pred,
                           TCGCond cond, int pc_off)
 {
     TCGv lr = get_result_gpr(ctx, HEX_REG_LR);
-    TCGv lsb = tcg_temp_new();
     TCGLabel *skip = gen_new_label();
-    tcg_gen_andi_tl(lsb, pred, 1);
-    gen_write_new_pc_pcrel(ctx, pc_off, cond, lsb);
-    tcg_gen_brcondi_tl(cond, lsb, 0, skip);
+    gen_write_new_pc_pcrel(ctx, pc_off, cond, pred);
+    tcg_gen_brcondi_tl(cond, pred, 1, skip);
     tcg_gen_movi_tl(lr, ctx->next_PC);
     gen_set_label(skip);
 }
@@ -710,10 +704,8 @@ static void gen_cond_call(DisasContext *ctx, TCGv pred,
 static void gen_cond_callr(DisasContext *ctx,
                            TCGCond cond, TCGv pred, TCGv new_pc)
 {
-    TCGv lsb = tcg_temp_new();
     TCGLabel *skip = gen_new_label();
-    tcg_gen_andi_tl(lsb, pred, 1);
-    tcg_gen_brcondi_tl(cond, lsb, 0, skip);
+    tcg_gen_brcondi_tl(cond, pred, 1, skip);
     gen_callr(ctx, new_pc);
     gen_set_label(skip);
 }
@@ -955,7 +947,7 @@ static void gen_cmp_jumpnv(DisasContext *ctx,
 {
     TCGv pred = tcg_temp_new();
     tcg_gen_setcond_tl(cond, pred, val, src);
-    gen_cond_jump(ctx, TCG_COND_EQ, pred, pc_off);
+    gen_cond_jump(ctx, TCG_COND_TSTEQ, pred, pc_off);
 }
 
 static void gen_cmpi_jumpnv(DisasContext *ctx,
@@ -963,7 +955,7 @@ static void gen_cmpi_jumpnv(DisasContext *ctx,
 {
     TCGv pred = tcg_temp_new();
     tcg_gen_setcondi_tl(cond, pred, val, src);
-    gen_cond_jump(ctx, TCG_COND_EQ, pred, pc_off);
+    gen_cond_jump(ctx, TCG_COND_TSTEQ, pred, pc_off);
 }
 
 /* Shift left with saturation */
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index 8a223f6e13e..633401451d8 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -163,7 +163,7 @@ static void gen_end_tb(DisasContext *ctx)
     if (ctx->branch_cond != TCG_COND_NEVER) {
         if (ctx->branch_cond != TCG_COND_ALWAYS) {
             TCGLabel *skip = gen_new_label();
-            tcg_gen_brcondi_tl(ctx->branch_cond, ctx->branch_taken, 0, skip);
+            tcg_gen_brcondi_tl(ctx->branch_cond, ctx->branch_taken, 1, skip);
             gen_goto_tb(ctx, 0, ctx->branch_dest, true);
             gen_set_label(skip);
             gen_goto_tb(ctx, 1, ctx->next_PC, false);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PULL 3/3] tests/tcg/hexagon: add test for predicated .new branch LSB evaluation
  2026-03-20 14:50 [PULL 0/3] hex queue Brian Cain
  2026-03-20 14:50 ` [PULL 1/3] target/hexagon: fix J2_jumptnew/pt predicate check to use LSB Brian Cain
  2026-03-20 14:50 ` [PULL 2/3] target/hexagon: use TCG_COND_TSTEQ/TSTNE for predicate branches Brian Cain
@ 2026-03-20 14:50 ` Brian Cain
  2026-03-23 12:42 ` [PULL 0/3] hex queue Peter Maydell
  3 siblings, 0 replies; 5+ messages in thread
From: Brian Cain @ 2026-03-20 14:50 UTC (permalink / raw)
  To: qemu-devel, peter.maydell; +Cc: brian.cain, Taylor Simpson

Test for predicated .new branches with non-standard predicate values
(non-all-0, non-all-1).  Hexagon predicates are 8 bits wide but conditional
branches evaluate only the LSB.

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 tests/tcg/hexagon/test_pnew_jump_loads.c | 341 +++++++++++++++++++++++
 tests/tcg/hexagon/Makefile.target        |   3 +
 2 files changed, 344 insertions(+)
 create mode 100644 tests/tcg/hexagon/test_pnew_jump_loads.c

diff --git a/tests/tcg/hexagon/test_pnew_jump_loads.c b/tests/tcg/hexagon/test_pnew_jump_loads.c
new file mode 100644
index 00000000000..06178bdac11
--- /dev/null
+++ b/tests/tcg/hexagon/test_pnew_jump_loads.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Exhaustive test for predicated .new branches with non-standard predicate
+ * values (non-all-0, non-all-1).
+ *
+ * Hexagon predicates are 8 bits wide but conditional branches evaluate only
+ * bit 0 (the LSB).  A predicate value like 0xFE is non-zero yet has bit 0
+ * clear, so it must evaluate as "false".
+ *
+ * This test covers the distinct TCG code paths for predicated .new ops:
+ *
+ *   1. gen_cond_jump      - J2_jumptnewpt / J2_jumpfnewpt  (p0..p3)
+ *   2. gen_cond_jumpr     - J2_jumprtnewpt / J2_jumprfnewpt
+ *   3. gen_cond_jumpr31   - SL2_jumpr31_tnew / SL2_jumpr31_fnew (duplex)
+ *   4. gen_testbit0_jumpnv - J4_tstbit0_t/f_jumpnv_t
+ *   5. Conditional .new loads and stores
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+
+int err;
+
+#include "hex_test.h"
+
+/*
+ * Non-standard predicate: non-zero (0xFE) but bit 0 clear => false.
+ * This distinguishes correct LSB evaluation from incorrect non-zero checks.
+ */
+#define PRED_VAL    0xFEu
+#define SENTINEL    0xDEADBEEFu
+#define LOAD_VAL    0xAAAABBBBu
+
+/* gen_cond_jump (J2_jumptnewpt) */
+
+/*
+ * Macro to test jumptnew across predicate registers p0..p3.
+ * { Pn = and(Pn, Pn); if (Pn.new) jump:t TARGET }
+ *
+ * Pn.new = PRED_VAL & PRED_VAL = 0xFE => bit0=0 => not taken.
+ * Different predicate registers produce different instruction encodings.
+ */
+#define TEST_JUMPTNEW(PREG)                                     \
+static void test_jumptnew_##PREG(void)                          \
+{                                                               \
+    uint32_t jumped;                                            \
+    asm(                                                        \
+        #PREG " = %[pred]\n"                                    \
+        "{ " #PREG " = and(" #PREG ", " #PREG ")\n"            \
+        "  if (" #PREG ".new) jump:t 1f }\n"                   \
+        "%[jumped] = #0\n"                                      \
+        "jump 2f\n"                                             \
+        "1:\n"                                                  \
+        "%[jumped] = #1\n"                                      \
+        "2:\n"                                                  \
+        : [jumped] "=r"(jumped)                                 \
+        : [pred] "r"(PRED_VAL)                                  \
+        : #PREG                                                 \
+    );                                                          \
+    check32(jumped, 0);                                         \
+}
+
+TEST_JUMPTNEW(p0)
+TEST_JUMPTNEW(p1)
+TEST_JUMPTNEW(p2)
+TEST_JUMPTNEW(p3)
+
+/* jumpfnew: bit0=0 => condition "false" => negated => jump IS taken */
+static void test_jumpfnew_p0(void)
+{
+    uint32_t jumped;
+
+    asm(
+        "p0 = %[pred]\n"
+        "{ p0 = and(p0, p0)\n"
+        "  if (!p0.new) jump:t 1f }\n"
+        "%[jumped] = #0\n"
+        "jump 2f\n"
+        "1:\n"
+        "%[jumped] = #1\n"
+        "2:\n"
+        : [jumped] "=r"(jumped)
+        : [pred] "r"(PRED_VAL)
+        : "p0"
+    );
+    check32(jumped, 1);
+}
+
+/* gen_cond_jumpr (J2_jumprtnewpt) */
+
+static void test_jumprtnew_p0(void)
+{
+    uint32_t jumped;
+
+    asm(
+        "p0 = %[pred]\n"
+        "r0 = ##1f\n"
+        "{ p0 = and(p0, p0)\n"
+        "  if (p0.new) jumpr:t r0 }\n"
+        "%[jumped] = #0\n"
+        "jump 2f\n"
+        "1:\n"
+        "%[jumped] = #1\n"
+        "2:\n"
+        : [jumped] "=r"(jumped)
+        : [pred] "r"(PRED_VAL)
+        : "p0", "r0"
+    );
+    check32(jumped, 0);
+}
+
+static void test_jumprfnew_p0(void)
+{
+    uint32_t jumped;
+
+    asm(
+        "p0 = %[pred]\n"
+        "r0 = ##1f\n"
+        "{ p0 = and(p0, p0)\n"
+        "  if (!p0.new) jumpr:t r0 }\n"
+        "%[jumped] = #0\n"
+        "jump 2f\n"
+        "1:\n"
+        "%[jumped] = #1\n"
+        "2:\n"
+        : [jumped] "=r"(jumped)
+        : [pred] "r"(PRED_VAL)
+        : "p0", "r0"
+    );
+    check32(jumped, 1);
+}
+
+/* gen_cond_jumpr31 (SL2_jumpr31_tnew) */
+
+/*
+ * Duplex sub-instructions: only SA1_cmpeqi and similar can produce .new
+ * predicates in a duplex packet, and those only yield 0x00/0xFF.
+ * We test with standard values to exercise the duplex decode path.
+ *
+ * { p0 = cmp.eq(r0, #0); if (p0.new) jumpr:nt r31 }
+ * With r0=0: p0.new = 0xFF => bit0=1 => taken.
+ */
+static void test_jumpr31_tnew(void)
+{
+    uint32_t jumped;
+
+    asm(
+        "r0 = #0\n"
+        "r31 = ##1f\n"
+        "{ p0 = cmp.eq(r0, #0)\n"
+        "  if (p0.new) jumpr:nt r31 }\n"
+        "%[jumped] = #0\n"
+        "jump 2f\n"
+        "1:\n"
+        "%[jumped] = #1\n"
+        "2:\n"
+        : [jumped] "=r"(jumped)
+        :
+        : "r0", "r31", "p0"
+    );
+    check32(jumped, 1);
+}
+
+/* p0.new = 0xFF => bit0=1 => !true => not taken */
+static void test_jumpr31_fnew(void)
+{
+    uint32_t jumped;
+
+    asm(
+        "r0 = #0\n"
+        "r31 = ##1f\n"
+        "{ p0 = cmp.eq(r0, #0)\n"
+        "  if (!p0.new) jumpr:nt r31 }\n"
+        "%[jumped] = #0\n"
+        "jump 2f\n"
+        "1:\n"
+        "%[jumped] = #1\n"
+        "2:\n"
+        : [jumped] "=r"(jumped)
+        :
+        : "r0", "r31", "p0"
+    );
+    check32(jumped, 0);
+}
+
+/* gen_testbit0_jumpnv (J4_tstbit0) */
+
+/*
+ * { r0 = #0xFE; if (tstbit(r0.new, #0)) jump:t TARGET }
+ * r0.new = 0xFE => bit0=0 => tstbit false => not taken.
+ */
+static void test_tstbit0_t_jumpnv(void)
+{
+    uint32_t jumped;
+
+    asm(
+        "{ r0 = #0xFE\n"
+        "  if (tstbit(r0.new, #0)) jump:t 1f }\n"
+        "%[jumped] = #0\n"
+        "jump 2f\n"
+        "1:\n"
+        "%[jumped] = #1\n"
+        "2:\n"
+        : [jumped] "=r"(jumped)
+        :
+        : "r0"
+    );
+    check32(jumped, 0);
+}
+
+/* bit0=0 => tstbit false => negated => taken */
+static void test_tstbit0_f_jumpnv(void)
+{
+    uint32_t jumped;
+
+    asm(
+        "{ r0 = #0xFE\n"
+        "  if (!tstbit(r0.new, #0)) jump:t 1f }\n"
+        "%[jumped] = #0\n"
+        "jump 2f\n"
+        "1:\n"
+        "%[jumped] = #1\n"
+        "2:\n"
+        : [jumped] "=r"(jumped)
+        :
+        : "r0"
+    );
+    check32(jumped, 1);
+}
+
+/* conditional .new loads and stores */
+
+static uint32_t load_val;
+static uint32_t store_dst;
+
+/* bit0=0 => condition false => load skipped => sentinel remains */
+static void test_cond_load_tnew(void)
+{
+    uint32_t result;
+
+    load_val = LOAD_VAL;
+    asm(
+        "p0 = %[pred]\n"
+        "%[res] = %[sentinel]\n"
+        "{ p0 = and(p0, p0)\n"
+        "  if (p0.new) %[res] = memw(%[addr]+#0) }\n"
+        : [res] "=&r"(result)
+        : [pred] "r"(PRED_VAL),
+          [addr] "r"(&load_val),
+          [sentinel] "r"(SENTINEL)
+        : "p0", "memory"
+    );
+    check32(result, SENTINEL);
+}
+
+/* bit0=0 => condition false => negated => load executed */
+static void test_cond_load_fnew(void)
+{
+    uint32_t result;
+
+    load_val = LOAD_VAL;
+    asm(
+        "p0 = %[pred]\n"
+        "%[res] = %[sentinel]\n"
+        "{ p0 = and(p0, p0)\n"
+        "  if (!p0.new) %[res] = memw(%[addr]+#0) }\n"
+        : [res] "=&r"(result)
+        : [pred] "r"(PRED_VAL),
+          [addr] "r"(&load_val),
+          [sentinel] "r"(SENTINEL)
+        : "p0", "memory"
+    );
+    check32(result, LOAD_VAL);
+}
+
+/* bit0=0 => condition false => store skipped => sentinel remains */
+static void test_cond_store_tnew(void)
+{
+    store_dst = SENTINEL;
+    asm(
+        "p0 = %[pred]\n"
+        "{ p0 = and(p0, p0)\n"
+        "  if (p0.new) memw(%[addr]+#0) = %[val] }\n"
+        :
+        : [pred] "r"(PRED_VAL),
+          [addr] "r"(&store_dst),
+          [val] "r"(LOAD_VAL)
+        : "p0", "memory"
+    );
+    check32(store_dst, SENTINEL);
+}
+
+/* bit0=0 => condition false => negated => store executed */
+static void test_cond_store_fnew(void)
+{
+    store_dst = SENTINEL;
+    asm(
+        "p0 = %[pred]\n"
+        "{ p0 = and(p0, p0)\n"
+        "  if (!p0.new) memw(%[addr]+#0) = %[val] }\n"
+        :
+        : [pred] "r"(PRED_VAL),
+          [addr] "r"(&store_dst),
+          [val] "r"(LOAD_VAL)
+        : "p0", "memory"
+    );
+    check32(store_dst, LOAD_VAL);
+}
+
+int main(void)
+{
+    /* gen_cond_jump with all predicate registers */
+    test_jumptnew_p0();
+    test_jumptnew_p1();
+    test_jumptnew_p2();
+    test_jumptnew_p3();
+    test_jumpfnew_p0();
+
+    /* gen_cond_jumpr */
+    test_jumprtnew_p0();
+    test_jumprfnew_p0();
+
+    /* gen_cond_jumpr31 (duplex, standard values) */
+    test_jumpr31_tnew();
+    test_jumpr31_fnew();
+
+    /* gen_testbit0_jumpnv */
+    test_tstbit0_t_jumpnv();
+    test_tstbit0_f_jumpnv();
+
+    /* conditional .new loads and stores */
+    test_cond_load_tnew();
+    test_cond_load_fnew();
+    test_cond_store_tnew();
+    test_cond_store_fnew();
+
+    puts(err ? "FAIL" : "PASS");
+    return err ? 1 : 0;
+}
diff --git a/tests/tcg/hexagon/Makefile.target b/tests/tcg/hexagon/Makefile.target
index a70ef2f6607..549c95082f6 100644
--- a/tests/tcg/hexagon/Makefile.target
+++ b/tests/tcg/hexagon/Makefile.target
@@ -81,6 +81,8 @@ HEX_TESTS += test_vminh
 HEX_TESTS += test_vpmpyh
 HEX_TESTS += test_vspliceb
 
+HEX_TESTS += test_pnew_jump_loads
+
 HEX_TESTS += v68_scalar
 HEX_TESTS += v68_hvx
 HEX_TESTS += v69_hvx
@@ -104,6 +106,7 @@ overflow: overflow.c hex_test.h
 preg_alias: preg_alias.c hex_test.h
 read_write_overlap: read_write_overlap.c hex_test.h
 reg_mut: reg_mut.c hex_test.h
+test_pnew_jump_loads: test_pnew_jump_loads.c hex_test.h
 unaligned_pc: unaligned_pc.c
 
 # This test has to be compiled for the -mv67t target
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PULL 0/3] hex queue
  2026-03-20 14:50 [PULL 0/3] hex queue Brian Cain
                   ` (2 preceding siblings ...)
  2026-03-20 14:50 ` [PULL 3/3] tests/tcg/hexagon: add test for predicated .new branch LSB evaluation Brian Cain
@ 2026-03-23 12:42 ` Peter Maydell
  3 siblings, 0 replies; 5+ messages in thread
From: Peter Maydell @ 2026-03-23 12:42 UTC (permalink / raw)
  To: Brian Cain; +Cc: qemu-devel

On Fri, 20 Mar 2026 at 14:50, Brian Cain <brian.cain@oss.qualcomm.com> wrote:
>
> The following changes since commit 8e711856d7639cbffa51405f2cc2366e3d9e3a23:
>
>   Merge tag 'hppa-fixes-for-v11-pull-request' of https://github.com/hdeller/qemu-hppa into staging (2026-03-20 10:04:48 +0000)
>
> are available in the Git repository at:
>
>   https://github.com/quic/qemu tags/pull-hex-20260320
>
> for you to fetch changes up to 1adf67b3c445f4060900440ea210e7a1e03042f5:
>
>   tests/tcg/hexagon: add test for predicated .new branch LSB evaluation (2026-03-20 07:43:03 -0700)
>
> ----------------------------------------------------------------
> Fix for J2_jumptnew{,pt} pred-reg misbehavior
>



Applied, thanks.

Please update the changelog at https://wiki.qemu.org/ChangeLog/11.0
for any user-visible changes.

-- PMM


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-03-23 12:43 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-20 14:50 [PULL 0/3] hex queue Brian Cain
2026-03-20 14:50 ` [PULL 1/3] target/hexagon: fix J2_jumptnew/pt predicate check to use LSB Brian Cain
2026-03-20 14:50 ` [PULL 2/3] target/hexagon: use TCG_COND_TSTEQ/TSTNE for predicate branches Brian Cain
2026-03-20 14:50 ` [PULL 3/3] tests/tcg/hexagon: add test for predicated .new branch LSB evaluation Brian Cain
2026-03-23 12:42 ` [PULL 0/3] hex queue Peter Maydell

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox