X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcompiler%2Fir1-translators.lisp;h=a5e4cfb7c0f1b720bd2710788db23e157fe135a4;hb=2050b7c3644ab235aaf1959795bb33e89bd571a3;hp=d26e53a00ee0d4e1c359de9c9136b58fb70b97ea;hpb=45bc305be4e269d2e1a477c8e0ae9a64df1ccd1c;p=sbcl.git diff --git a/src/compiler/ir1-translators.lisp b/src/compiler/ir1-translators.lisp index d26e53a..a5e4cfb 100644 --- a/src/compiler/ir1-translators.lisp +++ b/src/compiler/ir1-translators.lisp @@ -26,7 +26,7 @@ forms, returns NIL." #!+sb-doc "IF predicate then [else] -If PREDICATE evaluates to false, evaluate THEN and return its values, +If PREDICATE evaluates to true, evaluate THEN and return its values, otherwise evaluate ELSE and return its values. ELSE defaults to NIL." (let* ((pred-ctran (make-ctran)) (pred-lvar (make-lvar)) @@ -75,9 +75,14 @@ otherwise evaluate ELSE and return its values. ELSE defaults to NIL." nil (labels ((sub (form) (or (get-source-path form) - (and (consp form) - (some #'sub form))))) - (or (sub form))))) + (when (consp form) + (unless (eq 'quote (car form)) + (somesub form))))) + (somesub (forms) + (when (consp forms) + (or (sub (car forms)) + (somesub (cdr forms)))))) + (sub form)))) ;;;; BLOCK and TAGBODY @@ -373,7 +378,7 @@ destructuring lambda list, and the FORMS evaluate to the expansion." (program-assert-symbol-home-package-unlocked context name "binding ~A as a local symbol-macro")) (let ((kind (info :variable :kind name))) - (when (member kind '(:special :constant)) + (when (member kind '(:special :constant :global)) (fail "Attempt to bind a ~(~A~) variable with SYMBOL-MACROLET: ~S" kind name))) ;; A magical cons that MACROEXPAND-1 understands. @@ -449,7 +454,7 @@ body, references to a NAME will effectively be replaced with the EXPANSION." nargs min))) - (when (eq (template-result-types template) :conditional) + (when (template-conditional-p template) (bug "%PRIMITIVE was used with a conditional template.")) (when (template-more-results-type template) @@ -471,22 +476,37 @@ body, references to a NAME will effectively be replaced with the EXPANSION." Return VALUE without evaluating it." (reference-constant start next result thing)) +(defun name-context () + ;; Name of the outermost non-NIL BLOCK, or the source namestring + ;; of the source file. + (let ((context + (or (car (find-if #'car (lexenv-blocks *lexenv*) :from-end t)) + *source-namestring* + (let ((p (or *compile-file-truename* *load-truename*))) + (when p (namestring p)))))) + (when context + (list :in context)))) + ;;;; FUNCTION and NAMED-LAMBDA (defun name-lambdalike (thing) - (ecase (car thing) + (case (car thing) ((named-lambda) (or (second thing) - `(lambda ,(third thing)))) - ((lambda instance-lambda) - `(lambda ,(second thing))) + `(lambda ,(third thing) ,(name-context)))) + ((lambda) + `(lambda ,(second thing) ,@(name-context))) ((lambda-with-lexenv) - `(lambda ,(fifth thing))))) + ;; FIXME: Get the original DEFUN name here. + `(lambda ,(fifth thing))) + (otherwise + (compiler-error "Not a valid lambda expression:~% ~S" + thing)))) (defun fun-name-leaf (thing) (if (consp thing) (cond ((member (car thing) - '(lambda named-lambda instance-lambda lambda-with-lexenv)) + '(lambda named-lambda lambda-with-lexenv)) (values (ir1-convert-lambdalike thing :debug-name (name-lambdalike thing)) @@ -509,9 +529,9 @@ Return VALUE without evaluating it." (dolist (lambda lambdas) (setf (functional-allocator lambda) allocator))))) -(defmacro with-fun-name-leaf ((leaf thing start &key global) &body body) +(defmacro with-fun-name-leaf ((leaf thing start &key global-function) &body body) `(multiple-value-bind (,leaf allocate-p) - (if ,global + (if ,global-function (find-global-fun ,thing t) (fun-name-leaf ,thing)) (if allocate-p @@ -535,14 +555,45 @@ be a lambda expression." ;;; expansions, and doesn't nag about undefined functions. ;;; Used for optimizing things like (FUNCALL 'FOO). (def-ir1-translator global-function ((thing) start next result) - (with-fun-name-leaf (leaf thing start :global t) + (with-fun-name-leaf (leaf thing start :global-function t) (reference-leaf start next result leaf))) (defun constant-global-fun-name (thing) (let ((constantp (sb!xc:constantp thing))) - (and constantp - (let ((name (constant-form-value thing))) - (and (legal-fun-name-p name) name))))) + (when constantp + (let ((name (constant-form-value thing))) + (when (legal-fun-name-p name) + name))))) + +(defun lvar-constant-global-fun-name (lvar) + (when (constant-lvar-p lvar) + (let ((name (lvar-value lvar))) + (when (legal-fun-name-p name) + name)))) + +(defun ensure-source-fun-form (source &optional give-up) + (let ((op (when (consp source) (car source)))) + (cond ((eq op '%coerce-callable-to-fun) + (ensure-source-fun-form (second source))) + ((member op '(function global-function lambda named-lambda)) + (values source nil)) + (t + (let ((cname (constant-global-fun-name source))) + (if cname + (values `(global-function ,cname) nil) + (values `(%coerce-callable-to-fun ,source) give-up))))))) + +(defun ensure-lvar-fun-form (lvar lvar-name &optional give-up) + (aver (and lvar-name (symbolp lvar-name))) + (if (csubtypep (lvar-type lvar) (specifier-type 'function)) + lvar-name + (let ((cname (lvar-constant-global-fun-name lvar))) + (cond (cname + `(global-function ,cname)) + (give-up + (give-up-ir1-transform give-up)) + (t + `(%coerce-callable-to-fun ,lvar-name)))))) ;;;; FUNCALL @@ -552,45 +603,42 @@ be a lambda expression." (deftransform funcall ((function &rest args) * *) (let ((arg-names (make-gensym-list (length args)))) `(lambda (function ,@arg-names) - (%funcall ,(if (csubtypep (lvar-type function) - (specifier-type 'function)) - 'function - '(%coerce-callable-to-fun function)) - ,@arg-names)))) + (declare (ignorable function)) + `(%funcall ,(ensure-lvar-fun-form function 'function) ,@arg-names)))) (def-ir1-translator %funcall ((function &rest args) start next result) - (cond ((and (consp function) (eq (car function) 'function)) - (with-fun-name-leaf (leaf (second function) start) - (ir1-convert start next result `(,leaf ,@args)))) - ((and (consp function) (eq (car function) 'global-function)) - (with-fun-name-leaf (leaf (second function) start :global t) - (ir1-convert start next result `(,leaf ,@args)))) - (t - (let ((ctran (make-ctran)) - (fun-lvar (make-lvar))) - (ir1-convert start ctran fun-lvar `(the function ,function)) - (ir1-convert-combination-args fun-lvar ctran next result args))))) + ;; MACROEXPAND so that (LAMBDA ...) forms arriving here don't get an + ;; extra cast inserted for them. + (let* ((function (%macroexpand function *lexenv*)) + (op (when (consp function) (car function)))) + (cond ((eq op 'function) + (compiler-destructuring-bind (thing) (cdr function) + function + (with-fun-name-leaf (leaf thing start) + (ir1-convert start next result `(,leaf ,@args))))) + ((eq op 'global-function) + (compiler-destructuring-bind (thing) (cdr function) + global-function + (with-fun-name-leaf (leaf thing start :global-function t) + (ir1-convert start next result `(,leaf ,@args))))) + (t + (let ((ctran (make-ctran)) + (fun-lvar (make-lvar))) + (ir1-convert start ctran fun-lvar `(the function ,function)) + (ir1-convert-combination-args fun-lvar ctran next result args)))))) ;;; This source transform exists to reduce the amount of work for the ;;; compiler. If the called function is a FUNCTION form, then convert ;;; directly to %FUNCALL, instead of waiting around for type ;;; inference. (define-source-transform funcall (function &rest args) - (if (and (consp function) (member (car function) '(function lambda))) - `(%funcall ,function ,@args) - (let ((name (constant-global-fun-name function))) - (if name - `(%funcall (global-function ,name) ,@args) - (values nil t))))) + `(%funcall ,(ensure-source-fun-form function) ,@args)) -(deftransform %coerce-callable-to-fun ((thing) (function) *) - "optimize away possible call to FDEFINITION at runtime" - 'thing) +(deftransform %coerce-callable-to-fun ((thing) * *) + (ensure-lvar-fun-form thing 'thing "optimize away possible call to FDEFINITION at runtime")) (define-source-transform %coerce-callable-to-fun (thing) - (if (and (consp thing) (member (car thing) '(function lambda))) - thing - (values nil t))) + (ensure-source-fun-form thing t)) ;;;; LET and LET* ;;;; @@ -615,7 +663,8 @@ be a lambda expression." (varify-lambda-arg name (if (eq context 'let*) nil - (names))))) + (names)) + context))) (dolist (spec bindings) (cond ((atom spec) (let ((var (get-var spec))) @@ -733,8 +782,9 @@ also processed as top level forms." (program-assert-symbol-home-package-unlocked :compile name "binding ~A as a local function")) (names name) - (multiple-value-bind (forms decls) (parse-body (cddr def)) + (multiple-value-bind (forms decls doc) (parse-body (cddr def)) (defs `(lambda ,(second def) + ,@(when doc (list doc)) ,@decls (block ,(fun-name-block-name name) . ,forms)))))) @@ -776,10 +826,11 @@ lexically apparent function definition in the enclosing environment." (multiple-value-bind (names defs) (extract-flet-vars definitions 'flet) (let ((fvars (mapcar (lambda (n d) - (ir1-convert-lambda d - :source-name n - :maybe-add-debug-catch t - :debug-name (debug-name 'flet n))) + (ir1-convert-lambda + d :source-name n + :maybe-add-debug-catch t + :debug-name + (debug-name 'flet n t))) names defs))) (processing-decls (decls nil fvars next result) (let ((*lexenv* (make-lexenv :funs (pairlis names fvars)))) @@ -814,7 +865,7 @@ other." (ir1-convert-lambda def :source-name name :maybe-add-debug-catch t - :debug-name (debug-name 'labels name))) + :debug-name (debug-name 'labels name t))) names defs)))) ;; Modify all the references to the dummy function leaves so @@ -878,6 +929,12 @@ is unable to derive from other declared types." ;;; whatever you tell it. It will never generate a type check, but ;;; will cause a warning if the compiler can prove the assertion is ;;; wrong. +;;; +;;; For the benefit of code-walkers we also add a macro-expansion. (Using INFO +;;; directly to get around safeguards for adding a macro-expansion for special +;;; operator.) Because :FUNCTION :KIND remains :SPECIAL-FORM, the compiler +;;; never uses the macro -- but manually calling its MACRO-FUNCTION or +;;; MACROEXPANDing TRULY-THE forms does. (def-ir1-translator truly-the ((value-type form) start next result) #!+sb-doc "Specifies that the values returned by FORM conform to the @@ -888,6 +945,12 @@ Consequences are undefined if any result is not of the declared type -- typical symptoms including memory corruptions. Use with great care." (the-in-policy value-type form '((type-check . 0)) start next result)) + +#-sb-xc-host +(setf (info :function :macro-function 'truly-the) + (lambda (whole env) + (declare (ignore env)) + `(the ,@(cdr whole)))) ;;;; SETQ @@ -916,7 +979,7 @@ care." (compiler-style-warn "~S is being set even though it was declared to be ignored." name))) - (if (and (global-var-p leaf) (eq :global (global-var-kind leaf))) + (if (and (global-var-p leaf) (eq :unknown (global-var-kind leaf))) ;; For undefined variables go through SET, so that we can catch ;; constant modifications. (ir1-convert start next result `(set ',name ,value-form)) @@ -944,7 +1007,8 @@ care." (dest-lvar (make-lvar)) (type (or (lexenv-find var type-restrictions) (leaf-type var)))) - (ir1-convert start dest-ctran dest-lvar `(the ,type ,value)) + (ir1-convert start dest-ctran dest-lvar `(the ,(type-specifier type) + ,value)) (let ((res (make-set :var var :value dest-lvar))) (setf (lvar-dest dest-lvar) res) (setf (leaf-ever-used var) t) @@ -1061,6 +1125,7 @@ due to normal completion or a non-local exit such as THROW)." ;; ,CLEANUP-FUN should probably be declared DYNAMIC-EXTENT, ;; and something can be done to make %ESCAPE-FUN have ;; dynamic extent too. + (declare (dynamic-extent #',cleanup-fun)) (block ,drop-thru-tag (multiple-value-bind (,next ,start ,count) (block ,exit-tag @@ -1094,13 +1159,7 @@ values from the first VALUES-FORM making up the first argument, etc." ;; important for simplifying compilation of ;; MV-COMBINATIONS. (make-combination fun-lvar)))) - (ir1-convert start ctran fun-lvar - (if (and (consp fun) (eq (car fun) 'function)) - fun - (let ((name (constant-global-fun-name fun))) - (if name - `(global-function ,name) - `(%coerce-callable-to-fun ,fun))))) + (ir1-convert start ctran fun-lvar (ensure-source-fun-form fun)) (setf (lvar-dest fun-lvar) node) (collect ((arg-lvars)) (let ((this-start ctran))