1.0.2.1: DATA-VECTOR-{REF,SET}-WITH-OFFSET for the x86
[sbcl.git] / src / compiler / ir1opt.lisp
index 4944949..314bb79 100644 (file)
 ;;; appropriate.)
 ;;;
 ;;; We call MAYBE-CONVERT-TAIL-LOCAL-CALL on each local non-MV
-;;; combination, which may change the succesor of the call to be the
+;;; combination, which may change the successor of the call to be the
 ;;; called function, and if so, checks if the call can become an
 ;;; assignment. If we convert to an assignment, we abort, since the
 ;;; RETURN has been deleted.
 #!+sb-show
 (defvar *show-transforms-p* nil)
 
+(defun check-important-result (node info)
+  (when (and (null (node-lvar node))
+             (ir1-attributep (fun-info-attributes info) important-result))
+    (let ((*compiler-error-context* node))
+      (compiler-style-warn
+       "The return value of ~A should not be discarded."
+       (lvar-fun-name (basic-combination-fun node))))))
+
 ;;; Do IR1 optimizations on a COMBINATION node.
 (declaim (ftype (function (combination) (values)) ir1-optimize-combination))
 (defun ir1-optimize-combination (node)
          (when arg
            (setf (lvar-reoptimize arg) nil)))
        (when info
+         (check-important-result node info)
          (let ((fun (fun-info-destroyed-constant-args info)))
            (when fun
              (let ((destroyed-constant-args (funcall fun args)))
                (when destroyed-constant-args
-                 (warn 'constant-modified
-                       :fun-name (lvar-fun-name
-                                  (basic-combination-fun node)))
-                 (setf (basic-combination-kind node) :error)
-                 (return-from ir1-optimize-combination)))))
+                 (let ((*compiler-error-context* node))
+                   (warn 'constant-modified
+                         :fun-name (lvar-fun-name
+                                    (basic-combination-fun node)))
+                   (setf (basic-combination-kind node) :error)
+                   (return-from ir1-optimize-combination))))))
          (let ((fun (fun-info-derive-type info)))
            (when fun
              (let ((res (funcall fun node)))
        (dolist (arg args)
          (when arg
            (setf (lvar-reoptimize arg) nil)))
-
+       (check-important-result node info)
        (let ((fun (fun-info-destroyed-constant-args info)))
          (when fun
            (let ((destroyed-constant-args (funcall fun args)))
              (when destroyed-constant-args
-               (warn 'constant-modified
-                     :fun-name (lvar-fun-name
-                                (basic-combination-fun node)))
+               (let ((*compiler-error-context* node))
+                 (warn 'constant-modified
+                       :fun-name (lvar-fun-name
+                                  (basic-combination-fun node)))
                  (setf (basic-combination-kind node) :error)
-                 (return-from ir1-optimize-combination)))))
+                 (return-from ir1-optimize-combination))))))
 
        (let ((attr (fun-info-attributes info)))
          (when (and (ir1-attributep attr foldable)
 
        (let ((fun (fun-info-optimizer info)))
          (unless (and fun (funcall fun node))
-           (dolist (x (fun-info-transforms info))
-             #!+sb-show
-             (when *show-transforms-p*
-               (let* ((lvar (basic-combination-fun node))
-                      (fname (lvar-fun-name lvar t)))
-                 (/show "trying transform" x (transform-function x) "for" fname)))
-             (unless (ir1-transform node x)
-               #!+sb-show
-               (when *show-transforms-p*
-                 (/show "quitting because IR1-TRANSFORM result was NIL"))
-               (return))))))))
+           ;; First give the VM a peek at the call
+           (multiple-value-bind (style transform)
+               (combination-implementation-style node)
+             (ecase style
+               (:direct
+                ;; The VM knows how to handle this.
+                )
+               (:transform
+                ;; The VM mostly knows how to handle this.  We need
+                ;; to massage the call slightly, though.
+                (transform-call node transform (combination-fun-source-name node)))
+               (:default
+                ;; Let transforms have a crack at it.
+                (dolist (x (fun-info-transforms info))
+                  #!+sb-show
+                  (when *show-transforms-p*
+                    (let* ((lvar (basic-combination-fun node))
+                           (fname (lvar-fun-name lvar t)))
+                      (/show "trying transform" x (transform-function x) "for" fname)))
+                  (unless (ir1-transform node x)
+                    #!+sb-show
+                    (when *show-transforms-p*
+                      (/show "quitting because IR1-TRANSFORM result was NIL"))
+                    (return)))))))))))
 
   (values))
 
              ;; called semi-inlining? A more descriptive name would
              ;; be nice. -- WHN 2002-01-07
              (frob ()
-               (let ((res (let ((*allow-instrumenting* t))
-                            (ir1-convert-lambda-for-defun
-                             (defined-fun-inline-expansion leaf)
-                             leaf t
-                             #'ir1-convert-inline-lambda))))
+               (let* ((name (leaf-source-name leaf))
+                      (res (ir1-convert-inline-expansion
+                            name
+                            (defined-fun-inline-expansion leaf)
+                            leaf
+                            inlinep
+                            (info :function :info name))))
+                 ;; allow backward references to this function from
+                 ;; following top level forms
                  (setf (defined-fun-functional leaf) res)
                  (change-ref-leaf ref res))))
         (if ir1-converting-not-optimizing-p
                                 (block-next (node-block call)))
       (let ((new-fun (ir1-convert-inline-lambda
                       res
-                      :debug-name (debug-name 'lambda-inlined source-name)))
+                      :debug-name (debug-name 'lambda-inlined source-name)
+                      :system-lambda t))
             (ref (lvar-use (combination-fun call))))
         (change-ref-leaf ref new-fun)
         (setf (combination-kind call) :full)
+        ;; The internal variables of a transform are not going to be
+        ;; interesting to the debugger, so there's no sense in
+        ;; suppressing the substitution of variables with only one use
+        ;; (the extra variables can slow down constraint propagation).
+        (setf (combination-lexenv call)
+              (make-lexenv :default (combination-lexenv call)
+                           :policy (process-optimize-decl
+                                    '(optimize
+                                      (preserve-single-use-debug-variables 0))
+                                    (lexenv-policy
+                                     (combination-lexenv call)))))
         (locall-analyze-component *current-component*))))
   (values))
 
                       (eq (combination-kind set-use) :known)
                       (fun-info-p (combination-fun-info set-use))
                       (not (node-to-be-deleted-p set-use))
-                      (eq (combination-fun-source-name set-use) '+))
-               :exit-if-null)
+                      (or (eq (combination-fun-source-name set-use) '+)
+                          (eq (combination-fun-source-name set-use) '-)))
+              :exit-if-null)
+             (minusp (eq (combination-fun-source-name set-use) '-))
              (+-args (basic-combination-args set-use))
              (() (and (proper-list-of-length-p +-args 2 2)
                       (let ((first (principal-lvar-use
                                     (first +-args))))
                         (and (ref-p first)
                              (eq (ref-leaf first) var))))
-               :exit-if-null)
+              :exit-if-null)
              (step-type (lvar-type (second +-args)))
              (set-type (lvar-type (set-value set))))
     (when (and (numeric-type-p initial-type)
                (numeric-type-p step-type)
-               (numeric-type-equal initial-type step-type))
+               (or (numeric-type-equal initial-type step-type)
+                   ;; Detect cases like (LOOP FOR 1.0 to 5.0 ...), where
+                   ;; the initial and the step are of different types,
+                   ;; and the step is less contagious.
+                   (numeric-type-equal initial-type
+                                       (numeric-contagion initial-type
+                                                          step-type))))
       (labels ((leftmost (x y cmp cmp=)
                  (cond ((eq x nil) nil)
                        ((eq y nil) nil)
                        (t (if (funcall cmp x y) x y))))
                (max* (x y) (leftmost x y #'> #'>=))
                (min* (x y) (leftmost x y #'< #'<=)))
-        (declare (inline compare))
         (multiple-value-bind (low high)
-            (cond ((csubtypep step-type (specifier-type '(real 0 *)))
-                   (values (numeric-type-low initial-type)
-                           (when (and (numeric-type-p set-type)
-                                      (numeric-type-equal set-type initial-type))
-                             (max* (numeric-type-high initial-type)
-                                   (numeric-type-high set-type)))))
-                  ((csubtypep step-type (specifier-type '(real * 0)))
-                   (values (when (and (numeric-type-p set-type)
-                                      (numeric-type-equal set-type initial-type))
-                             (min* (numeric-type-low initial-type)
-                                   (numeric-type-low set-type)))
-                           (numeric-type-high initial-type)))
-                  (t
-                   (values nil nil)))
+            (let ((step-type-non-negative (csubtypep step-type (specifier-type
+                                                                '(real 0 *))))
+                  (step-type-non-positive (csubtypep step-type (specifier-type
+                                                                '(real * 0)))))
+              (cond ((or (and step-type-non-negative (not minusp))
+                         (and step-type-non-positive minusp))
+                     (values (numeric-type-low initial-type)
+                             (when (and (numeric-type-p set-type)
+                                        (numeric-type-equal set-type initial-type))
+                               (max* (numeric-type-high initial-type)
+                                     (numeric-type-high set-type)))))
+                    ((or (and step-type-non-positive (not minusp))
+                         (and step-type-non-negative minusp))
+                     (values (when (and (numeric-type-p set-type)
+                                        (numeric-type-equal set-type initial-type))
+                               (min* (numeric-type-low initial-type)
+                                     (numeric-type-low set-type)))
+                             (numeric-type-high initial-type)))
+                    (t
+                     (values nil nil))))
           (modified-numeric-type initial-type
                                  :low low
                                  :high high
                            leaf var)))
                  t)))))
         ((and (null (rest (leaf-refs var)))
+              ;; Don't substitute single-ref variables on high-debug /
+              ;; low speed, to improve the debugging experience.
+              (policy call (< preserve-single-use-debug-variables 3))
               (substitute-single-use-lvar arg var)))
         (t
          (propagate-to-refs var (lvar-type arg))))))
 
 ;;; TODO:
 ;;; - CAST chains;
+(defun delete-cast (cast)
+  (declare (type cast cast))
+  (let ((value (cast-value cast))
+        (lvar (node-lvar cast)))
+    (delete-filter cast lvar value)
+    (when lvar
+      (reoptimize-lvar lvar)
+      (when (lvar-single-value-p lvar)
+        (note-single-valuified-lvar lvar)))
+    (values)))
+
 (defun ir1-optimize-cast (cast &optional do-not-optimize)
   (declare (type cast cast))
   (let ((value (cast-value cast))
       (let ((lvar (node-lvar cast)))
         (when (values-subtypep (lvar-derived-type value)
                                (cast-asserted-type cast))
-          (delete-filter cast lvar value)
-          (when lvar
-            (reoptimize-lvar lvar)
-            (when (lvar-single-value-p lvar)
-              (note-single-valuified-lvar lvar)))
+          (delete-cast cast)
           (return-from ir1-optimize-cast t))
 
         (when (and (listp (lvar-uses value))
 
   (unless do-not-optimize
     (setf (node-reoptimize cast) nil)))
+
+(deftransform make-symbol ((string) (simple-string))
+  `(%make-symbol string))