0.8.4.12:
authorChristophe Rhodes <csr21@cam.ac.uk>
Thu, 9 Oct 2003 11:05:11 +0000 (11:05 +0000)
committerChristophe Rhodes <csr21@cam.ac.uk>
Thu, 9 Oct 2003 11:05:11 +0000 (11:05 +0000)
        I'm not proud of this.

        HEALTH WARNING: this may not work.  It does for me, on Linux/PPC.
If your sourceforge-fu is strong, please try it.
        HEALTH WARNING: this is ugly as sin.  Unexported symbols, special
                assumptions, KLUDGEs thrown in with gay abandon.

        In partial mitigation, it does fix a bug :-)

        Fix for lying-to-the-compiler bug in
                UB32-STRENGTH-REDUCE-CONSTANT-MULTIPLY
        ... turn TRULY-THEs into suitable LOGANDs
                (inefficient in compile-time space; we only need one
                LOGAND wrapping the resulting form)
        ... likewise in x86 OPTIMIZE-MULTIPLY
                (even less efficient: constant mask is first :-)
        but that would be slow at runtime if we just left it there, so
        ... add - as a modular function (that was easy)
        ... add preliminary support for ASH as a modular function
                (for constant right shifts):
        ... delete ASH-RIGHT-[UN]SIGNED from the sparc backend
                (will be restored eventually, fear not, probably more
cross-platformly)
        ... hack in special knowledge about ASH into CUT-TO-WIDTH
        ... ensure that all backends have a suitable VOP for translation
                of new ASH function
        ... (alpha version is 64bit, oh yes)
        ... don't forget out-of-line version (for xc also!)
                (aside: might we not need out-of-line versions of
                other modular functions in the xc?)

12 files changed:
src/code/cross-misc.lisp
src/code/numbers.lisp
src/compiler/alpha/arith.lisp
src/compiler/generic/vm-tran.lisp
src/compiler/hppa/arith.lisp
src/compiler/mips/arith.lisp
src/compiler/ppc/arith.lisp
src/compiler/sparc/arith.lisp
src/compiler/srctran.lisp
src/compiler/x86/arith.lisp
tests/compiler.pure.lisp
version.lisp-expr

index 0d68f25..838c63b 100644 (file)
   (assert (typep array '(simple-array * (*))))
   (values array start end 0))
 
-#!+sparc
-(progn
-  (defun sb!vm::ash-right-signed (num shift)
-    (ash num (- shift)))
-  (defun sb!vm::ash-right-unsigned (num shift)
-    (ash num (- shift))))
+#!-alpha
+(defun sb!vm::ash-left-constant-mod32 (integer amount)
+  (ldb (byte 32 0) (ash integer amount)))
+#!+alpha
+(defun sb!vm::ash-left-constant-mod64 (integer amount)
+  (ldb (byte 64 0) (ash integer amount)))
index 5522134..a9987d6 100644 (file)
                    for pattern = (1- (ash 1 width))
                    do (forms (definition name lambda-list width pattern)))))
   `(progn ,@(forms)))
+
+;;; KLUDGE: these out-of-line definitions can't use the modular
+;;; arithmetic, as that is only (currently) defined for constant
+;;; shifts.  See also the comment in (LOGAND OPTIMIZER) for more
+;;; discussion of this hack.  -- CSR, 2003-10-09
+#!-alpha
+(defun sb!vm::ash-left-constant-mod32 (integer amount)
+  (etypecase integer
+    ((unsigned-byte 32) (ldb (byte 32 0) (ash integer amount)))
+    (fixnum (ldb (byte 32 0) (ash (logand integer #xffffffff) amount)))
+    (bignum (ldb (byte 32 0) (ash (logand integer #xffffffff) amount)))))
+#!+alpha
+(defun sb!vm::ash-left-constant-mod64 (integer amount)
+  (etypecase integer
+    ((unsigned-byte 64) (ldb (byte 64 0) (ash integer amount)))
+    (fixnum (ldb (byte 64 0) (ash (logand integer #xffffffffffffffff) amount)))
+    (bignum (ldb (byte 64 0) 
+                (ash (logand integer #xffffffffffffffff) amount)))))
+    
index c680c61..9eece3c 100644 (file)
   (:generator 1
     (inst not x res)))
 
+(defknown ash-left-constant-mod64 (integer (integer 0)) (unsigned-byte 64)
+  (foldable flushable movable))
+(define-vop (fast-ash-left-constant-mod64/unsigned=>unsigned
+            fast-ash-c/unsigned=>unsigned)
+  (:translate ash-left-constant-mod64))
+
 (macrolet
     ((define-modular-backend (fun &optional constantp)
        (let ((mfun-name (symbolicate fun '-mod64))
              (modvop (symbolicate 'fast- fun '-mod64/unsigned=>unsigned))
-             (modcvop (symbolicate 'fast- fun 'mod64-c/unsigned=>unsigned))
+             (modcvop (symbolicate 'fast- fun '-mod64-c/unsigned=>unsigned))
              (vop (symbolicate 'fast- fun '/unsigned=>unsigned))
              (cvop (symbolicate 'fast- fun '-c/unsigned=>unsigned)))
          `(progn
                 `((define-vop (,modcvop ,cvop)
                     (:translate ,mfun-name))))))))
   (define-modular-backend + t)
+  (define-modular-backend - t)
   (define-modular-backend logxor t)
   (define-modular-backend logeqv t)
   (define-modular-backend logandc1)
index 9365c72..f8e7bda 100644 (file)
   (declare (type (unsigned-byte 32) num))
   (let ((adds 0) (shifts 0)
        (result nil) first-one)
-    (labels ((tub32 (x) `(truly-the (unsigned-byte 32) ,x))
+    (labels ((tub32 (x) `(logand ,x #xffffffff)) ; uses modular arithmetic
             (add (next-factor)
               (setf result
                     (tub32
index d47fc76..c09800b 100644 (file)
   (:translate +-mod32))
 (define-vop (fast-+-mod32-c/unsigned=>unsigned fast-+-c/unsigned=>unsigned)
   (:translate +-mod32))
+(define-modular-fun --mod32 (x y) - 32)
+(define-vop (fast---mod32/unsigned=>unsigned fast--/unsigned=>unsigned)
+  (:translate --mod32))
+(define-vop (fast---mod32-c/unsigned=>unsigned fast---c/unsigned=>unsigned)
+  (:translate --mod32))
+
+(defknown ash-left-constant-mod32 (integer (integer 0)) (unsigned-byte 32)
+  (foldable flushable movable))
+(define-vop (fast-ash-left-constant-mod32/unsigned=>unsigned
+            fast-ash-c/unsigned=>unsigned)
+  (:translate ash-left-constant-mod32))
 
 (define-modular-fun lognot-mod32 (x) lognot 32)
 (define-vop (lognot-mod32/unsigned=>unsigned)
index 1d1ee7e..e38cffe 100644 (file)
   (:translate +-mod32))
 (define-vop (fast-+-mod32-c/unsigned=>unsigned fast-+-c/unsigned=>unsigned)
   (:translate +-mod32))
+(define-modular-fun --mod32 (x y) - 32)
+(define-vop (fast---mod32/unsigned=>unsigned fast--/unsigned=>unsigned)
+  (:translate --mod32))
+(define-vop (fast---mod32-c/unsigned=>unsigned fast---c/unsigned=>unsigned)
+  (:translate --mod32))
+
+(defknown ash-left-constant-mod32 (integer (integer 0)) (unsigned-byte 32)
+  (foldable flushable movable))
+(define-vop (fast-ash-left-constant-mod32/unsigned=>unsigned
+            fast-ash-c/unsigned=>unsigned)
+  (:translate ash-left-constant-mod32))
 
 ;;; logical operations
 (define-modular-fun lognot-mod32 (x) lognot 32)
index 1cfa927..8dab1bb 100644 (file)
 (define-vop (fast-ash/unsigned=>unsigned)
   (:note "inline ASH")
   (:args (number :scs (unsigned-reg) :to :save)
-        (amount :scs (signed-reg immediate)))
+        (amount :scs (signed-reg)))
   (:arg-types (:or 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 3
-    (sc-case amount
-      (signed-reg
-       (let ((positive (gen-label))
-            (done (gen-label)))
-        (inst cmpwi amount 0)
-        (inst neg ndesc amount)
-        (inst bge positive)
-        (inst cmpwi ndesc 31)
-        (inst srw result number ndesc)
-        (inst ble done)
-        (move result zero-tn)
-        (inst b done)
-
-        (emit-label positive)
-        ;; The result-type assures us that this shift will not overflow.
-        (inst slw result number amount)
+  (:generator 5
+    (let ((positive (gen-label))
+         (done (gen-label)))
+      (inst cmpwi amount 0)
+      (inst neg ndesc amount)
+      (inst bge positive)
+      (inst cmpwi ndesc 31)
+      (inst srw result number ndesc)
+      (inst ble done)
+      (move result zero-tn)
+      (inst b done)
+      
+      (emit-label positive)
+      ;; The result-type assures us that this shift will not overflow.
+      (inst slw result number amount)
+      
+      (emit-label done))))
 
-        (emit-label done)))
-      (immediate
-       (let ((amount (tn-value amount)))
-        (cond
-         ((and (minusp amount) (< amount -31)) (move result zero-tn))
-         ((minusp amount) (inst srwi result number (- amount)))
-         (t (inst slwi result number amount))))))))
+(define-vop (fast-ash-c/unsigned=>unsigned)
+  (:note "inline constant ASH")
+  (:args (number :scs (unsigned-reg)))
+  (:info amount)
+  (:arg-types unsigned-num (:constant integer))
+  (:results (result :scs (unsigned-reg)))
+  (:result-types unsigned-num)
+  (:translate ash)
+  (:policy :fast-safe)
+  (:generator 4
+    (cond
+      ((and (minusp amount) (< amount -31)) (move result zero-tn))
+      ((minusp amount) (inst srwi result number (- amount)))
+      (t (inst slwi result number amount)))))
 
 (define-vop (fast-ash/signed=>signed)
   (:note "inline ASH")
   (:generator 1
     (inst not res x)))
 
+(defknown ash-left-constant-mod32 (integer (integer 0)) (unsigned-byte 32)
+  (foldable flushable movable))
+(define-vop (fast-ash-left-constant-mod32/unsigned=>unsigned
+            fast-ash-c/unsigned=>unsigned)
+  (:translate ash-left-constant-mod32))
+
 (macrolet 
     ((define-modular-backend (fun &optional constantp)
        (let ((mfun-name (symbolicate fun '-mod32))
                `((define-vop (,modcvop ,cvop)
                    (:translate ,mfun-name))))))))
   (define-modular-backend + t)
