📄 arith.lisp
字号:
;; overflow. (inst sll result number amount) (inst neg ndesc amount) (inst cmp ndesc 31) (if (member :sparc-v9 *backend-subfeatures*) (progn (inst cmove :ge ndesc 31) (inst sra result number ndesc)) (progn (inst b :le done) (inst sra result number ndesc) (inst sra result number 31))) (emit-label done))))(define-vop (fast-ash-c/signed=>signed) (:note "inline constant ASH") (:args (number :scs (signed-reg))) (:info count) (:arg-types signed-num (:constant integer)) (:results (result :scs (signed-reg))) (:result-types signed-num) (:translate ash) (:policy :fast-safe) (:generator 4 (cond ((< count 0) (inst sra result number (min (- count) 31))) ((> count 0) (inst sll result number (min count 31))) (t (bug "identity ASH not transformed away")))))(define-vop (fast-ash/unsigned=>unsigned) (:note "inline ASH") (:args (number :scs (unsigned-reg) :to :save) (amount :scs (signed-reg) :to :save)) (:arg-types unsigned-num signed-num) (:results (result :scs (unsigned-reg))) (:result-types unsigned-num) (:translate ash) (:policy :fast-safe) (:temporary (:sc non-descriptor-reg) ndesc) (:generator 5 (let ((done (gen-label))) (inst cmp amount) (inst b :ge done) ;; The result-type assures us that this shift will not ;; overflow. (inst sll result number amount) (inst neg ndesc amount) (inst cmp ndesc 32) (if (member :sparc-v9 *backend-subfeatures*) (progn (inst srl result number ndesc) (inst cmove :ge result zero-tn)) (progn (inst b :lt done) (inst srl result number ndesc) (move result zero-tn))) (emit-label done))))(define-vop (fast-ash-c/unsigned=>unsigned) (:note "inline constant ASH") (:args (number :scs (unsigned-reg))) (:info count) (:arg-types unsigned-num (:constant integer)) (:results (result :scs (unsigned-reg))) (:result-types unsigned-num) (:translate ash) (:policy :fast-safe) (:generator 4 (cond ((< count -31) (move result zero-tn)) ((< count 0) (inst srl result number (min (- count) 31))) ((> count 0) (inst sll result number (min count 31))) (t (bug "identity ASH not transformed away")))));; Some special cases where we know we want a left shift. Just do the;; shift, instead of checking for the sign of the shift.(macrolet ((def (name sc-type type result-type cost) `(define-vop (,name) (:note "inline ASH") (:translate ash) (:args (number :scs (,sc-type)) (amount :scs (signed-reg unsigned-reg immediate))) (:arg-types ,type positive-fixnum) (:results (result :scs (,result-type))) (:result-types ,type) (:policy :fast-safe) (:generator ,cost ;; The result-type assures us that this shift will not ;; overflow. And for fixnums, the zero bits that get ;; shifted in are just fine for the fixnum tag. (sc-case amount ((signed-reg unsigned-reg) (inst sll result number amount)) (immediate (let ((amount (tn-value amount))) (aver (>= amount 0)) (inst sll result number amount)))))))) (def fast-ash-left/signed=>signed signed-reg signed-num signed-reg 3) (def fast-ash-left/fixnum=>fixnum any-reg tagged-num any-reg 2) (def fast-ash-left/unsigned=>unsigned unsigned-reg unsigned-num unsigned-reg 3))(define-vop (signed-byte-32-len) (:translate integer-length) (:note "inline (signed-byte 32) integer-length") (:policy :fast-safe) (:args (arg :scs (signed-reg) :target shift)) (:arg-types signed-num) (:results (res :scs (any-reg))) (:result-types positive-fixnum) (:temporary (:scs (non-descriptor-reg) :from (:argument 0)) shift) (:generator 30 (let ((loop (gen-label)) (test (gen-label))) (inst addcc shift zero-tn arg) (inst b :ge test) (move res zero-tn) (inst b test) (inst not shift) (emit-label loop) (inst add res (fixnumize 1)) (emit-label test) (inst cmp shift) (inst b :ne loop) (inst srl shift 1))))(define-vop (unsigned-byte-32-count) (:translate logcount) (:note "inline (unsigned-byte 32) logcount") (:policy :fast-safe) (:args (arg :scs (unsigned-reg))) (:arg-types unsigned-num) (:results (res :scs (unsigned-reg))) (:result-types positive-fixnum) (:temporary (:scs (non-descriptor-reg) :from (:argument 0)) mask temp) (:generator 35 (move res arg) (dolist (stuff '((1 #x55555555) (2 #x33333333) (4 #x0f0f0f0f) (8 #x00ff00ff) (16 #x0000ffff))) (destructuring-bind (shift bit-mask) stuff ;; Set mask (inst sethi mask (ldb (byte 22 10) bit-mask)) (inst add mask (ldb (byte 10 0) bit-mask)) (inst and temp res mask) (inst srl res shift) (inst and res mask) (inst add res temp)))));;; Multiply and Divide.(define-vop (fast-v8-*/fixnum=>fixnum fast-fixnum-binop) (:temporary (:scs (non-descriptor-reg)) temp) (:translate *) (:guard (or (member :sparc-v8 *backend-subfeatures*) (and (member :sparc-v9 *backend-subfeatures*) (not (member :sparc-64 *backend-subfeatures*))))) (:generator 2 ;; The cost here should be less than the cost for ;; */signed=>signed. Why? A fixnum product using signed=>signed ;; has to convert both args to signed-nums. But using this, we ;; don't have to and that saves an instruction. (inst sra temp y n-fixnum-tag-bits) (inst smul r x temp)))(define-vop (fast-v8-*-c/fixnum=>fixnum fast-safe-arith-op) (:args (x :target r :scs (any-reg zero))) (:info y) (:arg-types tagged-num (:constant (and (signed-byte 13) (not (integer 0 0))))) (:results (r :scs (any-reg))) (:result-types tagged-num) (:note "inline fixnum arithmetic") (:translate *) (:guard (or (member :sparc-v8 *backend-subfeatures*) (and (member :sparc-v9 *backend-subfeatures*) (not (member :sparc-64 *backend-subfeatures*))))) (:generator 1 (inst smul r x y)))(define-vop (fast-v8-*/signed=>signed fast-signed-binop) (:translate *) (:guard (or (member :sparc-v8 *backend-subfeatures*) (and (member :sparc-v9 *backend-subfeatures*) (not (member :sparc-64 *backend-subfeatures*))))) (:generator 3 (inst smul r x y)))(define-vop (fast-v8-*-c/signed=>signed fast-signed-binop-c) (:translate *) (:guard (or (member :sparc-v8 *backend-subfeatures*) (and (member :sparc-v9 *backend-subfeatures*) (not (member :sparc-64 *backend-subfeatures*))))) (:generator 2 (inst smul r x y)))(define-vop (fast-v8-*/unsigned=>unsigned fast-unsigned-binop) (:translate *) (:guard (or (member :sparc-v8 *backend-subfeatures*) (and (member :sparc-v9 *backend-subfeatures*) (not (member :sparc-64 *backend-subfeatures*))))) (:generator 3 (inst umul r x y)))(define-vop (fast-v8-*-c/unsigned=>unsigned fast-unsigned-binop-c) (:translate *) (:guard (or (member :sparc-v8 *backend-subfeatures*) (and (member :sparc-v9 *backend-subfeatures*) (not (member :sparc-64 *backend-subfeatures*))))) (:generator 2 (inst umul r x y)));; The smul and umul instructions are deprecated on the Sparc V9. Use;; mulx instead.(define-vop (fast-v9-*/fixnum=>fixnum fast-fixnum-binop) (:temporary (:scs (non-descriptor-reg)) temp) (:translate *) (:guard (member :sparc-64 *backend-subfeatures*)) (:generator 4 (inst sra temp y n-fixnum-tag-bits) (inst mulx r x temp)))(define-vop (fast-v9-*/signed=>signed fast-signed-binop) (:translate *) (:guard (member :sparc-64 *backend-subfeatures*)) (:generator 3 (inst mulx r x y)))(define-vop (fast-v9-*/unsigned=>unsigned fast-unsigned-binop) (:translate *) (:guard (member :sparc-64 *backend-subfeatures*)) (:generator 3 (inst mulx r x y)));;;; Modular functions:(define-modular-fun lognot-mod32 (x) lognot :untagged nil 32)(define-vop (lognot-mod32/unsigned=>unsigned) (:translate lognot-mod32) (:args (x :scs (unsigned-reg))) (:arg-types unsigned-num) (:results (res :scs (unsigned-reg))) (:result-types unsigned-num) (:policy :fast-safe) (:generator 1 (inst not res x)))(macrolet ((define-modular-backend (fun &optional constantp) (let ((mfun-name (symbolicate fun '-mod32)) (modvop (symbolicate 'fast- fun '-mod32/unsigned=>unsigned)) (modcvop (symbolicate 'fast- fun '-mod32-c/unsigned=>unsigned)) (vop (symbolicate 'fast- fun '/unsigned=>unsigned)) (cvop (symbolicate 'fast- fun '-c/unsigned=>unsigned))) `(progn (define-modular-fun ,mfun-name (x y) ,fun :untagged nil 32) (define-vop (,modvop ,vop) (:translate ,mfun-name)) ,@(when constantp `((define-vop (,modcvop ,cvop) (:translate ,mfun-name)))))))) (define-modular-backend + t) (define-modular-backend - t) (define-modular-backend logeqv t) (define-modular-backend logandc1) (define-modular-backend logandc2 t) (define-modular-backend logorc1) (define-modular-backend logorc2 t))(define-source-transform lognand (x y) `(lognot (logand ,x ,y)))(define-source-transform lognor (x y) `(lognot (logior ,x ,y)))(define-vop (fast-ash-left-mod32-c/unsigned=>unsigned fast-ash-c/unsigned=>unsigned) (:translate ash-left-mod32))(define-vop (fast-ash-left-mod32/unsigned=>unsigned fast-ash-left/unsigned=>unsigned))(deftransform ash-left-mod32 ((integer count) ((unsigned-byte 32) (unsigned-byte 5))) (when (sb!c::constant-lvar-p count) (sb!c::give-up-ir1-transform)) '(%primitive fast-ash-left-mod32/unsigned=>unsigned integer count));;;; Binary conditional VOPs:(define-vop (fast-conditional) (:conditional) (:info target not-p) (:effects) (:affected) (:policy :fast-safe))(define-vop (fast-conditional/fixnum fast-conditional) (:args (x :scs (any-reg zero)) (y :scs (any-reg zero))) (:arg-types tagged-num tagged-num) (:note "inline fixnum comparison"))(define-vop (fast-conditional-c/fixnum fast-conditional/fixnum) (:args (x :scs (any-reg zero))) (:arg-types tagged-num (:constant (signed-byte 11))) (:info target not-p y))(define-vop (fast-conditional/signed fast-conditional) (:args (x :scs (signed-reg zero)) (y :scs (signed-reg zero))) (:arg-types signed-num signed-num) (:note "inline (signed-byte 32) comparison"))(define-vop (fast-conditional-c/signed fast-conditional/signed) (:args (x :scs (signed-reg zero))) (:arg-types signed-num (:constant (signed-byte 13))) (:info target not-p y))(define-vop (fast-conditional/unsigned fast-conditional) (:args (x :scs (unsigned-reg zero)) (y :scs (unsigned-reg zero))) (:arg-types unsigned-num unsigned-num) (:note "inline (unsigned-byte 32) comparison"))(define-vop (fast-conditional-c/unsigned fast-conditional/unsigned) (:args (x :scs (unsigned-reg zero))) (:arg-types unsigned-num (:constant (unsigned-byte 12))) (:info target not-p y))(defmacro define-conditional-vop (tran cond unsigned not-cond not-unsigned) `(progn ,@(mapcar (lambda (suffix cost signed) (unless (and (member suffix '(/fixnum -c/fixnum)) (eq tran 'eql)) `(define-vop (,(intern (format nil "~:@(FAST-IF-~A~A~)" tran suffix)) ,(intern (format nil "~:@(FAST-CONDITIONAL~A~)" suffix))) (:translate ,tran) (:generator ,cost (inst cmp x ,(if (eq suffix '-c/fixnum) '(fixnumize y) 'y)) (inst b (if not-p ,(if signed not-cond not-unsigned) ,(if signed cond unsigned)) target) (inst nop))))) '(/fixnum -c/fixnum /signed -c/signed /unsigned -c/unsigned) '(4 3 6 5 6 5) '(t t t t nil nil))))(define-conditional-vop < :lt :ltu :ge :geu)(define-conditional-vop > :gt :gtu :le :leu)(define-conditional-vop eql :eq :eq :ne :ne);;; EQL/FIXNUM is funny because the first arg can be of any type, not just a;;; known fixnum.;;; These versions specify a fixnum restriction on their first arg. We have;;; also generic-eql/fixnum VOPs which are the same, but have no restriction on;;; the first arg and a higher cost. The reason for doing this is to prevent;;; fixnum specific operations from being used on word integers, spuriously;;; consing the argument.;;;(define-vop (fast-eql/fixnum fast-conditional) (:args (x :scs (any-reg descriptor-reg zero)) (y :scs (any-reg zero))) (:arg-types tagged-num tagged-num) (:note "inline fixnum comparison") (:translate eql) (:generator 4 (inst cmp x y) (inst b (if not-p :ne :eq) target) (inst nop)));;;(define-vop (generic-eql/fixnum fast-eql/fixnum) (:arg-types * tagged-num) (:variant-cost 7))(define-vop (fast-eql-c/fixnum fast-conditional/fixnum) (:args (x :scs (any-reg descriptor-reg zero))) (:arg-types tagged-num (:constant (signed-byte 11))) (:info target not-p y) (:translate eql) (:generator 2 (inst cmp x (fixnumize y)) (inst b (if not-p :ne :eq) target) (inst nop)));;;(define-vop (generic-eql-c/fixnum fast-eql-c/fixnum) (:arg-types * (:constant (signed-byte 11))) (:variant-cost 6));;;; 32-bit logical operations(define-vop (merge-bits) (:translate merge-bits)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -