|
From: <sv...@va...> - 2012-06-06 02:28:09
|
florian 2012-06-06 03:27:51 +0100 (Wed, 06 Jun 2012)
New Revision: 12615
Log:
Support "compare double ansd swap" insns: CDS, CDSY, and CDSG
valgrind bits for fixing bugzilla #291865. See also VEX r2372.
Added files:
trunk/memcheck/tests/s390x/cds.c
trunk/memcheck/tests/s390x/cds.stderr.exp
trunk/memcheck/tests/s390x/cds.stdout.exp
trunk/memcheck/tests/s390x/cds.vgtest
trunk/memcheck/tests/s390x/cdsg.c
trunk/memcheck/tests/s390x/cdsg.stderr.exp
trunk/memcheck/tests/s390x/cdsg.stdout.exp
trunk/memcheck/tests/s390x/cdsg.vgtest
trunk/none/tests/s390x/cds.c
trunk/none/tests/s390x/cds.stderr.exp
trunk/none/tests/s390x/cds.stdout.exp
trunk/none/tests/s390x/cds.vgtest
trunk/none/tests/s390x/cdsg.c
trunk/none/tests/s390x/cdsg.stderr.exp
trunk/none/tests/s390x/cdsg.stdout.exp
trunk/none/tests/s390x/cdsg.vgtest
Modified directories:
trunk/memcheck/tests/s390x/
trunk/none/tests/s390x/
Modified files:
trunk/NEWS
trunk/docs/internals/s390-opcodes.csv
trunk/memcheck/tests/s390x/Makefile.am
trunk/none/tests/s390x/Makefile.am
Modified: trunk/memcheck/tests/s390x/
Modified: trunk/none/tests/s390x/
Added: trunk/memcheck/tests/s390x/cds.vgtest (+2 -0)
===================================================================
--- trunk/memcheck/tests/s390x/cds.vgtest 2012-06-05 12:10:19 +01:00 (rev 12614)
+++ trunk/memcheck/tests/s390x/cds.vgtest 2012-06-06 03:27:51 +01:00 (rev 12615)
@@ -0,0 +1,2 @@
+prog: cds
+vgopts: -q
Added: trunk/none/tests/s390x/cds.stderr.exp (+2 -0)
===================================================================
--- trunk/none/tests/s390x/cds.stderr.exp 2012-06-05 12:10:19 +01:00 (rev 12614)
+++ trunk/none/tests/s390x/cds.stderr.exp 2012-06-06 03:27:51 +01:00 (rev 12615)
@@ -0,0 +1,2 @@
+
+
Added: trunk/none/tests/s390x/cdsg.vgtest (+1 -0)
===================================================================
--- trunk/none/tests/s390x/cdsg.vgtest 2012-06-05 12:10:19 +01:00 (rev 12614)
+++ trunk/none/tests/s390x/cdsg.vgtest 2012-06-06 03:27:51 +01:00 (rev 12615)
@@ -0,0 +1 @@
+prog: cdsg
Added: trunk/none/tests/s390x/cds.vgtest (+1 -0)
===================================================================
--- trunk/none/tests/s390x/cds.vgtest 2012-06-05 12:10:19 +01:00 (rev 12614)
+++ trunk/none/tests/s390x/cds.vgtest 2012-06-06 03:27:51 +01:00 (rev 12615)
@@ -0,0 +1 @@
+prog: cds
Added: trunk/memcheck/tests/s390x/cdsg.stdout.exp (+0 -0)
===================================================================
Added: trunk/memcheck/tests/s390x/cdsg.stderr.exp (+10 -0)
===================================================================
--- trunk/memcheck/tests/s390x/cdsg.stderr.exp 2012-06-05 12:10:19 +01:00 (rev 12614)
+++ trunk/memcheck/tests/s390x/cdsg.stderr.exp 2012-06-06 03:27:51 +01:00 (rev 12615)
@@ -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)
+
Property changed: trunk/memcheck/tests/s390x (+0 -0)
___________________________________________________________________
Name: svn:ignore
- .deps
Makefile
Makefile.in
cs
csg
+ .deps
Makefile
Makefile.in
cs
csg
cds
cdsg
Modified: trunk/NEWS (+1 -0)
===================================================================
--- trunk/NEWS 2012-06-05 12:10:19 +01:00 (rev 12614)
+++ trunk/NEWS 2012-06-06 03:27:51 +01:00 (rev 12615)
@@ -90,6 +90,7 @@
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
Added: trunk/none/tests/s390x/cdsg.stderr.exp (+2 -0)
===================================================================
--- trunk/none/tests/s390x/cdsg.stderr.exp 2012-06-05 12:10:19 +01:00 (rev 12614)
+++ trunk/none/tests/s390x/cdsg.stderr.exp 2012-06-06 03:27:51 +01:00 (rev 12615)
@@ -0,0 +1,2 @@
+
+
Added: trunk/memcheck/tests/s390x/cdsg.c (+65 -0)
===================================================================
--- trunk/memcheck/tests/s390x/cdsg.c 2012-06-05 12:10:19 +01:00 (rev 12614)
+++ trunk/memcheck/tests/s390x/cdsg.c 2012-06-06 03:27:51 +01:00 (rev 12615)
@@ -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;
+}
Added: trunk/none/tests/s390x/cdsg.stdout.exp (+21 -0)
===================================================================
--- trunk/none/tests/s390x/cdsg.stdout.exp 2012-06-05 12:10:19 +01:00 (rev 12614)
+++ trunk/none/tests/s390x/cdsg.stdout.exp 2012-06-06 03:27:51 +01:00 (rev 12615)
@@ -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
Added: trunk/none/tests/s390x/cds.c (+114 -0)
===================================================================
--- trunk/none/tests/s390x/cds.c 2012-06-05 12:10:19 +01:00 (rev 12614)
+++ trunk/none/tests/s390x/cds.c 2012-06-06 03:27:51 +01:00 (rev 12615)
@@ -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;
+}
Property changed: trunk/none/tests/s390x (+0 -0)
___________________________________________________________________
Name: svn:ignore
- .deps
add
add_EI
add_GE
allexec
and
and_EI
clc
clcle
cvb
cvd
div
ex_clone
ex_sig
flogr
icm
insert
insert_EI
lam_stam
lpr
Makefile
Makefile.in
mul
mul_GE
mvst
or
or_EI
srst
sub
sub_EI
tcxb
xc
xor
xor_EI
stck
stcke
stckf
op_exception
fgx
condloadstore
fold_And16
stfle
op00
cksm
clcl
mvcl
troo
trot
trto
trtt
tr
tre
clrj
clgrj
crj
cgrj
clij
clgij
cij
cgij
cs
csg
+ .deps
add
add_EI
add_GE
allexec
and
and_EI
clc
clcle
cvb
cvd
div
ex_clone
ex_sig
flogr
icm
insert
insert_EI
lam_stam
lpr
Makefile
Makefile.in
mul
mul_GE
mvst
or
or_EI
srst
sub
sub_EI
tcxb
xc
xor
xor_EI
stck
stcke
stckf
op_exception
fgx
condloadstore
fold_And16
stfle
op00
cksm
clcl
mvcl
troo
trot
trto
trtt
tr
tre
clrj
clgrj
crj
cgrj
clij
clgij
cij
cgij
cs
csg
cds
cdsg
Added: trunk/memcheck/tests/s390x/cds.stdout.exp (+0 -0)
===================================================================
Added: trunk/memcheck/tests/s390x/cds.stderr.exp (+10 -0)
===================================================================
--- trunk/memcheck/tests/s390x/cds.stderr.exp 2012-06-05 12:10:19 +01:00 (rev 12614)
+++ trunk/memcheck/tests/s390x/cds.stderr.exp 2012-06-06 03:27:51 +01:00 (rev 12615)
@@ -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)
+
Added: trunk/none/tests/s390x/cds.stdout.exp (+14 -0)
===================================================================
--- trunk/none/tests/s390x/cds.stdout.exp 2012-06-05 12:10:19 +01:00 (rev 12614)
+++ trunk/none/tests/s390x/cds.stdout.exp 2012-06-06 03:27:51 +01:00 (rev 12615)
@@ -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
Added: trunk/memcheck/tests/s390x/cds.c (+82 -0)
===================================================================
--- trunk/memcheck/tests/s390x/cds.c 2012-06-05 12:10:19 +01:00 (rev 12614)
+++ trunk/memcheck/tests/s390x/cds.c 2012-06-06 03:27:51 +01:00 (rev 12615)
@@ -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;
+}
Added: trunk/memcheck/tests/s390x/cdsg.vgtest (+2 -0)
===================================================================
--- trunk/memcheck/tests/s390x/cdsg.vgtest 2012-06-05 12:10:19 +01:00 (rev 12614)
+++ trunk/memcheck/tests/s390x/cdsg.vgtest 2012-06-06 03:27:51 +01:00 (rev 12615)
@@ -0,0 +1,2 @@
+prog: cdsg
+vgopts: -q
Modified: trunk/memcheck/tests/s390x/Makefile.am (+1 -1)
===================================================================
--- trunk/memcheck/tests/s390x/Makefile.am 2012-06-05 12:10:19 +01:00 (rev 12614)
+++ trunk/memcheck/tests/s390x/Makefile.am 2012-06-06 03:27:51 +01:00 (rev 12615)
@@ -2,7 +2,7 @@
dist_noinst_SCRIPTS = filter_stderr
-INSN_TESTS = cs csg
+INSN_TESTS = cs csg cds cdsg
check_PROGRAMS = $(INSN_TESTS)
Modified: trunk/docs/internals/s390-opcodes.csv (+3 -3)
===================================================================
--- trunk/docs/internals/s390-opcodes.csv 2012-06-05 12:10:19 +01:00 (rev 12614)
+++ trunk/docs/internals/s390-opcodes.csv 2012-06-06 03:27:51 +01:00 (rev 12615)
@@ -30,7 +30,7 @@
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 @@
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 @@
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,
Modified: trunk/none/tests/s390x/Makefile.am (+1 -1)
===================================================================
--- trunk/none/tests/s390x/Makefile.am 2012-06-05 12:10:19 +01:00 (rev 12614)
+++ trunk/none/tests/s390x/Makefile.am 2012-06-06 03:27:51 +01:00 (rev 12615)
@@ -7,7 +7,7 @@
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 \
Added: trunk/none/tests/s390x/cdsg.c (+105 -0)
===================================================================
--- trunk/none/tests/s390x/cdsg.c 2012-06-05 12:10:19 +01:00 (rev 12614)
+++ trunk/none/tests/s390x/cdsg.c 2012-06-06 03:27:51 +01:00 (rev 12615)
@@ -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;
+}
|