valgrind bits for fixing bugzilla #291865. See also VEX r2372.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@12615
289939 wish: complete monitor cmd 'leak_check' with details about leaked or reachable blocks
290655 Add support for AESKEYGENASSIST instruction
290974 vgdb must align pages to VKI_SHMLBA (16KB) on ARM
+291865 s390x: Support the "Compare Double and Swap" family of instructions
293088 Add some VEX sanity checks for ppc64 unhandled instructions
294055 regtest none/tests/shell fails when locale is not set to C
294190 --vgdb-error=xxx can be out of sync with errors shown to the user
c,compare,implemented,
cd,"compare (long)","not implemented",
cdr,"compare (long)","not implemented",
-cds,"compare double and swap","not implemented","open bugzilla"
+cds,"compare double and swap",implemented,
ce,"compare (short)","not implemented",
cer,"compare (short)","not implemented",
cfc,"compare and form codeword","not implemented",
stctg,"store control 64",N/A,"privileged instruction"
lctlg,"load control 64",N/A,"privileged instruction"
csg,"compare and swap 64",implemented,
-cdsg,"compare double and swap 64","not implemented","open bugzilla"
+cdsg,"compare double and swap 64",implemented,
clmh,"compare logical characters under mask high",implemented,
stcmh,"store characters under mask high",implemented,
icmh,"insert characters under mask high",implemented,
ny,"and with long offset",implemented,
cy,"compare with long offset",implemented,
csy,"compare and swap with long offset",implemented,
-cdsy,"compare double and swap with long offset","not implemented","open bugzilla"
+cdsy,"compare double and swap with long offset",implemented,
chy,"compare halfword with long offset",implemented,
cly,"compare logical with long offset",implemented,
cliy,"compare logical immediate with long offset",implemented,
dist_noinst_SCRIPTS = filter_stderr
-INSN_TESTS = cs csg
+INSN_TESTS = cs csg cds cdsg
check_PROGRAMS = $(INSN_TESTS)
--- /dev/null
+#include <stdint.h>
+#include <stdio.h>
+
+typedef struct {
+ uint64_t high;
+ uint64_t low;
+} quad_word;
+
+void
+test(quad_word op1_init, uint64_t op2_init, quad_word op3_init)
+{
+ int cc; // unused
+ quad_word op1 = op1_init;
+ uint64_t op2 = op2_init;
+ quad_word op3 = op3_init;
+
+ __asm__ volatile (
+ "lmg %%r0,%%r1,%1\n\t"
+ "lmg %%r2,%%r3,%3\n\t"
+ "cds %%r0,%%r2,%2\n\t" // cds 1st,3rd,2nd
+ "stmg %%r0,%%r1,%1\n" // store r0,r1 to op1
+ "stmg %%r2,%%r3,%3\n" // store r2,r3 to op3
+ : "=d" (cc), "+QS" (op1), "+QS" (op2), "+QS" (op3)
+ :
+ : "r0", "r1", "r2", "r3", "cc");
+
+}
+
+// Return a quad-word that only bits low[32:63] are undefined
+quad_word
+make_undefined(void)
+{
+ quad_word val;
+
+ val.high = 0;
+ val.low |= 0xFFFFFFFF00000000ull;
+
+ return val;
+}
+
+void op1_undefined(void)
+{
+ quad_word op1, op3;
+ uint64_t op2;
+
+ // op1 undefined
+ op1 = make_undefined();
+ op2 = 42;
+ op3.high = op3.low = 0xdeadbeefdeadbabeull;
+ test(op1, op2, op3); // complaint
+}
+
+void op2_undefined(void)
+{
+ quad_word op1, op3;
+ uint64_t op2;
+
+ op1.high = op1.low = 42;
+ // op2 undefined
+ op3.high = op3.low = 0xdeadbeefdeadbabeull;
+ test(op1, op2, op3); // complaint
+}
+
+void op3_undefined(void)
+{
+ quad_word op1, op3;
+ uint64_t op2;
+
+ op1.high = op1.low = 42;
+ op2 = 100;
+ op3 = make_undefined();
+ test(op1, op2, op3); // no complaint; op3 is just copied around
+}
+
+int main ()
+{
+ op1_undefined();
+ op2_undefined();
+ op3_undefined();
+
+ return 0;
+}
--- /dev/null
+Conditional jump or move depends on uninitialised value(s)
+ at 0x........: test (cds.c:17)
+ by 0x........: op1_undefined (cds.c:50)
+ by 0x........: main (cds.c:77)
+
+Conditional jump or move depends on uninitialised value(s)
+ at 0x........: test (cds.c:17)
+ by 0x........: op2_undefined (cds.c:61)
+ by 0x........: main (cds.c:78)
+
--- /dev/null
+prog: cds
+vgopts: -q
--- /dev/null
+#include <stdint.h>
+#include <stdio.h>
+
+typedef struct {
+ uint64_t high;
+ uint64_t low;
+} quad_word;
+
+void
+test(quad_word op1_init, quad_word op2_init, quad_word op3_init)
+{
+ int cc; // unused
+ quad_word op1 = op1_init;
+ quad_word op2 = op2_init;
+ quad_word op3 = op3_init;
+
+ __asm__ volatile (
+ "lmg %%r0,%%r1,%1\n\t"
+ "lmg %%r2,%%r3,%3\n\t"
+ "cdsg %%r0,%%r2,%2\n\t" // cdsg 1st,3rd,2nd
+ "stmg %%r0,%%r1,%1\n" // store r0,r1 to op1
+ "stmg %%r2,%%r3,%3\n" // store r2,r3 to op3
+ : "=d"(cc), "+QS" (op1), "+QS" (op2), "+QS" (op3)
+ :
+ : "r0", "r1", "r2", "r3", "cc");
+}
+
+void op1_undefined(void)
+{
+ quad_word op1, op2, op3;
+
+ // op1 undefined
+ op2.high = op2.low = 42;
+ op3.high = op3.low = 0xdeadbeefdeadbabeull;
+ test(op1, op2, op3); // complaint
+}
+
+void op2_undefined(void)
+{
+ quad_word op1, op2, op3;
+
+ op1.high = op1.low = 42;
+ // op2 undefined
+ op3.high = op3.low = 0xdeadbeefdeadbabeull;
+ test(op1, op2, op3); // complaint
+}
+
+void op3_undefined(void)
+{
+ quad_word op1, op2, op3;
+
+ op1.high = op1.low = 42;
+ op2 = op1;
+ // op3 undefined
+ test(op1, op2, op3); // no complaint; op3 is just copied around
+}
+
+int main ()
+{
+ op1_undefined();
+ op2_undefined();
+ op3_undefined();
+
+ return 0;
+}
--- /dev/null
+Conditional jump or move depends on uninitialised value(s)
+ at 0x........: test (cdsg.c:17)
+ by 0x........: op1_undefined (cdsg.c:35)
+ by 0x........: main (cdsg.c:60)
+
+Conditional jump or move depends on uninitialised value(s)
+ at 0x........: test (cdsg.c:17)
+ by 0x........: op2_undefined (cdsg.c:45)
+ by 0x........: main (cdsg.c:61)
+
--- /dev/null
+prog: cdsg
+vgopts: -q
and_EI or_EI xor_EI insert_EI mul_GE add_GE condloadstore \
op_exception fgx stck stckf stcke stfle cksm mvcl clcl troo \
trto trot trtt tr tre cij cgij clij clgij crj cgrj clrj clgrj \
- cs csg
+ cs csg cds cdsg
check_PROGRAMS = $(INSN_TESTS) \
allexec \
--- /dev/null
+#include <stdint.h>
+#include <stdio.h>
+
+typedef struct {
+ uint64_t high;
+ uint64_t low;
+} quad_word;
+
+void
+test(quad_word op1_init, uint64_t op2_init, quad_word op3_init,
+ int expected_cc)
+{
+ int cc = 1 - expected_cc;
+
+ quad_word op1 = op1_init;
+ uint64_t op2 = op2_init;
+ quad_word op3 = op3_init;
+
+ quad_word op1_before = op1;
+ uint64_t op2_before = op2;
+ quad_word op3_before = op3;
+
+ printf("before op1 = (%#lx, %#lx)\n", op1.high, op1.low);
+ printf("before op2 = %#lx\n", op2);
+ printf("before op3 = (%#lx, %#lx)\n", op3.high, op3.low);
+
+ __asm__ volatile (
+ "lmg %%r0,%%r1,%1\n\t"
+ "lmg %%r2,%%r3,%3\n\t"
+ "cds %%r0,%%r2,%2\n\t" // cds 1st,3rd,2nd
+ "stmg %%r0,%%r1,%1\n" // store r0,r1 to op1
+ "stmg %%r2,%%r3,%3\n" // store r2,r3 to op3
+ "ipm %0\n\t"
+ "srl %0,28\n\t"
+ : "=d" (cc), "+QS" (op1), "+QS" (op2), "+QS" (op3)
+ :
+ : "r0", "r1", "r2", "r3", "cc");
+
+ printf("after op1 = (%#lx, %#lx)\n", op1.high, op1.low);
+ printf("after op2 = %#lx\n", op2);
+ printf("after op3 = (%#lx, %#lx)\n", op3.high, op3.low);
+ printf("cc = %d\n", cc);
+
+ // Check the condition code
+ if (cc != expected_cc) {
+ printf("condition code is incorrect\n");
+ }
+
+ // op3 never changes
+ if (op3.low != op3_before.low || op3.high != op3_before.high) {
+ printf("operand #3 modified\n");
+ }
+
+ if (expected_cc == 0) {
+ // 3rd operand stored at 2nd operand location
+
+ // op1 did not change
+ if (op1.low != op1_before.low || op1.high != op1_before.high) {
+ printf("operand #1 modified\n");
+ }
+
+ // lower 32 bits of op2 are the lower 32 bits of op3.low
+ if ((op2 & 0xffffffff) != (op3.low & 0xffffffff)) {
+ printf("operand #2 [32:63] incorrect\n");
+ }
+ // higher 32 bits of op2 are the lower 32 bits of op3.high
+ if ((op2 >> 32) != (op3.high & 0xffffffff)) {
+ printf("operand #2 [0:31] incorrect\n");
+ }
+ } else {
+ // 2nd operand stored at 1st operand location
+
+ // op2 did not change
+ if (op2 != op2_before) {
+ printf("operand #2 modified\n");
+ }
+
+ // bits [0:31] of op1 (both parts) are unchanged
+ if ((op1.high >> 32) != (op1_before.high >> 32) ||
+ (op1.low >> 32) != (op1_before.low >> 32)) {
+ printf("operand #1 [0:31] modified\n");
+ }
+
+ if ((op1.low & 0xffffffff) != (op2 & 0xffffffff)) {
+ printf("operand #1 low[32:63] incorrect\n");
+ }
+ if ((op1.high & 0xffffffff) != (op2 >> 32)) {
+ printf("operand #1 high[32:63] not updated\n");
+ }
+ }
+}
+
+int main ()
+{
+ quad_word op1, op3;
+ uint64_t op2;
+
+ // (op1.high[32:63], op1.low[32:63]) == op2
+ op1.high = 0x0000000044556677ull;
+ op1.low = 0x111111118899aabbull;
+ op2 = 0x445566778899aabbull;
+
+ op3.high = op3.low = 0xdeadbeefdeadbabeull;
+ test(op1, op2, op3, 0);
+
+ // (op1.high[32:63], op1.low[32:63]) != op2
+ op1.high = 0x1000000000000000ull;
+ op1.low = 0x0000000000000000ull;
+ op2 = 0x8000000000000001ull;;
+ op3.high = op3.low = 0xdeadbeefdeadbabeull;
+ test(op1, op2, op3, 1);
+
+ return 0;
+}
--- /dev/null
+before op1 = (0x44556677, 0x111111118899aabb)
+before op2 = 0x445566778899aabb
+before op3 = (0xdeadbeefdeadbabe, 0xdeadbeefdeadbabe)
+after op1 = (0x44556677, 0x111111118899aabb)
+after op2 = 0xdeadbabedeadbabe
+after op3 = (0xdeadbeefdeadbabe, 0xdeadbeefdeadbabe)
+cc = 0
+before op1 = (0x1000000000000000, 0)
+before op2 = 0x8000000000000001
+before op3 = (0xdeadbeefdeadbabe, 0xdeadbeefdeadbabe)
+after op1 = (0x1000000080000000, 0x1)
+after op2 = 0x8000000000000001
+after op3 = (0xdeadbeefdeadbabe, 0xdeadbeefdeadbabe)
+cc = 1
--- /dev/null
+#include <stdint.h>
+#include <stdio.h>
+
+typedef struct {
+ uint64_t high;
+ uint64_t low;
+} quad_word;
+
+void
+test(quad_word op1_init, quad_word op2_init, quad_word op3_init,
+ int expected_cc)
+{
+ int cc = 1 - expected_cc;
+
+ quad_word op1 = op1_init;
+ quad_word op2 = op2_init;
+ quad_word op3 = op3_init;
+
+ quad_word op1_before = op1;
+ quad_word op2_before = op2;
+ quad_word op3_before = op3;
+
+ printf("before op1 = (%#lx, %#lx)\n", op1.high, op1.low);
+ printf("before op2 = (%#lx, %#lx)\n", op2.high, op2.low);
+ printf("before op3 = (%#lx, %#lx)\n", op3.high, op3.low);
+
+ __asm__ volatile (
+ "lmg %%r0,%%r1,%1\n\t"
+ "lmg %%r2,%%r3,%3\n\t"
+ "cdsg %%r0,%%r2,%2\n\t" // cdsg 1st,3rd,2nd
+ "stmg %%r0,%%r1,%1\n" // store r0,r1 to op1
+ "stmg %%r2,%%r3,%3\n" // store r2,r3 to op3
+ "ipm %0\n\t"
+ "srl %0,28\n\t"
+ : "=d" (cc), "+QS" (op1), "+QS" (op2), "+QS" (op3)
+ :
+ : "r0", "r1", "r2", "r3", "cc");
+
+ printf("after op1 = (%#lx, %#lx)\n", op1.high, op1.low);
+ printf("after op2 = (%#lx, %#lx)\n", op2.high, op2.low);
+ printf("after op3 = (%#lx, %#lx)\n", op3.high, op3.low);
+ printf("cc = %d\n", cc);
+
+ if (cc != expected_cc) {
+ printf("condition code is incorrect\n");
+ }
+
+ // op3 never changes
+ if (op3.low != op3_before.low || op3.high != op3_before.high) {
+ printf("operand #3 modified\n");
+ }
+
+ if (expected_cc == 0) {
+ // 3rd operand stored at 2nd operand location
+
+ // op1 did not change
+ if (op1.low != op1_before.low || op1.high != op1_before.high) {
+ printf("operand #1 modified\n");
+ }
+ if (op2.high != op3.high || op2.low != op3.low) {
+ printf("operand #2 incorrect\n");
+ }
+ } else {
+ // 2nd operand stored at 1st operand location
+
+ // op2 did not change
+ if (op2.low != op2_before.low || op2.high != op2_before.high) {
+ printf("operand #2 modified\n");
+ }
+
+ if (op1.high != op2.high || op1.low != op2.low) {
+ printf("operand #1 incorrect\n");
+ }
+ }
+}
+
+int main ()
+{
+ quad_word op1, op2, op3;
+
+ // op1 == op2
+ op1.high = 0x0011223344556677ull;
+ op1.low = 0x8899aabbccddeeffull;
+ op2 = op1;
+ op3.high = op3.low = 0xdeadbeefdeadbabeull;
+ test(op1, op2, op3, 0);
+
+ // op1 != op2 (only MSB differs)
+ op1.high = 0x8000000000000000ull;
+ op1.low = 0x0000000000000000ull;
+ op2.high = 0;
+ op2.low = 1;
+ op3.high = op3.low = 0xdeadbeefdeadbabeull;
+ test(op1, op2, op3, 1);
+
+ // op1 != op2 (only LSB differs)
+ op1.high = 0x0000000000000000ull;
+ op1.low = 0x0000000000000001ull;
+ op2.high = 1;
+ op2.low = 0;
+ op3.high = op3.low = 0xdeadbeefdeadbabeull;
+ test(op1, op2, op3, 1);
+
+ return 0;
+}
--- /dev/null
+before op1 = (0x11223344556677, 0x8899aabbccddeeff)
+before op2 = (0x11223344556677, 0x8899aabbccddeeff)
+before op3 = (0xdeadbeefdeadbabe, 0xdeadbeefdeadbabe)
+after op1 = (0x11223344556677, 0x8899aabbccddeeff)
+after op2 = (0xdeadbeefdeadbabe, 0xdeadbeefdeadbabe)
+after op3 = (0xdeadbeefdeadbabe, 0xdeadbeefdeadbabe)
+cc = 0
+before op1 = (0x8000000000000000, 0)
+before op2 = (0, 0x1)
+before op3 = (0xdeadbeefdeadbabe, 0xdeadbeefdeadbabe)
+after op1 = (0, 0x1)
+after op2 = (0, 0x1)
+after op3 = (0xdeadbeefdeadbabe, 0xdeadbeefdeadbabe)
+cc = 1
+before op1 = (0, 0x1)
+before op2 = (0x1, 0)
+before op3 = (0xdeadbeefdeadbabe, 0xdeadbeefdeadbabe)
+after op1 = (0x1, 0)
+after op2 = (0x1, 0)
+after op3 = (0xdeadbeefdeadbabe, 0xdeadbeefdeadbabe)
+cc = 1
--- /dev/null
+prog: cdsg