Add tests for: vallocframe, atomics, trap2, CFI/restricted branches, and
scalar fp instructions.

New instructions not yet supported by the toolchain are manually encoded
with .word directives.

Signed-off-by: Brian Cain <[email protected]>
---
 tests/tcg/hexagon/cfi_tgts.h         |  16 +++
 tests/tcg/hexagon/atomics.c          | 102 +++++++++++++++++
 tests/tcg/hexagon/cfi_user.c         |  63 +++++++++++
 tests/tcg/hexagon/check_rev_gating.c |  10 ++
 tests/tcg/hexagon/invalid-encoding.c |  20 ++++
 tests/tcg/hexagon/trap2.c            |  34 ++++++
 tests/tcg/hexagon/v83_scalar_fp.c    |  98 +++++++++++++++++
 tests/tcg/hexagon/vallocframe.c      | 111 +++++++++++++++++++
 tests/tcg/hexagon/cfi_tgts.S         | 157 +++++++++++++++++++++++++++
 tests/tcg/hexagon/meson.build        |  19 +++-
 10 files changed, 628 insertions(+), 2 deletions(-)
 create mode 100644 tests/tcg/hexagon/cfi_tgts.h
 create mode 100644 tests/tcg/hexagon/cfi_user.c
 create mode 100644 tests/tcg/hexagon/trap2.c
 create mode 100644 tests/tcg/hexagon/v83_scalar_fp.c
 create mode 100644 tests/tcg/hexagon/vallocframe.c
 create mode 100644 tests/tcg/hexagon/cfi_tgts.S

diff --git a/tests/tcg/hexagon/cfi_tgts.h b/tests/tcg/hexagon/cfi_tgts.h
new file mode 100644
index 00000000000..324075c1ec2
--- /dev/null
+++ b/tests/tcg/hexagon/cfi_tgts.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef CFI_TGTS_H
+#define CFI_TGTS_H
+
+#define CFI_TEST_CASES 13
+
+void run_test_case(int valid, int test_case);
+void run_callr_rb_lr_test(int valid);
+void run_jumpr_rb_lr_test(void);
+void run_allocframe_test(void);
+
+#endif
diff --git a/tests/tcg/hexagon/atomics.c b/tests/tcg/hexagon/atomics.c
index 5017ca003f1..7416c494363 100644
--- a/tests/tcg/hexagon/atomics.c
+++ b/tests/tcg/hexagon/atomics.c
@@ -109,6 +109,43 @@ static inline int64_t atomic_dec64(int64_t *x)
     return old;
 }
 
+static uint32_t v85_atomic_inc(uint64_t *counter)
+{
+    uint32_t old_val;
+
+    asm volatile("r0 = %0\n"
+                 "r1 = %1\n"
+                 "r2 = #1\n"
+                 ".word 0x9001e220\n" /* r0 = atomw_add(r1,r2):aq */
+                 "%0 = r0\n"
+                 : "=r"(old_val)
+                 : "r"(counter)
+                 : "r0", "r1", "r2");
+    return old_val;
+}
+
+static uint64_t v85_atomic_swap64(uint64_t *addr, uint64_t val)
+{
+    asm volatile("r1:0 = %0\n"
+                 "r2 = %1\n"
+                 ".word 0x90c2e0a0\n" /* r1:0 = atomd_swap(r2,r1:0):aq */
+                 "%0 = r1:0\n"
+                 : "+r"(val)
+                 : "r"(addr)
+                 : "r0", "r1", "r2");
+    return val;
+}
+
+static void v85_dcfetch_multi(const void *addr)
+{
+    asm volatile("r0 = %0\n"
+                 "r1 = #0\n"
+                 ".word 0x9400c840\n" /* dcfetch_multi(r0,r1) */
+                 :
+                 : "r"(addr)
+                 : "r0", "r1", "memory");
+}
+
 #define LOOP_CNT 1000
 volatile int32_t tick32 = 1; /* Using volatile because we are testing atomics 
*/
 volatile int64_t tick64 = 1; /* Using volatile because we are testing atomics 
*/
@@ -159,10 +196,75 @@ void test_pthread(void)
     check64(tick64, 1);
 }
 
+static void test_v85_swap64(void)
+{
+#define INITIAL_V1 0xffffffffffffffff
+#define INITIAL_V2 0x1111111111111111
+
+    uint64_t v1 = INITIAL_V1;
+    uint64_t v2 = INITIAL_V2;
+
+    v2 = v85_atomic_swap64(&v1, v2);
+    check64(v1, INITIAL_V2);
+    check64(v2, INITIAL_V1);
+
+    v2 = v85_atomic_swap64(&v1, v2);
+    check64(v1, INITIAL_V1);
+    check64(v2, INITIAL_V2);
+
+#undef INITIAL_V1
+#undef INITIAL_V2
+}
+
+#define V85_ROUNDS 1000
+#define V85_THREADS 10
+static uint64_t v85_global_counter = 1;
+static uint64_t v85_started_threads;
+
+static void *v85_counter_thread(void *arg)
+{
+    uint32_t previous;
+
+    v85_atomic_inc(&v85_started_threads);
+    while (v85_started_threads != V85_THREADS) {
+        asm volatile("pause(#0)");
+    }
+    previous = 0;
+    for (int i = 0; i < V85_ROUNDS; i++) {
+        uint32_t current = v85_atomic_inc(&v85_global_counter);
+
+        if (current <= previous) {
+            printf("ERROR: counter is not strictly growing. "
+                   "Before: %" PRIu32 ", Now: %" PRIu32 "\n",
+                   previous, current);
+            err = 1;
+            return arg;
+        }
+        previous = current;
+    }
+    return arg;
+}
+
+static void test_v85_race(void)
+{
+    pthread_t tids[V85_THREADS];
+
+    for (int i = 0; i < V85_THREADS; i++) {
+        pthread_create(&tids[i], NULL, v85_counter_thread, NULL);
+    }
+    for (int i = 0; i < V85_THREADS; i++) {
+        pthread_join(tids[i], NULL);
+    }
+    check64(v85_global_counter, 1 + V85_THREADS * V85_ROUNDS);
+}
+
 int main(int argc, char **argv)
 {
     test_reservations();
     test_pthread();
+    v85_dcfetch_multi(&v85_global_counter);
+    test_v85_swap64();
+    test_v85_race();
     puts(err ? "FAIL" : "PASS");
     return err;
 }
diff --git a/tests/tcg/hexagon/cfi_user.c b/tests/tcg/hexagon/cfi_user.c
new file mode 100644
index 00000000000..cf97b4e0c32
--- /dev/null
+++ b/tests/tcg/hexagon/cfi_user.c
@@ -0,0 +1,63 @@
+/*
+ * Test v83 restricted indirect control-flow forms and restricted targets.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <assert.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cfi_tgts.h"
+
+static sigjmp_buf cfi_jmp;
+static volatile sig_atomic_t cfi_signal;
+
+static void handle_sigill(int sig, siginfo_t *info, void *context)
+{
+    assert(sig == SIGILL);
+    cfi_signal = sig;
+    siglongjmp(cfi_jmp, 1);
+}
+
+int main(void)
+{
+    struct sigaction action;
+    int i;
+
+    action.sa_sigaction = handle_sigill;
+    sigemptyset(&action.sa_mask);
+    action.sa_flags = SA_SIGINFO;
+    assert(sigaction(SIGILL, &action, NULL) == 0);
+
+    for (i = 0; i < CFI_TEST_CASES; i++) {
+        run_test_case(1, i);
+    }
+
+    for (i = 0; i < CFI_TEST_CASES; i++) {
+        cfi_signal = 0;
+        if (sigsetjmp(cfi_jmp, 1) == 0) {
+            run_test_case(0, i);
+            abort();
+        }
+        assert(cfi_signal == SIGILL);
+    }
+
+    run_jumpr_rb_lr_test();
+    run_callr_rb_lr_test(1);
+
+    cfi_signal = 0;
+    if (sigsetjmp(cfi_jmp, 1) == 0) {
+        run_callr_rb_lr_test(0);
+        abort();
+    }
+    assert(cfi_signal == SIGILL);
+
+    run_allocframe_test();
+
+    puts("PASS");
+    return EXIT_SUCCESS;
+}
diff --git a/tests/tcg/hexagon/check_rev_gating.c 
b/tests/tcg/hexagon/check_rev_gating.c
index ad22a93bdaf..3a5ed9c71ca 100644
--- a/tests/tcg/hexagon/check_rev_gating.c
+++ b/tests/tcg/hexagon/check_rev_gating.c
@@ -122,6 +122,13 @@ TRY_FUNC(v79_dczeroa_nt,
 TRY_FUNC(v79_dcfetchbo_nt,
          ".word 0x9402e000    /* dcfetch(r2+#0):nt */\n")
 
