📄 arith.lisp
字号:
(t (move result number) (cond ((< -32 amount 32) ;; this code is used both in ASH and ASH-MOD32, so ;; be careful (if (plusp amount) (inst shl result amount) (inst shr result (- amount)))) (t (if (sc-is result unsigned-reg) (inst xor result result) (inst mov result 0))))))))(define-vop (fast-ash-left/signed=>signed) (:translate ash) (:args (number :scs (signed-reg) :target result :load-if (not (and (sc-is number signed-stack) (sc-is result signed-stack) (location= number result)))) (amount :scs (unsigned-reg) :target ecx)) (:arg-types signed-num positive-fixnum) (:temporary (:sc unsigned-reg :offset ecx-offset :from (:argument 1)) ecx) (:results (result :scs (signed-reg) :from (:argument 0) :load-if (not (and (sc-is number signed-stack) (sc-is result signed-stack) (location= number result))))) (:result-types signed-num) (:policy :fast-safe) (:note "inline ASH") (:generator 4 (move result number) (move ecx amount) (inst shl result :cl)))(define-vop (fast-ash-left/unsigned=>unsigned) (:translate ash) (:args (number :scs (unsigned-reg) :target result :load-if (not (and (sc-is number unsigned-stack) (sc-is result unsigned-stack) (location= number result)))) (amount :scs (unsigned-reg) :target ecx)) (:arg-types unsigned-num positive-fixnum) (:temporary (:sc unsigned-reg :offset ecx-offset :from (:argument 1)) ecx) (:results (result :scs (unsigned-reg) :from (:argument 0) :load-if (not (and (sc-is number unsigned-stack) (sc-is result unsigned-stack) (location= number result))))) (:result-types unsigned-num) (:policy :fast-safe) (:note "inline ASH") (:generator 4 (move result number) (move ecx amount) (inst shl result :cl)))(define-vop (fast-ash/signed=>signed) (:translate ash) (:policy :fast-safe) (:args (number :scs (signed-reg) :target result) (amount :scs (signed-reg) :target ecx)) (:arg-types signed-num signed-num) (:results (result :scs (signed-reg) :from (:argument 0))) (:result-types signed-num) (:temporary (:sc signed-reg :offset ecx-offset :from (:argument 1)) ecx) (:note "inline ASH") (:generator 5 (move result number) (move ecx amount) (inst or ecx ecx) (inst jmp :ns positive) (inst neg ecx) (inst cmp ecx 31) (inst jmp :be okay) (inst mov ecx 31) OKAY (inst sar result :cl) (inst jmp done) POSITIVE ;; The result-type ensures us that this shift will not overflow. (inst shl result :cl) DONE))(define-vop (fast-ash/unsigned=>unsigned) (:translate ash) (:policy :fast-safe) (:args (number :scs (unsigned-reg) :target result) (amount :scs (signed-reg) :target ecx)) (:arg-types unsigned-num signed-num) (:results (result :scs (unsigned-reg) :from (:argument 0))) (:result-types unsigned-num) (:temporary (:sc signed-reg :offset ecx-offset :from (:argument 1)) ecx) (:note "inline ASH") (:generator 5 (move result number) (move ecx amount) (inst or ecx ecx) (inst jmp :ns positive) (inst neg ecx) (inst cmp ecx 31) (inst jmp :be okay) (inst xor result result) (inst jmp done) OKAY (inst shr result :cl) (inst jmp done) POSITIVE ;; The result-type ensures us that this shift will not overflow. (inst shl result :cl) DONE))(in-package "SB!C")(defknown %lea (integer integer (member 1 2 4 8) (signed-byte 32)) integer (foldable flushable movable))(defoptimizer (%lea derive-type) ((base index scale disp)) (when (and (constant-lvar-p scale) (constant-lvar-p disp)) (let ((scale (lvar-value scale)) (disp (lvar-value disp)) (base-type (lvar-type base)) (index-type (lvar-type index))) (when (and (numeric-type-p base-type) (numeric-type-p index-type)) (let ((base-lo (numeric-type-low base-type)) (base-hi (numeric-type-high base-type)) (index-lo (numeric-type-low index-type)) (index-hi (numeric-type-high index-type))) (make-numeric-type :class 'integer :complexp :real :low (when (and base-lo index-lo) (+ base-lo (* index-lo scale) disp)) :high (when (and base-hi index-hi) (+ base-hi (* index-hi scale) disp))))))))(defun %lea (base index scale disp) (+ base (* index scale) disp))(in-package "SB!VM")(define-vop (%lea/unsigned=>unsigned) (:translate %lea) (:policy :fast-safe) (:args (base :scs (unsigned-reg)) (index :scs (unsigned-reg))) (:info scale disp) (:arg-types unsigned-num unsigned-num (:constant (member 1 2 4 8)) (:constant (signed-byte 32))) (:results (r :scs (unsigned-reg))) (:result-types unsigned-num) (:generator 5 (inst lea r (make-ea :dword :base base :index index :scale scale :disp disp))))(define-vop (%lea/signed=>signed) (:translate %lea) (:policy :fast-safe) (:args (base :scs (signed-reg)) (index :scs (signed-reg))) (:info scale disp) (:arg-types signed-num signed-num (:constant (member 1 2 4 8)) (:constant (signed-byte 32))) (:results (r :scs (signed-reg))) (:result-types signed-num) (:generator 4 (inst lea r (make-ea :dword :base base :index index :scale scale :disp disp))))(define-vop (%lea/fixnum=>fixnum) (:translate %lea) (:policy :fast-safe) (:args (base :scs (any-reg)) (index :scs (any-reg))) (:info scale disp) (:arg-types tagged-num tagged-num (:constant (member 1 2 4 8)) (:constant (signed-byte 32))) (:results (r :scs (any-reg))) (:result-types tagged-num) (:generator 3 (inst lea r (make-ea :dword :base base :index index :scale scale :disp disp))));;; FIXME: before making knowledge of this too public, it needs to be;;; fixed so that it's actually _faster_ than the non-CMOV version; at;;; least on my Celeron-XXX laptop, this version is marginally slower;;; than the above version with branches. -- CSR, 2003-09-04(define-vop (fast-cmov-ash/unsigned=>unsigned) (:translate ash) (:policy :fast-safe) (:args (number :scs (unsigned-reg) :target result) (amount :scs (signed-reg) :target ecx)) (:arg-types unsigned-num signed-num) (:results (result :scs (unsigned-reg) :from (:argument 0))) (:result-types unsigned-num) (:temporary (:sc signed-reg :offset ecx-offset :from (:argument 1)) ecx) (:temporary (:sc any-reg :from (:eval 0) :to (:eval 1)) zero) (:note "inline ASH") (:guard (member :cmov *backend-subfeatures*)) (:generator 4 (move result number) (move ecx amount) (inst or ecx ecx) (inst jmp :ns positive) (inst neg ecx) (inst xor zero zero) (inst shr result :cl) (inst cmp ecx 31) (inst cmov :nbe result zero) (inst jmp done) POSITIVE ;; The result-type ensures us that this shift will not overflow. (inst shl result :cl) DONE))(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 res)) (:arg-types signed-num) (:results (res :scs (unsigned-reg))) (:result-types unsigned-num) (:generator 28 (move res arg) (if (sc-is res unsigned-reg) (inst test res res) (inst cmp res 0)) (inst jmp :ge POS) (inst not res) POS (inst bsr res res) (inst jmp :z zero) (inst inc res) (inst jmp done) ZERO (inst xor res res) DONE))(define-vop (unsigned-byte-32-len) (:translate integer-length) (:note "inline (unsigned-byte 32) integer-length") (:policy :fast-safe) (:args (arg :scs (unsigned-reg))) (:arg-types unsigned-num) (:results (res :scs (unsigned-reg))) (:result-types unsigned-num) (:generator 26 (inst bsr res arg) (inst jmp :z zero) (inst inc res) (inst jmp done) ZERO (inst xor res res) DONE))(define-vop (unsigned-byte-32-count) (:translate logcount) (:note "inline (unsigned-byte 32) logcount") (:policy :fast-safe) (:args (arg :scs (unsigned-reg) :target result)) (:arg-types unsigned-num) (:results (result :scs (unsigned-reg))) (:result-types positive-fixnum) (:temporary (:sc unsigned-reg) temp) (:generator 14 ;; See the comments below for how the algorithm works. The tricks ;; used can be found for example in AMD's software optimization ;; guide or at "http://www.hackersdelight.org/HDcode/pop.cc" in the ;; function "pop1". ;; Calculate 2-bit sums. Note that the value of a two-digit binary ;; number is the sum of the right digit and twice the left digit. ;; Thus we can calculate the sum of the two digits by shifting the ;; left digit to the right position and doing a two-bit subtraction. ;; This subtraction will never create a borrow and thus can be made ;; on all 16 2-digit numbers at once. (move result arg) (move temp arg) (inst shr result 1) (inst and result #x55555555) (inst sub temp result) ;; Calculate 4-bit sums by straightforward shift, mask and add. ;; Note that we shift the source operand of the MOV and not its ;; destination so that the SHR and the MOV can execute in the same ;; clock cycle. (inst mov result temp) (inst shr temp 2) (inst and result #x33333333) (inst and temp #x33333333) (inst add result temp) ;; Calculate 8-bit sums. Since each sum is at most 8, which fits ;; into 4 bits, we can apply the mask after the addition, saving one ;; instruction. (inst mov temp result) (inst shr result 4) (inst add result temp) (inst and result #x0f0f0f0f) ;; Calculate the two 16-bit sums and the 32-bit sum. No masking is ;; necessary inbetween since the final sum is at most 32 which fits ;; into 6 bits. (inst mov temp result) (inst shr result 8) (inst add result temp) (inst mov temp result) (inst shr result 16) (inst add result temp) (inst and result #xff)));;;; 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) :load-if (not (and (sc-is x control-stack) (sc-is y any-reg)))) (y :scs (any-reg control-stack))) (:arg-types tagged-num tagged-num) (:note "inline fixnum comparison"))(define-vop (fast-conditional-c/fixnum fast-conditional/fixnum) (:args (x :scs (any-reg control-stack))) (:arg-types tagged-num (:constant (signed-byte 30))) (:info target not-p y))(define-vop (fast-conditional/signed fast-conditional) (:args (x :scs (signed-reg) :load-if (not (and (sc-is x signed-stack) (sc-is y signed-reg)))) (y :scs (signed-reg signed-stack))) (:arg-types signed-num signed-num) (:note "inline (signed-byte 32) comparison"))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -