1.0.9.9: rename CLASS-SLOT-VECTOR to CLASS-SLOT-TABLE
[sbcl.git] / src / compiler / x86-64 / arith.lisp
index 3045903..3e55ac2 100644 (file)
   (:args (x :scs (unsigned-reg) :target eax)
          (y :scs (unsigned-reg unsigned-stack)))
   (:arg-types unsigned-num unsigned-num)
-  (:temporary (:sc unsigned-reg :offset eax-offset :target result
+  (:temporary (:sc unsigned-reg :offset eax-offset :target r
                    :from (:argument 0) :to :result) eax)
   (:temporary (:sc unsigned-reg :offset edx-offset
                    :from :eval :to :result) edx)
   (:ignore edx)
-  (:results (result :scs (unsigned-reg)))
+  (:results (r :scs (unsigned-reg)))
   (:result-types unsigned-num)
   (:note "inline (unsigned-byte 64) arithmetic")
   (:vop-var vop)
   (:generator 6
     (move eax x)
     (inst mul eax y)
-    (move result eax)))
+    (move r eax)))
 
 
 (define-vop (fast-truncate/fixnum=>fixnum fast-safe-arith-op)
   (:note "inline ASH")
   (:generator 2
     (cond ((and (= amount 1) (not (location= number result)))
-           (inst lea result (make-ea :qword :index number :scale 2)))
+           (inst lea result (make-ea :qword :base number :index number)))
           ((and (= amount 2) (not (location= number result)))
            (inst lea result (make-ea :qword :index number :scale 4)))
           ((and (= amount 3) (not (location= number result)))
   (:note "inline ASH")
   (:generator 3
     (cond ((and (= amount 1) (not (location= number result)))
-           (inst lea result (make-ea :qword :index number :scale 2)))
+           (inst lea result (make-ea :qword :base number :index number)))
           ((and (= amount 2) (not (location= number result)))
            (inst lea result (make-ea :qword :index number :scale 4)))
           ((and (= amount 3) (not (location= number result)))
   (:note "inline ASH")
   (:generator 3
     (cond ((and (= amount 1) (not (location= number result)))
-           (inst lea result (make-ea :qword :index number :scale 2)))
+           (inst lea result (make-ea :qword :base number :index number)))
           ((and (= amount 2) (not (location= number result)))
            (inst lea result (make-ea :qword :index number :scale 4)))
           ((and (= amount 3) (not (location= number result)))
                       (inst shl result amount)
                       (inst shr result (- amount))))
                  (t (if (sc-is result unsigned-reg)
-                        (inst xor result result)
+                        (zeroize result)
                         (inst mov result 0))))))))
 
 (define-vop (fast-ash-left/signed=>signed)
     (inst neg ecx)
     (inst cmp ecx 63)
     (inst jmp :be OKAY)
-    (inst xor result result)
+    (zeroize result)
     (inst jmp DONE)
     OKAY
     (inst shr result :cl)
     (inst or ecx ecx)
     (inst jmp :ns POSITIVE)
     (inst neg ecx)
-    (inst xor zero zero)
+    (zeroize zero)
     (inst shr result :cl)
     (inst cmp ecx 63)
     (inst cmov :nbe result zero)
     (inst inc res)
     (inst jmp DONE)
     ZERO
-    (inst xor res res)
+    (zeroize res)
     DONE))
 
 (define-vop (unsigned-byte-64-len)
     (inst inc res)
     (inst jmp DONE)
     ZERO
-    (inst xor res res)
+    (zeroize res)
     DONE))
 
