0.8.3.62:
[sbcl.git] / src / compiler / sparc / arith.lisp
index aece39a..b0fa826 100644 (file)
 
 ;;; Shifting
 
-(macrolet
-    ((frob (name sc-type type shift-right-inst)
-       `(define-vop (,name)
-         (:note "inline ASH")
-         (:args (number :scs (,sc-type) :to :save)
-                (amount :scs (signed-reg immediate)))
-         (:arg-types ,type signed-num)
-         (:results (result :scs (,sc-type)))
-         (:result-types ,type)
-         (:translate ash)
-         (:policy :fast-safe)
-         (:temporary (:sc non-descriptor-reg) ndesc)
-         (:generator 5
-           (sc-case amount
-            (signed-reg
-             (cond
-               ;; FIXME: These two don't look different enough.
-               ((member :sparc-v9 *backend-subfeatures*)
-                (let ((done (gen-label))
-                      (positive (gen-label)))
-                  (inst cmp amount)
-                  (inst b :ge positive)
-                  (inst neg ndesc amount)
-                  ;; ndesc = max(-amount, 31)
-                  (inst cmp ndesc 31)
-                  (inst cmove :ge ndesc 31)
-                  (inst b done)
-                  (inst ,shift-right-inst result number ndesc)
-                  (emit-label positive)
-                  ;; The result-type assures us that this shift will
-                  ;; not overflow.
-                  (inst sll result number amount)
-                  ;; We want a right shift of the appropriate size.
-                  (emit-label done)))
-               (t
-                (let ((positive (gen-label))
-                      (done (gen-label)))
-                  (inst cmp amount)
-                  (inst b :ge positive)
-                  (inst neg ndesc amount)
-                  (inst cmp ndesc 31)
-                  (inst b :le done)
-                  (inst ,shift-right-inst result number ndesc)
-                  (inst b done)
-                  (inst ,shift-right-inst result number 31)
-                  (emit-label positive)
-                  ;; The result-type assures us that this shift will
-                  ;; not overflow.
-                  (inst sll result number amount)
-                  (emit-label done)))))
-            (immediate
-             (let ((amount (tn-value amount)))
-               (if (minusp amount)
-                   (let ((amount (min 31 (- amount))))
-                     (inst ,shift-right-inst result number amount))
-                   (inst sll result number amount)))))))))
-  (frob fast-ash/signed=>signed signed-reg signed-num sra)
-  (frob fast-ash/unsigned=>unsigned unsigned-reg unsigned-num srl))
+(define-vop (fast-ash/signed=>signed)
+  (:note "inline ASH")
+  (:args (number :scs (signed-reg) :to :save)
+        (amount :scs (signed-reg immediate) :to :save))
+  (:arg-types signed-num signed-num)
+  (:results (result :scs (signed-reg)))
+  (:result-types signed-num)
+  (:translate ash)
+  (:policy :fast-safe)
+  (:temporary (:sc non-descriptor-reg) ndesc)
+  (:generator 5
+    (sc-case amount
+      (signed-reg
+       (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 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)))
+      (immediate
+       (bug "IMMEDIATE case in ASH VOP; should have been transformed")))))
+
+(define-vop (fast-ash/unsigned=>unsigned)
+  (:note "inline ASH")
+  (:args (number :scs (unsigned-reg) :to :save)
+        (amount :scs (signed-reg immediate) :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
+    (sc-case amount
+      (signed-reg
+       (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)))
+      (immediate
+       (bug "IMMEDIATE case in ASH VOP; should have been transformed")))))
 
 ;; Some special cases where we know we want a left shift.  Just do the
 ;; shift, instead of checking for the sign of the shift.
         (:policy :fast-safe)
         (:generator ,cost
          ;; The result-type assures us that this shift will not
-         ;; overflow. And for fixnum's, the zero bits that get
+         ;; 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)
 
 (in-package "SB!C")
 
-;;; If both arguments and the result are (UNSIGNED-BYTE 32), try to
-;;; come up with a ``better'' multiplication using multiplier
-;;; recoding. There are two different ways the multiplier can be
-;;; recoded. The more obvious is to shift X by the correct amount for
-;;; each bit set in Y and to sum the results. But if there is a string
-;;; of bits that are all set, you can add X shifted by one more then
-;;; the bit position of the first set bit and subtract X shifted by
-;;; the bit position of the last set bit. We can't use this second
-;;; method when the high order bit is bit 31 because shifting by 32
-;;; doesn't work too well.
 (deftransform * ((x y)
                 ((unsigned-byte 32) (constant-arg (unsigned-byte 32)))
                 (unsigned-byte 32))
   "recode as shifts and adds"
-  (let ((y (continuation-value y))
-       (adds 0)
-       (shifts 0)
-       (result nil)
-       (first-one nil))
-    (labels ((tub32 (x) `(truly-the (unsigned-byte 32) ,x))
-            (add (next-factor)
-              (setf result
-                    (tub32
-                     (if result
-                         (progn (incf adds) `(+ ,result ,(tub32 next-factor)))
-                         next-factor)))))
-      (declare (inline add))
-      (dotimes (bitpos 32)
-       (if first-one
-           (when (not (logbitp bitpos y))
-             (add (if (= (1+ first-one) bitpos)
-                      ;; There is only a single bit in the string.
-                      (progn (incf shifts) `(ash x ,first-one))
-                      ;; There are at least two.
-                      (progn
-                        (incf adds)
-                        (incf shifts 2)
-                        `(- ,(tub32 `(ash x ,bitpos))
-                            ,(tub32 `(ash x ,first-one))))))
-             (setf first-one nil))
-           (when (logbitp bitpos y)
-             (setf first-one bitpos))))
-      (when first-one
-       (cond ((= first-one 31))
-             ((= first-one 30) (incf shifts) (add '(ash x 30)))
-             (t
-              (incf shifts 2)
-              (incf adds)
-              (add `(- ,(tub32 '(ash x 31)) ,(tub32 `(ash x ,first-one))))))
-       (incf shifts)
-       (add '(ash x 31))))
-
-    (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)))
+  (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))))
 
 ;; If we can prove that we have a right shift, just do the right shift
 ;; instead of calling the inline ASH which has to check for the
 ;; direction of the shift at run-time.
 (deftransform ash ((num shift) (integer integer))
-  (let ((num-type (continuation-type num))
-       (shift-type (continuation-type shift)))
+  (let ((num-type (lvar-type num))
+       (shift-type (lvar-type shift)))
     ;; Can only handle right shifts
     (unless (csubtypep shift-type (specifier-type '(integer * 0)))
       (give-up-ir1-transform))