(setf (%bignum-ref res i) (%logxor sign (%bignum-ref b i))))
(%normalize-bignum res len-b))
\f
-;;;; LDB (load byte)
-
-#|
-FOR NOW WE DON'T USE LDB OR DPB. WE USE SHIFTS AND MASKS IN NUMBERS.LISP WHICH
-IS LESS EFFICIENT BUT EASIER TO MAINTAIN. BILL SAYS THIS CODE CERTAINLY WORKS!
-
-(defconstant maximum-fixnum-bits (- sb!vm:n-word-bits sb!vm:n-lowtag-bits))
-
-(defun bignum-load-byte (byte bignum)
- (declare (type bignum-type bignum))
- (let ((byte-len (byte-size byte))
- (byte-pos (byte-position byte)))
- (if (< byte-len maximum-fixnum-bits)
- (bignum-ldb-fixnum-res bignum byte-len byte-pos)
- (bignum-ldb-bignum-res bignum byte-len byte-pos))))
-
-;;; This returns a fixnum result of loading a byte from a bignum. In order, we
-;;; check for the following conditions:
-;;; Insufficient bignum digits to start loading a byte --
-;;; Return 0 or byte-len 1's depending on sign of bignum.
-;;; One bignum digit containing the whole byte spec --
-;;; Grab 'em, shift 'em, and mask out what we don't want.
-;;; Insufficient bignum digits to cover crossing a digit boundary --
-;;; Grab the available bits in the last digit, and or in whatever
-;;; virtual sign bits we need to return a full byte spec.
-;;; Else (we cross a digit boundary with all bits available) --
-;;; Make a couple masks, grab what we want, shift it around, and
-;;; LOGIOR it all together.
-;;; Because (< maximum-fixnum-bits digit-size) and
-;;; (< byte-len maximum-fixnum-bits),
-;;; we only cross one digit boundary if any.
-(defun bignum-ldb-fixnum-res (bignum byte-len byte-pos)
- (multiple-value-bind (skipped-digits pos) (truncate byte-pos digit-size)
- (let ((bignum-len (%bignum-length bignum))
- (s-digits+1 (1+ skipped-digits)))
- (declare (type bignum-index bignum-len s-digits+1))
- (if (>= skipped-digits bignum-len)
- (if (%bignum-0-or-plusp bignum bignum-len)
- 0
- (%make-ones byte-len))
- (let ((end (+ pos byte-len)))
- (cond ((<= end digit-size)
- (logand (ash (%bignum-ref bignum skipped-digits) (- pos))
- ;; Must LOGAND after shift here.
- (%make-ones byte-len)))
- ((>= s-digits+1 bignum-len)
- (let* ((available-bits (- digit-size pos))
- (res (logand (ash (%bignum-ref bignum skipped-digits)
- (- pos))
- ;; LOGAND should be unnecessary here
- ;; with a logical right shift or a
- ;; correct digit-sized one.
- (%make-ones available-bits))))
- (if (%bignum-0-or-plusp bignum bignum-len)
- res
- (logior (%ashl (%make-ones (- end digit-size))
- available-bits)
- res))))
- (t
- (let* ((high-bits-in-first-digit (- digit-size pos))
- (high-mask (%make-ones high-bits-in-first-digit))
- (low-bits-in-next-digit (- end digit-size))
- (low-mask (%make-ones low-bits-in-next-digit)))
- (declare (type bignum-element-type high-mask low-mask))
- (logior (%ashl (logand (%bignum-ref bignum s-digits+1)
- low-mask)
- high-bits-in-first-digit)
- (logand (ash (%bignum-ref bignum skipped-digits)
- (- pos))
- ;; LOGAND should be unnecessary here with
- ;; a logical right shift or a correct
- ;; digit-sized one.
- high-mask))))))))))
-
-;;; This returns a bignum result of loading a byte from a bignum. In order, we
-;;; check for the following conditions:
-;;; Insufficient bignum digits to start loading a byte --
-;;; Byte-pos starting on a digit boundary --
-;;; Byte spec contained in one bignum digit --
-;;; Grab the bits we want and stick them in a single digit result.
-;;; Since we know byte-pos is non-zero here, we know our single digit
-;;; will have a zero high sign bit.
-;;; Else (unaligned multiple digits) --
-;;; This is like doing a shift right combined with either masking
-;;; out unwanted high bits from bignum or filling in virtual sign
-;;; bits if bignum had insufficient bits. We use SHIFT-RIGHT-ALIGNED
-;;; and reference lots of local variables this macro establishes.
-(defun bignum-ldb-bignum-res (bignum byte-len byte-pos)
- (multiple-value-bind (skipped-digits pos) (truncate byte-pos digit-size)
- (let ((bignum-len (%bignum-length bignum)))
- (declare (type bignum-index bignum-len))
- (cond
- ((>= skipped-digits bignum-len)
- (make-bignum-virtual-ldb-bits bignum bignum-len byte-len))
- ((zerop pos)
- (make-aligned-ldb-bignum bignum bignum-len byte-len skipped-digits))
- ((< (+ pos byte-len) digit-size)
- (let ((res (%allocate-bignum 1)))
- (setf (%bignum-ref res 0)
- (logand (%ashr (%bignum-ref bignum skipped-digits) pos)
- (%make-ones byte-len)))
- res))
- (t
- (make-unaligned-ldb-bignum bignum bignum-len
- byte-len skipped-digits pos))))))
-
-;;; This returns bits from bignum that don't physically exist. These are
-;;; all zero or one depending on the sign of the bignum.
-(defun make-bignum-virtual-ldb-bits (bignum bignum-len byte-len)
- (if (%bignum-0-or-plusp bignum bignum-len)
- 0
- (multiple-value-bind (res-len-1 extra) (truncate byte-len digit-size)
- (declare (type bignum-index res-len-1))
- (let* ((res-len (1+ res-len-1))
- (res (%allocate-bignum res-len)))
- (declare (type bignum-index res-len))
- (do ((j 0 (1+ j)))
- ((= j res-len-1)
- (setf (%bignum-ref res j) (%make-ones extra))
- (%normalize-bignum res res-len))
- (declare (type bignum-index j))
- (setf (%bignum-ref res j) all-ones-digit))))))
-
-;;; Since we are picking up aligned digits, we just copy the whole digits
-;;; we want and fill in extra bits. We might have a byte-len that extends
-;;; off the end of the bignum, so we may have to fill in extra 1's if the
-;;; bignum is negative.
-(defun make-aligned-ldb-bignum (bignum bignum-len byte-len skipped-digits)
- (multiple-value-bind (res-len-1 extra) (truncate byte-len digit-size)
- (declare (type bignum-index res-len-1))
- (let* ((res-len (1+ res-len-1))
- (res (%allocate-bignum res-len)))
- (declare (type bignum-index res-len))
- (do ((i skipped-digits (1+ i))
- (j 0 (1+ j)))
- ((or (= j res-len-1) (= i bignum-len))
- (cond ((< i bignum-len)
- (setf (%bignum-ref res j)
- (logand (%bignum-ref bignum i)
- (the bignum-element-type (%make-ones extra)))))
- ((%bignum-0-or-plusp bignum bignum-len))
- (t
- (do ((j j (1+ j)))
- ((= j res-len-1)
- (setf (%bignum-ref res j) (%make-ones extra)))
- (setf (%bignum-ref res j) all-ones-digit))))
- (%normalize-bignum res res-len))
- (declare (type bignum-index i j))
- (setf (%bignum-ref res j) (%bignum-ref bignum i))))))
-
-;;; This grabs unaligned bignum bits from bignum assuming byte-len causes at
-;;; least one digit boundary crossing. We use SHIFT-RIGHT-UNALIGNED referencing
-;;; lots of local variables established by it.
-(defun make-unaligned-ldb-bignum (bignum
- bignum-len
- byte-len
- skipped-digits
- pos)
- (multiple-value-bind (res-len-1 extra) (truncate byte-len digit-size)
- (shift-right-unaligned
- bignum skipped-digits pos (1+ res-len-1)
- ((or (= j res-len-1) (= i+1 bignum-len))
- (cond ((= j res-len-1)
- (cond
- ((< extra high-bits-in-first-digit)
- (setf (%bignum-ref res j)
- (logand (ash (%bignum-ref bignum i) minus-start-pos)
- ;; Must LOGAND after shift here.
- (%make-ones extra))))
- (t
- (setf (%bignum-ref res j)
- (logand (ash (%bignum-ref bignum i) minus-start-pos)
- ;; LOGAND should be unnecessary here with a logical
- ;; right shift or a correct digit-sized one.
- high-mask))
- (when (%bignum-0-or-plusp bignum bignum-len)
- (setf (%bignum-ref res j)
- (logior (%bignum-ref res j)
- (%ashl (%make-ones
- (- extra high-bits-in-first-digit))
- high-bits-in-first-digit)))))))
- (t
- (setf (%bignum-ref res j)
- (logand (ash (%bignum-ref bignum i) minus-start-pos)
- ;; LOGAND should be unnecessary here with a logical
- ;; right shift or a correct digit-sized one.
- high-mask))
- (unless (%bignum-0-or-plusp bignum bignum-len)
- ;; Fill in upper half of this result digit with 1's.
- (setf (%bignum-ref res j)
- (logior (%bignum-ref res j)
- (%ashl low-mask high-bits-in-first-digit)))
- ;; Fill in any extra 1's we need to be byte-len long.
- (do ((j (1+ j) (1+ j)))
- ((>= j res-len-1)
- (setf (%bignum-ref res j) (%make-ones extra)))
- (setf (%bignum-ref res j) all-ones-digit)))))
- (%normalize-bignum res res-len))
- res)))
-\f
-;;;; DPB (deposit byte)
-
-(defun bignum-deposit-byte (new-byte byte-spec bignum)
- (declare (type bignum-type bignum))
- (let* ((byte-len (byte-size byte-spec))
- (byte-pos (byte-position byte-spec))
- (bignum-len (%bignum-length bignum))
- (bignum-plusp (%bignum-0-or-plusp bignum bignum-len))
- (byte-end (+ byte-pos byte-len))
- (res-len (1+ (max (ceiling byte-end digit-size) bignum-len)))
- (res (%allocate-bignum res-len)))
- (declare (type bignum-index bignum-len res-len))
- ;; Fill in an extra sign digit in case we set what would otherwise be the
- ;; last digit's last bit. Normalize at the end in case this was
- ;; unnecessary.
- (unless bignum-plusp
- (setf (%bignum-ref res (1- res-len)) all-ones-digit))
- (multiple-value-bind (end-digit end-bits) (truncate byte-end digit-size)
- (declare (type bignum-index end-digit))
- ;; Fill in bits from bignum up to byte-pos.
- (multiple-value-bind (pos-digit pos-bits) (truncate byte-pos digit-size)
- (declare (type bignum-index pos-digit))
- (do ((i 0 (1+ i))
- (end (min pos-digit bignum-len)))
- ((= i end)
- (cond ((< i bignum-len)
- (unless (zerop pos-bits)
- (setf (%bignum-ref res i)
- (logand (%bignum-ref bignum i)
- (%make-ones pos-bits)))))
- (bignum-plusp)
- (t
- (do ((i i (1+ i)))
- ((= i pos-digit)
- (unless (zerop pos-bits)
- (setf (%bignum-ref res i) (%make-ones pos-bits))))
- (setf (%bignum-ref res i) all-ones-digit)))))
- (setf (%bignum-ref res i) (%bignum-ref bignum i)))
- ;; Fill in bits from new-byte.
- (if (typep new-byte 'fixnum)
- (deposit-fixnum-bits new-byte byte-len pos-digit pos-bits
- end-digit end-bits res)
- (deposit-bignum-bits new-byte byte-len pos-digit pos-bits
- end-digit end-bits res)))
- ;; Fill in remaining bits from bignum after byte-spec.
- (when (< end-digit bignum-len)
- (setf (%bignum-ref res end-digit)
- (logior (logand (%bignum-ref bignum end-digit)
- (%ashl (%make-ones (- digit-size end-bits))
- end-bits))
- ;; DEPOSIT-FIXNUM-BITS and DEPOSIT-BIGNUM-BITS only store
- ;; bits from new-byte into res's end-digit element, so
- ;; we don't need to mask out unwanted high bits.
- (%bignum-ref res end-digit)))
- (do ((i (1+ end-digit) (1+ i)))
- ((= i bignum-len))
- (setf (%bignum-ref res i) (%bignum-ref bignum i)))))
- (%normalize-bignum res res-len)))
-
-;;; This starts at result's pos-digit skipping pos-bits, and it stores bits
-;;; from new-byte, a fixnum, into result. It effectively stores byte-len
-;;; number of bits, but never stores past end-digit and end-bits in result.
-;;; The first branch fires when all the bits we want from new-byte are present;
-;;; if byte-len crosses from the current result digit into the next, the last
-;;; argument to DEPOSIT-FIXNUM-DIGIT is a mask for those bits. The second
-;;; branch handles the need to grab more bits than the fixnum new-byte has, but
-;;; new-byte is positive; therefore, any virtual bits are zero. The mask for
-;;; bits that don't fit in the current result digit is simply the remaining
-;;; bits in the bignum digit containing new-byte; we don't care if we store
-;;; some extra in the next result digit since they will be zeros. The last
-;;; branch handles the need to grab more bits than the fixnum new-byte has, but
-;;; new-byte is negative; therefore, any virtual bits must be explicitly filled
-;;; in as ones. We call DEPOSIT-FIXNUM-DIGIT to grab what bits actually exist
-;;; and to fill in the current result digit.
-(defun deposit-fixnum-bits (new-byte byte-len pos-digit pos-bits
- end-digit end-bits result)
- (declare (type bignum-index pos-digit end-digit))
- (let ((other-bits (- digit-size pos-bits))
- (new-byte-digit (%fixnum-to-digit new-byte)))
- (declare (type bignum-element-type new-byte-digit))
- (cond ((< byte-len maximum-fixnum-bits)
- (deposit-fixnum-digit new-byte-digit byte-len pos-digit pos-bits
- other-bits result
- (- byte-len other-bits)))
- ((or (plusp new-byte) (zerop new-byte))
- (deposit-fixnum-digit new-byte-digit byte-len pos-digit pos-bits
- other-bits result pos-bits))
- (t
- (multiple-value-bind (digit bits)
- (deposit-fixnum-digit new-byte-digit byte-len pos-digit pos-bits
- other-bits result
- (if (< (- byte-len other-bits) digit-size)
- (- byte-len other-bits)
- digit-size))
- (declare (type bignum-index digit))
- (cond ((< digit end-digit)
- (setf (%bignum-ref result digit)
- (logior (%bignum-ref result digit)
- (%ashl (%make-ones (- digit-size bits)) bits)))
- (do ((i (1+ digit) (1+ i)))
- ((= i end-digit)
- (setf (%bignum-ref result i) (%make-ones end-bits)))
- (setf (%bignum-ref result i) all-ones-digit)))
- ((> digit end-digit))
- ((< bits end-bits)
- (setf (%bignum-ref result digit)
- (logior (%bignum-ref result digit)
- (%ashl (%make-ones (- end-bits bits))
- bits))))))))))
-
-;;; This fills in the current result digit from new-byte-digit. The first case
-;;; handles everything we want fitting in the current digit, and other-bits is
-;;; the number of bits remaining to be filled in result's current digit. This
-;;; number is digit-size minus pos-bits. The second branch handles filling in
-;;; result's current digit, and it shoves the unused bits of new-byte-digit
-;;; into the next result digit. This is correct regardless of new-byte-digit's
-;;; sign. It returns the new current result digit and how many bits already
-;;; filled in the result digit.
-(defun deposit-fixnum-digit (new-byte-digit byte-len pos-digit pos-bits
- other-bits result next-digit-bits-needed)
- (declare (type bignum-index pos-digit)
- (type bignum-element-type new-byte-digit next-digit-mask))
- (cond ((<= byte-len other-bits)
- ;; Bits from new-byte fit in the current result digit.
- (setf (%bignum-ref result pos-digit)
- (logior (%bignum-ref result pos-digit)
- (%ashl (logand new-byte-digit (%make-ones byte-len))
- pos-bits)))
- (if (= byte-len other-bits)
- (values (1+ pos-digit) 0)
- (values pos-digit (+ byte-len pos-bits))))
- (t
- ;; Some of new-byte's bits go in current result digit.
- (setf (%bignum-ref result pos-digit)
- (logior (%bignum-ref result pos-digit)
- (%ashl (logand new-byte-digit (%make-ones other-bits))
- pos-bits)))
- (let ((pos-digit+1 (1+ pos-digit)))
- ;; The rest of new-byte's bits go in the next result digit.
- (setf (%bignum-ref result pos-digit+1)
- (logand (ash new-byte-digit (- other-bits))
- ;; Must LOGAND after shift here.
- (%make-ones next-digit-bits-needed)))
- (if (= next-digit-bits-needed digit-size)
- (values (1+ pos-digit+1) 0)
- (values pos-digit+1 next-digit-bits-needed))))))
-
-;;; This starts at result's pos-digit skipping pos-bits, and it stores bits
-;;; from new-byte, a bignum, into result. It effectively stores byte-len
-;;; number of bits, but never stores past end-digit and end-bits in result.
-;;; When handling a starting bit unaligned with a digit boundary, we check
-;;; in the second branch for the byte spec fitting into the pos-digit element
-;;; after after pos-bits; DEPOSIT-UNALIGNED-BIGNUM-BITS expects at least one
-;;; digit boundary crossing.
-(defun deposit-bignum-bits (bignum-byte byte-len pos-digit pos-bits
- end-digit end-bits result)
- (declare (type bignum-index pos-digit end-digit))
- (cond ((zerop pos-bits)
- (deposit-aligned-bignum-bits bignum-byte pos-digit end-digit end-bits
- result))
- ((or (= end-digit pos-digit)
- (and (= end-digit (1+ pos-digit))
- (zerop end-bits)))
- (setf (%bignum-ref result pos-digit)
- (logior (%bignum-ref result pos-digit)
- (%ashl (logand (%bignum-ref bignum-byte 0)
- (%make-ones byte-len))
- pos-bits))))
- (t (deposit-unaligned-bignum-bits bignum-byte pos-digit pos-bits
- end-digit end-bits result))))
-
-;;; This deposits bits from bignum-byte into result starting at pos-digit and
-;;; the zero'th bit. It effectively only stores bits to end-bits in the
-;;; end-digit element of result. The loop termination code takes care of
-;;; picking up the last digit's bits or filling in virtual negative sign bits.
-(defun deposit-aligned-bignum-bits (bignum-byte pos-digit end-digit end-bits
- result)
- (declare (type bignum-index pos-digit end-digit))
- (let* ((bignum-len (%bignum-length bignum-byte))
- (bignum-plusp (%bignum-0-or-plusp bignum-byte bignum-len)))
- (declare (type bignum-index bignum-len))
- (do ((i 0 (1+ i ))
- (j pos-digit (1+ j)))
- ((or (= j end-digit) (= i bignum-len))
- (cond ((= j end-digit)
- (cond ((< i bignum-len)
- (setf (%bignum-ref result j)
- (logand (%bignum-ref bignum-byte i)
- (%make-ones end-bits))))
- (bignum-plusp)
- (t
- (setf (%bignum-ref result j) (%make-ones end-bits)))))
- (bignum-plusp)
- (t
- (do ((j j (1+ j)))
- ((= j end-digit)
- (setf (%bignum-ref result j) (%make-ones end-bits)))
- (setf (%bignum-ref result j) all-ones-digit)))))
- (setf (%bignum-ref result j) (%bignum-ref bignum-byte i)))))
-
-;;; This assumes at least one digit crossing.
-(defun deposit-unaligned-bignum-bits (bignum-byte pos-digit pos-bits
- end-digit end-bits result)
- (declare (type bignum-index pos-digit end-digit))
- (let* ((bignum-len (%bignum-length bignum-byte))
- (bignum-plusp (%bignum-0-or-plusp bignum-byte bignum-len))
- (low-mask (%make-ones pos-bits))
- (bits-past-pos-bits (- digit-size pos-bits))
- (high-mask (%make-ones bits-past-pos-bits))
- (minus-high-bits (- bits-past-pos-bits)))
- (declare (type bignum-element-type low-mask high-mask)
- (type bignum-index bignum-len))
- (do ((i 0 (1+ i))
- (j pos-digit j+1)
- (j+1 (1+ pos-digit) (1+ j+1)))
- ((or (= j end-digit) (= i bignum-len))
- (cond
- ((= j end-digit)
- (setf (%bignum-ref result j)
- (cond
- ((>= pos-bits end-bits)
- (logand (%bignum-ref result j) (%make-ones end-bits)))
- ((< i bignum-len)
- (logior (%bignum-ref result j)
- (%ashl (logand (%bignum-ref bignum-byte i)
- (%make-ones (- end-bits pos-bits)))
- pos-bits)))
- (bignum-plusp
- (logand (%bignum-ref result j)
- ;; 0's between pos-bits and end-bits positions.
- (logior (%ashl (%make-ones (- digit-size end-bits))
- end-bits)
- low-mask)))
- (t (logior (%bignum-ref result j)
- (%ashl (%make-ones (- end-bits pos-bits))
- pos-bits))))))
- (bignum-plusp)
- (t
- (setf (%bignum-ref result j)
- (%ashl (%make-ones bits-past-pos-bits) pos-bits))
- (do ((j j+1 (1+ j)))
- ((= j end-digit)
- (setf (%bignum-ref result j) (%make-ones end-bits)))
- (declare (type bignum-index j))
- (setf (%bignum-ref result j) all-ones-digit)))))
- (declare (type bignum-index i j j+1))
- (let ((digit (%bignum-ref bignum-byte i)))
- (declare (type bignum-element-type digit))
- (setf (%bignum-ref result j)
- (logior (%bignum-ref result j)
- (%ashl (logand digit high-mask) pos-bits)))
- (setf (%bignum-ref result j+1)
- (logand (ash digit minus-high-bits)
- ;; LOGAND should be unnecessary here with a logical right
- ;; shift or a correct digit-sized one.
- low-mask))))))
-|#
+;;;; There used to be a bunch of code to implement "efficient" versions of LDB
+;;;; and DPB here. But it apparently was never used, so it's been deleted.
+;;;; --njf, 2007-02-04
\f
;;;; TRUNCATE
(%normalize-bignum rem (%bignum-length rem))))))))))
\f
-;;;; %FLOOR primitive for BIGNUM-TRUNCATE
-
-;;; When a machine leaves out a 2*digit-size by digit-size divide
-;;; instruction (that is, two bignum-digits divided by one), we have to
-;;; roll our own (the hard way). Basically, we treat the operation as
-;;; four digit-size/2 digits divided by two digit-size/2 digits. This
-;;; means we have duplicated most of the code above to do this nearly
-;;; general digit-size/2 digit bignum divide, but we've unrolled loops
-;;; and made use of other properties of this specific divide situation.
-
-;;;; %FLOOR for machines with a 32x32 divider.
-
-#!+(and 32x16-divide (not sb-fluid))
-(declaim (inline 32x16-subtract-with-borrow 32x16-add-with-carry
- 32x16-divide 32x16-multiply 32x16-multiply-split))
-
-#!+32x16-divide
-(defconstant 32x16-base-1 (1- (ash 1 (/ sb!vm:n-word-bits 2))))
-
-#!+32x16-divide
-(deftype bignum-half-element-type () `(unsigned-byte ,(/ sb!vm:n-word-bits 2)))
-#!+32x16-divide
-(defconstant half-digit-size (/ digit-size 2))
-
-;;; This is similar to %SUBTRACT-WITH-BORROW. It returns a
-;;; half-digit-size difference and a borrow. Returning a 1 for the
-;;; borrow means there was no borrow, and 0 means there was one.
-#!+32x16-divide
-(defun 32x16-subtract-with-borrow (a b borrow)
- (declare (type bignum-half-element-type a b)
- (type (integer 0 1) borrow))
- (let ((diff (+ (- a b) borrow 32x16-base-1)))
- (declare (type (unsigned-byte #.(1+ half-digit-size)) diff))
- (values (logand diff (1- (ash 1 half-digit-size)))
- (ash diff (- half-digit-size)))))
-
-;;; This adds a and b, half-digit-size quantities, with the carry k. It
-;;; returns a half-digit-size sum and a second value, 0 or 1, indicating
-;;; whether there was a carry.
-#!+32x16-divide
-(defun 32x16-add-with-carry (a b k)
- (declare (type bignum-half-element-type a b)
- (type (integer 0 1) k))
- (let ((res (the fixnum (+ a b k))))
- (declare (type (unsigned-byte #.(1+ half-digit-size)) res))
- (if (zerop (the fixnum (logand (ash 1 half-digit-size) res)))
- (values res 0)
- (values (the bignum-half-element-type (logand (1- (ash 1 half-digit-size)) res))
- 1))))
-
-;;; This is probably a digit-size by digit-size divide instruction.
-#!+32x16-divide
-(defun 32x16-divide (a b c)
- (declare (type bignum-half-element-type a b c))
- (floor (the bignum-element-type
- (logior (the bignum-element-type (ash a 16))
- b))
- c))
-
-;;; This basically exists since we know the answer won't overflow
-;;; bignum-element-type. It's probably just a basic multiply instruction, but
-;;; it can't cons an intermediate bignum. The result goes in a non-descriptor
-;;; register.
-#!+32x16-divide
-(defun 32x16-multiply (a b)
- (declare (type bignum-half-element-type a b))
- (the bignum-element-type (* a b)))
-
-;;; This multiplies a and b, half-digit-size quantities, and returns the
-;;; result as two half-digit-size quantities, high and low.
-#!+32x16-divide
-(defun 32x16-multiply-split (a b)
- (let ((res (32x16-multiply a b)))
- (declare (the bignum-element-type res))
- (values (the bignum-half-element-type (logand (1- (ash 1 half-digit-size)) (ash res (- half-digit-size))))
- (the bignum-half-element-type (logand (1- (ash 1 half-digit-size)) res)))))
-
-;;; The %FLOOR below uses this buffer the same way BIGNUM-TRUNCATE uses
-;;; *truncate-x*. There's no y buffer since we pass around the two
-;;; half-digit-size digits and use them slightly differently than the
-;;; general truncation algorithm above.
-#!+32x16-divide
-(defvar *32x16-truncate-x* (make-array 4 :element-type 'bignum-half-element-type
- :initial-element 0))
-
-;;; This does the same thing as the %FLOOR above, but it does it at Lisp level
-;;; when there is no 64x32-bit divide instruction on the machine.
-;;;
-;;; It implements the higher level tactics of BIGNUM-TRUNCATE, but it
-;;; makes use of special situation provided, four half-digit-size digits
-;;; divided by two half-digit-size digits.
-#!+32x16-divide
-(defun %floor (a b c)
- (declare (type bignum-element-type a b c))
- ;; Setup *32x16-truncate-x* buffer from a and b.
- (setf (aref *32x16-truncate-x* 0)
- (the bignum-half-element-type (logand (1- (ash 1 half-digit-size)) b)))
- (setf (aref *32x16-truncate-x* 1)
- (the bignum-half-element-type
- (logand (1- (ash 1 half-digit-size))
- (the bignum-half-element-type (ash b (- half-digit-size))))))
- (setf (aref *32x16-truncate-x* 2)
- (the bignum-half-element-type (logand (1- (ash 1 half-digit-size)) a)))
- (setf (aref *32x16-truncate-x* 3)
- (the bignum-half-element-type
- (logand (1- (ash 1 half-digit-size))
- (the bignum-half-element-type (ash a (- half-digit-size))))))
- ;; From DO-TRUNCATE, but unroll the loop.
- (let* ((y1 (logand (1- (ash 1 half-digit-size)) (ash c (- half-digit-size))))
- (y2 (logand (1- (ash 1 half-digit-size)) c))
- (q (the bignum-element-type
- (ash (32x16-try-bignum-truncate-guess
- (32x16-truncate-guess y1 y2
- (aref *32x16-truncate-x* 3)
- (aref *32x16-truncate-x* 2)
- (aref *32x16-truncate-x* 1))
- y1 y2 1)
- 16))))
- (declare (type bignum-element-type q)
- (type bignum-half-element-type y1 y2))
- (values (the bignum-element-type
- (logior q
- (the bignum-half-element-type
- (32x16-try-bignum-truncate-guess
- (32x16-truncate-guess
- y1 y2
- (aref *32x16-truncate-x* 2)
- (aref *32x16-truncate-x* 1)
- (aref *32x16-truncate-x* 0))
- y1 y2 0))))
- (the bignum-element-type
- (logior (the bignum-element-type
- (ash (aref *32x16-truncate-x* 1) 16))
- (the bignum-half-element-type
- (aref *32x16-truncate-x* 0)))))))
-
-;;; This is similar to TRY-BIGNUM-TRUNCATE-GUESS, but this unrolls the two
-;;; loops. This also substitutes for %DIGIT-0-OR-PLUSP the equivalent
-;;; expression without any embellishment or pretense of abstraction. The first
-;;; loop is unrolled, but we've put the body of the loop into the function
-;;; 32X16-TRY-GUESS-ONE-RESULT-DIGIT.
-#!+32x16-divide
-(defun 32x16-try-bignum-truncate-guess (guess y-high y-low low-x-digit)
- (declare (type bignum-index low-x-digit)
- (type bignum-half-element-type guess y-high y-low))
- (let ((high-x-digit (+ 2 low-x-digit)))
- ;; Multiply guess and divisor, subtracting from dividend simultaneously.
- (multiple-value-bind (guess*y-hold carry borrow)
- (32x16-try-guess-one-result-digit guess y-low 0 0 1 low-x-digit)
- (declare (type bignum-half-element-type guess*y-hold)
- (fixnum carry borrow))
- (multiple-value-bind (guess*y-hold carry borrow)
- (32x16-try-guess-one-result-digit guess y-high guess*y-hold
- carry borrow (1+ low-x-digit))
- (declare (type bignum-half-element-type guess*y-hold)
- (fixnum borrow)
- (ignore carry))
- (setf (aref *32x16-truncate-x* high-x-digit)
- (32x16-subtract-with-borrow (aref *32x16-truncate-x* high-x-digit)
- guess*y-hold borrow))))
- ;; See whether guess is off by one, adding one Y back in if necessary.
- (cond ((zerop (logand (ash 1 (1- half-digit-size))
- (aref *32x16-truncate-x* high-x-digit)))
- ;; The subtraction result is zero or positive.
- guess)
- (t
- ;; If subtraction has negative result, add one divisor value back
- ;; in. The guess was one too large in magnitude.
- (multiple-value-bind (v carry)
- (32x16-add-with-carry y-low
- (aref *32x16-truncate-x* low-x-digit)
- 0)
- (declare (type bignum-half-element-type v))
- (setf (aref *32x16-truncate-x* low-x-digit) v)
- (multiple-value-bind (v carry)
- (32x16-add-with-carry y-high
- (aref *32x16-truncate-x*
- (1+ low-x-digit))
- carry)
- (setf (aref *32x16-truncate-x* (1+ low-x-digit)) v)
- (setf (aref *32x16-truncate-x* high-x-digit)
- (32x16-add-with-carry (aref *32x16-truncate-x* high-x-digit)
- carry 0))))
- (if (zerop (logand (ash 1 (1- half-digit-size)) guess))
- (1- guess)
- (1+ guess))))))
-
-;;; This is similar to the body of the loop in TRY-BIGNUM-TRUNCATE-GUESS that
-;;; multiplies the guess by y and subtracts the result from x simultaneously.
-;;; This returns the digit remembered as part of the multiplication, the carry
-;;; from additions done on behalf of the multiplication, and the borrow from
-;;; doing the subtraction.
-#!+32x16-divide
-(defun 32x16-try-guess-one-result-digit (guess y-digit guess*y-hold
- carry borrow x-index)
- (multiple-value-bind (high-digit low-digit)
- (32x16-multiply-split guess y-digit)
- (declare (type bignum-half-element-type high-digit low-digit))
- (multiple-value-bind (low-digit temp-carry)
- (32x16-add-with-carry low-digit guess*y-hold carry)
- (declare (type bignum-half-element-type low-digit))
- (multiple-value-bind (high-digit temp-carry)
- (32x16-add-with-carry high-digit temp-carry 0)
- (declare (type bignum-half-element-type high-digit))
- (multiple-value-bind (x temp-borrow)
- (32x16-subtract-with-borrow (aref *32x16-truncate-x* x-index)
- low-digit borrow)
- (declare (type bignum-half-element-type x))
- (setf (aref *32x16-truncate-x* x-index) x)
- (values high-digit temp-carry temp-borrow))))))
-
-;;; This is similar to BIGNUM-TRUNCATE-GUESS, but instead of computing
-;;; the guess exactly as described in the its comments (digit by digit),
-;;; this massages the digit-size/2 quantities into digit-size quantities
-;;; and performs the
-#!+32x16-divide
-(defun 32x16-truncate-guess (y1 y2 x-i x-i-1 x-i-2)
- (declare (type bignum-half-element-type y1 y2 x-i x-i-1 x-i-2))
- (let ((guess (if (= x-i y1)
- (1- (ash 1 half-digit-size))
- (32x16-divide x-i x-i-1 y1))))
- (declare (type bignum-half-element-type guess))
- (loop
- (let* ((guess*y1 (the bignum-element-type
- (ash (logand (1- (ash 1 half-digit-size))
- (the bignum-element-type
- (32x16-multiply guess y1)))
- 16)))
- (x-y (%subtract-with-borrow
- (the bignum-element-type
- (logior (the bignum-element-type
- (ash x-i-1 16))
- x-i-2))
- guess*y1
- 1))
- (guess*y2 (the bignum-element-type (%multiply guess y2))))
- (declare (type bignum-element-type guess*y1 x-y guess*y2))
- (if (%digit-greater guess*y2 x-y)
- (decf guess)
- (return guess))))))
+;;;; There used to be a pile of code for implementing division for bignum digits
+;;;; for machines that don't have a 2*digit-size by digit-size divide instruction.
+;;;; This happens to be most machines, but all the SBCL ports seem to be content
+;;;; to implement SB-BIGNUM:%FLOOR as a VOP rather than using the code here.
+;;;; So it's been deleted. --njf, 2007-02-04
\f
;;;; general utilities