-
 (define-vop (unsigned-byte-64-count)
   (:translate logcount)
   (:note "inline (unsigned-byte 64) logcount")
   (:policy :fast-safe)
-  (:args (arg :scs (unsigned-reg)))
+  (:args (arg :scs (unsigned-reg) :target result))
   (:arg-types unsigned-num)
   (:results (result :scs (unsigned-reg)))
   (:result-types positive-fixnum)
-  (:temporary (:sc unsigned-reg :from (:argument 0)) temp)
-  (:temporary (:sc unsigned-reg :from (:argument 0)) t1)
-  (:generator 60
+  (:temporary (:sc unsigned-reg) temp)
+  (:temporary (:sc unsigned-reg) mask)
+  (: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", for 32-bit words. The extension to 64 bits is
+    ;; straightforward.
+    ;; 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 32 2-digit numbers at once.
     (move result arg)
-    (move t1 arg)
-
-    (inst mov temp result)
-    (inst shr temp 1)
-    (inst and result #x55555555)        ; note these masks will restrict the
-    (inst and temp #x55555555)          ; count to the lower half of arg
-    (inst add result temp)
-
-    (inst mov temp result)
+    (move temp arg)
+    (inst shr result 1)
+    (inst mov mask #x5555555555555555)
+    (inst and result mask)
+    (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 mov mask #x3333333333333333)
+    (inst and result mask)
+    (inst and temp mask)
     (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 temp 4)
-    (inst and result #x0f0f0f0f)
-    (inst and temp #x0f0f0f0f)
+    (inst shr result 4)
     (inst add result temp)
-
-    (inst mov temp result)
-    (inst shr temp 8)
-    (inst and result #x00ff00ff)
-    (inst and temp #x00ff00ff)
-    (inst add result temp)
-
-    (inst mov temp result)
-    (inst shr temp 16)
-    (inst and result #x0000ffff)
-    (inst and temp #x0000ffff)
-    (inst add result temp)
-
-    ;;; now do the upper half
-    (inst shr t1 32)
-
-    (inst mov temp t1)
-    (inst shr temp 1)
-    (inst and t1 #x55555555)
-    (inst and temp #x55555555)
-    (inst add t1 temp)
-
-    (inst mov temp t1)
-    (inst shr temp 2)
-    (inst and t1 #x33333333)
-    (inst and temp #x33333333)
-    (inst add t1 temp)
-
-    (inst mov temp t1)
-    (inst shr temp 4)
-    (inst and t1 #x0f0f0f0f)
-    (inst and temp #x0f0f0f0f)
-    (inst add t1 temp)
-
-    (inst mov temp t1)
-    (inst shr temp 8)
-    (inst and t1 #x00ff00ff)
-    (inst and temp #x00ff00ff)
-    (inst add t1 temp)
-
-    (inst mov temp t1)
-    (inst shr temp 16)
-    (inst and t1 #x0000ffff)
-    (inst and temp #x0000ffff)
-    (inst add t1 temp)
-    (inst add result t1)))
-
-
+    (inst mov mask #x0f0f0f0f0f0f0f0f)
+    (inst and result mask)
+    ;; Add all 8 bytes at once by multiplying with #256r11111111.
+    ;; We need to calculate only the lower 8 bytes of the product.
+    ;; Of these the most significant byte contains the final result.
+    ;; Note that there can be no overflow from one byte to the next
+    ;; as the sum is at most 64 which needs only 7 bits.
+    (inst mov mask #x0101010101010101)
+    (inst imul result mask)
+    (inst shr result 56)))
 \f
 ;;;; binary conditional VOPs
 
 \f
 ;;;; Modular functions
 
+(defmacro define-mod-binop ((name prototype) function)
+  `(define-vop (,name ,prototype)
+       (:args (x :target r :scs (unsigned-reg signed-reg)
+                 :load-if (not (and (or (sc-is x unsigned-stack)
+                                        (sc-is x signed-stack))
+                                    (or (sc-is y unsigned-reg)
+                                        (sc-is y signed-reg))
+                                    (or (sc-is r unsigned-stack)
+                                        (sc-is r signed-stack))
+                                    (location= x r))))
+              (y :scs (unsigned-reg signed-reg unsigned-stack signed-stack)))
+     (:arg-types untagged-num untagged-num)
+     (:results (r :scs (unsigned-reg signed-reg) :from (:argument 0)
+                  :load-if (not (and (or (sc-is x unsigned-stack)
+                                         (sc-is x signed-stack))
+                                     (or (sc-is y unsigned-reg)
+                                         (sc-is y unsigned-reg))
+                                     (or (sc-is r unsigned-stack)
+                                         (sc-is r unsigned-stack))
+                                     (location= x r)))))
+     (:result-types unsigned-num)
+     (:translate ,function)))
+(defmacro define-mod-binop-c ((name prototype) function)
+  `(define-vop (,name ,prototype)
+       (:args (x :target r :scs (unsigned-reg signed-reg)
+                 :load-if (not (and (or (sc-is x unsigned-stack)
+                                        (sc-is x signed-stack))
+                                    (or (sc-is r unsigned-stack)
+                                        (sc-is r signed-stack))
+                                    (location= x r)))))
+     (:info y)
+     (:arg-types untagged-num (:constant (or (unsigned-byte 31) (signed-byte 32))))
+     (:results (r :scs (unsigned-reg signed-reg) :from (:argument 0)
+                  :load-if (not (and (or (sc-is x unsigned-stack)
+                                         (sc-is x signed-stack))
+                                     (or (sc-is r unsigned-stack)
+                                         (sc-is r unsigned-stack))
+                                     (location= x r)))))
+     (:result-types unsigned-num)
+     (:translate ,function)))
+
 (macrolet ((def (name -c-p)
              (let ((fun64 (intern (format nil "~S-MOD64" name)))
                    (vopu (intern (format nil "FAST-~S/UNSIGNED=>UNSIGNED" name)))
                    (vopcu (intern (format nil "FAST-~S-C/UNSIGNED=>UNSIGNED" name)))
                    (vopf (intern (format nil "FAST-~S/FIXNUM=>FIXNUM" name)))
                    (vopcf (intern (format nil "FAST-~S-C/FIXNUM=>FIXNUM" name)))
-                   (vop64u (intern (format nil "FAST-~S-MOD64/UNSIGNED=>UNSIGNED" name)))
+                   (vop64u (intern (format nil "FAST-~S-MOD64/WORD=>UNSIGNED" name)))
                    (vop64f (intern (format nil "FAST-~S-MOD64/FIXNUM=>FIXNUM" name)))
-                   (vop64cu (intern (format nil "FAST-~S-MOD64-C/UNSIGNED=>UNSIGNED" name)))
+                   (vop64cu (intern (format nil "FAST-~S-MOD64-C/WORD=>UNSIGNED" name)))
                    (vop64cf (intern (format nil "FAST-~S-MOD64-C/FIXNUM=>FIXNUM" name)))
                    (sfun61 (intern (format nil "~S-SMOD61" name)))
                    (svop61f (intern (format nil "FAST-~S-SMOD61/FIXNUM=>FIXNUM" name)))
                `(progn
                   (define-modular-fun ,fun64 (x y) ,name :unsigned 64)
                   (define-modular-fun ,sfun61 (x y) ,name :signed 61)
-                  (define-vop (,vop64u ,vopu) (:translate ,fun64))
+                  (define-mod-binop (,vop64u ,vopu) ,fun64)
                   (define-vop (,vop64f ,vopf) (:translate ,fun64))
                   (define-vop (,svop61f ,vopf) (:translate ,sfun61))
                   ,@(when -c-p
-                      `((define-vop (,vop64cu ,vopcu) (:translate ,fun64))
+                      `((define-mod-binop-c (,vop64cu ,vopcu) ,fun64)
                         (define-vop (,svop61cf ,vopcf) (:translate ,sfun61))))))))
   (def + t)
   (def - t)
     (inst not r)))
 
 (define-modular-fun logxor-mod64 (x y) logxor :unsigned 64)
-(define-vop (fast-logxor-mod64/unsigned=>unsigned
-             fast-logxor/unsigned=>unsigned)
-  (:translate logxor-mod64))
-(define-vop (fast-logxor-mod64-c/unsigned=>unsigned
-             fast-logxor-c/unsigned=>unsigned)
-  (:translate logxor-mod64))
+(define-mod-binop (fast-logxor-mod64/word=>unsigned
+                   fast-logxor/unsigned=>unsigned)
+    logxor-mod64)
+(define-mod-binop-c (fast-logxor-mod64-c/word=>unsigned
+                     fast-logxor-c/unsigned=>unsigned)
+    logxor-mod64)
 (define-vop (fast-logxor-mod64/fixnum=>fixnum
              fast-logxor/fixnum=>fixnum)
   (:translate logxor-mod64))
 
 (define-full-reffer bignum-ref * bignum-digits-offset other-pointer-lowtag
   (unsigned-reg) unsigned-num sb!bignum:%bignum-ref)
-
+(define-full-reffer+offset bignum--ref-with-offset * bignum-digits-offset
+  other-pointer-lowtag (unsigned-reg) unsigned-num
+  sb!bignum:%bignum-ref-with-offset)
 (define-full-setter bignum-set * bignum-digits-offset other-pointer-lowtag
   (unsigned-reg) unsigned-num sb!bignum:%bignum-set)
 
 
 
 ;;; For add and sub with carry the sc of carry argument is any-reg so
-;;; the it may be passed as a fixnum or word and thus may be 0, 1, or
-;;; 4. This is easy to deal with and may save a fixnum-word
+;;; that it may be passed as a fixnum or word and thus may be 0, 1, or
+;;; 8. This is easy to deal with and may save a fixnum-word
 ;;; conversion.
 (define-vop (add-w/carry)
   (:translate sb!bignum:%add-with-carry)
     (inst mov carry 0)
     (inst adc carry carry)))
 
-;;; Note: the borrow is the oppostite of the x86 convention - 1 for no
-;;; borrow and 0 for a borrow.
+;;; Note: the borrow is 1 for no borrow and 0 for a borrow, the opposite
+;;; of the x86-64 convention.
 (define-vop (sub-w/borrow)
   (:translate sb!bignum:%subtract-with-borrow)
   (:policy :fast-safe)
     (inst cmp c 1) ; Set the carry flag to 1 if c=0 else to 0
     (move result a)
     (inst sbb result b)
-    (inst mov borrow 0)
-    (inst adc borrow borrow)
-    (inst xor borrow 1)))
+    (inst mov borrow 1)
+    (inst sbb borrow 0)))
 
 
 (define-vop (bignum-mult-and-add-3-arg)
                     :load-if (not (and (sc-is result unsigned-stack)
                                        (location= digit result)))))
   (:result-types unsigned-num)
-  (:generator 1
+  (:generator 2
     (move result digit)
     (move ecx count)
     (inst sar result :cl)))
 
+(define-vop (digit-ashr/c)
+  (:translate sb!bignum:%ashr)
+  (:policy :fast-safe)
+  (:args (digit :scs (unsigned-reg unsigned-stack) :target result))
+  (:arg-types unsigned-num (:constant (integer 0 63)))
+  (:info count)
+  (:results (result :scs (unsigned-reg) :from (:argument 0)
+                    :load-if (not (and (sc-is result unsigned-stack)
+                                       (location= digit result)))))
+  (:result-types unsigned-num)
+  (:generator 1
+    (move result digit)
+    (inst sar result count)))
+
 (define-vop (digit-lshr digit-ashr)
   (:translate sb!bignum:%digit-logical-shift-right)
   (:generator 1