This commit is a fix for "Bug 330622 - Add test to regression suite for POWER
instruction: dcbzl" submitted by Anmol P. Paralkar <paralkar@freescale.com>
The patch adds the following files:
none/tests/ppc64/data-cache-instructions.vgtest
none/tests/ppc64/data-cache-instructions.c
none/tests/ppc64/data-cache-instructions.stdout.exp
none/tests/ppc64/data-cache-instructions.stderr.exp
none/tests/ppc32/data-cache-instructions.stdout.exp
none/tests/ppc32/data-cache-instructions.c
none/tests/ppc32/data-cache-instructions.vgtest
none/tests/ppc32/data-cache-instructions.stderr.exp
tests/power_insn_available.c
The following files are modified:
none/tests/ppc32/Makefile.am
none/tests/ppc64/Makefile.am
tests/Makefile.am
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13791 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/none/tests/ppc32/Makefile.am b/none/tests/ppc32/Makefile.am
index 08486cd..5b3fef9 100644
--- a/none/tests/ppc32/Makefile.am
+++ b/none/tests/ppc32/Makefile.am
@@ -44,7 +44,8 @@
test_isa_2_07_part2.stderr.exp test_isa_2_07_part2.stdout.exp test_isa_2_07_part2.vgtest \
test_tm.stderr.exp test_tm.stdout.exp test_tm.vgtest \
test_touch_tm.stderr.exp test_touch_tm.stdout.exp test_touch_tm.vgtest \
- ldst_multiple.stderr.exp ldst_multiple.stdout.exp ldst_multiple.vgtest
+ ldst_multiple.stderr.exp ldst_multiple.stdout.exp ldst_multiple.vgtest \
+ data-cache-instructions.stderr.exp data-cache-instructions.stdout.exp data-cache-instructions.vgtest
check_PROGRAMS = \
@@ -61,7 +62,8 @@
test_isa_2_07_part2 \
test_tm \
test_touch_tm \
- ldst_multiple
+ ldst_multiple \
+ data-cache-instructions
AM_CFLAGS += @FLAG_M32@
AM_CXXFLAGS += @FLAG_M32@
diff --git a/none/tests/ppc32/data-cache-instructions.c b/none/tests/ppc32/data-cache-instructions.c
new file mode 100644
index 0000000..566f5c9
--- /dev/null
+++ b/none/tests/ppc32/data-cache-instructions.c
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Derived from the test case for the "dcbzl" instruction support by
+ * Dave Goodell * <goodell@mcs.anl.gov>
+ * (see: Bug 135264 - dcbzl instruction missing)
+ * and: coregrind/m_machine.c/find_ppc_dcbz_sz()
+ ******************************************************************************/
+
+/* ensure we have posix_memalign */
+#define _POSIX_C_SOURCE 200112L
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+static int query_block_size(void)
+{
+#define MAX_DCBZL_SZB (128) /* largest known effect of dcbzl */
+ char *test_block = NULL;
+ register char *rb asm ("r14");
+ int block_size, test_block_size = 4 * MAX_DCBZL_SZB, err;
+ char *p;
+
+ err = posix_memalign ((void **)&test_block, MAX_DCBZL_SZB, test_block_size);
+ if (err) {
+ fprintf(stderr, "posix_memalign() failed (err = %d [%s])\n", err, strerror(err));
+ return err;
+ }
+
+ rb = test_block;
+
+ memset(rb, 0xff, test_block_size);
+ asm volatile ("dcbzl 0, %[RB]" : : [RB] "r" (rb));
+ for (block_size = 0, p = rb; (p - rb) < test_block_size; p++)
+ if (!*p)
+ block_size++;
+ assert(block_size == 16 || block_size == 32 || block_size == 64 || block_size == 128);
+
+ free(test_block);
+ return block_size;
+}
+
+/* Test dcbzl at addr in buffer given dcbzl_block_size */
+static void test_dcbzl_at(char *addr, char *buffer, int block_size)
+{
+ int i;
+
+ /* Note: Assumption is that the length of buffer is three times the block_size. */
+ memset(buffer, 0xff, 3 * block_size);
+ asm volatile ("dcbzl %[RA], %[RB]" : : [RA] "r" (0), [RB] "r" (addr));
+ for (i = 0; i < block_size; i++) {
+ assert(buffer[i] == 0xff);
+ assert(buffer[block_size + i] == 0x00);
+ assert(buffer[2 * block_size + i] == 0xff);
+ }
+}
+
+/* Test for insn: dcbzl */
+static int test_dcbzl(void)
+{
+ int err;
+ char *buffer = NULL;
+ int buffer_size;
+ int block_size;
+
+ block_size = query_block_size();
+ assert(block_size == 16 || block_size == 32 || block_size == 64 || block_size == 128);
+ buffer_size = 3 * block_size;
+ err = posix_memalign((void **) &buffer, block_size, buffer_size);
+ if (err) {
+ fprintf(stderr, "posix_memalign() failed (err = %d [%s])\n", err, strerror(err));
+ return err;
+ }
+
+ /* check at aligned address within the test block */
+ test_dcbzl_at(&buffer[block_size], buffer, block_size);
+ fprintf(stdout, "Passed dcbzl test at aligned address within the test block.\n");
+
+ /* check at un-aligned (1 modulo block_size) address within the test block */
+ test_dcbzl_at(&buffer[block_size+1], buffer, block_size);
+ fprintf(stdout, "Passed dcbzl test at un-aligned (1 modulo block_size) address within the test block.\n");
+
+ /* check at un-aligned ((block_size - 1) modulo block_size) address within the test block */
+ test_dcbzl_at(&buffer[2 * block_size - 1], buffer, block_size);
+ fprintf(stdout, "Passed dcbzl test at un-aligned ((block_size - 1) modulo block_size) address within the test block.\n");
+
+ free(buffer);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int status;
+ status = test_dcbzl ();
+ return status;
+}
diff --git a/none/tests/ppc32/data-cache-instructions.stderr.exp b/none/tests/ppc32/data-cache-instructions.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/none/tests/ppc32/data-cache-instructions.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/none/tests/ppc32/data-cache-instructions.stdout.exp b/none/tests/ppc32/data-cache-instructions.stdout.exp
new file mode 100644
index 0000000..bf98e13
--- /dev/null
+++ b/none/tests/ppc32/data-cache-instructions.stdout.exp
@@ -0,0 +1,3 @@
+Passed dcbzl test at aligned address within the test block.
+Passed dcbzl test at un-aligned (1 modulo block_size) address within the test block.
+Passed dcbzl test at un-aligned ((block_size - 1) modulo block_size) address within the test block.
diff --git a/none/tests/ppc32/data-cache-instructions.vgtest b/none/tests/ppc32/data-cache-instructions.vgtest
new file mode 100644
index 0000000..42a3b31
--- /dev/null
+++ b/none/tests/ppc32/data-cache-instructions.vgtest
@@ -0,0 +1,2 @@
+prereq: ../../../tests/power_insn_available dcbzl
+prog: data-cache-instructions
diff --git a/none/tests/ppc64/Makefile.am b/none/tests/ppc64/Makefile.am
index fc43f08..20a2ebb 100644
--- a/none/tests/ppc64/Makefile.am
+++ b/none/tests/ppc64/Makefile.am
@@ -32,7 +32,8 @@
test_isa_2_07_part2.stderr.exp test_isa_2_07_part2.stdout.exp test_isa_2_07_part2.vgtest \
test_tm.stderr.exp test_tm.stdout.exp test_tm.vgtest \
test_touch_tm.stderr.exp test_touch_tm.stdout.exp test_touch_tm.vgtest \
- ldst_multiple.stderr.exp ldst_multiple.stdout.exp ldst_multiple.vgtest
+ ldst_multiple.stderr.exp ldst_multiple.stdout.exp ldst_multiple.vgtest \
+ data-cache-instructions.stderr.exp data-cache-instructions.stdout.exp data-cache-instructions.vgtest
check_PROGRAMS = \
allexec \
@@ -40,7 +41,7 @@
power6_mf_gpr test_isa_2_06_part1 test_isa_2_06_part2 \
test_isa_2_06_part3 test_dfp1 test_dfp2 test_dfp3 test_dfp4 \
test_dfp5 test_isa_2_07_part1 test_isa_2_07_part2 \
- test_tm test_touch_tm ldst_multiple
+ test_tm test_touch_tm ldst_multiple data-cache-instructions
AM_CFLAGS += @FLAG_M64@
AM_CXXFLAGS += @FLAG_M64@
diff --git a/none/tests/ppc64/data-cache-instructions.c b/none/tests/ppc64/data-cache-instructions.c
new file mode 120000
index 0000000..d2b3df0
--- /dev/null
+++ b/none/tests/ppc64/data-cache-instructions.c
@@ -0,0 +1 @@
+../ppc32/data-cache-instructions.c
\ No newline at end of file
diff --git a/none/tests/ppc64/data-cache-instructions.stderr.exp b/none/tests/ppc64/data-cache-instructions.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/none/tests/ppc64/data-cache-instructions.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/none/tests/ppc64/data-cache-instructions.stdout.exp b/none/tests/ppc64/data-cache-instructions.stdout.exp
new file mode 100644
index 0000000..bf98e13
--- /dev/null
+++ b/none/tests/ppc64/data-cache-instructions.stdout.exp
@@ -0,0 +1,3 @@
+Passed dcbzl test at aligned address within the test block.
+Passed dcbzl test at un-aligned (1 modulo block_size) address within the test block.
+Passed dcbzl test at un-aligned ((block_size - 1) modulo block_size) address within the test block.
diff --git a/none/tests/ppc64/data-cache-instructions.vgtest b/none/tests/ppc64/data-cache-instructions.vgtest
new file mode 100644
index 0000000..42a3b31
--- /dev/null
+++ b/none/tests/ppc64/data-cache-instructions.vgtest
@@ -0,0 +1,2 @@
+prereq: ../../../tests/power_insn_available dcbzl
+prog: data-cache-instructions
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 974f0a5..adfbec4 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -30,7 +30,8 @@
true \
x86_amd64_features \
s390x_features \
- mips_features
+ mips_features \
+ power_insn_available
AM_CFLAGS += $(AM_FLAG_M3264_PRI)
AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
diff --git a/tests/power_insn_available.c b/tests/power_insn_available.c
new file mode 100644
index 0000000..1bfea2a
--- /dev/null
+++ b/tests/power_insn_available.c
@@ -0,0 +1,92 @@
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <setjmp.h>
+
+typedef enum exit_codes_ {
+
+#if defined(VGA_ppc32) || defined(VGA_ppc64)
+ /* If the insn that got queried for: exists */
+ POWER_INSN_AVAILABLE = 0,
+ /* If the insn that got queried for: does not exist on this platform */
+ POWER_INSN_UNAVAILABLE = 1,
+ /* If the insn that got queried for: does not exist in the vocabulary of this program */
+ POWER_INSN_UNRECOGNIZED = 2,
+
+ /* Note: Please keep USAGE_ERROR last. */
+ USAGE_ERROR
+#else
+ /* When not on a POWER system: */
+ NOT_POWER_ARCH = 255,
+#endif
+
+} exit_code;
+
+#if defined(VGA_ppc32) || defined(VGA_ppc64)
+/* Signal Handling support for unsupported instructions. */
+static jmp_buf unsup_insn_env;
+static void unsup_insn_handler(int signal_number)
+{
+ if (signal_number == SIGILL)
+ longjmp(unsup_insn_env, 1);
+ return;
+}
+static struct sigaction unsup_insn_action = (struct sigaction) {
+ .sa_handler = &unsup_insn_handler,
+};
+
+/* Instruction existence tests. */
+static bool dcbzl_available(void)
+{
+#define MAX_DCBZL_SZB (128) /* largest known effect of dcbzl */
+ char *test_block = NULL;
+ register char *rb asm ("r14");
+ int err;
+ bool dcbzl_exists = false;
+
+ err = posix_memalign ((void **)&test_block, MAX_DCBZL_SZB, 4 * MAX_DCBZL_SZB);
+ if (err) {
+ fprintf(stderr, "posix_memalign() failed (err = %d [%s])\n", err, strerror(err));
+ return err;
+ }
+
+ rb = test_block;
+
+ if (setjmp(unsup_insn_env) != 0)
+ dcbzl_exists = false;
+ else {
+ sigaction(SIGILL, &unsup_insn_action, NULL);
+ asm volatile ("dcbzl 0, %[RB]" : : [RB] "r" (rb));
+ dcbzl_exists = true;
+ }
+
+ free(test_block);
+ return dcbzl_exists;
+}
+#endif
+
+/* main() */
+int main(int argc, char **argv)
+{
+ exit_code status;
+
+#if defined(VGA_ppc32) || defined(VGA_ppc64)
+ char *insn;
+ if (argc != 2) {
+ fprintf(stderr, "usage: power_insn_available <insn>\n" );
+ exit(USAGE_ERROR);
+ }
+
+ insn = argv[1];
+ if (strcmp (insn, "dcbzl") == 0)
+ status = ((dcbzl_available ()) ? POWER_INSN_AVAILABLE : POWER_INSN_UNAVAILABLE);
+ else
+ /* power_insn_available has not been taught anything about this insn yet. */
+ status = POWER_INSN_UNRECOGNIZED;
+#else
+ status = NOT_POWER_ARCH;
+#endif
+ return status;
+}