📄 arith.lisp
字号:
(:args (shift :scs (signed-reg unsigned-reg)) (prev :scs (unsigned-reg)) (next :scs (unsigned-reg))) (:arg-types tagged-num unsigned-num unsigned-num) (:temporary (:scs (unsigned-reg) :to (:result 0)) temp) (:temporary (:scs (unsigned-reg) :to (:result 0) :target result) res) (:results (result :scs (unsigned-reg))) (:result-types unsigned-num) (:policy :fast-safe) (:generator 4 (let ((done (gen-label))) (inst cmp shift) (inst b :eq done) (inst srl res next shift) (inst sub temp zero-tn shift) (inst sll temp prev temp) (inst or res temp) (emit-label done) (move result res))))(define-vop (shift-towards-someplace) (:policy :fast-safe) (:args (num :scs (unsigned-reg)) (amount :scs (signed-reg))) (:arg-types unsigned-num tagged-num) (:results (r :scs (unsigned-reg))) (:result-types unsigned-num))(define-vop (shift-towards-start shift-towards-someplace) (:translate shift-towards-start) (:note "shift-towards-start") (:generator 1 (inst sll r num amount)))(define-vop (shift-towards-end shift-towards-someplace) (:translate shift-towards-end) (:note "shift-towards-end") (:generator 1 (inst srl r num amount)));;;; Bignum stuff.(define-vop (bignum-length get-header-data) (:translate sb!bignum:%bignum-length) (:policy :fast-safe))(define-vop (bignum-set-length set-header-data) (:translate sb!bignum:%bignum-set-length) (:policy :fast-safe))(define-vop (bignum-ref word-index-ref) (:variant bignum-digits-offset other-pointer-lowtag) (:translate sb!bignum:%bignum-ref) (:results (value :scs (unsigned-reg))) (:result-types unsigned-num))(define-vop (bignum-set word-index-set) (:variant bignum-digits-offset other-pointer-lowtag) (:translate sb!bignum:%bignum-set) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate zero)) (value :scs (unsigned-reg))) (:arg-types t positive-fixnum unsigned-num) (:results (result :scs (unsigned-reg))) (:result-types unsigned-num))(define-vop (digit-0-or-plus) (:translate sb!bignum:%digit-0-or-plusp) (:policy :fast-safe) (:args (digit :scs (unsigned-reg))) (:arg-types unsigned-num) (:results (result :scs (descriptor-reg))) (:guard (not (member :sparc-v9 *backend-subfeatures*))) (:generator 3 (let ((done (gen-label))) (inst cmp digit) (inst b :lt done) (move result null-tn) (load-symbol result t) (emit-label done))))(define-vop (v9-digit-0-or-plus-cmove) (:translate sb!bignum:%digit-0-or-plusp) (:policy :fast-safe) (:args (digit :scs (unsigned-reg))) (:arg-types unsigned-num) (:results (result :scs (descriptor-reg))) (:guard (member :sparc-v9 *backend-subfeatures*)) (:generator 3 (inst cmp digit) (load-symbol result t) (inst cmove :lt result null-tn)));; This doesn't work?#+nil(define-vop (v9-digit-0-or-plus-movr) (:translate sb!bignum:%digit-0-or-plusp) (:policy :fast-safe) (:args (digit :scs (unsigned-reg))) (:arg-types unsigned-num) (:results (result :scs (descriptor-reg))) (:temporary (:scs (descriptor-reg)) temp) (:guard #!+:sparc-v9 t #!-:sparc-v9 nil) (:generator 2 (load-symbol temp t) (inst movr result null-tn digit :lz) (inst movr result temp digit :gez)))(define-vop (add-w/carry) (:translate sb!bignum:%add-with-carry) (:policy :fast-safe) (:args (a :scs (unsigned-reg)) (b :scs (unsigned-reg)) (c :scs (any-reg))) (:arg-types unsigned-num unsigned-num positive-fixnum) (:results (result :scs (unsigned-reg)) (carry :scs (unsigned-reg))) (:result-types unsigned-num positive-fixnum) (:generator 3 (inst addcc zero-tn c -1) (inst addxcc result a b) (inst addx carry zero-tn zero-tn)))(define-vop (sub-w/borrow) (:translate sb!bignum:%subtract-with-borrow) (:policy :fast-safe) (:args (a :scs (unsigned-reg)) (b :scs (unsigned-reg)) (c :scs (any-reg))) (:arg-types unsigned-num unsigned-num positive-fixnum) (:results (result :scs (unsigned-reg)) (borrow :scs (unsigned-reg))) (:result-types unsigned-num positive-fixnum) (:generator 4 (inst subcc zero-tn c 1) (inst subxcc result a b) (inst addx borrow zero-tn zero-tn) (inst xor borrow 1)));;; EMIT-MULTIPLY -- This is used both for bignum stuff and in assembly;;; routines.;;;(defun emit-multiply (multiplier multiplicand result-high result-low) "Emit code to multiply MULTIPLIER with MULTIPLICAND, putting the result in RESULT-HIGH and RESULT-LOW. KIND is either :signed or :unsigned. Note: the lifetimes of MULTIPLICAND and RESULT-HIGH overlap." (declare (type tn multiplier result-high result-low) (type (or tn (signed-byte 13)) multiplicand)) ;; It seems that emit-multiply is only used to do an unsigned ;; multiply, so the code only does an unsigned multiply. (cond ((member :sparc-64 *backend-subfeatures*) ;; Take advantage of V9's 64-bit multiplier. ;; ;; Make sure the multiplier and multiplicand are really ;; unsigned 64-bit numbers. (inst srl multiplier 0) (inst srl multiplicand 0) ;; Multiply the two numbers and put the result in ;; result-high. Copy the low 32-bits to result-low. Then ;; shift result-high so the high 32-bits end up in the low ;; 32-bits. (inst mulx result-high multiplier multiplicand) (inst move result-low result-high) (inst srax result-high 32)) ((or (member :sparc-v8 *backend-subfeatures*) (member :sparc-v9 *backend-subfeatures*)) ;; V8 has a multiply instruction. This should also work for ;; the V9, but umul and the Y register is deprecated on the ;; V9. (inst umul result-low multiplier multiplicand) (inst rdy result-high)) (t (let ((label (gen-label))) (inst wry multiplier) (inst andcc result-high zero-tn) ;; Note: we can't use the Y register until three insts ;; after it's written. (inst nop) (inst nop) (dotimes (i 32) (inst mulscc result-high multiplicand)) (inst mulscc result-high zero-tn) (inst cmp multiplicand) (inst b :ge label) (inst nop) (inst add result-high multiplier) (emit-label label) (inst rdy result-low)))))(define-vop (bignum-mult-and-add-3-arg) (:translate sb!bignum:%multiply-and-add) (:policy :fast-safe) (:args (x :scs (unsigned-reg) :to (:eval 1)) (y :scs (unsigned-reg) :to (:eval 1)) (carry-in :scs (unsigned-reg) :to (:eval 2))) (:arg-types unsigned-num unsigned-num unsigned-num) (:results (hi :scs (unsigned-reg) :from (:eval 0)) (lo :scs (unsigned-reg) :from (:eval 1))) (:result-types unsigned-num unsigned-num) (:generator 40 (emit-multiply x y hi lo) (inst addcc lo carry-in) (inst addx hi zero-tn)))(define-vop (bignum-mult-and-add-4-arg) (:translate sb!bignum:%multiply-and-add) (:policy :fast-safe) (:args (x :scs (unsigned-reg) :to (:eval 1)) (y :scs (unsigned-reg) :to (:eval 1)) (prev :scs (unsigned-reg) :to (:eval 2)) (carry-in :scs (unsigned-reg) :to (:eval 2))) (:arg-types unsigned-num unsigned-num unsigned-num unsigned-num) (:results (hi :scs (unsigned-reg) :from (:eval 0)) (lo :scs (unsigned-reg) :from (:eval 1))) (:result-types unsigned-num unsigned-num) (:generator 40 (emit-multiply x y hi lo) (inst addcc lo carry-in) (inst addx hi zero-tn) (inst addcc lo prev) (inst addx hi zero-tn)))(define-vop (bignum-mult) (:translate sb!bignum:%multiply) (:policy :fast-safe) (:args (x :scs (unsigned-reg) :to (:result 1)) (y :scs (unsigned-reg) :to (:result 1))) (:arg-types unsigned-num unsigned-num) (:results (hi :scs (unsigned-reg)) (lo :scs (unsigned-reg))) (:result-types unsigned-num unsigned-num) (:generator 40 (emit-multiply x y hi lo)))(define-vop (bignum-lognot lognot-mod32/unsigned=>unsigned) (:translate sb!bignum:%lognot))(define-vop (fixnum-to-digit) (:translate sb!bignum:%fixnum-to-digit) (:policy :fast-safe) (:args (fixnum :scs (any-reg))) (:arg-types tagged-num) (:results (digit :scs (unsigned-reg))) (:result-types unsigned-num) (:generator 1 (inst sra digit fixnum n-fixnum-tag-bits)))(define-vop (bignum-floor) (:translate sb!bignum:%floor) (:policy :fast-safe) (:args (div-high :scs (unsigned-reg) :target rem) (div-low :scs (unsigned-reg) :target quo) (divisor :scs (unsigned-reg))) (:arg-types unsigned-num unsigned-num unsigned-num) (:results (quo :scs (unsigned-reg) :from (:argument 1)) (rem :scs (unsigned-reg) :from (:argument 0))) (:result-types unsigned-num unsigned-num) (:generator 300 (move rem div-high) (move quo div-low) (dotimes (i 33) (let ((label (gen-label))) (inst cmp rem divisor) (inst b :ltu label) (inst addxcc quo quo) (inst sub rem divisor) (emit-label label) (unless (= i 32) (inst addx rem rem)))) (inst not quo)))(define-vop (bignum-floor-v8) (:translate sb!bignum:%floor) (:policy :fast-safe) (:args (div-high :scs (unsigned-reg) :target rem) (div-low :scs (unsigned-reg) :target quo) (divisor :scs (unsigned-reg))) (:arg-types unsigned-num unsigned-num unsigned-num) (:results (quo :scs (unsigned-reg) :from (:argument 1)) (rem :scs (unsigned-reg) :from (:argument 0))) (:result-types unsigned-num unsigned-num) (:temporary (:scs (unsigned-reg) :target quo) q) ;; This vop is for a v8 or v9, provided we're also not using ;; sparc-64, for which there a special sparc-64 vop. (:guard (or (member :sparc-v8 *backend-subfeatures*) (member :sparc-v9 *backend-subfeatures*))) (:generator 15 (inst wry div-high) (inst nop) (inst nop) (inst nop) ;; Compute the quotient [Y, div-low] / divisor (inst udiv q div-low divisor) ;; Compute the remainder. The high part of the result is in the Y ;; register. (inst umul rem q divisor) (inst sub rem div-low rem) (unless (location= quo q) (move quo q))))(define-vop (bignum-floor-v9) (:translate sb!bignum:%floor) (:policy :fast-safe) (:args (div-high :scs (unsigned-reg)) (div-low :scs (unsigned-reg)) (divisor :scs (unsigned-reg) :to (:result 1))) (:arg-types unsigned-num unsigned-num unsigned-num) (:temporary (:sc unsigned-reg :from (:argument 0)) dividend) (:results (quo :scs (unsigned-reg)) (rem :scs (unsigned-reg))) (:result-types unsigned-num unsigned-num) (:guard (member :sparc-64 *backend-subfeatures*)) (:generator 5 ;; Set dividend to be div-high and div-low (inst sllx dividend div-high 32) (inst add dividend div-low) ;; Compute quotient (inst udivx quo dividend divisor) ;; Compute the remainder (inst mulx rem quo divisor) (inst sub rem dividend rem)))(define-vop (signify-digit) (:translate sb!bignum:%fixnum-digit-with-correct-sign) (:policy :fast-safe) (:args (digit :scs (unsigned-reg) :target res)) (:arg-types unsigned-num) (:results (res :scs (any-reg signed-reg))) (:result-types signed-num) (:generator 1 (sc-case res (any-reg (inst sll res digit n-fixnum-tag-bits)) (signed-reg (move res digit)))))(define-vop (digit-ashr) (:translate sb!bignum:%ashr) (:policy :fast-safe) (:args (digit :scs (unsigned-reg)) (count :scs (unsigned-reg))) (:arg-types unsigned-num positive-fixnum) (:results (result :scs (unsigned-reg))) (:result-types unsigned-num) (:generator 1 (inst sra result digit count)))(define-vop (digit-lshr digit-ashr) (:translate sb!bignum:%digit-logical-shift-right) (:generator 1 (inst srl result digit count)))(define-vop (digit-ashl digit-ashr) (:translate sb!bignum:%ashl) (:generator 1 (inst sll result digit count)));;;; Static functions.(define-static-fun two-arg-gcd (x y) :translate gcd)(define-static-fun two-arg-lcm (x y) :translate lcm)(define-static-fun two-arg-+ (x y) :translate +)(define-static-fun two-arg-- (x y) :translate -)(define-static-fun two-arg-* (x y) :translate *)(define-static-fun two-arg-/ (x y) :translate /)(define-static-fun two-arg-< (x y) :translate <)(define-static-fun two-arg-<= (x y) :translate <=)(define-static-fun two-arg-> (x y) :translate >)(define-static-fun two-arg->= (x y) :translate >=)(define-static-fun two-arg-= (x y) :translate =)(define-static-fun two-arg-/= (x y) :translate /=)(define-static-fun %negate (x) :translate %negate)(define-static-fun two-arg-and (x y) :translate logand)(define-static-fun two-arg-ior (x y) :translate logior)(define-static-fun two-arg-xor (x y) :translate logxor)(define-static-fun two-arg-eqv (x y) :translate logeqv)(in-package "SB!C")(deftransform * ((x y) ((unsigned-byte 32) (constant-arg (unsigned-byte 32))) (unsigned-byte 32)) "recode as shifts and adds" (let ((y (lvar-value y))) (multiple-value-bind (result adds shifts) (ub32-strength-reduce-constant-multiply 'x y) (cond ;; we assume, perhaps foolishly, that good SPARCs don't have an ;; issue with multiplications. (Remember that there's a ;; different transform for converting x*2^k to a shift). ((member :sparc-64 *backend-subfeatures*) (give-up-ir1-transform)) ((or (member :sparc-v9 *backend-subfeatures*) (member :sparc-v8 *backend-subfeatures*)) ;; breakeven point as measured by Raymond Toy (when (> (+ adds shifts) 9) (give-up-ir1-transform)))) (or result 0))))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -