X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcompiler%2Fmacros.lisp;h=df8fb02defd4a4319e985af083dc3b0dbff0d2db;hb=148e3820ad314a9b59d0133c1d60eaac4af9118b;hp=58448291b8551eb01c7b047dfd3d496b5887c234;hpb=416152f084604094445a758ff399871132dff2bd;p=sbcl.git diff --git a/src/compiler/macros.lisp b/src/compiler/macros.lisp index 5844829..df8fb02 100644 --- a/src/compiler/macros.lisp +++ b/src/compiler/macros.lisp @@ -78,8 +78,8 @@ `((setf (symbol-function ',name) (lambda (&rest rest) (declare (ignore rest)) - (error "can't FUNCALL the SYMBOL-FUNCTION of ~ - special forms"))))))))) + (error 'special-form-function + :name ',name))))))))) ;;; (This is similar to DEF-IR1-TRANSLATOR, except that we pass if the ;;; syntax is invalid.) @@ -100,7 +100,7 @@ ;;; If the desirability of the transformation depends on the current ;;; OPTIMIZE parameters, then the POLICY macro should be used to ;;; determine when to pass. -(defmacro def-source-transform (name lambda-list &body body) +(defmacro define-source-transform (name lambda-list &body body) (let ((fn-name (if (listp name) (collect ((pieces)) @@ -124,23 +124,6 @@ ,@decls ,body)) (setf (info :function :source-transform ',name) #',fn-name))))) - -;;; Define a function that converts a use of (%PRIMITIVE NAME ..) -;;; into Lisp code. LAMBDA-LIST is a DEFMACRO-style lambda list. -(defmacro def-primitive-translator (name lambda-list &body body) - (let ((fn-name (symbolicate "PRIMITIVE-TRANSLATE-" name)) - (n-form (gensym)) - (n-env (gensym))) - (multiple-value-bind (body decls) - (parse-defmacro lambda-list n-form body name "%primitive" - :environment n-env - :error-fun 'convert-condition-into-compiler-error) - `(progn - (defun ,fn-name (,n-form) - (let ((,n-env *lexenv*)) - ,@decls - ,body)) - (setf (gethash ',name *primitive-translators*) ',fn-name))))) ;;;; boolean attribute utilities ;;;; @@ -166,7 +149,7 @@ ) ; EVAL-WHEN ;;; Define a new class of boolean attributes, with the attributes -;;; having the specified Attribute-Names. Name is the name of the +;;; having the specified ATTRIBUTE-NAMES. NAME is the name of the ;;; class, which is used to generate some macros to manipulate sets of ;;; the attributes: ;;; @@ -177,71 +160,80 @@ ;;; ;;; NAME-attributes attribute-name* ;;; Return a set of the named attributes. -;;; -;;; KLUDGE: This is expanded out twice, by cut-and-paste, in a -;;; (DEF!MACRO FOO (..) .. CL:GET-SETF-EXPANSION ..) -;;; #+SB-XC-HOST -;;; (SB!XC:DEFMACRO FOO (..) .. SB!XC:GET-SETF-EXPANSION ..) -;;; arrangement, in order to get it to work in cross-compilation. This -;;; duplication should be removed, perhaps by rewriting the macro in a -;;; more cross-compiler-friendly way, or perhaps just by using some -;;; (MACROLET ((FROB ..)) .. FROB .. FROB) form, but I don't want to -;;; do it now, because the system isn't running yet, so it'd be too -;;; hard to check that my changes were correct -- WHN 19990806 -(def!macro def-boolean-attribute (name &rest attribute-names) - - (let ((translations-name (symbolicate "*" name "-ATTRIBUTE-TRANSLATIONS*")) - (test-name (symbolicate name "-ATTRIBUTEP"))) - (collect ((alist)) - (do ((mask 1 (ash mask 1)) - (names attribute-names (cdr names))) - ((null names)) - (alist (cons (car names) mask))) - - `(progn - - (eval-when (:compile-toplevel :load-toplevel :execute) - (defparameter ,translations-name ',(alist))) - - (defmacro ,test-name (attributes &rest attribute-names) - "Automagically generated boolean attribute test function. See - Def-Boolean-Attribute." - `(logtest ,(compute-attribute-mask attribute-names - ,translations-name) - (the attributes ,attributes))) - - (define-setf-expander ,test-name (place &rest attributes - &environment env) - "Automagically generated boolean attribute setter. See - Def-Boolean-Attribute." - #-sb-xc-host (declare (type sb!c::lexenv env)) - ;; FIXME: It would be better if &ENVIRONMENT arguments - ;; were automatically declared to have type LEXENV by the - ;; hairy-argument-handling code. - (multiple-value-bind (temps values stores set get) - (get-setf-expansion place env) - (when (cdr stores) - (error "multiple store variables for ~S" place)) - (let ((newval (gensym)) - (n-place (gensym)) - (mask (compute-attribute-mask attributes - ,translations-name))) - (values `(,@temps ,n-place) - `(,@values ,get) - `(,newval) - `(let ((,(first stores) - (if ,newval - (logior ,n-place ,mask) - (logand ,n-place ,(lognot mask))))) - ,set - ,newval) - `(,',test-name ,n-place ,@attributes))))) - - (defmacro ,(symbolicate name "-ATTRIBUTES") (&rest attribute-names) - "Automagically generated boolean attribute creation function. See - Def-Boolean-Attribute." - (compute-attribute-mask attribute-names ,translations-name)))))) -;;; #+SB-XC-HOST SB!XC:DEFMACRO version is in late-macros.lisp. -- WHN 19990806 +#+sb-xc-host +(progn + (def!macro !def-boolean-attribute (name &rest attribute-names) + + (let ((translations-name (symbolicate "*" name "-ATTRIBUTE-TRANSLATIONS*")) + (test-name (symbolicate name "-ATTRIBUTEP"))) + (collect ((alist)) + (do ((mask 1 (ash mask 1)) + (names attribute-names (cdr names))) + ((null names)) + (alist (cons (car names) mask))) + `(progn + (eval-when (:compile-toplevel :load-toplevel :execute) + (defparameter ,translations-name ',(alist))) + (defmacro ,(symbolicate name "-ATTRIBUTES") (&rest attribute-names) + "Automagically generated boolean attribute creation function. + See !DEF-BOOLEAN-ATTRIBUTE." + (compute-attribute-mask attribute-names ,translations-name)) + (defmacro ,test-name (attributes &rest attribute-names) + "Automagically generated boolean attribute test function. + See !DEF-BOOLEAN-ATTRIBUTE." + `(logtest ,(compute-attribute-mask attribute-names + ,translations-name) + (the attributes ,attributes))) + ;; This definition transforms strangely under UNCROSS, in a + ;; way that DEF!MACRO doesn't understand, so we delegate it + ;; to a submacro then define the submacro differently when + ;; building the xc and when building the target compiler. + (!def-boolean-attribute-setter ,test-name + ,translations-name + ,@attribute-names))))) + + ;; It seems to be difficult to express in DEF!MACRO machinery what + ;; to do with target-vs-host GET-SETF-EXPANSION in here, so we just + ;; hack it by hand, passing a different GET-SETF-EXPANSION-FUN-NAME + ;; in the host DEFMACRO and target DEFMACRO-MUNDANELY cases. + (defun guts-of-!def-boolean-attribute-setter (test-name + translations-name + attribute-names + get-setf-expansion-fun-name) + `(define-setf-expander ,test-name (place &rest attributes + &environment env) + "Automagically generated boolean attribute setter. See + !DEF-BOOLEAN-ATTRIBUTE." + #-sb-xc-host (declare (type sb!c::lexenv env)) + ;; FIXME: It would be better if &ENVIRONMENT arguments were + ;; automatically declared to have type LEXENV by the + ;; hairy-argument-handling code. + (multiple-value-bind (temps values stores set get) + (,get-setf-expansion-fun-name place env) + (when (cdr stores) + (error "multiple store variables for ~S" place)) + (let ((newval (gensym)) + (n-place (gensym)) + (mask (compute-attribute-mask attributes ,translations-name))) + (values `(,@temps ,n-place) + `(,@values ,get) + `(,newval) + `(let ((,(first stores) + (if ,newval + (logior ,n-place ,mask) + (logand ,n-place ,(lognot mask))))) + ,set + ,newval) + `(,',test-name ,n-place ,@attributes)))))) + ;; We define the host version here, and the just-like-it-but-different + ;; target version later, after DEFMACRO-MUNDANELY has been defined. + (defmacro !def-boolean-attribute-setter (test-name + translations-name + &rest attribute-names) + (guts-of-!def-boolean-attribute-setter test-name + translations-name + attribute-names + 'get-setf-expansion))) ;;; And now for some gratuitous pseudo-abstraction... ;;; @@ -251,15 +243,15 @@ ;;; ATTRIBUTES-INTERSECTION ;;; Return the intersection of all the sets of boolean attributes which ;;; are its arguments. -;;; ATTRIBUTES= -;;; True if the attributes present in Attr1 are identical to -;;; those in Attr2. +;;; ATTRIBUTES +;;; True if the attributes present in ATTR1 are identical to +;;; those in ATTR2. (defmacro attributes-union (&rest attributes) `(the attributes - (logior ,@(mapcar #'(lambda (x) `(the attributes ,x)) attributes)))) + (logior ,@(mapcar (lambda (x) `(the attributes ,x)) attributes)))) (defmacro attributes-intersection (&rest attributes) `(the attributes - (logand ,@(mapcar #'(lambda (x) `(the attributes ,x)) attributes)))) + (logand ,@(mapcar (lambda (x) `(the attributes ,x)) attributes)))) (declaim (ftype (function (attributes attributes) boolean) attributes=)) #!-sb-fluid (declaim (inline attributes=)) (defun attributes= (attr1 attr2) @@ -403,13 +395,10 @@ ;;; which means efficiency notes will be generated when this ;;; transform fails even if INHIBIT-WARNINGS=SPEED (but not if ;;; INHIBIT-WARNINGS>SPEED). -;;; :WHEN {:NATIVE | :BYTE | :BOTH} -;;; - Indicates whether this transform applies to native code, -;;; byte-code or both (default :native.) (defmacro deftransform (name (lambda-list &optional (arg-types '*) (result-type '*) &key result policy node defun-only - eval-name important (when :native)) + eval-name important) &body body-decls-doc) (when (and eval-name defun-only) (error "can't specify both DEFUN-ONLY and EVAL-NAME")) @@ -448,10 +437,9 @@ ,(if eval-name ``(function ,,arg-types ,,result-type) `'(function ,arg-types ,result-type)) - #'(lambda ,@stuff) + (lambda ,@stuff) ,doc - ,(if important t nil) - ,when))))))) + ,(if important t nil)))))))) ;;;; DEFKNOWN and DEFOPTIMIZER @@ -468,73 +456,35 @@ ;;; Declare the function NAME to be a known function. We construct a ;;; type specifier for the function by wrapping (FUNCTION ...) around ;;; the ARG-TYPES and RESULT-TYPE. ATTRIBUTES is an unevaluated list -;;; of boolean attributes of the function. These attributes are -;;; meaningful here: -;;; -;;; CALL -;;; May call functions that are passed as arguments. In order -;;; to determine what other effects are present, we must find -;;; the effects of all arguments that may be functions. -;;; -;;; UNSAFE -;;; May incorporate arguments in the result or somehow pass -;;; them upward. -;;; -;;; UNWIND -;;; May fail to return during correct execution. Errors -;;; are O.K. -;;; -;;; ANY -;;; The (default) worst case. Includes all the other bad -;;; things, plus any other possible bad thing. -;;; -;;; FOLDABLE -;;; May be constant-folded. The function has no side effects, -;;; but may be affected by side effects on the arguments. E.g. -;;; SVREF, MAPC. -;;; -;;; FLUSHABLE -;;; May be eliminated if value is unused. The function has -;;; no side effects except possibly CONS. If a function is -;;; defined to signal errors, then it is not flushable even -;;; if it is movable or foldable. -;;; -;;; MOVABLE -;;; May be moved with impunity. Has no side effects except -;;; possibly CONS, and is affected only by its arguments. -;;; -;;; PREDICATE -;;; A true predicate likely to be open-coded. This is a -;;; hint to IR1 conversion that it should ensure calls always -;;; appear as an IF test. Not usually specified to DEFKNOWN, -;;; since this is implementation dependent, and is usually -;;; automatically set by the DEFINE-VOP :CONDITIONAL option. -;;; -;;; NAME may also be a list of names, in which case the same -;;; information is given to all the names. The keywords specify the -;;; initial values for various optimizers that the function might -;;; have. +;;; of boolean attributes of the function. See their description in +;;; (!DEF-BOOLEAN-ATTRIBUTE IR1). NAME may also be a list of names, in +;;; which case the same information is given to all the names. The +;;; keywords specify the initial values for various optimizers that +;;; the function might have. (defmacro defknown (name arg-types result-type &optional (attributes '(any)) &rest keys) (when (and (intersection attributes '(any call unwind)) (intersection attributes '(movable))) (error "function cannot have both good and bad attributes: ~S" attributes)) + (when (member 'any attributes) + (setf attributes (union '(call unsafe unwind) attributes))) + (when (member 'flushable attributes) + (pushnew 'unsafely-flushable attributes)) + `(%defknown ',(if (and (consp name) (not (eq (car name) 'setf))) name (list name)) '(function ,arg-types ,result-type) - (ir1-attributes ,@(if (member 'any attributes) - (union '(call unsafe unwind) attributes) - attributes)) + (ir1-attributes ,@attributes) ,@keys)) ;;; Create a function which parses combination args according to WHAT ;;; and LAMBDA-LIST, where WHAT is either a function name or a list -;;; (FUNCTION-NAME KIND) and does some KIND of optimization. +;;; (FUN-NAME KIND) and does some KIND of optimization. ;;; -;;; The FUNCTION-NAME must name a known function. LAMBDA-LIST is used +;;; The FUN-NAME must name a known function. LAMBDA-LIST is used ;;; to parse the arguments to the combination as in DEFTRANSFORM. If ;;; the argument syntax is invalid or there are non-constant keys, ;;; then we simply return NIL. @@ -564,8 +514,8 @@ ,(parse-deftransform lambda-list body n-args `(return-from ,name nil)))) ,@(when (consp what) - `((setf (,(symbolicate "FUNCTION-INFO-" (second what)) - (function-info-or-lose ',(first what))) + `((setf (,(symbolicate "FUN-INFO-" (second what)) + (fun-info-or-lose ',(first what))) #',name))))))) ;;;; IR groveling macros @@ -674,7 +624,7 @@ `(eq ,node-var (block-last ,n-block)) `(eq ,cont-var ,n-last-cont)) (return nil)))))) -;;; like Do-Nodes, only iterating in reverse order +;;; like DO-NODES, only iterating in reverse order (defmacro do-nodes-backwards ((node-var cont-var block) &body body) (let ((n-block (gensym)) (n-start (gensym)) @@ -691,23 +641,28 @@ (when (eq ,n-next ,n-start) (return nil)))))) -;;; Bind the IR1 context variables so that IR1 conversion can be done -;;; after the main conversion pass has finished. -;;; -;;; The lexical environment is presumably already null... -(defmacro with-ir1-environment (node &rest forms) - (let ((n-node (gensym))) - `(let* ((,n-node ,node) - (*current-component* (block-component (node-block ,n-node))) - (*lexenv* (node-lexenv ,n-node)) - (*current-path* (node-source-path ,n-node))) - ,@forms))) +;;; Bind the IR1 context variables to the values associated with NODE, +;;; so that new, extra IR1 conversion related to NODE can be done +;;; after the original conversion pass has finished. +(defmacro with-ir1-environment-from-node (node &rest forms) + `(flet ((closure-needing-ir1-environment-from-node () + ,@forms)) + (%with-ir1-environment-from-node + ,node + #'closure-needing-ir1-environment-from-node))) +(defun %with-ir1-environment-from-node (node fun) + (declare (type node node) (type function fun)) + (let ((*current-component* (node-component node)) + (*lexenv* (node-lexenv node)) + (*current-path* (node-source-path node))) + (aver-live-component *current-component*) + (funcall fun))) ;;; Bind the hashtables used for keeping track of global variables, -;;; functions, &c. Also establish condition handlers. +;;; functions, etc. Also establish condition handlers. (defmacro with-ir1-namespace (&body forms) - `(let ((*free-variables* (make-hash-table :test 'eq)) - (*free-functions* (make-hash-table :test 'equal)) + `(let ((*free-vars* (make-hash-table :test 'eq)) + (*free-funs* (make-hash-table :test 'equal)) (*constants* (make-hash-table :test 'equal)) (*source-paths* (make-hash-table :test 'eq))) (handler-bind ((compiler-error #'compiler-error-handler) @@ -720,11 +675,18 @@ ;;; :TEST keyword may be used to determine the name equality ;;; predicate. (defmacro lexenv-find (name slot &key test) - (once-only ((n-res `(assoc ,name (,(symbolicate "LEXENV-" slot) *lexenv*) + (once-only ((n-res `(assoc ,name (,(let ((*package* (symbol-package 'lexenv-funs))) + (symbolicate "LEXENV-" slot)) + *lexenv*) :test ,(or test '#'eq)))) `(if ,n-res (values (cdr ,n-res) t) (values nil nil)))) + +;;; +(defmacro with-continuation-type-assertion ((cont ctype context) &body body) + `(let ((*lexenv* (ir1ize-the-or-values ,ctype ,cont *lexenv* ,context))) + ,@body)) ;;;; the EVENT statistics/trace utility @@ -736,15 +698,15 @@ (defstruct (event-info (:copier nil)) ;; The name of this event. - (name (required-argument) :type symbol) + (name (missing-arg) :type symbol) ;; The string rescribing this event. - (description (required-argument) :type string) + (description (missing-arg) :type string) ;; The name of the variable we stash this in. - (var (required-argument) :type symbol) + (var (missing-arg) :type symbol) ;; The number of times this event has happened. (count 0 :type fixnum) ;; The level of significance of this event. - (level (required-argument) :type unsigned-byte) + (level (missing-arg) :type unsigned-byte) ;; If true, a function that gets called with the node that the event ;; happened to. (action nil :type (or function null))) @@ -827,10 +789,10 @@ (declaim (ftype (function (&optional unsigned-byte stream) (values)) event-statistics)) (defun event-statistics (&optional (min-count 1) (stream *standard-output*)) (collect ((info)) - (maphash #'(lambda (k v) - (declare (ignore k)) - (when (>= (event-info-count v) min-count) - (info v))) + (maphash (lambda (k v) + (declare (ignore k)) + (when (>= (event-info-count v) min-count) + (info v))) *event-info*) (dolist (event (sort (info) #'> :key #'event-info-count)) (format stream "~6D: ~A~%" (event-info-count event) @@ -840,16 +802,16 @@ (declaim (ftype (function nil (values)) clear-event-statistics)) (defun clear-event-statistics () - (maphash #'(lambda (k v) - (declare (ignore k)) - (setf (event-info-count v) 0)) + (maphash (lambda (k v) + (declare (ignore k)) + (setf (event-info-count v) 0)) *event-info*) (values)) ;;;; functions on directly-linked lists (linked through specialized ;;;; NEXT operations) -#!-sb-fluid (declaim (inline find-in position-in map-in)) +#!-sb-fluid (declaim (inline find-in position-in)) ;;; Find Element in a null-terminated List linked by the accessor ;;; function Next. Key, Test and Test-Not are the same as for generic @@ -860,7 +822,8 @@ &key (key #'identity) (test #'eql test-p) - (test-not nil not-p)) + (test-not #'eql not-p)) + (declare (type function next key test test-not)) (when (and test-p not-p) (error "It's silly to supply both :TEST and :TEST-NOT arguments.")) (if not-p @@ -882,7 +845,8 @@ &key (key #'identity) (test #'eql test-p) - (test-not nil not-p)) + (test-not #'eql not-p)) + (declare (type function next key test test-not)) (when (and test-p not-p) (error "It's silly to supply both :TEST and :TEST-NOT arguments.")) (if not-p @@ -897,14 +861,6 @@ (when (funcall test (funcall key current) element) (return i))))) -;;; Map FUNCTION over the elements in a null-terminated LIST linked by the -;;; accessor function NEXT, returning an ordinary list of the results. -(defun map-in (next function list) - (collect ((res)) - (do ((current list (funcall next current))) - ((null current)) - (res (funcall function current))) - (res))) ;;; KLUDGE: This is expanded out twice, by cut-and-paste, in a ;;; (DEF!MACRO FOO (..) .. CL:GET-SETF-EXPANSION ..)