math/mpx.c: Fix two's-complement storing.
authorMark Wooding <mdw@distorted.org.uk>
Sun, 28 May 2017 18:03:08 +0000 (19:03 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Thu, 22 Jun 2017 08:33:20 +0000 (09:33 +0100)
Oh, dear.  This was a bit wrong.

  * The internal representation, in terms of `mpw' vectors, is always
    nonnegative.  Remove the bogus sign-extension machinery for
    `mpx_load*2cn'.

  * The logic for sign-extending octet vectors in `mpx_store*2cn' was
    the wrong way round.  Fix it.

  * Rather than sign-extending `mpw' vectors, it's necessary to apply a
    correction when we reach the end of an octet vector in
    `mpx_load*2cn'.  Introduce a new argument to `MPX_LOADSTORE' to
    carry the necessary correction logic, and use it.

  * The test functions used a single `mpw' vector length for both
    positive and negative values, which meant that the logic for sign-
    extending octet strings on output wasn't exercised.  Fix the test:
    so that it now does two passes, forcing both sign-extension on
    output and zero-extension on input.

math/mpx.c
math/t/mpx

index e759c5f..18baf2f 100644 (file)
  *             @obits@ = width of output units, in bits
  *             @oavail@ = condition expression: is output space available?
  *             @putbits@ = function or macro: write its argument to output
+ *             @fixfinal@ = statements to fix shift register at the end
  *             @clear@ = statements to clear remainder of output
  *
  * Use:                Generates a function to convert between a sequence of
 
 #define MPX_LOADSTORE(name, wconst, oconst, decls,                     \
                      ibits, iavail, getbits, obits, oavail, putbits,   \
-                     clear)                                            \
+                     fixfinal, clear)                                  \
                                                                        \
 void mpx_##name(wconst mpw *v, wconst mpw *vl,                         \
                oconst void *pp, size_t sz)                             \
@@ -157,7 +158,10 @@ void mpx_##name(wconst mpw *v, wconst mpw *vl,                             \
   }                                                                    \
                                                                        \
 flush:                                                                 \
-  while (bits > 0) MPX_PUTBITS(ibits, obits, oavail, putbits);         \
+  if (bits) {                                                          \
+    fixfinal;                                                          \
+    while (bits > 0) MPX_PUTBITS(ibits, obits, oavail, putbits);       \
+  }                                                                    \
   clear;                                                               \
 }
 
@@ -190,13 +194,14 @@ flush:                                                                    \
   *v++ = _t;                                                           \
 } while (0)
 
-#define FLUSHW_2CN do {                                                        \
-  if (c) MPX_ONE(v, vl);                                               \
-  else MPX_ZERO(v, vl);                                                        \
+#define FIXFINALW_2CN do {                                             \
+  if (c && !w && !t);                                                  \
+  else if (bits == 8) t ^= ~(mpw)0xffu;                                        \
+  else t ^= ((mpw)1 << (MPW_BITS - bits + 8)) - 256u;                  \
 } while (0)
 
 #define FLUSHO_2CN do {                                                        \
-  memset(p, c ? 0xff : 0, q - p);                                      \
+  memset(p, c ? 0 : 0xff, q - p);                                      \
 } while (0)
 
 /* --- @mpx_storel@ --- *
@@ -215,7 +220,7 @@ flush:                                                                      \
 MPX_LOADSTORE(storel, const, EMPTY, EMPTY,
              MPW_BITS, (v < vl), GETMPW,
              8, (p < q), PUTOCTETI,
-             { memset(p, 0, q - p); })
+             EMPTY, { memset(p, 0, q - p); })
 
 /* --- @mpx_loadl@ --- *
  *
@@ -233,7 +238,7 @@ MPX_LOADSTORE(storel, const, EMPTY, EMPTY,
 MPX_LOADSTORE(loadl, EMPTY, const, EMPTY,
              8, (p < q), GETOCTETI,
              MPW_BITS, (v < vl), PUTMPW,
-             { MPX_ZERO(v, vl); })
+             EMPTY, { MPX_ZERO(v, vl); })
 
 
 /* --- @mpx_storeb@ --- *
@@ -252,7 +257,7 @@ MPX_LOADSTORE(loadl, EMPTY, const, EMPTY,
 MPX_LOADSTORE(storeb, const, EMPTY, EMPTY,
              MPW_BITS, (v < vl), GETMPW,
              8, (p < q), PUTOCTETD,
-             { memset(p, 0, q - p); })
+             EMPTY, { memset(p, 0, q - p); })
 
 /* --- @mpx_loadb@ --- *
  *
@@ -270,7 +275,7 @@ MPX_LOADSTORE(storeb, const, EMPTY, EMPTY,
 MPX_LOADSTORE(loadb, EMPTY, const, EMPTY,
              8, (p < q), GETOCTETD,
              MPW_BITS, (v < vl), PUTMPW,
-             { MPX_ZERO(v, vl); })
+             EMPTY, { MPX_ZERO(v, vl); })
 
 /* --- @mpx_storel2cn@ --- *
  *
@@ -289,7 +294,7 @@ MPX_LOADSTORE(loadb, EMPTY, const, EMPTY,
 MPX_LOADSTORE(storel2cn, const, EMPTY, DECL_2CN,
              MPW_BITS, (v < vl), GETMPW_2CN,
              8, (p < q), PUTOCTETI,
-             { FLUSHO_2CN; })
+             EMPTY, { FLUSHO_2CN; })
 
 /* --- @mpx_loadl2cn@ --- *
  *
@@ -308,7 +313,7 @@ MPX_LOADSTORE(storel2cn, const, EMPTY, DECL_2CN,
 MPX_LOADSTORE(loadl2cn, EMPTY, const, DECL_2CN,
              8, (p < q), GETOCTETI,
              MPW_BITS, (v < vl), PUTMPW_2CN,
-             { FLUSHW_2CN; })
+             { FIXFINALW_2CN; }, { MPX_ZERO(v, vl); })
 
 /* --- @mpx_storeb2cn@ --- *
  *
@@ -327,7 +332,7 @@ MPX_LOADSTORE(loadl2cn, EMPTY, const, DECL_2CN,
 MPX_LOADSTORE(storeb2cn, const, EMPTY, DECL_2CN,
              MPW_BITS, (v < vl), GETMPW_2CN,
              8, (p < q), PUTOCTETD,
-             { FLUSHO_2CN; })
+             EMPTY, { FLUSHO_2CN; })
 
 /* --- @mpx_loadb2cn@ --- *
  *
@@ -346,7 +351,7 @@ MPX_LOADSTORE(storeb2cn, const, EMPTY, DECL_2CN,
 MPX_LOADSTORE(loadb2cn, EMPTY, const, DECL_2CN,
              8, (p < q), GETOCTETD,
              MPW_BITS, (v < vl), PUTMPW_2CN,
-             { FLUSHW_2CN; })
+             { FIXFINALW_2CN; }, { MPX_ZERO(v, vl); })
 
 /*----- Logical shifting --------------------------------------------------*/
 
@@ -1376,29 +1381,34 @@ static int loadstore(dstr *v)
 static int twocl(dstr *v)
 {
   dstr d = DSTR_INIT;
-  mpw *m, *ml;
-  size_t sz;
+  mpw *m, *ml0, *ml1;
+  size_t sz0, sz1, szmax;
   int ok = 1;
+  int i;
 
-  sz = v[0].len; if (v[1].len > sz) sz = v[1].len;
-  dstr_ensure(&d, sz);
+  sz0 = MPW_RQ(v[0].len); sz1 = MPW_RQ(v[1].len);
+  dstr_ensure(&d, v[0].len > v[1].len ? v[0].len : v[1].len);
 
-  sz = MPW_RQ(sz);
-  m = xmalloc(MPWS(sz));
-  ml = m + sz;
+  szmax = sz0 > sz1 ? sz0 : sz1;
+  m = xmalloc(MPWS(szmax));
+  ml0 = m + sz0; ml1 = m + sz1;
 
-  mpx_loadl(m, ml, v[0].buf, v[0].len);
-  mpx_storel2cn(m, ml, d.buf, v[1].len);
-  if (memcmp(d.buf, v[1].buf, v[1].len)) {
-    dumpbits("\n*** storel2cn failed", d.buf, v[1].len);
-    ok = 0;
-  }
+  for (i = 0; i < 2; i++) {
+    if (i) ml0 = ml1 = m + szmax;
 
-  mpx_loadl2cn(m, ml, v[1].buf, v[1].len);
-  mpx_storel(m, ml, d.buf, v[0].len);
-  if (memcmp(d.buf, v[0].buf, v[0].len)) {
-    dumpbits("\n*** loadl2cn failed", d.buf, v[0].len);
-    ok = 0;
+    mpx_loadl(m, ml0, v[0].buf, v[0].len);
+    mpx_storel2cn(m, ml0, d.buf, v[1].len);
+    if (memcmp(d.buf, v[1].buf, v[1].len)) {
+      dumpbits("\n*** storel2cn failed", d.buf, v[1].len);
+      ok = 0;
+    }
+
+    mpx_loadl2cn(m, ml1, v[1].buf, v[1].len);
+    mpx_storel(m, ml1, d.buf, v[0].len);
+    if (memcmp(d.buf, v[0].buf, v[0].len)) {
+      dumpbits("\n*** loadl2cn failed", d.buf, v[0].len);
+      ok = 0;
+    }
   }
 
   if (!ok) {
@@ -1415,29 +1425,34 @@ static int twocl(dstr *v)
 static int twocb(dstr *v)
 {
   dstr d = DSTR_INIT;
-  mpw *m, *ml;
-  size_t sz;
+  mpw *m, *ml0, *ml1;
+  size_t sz0, sz1, szmax;
   int ok = 1;
+  int i;
 
-  sz = v[0].len; if (v[1].len > sz) sz = v[1].len;
-  dstr_ensure(&d, sz);
+  sz0 = MPW_RQ(v[0].len); sz1 = MPW_RQ(v[1].len);
+  dstr_ensure(&d, v[0].len > v[1].len ? v[0].len : v[1].len);
 
-  sz = MPW_RQ(sz);
-  m = xmalloc(MPWS(sz));
-  ml = m + sz;
+  szmax = sz0 > sz1 ? sz0 : sz1;
+  m = xmalloc(MPWS(szmax));
+  ml0 = m + sz0; ml1 = m + sz1;
 
-  mpx_loadb(m, ml, v[0].buf, v[0].len);
-  mpx_storeb2cn(m, ml, d.buf, v[1].len);
-  if (memcmp(d.buf, v[1].buf, v[1].len)) {
-    dumpbits("\n*** storeb2cn failed", d.buf, v[1].len);
-    ok = 0;
-  }
+  for (i = 0; i < 2; i++) {
+    if (i) ml0 = ml1 = m + szmax;
 
-  mpx_loadb2cn(m, ml, v[1].buf, v[1].len);
-  mpx_storeb(m, ml, d.buf, v[0].len);
-  if (memcmp(d.buf, v[0].buf, v[0].len)) {
-    dumpbits("\n*** loadb2cn failed", d.buf, v[0].len);
-    ok = 0;
+    mpx_loadb(m, ml0, v[0].buf, v[0].len);
+    mpx_storeb2cn(m, ml0, d.buf, v[1].len);
+    if (memcmp(d.buf, v[1].buf, v[1].len)) {
+      dumpbits("\n*** storeb2cn failed", d.buf, v[1].len);
+      ok = 0;
+    }
+
+    mpx_loadb2cn(m, ml1, v[1].buf, v[1].len);
+    mpx_storeb(m, ml1, d.buf, v[0].len);
+    if (memcmp(d.buf, v[0].buf, v[0].len)) {
+      dumpbits("\n*** loadb2cn failed", d.buf, v[0].len);
+      ok = 0;
+    }
   }
 
   if (!ok) {
index bf104e9..f5caed2 100644 (file)
@@ -23,8 +23,25 @@ load-store {
 2cb {
   "" "";
   00 00;
+  0000 00;
+  000000 00;
+  00000000 00;
+  0000000000 00;
+  00 0000;
+  00 000000;
+  00 00000000;
+  00 0000000000;
   000000 00000000000000000000;
-  01 ff;
+  0001 ff;
+  000001 ff;
+  00000001 ff;
+  0000000001 ff;
+  01 ffffff;
+  01 ffffffff;
+  01 ffffffffff;
+  01 ffff;
+  00007f01 80ff;
+  40 ffffffffffffffffffffffc0;
   0123456789abcdef fedcba9876543211;
   0123456789abcdef fffffffedcba9876543211;
   0100000000 ffffff00000000;
@@ -35,8 +52,25 @@ load-store {
 2cl {
   "" "";
   00 00;
+  0000 00;
+  000000 00;
+  00000000 00;
+  0000000000 00;
+  00 0000;
+  00 000000;
+  00 00000000;
+  00 0000000000;
   000000 00000000000000000000;
+  0100 ff;
+  010000 ff;
+  01000000 ff;
+  0100000000 ff;
+  01 ffffff;
+  01 ffffffff;
+  01 ffffffffff;
   01 ff;
+  017f0000 ff80;
+  40 c0ffffffffffffffffffffff;
   efcdab8967452301 1132547698badcfe;
   efcdab8967452301 1132547698badcfeffffffff;
   0000000001 00000000ffffffff;