0.8.16.16:
[sbcl.git] / src / compiler / srctran.lisp
index 46cbfa8..a5ccd02 100644 (file)
                       #'%unary-truncate-derive-type-aux
                       #'%unary-truncate))
 
+(defoptimizer (%unary-ftruncate derive-type) ((number))
+  (let ((divisor (specifier-type '(integer 1 1))))
+    (one-arg-derive-type number
+                         #'(lambda (n)
+                             (ftruncate-derive-type-quot-aux n divisor nil))
+                         #'%unary-ftruncate)))
+
 ;;; Define optimizers for FLOOR and CEILING.
 (macrolet
     ((def (name q-name r-name)
     (return-from logand-derive-type-aux x))
   (multiple-value-bind (x-len x-pos x-neg) (integer-type-length x)
     (declare (ignore x-pos))
-    (multiple-value-bind (y-len y-pos y-neg) (integer-type-length  y)
+    (multiple-value-bind (y-len y-pos y-neg) (integer-type-length y)
       (declare (ignore y-pos))
       (if (not x-neg)
          ;; X must be positive.
          (if (not y-neg)
              ;; They must both be positive.
-             (cond ((or (null x-len) (null y-len))
+             (cond ((and (null x-len) (null y-len))
                     (specifier-type 'unsigned-byte))
+                   ((null x-len)
+                    (specifier-type `(unsigned-byte* ,y-len)))
+                   ((null y-len)
+                    (specifier-type `(unsigned-byte* ,x-len)))
                    (t
                     (specifier-type `(unsigned-byte* ,(min x-len y-len)))))
              ;; X is positive, but Y might be negative.
                                              (max x-len y-len)
                                              '*))))
        ((or (and (not x-pos) (not y-neg))
-           (and (not y-neg) (not y-pos)))
+           (and (not y-pos) (not x-neg)))
        ;; Either X is negative and Y is positive or vice-versa. The
        ;; result will be negative.
        (specifier-type `(integer ,(if (and x-len y-len)
   (deffrob logior)
   (deffrob logxor))
 
-;;; FIXME: could actually do stuff with SAME-LEAF
 (defoptimizer (logeqv derive-type) ((x y))
   (two-arg-derive-type x y (lambda (x y same-leaf)
                             (lognot-derive-type-aux 
                             (lognot-derive-type-aux
                              (logior-derive-type-aux x y same-leaf)))
                       #'lognor))
-;;; FIXME: use SAME-LEAF instead of ignoring it.
 (defoptimizer (logandc1 derive-type) ((x y))
   (two-arg-derive-type x y (lambda (x y same-leaf)
                             (if same-leaf
         (specifier-type `(integer ,lo-res ,hi-res))))))
 
 (defoptimizer (code-char derive-type) ((code))
-  (specifier-type 'base-char))
+  (let ((type (lvar-type code)))
+    ;; FIXME: unions of integral ranges?  It ought to be easier to do
+    ;; this, given that CHARACTER-SET is basically an integral range
+    ;; type.  -- CSR, 2004-10-04
+    (when (numeric-type-p type)
+      (let* ((lo (numeric-type-low type))
+             (hi (numeric-type-high type))
+             (type (specifier-type `(character-set ((,lo . ,hi))))))
+        (cond
+          ;; KLUDGE: when running on the host, we lose a slight amount
+          ;; of precision so that we don't have to "unparse" types
+          ;; that formally we can't, such as (CHARACTER-SET ((0
+          ;; . 0))).  -- CSR, 2004-10-06
+          #+sb-xc-host
+          ((csubtypep type (specifier-type 'standard-char)) type)
+          #+sb-xc-host
+          ((csubtypep type (specifier-type 'base-char))
+           (specifier-type 'base-char))
+          #+sb-xc-host
+          ((csubtypep type (specifier-type 'extended-char))
+           (specifier-type 'extended-char))
+          (t #+sb-xc-host (specifier-type 'character)
+             #-sb-xc-host type))))))
 
 (defoptimizer (values derive-type) ((&rest values))
   (make-values-type :required (mapcar #'lvar-type values)))
   (let* ((y (lvar-value y))
         (y-abs (abs y))
         (len (1- (integer-length y-abs))))
-    (unless (= y-abs (ash 1 len))
+    (unless (and (> y-abs 0) (= y-abs (ash 1 len)))
       (give-up-ir1-transform))
     (if (minusp y)
        `(- (ash x ,len))
         (let* ((y (lvar-value y))
                (y-abs (abs y))
                (len (1- (integer-length y-abs))))
-          (unless (= y-abs (ash 1 len))
+          (unless (and (> y-abs 0) (= y-abs (ash 1 len)))
             (give-up-ir1-transform))
           (let ((shift (- len))
                 (mask (1- y-abs))
   (let* ((y (lvar-value y))
         (y-abs (abs y))
         (len (1- (integer-length y-abs))))
-    (unless (= y-abs (ash 1 len))
+    (unless (and (> y-abs 0) (= y-abs (ash 1 len)))
       (give-up-ir1-transform))
     (let ((mask (1- y-abs)))
       (if (minusp y)
   (let* ((y (lvar-value y))
         (y-abs (abs y))
         (len (1- (integer-length y-abs))))
-    (unless (= y-abs (ash 1 len))
+    (unless (and (> y-abs 0) (= y-abs (ash 1 len)))
       (give-up-ir1-transform))
     (let* ((shift (- len))
           (mask (1- y-abs)))
   (let* ((y (lvar-value y))
         (y-abs (abs y))
         (len (1- (integer-length y-abs))))
-    (unless (= y-abs (ash 1 len))
+    (unless (and (> y-abs 0) (= y-abs (ash 1 len)))
       (give-up-ir1-transform))
     (let ((mask (1- y-abs)))
       `(if (minusp x)
 \f
 ;;;; character operations
 
-(deftransform char-equal ((a b) (base-char base-char))
+(deftransform char-equal ((a b)
+                          ((character-set ((0 . 255)))
+                           (character-set ((0 . 255)))))
   "open code"
   '(let* ((ac (char-code a))
          (bc (char-code b))
      (or (zerop sum)
         (when (eql sum #x20)
           (let ((sum (+ ac bc)))
-            (and (> sum 161) (< sum 213)))))))
+             (or (and (> sum 161) (< sum 213))
+                 (and (> sum 415) (< sum 461))
+                 (and (> sum 463) (< sum 477))))))))
 
-(deftransform char-upcase ((x) (base-char))
+(deftransform char-upcase ((x) ((character-set ((0 . 255)))))
   "open code"
   '(let ((n-code (char-code x)))
-     (if (and (> n-code #o140) ; Octal 141 is #\a.
-             (< n-code #o173)) ; Octal 172 is #\z.
+     (if (or (and (> n-code #o140)     ; Octal 141 is #\a.
+                  (< n-code #o173))    ; Octal 172 is #\z.
+             (and (> n-code #o337)
+                  (< n-code #o367))
+             (and (> n-code #o367)
+                  (< n-code #o377)))
         (code-char (logxor #x20 n-code))
         x)))
 
-(deftransform char-downcase ((x) (base-char))
+(deftransform char-downcase ((x) ((character-set ((0 . 255)))))
   "open code"
   '(let ((n-code (char-code x)))
-     (if (and (> n-code 64)    ; 65 is #\A.
-             (< n-code 91))    ; 90 is #\Z.
+     (if (or (and (> n-code 64)                ; 65 is #\A.
+                  (< n-code 91))        ; 90 is #\Z.
+             (and (> n-code 191)
+                  (< n-code 215))
+             (and (> n-code 215)
+                  (< n-code 223)))
         (code-char (logxor #x20 n-code))
         x)))
 \f
 ;;; then the result is definitely false.
 (deftransform simple-equality-transform ((x y) * *
                                         :defun-only t)
-  (cond ((same-leaf-ref-p x y)
-        t)
-       ((not (types-equal-or-intersect (lvar-type x)
-                                       (lvar-type y)))
+  (cond
+    ((same-leaf-ref-p x y) t)
+    ((not (types-equal-or-intersect (lvar-type x) (lvar-type y)))
         nil)
-       (t
-        (give-up-ir1-transform))))
+    (t (give-up-ir1-transform))))
 
 (macrolet ((def (x)
              `(%deftransform ',x '(function * *) #'simple-equality-transform)))
   (def eq)
-  (def char=)
-  (def equal))
+  (def char=))
 
-;;; This is similar to SIMPLE-EQUALITY-PREDICATE, except that we also
+;;; This is similar to SIMPLE-EQUALITY-TRANSFORM, except that we also
 ;;; try to convert to a type-specific predicate or EQ:
 ;;; -- If both args are characters, convert to CHAR=. This is better than
 ;;;    just converting to EQ, since CHAR= may have special compilation
        (y-type (lvar-type y))
        (char-type (specifier-type 'character))
        (number-type (specifier-type 'number)))
-    (cond ((same-leaf-ref-p x y)
-          t)
+    (cond
+      ((same-leaf-ref-p x y) t)
          ((not (types-equal-or-intersect x-type y-type))
           nil)
          ((and (csubtypep x-type char-type)
          (t
           (give-up-ir1-transform)))))
 
+;;; similarly to the EQL transform above, we attempt to constant-fold
+;;; or convert to a simpler predicate: mostly we have to be careful
+;;; with strings.
+(deftransform equal ((x y) * *)
+  "convert to simpler equality predicate"
+  (let ((x-type (lvar-type x))
+       (y-type (lvar-type y))
+       (string-type (specifier-type 'string)))
+    (cond
+      ((same-leaf-ref-p x y) t)
+      ((and (csubtypep x-type string-type)
+           (csubtypep y-type string-type))
+       '(string= x y))
+      ((and (or (not (types-equal-or-intersect x-type string-type))
+               (not (types-equal-or-intersect y-type string-type)))
+           (not (types-equal-or-intersect x-type y-type)))
+       nil)
+      (t (give-up-ir1-transform)))))
+
 ;;; Convert to EQL if both args are rational and complexp is specified
 ;;; and the same for both.
 (deftransform = ((x y) * *)
 
 ;;; for compile-time argument count checking.
 ;;;
-;;; FIXME I: this is currently called from DEFTRANSFORMs, the vast
-;;; majority of which are not going to transform the code, but instead
-;;; are going to GIVE-UP-IR1-TRANSFORM unconditionally.  It would be
-;;; nice to make this explicit, maybe by implementing a new
-;;; "optimizer" (say, DEFOPTIMIZER CONSISTENCY-CHECK).
-;;;
 ;;; FIXME II: In some cases, type information could be correlated; for
 ;;; instance, ~{ ... ~} requires a list argument, so if the lvar-type
 ;;; of a corresponding argument is known and does not intersect the
       (let ((nargs (length args)))
        (cond
          ((< nargs min)
-          (compiler-warn "Too few arguments (~D) to ~S ~S: ~
-                           requires at least ~D."
-                         nargs fun string min))
+          (warn 'format-too-few-args-warning
+                :format-control
+                "Too few arguments (~D) to ~S ~S: requires at least ~D."
+                :format-arguments (list nargs fun string min)))
          ((> nargs max)
-          (;; to get warned about probably bogus code at
-           ;; cross-compile time.
-           #+sb-xc-host compiler-warn
-           ;; ANSI saith that too many arguments doesn't cause a
-           ;; run-time error.
-           #-sb-xc-host compiler-style-warn
-           "Too many arguments (~D) to ~S ~S: uses at most ~D."
-           nargs fun string max)))))))
+          (warn 'format-too-many-args-warning
+                :format-control
+                "Too many arguments (~D) to ~S ~S: uses at most ~D."
+                :format-arguments (list nargs fun string max))))))))
 
 (defoptimizer (format optimizer) ((dest control &rest args))
   (when (constant-lvar-p control)
                (let ((nargs (length args)))
                  (cond
                    ((< nargs (min min1 min2))
-                    (compiler-warn "Too few arguments (~D) to ~S ~S ~S: ~
-                                     requires at least ~D."
-                                   nargs 'cerror y x (min min1 min2)))
+                    (warn 'format-too-few-args-warning
+                          :format-control
+                          "Too few arguments (~D) to ~S ~S ~S: ~
+                            requires at least ~D."
+                          :format-arguments
+                          (list nargs 'cerror y x (min min1 min2))))
                    ((> nargs (max max1 max2))
-                    (;; to get warned about probably bogus code at
-                     ;; cross-compile time.
-                     #+sb-xc-host compiler-warn
-                     ;; ANSI saith that too many arguments doesn't cause a
-                     ;; run-time error.
-                     #-sb-xc-host compiler-style-warn
-                     "Too many arguments (~D) to ~S ~S ~S: uses at most ~D."
-                     nargs 'cerror y x (max max1 max2)))))))))))))
+                    (warn 'format-too-many-args-warning
+                          :format-control
+                          "Too many arguments (~D) to ~S ~S ~S: ~
+                            uses at most ~D."
+                          :format-arguments
+                          (list nargs 'cerror y x (max max1 max2))))))))))))))
 
 (defoptimizer (coerce derive-type) ((value type))
   (cond