📄 array.lisp
字号:
;;;; array operations for the x86 VM;;;; This software is part of the SBCL system. See the README file for;;;; more information.;;;;;;;; This software is derived from the CMU CL system, which was;;;; written at Carnegie Mellon University and released into the;;;; public domain. The software is in the public domain and is;;;; provided with absolutely no warranty. See the COPYING and CREDITS;;;; files for more information.(in-package "SB!VM");; For use in constant indexing; we can't use INDEX since the displacement;; field of an EA can't contain 64 bit values.(deftype low-index () '(signed-byte 29));;;; allocator for the array header(define-vop (make-array-header) (:translate make-array-header) (:policy :fast-safe) (:args (type :scs (any-reg)) (rank :scs (any-reg))) (:arg-types positive-fixnum positive-fixnum) (:temporary (:sc any-reg :to :eval) bytes) (:temporary (:sc any-reg :to :result) header) (:results (result :scs (descriptor-reg) :from :eval)) (:node-var node) (:generator 13 (inst lea bytes (make-ea :qword :base rank :disp (+ (* (1+ array-dimensions-offset) n-word-bytes) lowtag-mask))) (inst and bytes (lognot lowtag-mask)) (inst lea header (make-ea :qword :base rank :disp (fixnumize (1- array-dimensions-offset)))) (inst shl header n-widetag-bits) (inst or header type) (inst shr header (1- n-lowtag-bits)) (pseudo-atomic (allocation result bytes node) (inst lea result (make-ea :qword :base result :disp other-pointer-lowtag)) (storew header result 0 other-pointer-lowtag))));;;; additional accessors and setters for the array header(define-full-reffer %array-dimension * array-dimensions-offset other-pointer-lowtag (any-reg) positive-fixnum sb!kernel:%array-dimension)(define-full-setter %set-array-dimension * array-dimensions-offset other-pointer-lowtag (any-reg) positive-fixnum sb!kernel:%set-array-dimension)(define-vop (array-rank-vop) (:translate sb!kernel:%array-rank) (:policy :fast-safe) (:args (x :scs (descriptor-reg))) (:results (res :scs (unsigned-reg))) (:result-types positive-fixnum) (:generator 6 (loadw res x 0 other-pointer-lowtag) (inst shr res n-widetag-bits) (inst sub res (1- array-dimensions-offset))));;;; bounds checking routine;;; Note that the immediate SC for the index argument is disabled;;; because it is not possible to generate a valid error code SC for;;; an immediate value.;;;;;; FIXME: As per the KLUDGE note explaining the :IGNORE-FAILURE-P;;; flag in build-order.lisp-expr, compiling this file causes warnings;;; Argument FOO to VOP CHECK-BOUND has SC restriction;;; DESCRIPTOR-REG which is not allowed by the operand type:;;; (:OR POSITIVE-FIXNUM);;; CSR's message "format ~/ /" on sbcl-devel 2002-03-12 contained;;; a possible patch, described as;;; Another patch is included more for information than anything --;;; removing the descriptor-reg SCs from the CHECK-BOUND vop in;;; x86/array.lisp seems to allow that file to compile without error[*],;;; and build; I haven't tested rebuilding capability, but I'd be;;; surprised if there were a problem. I'm not certain that this is the;;; correct fix, though, as the restrictions on the arguments to the VOP;;; aren't the same as in the sparc and alpha ports, where, incidentally,;;; the corresponding file builds without error currently.;;; Since neither of us (CSR or WHN) was quite sure that this is the;;; right thing, I've just recorded the patch here in hopes it might;;; help when someone attacks this problem again:;;; diff -u -r1.7 array.lisp;;; --- src/compiler/x86/array.lisp 11 Oct 2001 14:05:26 -0000 1.7;;; +++ src/compiler/x86/array.lisp 12 Mar 2002 12:23:37 -0000;;; @@ -76,10 +76,10 @@;;; (:translate %check-bound);;; (:policy :fast-safe);;; (:args (array :scs (descriptor-reg));;; - (bound :scs (any-reg descriptor-reg));;; - (index :scs (any-reg descriptor-reg #+nil immediate) :target result));;; + (bound :scs (any-reg));;; + (index :scs (any-reg #+nil immediate) :target result));;; (:arg-types * positive-fixnum tagged-num);;; - (:results (result :scs (any-reg descriptor-reg)));;; + (:results (result :scs (any-reg)));;; (:result-types positive-fixnum);;; (:vop-var vop);;; (:save-p :compute-only)(define-vop (check-bound) (:translate %check-bound) (:policy :fast-safe) (:args (array :scs (descriptor-reg)) (bound :scs (any-reg descriptor-reg)) (index :scs (any-reg descriptor-reg) :target result)); (:arg-types * positive-fixnum tagged-num) (:results (result :scs (any-reg descriptor-reg))) ; (:result-types positive-fixnum) (:vop-var vop) (:save-p :compute-only) (:generator 5 (let ((error (generate-error-code vop 'invalid-array-index-error array bound index)) (index (if (sc-is index immediate) (fixnumize (tn-value index)) index))) (inst cmp bound index) ;; We use below-or-equal even though it's an unsigned test, ;; because negative indexes appear as large unsigned numbers. ;; Therefore, we get the <0 and >=bound test all rolled into one. (inst jmp :be error) (unless (and (tn-p index) (location= result index)) (inst mov result index)))));;;; accessors/setters;;; variants built on top of WORD-INDEX-REF, etc. I.e., those vectors;;; whose elements are represented in integer registers and are built;;; out of 8, 16, or 32 bit elements.(macrolet ((def-full-data-vector-frobs (type element-type &rest scs) `(progn (define-full-reffer+offset ,(symbolicate "DATA-VECTOR-REF-WITH-OFFSET/" type) ,type vector-data-offset other-pointer-lowtag ,scs ,element-type data-vector-ref-with-offset) (define-full-setter+offset ,(symbolicate "DATA-VECTOR-SET-WITH-OFFSET/" type) ,type vector-data-offset other-pointer-lowtag ,scs ,element-type data-vector-set-with-offset))) ) (def-full-data-vector-frobs simple-vector * descriptor-reg any-reg) (def-full-data-vector-frobs simple-array-unsigned-byte-64 unsigned-num unsigned-reg) (def-full-data-vector-frobs simple-array-signed-byte-61 tagged-num any-reg) (def-full-data-vector-frobs simple-array-unsigned-byte-60 positive-fixnum any-reg) (def-full-data-vector-frobs simple-array-signed-byte-64 signed-num signed-reg) (def-full-data-vector-frobs simple-array-unsigned-byte-63 unsigned-num unsigned-reg))(define-full-compare-and-swap %compare-and-swap-svref simple-vector vector-data-offset other-pointer-lowtag (descriptor-reg any-reg) * %compare-and-swap-svref);;;; integer vectors whose elements are smaller than a byte, i.e.,;;;; bit, 2-bit, and 4-bit vectors(macrolet ((def-small-data-vector-frobs (type bits) (let* ((elements-per-word (floor n-word-bits bits)) (bit-shift (1- (integer-length elements-per-word)))) `(progn (define-vop (,(symbolicate 'data-vector-ref-with-offset/ type)) (:note "inline array access") (:translate data-vector-ref-with-offset) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (unsigned-reg))) (:info offset) (:arg-types ,type positive-fixnum (:constant (integer 0 0))) (:results (result :scs (unsigned-reg) :from (:argument 0))) (:result-types positive-fixnum) (:temporary (:sc unsigned-reg :offset ecx-offset) ecx) (:generator 20 (aver (zerop offset)) (move ecx index) (inst shr ecx ,bit-shift) (inst mov result (make-ea :qword :base object :index ecx :scale n-word-bytes :disp (- (* vector-data-offset n-word-bytes) other-pointer-lowtag))) (move ecx index) ;; We used to mask ECX for all values of BITS, but since ;; Intel's documentation says that the chip will mask shift ;; and rotate counts by 63 automatically, we can safely move ;; the masking operation under the protection of this UNLESS ;; in the bit-vector case. --njf, 2006-07-14 ,@(unless (= bits 1) `((inst and ecx ,(1- elements-per-word)) (inst shl ecx ,(1- (integer-length bits))))) (inst shr result :cl) (inst and result ,(1- (ash 1 bits))))) (define-vop (,(symbolicate 'data-vector-ref-c-with-offset/ type)) (:translate data-vector-ref-with-offset) (:policy :fast-safe) (:args (object :scs (descriptor-reg))) (:arg-types ,type (:constant low-index) (:constant (integer 0 0))) (:info index offset) (:results (result :scs (unsigned-reg))) (:result-types positive-fixnum) (:generator 15 (aver (zerop offset)) (multiple-value-bind (word extra) (floor index ,elements-per-word) (loadw result object (+ word vector-data-offset) other-pointer-lowtag) (unless (zerop extra) (inst shr result (* extra ,bits))) (unless (= extra ,(1- elements-per-word)) (inst and result ,(1- (ash 1 bits))))))) (define-vop (,(symbolicate 'data-vector-set-with-offset/ type)) (:note "inline array store") (:translate data-vector-set-with-offset) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (unsigned-reg) :target ecx) (value :scs (unsigned-reg immediate) :target result)) (:info offset) (:arg-types ,type positive-fixnum (:constant (integer 0 0)) positive-fixnum) (:results (result :scs (unsigned-reg))) (:result-types positive-fixnum) (:temporary (:sc unsigned-reg) word-index) (:temporary (:sc unsigned-reg) old) (:temporary (:sc unsigned-reg :offset ecx-offset) ecx) (:generator 25 (aver (zerop offset)) (move word-index index) (inst shr word-index ,bit-shift) (inst mov old (make-ea :qword :base object :index word-index :scale n-word-bytes :disp (- (* vector-data-offset n-word-bytes) other-pointer-lowtag))) (move ecx index) ;; We used to mask ECX for all values of BITS, but since ;; Intel's documentation says that the chip will mask shift ;; and rotate counts by 63 automatically, we can safely move ;; the masking operation under the protection of this UNLESS ;; in the bit-vector case. --njf, 2006-07-14 ,@(unless (= bits 1) `((inst and ecx ,(1- elements-per-word)) (inst shl ecx ,(1- (integer-length bits))))) (inst ror old :cl) (unless (and (sc-is value immediate) (= (tn-value value) ,(1- (ash 1 bits)))) (inst and old ,(lognot (1- (ash 1 bits))))) (sc-case value (immediate (unless (zerop (tn-value value)) (inst or old (logand (tn-value value) ,(1- (ash 1 bits)))))) (unsigned-reg (inst or old value))) (inst rol old :cl) (inst mov (make-ea :qword :base object :index word-index :scale n-word-bytes :disp (- (* vector-data-offset n-word-bytes) other-pointer-lowtag)) old) (sc-case value (immediate (inst mov result (tn-value value))) (unsigned-reg (move result value))))) (define-vop (,(symbolicate 'data-vector-set-c-with-offset/ type)) (:translate data-vector-set-with-offset) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (value :scs (unsigned-reg immediate) :target result)) (:arg-types ,type (:constant low-index) (:constant (integer 0 0)) positive-fixnum) (:temporary (:sc unsigned-reg) mask-tn) (:info index offset) (:results (result :scs (unsigned-reg))) (:result-types positive-fixnum) (:temporary (:sc unsigned-reg :to (:result 0)) old) (:generator 20 (aver (zerop offset)) (multiple-value-bind (word extra) (floor index ,elements-per-word) (inst mov old (make-ea :qword :base object :disp (- (* (+ word vector-data-offset) n-word-bytes) other-pointer-lowtag))) (sc-case value (immediate (let* ((value (tn-value value)) (mask ,(1- (ash 1 bits))) (shift (* extra ,bits))) (unless (= value mask) (inst mov mask-tn (ldb (byte 64 0) (lognot (ash mask shift)))) (inst and old mask-tn)) (unless (zerop value) (inst mov mask-tn (ash value shift)) (inst or old mask-tn)))) (unsigned-reg (let ((shift (* extra ,bits))) (unless (zerop shift) (inst ror old shift)) (inst mov mask-tn (lognot ,(1- (ash 1 bits)))) (inst and old mask-tn) (inst or old value) (unless (zerop shift) (inst rol old shift))))) (inst mov (make-ea :qword :base object :disp (- (* (+ word vector-data-offset) n-word-bytes) other-pointer-lowtag)) old) (sc-case value (immediate (inst mov result (tn-value value))) (unsigned-reg (move result value)))))))))) (def-small-data-vector-frobs simple-bit-vector 1) (def-small-data-vector-frobs simple-array-unsigned-byte-2 2) (def-small-data-vector-frobs simple-array-unsigned-byte-4 4))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -