Support "compare double ansd swap" insns: CDS, CDSY, and CDSG

valgrind bits for fixing bugzilla #291865. See also VEX r2372.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@12615
This commit is contained in:
Florian Krohm 2012-06-06 02:27:51 +00:00
parent 15d92f3799
commit 932ea4ad94
20 changed files with 437 additions and 5 deletions

1
NEWS
View File

@ -90,6 +90,7 @@ where XXXXXX is the bug number as listed below.
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

View File

@ -30,7 +30,7 @@ bxle,"branch on index low or equal",implemented,
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",
@ -441,7 +441,7 @@ strag,"store read address",N/A,"privileged instruction"
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,
@ -573,7 +573,7 @@ niy,"and immediate with long offset",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,

1 a add implemented
30 c compare implemented
31 cd compare (long) not implemented
32 cdr compare (long) not implemented
33 cds compare double and swap not implemented implemented open bugzilla
34 ce compare (short) not implemented
35 cer compare (short) not implemented
36 cfc compare and form codeword not implemented
441 stctg store control 64 N/A privileged instruction
442 lctlg load control 64 N/A privileged instruction
443 csg compare and swap 64 implemented
444 cdsg compare double and swap 64 not implemented implemented open bugzilla
445 clmh compare logical characters under mask high implemented
446 stcmh store characters under mask high implemented
447 icmh insert characters under mask high implemented
573 ny and with long offset implemented
574 cy compare with long offset implemented
575 csy compare and swap with long offset implemented
576 cdsy compare double and swap with long offset not implemented implemented open bugzilla
577 chy compare halfword with long offset implemented
578 cly compare logical with long offset implemented
579 cliy compare logical immediate with long offset implemented

View File

@ -2,7 +2,7 @@ include $(top_srcdir)/Makefile.tool-tests.am
dist_noinst_SCRIPTS = filter_stderr
INSN_TESTS = cs csg
INSN_TESTS = cs csg cds cdsg
check_PROGRAMS = $(INSN_TESTS)

View File

@ -0,0 +1,82 @@
#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;
}

View File

@ -0,0 +1,10 @@
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)

View File

View File

@ -0,0 +1,2 @@
prog: cds
vgopts: -q

View File

@ -0,0 +1,65 @@
#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;
}

View File

@ -0,0 +1,10 @@
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)

View File

View File

@ -0,0 +1,2 @@
prog: cdsg
vgopts: -q

View File

@ -7,7 +7,7 @@ INSN_TESTS = clc clcle cvb cvd icm lpr tcxb lam_stam xc mvst add sub mul \
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 \

114
none/tests/s390x/cds.c Normal file
View File

@ -0,0 +1,114 @@
#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;
}

View File

@ -0,0 +1,2 @@

View File

@ -0,0 +1,14 @@
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

View File

@ -0,0 +1 @@
prog: cds

105
none/tests/s390x/cdsg.c Normal file
View File

@ -0,0 +1,105 @@
#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;
}

View File

@ -0,0 +1,2 @@

View File

@ -0,0 +1,21 @@
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

View File

@ -0,0 +1 @@
prog: cdsg