(functional
(ir2-convert-closure node block leaf res))
(global-var
- (let ((unsafe (policy node (zerop safety)))
- (name (leaf-source-name leaf)))
- (ecase (global-var-kind leaf)
- ((:special :unknown)
- (aver (symbolp name))
- (let ((name-tn (emit-constant name)))
- (if (or unsafe (info :variable :always-bound name))
- (vop fast-symbol-value node block name-tn res)
- (vop symbol-value node block name-tn res))))
- (:global
- (aver (symbolp name))
- (let ((name-tn (emit-constant name)))
- (if (or unsafe (info :variable :always-bound name))
- (vop fast-symbol-global-value node block name-tn res)
- (vop symbol-global-value node block name-tn res))))
- (:global-function
- (let ((fdefn-tn (make-load-time-constant-tn :fdefinition name)))
- (if unsafe
- (vop fdefn-fun node block fdefn-tn res)
- (vop safe-fdefn-fun node block fdefn-tn res))))))))
+ (ir2-convert-global-var node block leaf res)))
(move-lvar-result node block locs lvar))
(values))
+(defun ir2-convert-global-var (node block leaf res)
+ (let ((unsafe (policy node (zerop safety)))
+ (name (leaf-source-name leaf)))
+ (ecase (global-var-kind leaf)
+ ((:special :unknown)
+ (aver (symbolp name))
+ (let ((name-tn (emit-constant name)))
+ (if (or unsafe (info :variable :always-bound name))
+ (vop fast-symbol-value node block name-tn res)
+ (vop symbol-value node block name-tn res))))
+ (:global
+ (aver (symbolp name))
+ (let ((name-tn (emit-constant name)))
+ (if (or unsafe (info :variable :always-bound name))
+ (vop fast-symbol-global-value node block name-tn res)
+ (vop symbol-global-value node block name-tn res))))
+ (:global-function
+ (cond #-sb-xc-host
+ ((and (info :function :definition name)
+ (info :function :info name))
+ ;; Known functions can be saved without going through fdefns,
+ ;; except during cross-compilation
+ (emit-move node block (make-load-time-constant-tn :known-fun name)
+ res))
+ (t
+ (let ((fdefn-tn (make-load-time-constant-tn :fdefinition name)))
+ (if unsafe
+ (vop fdefn-fun node block fdefn-tn res)
+ (vop safe-fdefn-fun node block fdefn-tn res)))))))))
+
;;; some sanity checks for a CLAMBDA passed to IR2-CONVERT-CLOSURE
(defun assertions-on-ir2-converted-clambda (clambda)
;; This assertion was sort of an experiment. It would be nice and
(type ir2-block ir2-block)
(type functional functional)
(type tn res))
- (aver (not (eql (functional-kind functional) :deleted)))
- (unless (leaf-info functional)
- (setf (leaf-info functional)
- (make-entry-info :name (functional-debug-name functional))))
- (let ((closure (etypecase functional
- (clambda
- (assertions-on-ir2-converted-clambda functional)
- (physenv-closure (get-lambda-physenv functional)))
- (functional
- (aver (eq (functional-kind functional) :toplevel-xep))
- nil))))
-
- (cond (closure
- (let* ((physenv (node-physenv ref))
- (tn (find-in-physenv functional physenv)))
- (emit-move ref ir2-block tn res)))
- (t
- (let ((entry (make-load-time-constant-tn :entry functional)))
- (emit-move ref ir2-block entry res)))))
+ (flet ((prepare ()
+ (aver (not (eql (functional-kind functional) :deleted)))
+ (unless (leaf-info functional)
+ (setf (leaf-info functional)
+ (make-entry-info :name
+ (functional-debug-name functional))))))
+ (let ((closure (etypecase functional
+ (clambda
+ (assertions-on-ir2-converted-clambda functional)
+ (physenv-closure (get-lambda-physenv functional)))
+ (functional
+ (aver (eq (functional-kind functional) :toplevel-xep))
+ nil)))
+ global-var)
+ (cond (closure
+ (prepare)
+ (let* ((physenv (node-physenv ref))
+ (tn (find-in-physenv functional physenv)))
+ (emit-move ref ir2-block tn res)))
+ ;; we're about to emit a reference to a "closure" that's actually
+ ;; an inlinable global function.
+ ((and (global-var-p (setf global-var
+ (functional-inline-expanded functional)))
+ (eq :global-function (global-var-kind global-var)))
+ (ir2-convert-global-var ref ir2-block global-var res))
+ (t
+ ;; if we're here, we should have either a toplevel-xep (some
+ ;; global scope function in a different component) or an external
+ ;; reference to the "closure"'s body.
+ (prepare)
+ (aver (memq (functional-kind functional) '(:external :toplevel-xep)))
+ (let ((entry (make-load-time-constant-tn :entry functional)))
+ (emit-move ref ir2-block entry res))))))
(values))
(defun closure-initial-value (what this-env current-fp)
(def list*))
\f
+(defoptimizer (mask-signed-field ir2-convert) ((width x) node block)
+ (block nil
+ (when (constant-lvar-p width)
+ (case (lvar-value width)
+ (#.(- sb!vm:n-word-bits sb!vm:n-fixnum-tag-bits)
+ (when (or (csubtypep (lvar-type x)
+ (specifier-type 'word))
+ (csubtypep (lvar-type x)
+ (specifier-type 'sb!vm:signed-word)))
+ (let* ((lvar (node-lvar node))
+ (temp (make-normal-tn
+ (if (csubtypep (lvar-type x)
+ (specifier-type 'word))
+ (primitive-type-of most-positive-word)
+ (primitive-type-of
+ (- (ash most-positive-word -1))))))
+ (results (lvar-result-tns
+ lvar
+ (list (primitive-type-or-lose 'fixnum)))))
+ (emit-move node block (lvar-tn node block x) temp)
+ (vop sb!vm::move-from-word/fixnum node block
+ temp (first results))
+ (move-lvar-result node block results lvar)
+ (return))))
+ (#.sb!vm:n-word-bits
+ (when (csubtypep (lvar-type x) (specifier-type 'word))
+ (let* ((lvar (node-lvar node))
+ (temp (make-normal-tn
+ (primitive-type-of most-positive-word)))
+ (results (lvar-result-tns
+ lvar
+ (list (primitive-type
+ (specifier-type 'sb!vm:signed-word))))))
+ (emit-move node block (lvar-tn node block x) temp)
+ (vop sb!vm::word-move node block
+ temp (first results))
+ (move-lvar-result node block results lvar)
+ (return))))))
+ (if (template-p (basic-combination-info node))
+ (ir2-convert-template node block)
+ (ir2-convert-full-call node block))))
+
+;; just a fancy identity
+(defoptimizer (%typep-wrapper ir2-convert) ((value variable type) node block)
+ (let* ((lvar (node-lvar node))
+ (results (lvar-result-tns lvar (list (primitive-type-or-lose t)))))
+ (emit-move node block (lvar-tn node block value) (first results))
+ (move-lvar-result node block results lvar)))
+\f
;;; Convert the code in a component into VOPs.
(defun ir2-convert (component)
(declare (type component component))
;;; If necessary, emit a terminal unconditional branch to go to the
;;; successor block. If the successor is the component tail, then
-;;; there isn't really any successor, but if the end is an unknown,
-;;; non-tail call, then we emit an error trap just in case the
-;;; function really does return.
+;;; there isn't really any successor, but if the end is a non-tail
+;;; call to a function that's not *known* to never return, then we
+;;; emit an error trap just in case the function really does return.
+;;;
+;;; Trapping after known calls makes it easier to understand type
+;;; derivation bugs at runtime: they show up as nil-fun-returned-error,
+;;; rather than the execution of arbitrary code or error traps.
(defun finish-ir2-block (block)
(declare (type cblock block))
(let* ((2block (block-info block))
(let ((target (first succ)))
(cond ((eq target (component-tail (block-component block)))
(when (and (basic-combination-p last)
- (eq (basic-combination-kind last) :full))
+ (or (eq (basic-combination-kind last) :full)
+ (and (eq (basic-combination-kind last) :known)
+ (eq (basic-combination-info last) :full))))
(let* ((fun (basic-combination-fun last))
(use (lvar-uses fun))
(name (and (ref-p use)
(leaf-has-source-name-p (ref-leaf use))
- (leaf-source-name (ref-leaf use)))))
+ (leaf-source-name (ref-leaf use))))
+ (ftype (and (info :function :info name) ; only use the FTYPE if
+ (info :function :type name)))) ; NAME was DEFKNOWN
(unless (or (node-tail-p last)
- (info :function :info name)
- (policy last (zerop safety)))
+ (policy last (zerop safety))
+ (and (fun-type-p ftype)
+ (eq *empty-type* (fun-type-returns ftype))))
(vop nil-fun-returned-error last 2block
(if name
(emit-constant name)