* [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 an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.