[FFmpeg-devel] [PATCH] checkasm: RISC-V 64-bit assembler test harness

Rémi Denis-Courmont remi at remlab.net
Thu Oct 6 22:15:41 EEST 2022


---
 tests/checkasm/Makefile         |   1 +
 tests/checkasm/checkasm.h       |  10 ++
 tests/checkasm/riscv/checkasm.S | 178 ++++++++++++++++++++++++++++++++
 3 files changed, 189 insertions(+)
 create mode 100644 tests/checkasm/riscv/checkasm.S

diff --git a/tests/checkasm/Makefile b/tests/checkasm/Makefile
index f330d3a8ab..62d6616faf 100644
--- a/tests/checkasm/Makefile
+++ b/tests/checkasm/Makefile
@@ -63,6 +63,7 @@ CHECKASMOBJS-$(CONFIG_AVUTIL)  += $(AVUTILOBJS)
 
 CHECKASMOBJS-$(ARCH_AARCH64)            += aarch64/checkasm.o
 CHECKASMOBJS-$(HAVE_ARMV5TE_EXTERNAL)   += arm/checkasm.o
+CHECKASMOBJS-$(ARCH_RISCV)              += riscv/checkasm.o
 CHECKASMOBJS-$(HAVE_X86ASM)             += x86/checkasm.o
 
 CHECKASMOBJS += $(CHECKASMOBJS-yes) checkasm.o
diff --git a/tests/checkasm/checkasm.h b/tests/checkasm/checkasm.h
index 97e909170f..ee9151410e 100644
--- a/tests/checkasm/checkasm.h
+++ b/tests/checkasm/checkasm.h
@@ -203,6 +203,16 @@ void checkasm_checked_call(void *func, ...);
                                               CLOB,CLOB,CLOB,CLOB,CLOB,CLOB,CLOB,CLOB,CLOB,CLOB,CLOB),\
                       checked_call(func_new, 0, 0, 0, 0, 0, 0, 0, __VA_ARGS__,\
                                    7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0))
+#elif ARCH_RISCV
+void checkasm_set_function(void *);
+void *checkasm_get_wrapper(void);
+
+#if (__riscv_xlen == 64) && defined (__riscv_d)
+#define declare_new(ret, ...) \
+    ret (*checked_call)(__VA_ARGS__) = checkasm_get_wrapper();
+#define call_new(...) \
+    (checkasm_set_function(func_new), checked_call(__VA_ARGS__))
+#endif
 #else
 #define declare_new(ret, ...)
 #define declare_new_float(ret, ...)