+TRY_FUNC(v83_callr_rb,
+         ".word 0x5020c000    /* callr_rb r0 */\n")
+TRY_FUNC(v83_nop_rb,
+         ".word 0x7f80c000    /* nop_rb */\n")
+TRY_FUNC(v83_vsfadd,
+         ".word 0xeb02c440    /* r1:0 = vsfadd(r3:2, r5:4) */\n")
+
 TRY_FUNC(v79hvx_vmerge_qf,
          ".word 0x1f01e0e2    /* v2 = vmerge(v0.x, v1.w) */\n")
 
@@ -165,6 +172,9 @@ int main(void)
     assert(try_v79_pstorerif_pi_nt() == SIGILL);
     assert(try_v79_dczeroa_nt() == SIGILL);
     assert(try_v79_dcfetchbo_nt() == SIGILL);
+    assert(try_v83_callr_rb() == SIGILL);
+    assert(try_v83_nop_rb() == SIGILL);
+    assert(try_v83_vsfadd() == SIGILL);
 
     assert(try_v79hvx_vmerge_qf() == SIGILL);
 
diff --git a/tests/tcg/hexagon/invalid-encoding.c 
b/tests/tcg/hexagon/invalid-encoding.c
index 639d7f24959..7c4dd244559 100644
--- a/tests/tcg/hexagon/invalid-encoding.c
+++ b/tests/tcg/hexagon/invalid-encoding.c
@@ -89,6 +89,25 @@ static int test_invalid_nonduplex(void)
     return sig;
 }
 