+  (define-modular-backend - t)
   (define-modular-backend logxor t)
   (define-modular-backend logeqv)
   (define-modular-backend lognand)
index 1887090..65f35be 100644 (file)
 (define-vop (fast-ash/signed=>signed)
   (:note "inline ASH")
   (:args (number :scs (signed-reg) :to :save)
-        (amount :scs (signed-reg immediate) :to :save))
+        (amount :scs (signed-reg) :to :save))
   (:arg-types signed-num signed-num)
   (:results (result :scs (signed-reg)))
   (:result-types signed-num)
   (: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")))))
+    (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))))
+
+(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 immediate) :to :save))
+        (amount :scs (signed-reg) :to :save))
   (:arg-types unsigned-num signed-num)
   (:results (result :scs (unsigned-reg)))
   (:result-types unsigned-num)
   (: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")))))
+    (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.
            (inst sll result number amount))
           (immediate
            (let ((amount (tn-value amount)))
-             (assert (>= amount 0))
+             (aver (>= amount 0))
              (inst sll result number amount))))))))
   (frob fast-ash-left/signed=>signed signed-reg signed-num signed-reg 3)
   (frob fast-ash-left/fixnum=>fixnum any-reg tagged-num any-reg 2)
   (frob fast-ash-left/unsigned=>unsigned unsigned-reg unsigned-num unsigned-reg 3))
 
