Store unibyte mapping tables more densely by specializing the vectors.

Incidentally, get the cross-compiler to dump SIGNED-BYTE arrays.
This commit is contained in:
Douglas Katzman 2014-07-15 14:47:10 -04:00
parent 6ec4b3459f
commit d12f5387f9
2 changed files with 50 additions and 20 deletions

View file

@ -186,32 +186,57 @@ one-past-the-end"
;; Create the lookup table.
(sorted-lookup-table
(reduce #'append sorted-pairs :from-end t :initial-value nil)))
`(progn
; Can't inline it with a non-null lexical environment anyway.
(flet ((pick-type (vector &optional missing-points-p)
(if missing-points-p
(let ((max (reduce #'max (remove nil vector))))
(cond ((<= max #x7F) '(signed-byte 8))
((<= max #x7FFF) '(signed-byte 16))
(t '(signed-byte 32))))
(let ((max (reduce #'max vector)))
(cond ((<= max #xFF) '(unsigned-byte 8))
((<= max #xFFFF) '(unsigned-byte 16))
(t '(unsigned-byte 32)))))))
`(progn
;; We *could* inline this, but it's not obviously the right thing,
;; because each use of the inlined function in a different file
;; would be forced to dump the large-ish array. To do things like
;; this, you generally want a load-time ref to a global constant.
;(declaim (inline ,byte-char-name))
(let ((byte-to-code-table
,(make-array 256 :element-type t #+nil 'char-code
:initial-contents (loop for byte below 256
collect
(let ((exception (cdr (assoc byte exceptions))))
(if exception
(car exception)
byte)))))
(code-to-byte-table
,(make-array (length sorted-lookup-table)
:initial-contents sorted-lookup-table)))
(defun ,byte-char-name (byte)
(declare (optimize speed (safety 0))
(type (unsigned-byte 8) byte))
(aref byte-to-code-table byte))
,(let ((byte-to-code
(loop for byte below 256
collect (let ((exception (cdr (assoc byte exceptions))))
(if exception
(car exception)
byte)))))
(if (position nil byte-to-code)
;; There are bytes with no translation. Represent "missing"
;; as -1 when stored, convert to NIL when accessed.
;; We could use a single otherwise-unused point to mean NIL,
;; but it would be confusing if in one table #xFFFF represents
;; NIL and another #xF00D represents NIL.
`(let ((code (aref ,(!make-specialized-array
256 (pick-type byte-to-code t)
(substitute -1 nil byte-to-code))
byte)))
(if (>= code 0) code))
;; Every byte has a translation
`(aref ,(!make-specialized-array
256 (pick-type byte-to-code) byte-to-code)
byte))))
(defun ,code-byte-name (code)
(declare (optimize speed (safety 0))
(type char-code code))
(if (< code ,lowest-non-equivalent-code)
code
;; We could toss in some TRULY-THEs if we really needed to
;; make this faster...
(loop with low = 0
(loop with code-to-byte-table =
,(!make-specialized-array
(length sorted-lookup-table)
(pick-type sorted-lookup-table)
sorted-lookup-table)
with low = 0
with high = (- (length code-to-byte-table) 2)
while (< low high)
do (let ((mid (logandc2 (truncate (+ low high 2) 2) 1)))

View file

@ -121,7 +121,7 @@
;;; for either signed or unsigned integers. There's no range checking
;;; -- if you don't specify enough bytes for the number to fit, this
;;; function cheerfully outputs the low bytes.
(defun dump-integer-as-n-bytes (num bytes fasl-output)
(defun dump-integer-as-n-bytes (num bytes fasl-output)
(declare (integer num) (type index bytes))
(declare (type fasl-output fasl-output))
(do ((n num (ash n -8))
@ -825,14 +825,19 @@
(dump-integer-as-n-bytes
(ecase sb!c:*backend-byte-order*
(:little-endian i)
(:big-endian (octet-swap i bits)))
(:big-endian (octet-swap i bits))) ; signed or unsigned OK
bytes file))))
(let ((et (!specialized-array-element-type vector)))
(cond
((listp et)
(destructuring-bind (type-id bits) et
(dump-unsigned-vector
(ecase type-id ; could easily extend this to signed-byte
(ecase type-id
(signed-byte
(ecase bits
(8 sb!vm:simple-array-signed-byte-8-widetag)
(16 sb!vm:simple-array-signed-byte-16-widetag)
(32 sb!vm:simple-array-signed-byte-32-widetag)))
(unsigned-byte
(ecase bits
(8 sb!vm:simple-array-unsigned-byte-8-widetag)