aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2022-07-20 11:51:00 +0100
committerPeter Maydell <peter.maydell@linaro.org>2022-07-20 11:51:00 +0100
commit1f64dd76a1bdf50ec8ab66da0ee7dcfd48ea31e4 (patch)
treef56ad93e416114952dc2f5385449f82b0c108c97 /tests
parent68e26e1e812c8b09313d7929271f6cbd47ef4c07 (diff)
parent15fc6badbd28a126346f84c1acae48e273b66b67 (diff)
Merge tag 'pull-hex-20220719-1' of https://github.com/quic/qemu into staging
Recall that the semantics of a Hexagon mem_noshuf packet are that the store effectively happens before the load. There are two bug fixes in this series. # gpg: Signature made Tue 19 Jul 2022 22:25:19 BST # gpg: using RSA key 3635C788CE62B91FD4C59AB47B0244FB12DE4422 # gpg: Good signature from "Taylor Simpson (Rock on) <tsimpson@quicinc.com>" [undefined] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 3635 C788 CE62 B91F D4C5 9AB4 7B02 44FB 12DE 4422 * tag 'pull-hex-20220719-1' of https://github.com/quic/qemu: Hexagon (target/hexagon) fix bug in mem_noshuf load exception Hexagon (target/hexagon) fix store w/mem_noshuf & predicated load Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'tests')
-rw-r--r--tests/tcg/hexagon/Makefile.target1
-rw-r--r--tests/tcg/hexagon/mem_noshuf.c122
-rw-r--r--tests/tcg/hexagon/mem_noshuf_exception.c146
3 files changed, 264 insertions, 5 deletions
diff --git a/tests/tcg/hexagon/Makefile.target b/tests/tcg/hexagon/Makefile.target
index 23b9870534..96a4d7a614 100644
--- a/tests/tcg/hexagon/Makefile.target
+++ b/tests/tcg/hexagon/Makefile.target
@@ -35,6 +35,7 @@ HEX_TESTS += preg_alias
HEX_TESTS += dual_stores
HEX_TESTS += multi_result
HEX_TESTS += mem_noshuf
+HEX_TESTS += mem_noshuf_exception
HEX_TESTS += circ
HEX_TESTS += brev
HEX_TESTS += load_unpack
diff --git a/tests/tcg/hexagon/mem_noshuf.c b/tests/tcg/hexagon/mem_noshuf.c
index dd714d5e98..0f4064e700 100644
--- a/tests/tcg/hexagon/mem_noshuf.c
+++ b/tests/tcg/hexagon/mem_noshuf.c
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ * Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -84,6 +84,70 @@ MEM_NOSHUF32(mem_noshuf_sd_luh, long long, unsigned short, memd, memuh)
MEM_NOSHUF32(mem_noshuf_sd_lw, long long, signed int, memd, memw)
MEM_NOSHUF64(mem_noshuf_sd_ld, long long, signed long long, memd, memd)
+static inline int pred_lw_sw(int pred, int *p, int *q, int x, int y)
+{
+ int ret;
+ asm volatile("p0 = cmp.eq(%5, #0)\n\t"
+ "%0 = %3\n\t"
+ "{\n\t"
+ " memw(%1) = %4\n\t"
+ " if (!p0) %0 = memw(%2)\n\t"
+ "}:mem_noshuf\n"
+ : "=&r"(ret)
+ : "r"(p), "r"(q), "r"(x), "r"(y), "r"(pred)
+ : "p0", "memory");
+ return ret;
+}
+
+static inline int pred_lw_sw_pi(int pred, int *p, int *q, int x, int y)
+{
+ int ret;
+ asm volatile("p0 = cmp.eq(%5, #0)\n\t"
+ "%0 = %3\n\t"
+ "r7 = %2\n\t"
+ "{\n\t"
+ " memw(%1) = %4\n\t"
+ " if (!p0) %0 = memw(r7++#4)\n\t"
+ "}:mem_noshuf\n"
+ : "=&r"(ret)
+ : "r"(p), "r"(q), "r"(x), "r"(y), "r"(pred)
+ : "r7", "p0", "memory");
+ return ret;
+}
+
+static inline long long pred_ld_sd(int pred, long long *p, long long *q,
+ long long x, long long y)
+{
+ unsigned long long ret;
+ asm volatile("p0 = cmp.eq(%5, #0)\n\t"
+ "%0 = %3\n\t"
+ "{\n\t"
+ " memd(%1) = %4\n\t"
+ " if (!p0) %0 = memd(%2)\n\t"
+ "}:mem_noshuf\n"
+ : "=&r"(ret)
+ : "r"(p), "r"(q), "r"(x), "r"(y), "r"(pred)
+ : "p0", "memory");
+ return ret;
+}
+
+static inline long long pred_ld_sd_pi(int pred, long long *p, long long *q,
+ long long x, long long y)
+{
+ long long ret;
+ asm volatile("p0 = cmp.eq(%5, #0)\n\t"
+ "%0 = %3\n\t"
+ "r7 = %2\n\t"
+ "{\n\t"
+ " memd(%1) = %4\n\t"
+ " if (!p0) %0 = memd(r7++#8)\n\t"
+ "}:mem_noshuf\n"
+ : "=&r"(ret)
+ : "r"(p), "r"(q), "r"(x), "r"(y), "r"(pred)
+ : "p0", "memory");
+ return ret;
+}
+
static inline unsigned int cancel_sw_lb(int pred, int *p, signed char *q, int x)
{
unsigned int ret;
@@ -126,18 +190,22 @@ typedef union {
int err;
-static void check32(int n, int expect)
+#define check32(n, expect) check32_(n, expect, __LINE__)
+
+static void check32_(int n, int expect, int line)
{
if (n != expect) {
- printf("ERROR: 0x%08x != 0x%08x\n", n, expect);
+ printf("ERROR: 0x%08x != 0x%08x, line %d\n", n, expect, line);
err++;
}
}
-static void check64(long long n, long long expect)
+#define check64(n, expect) check64_(n, expect, __LINE__)
+
+static void check64_(long long n, long long expect, int line)
{
if (n != expect) {
- printf("ERROR: 0x%08llx != 0x%08llx\n", n, expect);
+ printf("ERROR: 0x%08llx != 0x%08llx, line %d\n", n, expect, line);
err++;
}
}
@@ -323,6 +391,50 @@ int main()
res64 = mem_noshuf_sd_ld(&n.d[0], &n.d[1], 0x123456789abcdef0LL);
check64(res64, 0xffffffffffffffffLL);
+ n.w[0] = ~0;
+ res32 = pred_lw_sw(0, &n.w[0], &n.w[0], 0x12345678, 0xc0ffeeda);
+ check32(res32, 0x12345678);
+ check32(n.w[0], 0xc0ffeeda);
+
+ n.w[0] = ~0;
+ res32 = pred_lw_sw(1, &n.w[0], &n.w[0], 0x12345678, 0xc0ffeeda);
+ check32(res32, 0xc0ffeeda);
+ check32(n.w[0], 0xc0ffeeda);
+
+ n.w[0] = ~0;
+ res32 = pred_lw_sw_pi(0, &n.w[0], &n.w[0], 0x12345678, 0xc0ffeeda);
+ check32(res32, 0x12345678);
+ check32(n.w[0], 0xc0ffeeda);
+
+ n.w[0] = ~0;
+ res32 = pred_lw_sw_pi(1, &n.w[0], &n.w[0], 0x12345678, 0xc0ffeeda);
+ check32(res32, 0xc0ffeeda);
+ check32(n.w[0], 0xc0ffeeda);
+
+ n.d[0] = ~0LL;
+ res64 = pred_ld_sd(0, &n.d[0], &n.d[0],
+ 0x1234567812345678LL, 0xc0ffeedac0ffeedaLL);
+ check64(res64, 0x1234567812345678LL);
+ check64(n.d[0], 0xc0ffeedac0ffeedaLL);
+
+ n.d[0] = ~0LL;
+ res64 = pred_ld_sd(1, &n.d[0], &n.d[0],
+ 0x1234567812345678LL, 0xc0ffeedac0ffeedaLL);
+ check64(res64, 0xc0ffeedac0ffeedaLL);
+ check64(n.d[0], 0xc0ffeedac0ffeedaLL);
+
+ n.d[0] = ~0LL;
+ res64 = pred_ld_sd_pi(0, &n.d[0], &n.d[0],
+ 0x1234567812345678LL, 0xc0ffeedac0ffeedaLL);
+ check64(res64, 0x1234567812345678LL);
+ check64(n.d[0], 0xc0ffeedac0ffeedaLL);
+
+ n.d[0] = ~0LL;
+ res64 = pred_ld_sd_pi(1, &n.d[0], &n.d[0],
+ 0x1234567812345678LL, 0xc0ffeedac0ffeedaLL);
+ check64(res64, 0xc0ffeedac0ffeedaLL);
+ check64(n.d[0], 0xc0ffeedac0ffeedaLL);
+
puts(err ? "FAIL" : "PASS");
return err;
}
diff --git a/tests/tcg/hexagon/mem_noshuf_exception.c b/tests/tcg/hexagon/mem_noshuf_exception.c
new file mode 100644
index 0000000000..08660ea3e1
--- /dev/null
+++ b/tests/tcg/hexagon/mem_noshuf_exception.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright(c) 2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ *
+ * This program 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.
+ *
+ * This program 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Test the VLIW semantics of exceptions with mem_noshuf
+ *
+ * When a packet has the :mem_noshuf attribute, the semantics dictate
+ * That the load will get the data from the store if the addresses overlap.
+ * To accomplish this, we perform the store first. However, we have to
+ * handle the case where the store raises an exception. In that case, the
+ * store should not alter the machine state.
+ *
+ * We test this with a mem_noshuf packet with a store to a global variable,
+ * "should_not_change" and a load from NULL. After the SIGSEGV is caught,
+ * we check * that the "should_not_change" value is the same.
+ *
+ * We also check that a predicated load where the predicate is false doesn't
+ * raise an exception and allows the store to happen.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#include <signal.h>
+
+int err;
+int segv_caught;
+
+#define SHOULD_NOT_CHANGE_VAL 5
+int should_not_change = SHOULD_NOT_CHANGE_VAL;
+
+#define OK_TO_CHANGE_VAL 13
+int ok_to_change = OK_TO_CHANGE_VAL;
+
+static void __check(const char *filename, int line, int x, int expect)
+{
+ if (x != expect) {
+ printf("ERROR %s:%d - %d != %d\n",
+ filename, line, x, expect);
+ err++;
+ }
+}
+
+#define check(x, expect) __check(__FILE__, __LINE__, (x), (expect))
+
+static void __chk_error(const char *filename, int line, int ret)
+{
+ if (ret < 0) {
+ printf("ERROR %s:%d - %d\n", filename, line, ret);
+ err++;
+ }
+}
+
+#define chk_error(ret) __chk_error(__FILE__, __LINE__, (ret))
+
+jmp_buf jmp_env;
+
+static void sig_segv(int sig, siginfo_t *info, void *puc)
+{
+ check(sig, SIGSEGV);
+ segv_caught = 1;
+ longjmp(jmp_env, 1);
+}
+
+int main()
+{
+ struct sigaction act;
+ int dummy32;
+ long long dummy64;
+ void *p;
+
+ /* SIGSEGV test */
+ act.sa_sigaction = sig_segv;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_SIGINFO;
+ chk_error(sigaction(SIGSEGV, &act, NULL));
+ if (setjmp(jmp_env) == 0) {
+ asm volatile("r18 = ##should_not_change\n\t"
+ "r19 = #0\n\t"
+ "{\n\t"
+ " memw(r18) = #7\n\t"
+ " %0 = memw(r19)\n\t"
+ "}:mem_noshuf\n\t"
+ : "=r"(dummy32) : : "r18", "r19", "memory");
+ }
+
+ act.sa_handler = SIG_DFL;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ chk_error(sigaction(SIGSEGV, &act, NULL));
+
+ check(segv_caught, 1);
+ check(should_not_change, SHOULD_NOT_CHANGE_VAL);
+
+ /*
+ * Check that a predicated load where the predicate is false doesn't
+ * raise an exception and allows the store to happen.
+ */
+ asm volatile("r18 = ##ok_to_change\n\t"
+ "r19 = #0\n\t"
+ "p0 = cmp.gt(r0, r0)\n\t"
+ "{\n\t"
+ " memw(r18) = #7\n\t"
+ " if (p0) %0 = memw(r19)\n\t"
+ "}:mem_noshuf\n\t"
+ : "=r"(dummy32) : : "r18", "r19", "p0", "memory");
+
+ check(ok_to_change, 7);
+
+ /*
+ * Also check that the post-increment doesn't happen when the
+ * predicate is false.
+ */
+ ok_to_change = OK_TO_CHANGE_VAL;
+ p = NULL;
+ asm volatile("r18 = ##ok_to_change\n\t"
+ "p0 = cmp.gt(r0, r0)\n\t"
+ "{\n\t"
+ " memw(r18) = #9\n\t"
+ " if (p0) %1 = memd(%0 ++ #8)\n\t"
+ "}:mem_noshuf\n\t"
+ : "+r"(p), "=r"(dummy64) : : "r18", "p0", "memory");
+
+ check(ok_to_change, 9);
+ check((int)p, (int)NULL);
+
+ puts(err ? "FAIL" : "PASS");
+ return err ? EXIT_FAILURE : EXIT_SUCCESS;
+}