summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mpz/inp_raw.c69
-rw-r--r--mpz/out_raw.c78
2 files changed, 119 insertions, 28 deletions
diff --git a/mpz/inp_raw.c b/mpz/inp_raw.c
index 5db1202d7..58a8b9fc9 100644
--- a/mpz/inp_raw.c
+++ b/mpz/inp_raw.c
@@ -115,31 +115,74 @@ mpz_inp_raw (mpz_ptr x, FILE *fp)
abs_csize = ABS (csize);
/* round up to a multiple of limbs */
- abs_xsize = (abs_csize + BYTES_PER_MP_LIMB-1) / BYTES_PER_MP_LIMB;
+ abs_xsize = (abs_csize*8 + GMP_NUMB_BITS-1) / GMP_NUMB_BITS;
if (abs_xsize != 0)
{
MPZ_REALLOC (x, abs_xsize);
xp = PTR(x);
- /* get limb boundaries right in the read */
+ /* Get limb boundaries right in the read, for the benefit of the
+ non-nails case. */
xp[0] = 0;
cp = (char *) (xp + abs_xsize) - abs_csize;
if (fread (cp, abs_csize, 1, fp) != 1)
return 0;
- /* Reverse limbs to least significant first, and byte swap. If
- abs_xsize is odd then on the last iteration elimb and slimb are the
- same. It doesn't seem extra code to handle that case separately,
- to save an NTOH. */
- sp = xp;
- ep = xp + abs_xsize-1;
- for (i = 0; i < (abs_xsize+1)/2; i++)
+ if (GMP_NAIL_BITS == 0)
{
- NTOH_LIMB_FETCH (elimb, ep);
- NTOH_LIMB_FETCH (slimb, sp);
- *sp++ = elimb;
- *ep-- = slimb;
+ /* Reverse limbs to least significant first, and byte swap. If
+ abs_xsize is odd then on the last iteration elimb and slimb are
+ the same. It doesn't seem extra code to handle that case
+ separately, to save an NTOH. */
+ sp = xp;
+ ep = xp + abs_xsize-1;
+ for (i = 0; i < (abs_xsize+1)/2; i++)
+ {
+ NTOH_LIMB_FETCH (elimb, ep);
+ NTOH_LIMB_FETCH (slimb, sp);
+ *sp++ = elimb;
+ *ep-- = slimb;
+ }
+ }
+ else
+ {
+ /* It ought to be possible to do the transformation in-place, but
+ for now it's easier to use an extra temporary area. */
+ mp_limb_t byte, limb;
+ int bits;
+ mp_size_t tpos;
+ mp_ptr tp;
+ TMP_DECL (marker);
+
+ TMP_MARK (marker);
+ tp = TMP_ALLOC_LIMBS (abs_xsize);
+ limb = 0;
+ bits = 0;
+ tpos = 0;
+ for (i = abs_csize-1; i >= 0; i--)
+ {
+ byte = (unsigned char) cp[i];
+ limb |= (byte << bits);
+ bits += 8;
+ if (bits >= GMP_NUMB_BITS)
+ {
+ ASSERT (tpos < abs_xsize);
+ tp[tpos++] = limb & GMP_NUMB_MASK;
+ bits -= GMP_NUMB_BITS;
+ ASSERT (bits < 8);
+ limb = byte >> (8 - bits);
+ }
+ }
+ if (bits != 0)
+ {
+ ASSERT (tpos < abs_xsize);
+ tp[tpos++] = limb;
+ }
+ ASSERT (tpos == abs_xsize);
+
+ MPN_COPY (xp, tp, abs_xsize);
+ TMP_FREE (marker);
}
/* GMP 1.x mpz_out_raw wrote high zero bytes, strip any high zero
diff --git a/mpz/out_raw.c b/mpz/out_raw.c
index b3895e57b..0dafaa2fb 100644
--- a/mpz/out_raw.c
+++ b/mpz/out_raw.c
@@ -93,7 +93,7 @@ mpz_out_raw (FILE *fp, mpz_srcptr x)
xsize = SIZ(x);
abs_xsize = ABS (xsize);
- bytes = BYTES_PER_MP_LIMB * abs_xsize;
+ bytes = (abs_xsize * GMP_NUMB_BITS + 7) / 8;
tsize = ROUND_UP_MULTIPLE ((unsigned) 4, BYTES_PER_MP_LIMB) + bytes;
tp = __GMP_ALLOCATE_FUNC_TYPE (tsize, char);
@@ -101,27 +101,75 @@ mpz_out_raw (FILE *fp, mpz_srcptr x)
if (bytes != 0)
{
- /* reverse limb order, and byte swap if necessary */
bp += bytes;
xp = PTR (x);
i = abs_xsize;
+
+ if (GMP_NAIL_BITS == 0)
+ {
+ /* reverse limb order, and byte swap if necessary */
#ifdef _CRAY
- _Pragma ("_CRI ivdep");
+ _Pragma ("_CRI ivdep");
#endif
- do
+ do
+ {
+ bp -= BYTES_PER_MP_LIMB;
+ xlimb = *xp;
+ HTON_LIMB_STORE ((mp_ptr) bp, xlimb);
+ xp++;
+ }
+ while (--i > 0);
+
+ /* strip high zero bytes (without fetching from bp) */
+ count_leading_zeros (zeros, xlimb);
+ zeros /= 8;
+ bp += zeros;
+ bytes -= zeros;
+ }
+ else
{
- bp -= BYTES_PER_MP_LIMB;
- xlimb = *xp;
- HTON_LIMB_STORE ((mp_ptr) bp, xlimb);
- xp++;
+ mp_limb_t new_xlimb;
+ int bits;
+ ASSERT_CODE (char *bp_orig = bp - bytes);
+
+ ASSERT_ALWAYS (GMP_NUMB_BITS >= 8);
+
+ bits = 0;
+ xlimb = 0;
+ for (;;)
+ {
+ while (bits >= 8)
+ {
+ ASSERT (bp > bp_orig);
+ *--bp = xlimb & 0xFF;
+ xlimb >>= 8;
+ bits -= 8;
+ }
+
+ if (i == 0)
+ break;
+
+ new_xlimb = *xp++;
+ i--;
+ ASSERT (bp > bp_orig);
+ *--bp = (xlimb | (new_xlimb << bits)) & 0xFF;
+ xlimb = new_xlimb >> (8 - bits);
+ bits += GMP_NUMB_BITS - 8;
+ }
+
+ if (bits != 0)
+ {
+ ASSERT (bp > bp_orig);
+ *--bp = xlimb;
+ }
+
+ ASSERT (bp == bp_orig);
+ while (*bp == 0)
+ {
+ bp++;
+ bytes--;
+ }
}
- while (--i > 0);
-
- /* strip high zero bytes (without fetching from bp) */
- count_leading_zeros (zeros, xlimb);
- zeros /= 8;
- bp += zeros;
- bytes -= zeros;
}
/* total bytes to be written */