Re: [PATCH v2 1/2] target/sh4: add tests for sh4 fipr and ftrv instructions

[email protected] Thu, 30 Jul 2026 21:23:38 +0900
Newsgroups org.nongnu.qemu-trivial,org.nongnu.qemu-devel
Message-ID <[email protected]>
On Thu, 30 Jul 2026 05:45:05 +0900,
Randy Schifflin wrote:
> 
> Add tests for the TCG generation of the sh4-specific `fipr`
> and `ftrv` instructions.
> 
> Signed-off-by: Randy Schifflin <[email protected]>
> ---
>  tests/tcg/sh4/Makefile.target |   7 +++
>  tests/tcg/sh4/test-fpu-fipr.c |  72 ++++++++++++++++++++++++++++
>  tests/tcg/sh4/test-fpu-ftrv.c | 108 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 187 insertions(+)
> 
> diff --git a/tests/tcg/sh4/Makefile.target b/tests/tcg/sh4/Makefile.target
> index b7a8737be0..0975fac72d 100644
> --- a/tests/tcg/sh4/Makefile.target
> +++ b/tests/tcg/sh4/Makefile.target
> @@ -16,3 +16,10 @@ TESTS += test-addv
>  
>  test-subv: CFLAGS += -O -g
>  TESTS += test-subv
> +
> +test-fpu-fipr: CFLAGS += -O -g
> +TESTS += test-fpu-fipr
> +
> +test-fpu-ftrv: CFLAGS += -O -g
> +TESTS += test-fpu-ftrv
> +
> diff --git a/tests/tcg/sh4/test-fpu-fipr.c b/tests/tcg/sh4/test-fpu-fipr.c
> new file mode 100644
> index 0000000000..1bf1a1b4ec
> --- /dev/null
> +++ b/tests/tcg/sh4/test-fpu-fipr.c
> @@ -0,0 +1,72 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +
> +#include <limits.h>
> +#include <stdlib.h>
> +static const unsigned long FPSCR_PR_BIT = 1UL << 19;
> +
> +static void single_precision_mode(void)
> +{
> +    unsigned long fpscr;
> +    /* Read FPSCR register */
> +    asm volatile("sts fpscr, %0" : "=r" (fpscr));
> +    /* Set precision mode to single-precision */
> +    fpscr &= ~FPSCR_PR_BIT;
> +    /* Write FPSCR register */
> +    asm volatile("lds %0, fpscr" : : "r" (fpscr));
> +}
> +
> +static float fipr(const float v1[4], const float v2[4])
> +{
> +    float fout = 0.0;
> +    /*
> +     * Perform inner product of fv4 and fv8
> +     * Result is stored in the last float register of the last vector argument
> +     */
> +    asm volatile(
> +        "fmov %1,fr4\n"
> +        "fmov %2,fr5\n"
> +        "fmov %3,fr6\n"
> +        "fmov %4,fr7\n"
> +        "fmov %5,fr8\n"
> +        "fmov %6,fr9\n"
> +        "fmov %7,fr10\n"
> +        "fmov %8,fr11\n"
> +        "fipr fv4,fv8\n" /* (fr4,fr5,fr6,fr7) dot (fr8,fr9,fr10,fr11) */
> +        "fmov fr11,%0\n" /* Result in fr11 */
> +        : "=f" (fout)
> +        : "f" (v1[0]), "f" (v1[1]), "f" (v1[2]), "f" (v1[3]),
> +          "f" (v2[0]), "f" (v2[1]), "f" (v2[2]), "f" (v2[3]));
> +    return fout;
> +}
> +
> +int main(void)
> +{
> +    /*
> +     * The SH4 manual specifies `fipr` is only available when
> +     * FPSCR register precision-mode (PR) bit is 0
> +     */
> +    single_precision_mode();
> +
> +    float v1[4] = {1.0, 0.0, 0.0, 0.0};
> +    float mag_sq = 0.0;
> +    float dot = 0.0;
> +
> +    mag_sq = fipr(v1, v1);
> +    if (mag_sq != 1.0) {
> +        abort();
> +    }
> +
> +    v1[0] = 2.0;
> +    mag_sq = fipr(v1, v1);
> +    if (mag_sq != 4.0) {
> +        abort();
> +    }
> +
> +    float v2[4] = {1.0, 0.0, 0.0, 0.0};
> +    dot = fipr(v1, v2);
> +    if (dot != 2.0) {
> +        abort();
> +    }
> +
> +    return 0;
> +}
> diff --git a/tests/tcg/sh4/test-fpu-ftrv.c b/tests/tcg/sh4/test-fpu-ftrv.c
> new file mode 100644
> index 0000000000..041e03120e
> --- /dev/null
> +++ b/tests/tcg/sh4/test-fpu-ftrv.c
> @@ -0,0 +1,108 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +
> +#include <limits.h>
> +#include <stdlib.h>
> +static const unsigned long FPSCR_PR_BIT = 1UL << 19;
> +
> +static void single_precision_mode(void)
> +{
> +    unsigned long fpscr;
> +    /* Read FPSCR register */
> +    asm volatile("sts fpscr, %0" : "=r" (fpscr));
> +    /* Set precision mode to single-precision */
> +    fpscr &= ~FPSCR_PR_BIT;
> +    /* Write FPSCR register */
> +    asm volatile("lds %0, fpscr" : : "r" (fpscr));
> +}
> +
> +/* Set XMTRX registers to a doubling scale matrix */
> +static void xmtrx_scale_2(void)
> +{
> +    asm volatile(
> +        "fldi0 fr0\n" /* Pair dr0 (fr0, fr1) = zero,zero */
> +        "fldi0 fr1\n"
> +        "fldi1 fr2\n"
> +        "fadd fr2,fr2\n" /* Pair dr2 (fr2,fr3) = two,zero */
> +        "fldi0 fr3\n"
> +        "fldi0 fr4\n"
> +        "fmov fr2,fr5\n" /* Pair dr4 (fr4, fr5) = zero,two */
> +
> +        /* Enable pair-write */
> +        "fschg\n"
> +        /* matrix[0][0] = 2.0 */
> +        /* matrix[0][1] = 0.0 */
> +        "fmov dr2,xd0\n"
> +        /* matrix[0][2] = 0.0 */
> +        /* matrix[0][3] = 0.0 */
> +        "fmov dr0,xd2\n"
> +        /* matrix[1][0] = 0.0 */
> +        /* matrix[1][1] = 2.0 */
> +        "fmov dr4,xd4\n"
> +        /* matrix[1][2] = 0.0 */
> +        /* matrix[1][3] = 0.0 */
> +        "fmov dr0,xd6\n"
> +        /* matrix[2][0] = 0.0 */
> +        /* matrix[2][1] = 0.0 */
> +        "fmov dr0,xd8\n"
> +        /* matrix[2][2] = 2.0 */
> +        /* matrix[2][3] = 0.0 */
> +        "fmov dr2,xd10\n"
> +        /* matrix[3][0] = 0.0 */
> +        /* matrix[3][1] = 0.0 */
> +        "fmov dr0,xd12\n"
> +        /* matrix[3][2] = 0.0 */
> +        /* matrix[3][3] = 2.0 */
> +        "fmov dr4,xd14\n"
> +        /* Disable pair-write */
> +        "fschg"
> +        :
> +        :
> +        : "fr0", "fr1", "fr2", "fr3", "fr4", "fr5");
> +}
> +
> +/* Transform vector vin by xmtrx; store result in vector vout */
> +static void ftrv(const float vin[4], float vout[4])
> +{
> +    asm volatile("fmov %4,fr0\n"
> +                 "fmov %5,fr1\n"
> +                 "fmov %6,fr2\n"
> +                 "fmov %7,fr3\n"
> +                 "ftrv xmtrx,fv0\n"
> +                 "fmov fr0,%0\n"
> +                 "fmov fr1,%1\n"
> +                 "fmov fr2,%2\n"
> +                 "fmov fr3,%3"
> +                 : "=f" (vout[0]), "=f" (vout[1]),
> +                   "=f" (vout[2]), "=f" (vout[3])
> +                 : "f" (vin[0]), "f" (vin[1]),
> +                   "f" (vin[2]), "f" (vin[3])
> +                 : "fr0", "fr1", "fr2", "fr3");
> +}
> +
> +int main(void)
> +{
> +    /*
> +     * The SH4 manual specifies `ftrv` is only available when
> +     * FPSCR register precision-mode (PR) bit is 0
> +     */
> +    single_precision_mode();
> +    xmtrx_scale_2();
> +    float vin[4] = {1.0, 2.0, 3.0, 4.0};
> +    float vout[4] = { 0.0, 0.0, 0.0, 0.0};
> +
> +    ftrv(vin, vout);
> +    if (vout[0] != 2.0) {
> +        abort();
> +    }
> +    if (vout[1] != 4.0) {
> +        abort();
> +    }
> +    if (vout[2] != 6.0) {
> +        abort();
> +    }
> +    if (vout[3] != 8.0) {
> +        abort();
> +    }
> +
> +    return 0;
> +}
> 
> -- 
> 2.43.0
> 

Reviewed-by: Yoshinori Sato <[email protected]>

-- 
Yosinori Sato