All of lore.kernel.org
 help / color / mirror / Atom feed
From: Brian Cain <brian.cain@oss.qualcomm.com>
To: qemu-devel@nongnu.org, peter.maydell@linaro.org
Cc: brian.cain@oss.qualcomm.com, Taylor Simpson <ltaylorsimpson@gmail.com>
Subject: [PULL 3/3] tests/tcg/hexagon: add test for predicated .new branch LSB evaluation
Date: Fri, 20 Mar 2026 07:50:41 -0700	[thread overview]
Message-ID: <20260320145041.3027130-4-brian.cain@oss.qualcomm.com> (raw)
In-Reply-To: <20260320145041.3027130-1-brian.cain@oss.qualcomm.com>

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


  parent reply	other threads:[~2026-03-20 14:51 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
2026-03-23 12:42 ` [PULL 0/3] hex queue Peter Maydell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260320145041.3027130-4-brian.cain@oss.qualcomm.com \
    --to=brian.cain@oss.qualcomm.com \
    --cc=ltaylorsimpson@gmail.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.