1.0.3.23: fix sb-posix timeval struct
[sbcl.git] / src / compiler / srctran.lisp
index 81c82d2..30c0c61 100644 (file)
 ;;; 1] and Y = [1, 2] to determine intersection.
 (defun interval-intersect-p (x y &optional closed-intervals-p)
   (declare (type interval x y))
-  (multiple-value-bind (intersect diff)
-      (interval-intersection/difference (if closed-intervals-p
-                                            (interval-closure x)
-                                            x)
-                                        (if closed-intervals-p
-                                            (interval-closure y)
-                                            y))
-    (declare (ignore diff))
-    intersect))
+  (and (interval-intersection/difference (if closed-intervals-p
+                                             (interval-closure x)
+                                             x)
+                                         (if closed-intervals-p
+                                             (interval-closure y)
+                                             y))
+       t))
 
 ;;; Are the two intervals adjacent?  That is, is there a number
 ;;; between the two intervals that is not an element of either
            (if (listp p)
                (first p)
                (list p)))
-         (test-number (p int)
+         (test-number (p int bound)
            ;; Test whether P is in the interval.
-           (when (interval-contains-p (type-bound-number p)
-                                      (interval-closure int))
-             (let ((lo (interval-low int))
-                   (hi (interval-high int)))
+           (let ((pn (type-bound-number p)))
+             (when (interval-contains-p pn (interval-closure int))
                ;; Check for endpoints.
-               (cond ((and lo (= (type-bound-number p) (type-bound-number lo)))
-                      (not (and (consp p) (numberp lo))))
-                     ((and hi (= (type-bound-number p) (type-bound-number hi)))
-                      (not (and (numberp p) (consp hi))))
-                     (t t)))))
+               (let* ((lo (interval-low int))
+                      (hi (interval-high int))
+                      (lon (type-bound-number lo))
+                      (hin (type-bound-number hi)))
+                 (cond
+                   ;; Interval may be a point.
+                   ((and lon hin (= lon hin pn))
+                    (and (numberp p) (numberp lo) (numberp hi)))
+                   ;; Point matches the low end.
+                   ;; [P] [P,?} => TRUE     [P] (P,?} => FALSE
+                   ;; (P  [P,?} => TRUE      P) [P,?} => FALSE
+                   ;; (P  (P,?} => TRUE      P) (P,?} => FALSE
+                   ((and lon (= pn lon))
+                    (or (and (numberp p) (numberp lo))
+                        (and (consp p) (eq :low bound))))
+                   ;; [P] {?,P] => TRUE     [P] {?,P) => FALSE
+                   ;;  P) {?,P] => TRUE     (P  {?,P] => FALSE
+                   ;;  P) {?,P) => TRUE     (P  {?,P) => FALSE
+                   ((and hin (= pn hin))
+                    (or (and (numberp p) (numberp hi))
+                        (and (consp p) (eq :high bound))))
+                   ;; Not an endpoint, all is well.
+                   (t
+                    t))))))
          (test-lower-bound (p int)
            ;; P is a lower bound of an interval.
            (if p
-               (test-number p int)
+               (test-number p int :low)
                (not (interval-bounded-p int 'below))))
          (test-upper-bound (p int)
            ;; P is an upper bound of an interval.
            (if p
-               (test-number p int)
+               (test-number p int :high)
                (not (interval-bounded-p int 'above)))))
       (let ((x-lo-in-y (test-lower-bound x-lo y))
             (x-hi-in-y (test-upper-bound x-hi y))
     (>= (type-bound-number (interval-low x))
         (type-bound-number (interval-high y)))))
 
+;;; Return T if X = Y.
+(defun interval-= (x y)
+  (declare (type interval x y))
+  (and (interval-bounded-p x 'both)
+       (interval-bounded-p y 'both)
+       (flet ((bound (v)
+                (if (numberp v)
+                    v
+                    ;; Open intervals cannot be =
+                    (return-from interval-= nil))))
+         ;; Both intervals refer to the same point
+         (= (bound (interval-high x)) (bound (interval-low x))
+            (bound (interval-high y)) (bound (interval-low y))))))
+
+;;; Return T if X /= Y
+(defun interval-/= (x y)
+  (not (interval-intersect-p x y)))
+
 ;;; Return an interval that is the absolute value of X. Thus, if
 ;;; X = [-1 10], the result is [0, 10].
 (defun interval-abs (x)
 
 ;;; Convert to EQL if both args are rational and complexp is specified
 ;;; and the same for both.
-(deftransform = ((x y) * *)
+(deftransform = ((x y) (number number) *)
   "open code"
   (let ((x-type (lvar-type x))
         (y-type (lvar-type y)))
-    (if (and (csubtypep x-type (specifier-type 'number))
-             (csubtypep y-type (specifier-type 'number)))
-        (cond ((or (and (csubtypep x-type (specifier-type 'float))
-                        (csubtypep y-type (specifier-type 'float)))
-                   (and (csubtypep x-type (specifier-type '(complex float)))
-                        (csubtypep y-type (specifier-type '(complex float)))))
-               ;; They are both floats. Leave as = so that -0.0 is
-               ;; handled correctly.
-               (give-up-ir1-transform))
-              ((or (and (csubtypep x-type (specifier-type 'rational))
-                        (csubtypep y-type (specifier-type 'rational)))
-                   (and (csubtypep x-type
-                                   (specifier-type '(complex rational)))
-                        (csubtypep y-type
-                                   (specifier-type '(complex rational)))))
-               ;; They are both rationals and complexp is the same.
-               ;; Convert to EQL.
-               '(eql x y))
-              (t
-               (give-up-ir1-transform
-                "The operands might not be the same type.")))
-        (give-up-ir1-transform
-         "The operands might not be the same type."))))
-
-;;; If LVAR's type is a numeric type, then return the type, otherwise
-;;; GIVE-UP-IR1-TRANSFORM.
-(defun numeric-type-or-lose (lvar)
-  (declare (type lvar lvar))
-  (let ((res (lvar-type lvar)))
-    (unless (numeric-type-p res) (give-up-ir1-transform))
-    res))
+    (cond ((or (and (csubtypep x-type (specifier-type 'float))
+                    (csubtypep y-type (specifier-type 'float)))
+               (and (csubtypep x-type (specifier-type '(complex float)))
+                    (csubtypep y-type (specifier-type '(complex float)))))
+           ;; They are both floats. Leave as = so that -0.0 is
+           ;; handled correctly.
+           (give-up-ir1-transform))
+          ((or (and (csubtypep x-type (specifier-type 'rational))
+                    (csubtypep y-type (specifier-type 'rational)))
+               (and (csubtypep x-type
+                               (specifier-type '(complex rational)))
+                    (csubtypep y-type
+                               (specifier-type '(complex rational)))))
+           ;; They are both rationals and complexp is the same.
+           ;; Convert to EQL.
+           '(eql x y))
+          (t
+           (give-up-ir1-transform
+            "The operands might not be the same type.")))))
+
+(labels ((maybe-float-lvar-p (lvar)
+           (neq *empty-type* (type-intersection (specifier-type 'float)
+                                                (lvar-type lvar))))
+         (maybe-invert (op inverted x y)
+           ;; Don't invert if either argument can be a float (NaNs)
+           (if (or (maybe-float-lvar-p x) (maybe-float-lvar-p y))
+               `(or (,op x y) (= x y))
+               `(if (,inverted x y) nil t))))
+  (deftransform >= ((x y) (number number) *)
+    "invert or open code"
+    (maybe-invert '> '< x y))
+  (deftransform <= ((x y) (number number) *)
+    "invert or open code"
+    (maybe-invert '< '> x y)))
 
 ;;; See whether we can statically determine (< X Y) using type
 ;;; information. If X's high bound is < Y's low, then X < Y.
 ;;; NIL). If not, at least make sure any constant arg is second.
 (macrolet ((def (name inverse reflexive-p surely-true surely-false)
              `(deftransform ,name ((x y))
+                "optimize using intervals"
                 (if (same-leaf-ref-p x y)
                     ,reflexive-p
                     (let ((ix (or (type-approximate-interval (lvar-type x))
                              `(,',inverse y x))
                             (t
                              (give-up-ir1-transform))))))))
+  (def = = t (interval-= ix iy) (interval-/= ix iy))
+  (def /= /= nil (interval-/= ix iy) (interval-= ix iy))
   (def < > nil (interval-< ix iy) (interval->= ix iy))
   (def > < nil (interval-< iy ix) (interval->= iy ix))
   (def <= >= t (interval->= iy ix) (interval-< iy ix))
 (define-source-transform = (&rest args) (multi-compare '= args nil 'number))
 (define-source-transform < (&rest args) (multi-compare '< args nil 'real))
 (define-source-transform > (&rest args) (multi-compare '> args nil 'real))
-(define-source-transform <= (&rest args) (multi-compare '> args t 'real))
-(define-source-transform >= (&rest args) (multi-compare '< args t 'real))
+;;; We cannot do the inversion for >= and <= here, since both
+;;;   (< NaN X) and (> NaN X)
+;;; are false, and we don't have type-inforation available yet. The
+;;; deftransforms for two-argument versions of >= and <= takes care of
+;;; the inversion to > and < when possible.
+(define-source-transform <= (&rest args) (multi-compare '<= args nil 'real))
+(define-source-transform >= (&rest args) (multi-compare '>= args nil 'real))
 
 (define-source-transform char= (&rest args) (multi-compare 'char= args nil
                                                            'character))