aboutsummaryrefslogtreecommitdiff
path: root/tests/tcg/ppc64
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2022-09-29 12:42:02 +0100
committerAlex Bennée <alex.bennee@linaro.org>2022-10-06 11:53:40 +0100
commit37b0dba45c4e44a02000a4170f25af0110f501d5 (patch)
treee8099b7134d51aa64be14cc2af845ce91cb21ef6 /tests/tcg/ppc64
parent6ffe81370aab511f438ece256977def804f9b6e2 (diff)
downloadqemu-37b0dba45c4e44a02000a4170f25af0110f501d5.zip
qemu-37b0dba45c4e44a02000a4170f25af0110f501d5.tar.gz
qemu-37b0dba45c4e44a02000a4170f25af0110f501d5.tar.bz2
tests/tcg: unify ppc64 and ppc64le Makefiles
Make tests/tcg/ppc64le include tests/tcg/ppc64 instead of duplicating the rules. Because the ppc64le vpath includes tests/tcg/ppc64 but not vice versa, the tests have to be moved from tests/tcg/ppc64le/ to tests/tcg/ppc64. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-Id: <20220929114231.583801-23-alex.bennee@linaro.org>
Diffstat (limited to 'tests/tcg/ppc64')
-rw-r--r--tests/tcg/ppc64/Makefile.target1
-rw-r--r--tests/tcg/ppc64/bcdsub.c134
-rw-r--r--tests/tcg/ppc64/byte_reverse.c21
-rw-r--r--tests/tcg/ppc64/mffsce.c37
-rw-r--r--tests/tcg/ppc64/mtfsf.c60
-rw-r--r--tests/tcg/ppc64/non_signalling_xscv.c37
-rw-r--r--tests/tcg/ppc64/signal_save_restore_xer.c42
-rw-r--r--tests/tcg/ppc64/xxspltw.c46
8 files changed, 377 insertions, 1 deletions
diff --git a/tests/tcg/ppc64/Makefile.target b/tests/tcg/ppc64/Makefile.target
index 331fae6..7db7a3e 100644
--- a/tests/tcg/ppc64/Makefile.target
+++ b/tests/tcg/ppc64/Makefile.target
@@ -3,7 +3,6 @@
# ppc64 specific tweaks
VPATH += $(SRC_PATH)/tests/tcg/ppc64
-VPATH += $(SRC_PATH)/tests/tcg/ppc64le
ifneq ($(CROSS_CC_HAS_POWER8_VECTOR),)
PPC64_TESTS=bcdsub non_signalling_xscv
diff --git a/tests/tcg/ppc64/bcdsub.c b/tests/tcg/ppc64/bcdsub.c
new file mode 100644
index 0000000..87c8c44
--- /dev/null
+++ b/tests/tcg/ppc64/bcdsub.c
@@ -0,0 +1,134 @@
+#include <assert.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdint.h>
+
+#define CRF_LT (1 << 3)
+#define CRF_GT (1 << 2)
+#define CRF_EQ (1 << 1)
+#define CRF_SO (1 << 0)
+#define UNDEF 0
+
+#ifdef __has_builtin
+#if !__has_builtin(__builtin_bcdsub)
+#define NO_BUILTIN_BCDSUB
+#endif
+#endif
+
+#ifdef NO_BUILTIN_BCDSUB
+#define BCDSUB(T, A, B, PS) \
+ ".long 4 << 26 | (" #T ") << 21 | (" #A ") << 16 | (" #B ") << 11" \
+ " | 1 << 10 | (" #PS ") << 9 | 65\n\t"
+#else
+#define BCDSUB(T, A, B, PS) "bcdsub. " #T ", " #A ", " #B ", " #PS "\n\t"
+#endif
+
+#define TEST(AH, AL, BH, BL, PS, TH, TL, CR6) \
+ do { \
+ int cr = 0; \
+ uint64_t th, tl; \
+ /* \
+ * Use GPR pairs to load the VSR values and place the resulting VSR and\
+ * CR6 in th, tl, and cr. Note that we avoid newer instructions (e.g., \
+ * mtvsrdd/mfvsrld) so we can run this test on POWER8 machines. \
+ */ \
+ asm ("mtvsrd 32, %3\n\t" \
+ "mtvsrd 33, %4\n\t" \
+ "xxmrghd 32, 32, 33\n\t" \
+ "mtvsrd 33, %5\n\t" \
+ "mtvsrd 34, %6\n\t" \
+ "xxmrghd 33, 33, 34\n\t" \
+ BCDSUB(0, 0, 1, PS) \
+ "mfocrf %0, 0b10\n\t" \
+ "mfvsrd %1, 32\n\t" \
+ "xxswapd 32, 32\n\t" \
+ "mfvsrd %2, 32\n\t" \
+ : "=r" (cr), "=r" (th), "=r" (tl) \
+ : "r" (AH), "r" (AL), "r" (BH), "r" (BL) \
+ : "v0", "v1", "v2"); \
+ if (TH != UNDEF || TL != UNDEF) { \
+ assert(tl == TL); \
+ assert(th == TH); \
+ } \
+ assert((cr >> 4) == CR6); \
+ } while (0)
+
+/*
+ * Unbounded result is equal to zero:
+ * sign = (PS) ? 0b1111 : 0b1100
+ * CR6 = 0b0010
+ */
+void test_bcdsub_eq(void)
+{
+ /* maximum positive BCD value */
+ TEST(0x9999999999999999, 0x999999999999999c,
+ 0x9999999999999999, 0x999999999999999c,
+ 0, 0x0, 0xc, CRF_EQ);
+ TEST(0x9999999999999999, 0x999999999999999c,
+ 0x9999999999999999, 0x999999999999999c,
+ 1, 0x0, 0xf, CRF_EQ);
+}
+
+/*
+ * Unbounded result is greater than zero:
+ * sign = (PS) ? 0b1111 : 0b1100
+ * CR6 = (overflow) ? 0b0101 : 0b0100
+ */
+void test_bcdsub_gt(void)
+{
+ /* maximum positive and negative one BCD values */
+ TEST(0x9999999999999999, 0x999999999999999c, 0x0, 0x1d, 0,
+ 0x0, 0xc, (CRF_GT | CRF_SO));
+ TEST(0x9999999999999999, 0x999999999999999c, 0x0, 0x1d, 1,
+ 0x0, 0xf, (CRF_GT | CRF_SO));
+
+ TEST(0x9999999999999999, 0x999999999999998c, 0x0, 0x1d, 0,
+ 0x9999999999999999, 0x999999999999999c, CRF_GT);
+ TEST(0x9999999999999999, 0x999999999999998c, 0x0, 0x1d, 1,
+ 0x9999999999999999, 0x999999999999999f, CRF_GT);
+}
+
+/*
+ * Unbounded result is less than zero:
+ * sign = 0b1101
+ * CR6 = (overflow) ? 0b1001 : 0b1000
+ */
+void test_bcdsub_lt(void)
+{
+ /* positive zero and positive one BCD values */
+ TEST(0x0, 0xc, 0x0, 0x1c, 0, 0x0, 0x1d, CRF_LT);
+ TEST(0x0, 0xc, 0x0, 0x1c, 1, 0x0, 0x1d, CRF_LT);
+
+ /* maximum negative and positive one BCD values */
+ TEST(0x9999999999999999, 0x999999999999999d, 0x0, 0x1c, 0,
+ 0x0, 0xd, (CRF_LT | CRF_SO));
+ TEST(0x9999999999999999, 0x999999999999999d, 0x0, 0x1c, 1,
+ 0x0, 0xd, (CRF_LT | CRF_SO));
+}
+
+void test_bcdsub_invalid(void)
+{
+ TEST(0x0, 0x1c, 0x0, 0xf00, 0, UNDEF, UNDEF, CRF_SO);
+ TEST(0x0, 0x1c, 0x0, 0xf00, 1, UNDEF, UNDEF, CRF_SO);
+
+ TEST(0x0, 0xf00, 0x0, 0x1c, 0, UNDEF, UNDEF, CRF_SO);
+ TEST(0x0, 0xf00, 0x0, 0x1c, 1, UNDEF, UNDEF, CRF_SO);
+
+ TEST(0x0, 0xbad, 0x0, 0xf00, 0, UNDEF, UNDEF, CRF_SO);
+ TEST(0x0, 0xbad, 0x0, 0xf00, 1, UNDEF, UNDEF, CRF_SO);
+}
+
+int main(void)
+{
+ struct sigaction action;
+
+ action.sa_handler = _exit;
+ sigaction(SIGABRT, &action, NULL);
+
+ test_bcdsub_eq();
+ test_bcdsub_gt();
+ test_bcdsub_lt();
+ test_bcdsub_invalid();
+
+ return 0;
+}
diff --git a/tests/tcg/ppc64/byte_reverse.c b/tests/tcg/ppc64/byte_reverse.c
new file mode 100644
index 0000000..53b76fc
--- /dev/null
+++ b/tests/tcg/ppc64/byte_reverse.c
@@ -0,0 +1,21 @@
+#include <assert.h>
+
+int main(void)
+{
+ unsigned long var;
+
+ var = 0xFEDCBA9876543210;
+ asm("brh %0, %0" : "+r"(var));
+ assert(var == 0xDCFE98BA54761032);
+
+ var = 0xFEDCBA9876543210;
+ asm("brw %0, %0" : "+r"(var));
+ assert(var == 0x98BADCFE10325476);
+
+ var = 0xFEDCBA9876543210;
+ asm("brd %0, %0" : "+r"(var));
+ assert(var == 0x1032547698BADCFE);
+
+ return 0;
+}
+
diff --git a/tests/tcg/ppc64/mffsce.c b/tests/tcg/ppc64/mffsce.c
new file mode 100644
index 0000000..20d882c
--- /dev/null
+++ b/tests/tcg/ppc64/mffsce.c
@@ -0,0 +1,37 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+
+#define MTFSF(FLM, FRB) asm volatile ("mtfsf %0, %1" :: "i" (FLM), "f" (FRB))
+#define MFFS(FRT) asm("mffs %0" : "=f" (FRT))
+#define MFFSCE(FRT) asm("mffsce %0" : "=f" (FRT))
+
+#define PPC_BIT_NR(nr) (63 - (nr))
+
+#define FP_VE (1ull << PPC_BIT_NR(56))
+#define FP_UE (1ull << PPC_BIT_NR(58))
+#define FP_ZE (1ull << PPC_BIT_NR(59))
+#define FP_XE (1ull << PPC_BIT_NR(60))
+#define FP_NI (1ull << PPC_BIT_NR(61))
+#define FP_RN1 (1ull << PPC_BIT_NR(63))
+
+int main(void)
+{
+ uint64_t frt, fpscr;
+ uint64_t test_value = FP_VE | FP_UE | FP_ZE |
+ FP_XE | FP_NI | FP_RN1;
+ MTFSF(0b11111111, test_value); /* set test value to cpu fpscr */
+ MFFSCE(frt);
+ MFFS(fpscr); /* read the value that mffsce stored to cpu fpscr */
+
+ /* the returned value should be as the cpu fpscr was before */
+ assert((frt & 0xff) == test_value);
+
+ /*
+ * the cpu fpscr last 3 bits should be unchanged
+ * and enable bits should be unset
+ */
+ assert((fpscr & 0xff) == (test_value & 0x7));
+
+ return 0;
+}
diff --git a/tests/tcg/ppc64/mtfsf.c b/tests/tcg/ppc64/mtfsf.c
new file mode 100644
index 0000000..bed5b1a
--- /dev/null
+++ b/tests/tcg/ppc64/mtfsf.c
@@ -0,0 +1,60 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+#include <signal.h>
+#include <sys/prctl.h>
+
+#define MTFSF(FLM, FRB) asm volatile ("mtfsf %0, %1" :: "i" (FLM), "f" (FRB))
+#define MFFS(FRT) asm("mffs %0" : "=f" (FRT))
+
+#define FPSCR_VE 7 /* Floating-point invalid operation exception enable */
+#define FPSCR_VXSOFT 10 /* Floating-point invalid operation exception (soft) */
+#define FPSCR_FI 17 /* Floating-point fraction inexact */
+
+#define FP_VE (1ull << FPSCR_VE)
+#define FP_VXSOFT (1ull << FPSCR_VXSOFT)
+#define FP_FI (1ull << FPSCR_FI)
+
+void sigfpe_handler(int sig, siginfo_t *si, void *ucontext)
+{
+ if (si->si_code == FPE_FLTINV) {
+ exit(0);
+ }
+ exit(1);
+}
+
+int main(void)
+{
+ uint64_t fpscr;
+
+ struct sigaction sa = {
+ .sa_sigaction = sigfpe_handler,
+ .sa_flags = SA_SIGINFO
+ };
+
+ /*
+ * Enable the MSR bits F0 and F1 to enable exceptions.
+ * This shouldn't be needed in linux-user as these bits are enabled by
+ * default, but this allows to execute either in a VM or a real machine
+ * to compare the behaviors.
+ */
+ prctl(PR_SET_FPEXC, PR_FP_EXC_PRECISE);
+
+ /* First test if the FI bit is being set correctly */
+ MTFSF(0b11111111, FP_FI);
+ MFFS(fpscr);
+ assert((fpscr & FP_FI) != 0);
+
+ /* Then test if the deferred exception is being called correctly */
+ sigaction(SIGFPE, &sa, NULL);
+
+ /*
+ * Although the VXSOFT exception has been chosen, based on test in a Power9
+ * any combination of exception bit + its enabling bit should work.
+ * But if a different exception is chosen si_code check should
+ * change accordingly.
+ */
+ MTFSF(0b11111111, FP_VE | FP_VXSOFT);
+
+ return 1;
+}
diff --git a/tests/tcg/ppc64/non_signalling_xscv.c b/tests/tcg/ppc64/non_signalling_xscv.c
new file mode 100644
index 0000000..836df71
--- /dev/null
+++ b/tests/tcg/ppc64/non_signalling_xscv.c
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <assert.h>
+
+#define TEST(INSN, B_HI, B_LO, T_HI, T_LO) \
+ do { \
+ uint64_t th, tl, bh = B_HI, bl = B_LO; \
+ asm("mtvsrd 32, %2\n\t" \
+ "mtvsrd 33, %3\n\t" \
+ "xxmrghd 32, 32, 33\n\t" \
+ INSN " 32, 32\n\t" \
+ "mfvsrd %0, 32\n\t" \
+ "xxswapd 32, 32\n\t" \
+ "mfvsrd %1, 32\n\t" \
+ : "=r" (th), "=r" (tl) \
+ : "r" (bh), "r" (bl) \
+ : "v0", "v1"); \
+ printf(INSN "(0x%016" PRIx64 "%016" PRIx64 ") = 0x%016" PRIx64 \
+ "%016" PRIx64 "\n", bh, bl, th, tl); \
+ assert(th == T_HI && tl == T_LO); \
+ } while (0)
+
+int main(void)
+{
+ /* SNaN shouldn't be silenced */
+ TEST("xscvspdpn", 0x7fbfffff00000000ULL, 0x0, 0x7ff7ffffe0000000ULL, 0x0);
+ TEST("xscvdpspn", 0x7ff7ffffffffffffULL, 0x0, 0x7fbfffff7fbfffffULL, 0x0);
+
+ /*
+ * SNaN inputs having no significant bits in the upper 23 bits of the
+ * signifcand will return Infinity as the result.
+ */
+ TEST("xscvdpspn", 0x7ff000001fffffffULL, 0x0, 0x7f8000007f800000ULL, 0x0);
+
+ return 0;
+}
diff --git a/tests/tcg/ppc64/signal_save_restore_xer.c b/tests/tcg/ppc64/signal_save_restore_xer.c
new file mode 100644
index 0000000..9227f4f
--- /dev/null
+++ b/tests/tcg/ppc64/signal_save_restore_xer.c
@@ -0,0 +1,42 @@
+#include <assert.h>
+#include <stdint.h>
+#include <signal.h>
+#include <sys/user.h>
+
+#define XER_SO (1 << 31)
+#define XER_OV (1 << 30)
+#define XER_CA (1 << 29)
+#define XER_OV32 (1 << 19)
+#define XER_CA32 (1 << 18)
+
+uint64_t saved;
+
+void sigtrap_handler(int sig, siginfo_t *si, void *ucontext)
+{
+ ucontext_t *uc = ucontext;
+ uc->uc_mcontext.regs->nip += 4;
+ saved = uc->uc_mcontext.regs->xer;
+ uc->uc_mcontext.regs->xer |= XER_OV | XER_OV32;
+}
+
+int main(void)
+{
+ uint64_t initial = XER_CA | XER_CA32, restored;
+ struct sigaction sa = {
+ .sa_sigaction = sigtrap_handler,
+ .sa_flags = SA_SIGINFO
+ };
+
+ sigaction(SIGTRAP, &sa, NULL);
+
+ asm("mtspr 1, %1\n\t"
+ "trap\n\t"
+ "mfspr %0, 1\n\t"
+ : "=r" (restored)
+ : "r" (initial));
+
+ assert(saved == initial);
+ assert(restored == (XER_OV | XER_OV32 | XER_CA | XER_CA32));
+
+ return 0;
+}
diff --git a/tests/tcg/ppc64/xxspltw.c b/tests/tcg/ppc64/xxspltw.c
new file mode 100644
index 0000000..4cff78b
--- /dev/null
+++ b/tests/tcg/ppc64/xxspltw.c
@@ -0,0 +1,46 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <assert.h>
+
+#define WORD_A 0xAAAAAAAAUL
+#define WORD_B 0xBBBBBBBBUL
+#define WORD_C 0xCCCCCCCCUL
+#define WORD_D 0xDDDDDDDDUL
+
+#define DWORD_HI (WORD_A << 32 | WORD_B)
+#define DWORD_LO (WORD_C << 32 | WORD_D)
+
+#define TEST(HI, LO, UIM, RES) \
+ do { \
+ union { \
+ uint64_t u; \
+ double f; \
+ } h = { .u = HI }, l = { .u = LO }; \
+ /* \
+ * Use a pair of FPRs to load the VSR avoiding insns \
+ * newer than xxswapd. \
+ */ \
+ asm("xxmrghd 32, %0, %1\n\t" \
+ "xxspltw 32, 32, %2\n\t" \
+ "xxmrghd %0, 32, %0\n\t" \
+ "xxswapd 32, 32\n\t" \
+ "xxmrghd %1, 32, %1\n\t" \
+ : "+f" (h.f), "+f" (l.f) \
+ : "i" (UIM) \
+ : "v0"); \
+ printf("xxspltw(0x%016" PRIx64 "%016" PRIx64 ", %d) =" \
+ " %016" PRIx64 "%016" PRIx64 "\n", HI, LO, UIM, \
+ h.u, l.u); \
+ assert(h.u == (RES)); \
+ assert(l.u == (RES)); \
+ } while (0)
+
+int main(void)
+{
+ TEST(DWORD_HI, DWORD_LO, 0, WORD_A << 32 | WORD_A);
+ TEST(DWORD_HI, DWORD_LO, 1, WORD_B << 32 | WORD_B);
+ TEST(DWORD_HI, DWORD_LO, 2, WORD_C << 32 | WORD_C);
+ TEST(DWORD_HI, DWORD_LO, 3, WORD_D << 32 | WORD_D);
+ return 0;
+}