+/* L4_loadw_phys bit 7 was reserved beginning with v83. */
+static int test_v83_loadw_phys_reserved_bit(void)
+{
+    int sig;
+
+    asm volatile(
+        "r0 = #0\n"
+        "r1 = ##1f\n"
+        "memw(%1) = r1\n"
+        ".word 0x9200e080\n"
+        "1:\n"
+        "%0 = r0\n"
+        : "=r"(sig)
+        : "r"(&resume_pc)
+        : "r0", "r1", "memory");
+
+    return sig;
+}
+
 int main()
 {
     struct sigaction act;
@@ -100,6 +119,7 @@ int main()
 
     assert(test_invalid_duplex() == SIGILL);
     assert(test_invalid_nonduplex() == SIGILL);
+    assert(test_v83_loadw_phys_reserved_bit() == SIGILL);
 
     puts("PASS");
     return EXIT_SUCCESS;
diff --git a/tests/tcg/hexagon/trap2.c b/tests/tcg/hexagon/trap2.c
new file mode 100644
index 00000000000..8180d23ed04
--- /dev/null
+++ b/tests/tcg/hexagon/trap2.c
@@ -0,0 +1,34 @@
+/*
+ *  Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ *  SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+uint32_t err;
+
+#include "hex_test.h"
+
+static int trap2_getpid(void)
+{
+    int pid;
+
+    asm volatile("r6 = #172\n" /* __NR_getpid */
+                 ".word 0x54c0c004\n" /* trap2(#1) */
+                 "%0 = r0\n"
+                 : "=r"(pid)
+                 :
+                 : "r0", "r6");
+    return pid;
+}
+
+int main(void)
+{
+    if (trap2_getpid() <= 0) {
+        err++;
+    }
+    puts(err ? "FAIL" : "PASS");
+    return err;
+}
diff --git a/tests/tcg/hexagon/v83_scalar_fp.c 
b/tests/tcg/hexagon/v83_scalar_fp.c
new file mode 100644
index 00000000000..722491c1f62
--- /dev/null
+++ b/tests/tcg/hexagon/v83_scalar_fp.c
@@ -0,0 +1,98 @@
+/*
+ * Test the v83 scalar two-lane floating-point instructions.
+ *
+ * The assembler does not yet know these instructions, so use their encodings.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+uint32_t err;
+
+#include "hex_test.h"
+
+static uint64_t vsfadd(uint64_t a, uint64_t b)
+{
+    uint64_t result;
+
+    asm volatile("r3:2 = %1\n"
+                 "r5:4 = %2\n"
+                 ".word 0xeb02c440\n" /* r1:0 = vsfadd(r3:2, r5:4) */
+                 "%0 = r1:0\n"
+                 : "=r"(result) : "r"(a), "r"(b) : "r0", "r1", "r2",
+                   "r3", "r4", "r5");
+    return result;
+}
+
+static uint64_t vsfsub(uint64_t a, uint64_t b)
+{
+    uint64_t result;
+
+    asm volatile("r3:2 = %1\n"
+                 "r5:4 = %2\n"
+                 ".word 0xeb02c460\n" /* r1:0 = vsfsub(r3:2, r5:4) */
+                 "%0 = r1:0\n"
+                 : "=r"(result) : "r"(a), "r"(b) : "r0", "r1", "r2",
+                   "r3", "r4", "r5");
+    return result;
+}
+
+static uint64_t vsfmpy(uint64_t a, uint64_t b)
+{
+    uint64_t result;
+
+    asm volatile("r3:2 = %1\n"
+                 "r5:4 = %2\n"
+                 ".word 0xeb42c420\n" /* r1:0 = vsfmpy(r3:2, r5:4) */
+                 "%0 = r1:0\n"
+                 : "=r"(result) : "r"(a), "r"(b) : "r0", "r1", "r2",
+                   "r3", "r4", "r5");
+    return result;
+}
+
+static uint64_t vsffma(uint64_t a, uint64_t b, uint64_t acc)
+{
+    uint64_t result;
+
+    asm volatile("r1:0 = %3\n"
+                 "r3:2 = %1\n"
+                 "r5:4 = %2\n"
+                 ".word 0xeb42c440\n" /* r1:0 += vsfmpy(r3:2, r5:4) */
+                 "%0 = r1:0\n"
+                 : "=r"(result) : "r"(a), "r"(b), "r"(acc) : "r0", "r1",
+                   "r2", "r3", "r4", "r5");
+    return result;
+}
+
+static uint64_t vsffms(uint64_t a, uint64_t b, uint64_t acc)
+{
+    uint64_t result;
+
+    asm volatile("r1:0 = %3\n"
+                 "r3:2 = %1\n"
+                 "r5:4 = %2\n"
+                 ".word 0xeb42c460\n" /* r1:0 -= vsfmpy(r3:2, r5:4) */
+                 "%0 = r1:0\n"
+                 : "=r"(result) : "r"(a), "r"(b), "r"(acc) : "r0", "r1",
+                   "r2", "r3", "r4", "r5");
+    return result;
+}
+
+int main(void)
+{
+    uint64_t a = 0x400000003fc00000ULL;
+    uint64_t b = 0x4080000040000000ULL;
+    uint64_t acc = 0x40a000003f800000ULL;
+
+    check64(vsfadd(a, b), 0x40c0000040600000ULL);
+    check64(vsfsub(a, b), 0xc0000000bf000000ULL);
+    check64(vsfmpy(a, b), 0x4100000040400000ULL);
+    check64(vsffma(a, b, acc), 0x4150000040800000ULL);
+    check64(vsffms(a, b, acc), 0xc0400000c0000000ULL);
+
+    puts(err ? "FAIL" : "PASS");
+    return err;
+}
diff --git a/tests/tcg/hexagon/vallocframe.c b/tests/tcg/hexagon/vallocframe.c
new file mode 100644
index 00000000000..4fb6fd4d930
--- /dev/null
+++ b/tests/tcg/hexagon/vallocframe.c
@@ -0,0 +1,111 @@
+/*
+ *  Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ *  SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <setjmp.h>
+#include <signal.h>
+
+uint32_t err;
+
+#include "hex_test.h"
+
+#define VSP_INITIAL_OFFSET (5 * 1024)
+#define VALLOCFRAME_VALUE 2
+#define VSP_AFTER_VALLOCFRAME \
+    (VSP_INITIAL_OFFSET - (VALLOCFRAME_VALUE * 2 * 1024))
+
+#define VALLOCFRAME_IMM ".word 0x6080c802\n" /* vallocframe(#2) */
+#define VALLOCFRAME_REG ".word 0x6080d000\n" /* vallocframe(r0) */
+#define VDEALLOCFRAME_IMM ".word 0x6a80c802\n" /* vdeallocframe(#2) */
+#define VDEALLOCFRAME_REG ".word 0x6940d000\n" /* vdeallocframe(r0) */
+
+static uint32_t read_vsp(void)
+{
+    uint32_t value;
+
+    asm volatile(".word 0x6a1dc000\n" /* r0 = vsp */
+                 "%0 = r0\n"
+                 : "=r"(value));
+    return value;
+}
+
+static void write_vsp(uint32_t value)
+{
+    asm volatile("r0 = %0\n"
+                 ".word 0x6220c01d\n" /* vsp = r0 */
+                 :
+                 : "r"(value));
+}
+
+static void write_vframelimit(uint32_t value)
+{
+    asm volatile("r0 = %0\n"
+                 ".word 0x6220c01c\n" /* vframelimit = r0 */
+                 :
+                 : "r"(value));
+}
+
+static sigjmp_buf overflow_jmp;
+static int overflow_sig;
+static int overflow_code;
+
+static void overflow_handler(int sig, siginfo_t *info, void *context)
+{
+    overflow_sig = sig;
+    overflow_code = info->si_code;
+    siglongjmp(overflow_jmp, 1);
+}
+
+static void test_vallocframe_imm(void)
+{
+    write_vsp(VSP_INITIAL_OFFSET);
+    write_vframelimit(0);
+    asm volatile(VALLOCFRAME_IMM);
+    check32(VSP_AFTER_VALLOCFRAME, read_vsp());
+    asm volatile(VDEALLOCFRAME_IMM);
+    check32(VSP_INITIAL_OFFSET, read_vsp());
+}
+
+static void test_vallocframe_reg(void)
+{
+    uint32_t value = VALLOCFRAME_VALUE;
+
+    write_vsp(VSP_INITIAL_OFFSET);
+    write_vframelimit(0);
+    asm volatile("r0 = %0\n" VALLOCFRAME_REG : : "r"(value));
+    check32(VSP_AFTER_VALLOCFRAME, read_vsp());
+    asm volatile("r0 = %0\n" VDEALLOCFRAME_REG : : "r"(value));
+    check32(VSP_INITIAL_OFFSET, read_vsp());
+}
+
+static void test_vallocframe_overflow(void)
+{
+    struct sigaction action = {
+        .sa_sigaction = overflow_handler,
+        .sa_flags = SA_SIGINFO,
+    };
+
+    sigemptyset(&action.sa_mask);
+    sigaction(SIGSEGV, &action, NULL);
+    if (sigsetjmp(overflow_jmp, 1) == 0) {
+        write_vsp(VSP_INITIAL_OFFSET);
+        write_vframelimit(VSP_AFTER_VALLOCFRAME + 1);
+        asm volatile(VALLOCFRAME_IMM);
+        check32(1, 0);
+    }
+    check32(SIGSEGV, overflow_sig);
+    check32(SEGV_BNDERR, overflow_code);
+}
+
+int main(void)
+{
+    test_vallocframe_imm();
+    test_vallocframe_reg();
+    test_vallocframe_overflow();
+    puts(err ? "FAIL" : "PASS");
+    return err;
+}
diff --git a/tests/tcg/hexagon/cfi_tgts.S b/tests/tcg/hexagon/cfi_tgts.S
new file mode 100644
index 00000000000..e8752e17741
--- /dev/null
+++ b/tests/tcg/hexagon/cfi_tgts.S
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+    .text
+valid_tgt:
+    .word 0x7f80c000 /* nop_rb */
+    jumpr r2
+
+invalid_tgt:
+    nop
+    jumpr r2
+
+valid_call_tgt:
+    .word 0x7f80c000 /* nop_rb */
+    jumpr r31
+
+invalid_call_tgt:
+    nop
+    jumpr r31
+
+.macro set_pred reg, id
+    r4 = \id
+    r3 = xor(\reg, r4)
+    p0 = !cmp.eq(r3, #0)
+.endm
+
+.macro set_pred_in_packet reg, id
+    r4 = \id
+    r3 = xor(\reg, r4)
+    r3 = #0
+    .word 0x75034010 /* { p0 = !cmp.eq(r3, #0) */
+.endm
+
+/*
+ * r0: nonzero for a valid target, zero for an invalid target
+ * r1: test case number
+ */
+.global run_test_case
+run_test_case:
+    p1 = cmp.eq(r0, #1)
+    if (p1) r0 = #valid_tgt
+    if (!p1) r0 = #invalid_tgt
+    r2 = #return
+
+    set_pred r1, #0
+    .word 0x53e0c000 /* if (!p0) jumpr_rb:nt r0 */
+
+    set_pred r1, #1
+    .word 0x53e0d000 /* if (!p0) jumpr_rb:t r0 */
+
+    set_pred_in_packet r1, #2
+    .word 0x53e0c800 /* if (!p0.new) jumpr_rb:nt r0 } */
+
+    set_pred_in_packet r1, #3
+    .word 0x53e0d800 /* if (!p0.new) jumpr_rb:t r0 } */
+
+    p0 = cmp.eq(r1, #4)
+    .word 0x53c0c000 /* if (p0) jumpr_rb:nt r0 */
+
+    p0 = cmp.eq(r1, #5)
+    .word 0x53c0d000 /* if (p0) jumpr_rb:t r0 */
+
+    .word 0x750140c0 /* { p0 = cmp.eq(r1, #6) */
+    .word 0x53c0c800 /* if (p0.new) jumpr_rb:nt r0 } */
+
+    .word 0x750140e0 /* { p0 = cmp.eq(r1, #7) */
+    .word 0x53c0d800 /* if (p0.new) jumpr_rb:t r0 } */
+
+    p0 = cmp.eq(r1, #9)
+    if (p0) jump callr_case
+    p0 = cmp.eq(r1, #10)
+    if (p0) jump callrh_case
+    p0 = cmp.eq(r1, #11)
+    if (p0) jump callrt_case
+    p0 = cmp.eq(r1, #12)
+    if (p0) jump callrf_case
+
+    .word 0x5200c000 /* jumpr_rb r0 */
+
+callr_case:
+    if (p1) r0 = #valid_call_tgt
+    if (!p1) r0 = #invalid_call_tgt
+    .word 0x5020c000 /* callr_rb r0 */
+    jump return
+
+callrh_case:
+    if (p1) r0 = #valid_call_tgt
+    if (!p1) r0 = #invalid_call_tgt
+    .word 0x5040c000 /* callrh_rb r0 */
+    jump return
+
+callrt_case:
+    if (p1) r0 = #valid_call_tgt
+    if (!p1) r0 = #invalid_call_tgt
+    p0 = cmp.eq(r0, r0)
+    .word 0x5180c000 /* if (p0) callr_rb r0 */
+    jump return
+
+callrf_case:
+    if (p1) r0 = #valid_call_tgt
+    if (!p1) r0 = #invalid_call_tgt
+    p0 = cmp.eq(r0, #0)
+    .word 0x51a0c000 /* if (!p0) callr_rb r0 */
+    jump return
+
+return:
+    jumpr r31
+
+/* jumpr_rb r31 is a return, not a restricted branch. */
+.global run_jumpr_rb_lr_test
+run_jumpr_rb_lr_test:
+    .word 0x521fc000 /* jumpr_rb r31 */
+
+/*
+ * callr_rb r31 remains restricted: it must branch to a landing pad even
+ * though it overwrites r31 with its return address.
+ */
+.global run_callr_rb_lr_test
+run_callr_rb_lr_test:
+    r2 = r31
+    p0 = cmp.eq(r0, #1)
+    if (p0) r31 = #valid_callr_rb_lr_tgt
+    if (!p0) r31 = #invalid_callr_rb_lr_tgt
+    .word 0x503fc000 /* callr_rb r31 */
+    jumpr r2
+
+valid_callr_rb_lr_tgt:
+    .word 0x7f80c000 /* nop_rb */
+    jumpr r31
+
+invalid_callr_rb_lr_tgt:
+    nop
+    jumpr r31
+
+/*
+ * Enter each restricted allocframe instruction with CFI active.  The
+ * following ordinary instructions show that the restricted target reset it.
+ */
+.global run_allocframe_test
+run_allocframe_test:
+    r0 = #allocframe_rb_reg
+    r2 = #allocframe_rb_duplex
+    .word 0x5200c000 /* jumpr_rb r0 */
+
+allocframe_rb_reg:
+    .word 0xa09de000 /* allocframe_rb(r29, #0):raw */
+    deallocframe
+    nop
+    jumpr r2
+
+allocframe_rb_duplex:
+    .word 0x70003e00 /* r0 = r0; allocframe_rb(#0) */
+    deallocframe
+    nop
+    jumpr r31
diff --git a/tests/tcg/hexagon/meson.build b/tests/tcg/hexagon/meson.build
index a6ace4c77c2..0446fabb29f 100644
--- a/tests/tcg/hexagon/meson.build
+++ b/tests/tcg/hexagon/meson.build
@@ -25,8 +25,15 @@ foreach t: tcg_tests['multiarch-linux-user']['tests']
 endforeach
 
 tests += {
-  'atomics.c': {'cflags': cflags},
+  # The cross assembler does not know v85; v85 instructions in atomics.c
+  # are encoded with .word directives.
+  'atomics.c': {'cflags': cflags, 'qemu_args': ['-cpu', 'v85']},
   'brev.c': {'cflags': cflags},
+  # The cross assembler does not know v83; cfi_tgts.S uses raw encodings.
+  'cfi_user.c': {
+    'cflags': [cflags, '-O0', files('cfi_tgts.S')],
+    'qemu_args': ['-cpu', 'v85'],
+  },
   # Compile for v66 so that the ELF selects a v66 CPU; the test then
   # exercises revision gating by executing a v68 .word instruction.
   'check_rev_gating.c': {
@@ -57,7 +64,7 @@ tests += {
     'cflags': [cflags, '-mhvx', '-Wno-gnu-folding-constant',
                files('hvx_histogram_row.S')]
   },
-  'invalid-encoding.c': {'cflags': cflags},
+  'invalid-encoding.c': {'cflags': cflags, 'qemu_args': ['-cpu', 'v85']},
   'invalid-slots.c': {'cflags': cflags},
   'icinva.c': {'cflags': cflags},
   'load_align.c': {'cflags': cflags},
@@ -106,6 +113,8 @@ tests += {
   'test_vpmpyh.S': {'cflags': asmflags},
   'test_vspliceb.S': {'cflags': asmflags},
   'test_vwhist.c': {'cflags': [cflags, '-mhvx']},
+  # The cross assembler does not know trap2; the test uses its raw encoding.
+  'trap2.c': {'cflags': cflags, 'qemu_args': ['-cpu', 'v85']},
   'unaligned_pc.c': {'cflags': cflags},
   'unaligned_data.c': {'cflags': cflags},
   'usr.c': {
@@ -117,6 +126,12 @@ tests += {
   'v69_hvx.c': {'cflags': [cflags, '-mhvx', '-Wno-unused-function', '-mv69']},
   'v73_scalar.c': {'cflags': [cflags, '-Wno-unused-function', '-mv73']},
   'v79_scalar.c': {'cflags': [cflags, '-Wno-unused-function', '-mv79']},
+  'v83_scalar_fp.c': {'cflags': [cflags, '-mv67'],
+                      'qemu_args': ['-cpu', 'v85']},
+  # The cross assembler does not know v83; the vallocframe instructions in
+  # this test are encoded with .word directives.
+  'vallocframe.c': {'cflags': [cflags, '-mv67', '-O2'],
+                    'qemu_args': ['-cpu', 'v85']},
   'valid-slots.c': {'cflags': cflags},
   'vector_add_int.c': {'cflags': [cflags, '-mhvx', '-fvectorize']},
 }
-- 
2.34.1

Reply via email to