diff options
-rw-r--r-- | mpz/inp_raw.c | 69 | ||||
-rw-r--r-- | mpz/out_raw.c | 78 |
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 */ |