From: Florian Krohm Date: Thu, 11 Aug 2011 17:00:15 +0000 (+0000) Subject: Non-VEX changes to fix #275517. X-Git-Tag: svn/VALGRIND_3_7_0~271 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6fb27ec7809335e9639c8a6cfacd74316566e246;p=thirdparty%2Fvalgrind.git Non-VEX changes to fix #275517. Add testcase and announce fix in NEWS. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@11966 --- diff --git a/NEWS b/NEWS index 82303f867d..2666a89456 100644 --- a/NEWS +++ b/NEWS @@ -271,6 +271,8 @@ fixed 279062 - Remove a redundant check in the insn selector for ppc. +275517 - s390x: Provide support for CKSM instruction + Release 3.6.1 (16 February 2011) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/none/tests/s390x/Makefile.am b/none/tests/s390x/Makefile.am index a7b25660c0..669e196504 100644 --- a/none/tests/s390x/Makefile.am +++ b/none/tests/s390x/Makefile.am @@ -5,7 +5,7 @@ dist_noinst_SCRIPTS = filter_stderr INSN_TESTS = clc clcle cvb cvd icm lpr tcxb lam_stam xc mvst add sub mul \ and or xor insert div srst fold_And16 flogr sub_EI add_EI \ and_EI or_EI xor_EI insert_EI mul_GE add_GE condloadstore \ - op_exception fgx stck stckf stcke stfle op00 + op_exception fgx stck stckf stcke stfle op00 cksm check_PROGRAMS = $(INSN_TESTS) \ ex_sig \ diff --git a/none/tests/s390x/cksm.c b/none/tests/s390x/cksm.c new file mode 100644 index 0000000000..6051a06682 --- /dev/null +++ b/none/tests/s390x/cksm.c @@ -0,0 +1,295 @@ +#include +#include +#include +#include "test.h" + +uint32_t data[64]; + +/* The result of a checksum operation */ +typedef struct { + uint64_t addr; + uint64_t len; + uint32_t sum; + char cc; +} cksm_t; + + +/* Compute the checksum via the cksm insn */ +static __attribute__((noinline)) cksm_t +cksm_by_insn(const uint32_t *buff, uint64_t len, uint32_t sum) +{ + const uint32_t *init_addr = buff; + uint64_t init_length = len; + uint64_t addr; + char cc; + cksm_t result; + register uint64_t reg2 asm("2") = (uint64_t) buff; + register uint64_t reg3 asm("3") = len; + + asm volatile( " lhi 4,42\n\t" + " xr 4,4\n\t" /* set cc to != 0 */ + "0: cksm %0,%1\n\t" /* do checksum on longs */ + " jo 0b\n\t" + : "+d" (sum), "+d" (reg2), "+d" (reg3) : : "cc", "memory"); + + cc = get_cc(); + len = reg3; + addr = reg2; + + /* Check the results */ + if(addr != (uint64_t)init_addr + init_length) + printf("FAIL: address not updated properly\n"); + + if(len != 0) + printf("FAIL: length not zero\n"); + + if (cc != 0) + printf("FAIL: condition code not zero\n"); + + result.addr = addr; + result.len = len; + result.cc = cc; + result.sum = sum; + + return result; +} + + +/* Compute the checksum via hand-crafted algorithm */ +static __attribute__((noinline)) cksm_t +cksm_by_hand(const uint32_t *buff, uint64_t len, uint32_t sum) +{ + cksm_t result; + unsigned int n; + uint64_t v64; + uint32_t final; + + for (n=0; n < len/4; n++) { + /* Add 4 bytes to the sum. Do this in 64-bit arithmetic so it's + easy to see whether there was a carry-out. */ + v64 = sum; + v64 += buff[n]; + /* If there was a carry-out, add 1 to the sum. */ + if (v64 >> 32) + sum = sum + buff[n] + 1; + else + sum = sum + buff[n]; + } + + if (len != 0) { + switch (len % 4) { + case 0: + final = 0; // suppress gcc warning + /* done */ + break; + + case 1: + final = buff[n] & 0xFF000000; + break; + + case 2: + final = buff[n] & 0xFFFF0000; + break; + + case 3: + final = buff[n] & 0xFFFFFF00; + break; + } + + if (len % 4) { + v64 = sum; + v64 += final; + /* If there was a carry-out, add 1 to the sum. */ + if (v64 >> 32) + sum = sum + final + 1; + else + sum = sum + final; + } + } + + result.addr = (uint64_t)buff + len; + result.len = 0; + result.cc = 0; + result.sum = sum; + + return result; +} + +/* The results computed by-insn and by-hand must compare equal and + the sum must be identical to EXPECTED_SUM. */ +int +compare_results(cksm_t by_hand, cksm_t by_insn, uint32_t expected_sum) +{ + int rc = 0; + + if (by_hand.sum != by_insn.sum) { + ++rc; + printf("FAIL: sum: by-hand %"PRIx32" by-insn %"PRIx32"\n", + by_hand.sum, by_insn.sum); + } + + if (by_hand.addr != by_insn.addr) { + ++rc; + printf("FAIL: addr: by-hand %"PRIx64" by-insn %"PRIx64"\n", + by_hand.addr, by_insn.addr); + } + + if (by_hand.len != by_insn.len) { + ++rc; + printf("FAIL: len: by-hand %"PRIx64" by-insn %"PRIx64"\n", + by_hand.len, by_insn.len); + } + + if (by_hand.cc != by_insn.cc) { + ++rc; + printf("FAIL: cc: by-hand %d by-insn %d\n", + by_hand.cc, by_insn.cc); + } + + if (by_insn.sum != expected_sum) { + ++rc; + printf("FAIL: sum: by-insn %"PRIx32" expected %"PRIx32"\n", + by_insn.sum, expected_sum); + } + + if (by_hand.sum != expected_sum) { + ++rc; + printf("FAIL: sum: by-hand %"PRIx32" expected %"PRIx32"\n", + by_hand.sum, expected_sum); + } + + return rc; +} + +/* Run a testcase. Compute the checksum by-hand and by-insn and compare + the results */ +void +run_test(const char *name, const uint32_t *buff, uint64_t len, uint32_t sum, + uint32_t expected_sum) +{ + cksm_t by_hand, by_insn; + + by_hand = cksm_by_hand(buff, len, sum); + by_insn = cksm_by_insn(buff, len, sum); + if (compare_results(by_hand, by_insn, expected_sum) != 0) { + printf("%s failed\n", name); + } +} + +int main () +{ + uint32_t sum, expected_sum; + uint64_t len; + + /* ---------------- test 1 ------------------------------ */ + /* Add one word to an initial sum; no carry */ + sum = 2; + data[0] = 1; + len = 4; + expected_sum = 3; + run_test("test1", data, len, sum, expected_sum); + + /* ---------------- test 2 ------------------------------ */ + /* Add one word to an initial sum; with carry */ + sum = 1; + data[0] = 0xffffffff; + len = 4; + expected_sum = 1; + run_test("test2", data, len, sum, expected_sum); + + /* ---------------- test 3 ------------------------------ */ + /* Add 15 words to an initial sum; no carry */ + sum = 0x1; + data[0] = 0x4; + data[1] = 0x10; + data[2] = 0x40; + data[3] = 0x100; + data[4] = 0x400; + data[5] = 0x1000; + data[6] = 0x4000; + data[7] = 0x10000; + data[8] = 0x40000; + data[9] = 0x100000; + data[10] = 0x400000; + data[11] = 0x1000000; + data[12] = 0x4000000; + data[13] = 0x10000000; + data[14] = 0x40000000; + len = 60; + expected_sum = 0x55555555; + run_test("test3", data, len, sum, expected_sum); + + /* ---------------- test 4 ------------------------------ */ + /* Add some words such that every addition generates a carry. + The data is such that the least significant byte is zero, + and the carrys from intermediate additions will accumulate + in the least significant byte. */ + sum = 0xff000000; + data[0] = 0x80000000; /* 7f0000001 */ + data[1] = 0x85000000; /* 040000002 */ + data[2] = 0xff000000; /* 030000003 */ + data[3] = 0xff000000; /* 020000004 */ + data[4] = 0xff000000; /* 010000005 */ + data[5] = 0xff000000; /* 000000006 */ + len = 24; + expected_sum = 0x00000006; + run_test("test4", data, len, sum, expected_sum); + + /* ---------------- test 5 ------------------------------ */ + /* No words are added. Pass a NULL pointer so an attempt to + load would raise a SIGSEGV. */ + len = 0; + sum = 42; + expected_sum = sum; + run_test("test5", NULL, len, sum, expected_sum); + + /* ---------------- test 6 ------------------------------ */ + /* Add 1 byte; no carry */ + sum = 0x02000000; + len = 1; + data[0] = 0x7fffffff; + expected_sum = 0x81000000; + run_test("test6", data, len, sum, expected_sum); + + /* ---------------- test 7 ------------------------------ */ + /* Add 1 byte; carry */ + sum = 0x02000000; + len = 1; + data[0] = 0xffffffff; + expected_sum = 0x01000001; + run_test("test7", data, len, sum, expected_sum); + + /* ---------------- test 8 ------------------------------ */ + /* Add 2 bytes; no carry */ + sum = 0x00020000; + len = 2; + data[0] = 0x7fffffff; + expected_sum = 0x80010000; + run_test("test8", data, len, sum, expected_sum); + + /* ---------------- test 9 ------------------------------ */ + /* Add 2 bytes; carry */ + sum = 0x00020000; + len = 2; + data[0] = 0xffffffff; + expected_sum = 0x00010001; + run_test("test9", data, len, sum, expected_sum); + + /* ---------------- test 10 ------------------------------ */ + /* Add 3 bytes; no carry */ + sum = 0x00000200; + len = 3; + data[0] = 0x7fffffff; + expected_sum = 0x80000100; + run_test("test10", data, len, sum, expected_sum); + + /* ---------------- test 11 ------------------------------ */ + /* Add 3 bytes; carry */ + sum = 0x00000200; + len = 3; + data[0] = 0xffffffff; + expected_sum = 0x00000101; + run_test("test11", data, len, sum, expected_sum); + + return 0; +} diff --git a/none/tests/s390x/cksm.stderr.exp b/none/tests/s390x/cksm.stderr.exp new file mode 100644 index 0000000000..139597f9cb --- /dev/null +++ b/none/tests/s390x/cksm.stderr.exp @@ -0,0 +1,2 @@ + + diff --git a/none/tests/s390x/cksm.stdout.exp b/none/tests/s390x/cksm.stdout.exp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/none/tests/s390x/cksm.vgtest b/none/tests/s390x/cksm.vgtest new file mode 100644 index 0000000000..2d981bb4d6 --- /dev/null +++ b/none/tests/s390x/cksm.vgtest @@ -0,0 +1 @@ +prog: cksm