Test conditional callr, compound tstbit0-and-jump instructions and endloop01. These exercise previously uncovered branch paths in translate.c.
Reviewed-by: Pierrick Bouvier <[email protected]> Signed-off-by: Brian Cain <[email protected]> --- tests/tcg/hexagon/test_cond_branch.c | 162 +++++++++++++++++++++++++++ tests/tcg/hexagon/meson.build | 1 + 2 files changed, 163 insertions(+) create mode 100644 tests/tcg/hexagon/test_cond_branch.c diff --git a/tests/tcg/hexagon/test_cond_branch.c b/tests/tcg/hexagon/test_cond_branch.c new file mode 100644 index 00000000000..73be8fbb43c --- /dev/null +++ b/tests/tcg/hexagon/test_cond_branch.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +/* + * Test conditional calls, compound testbit0-and-jump instructions, + * and endloop01 (dual hardware loop end). + */ + +#include <stdio.h> +#include <stdint.h> + +int err; + +#include "hex_test.h" + +/* Target function for conditional calls */ +static int call_target_val; + +__attribute__((noinline)) +static void call_target(void) +{ + call_target_val = 42; +} + +/* + * Test conditional call: if (Pu) callr Rs / if (!Pu) callr Rs + */ +static void check_cond_call(void) +{ + void (*fn)(void) = call_target; + + /* + * callr clobbers all caller-saved registers. + * Hexagon caller-saved: r0-r5, r14-r15, r28, p0-p3. + */ + + /* if (p0) callr Rs -- predicate true */ + call_target_val = 0; + asm volatile("p0 = cmp.eq(%[one], %[one])\n\t" /* p0 = true */ + "if (p0) callr %[fn]\n\t" + : + : [one] "r"(1), [fn] "r"(fn) + : "r0", "r1", "r2", "r3", "r4", "r5", + "r14", "r15", "r28", "r31", + "p0", "p1", "p2", "p3", "memory"); + check32(call_target_val, 42); + + /* if (!p0) callr Rs -- predicate true, so !p0 is false */ + call_target_val = 0; + asm volatile("p0 = cmp.eq(%[one], %[one])\n\t" /* p0 = true */ + "if (!p0) callr %[fn]\n\t" + : + : [one] "r"(1), [fn] "r"(fn) + : "r0", "r1", "r2", "r3", "r4", "r5", + "r14", "r15", "r28", "r31", + "p0", "p1", "p2", "p3", "memory"); + check32(call_target_val, 0); + + /* if (!p0) callr Rs -- predicate false, so !p0 is true */ + call_target_val = 0; + asm volatile("p0 = cmp.eq(%[a], %[b])\n\t" /* p0 = false (1 != 2) */ + "if (!p0) callr %[fn]\n\t" + : + : [a] "r"(1), [b] "r"(2), [fn] "r"(fn) + : "r0", "r1", "r2", "r3", "r4", "r5", + "r14", "r15", "r28", "r31", + "p0", "p1", "p2", "p3", "memory"); + check32(call_target_val, 42); +} + +/* + * Test compound testbit0-and-jump. + * p0 = tstbit(Rs, #0); if ([!]p0.new) jump:t/nt target + */ +static void check_tstbit0_jump(void) +{ + uint32_t result; + + /* Rs has bit0 = 1, test "if (p0.new) jump" -> should jump */ + result = 0; + asm volatile( + "{\n\t" + " p0 = tstbit(%[val], #0)\n\t" + " if (p0.new) jump:t 1f\n\t" + "}\n\t" + "%[res] = #0\n\t" + "jump 2f\n\t" + "1:\n\t" + "%[res] = #1\n\t" + "2:\n\t" + : [res] "=r"(result) + : [val] "r"(0x5) /* bit 0 is set */ + : "p0"); + check32(result, 1); + + /* Rs has bit0 = 0, test "if (p0.new) jump" -> should NOT jump */ + result = 0; + asm volatile( + "{\n\t" + " p0 = tstbit(%[val], #0)\n\t" + " if (p0.new) jump:t 1f\n\t" + "}\n\t" + "%[res] = #0\n\t" + "jump 2f\n\t" + "1:\n\t" + "%[res] = #1\n\t" + "2:\n\t" + : [res] "=r"(result) + : [val] "r"(0x4) /* bit 0 is clear */ + : "p0"); + check32(result, 0); + + /* Rs has bit0 = 0, test "if (!p0.new) jump" -> should jump */ + result = 0; + asm volatile( + "{\n\t" + " p0 = tstbit(%[val], #0)\n\t" + " if (!p0.new) jump:t 1f\n\t" + "}\n\t" + "%[res] = #0\n\t" + "jump 2f\n\t" + "1:\n\t" + "%[res] = #1\n\t" + "2:\n\t" + : [res] "=r"(result) + : [val] "r"(0x4) /* bit 0 is clear */ + : "p0"); + check32(result, 1); +} + +/* + * Test endloop01: a packet that terminates both loop0 and loop1. + * Outer loop runs 3 iterations, inner loop runs 4. + */ +static void check_endloop01(void) +{ + uint32_t count; + + asm volatile( + "%[cnt] = #0\n\t" + "loop1(1f, #3)\n\t" /* outer loop: 3 iterations */ + "1:\n\t" + "loop0(2f, #4)\n\t" /* inner loop: 4 iterations */ + "2:\n\t" + "{ %[cnt] = add(%[cnt], #1) }:endloop01\n\t" + : [cnt] "=r"(count)); + + /* 3 outer * 4 inner = 12 total iterations */ + check32(count, 12); +} + +int main(void) +{ + check_cond_call(); + check_tstbit0_jump(); + check_endloop01(); + + puts(err ? "FAIL" : "PASS"); + return err ? 1 : 0; +} diff --git a/tests/tcg/hexagon/meson.build b/tests/tcg/hexagon/meson.build index 6935d02802b..6074e56f6d6 100644 --- a/tests/tcg/hexagon/meson.build +++ b/tests/tcg/hexagon/meson.build @@ -73,6 +73,7 @@ tests += { 'test_call.S': {'cflags': asmflags}, 'test_clobber.S': {'cflags': asmflags}, 'test_cmp.S': {'cflags': asmflags}, + 'test_cond_branch.c': {'cflags': cflags}, 'test_dotnew.S': {'cflags': asmflags}, 'test_ext.S': {'cflags': asmflags}, 'test_fibonacci.S': {'cflags': asmflags}, -- 2.34.1