-(defknown ash-right-signed ((signed-byte #.sb!vm:n-word-bits)
-                           (and fixnum unsigned-byte))
-  (signed-byte #.sb!vm:n-word-bits)
-  (movable foldable flushable))
-
-(defknown ash-right-unsigned ((unsigned-byte #.sb!vm:n-word-bits)
-                             (and fixnum unsigned-byte))
-  (unsigned-byte #.sb!vm:n-word-bits)
-  (movable foldable flushable))
-
-;; Some special cases where we want a right shift.  Just do the shift.
-;; (Needs appropriate deftransforms to call these, though.)
-
-(macrolet
-    ((frob (trans name sc-type type shift-inst cost)
-       `(define-vop (,name)
-        (:note "inline right ASH")
-        (:translate ,trans)
-        (:args (number :scs (,sc-type))
-               (amount :scs (signed-reg unsigned-reg immediate)))
-        (:arg-types ,type positive-fixnum)
-        (:results (result :scs (,sc-type)))
-        (:result-types ,type)
-        (:policy :fast-safe)
-        (:generator ,cost
-           (sc-case amount
-            ((signed-reg unsigned-reg)
-               (inst ,shift-inst result number amount))
-            (immediate
-             (let ((amt (tn-value amount)))
-               (inst ,shift-inst result number amt))))))))
-  (frob ash-right-signed fast-ash-right/signed=>signed
-       signed-reg signed-num sra 3)
-  (frob ash-right-unsigned fast-ash-right/unsigned=>unsigned
-       unsigned-reg unsigned-num srl 3))
-
-(define-vop (fast-ash-right/fixnum=>fixnum)
-    (:note "inline right ASH")
-  (:translate ash-right-signed)
-  (:args (number :scs (any-reg))
-        (amount :scs (signed-reg unsigned-reg immediate)))
-  (:arg-types tagged-num positive-fixnum)
-  (:results (result :scs (any-reg)))
-  (:result-types tagged-num)
-  (:temporary (:sc non-descriptor-reg :target result) temp)
-  (:policy :fast-safe)
-  (:generator 2
-    ;; Shift the fixnum right by the desired amount.  Then zap out the
-    ;; 2 LSBs to make it a fixnum again.  (Those bits are junk.)
-    (sc-case amount
-      ((signed-reg unsigned-reg)
-       (inst sra temp number amount))
-      (immediate
-       (inst sra temp number (tn-value amount))))
-    (inst andn result temp fixnum-tag-mask)))
-    
-
-
 \f
 (define-vop (signed-byte-32-len)
   (:translate integer-length)
     ((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))
+             (modcvop (symbolicate 'fast- fun '-mod32-c/unsigned=>unsigned))
              (vop (symbolicate 'fast- fun '/unsigned=>unsigned))
              (cvop (symbolicate 'fast- fun '-c/unsigned=>unsigned)))
          `(progn
                `((define-vop (,modcvop ,cvop)
                    (:translate ,mfun-name))))))))
   (define-modular-backend + t)
+  (define-modular-backend - t)
   (define-modular-backend logxor t)
   (define-modular-backend logeqv t)
   (define-modular-backend logandc1)
   `(lognot (logand ,x ,y)))
 (define-source-transform lognor (x y)
   `(lognot (logior ,x ,y)))
+
+(defknown ash-left-constant-mod32 (integer (integer 0)) (unsigned-byte 32)
+  (foldable flushable movable))
+(define-vop (fast-ash-left-constant-mod32/unsigned=>unsigned
+            fast-ash-c/unsigned=>unsigned)
+  (:translate ash-left-constant-mod32))
 \f
 ;;;; Binary conditional VOPs:
 
 
 \f
 ;;;; 32-bit logical operations
-
 (define-vop (merge-bits)
   (:translate merge-bits)
   (:args (shift :scs (signed-reg unsigned-reg))
     (inst srl r num amount)))
 \f
 ;;;; Bignum stuff.
-
 (define-vop (bignum-length get-header-data)
   (:translate sb!bignum::%bignum-length)
   (:policy :fast-safe))
     (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)
       (signed-reg
        (move res digit)))))
 
-
 (define-vop (digit-ashr)
   (:translate sb!bignum::%ashr)
   (:policy :fast-safe)
 (define-static-fun two-arg-eqv (x y) :translate logeqv)
 
 \f
-;; Need these so constant folding works with the deftransform.
-
-;; FIXME KLUDGE ew yuk.
-#-sb-xc-host
-(progn
-  (defun ash-right-signed (num shift)
-    (ash-right-signed num shift))
-
-  (defun ash-right-unsigned (num shuft)
-    (ash-right-unsigned num shift)))
-
 (in-package "SB!C")
 
 (deftransform * ((x y)
         (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 (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))
-
-    ;; If we can prove the shift is so large that all bits are shifted
-    ;; out, return the appropriate constant.  If the shift is small
-    ;; enough, call the VOP.  Otherwise, check for the shift size and
-    ;; do the appropriate thing.  (Hmm, could we just leave the IF
-    ;; s-expr and depend on other parts of the compiler to delete the
-    ;; unreachable parts, if any?)
-    (cond ((csubtypep num-type (specifier-type '(signed-byte #.sb!vm:n-word-bits)))
-          ;; A right shift by 31 is the same as a right shift by
-          ;; larger amount.  We get just the sign.
-          (if (csubtypep shift-type (specifier-type '(integer #.(- 1 sb!vm:n-word-bits) 0)))
-              ;; FIXME: ash-right-{un,}signed package problems
-              `(sb!vm::ash-right-signed num (- shift))
-              `(sb!vm::ash-right-signed num (min (- shift) #.(1- sb!vm:n-word-bits)))))
-         ((csubtypep num-type (specifier-type '(unsigned-byte #.sb!vm:n-word-bits)))
-          (if (csubtypep shift-type (specifier-type '(integer #.(- 1 sb!vm:n-word-bits) 0)))
-              `(sb!vm::ash-right-unsigned num (- shift))
-              `(if (<= shift #.(- sb!vm:n-word-bits))
-                0
-                (sb!vm::ash-right-unsigned num (- shift)))))
-         (t
-          (give-up-ir1-transform)))))
-
index fe7f950..8df9c25 100644 (file)
                       (modular-fun (find-modular-version fun-name width))
                       (name (and (modular-fun-info-p modular-fun)
                                  (modular-fun-info-name modular-fun))))
-                 (when (and modular-fun
-                            (not (and (eq name 'logand)
-                                      (csubtypep
-                                       (single-value-type (node-derived-type node))
-                                       (specifier-type `(unsigned-byte ,width))))))
-                   (unless (eq modular-fun :good)
-                     (setq did-something t)
-                     (change-ref-leaf
-                        fun-ref
-                        (find-free-fun name "in a strange place"))
-                       (setf (combination-kind node) :full))
-                   (dolist (arg (basic-combination-args node))
-                     (when (cut-lvar arg)
-                       (setq did-something t)))
-                   (when did-something
-                     (reoptimize-node node fun-name))
-                   did-something))))
+                (cond
+                  ((and modular-fun
+                        (not (and (eq name 'logand)
+                                  (csubtypep
+                                   (single-value-type (node-derived-type node))
+                                   (specifier-type `(unsigned-byte ,width))))))
+                   (unless (eq modular-fun :good)
+                     (setq did-something t)
+                     (change-ref-leaf
+                      fun-ref
+                      (find-free-fun name "in a strange place"))
+                     (setf (combination-kind node) :full))
+                   (dolist (arg (basic-combination-args node))
+                     (when (cut-lvar arg)
+                       (setq did-something t)))
+                   (when did-something
+                     (reoptimize-node node fun-name))
+                   did-something)
+                  ;; FIXME: This clause is a workaround for a fairly
+                  ;; critical bug.  Prior to this, strength reduction
+                  ;; of constant (unsigned-byte 32) multiplication
+                  ;; achieved modular arithmetic by lying to the
+                  ;; compiler with TRULY-THE.  Since we now have an
+                  ;; understanding of modular arithmetic, we can stop
+                  ;; lying to the compiler, at the cost of
+                  ;; uglification of this code.  Probably we want to
+                  ;; generalize the modular arithmetic mechanism to
+                  ;; be able to deal with more complex operands (ASH,
+                  ;; EXPT, ...?)  -- CSR, 2003-10-09
+                  ((and 
+                    (eq fun-name 'ash)
+                    ;; FIXME: only constants for now, but this
+                    ;; complicates implementation of the out of line
+                    ;; version of modular ASH.  -- CSR, 2003-10-09
+                    (constant-lvar-p (second (basic-combination-args node)))
+                    (> (lvar-value (second (basic-combination-args node))) 0))
+                   (setq did-something t)
+                   (change-ref-leaf
+                    fun-ref
+                    (find-free-fun 
+                     #!-alpha 'sb!vm::ash-left-constant-mod32
+                     #!+alpha 'sb!vm::ash-left-constant-mod64
+                     "in a strange place"))
+                   (setf (combination-kind node) :full)
+                   (cut-lvar (first (basic-combination-args node)))
+                   (reoptimize-node node 'ash))))))
            (cut-lvar (lvar &aux did-something)
              (do-uses (node lvar)
                (when (cut-node node)
index af7da99..2da36e3 100644 (file)
                 ((< amount -31) (inst xor result result))
                 (t (inst shr result (- amount))))))))
 
-(define-vop (fast-ash-left/signed)
+(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)
     (move ecx amount)
     (inst shl result :cl)))
 
-(define-vop (fast-ash-left/unsigned)
+(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)
   (:translate +-mod32))
 (define-vop (fast-+-mod32-c/unsigned=>unsigned fast-+-c/unsigned=>unsigned)
   (:translate +-mod32))
+(define-modular-fun --mod32 (x y) - 32)
+(define-vop (fast---mod32/unsigned=>unsigned fast--/unsigned=>unsigned)
+  (:translate --mod32))
+(define-vop (fast---mod32-c/unsigned=>unsigned fast---c/unsigned=>unsigned)
+  (:translate --mod32))
+
+(defknown ash-left-constant-mod32 (integer (integer 0)) (unsigned-byte 32)
+  (foldable flushable movable))
+(define-vop (fast-ash-left-constant-mod32/unsigned=>unsigned
+            fast-ash-c/unsigned=>unsigned)
+  (:translate ash-left-constant-mod32))
 
 ;;; logical operations
 (define-modular-fun lognot-mod32 (x) lognot 32)
     (0
      (let ((tmp (min 3 (aref condensed 1))))
        (decf (aref condensed 1) tmp)
-       `(truly-the (unsigned-byte 32)
+       `(logand #xffffffff
         (%lea ,arg
               ,(decompose-multiplication
                 arg (ash (1- num) (- tmp)) (1- n-bits) (subseq condensed 1))
     ((1 2 3)
      (let ((r0 (aref condensed 0)))
        (incf (aref condensed 1) r0)
-       `(truly-the (unsigned-byte 32)
+       `(logand #xffffffff
         (%lea ,(decompose-multiplication
                 arg (- num (ash 1 r0)) (1- n-bits) (subseq condensed 1))
               ,arg
               ,(ash 1 r0) 0))))
     (t (let ((r0 (aref condensed 0)))
         (setf (aref condensed 0) 0)
-        `(truly-the (unsigned-byte 32)
+        `(logand #xffffffff
           (ash ,(decompose-multiplication
                  arg (ash num (- r0)) n-bits condensed)
                ,r0))))))
     ((= n-bits 0) 0)
     ((= num 1) arg)
     ((= n-bits 1)
-     `(truly-the (unsigned-byte 32) (ash ,arg ,(1- (integer-length num)))))
+     `(logand #xffffffff (ash ,arg ,(1- (integer-length num)))))
     ((let ((max 0) (end 0))
        (loop for i from 2 to (length condensed)
             for j = (reduce #'+ (subseq condensed 0 i))
           (let ((n2 (+ (ash 1 (1+ j))
                        (ash (ldb (byte (- 32 (1+ j)) (1+ j)) num) (1+ j))))
                 (n1 (1+ (ldb (byte (1+ j) 0) (lognot num)))))
-          `(truly-the (unsigned-byte 32)
+          `(logand #xffffffff
             (- ,(optimize-multiply arg n2) ,(optimize-multiply arg n1))))))))
     ((dolist (i '(9 5 3))
        (when (integerp (/ num i))
         (when (< (logcount (/ num i)) (logcount num))
           (let ((x (gensym)))
             (return `(let ((,x ,(optimize-multiply arg (/ num i))))
-                      (truly-the (unsigned-byte 32)
+                      (logand #xffffffff
                        (%lea ,x ,x (1- ,i) 0)))))))))
     (t (basic-decompose-multiplication arg num n-bits condensed))))
           
index 9525cca..ad1853d 100644 (file)
                    (wum #'bbfn "hc3" (list)))
                  r3533)))
 (compile nil '(lambda () (flet ((%f () (unwind-protect nil))) nil)))
+
+;;; the strength reduction of constant multiplication used (before
+;;; sbcl-0.8.4.x) to lie to the compiler.  This meant that, under
+;;; certain circumstances, the compiler would derive that a perfectly
+;;; reasonable multiplication never returned, causing chaos.  Fixed by
+;;; explicitly doing modular arithmetic, and relying on the backends
+;;; being smart.
+(assert (= (funcall 
+           (compile nil 
+                    '(lambda (x)
+                       (declare (type (integer 178956970 178956970) x)
+                                (optimize speed)) 
+                       (* x 24)))
+           178956970)
+          4294967280))
index 0e72f46..cfce20d 100644 (file)
@@ -17,4 +17,4 @@
 ;;; checkins which aren't released. (And occasionally for internal
 ;;; versions, especially for internal versions off the main CVS
 ;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"0.8.4.11"
+"0.8.4.12"