summary refs log tree commit diff stats
path: root/tests/tcg
diff options
context:
space:
mode:
Diffstat (limited to 'tests/tcg')
-rw-r--r--tests/tcg/s390x/Makefile.target3
-rw-r--r--tests/tcg/s390x/add-logical-with-carry.c156
-rw-r--r--tests/tcg/s390x/clc.c48
-rw-r--r--tests/tcg/s390x/laalg.c27
4 files changed, 234 insertions, 0 deletions
diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target
index 826f0a18e4..0e670f3f8b 100644
--- a/tests/tcg/s390x/Makefile.target
+++ b/tests/tcg/s390x/Makefile.target
@@ -41,6 +41,9 @@ TESTS+=larl
 TESTS+=mdeb
 TESTS+=cgebra
 TESTS+=clgebr
+TESTS+=clc
+TESTS+=laalg
+TESTS+=add-logical-with-carry
 
 cdsg: CFLAGS+=-pthread
 cdsg: LDFLAGS+=-pthread
diff --git a/tests/tcg/s390x/add-logical-with-carry.c b/tests/tcg/s390x/add-logical-with-carry.c
new file mode 100644
index 0000000000..d982f8a651
--- /dev/null
+++ b/tests/tcg/s390x/add-logical-with-carry.c
@@ -0,0 +1,156 @@
+/*
+ * Test ADD LOGICAL WITH CARRY instructions.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <stdio.h>
+#include <stdlib.h>
+
+static const struct test {
+    const char *name;
+    unsigned long values[3];
+    unsigned long exp_sum;
+    int exp_cc;
+} tests[] = {
+    /*
+     * Each test starts with CC 0 and executes two chained ADD LOGICAL WITH
+     * CARRY instructions on three input values. The values must be compatible
+     * with both 32- and 64-bit test functions.
+     */
+
+    /* NAME       VALUES       EXP_SUM EXP_CC */
+    { "cc0->cc0", {0, 0, 0},   0,      0, },
+    { "cc0->cc1", {0, 0, 42},  42,     1, },
+    /* cc0->cc2 is not possible */
+    /* cc0->cc3 is not possible */
+    /* cc1->cc0 is not possible */
+    { "cc1->cc1", {-3, 1, 1},  -1,     1, },
+    { "cc1->cc2", {-3, 1, 2},  0,      2, },
+    { "cc1->cc3", {-3, 1, -1}, -3,     3, },
+    /* cc2->cc0 is not possible */
+    { "cc2->cc1", {-1, 1, 1},  2,      1, },
+    { "cc2->cc2", {-1, 1, -1}, 0,      2, },
+    /* cc2->cc3 is not possible */
+    /* cc3->cc0 is not possible */
+    { "cc3->cc1", {-1, 2, 1},  3,      1, },
+    { "cc3->cc2", {-1, 2, -2}, 0,      2, },
+    { "cc3->cc3", {-1, 2, -1}, 1,      3, },
+};
+
+/* Test ALCR (register variant) followed by ALC (memory variant). */
+static unsigned long test32rm(unsigned long a, unsigned long b,
+                              unsigned long c, int *cc)
+{
+    unsigned int a32 = a, b32 = b, c32 = c;
+
+    asm("xr %[cc],%[cc]\n"
+        "alcr %[a],%[b]\n"
+        "alc %[a],%[c]\n"
+        "ipm %[cc]"
+        : [a] "+&r" (a32), [cc] "+&r" (*cc)
+        : [b] "r" (b32), [c] "T" (c32)
+        : "cc");
+    *cc >>= 28;
+
+    return (int)a32;
+}
+
+/* Test ALC (memory variant) followed by ALCR (register variant). */
+static unsigned long test32mr(unsigned long a, unsigned long b,
+                              unsigned long c, int *cc)
+{
+    unsigned int a32 = a, b32 = b, c32 = c;
+
+    asm("xr %[cc],%[cc]\n"
+        "alc %[a],%[b]\n"
+        "alcr %[c],%[a]\n"
+        "ipm %[cc]"
+        : [a] "+&r" (a32), [c] "+&r" (c32), [cc] "+&r" (*cc)
+        : [b] "T" (b32)
+        : "cc");
+    *cc >>= 28;
+
+    return (int)c32;
+}
+
+/* Test ALCGR (register variant) followed by ALCG (memory variant). */
+static unsigned long test64rm(unsigned long a, unsigned long b,
+                              unsigned long c, int *cc)
+{
+    asm("xr %[cc],%[cc]\n"
+        "alcgr %[a],%[b]\n"
+        "alcg %[a],%[c]\n"
+        "ipm %[cc]"
+        : [a] "+&r" (a), [cc] "+&r" (*cc)
+        : [b] "r" (b), [c] "T" (c)
+        : "cc");
+    *cc >>= 28;
+    return a;
+}
+
+/* Test ALCG (memory variant) followed by ALCGR (register variant). */
+static unsigned long test64mr(unsigned long a, unsigned long b,
+                              unsigned long c, int *cc)
+{
+    asm("xr %[cc],%[cc]\n"
+        "alcg %[a],%[b]\n"
+        "alcgr %[c],%[a]\n"
+        "ipm %[cc]"
+        : [a] "+&r" (a), [c] "+&r" (c), [cc] "+&r" (*cc)
+        : [b] "T" (b)
+        : "cc");
+    *cc >>= 28;
+    return c;
+}
+
+static const struct test_func {
+    const char *name;
+    unsigned long (*ptr)(unsigned long, unsigned long, unsigned long, int *);
+} test_funcs[] = {
+    { "test32rm", test32rm },
+    { "test32mr", test32mr },
+    { "test64rm", test64rm },
+    { "test64mr", test64mr },
+};
+
+static const struct test_perm {
+    const char *name;
+    size_t a_idx, b_idx, c_idx;
+} test_perms[] = {
+    { "a, b, c", 0, 1, 2 },
+    { "b, a, c", 1, 0, 2 },
+};
+
+int main(void)
+{
+    unsigned long a, b, c, sum;
+    int result = EXIT_SUCCESS;
+    const struct test_func *f;
+    const struct test_perm *p;
+    size_t i, j, k;
+    const struct test *t;
+    int cc;
+
+    for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+        t = &tests[i];
+        for (j = 0; j < sizeof(test_funcs) / sizeof(test_funcs[0]); j++) {
+            f = &test_funcs[j];
+            for (k = 0; k < sizeof(test_perms) / sizeof(test_perms[0]); k++) {
+                p = &test_perms[k];
+                a = t->values[p->a_idx];
+                b = t->values[p->b_idx];
+                c = t->values[p->c_idx];
+                sum = f->ptr(a, b, c, &cc);
+                if (sum != t->exp_sum || cc != t->exp_cc) {
+                    fprintf(stderr,
+                            "[  FAILED  ] %s %s(0x%lx, 0x%lx, 0x%lx) returned 0x%lx cc %d, expected 0x%lx cc %d\n",
+                            t->name, f->name, a, b, c, sum, cc,
+                            t->exp_sum, t->exp_cc);
+                    result = EXIT_FAILURE;
+                }
+            }
+        }
+    }
+
+    return result;
+}
diff --git a/tests/tcg/s390x/clc.c b/tests/tcg/s390x/clc.c
new file mode 100644
index 0000000000..e14189bd75
--- /dev/null
+++ b/tests/tcg/s390x/clc.c
@@ -0,0 +1,48 @@
+/*
+ * Test the CLC instruction.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <assert.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void handle_sigsegv(int sig, siginfo_t *info, void *ucontext)
+{
+    mcontext_t *mcontext = &((ucontext_t *)ucontext)->uc_mcontext;
+    if (mcontext->gregs[0] != 600) {
+        write(STDERR_FILENO, "bad r0\n", 7);
+        _exit(EXIT_FAILURE);
+    }
+    if (((mcontext->psw.mask >> 44) & 3) != 1) {
+        write(STDERR_FILENO, "bad cc\n", 7);
+        _exit(EXIT_FAILURE);
+    }
+    _exit(EXIT_SUCCESS);
+}
+
+int main(void)
+{
+    register unsigned long r0 asm("r0");
+    unsigned long mem = 42, rhs = 500;
+    struct sigaction act;
+    int err;
+
+    memset(&act, 0, sizeof(act));
+    act.sa_sigaction = handle_sigsegv;
+    act.sa_flags = SA_SIGINFO;
+    err = sigaction(SIGSEGV, &act, NULL);
+    assert(err == 0);
+
+    r0 = 100;
+    asm("algr %[r0],%[rhs]\n"
+        "clc 0(8,%[mem]),0(0)\n"  /* The 2nd operand will cause a SEGV. */
+        : [r0] "+r" (r0)
+        : [mem] "r" (&mem)
+        , [rhs] "r" (rhs)
+        : "cc", "memory");
+
+    return EXIT_FAILURE;
+}
diff --git a/tests/tcg/s390x/laalg.c b/tests/tcg/s390x/laalg.c
new file mode 100644
index 0000000000..797d168bb1
--- /dev/null
+++ b/tests/tcg/s390x/laalg.c
@@ -0,0 +1,27 @@
+/*
+ * Test the LAALG instruction.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <assert.h>
+#include <stdlib.h>
+
+int main(void)
+{
+    unsigned long cc = 0, op1, op2 = 40, op3 = 2;
+
+    asm("slgfi %[cc],1\n"  /* Set cc_src = -1. */
+        "laalg %[op1],%[op3],%[op2]\n"
+        "ipm %[cc]"
+        : [cc] "+r" (cc)
+        , [op1] "=r" (op1)
+        , [op2] "+T" (op2)
+        : [op3] "r" (op3)
+        : "cc");
+
+    assert(cc == 0xffffffff10ffffff);
+    assert(op1 == 40);
+    assert(op2 == 42);
+
+    return EXIT_SUCCESS;
+}