]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Non-VEX changes to fix #275517.
authorFlorian Krohm <florian@eich-krohm.de>
Thu, 11 Aug 2011 17:00:15 +0000 (17:00 +0000)
committerFlorian Krohm <florian@eich-krohm.de>
Thu, 11 Aug 2011 17:00:15 +0000 (17:00 +0000)
Add testcase and announce fix in NEWS.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@11966

NEWS
none/tests/s390x/Makefile.am
none/tests/s390x/cksm.c [new file with mode: 0644]
none/tests/s390x/cksm.stderr.exp [new file with mode: 0644]
none/tests/s390x/cksm.stdout.exp [new file with mode: 0644]
none/tests/s390x/cksm.vgtest [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 82303f867d637ca65a50b3717663c30970c33ca0..2666a89456e47c1fd0ec52127ca9243851b3a4a8 100644 (file)
--- 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)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
index a7b25660c0a158d048c3558c55f6a5dffcc6098e..669e196504b311ee69a227e60b97d322d18c05a1 100644 (file)
@@ -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 (file)
index 0000000..6051a06
--- /dev/null
@@ -0,0 +1,295 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+#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 (file)
index 0000000..139597f
--- /dev/null
@@ -0,0 +1,2 @@
+
+
diff --git a/none/tests/s390x/cksm.stdout.exp b/none/tests/s390x/cksm.stdout.exp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/none/tests/s390x/cksm.vgtest b/none/tests/s390x/cksm.vgtest
new file mode 100644 (file)
index 0000000..2d981bb
--- /dev/null
@@ -0,0 +1 @@
+prog: cksm