This patch by adrian.sendroiu@freescale.com fixes the lrmw and stmw
instructions.

The patch also adds ppc32 and ppc64 test cases for the instructions.

The patch is a fix for bugzilla 329956 "valgrind crashes when lmw/stmw instructions are used on ppc64".

The VEX code commit is 2802




git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13780 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/none/tests/ppc32/Makefile.am b/none/tests/ppc32/Makefile.am
index 4f581b6..08486cd 100644
--- a/none/tests/ppc32/Makefile.am
+++ b/none/tests/ppc32/Makefile.am
@@ -43,7 +43,8 @@
 	jm_int_isa_2_07.stderr.exp jm_int_isa_2_07.stdout.exp jm_int_isa_2_07.vgtest \
 	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
+	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
 
 
 check_PROGRAMS = \
@@ -59,7 +60,8 @@
 	test_isa_2_07_part1 \
 	test_isa_2_07_part2 \
 	test_tm \
-	test_touch_tm
+	test_touch_tm \
+	ldst_multiple
 
 AM_CFLAGS    += @FLAG_M32@
 AM_CXXFLAGS  += @FLAG_M32@
diff --git a/none/tests/ppc32/ldst_multiple.c b/none/tests/ppc32/ldst_multiple.c
new file mode 100644
index 0000000..6c610b9
--- /dev/null
+++ b/none/tests/ppc32/ldst_multiple.c
@@ -0,0 +1,191 @@
+#include <stdio.h>
+#include <stdint.h>
+
+#ifndef __powerpc64__
+typedef uint32_t HWord_t;
+#else
+typedef uint64_t HWord_t;
+#endif
+
+typedef void (*test_func_t)();
+
+typedef struct test_table {
+   test_func_t func;
+   char *name;
+} test_table_t;
+
+static uint32_t values[] = {
+   0x6efbcfdf,
+   0xd16c2fd4,
+   0xf9dc1743,
+   0xa5aa0bd4,
+   0x6c8f0c14,
+   0x69a24188,
+   0x53b57f1b,
+};
+
+register HWord_t r27 asm("r27");
+register HWord_t r28 asm("r28");
+register HWord_t r29 asm("r29");
+register HWord_t r30 asm("r30");
+register HWord_t r31 asm("r31");
+
+register HWord_t r14 asm("r14");
+
+HWord_t temp[5];
+
+#ifdef __powerpc64__
+
+#define SAVE_REGS(addr)                       \
+   asm volatile(                              \
+   "	std   27, 0(%0)   \n"                   \
+   "	std   28, 8(%0)   \n"                   \
+   "	std   29, 16(%0)  \n"                   \
+   "	std   30, 24(%0)  \n"                   \
+   "	std   31, 32(%0)  \n"                   \
+   ::"b"(addr))
+
+#define RESTORE_REGS(addr)                    \
+   asm volatile(                              \
+   "	ld    27, 0(%0)   \n"                   \
+   "	ld    28, 8(%0)   \n"                   \
+   "	ld    29, 16(%0)  \n"                   \
+   "	ld    30, 24(%0)  \n"                   \
+   "	ld    31, 32(%0)  \n"                   \
+   ::"b"(addr))
+
+#else /* !__powerpc64__ */
+
+#define SAVE_REGS(addr)                       \
+   asm volatile(                              \
+   "	stw   27, 0(%0)   \n"                   \
+   "	stw   28, 4(%0)   \n"                   \
+   "	stw   29, 8(%0)   \n"                   \
+   "	stw   30, 12(%0)  \n"                   \
+   "	stw   31, 16(%0)  \n"                   \
+   ::"b"(addr))
+
+#define RESTORE_REGS(addr)                    \
+   asm volatile(                              \
+   "	lwz   27, 0(%0)   \n"                   \
+   "	lwz   28, 4(%0)   \n"                   \
+   "	lwz   29, 8(%0)   \n"                   \
+   "	lwz   30, 12(%0)  \n"                   \
+   "	lwz   31, 16(%0)  \n"                   \
+   ::"b"(addr))
+
+#endif /* __powerpc64__ */
+
+/*
+ * gcc is not happy if we modify r31 (the frame pointer) behind its back
+ * so we omit it
+ */
+static void __attribute__((optimize("-fomit-frame-pointer"))) test_lmw(void)
+{
+   r14 = (HWord_t)values;
+
+   /* save r27 - r31 */
+   SAVE_REGS(temp);
+
+   /* load r27 - r31 */
+   asm volatile(
+      "	lmw	%r27, 0(%r14)	\n");
+
+#ifdef __powerpc64__
+   printf("lmw => %016lx %016lx %016lx %016lx %016lx\n",
+#else
+   printf("lmw => %08x %08x %08x %08x %08x\n",
+#endif
+          r27, r28, r29, r30, r31);
+
+   /*
+    * test load multiple with nonzero immediate offset
+    * load the last two values into r30 - r31.
+    * r27 - r29 should remain the same
+    */
+   asm volatile(
+      "	lmw	%r30, 20(%r14)	\n");
+
+#ifdef __powerpc64__
+   printf("lmw => %016lx %016lx %016lx %016lx %016lx\n",
+#else
+   printf("lmw => %08x %08x %08x %08x %08x\n",
+#endif
+          r27, r28, r29, r30, r31);
+
+   /* restore r27 - r31 */
+   RESTORE_REGS(temp);
+}
+
+/*
+ * gcc is not happy if we modify r31 (the frame pointer) behind its back
+ * so we omit it
+ */
+static void __attribute__((optimize("-fomit-frame-pointer"))) test_stmw(void)
+{
+   uint32_t result[7] = { 0 };
+   int i;
+
+   SAVE_REGS(temp);
+
+#ifdef __powerpc64__
+   asm volatile(
+   "	lwz   27, 0(%0)   \n"                   \
+   "	lwz   28, 4(%0)   \n"                   \
+   "	lwz   29, 8(%0)   \n"                   \
+   "	lwz   30, 12(%0)  \n"                   \
+   "	lwz   31, 16(%0)  \n"                   \
+   ::"b"(values));
+#else
+   RESTORE_REGS(values);
+#endif
+
+   r14 = (HWord_t)&result;
+
+   /* store r27 - r31 */
+   asm volatile(
+      "	stmw	%r27, 0(%r14)	\n");
+
+   printf("stmw => ");
+   for (i = 0; i < sizeof(result) / sizeof(result[0]); i++)
+      printf("%08x ", result[i]);
+
+   printf("\n");
+
+   /*
+    * test store multiple with nonzero immediate offset
+    * store r30 - r31 into the last two places in the array
+    * the rest of the array should remain the same
+    */
+   asm volatile(
+      "	stmw	%r30, 20(%r14)	\n");
+
+   printf("stmw => ");
+   for (i = 0; i < sizeof(result) / sizeof(result[0]); i++)
+      printf("%08x ", result[i]);
+
+   printf("\n");
+
+   RESTORE_REGS(temp);
+}
+
+static test_table_t all_tests[] = {
+   { &test_lmw,
+     "Test Load Multiple instruction" },
+   { &test_stmw,
+     "Test Store Multiple instruction" },
+   { NULL, NULL },
+};
+
+int main(void)
+{
+   test_func_t func;
+   int i = 0;
+
+   while ((func = all_tests[i].func)) {
+      (*func)();
+      i++;
+   }
+
+   return 0;
+}
diff --git a/none/tests/ppc32/ldst_multiple.stderr.exp b/none/tests/ppc32/ldst_multiple.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/none/tests/ppc32/ldst_multiple.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/none/tests/ppc32/ldst_multiple.stdout.exp b/none/tests/ppc32/ldst_multiple.stdout.exp
new file mode 100644
index 0000000..f3579dc
--- /dev/null
+++ b/none/tests/ppc32/ldst_multiple.stdout.exp
@@ -0,0 +1,4 @@
+lmw => 6efbcfdf d16c2fd4 f9dc1743 a5aa0bd4 6c8f0c14
+lmw => 6efbcfdf d16c2fd4 f9dc1743 69a24188 53b57f1b
+stmw => 6efbcfdf d16c2fd4 f9dc1743 a5aa0bd4 6c8f0c14 00000000 00000000 
+stmw => 6efbcfdf d16c2fd4 f9dc1743 a5aa0bd4 6c8f0c14 a5aa0bd4 6c8f0c14 
diff --git a/none/tests/ppc32/ldst_multiple.vgtest b/none/tests/ppc32/ldst_multiple.vgtest
new file mode 100644
index 0000000..87e668e
--- /dev/null
+++ b/none/tests/ppc32/ldst_multiple.vgtest
@@ -0,0 +1 @@
+prog: ldst_multiple
diff --git a/none/tests/ppc64/Makefile.am b/none/tests/ppc64/Makefile.am
index 93c6fe1..fc43f08 100644
--- a/none/tests/ppc64/Makefile.am
+++ b/none/tests/ppc64/Makefile.am
@@ -31,7 +31,8 @@
 	jm_int_isa_2_07.stderr.exp jm_int_isa_2_07.stdout.exp jm_int_isa_2_07.vgtest \
 	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
+	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
 
 check_PROGRAMS = \
 	allexec \
@@ -39,7 +40,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
+	test_tm test_touch_tm ldst_multiple
 
 AM_CFLAGS    += @FLAG_M64@
 AM_CXXFLAGS  += @FLAG_M64@
diff --git a/none/tests/ppc64/ldst_multiple.c b/none/tests/ppc64/ldst_multiple.c
new file mode 120000
index 0000000..d155824
--- /dev/null
+++ b/none/tests/ppc64/ldst_multiple.c
@@ -0,0 +1 @@
+../ppc32/ldst_multiple.c
\ No newline at end of file
diff --git a/none/tests/ppc64/ldst_multiple.stderr.exp b/none/tests/ppc64/ldst_multiple.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/none/tests/ppc64/ldst_multiple.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/none/tests/ppc64/ldst_multiple.stdout.exp b/none/tests/ppc64/ldst_multiple.stdout.exp
new file mode 100644
index 0000000..31f923b
--- /dev/null
+++ b/none/tests/ppc64/ldst_multiple.stdout.exp
@@ -0,0 +1,4 @@
+lmw => 000000006efbcfdf 00000000d16c2fd4 00000000f9dc1743 00000000a5aa0bd4 000000006c8f0c14
+lmw => 000000006efbcfdf 00000000d16c2fd4 00000000f9dc1743 0000000069a24188 0000000053b57f1b
+stmw => 6efbcfdf d16c2fd4 f9dc1743 a5aa0bd4 6c8f0c14 00000000 00000000 
+stmw => 6efbcfdf d16c2fd4 f9dc1743 a5aa0bd4 6c8f0c14 a5aa0bd4 6c8f0c14 
diff --git a/none/tests/ppc64/ldst_multiple.vgtest b/none/tests/ppc64/ldst_multiple.vgtest
new file mode 100644
index 0000000..87e668e
--- /dev/null
+++ b/none/tests/ppc64/ldst_multiple.vgtest
@@ -0,0 +1 @@
+prog: ldst_multiple