diff --git a/tests/checkasm/riscv/checkasm.S b/tests/checkasm/riscv/checkasm.S
new file mode 100644
index 0000000000..73ca85f344
--- /dev/null
+++ b/tests/checkasm/riscv/checkasm.S
@@ -0,0 +1,178 @@
+/****************************************************************************
+ * Copyright © 2022 Rémi Denis-Courmont.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+#include "libavutil/riscv/asm.S"
+
+#if (__riscv_xlen == 64)
+
+const fail_s_reg
+        .asciz  "callee-saved integer register clobbered"
+endconst
+
+const fail_fs_reg
+        .asciz  "callee-saved floating-point register clobbered"
+endconst
+
+const fail_rsvd_reg
+        .asciz  "unallocatable register clobbered"
+endconst
+
+        .section .tbss, "waT"
+        .align  3
+        .hidden checked_func
+        .hidden saved_regs
+
+checked_func:
+        .quad   0
+
+saved_regs:
+        /* Space to spill RA, SP, GP, TP, S0-S11 and FS0-FS11 */
+        .rept   4 + 12 + 12
+        .quad   0
+        .endr
+
+func checkasm_set_function
+        la.tls.ie t0, checked_func
+        add     t0, tp, t0
+        sd      a0, (t0)
+        ret
+endfunc
+
+func checkasm_get_wrapper, v
+        addi    sp, sp, -16
+        sd      fp,  (sp)
+        sd      ra, 8(sp)
+        addi    fp, sp, 16
+
+        call    av_get_cpu_flags
+        andi    t0, a0, 8 /* AV_CPU_FLAG_RVV_I32 */
+
+        lla     a0, 3f
+        beqz    t0, 1f
+        lla     a0, 2f
+1:
+        ld      ra, 8(sp)
+        ld      fp,  (sp)
+        addi    sp, sp, 16
+        ret
+
+2:      /* <-- Entry point with the Vector extension --> */
+        /* Clobber the vectors */
+        vsetvli t0, zero, e32, m8, ta, ma
+        li      t0, 0xdeadbeef
+        vmv.v.x v0, t0
+        vmv.v.x v8, t0
+        vmv.v.x v16, t0
+        vmv.v.x v24, t0
+
+        /* Clobber the vector configuration */
+        li      t0, 0        /* Vector length: zero */
+        li      t1, -1 << 31 /* Vector type:   illegal */
+        vsetvl  zero, t0, t1
+        csrwi   vxrm, 3      /* Rounding mode: round-to-odd */
+        csrwi   vxsat, 1     /* Saturation:    encountered */
+
+3:      /* <-- Entry point without the Vector extension --> */
+        /* Save RA, unallocatable and callee-saved registers */
+        la.tls.ie t0, saved_regs
+        add     t0, tp, t0
+        sd      ra,   (t0)
+        sd      sp,  8(t0)
+        sd      gp, 16(t0)
+        sd      tp, 24(t0)
+        .irp    n, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+        sd      s\n, (32 + (16 * \n))(t0)
+        fsd     fs\n, (40 + (16 * \n))(t0)
+        .endr
+
+        /* Clobber the stack space right below SP */
+        li      t0, 0xdeadbeef1badf00d
+        .rept   16
+        addi    sp, sp, -16
+        sd      t0,  (sp)
+        sd      t0, 8(sp)
+        .endr
+        addi    sp, sp, 256
+
+        /* Clobber the saved and temporary registers */
+        .irp    n, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+        .if (\n > 0 && \n < 7)
+        mv      t\n, t0
+        .endif
+        fmv.d.x ft\n, t0
+        mv      s\n, t0
+        fmv.d.x fs\n, t0
+        .endr
+
+        /* Call the tested function */
+        la.tls.ie t0, checked_func
+        add     t0, tp, t0
+        ld      t1, (t0)
+        sd      zero, (t0)
+        jalr    t1
+
+        /* Check special register values */
+        la.tls.ie t0, saved_regs
+        add     t0, tp, t0
+        ld      t1,  8(t0)
+        bne     t1, sp, 5f
+        ld      t1, 16(t0)
+        bne     t1, gp, 5f
+        ld      t1, 24(t0) // If TP was corrupted, we probably will have...
+        bne     t1, tp, 5f // ...already crashed before we even get here.
+
+        /* Check value of saved registers */
+        li      t0, 0xdeadbeef1badf00d
+        .irp    n, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+        bne     t0, s\n, 6f
+#ifdef __riscv_float_abi_double
+        /* TODO: check float ABI single too */
+        fmv.x.d t1, fs\n
+        bne     t0, t1, 7f
+#endif
+        .endr
+
+4:
+        /* Restore RA and saved registers */
+        la.tls.ie t0, saved_regs
+        add     t0, tp, t0
+        ld      ra,   (t0)
+        .irp    n, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+        ld      s\n, (32 + (16 * \n))(t0)
+        fld     fs\n, (40 + (16 * \n))(t0)
+        .endr
+        ret
+
+5:
+        lla     a0, fail_rsvd_reg
+        call    checkasm_fail_func
+        tail    abort /* The test harness would probably crash anyway */
+
+6:
+        lla     a0, fail_s_reg
+        call    checkasm_fail_func
+        j       4b
+
+7:
+        lla     a0, fail_fs_reg
+        call    checkasm_fail_func
+        j       4b
+endfunc
+#endif
-- 
2.37.2



More information about the ffmpeg-devel mailing list