From b8fe7c0afeb9901091ce781ba351d0513f2ee86d Mon Sep 17 00:00:00 2001 From: Alexey Dejneka Date: Sat, 21 Sep 2002 10:24:08 +0000 Subject: [PATCH] 0.7.7.35: New ir1 attribute: UNSAFELY-FLUSHABLE. Functions, which must signal errors, are no longer (UNSAFELY-)FLUSHABLE. Those, which signal errors in safe mode code, are UNSAFELY-FLUSHABLE. --- NEWS | 1 + src/compiler/fndb.lisp | 104 +++++++++++++++++++++++--------------------- src/compiler/ir1opt.lisp | 16 ++++++- src/compiler/ir1util.lisp | 5 ++- src/compiler/knownfun.lisp | 16 +++++-- src/compiler/macros.lisp | 60 +++++-------------------- tests/compiler.pure.lisp | 16 +++++++ version.lisp-expr | 2 +- 8 files changed, 113 insertions(+), 107 deletions(-) diff --git a/NEWS b/NEWS index f8da51f..64a04a7 100644 --- a/NEWS +++ b/NEWS @@ -1277,6 +1277,7 @@ changes in sbcl-0.7.8 relative to sbcl-0.7.7: in several ways. (thanks to Alexey Dejneka) * fixed bug 181: compiler checks validity of user supplied type specifiers + * functions, which must signal errors, are no longer flushable planned incompatible changes in 0.7.x: * When the profiling interface settles down, maybe in 0.7.x, maybe diff --git a/src/compiler/fndb.lisp b/src/compiler/fndb.lisp index 64e584a..6614a44 100644 --- a/src/compiler/fndb.lisp +++ b/src/compiler/fndb.lisp @@ -48,7 +48,7 @@ ;;; These can be affected by type definitions, so they're not FOLDABLE. (defknown (upgraded-complex-part-type upgraded-array-element-type) (type-specifier) type-specifier - (flushable)) + (unsafely-flushable)) ;;;; from the "Predicates" chapter: @@ -59,7 +59,6 @@ ;;; this property should be protected by #-SB-XC-HOST? Perhaps we need ;;; 3-stage bootstrapping after all? (Ugh! It's *so* slow already!) (defknown typep (t type-specifier) t - (flushable ;; Unlike SUBTYPEP or UPGRADED-ARRAY-ELEMENT-TYPE and friends, this ;; seems to be FOLDABLE. Like SUBTYPEP, it's affected by type ;; definitions, but unlike SUBTYPEP, there should be no way to make @@ -77,14 +76,14 @@ ;; ;; (UPGRADED-ARRAY-ELEMENT-TYPE and UPGRADED-COMPLEX-PART-TYPE have ;; behavior like SUBTYPEP in this respect, not like TYPEP.) - foldable)) -(defknown subtypep (type-specifier type-specifier) (values boolean boolean) + (foldable)) +(defknown subtypep (type-specifier type-specifier) (values boolean boolean) ;; This is not FOLDABLE because its value is affected by type ;; definitions. ;; ;; FIXME: Is it OK to fold this when the types have already been ;; defined? Does the code inherited from CMU CL already do this? - (flushable)) + (unsafely-flushable)) (defknown (null symbolp atom consp listp numberp integerp rationalp floatp complexp characterp stringp bit-vector-p vectorp @@ -113,10 +112,10 @@ (defknown (symbol-value symbol-function) (symbol) t ()) (defknown boundp (symbol) boolean (flushable)) -(defknown fboundp ((or symbol cons)) boolean (flushable explicit-check)) +(defknown fboundp ((or symbol cons)) boolean (unsafely-flushable explicit-check)) (defknown special-operator-p (symbol) t ;; The set of special operators never changes. - (movable foldable flushable)) + (movable foldable flushable)) (defknown set (symbol t) t (unsafe) :derive-type #'result-type-last-arg) (defknown fdefinition ((or symbol cons)) function (unsafe explicit-check)) @@ -141,7 +140,7 @@ ;;; it into VALUES. VALUES is not foldable, since MV constants are ;;; represented by a call to VALUES. (defknown values (&rest t) * (movable flushable unsafe)) -(defknown values-list (list) * (movable foldable flushable)) +(defknown values-list (list) * (movable foldable unsafely-flushable)) ;;;; from the "Macros" chapter: @@ -190,13 +189,13 @@ (defknown find-package (package-designator) (or sb!xc:package null) (flushable)) (defknown package-name (package-designator) (or simple-string null) - (flushable)) -(defknown package-nicknames (package-designator) list (flushable)) + (unsafely-flushable)) +(defknown package-nicknames (package-designator) list (unsafely-flushable)) (defknown rename-package (package-designator package-designator &optional list) sb!xc:package) -(defknown package-use-list (package-designator) list (flushable)) -(defknown package-used-by-list (package-designator) list (flushable)) -(defknown package-shadowing-symbols (package-designator) list (flushable)) +(defknown package-use-list (package-designator) list (unsafely-flushable)) +(defknown package-used-by-list (package-designator) list (unsafely-flushable)) +(defknown package-shadowing-symbols (package-designator) list (unsafely-flushable)) (defknown list-all-packages () list (flushable)) (defknown intern (string &optional package-designator) (values symbol (member :internal :external :inherited nil)) @@ -280,7 +279,7 @@ (defknown atan (number &optional real) irrational - (movable foldable flushable explicit-check recursive) + (movable foldable unsafely-flushable explicit-check recursive) :derive-type #'result-type-float-contagion) (defknown (tan sinh cosh tanh asinh) @@ -296,7 +295,7 @@ (defknown atan (number &optional real) irrational - (movable foldable flushable explicit-check recursive)) + (movable foldable unsafely-flushable explicit-check recursive)) (defknown (tan sinh cosh tanh asinh) (number) irrational (movable foldable flushable explicit-check recursive)) @@ -400,7 +399,7 @@ char-lessp char-greaterp char-not-greaterp char-not-lessp) (character &rest character) boolean (movable foldable flushable)) -(defknown character (t) character (movable foldable flushable)) +(defknown character (t) character (movable foldable unsafely-flushable)) (defknown char-code (character) char-code (movable foldable flushable)) (defknown (char-upcase char-downcase) (character) character (movable foldable flushable)) @@ -423,7 +422,7 @@ ;;;; from the "Sequences" chapter: -(defknown elt (sequence index) t (foldable flushable)) +(defknown elt (sequence index) t (foldable unsafely-flushable)) (defknown subseq (sequence index &optional sequence-end) consed-sequence (flushable) @@ -444,16 +443,16 @@ &key (:initial-element t)) consed-sequence - (movable flushable unsafe) + (movable unsafe) :derive-type (result-type-specifier-nth-arg 1)) (defknown concatenate (type-specifier &rest sequence) consed-sequence - (flushable) + () :derive-type (result-type-specifier-nth-arg 1)) (defknown (map %map) (type-specifier callable sequence &rest sequence) consed-sequence - (flushable call) + (call) ; :DERIVE-TYPE 'TYPE-SPEC-ARG1 ? Nope... (MAP NIL ...) returns NULL, not NIL. ) (defknown %map-to-list-arity-1 (callable sequence) list (flushable call)) @@ -466,10 +465,10 @@ ;;; returns the result from the predicate... (defknown some (callable sequence &rest sequence) t - (foldable flushable call)) + (foldable unsafely-flushable call)) (defknown (every notany notevery) (callable sequence &rest sequence) boolean - (foldable flushable call)) + (foldable unsafely-flushable call)) ;;; unsafe for :INITIAL-VALUE... (defknown reduce (callable @@ -561,14 +560,14 @@ (sequence &key (:test callable) (:test-not callable) (:start index) (:from-end t) (:end sequence-end) (:key callable)) consed-sequence - (flushable call) + (unsafely-flushable call) :derive-type (sequence-result-nth-arg 1)) (defknown delete-duplicates (sequence &key (:test callable) (:test-not callable) (:start index) (:from-end t) (:end sequence-end) (:key callable)) sequence - (flushable call) + (unsafely-flushable call) :derive-type (sequence-result-nth-arg 1)) (defknown find (t sequence &key (:test callable) (:test-not callable) @@ -623,7 +622,7 @@ (defknown merge (type-specifier sequence sequence callable &key (:key callable)) sequence - (flushable call) + (call) :derive-type (result-type-specifier-nth-arg 1)) ;;; not FLUSHABLE, despite what CMU CL's DEFKNOWN said.. @@ -643,23 +642,28 @@ :derive-type (sequence-result-nth-arg 1)) ;;;; from the "Manipulating List Structure" chapter: -(defknown (car cdr caar cadr cdar cddr - caaar caadr cadar caddr cdaar cdadr cddar cdddr - caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr - cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar cddddr - first second third fourth fifth sixth seventh eighth ninth tenth - rest) +(defknown (car cdr first rest) (list) t (foldable flushable)) +(defknown (caar cadr cdar cddr + caaar caadr cadar caddr cdaar cdadr cddar cdddr + caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr + cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar cddddr + second third fourth fifth sixth seventh eighth ninth tenth) + (list) + t + (foldable unsafely-flushable)) + (defknown cons (t t) cons (movable flushable unsafe)) (defknown tree-equal (t t &key (:test callable) (:test-not callable)) boolean (foldable flushable call)) -(defknown endp (t) boolean (foldable flushable movable)) -(defknown list-length (list) (or index null) (foldable flushable)) -(defknown (nth nthcdr) (index list) t (foldable flushable)) +(defknown endp (t) boolean (foldable unsafely-flushable movable)) +(defknown list-length (list) (or index null) (foldable unsafely-flushable)) +(defknown nth (index list) t (foldable flushable)) +(defknown nthcdr (index list) t (foldable unsafely-flushable)) (defknown last (list &optional index) list (foldable flushable)) (defknown list (&rest t) list (movable flushable unsafe)) (defknown list* (t &rest t) t (movable flushable unsafe)) @@ -806,7 +810,7 @@ (defknown array-has-fill-pointer-p (array) boolean (movable foldable flushable)) -(defknown fill-pointer (vector) index (foldable flushable)) +(defknown fill-pointer (vector) index (foldable unsafely-flushable)) (defknown vector-push (t vector) (or index null) ()) (defknown vector-push-extend (t vector &optional index) index ()) (defknown vector-pop (vector) t ()) @@ -879,9 +883,9 @@ ;;;; from the "Streams" chapter: (defknown make-synonym-stream (symbol) stream (flushable)) -(defknown make-broadcast-stream (&rest stream) stream (flushable)) -(defknown make-concatenated-stream (&rest stream) stream (flushable)) -(defknown make-two-way-stream (stream stream) stream (flushable)) +(defknown make-broadcast-stream (&rest stream) stream (unsafely-flushable)) +(defknown make-concatenated-stream (&rest stream) stream (unsafely-flushable)) +(defknown make-two-way-stream (stream stream) stream (unsafely-flushable)) (defknown make-echo-stream (stream stream) stream (flushable)) (defknown make-string-input-stream (string &optional index index) stream (flushable unsafe)) @@ -1047,7 +1051,7 @@ (defknown load-logical-pathname-translations (string) t ()) (defknown logical-pathname-translations (logical-host-designator) list ()) -(defknown pathname (pathname-designator) pathname ()) +(defknown pathname (pathname-designator) pathname (unsafely-flushable)) (defknown truename (pathname-designator) pathname ()) (defknown parse-namestring @@ -1064,7 +1068,7 @@ (defknown merge-pathnames (pathname-designator &optional pathname-designator pathname-version) pathname - ()) + (unsafely-flushable)) (defknown make-pathname (&key (:defaults pathname-designator) @@ -1074,35 +1078,35 @@ (:name (or pathname-name string (member :wild))) (:type (or pathname-type string (member :wild))) (:version pathname-version) (:case (member :local :common))) - pathname ()) + pathname (unsafely-flushable)) (defknown pathnamep (t) boolean (movable flushable)) (defknown pathname-host (pathname-designator &key (:case (member :local :common))) - pathname-host ()) + pathname-host (flushable)) (defknown pathname-device (pathname-designator &key (:case (member :local :common))) - pathname-device ()) + pathname-device (flushable)) (defknown pathname-directory (pathname-designator &key (:case (member :local :common))) - pathname-directory ()) + pathname-directory (flushable)) (defknown pathname-name (pathname-designator &key (:case (member :local :common))) - pathname-name ()) + pathname-name (flushable)) (defknown pathname-type (pathname-designator &key (:case (member :local :common))) - pathname-type ()) + pathname-type (flushable)) (defknown pathname-version (pathname-designator) - pathname-version ()) + pathname-version (flushable)) (defknown (namestring file-namestring directory-namestring host-namestring) (pathname-designator) simple-string - ()) + (unsafely-flushable)) (defknown enough-namestring (pathname-designator &optional pathname-designator) simple-string - ()) + (unsafely-flushable)) (defknown user-homedir-pathname (&optional t) pathname (flushable)) @@ -1129,7 +1133,7 @@ (defknown file-position (stream &optional (or unsigned-byte (member :start :end))) (or unsigned-byte (member t nil))) -(defknown file-length (stream) (or unsigned-byte null) (flushable)) +(defknown file-length (stream) (or unsigned-byte null) (unsafely-flushable)) (defknown load ((or filename stream) diff --git a/src/compiler/ir1opt.lisp b/src/compiler/ir1opt.lisp index edd5cc4..98f4d9b 100644 --- a/src/compiler/ir1opt.lisp +++ b/src/compiler/ir1opt.lisp @@ -441,13 +441,25 @@ (let ((info (combination-kind node))) (when (fun-info-p info) (let ((attr (fun-info-attributes info))) - (when (and (ir1-attributep attr flushable) + (when (and (not (ir1-attributep attr call)) ;; ### For now, don't delete potentially ;; flushable calls when they have the CALL ;; attribute. Someday we should look at the ;; functional args to determine if they have ;; any side effects. - (not (ir1-attributep attr call))) + (if (policy node (= safety 3)) + (and (ir1-attributep attr flushable) + (every (lambda (arg) + (member (continuation-type-check arg) + '(nil :deleted))) + (basic-combination-args node)) + (valid-fun-use node + (info :function :type + (leaf-source-name (ref-leaf (continuation-use (basic-combination-fun node))))) + :result-test #'always-subtypep + :lossage-fun nil + :unwinnage-fun nil)) + (ir1-attributep attr unsafely-flushable))) (flush-dest (combination-fun node)) (dolist (arg (combination-args node)) (flush-dest arg)) diff --git a/src/compiler/ir1util.lisp b/src/compiler/ir1util.lisp index 926e183..e6637c1 100644 --- a/src/compiler/ir1util.lisp +++ b/src/compiler/ir1util.lisp @@ -469,7 +469,10 @@ `(when (eq (,slot last) old) (setf (,slot last) new)))) (frob if-consequent) - (frob if-alternative)))) + (frob if-alternative) + (when (eq (if-consequent last) + (if-alternative last)) + (setf (component-reoptimize (block-component block)) t))))) (t (unless (member new (block-succ block) :test #'eq) (link-blocks block new))))) diff --git a/src/compiler/knownfun.lisp b/src/compiler/knownfun.lisp index ea1ec4a..78433e0 100644 --- a/src/compiler/knownfun.lisp +++ b/src/compiler/knownfun.lisp @@ -49,15 +49,23 @@ ;; mark these functions as foldable in this database. foldable ;; 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. + ;; effects except possibly cons. If a function might signal errors, + ;; then it is not flushable even if it is movable, foldable or + ;; unsafely-flushable. Implies UNSAFELY-FLUSHABLE. flushable + ;; unsafe call may be eliminated if value is unused. The function + ;; has no side effects except possibly cons and signalling an error + ;; in the safe code. If a function MUST signal errors, then it is + ;; not unsafely-flushable even if it is movable or foldable. + unsafely-flushable ;; may be moved with impunity. Has no side effects except possibly ;; consing, and is affected only by its arguments. movable ;; The function is a true predicate likely to be open-coded. Convert - ;; any non-conditional uses into (IF T NIL). + ;; any non-conditional uses into (IF T NIL). Not usually + ;; specified to DEFKNOWN, since this is implementation dependent, + ;; and is usually automatically set by the DEFINE-VOP :CONDITIONAL + ;; option. predicate ;; Inhibit any warning for compiling a recursive definition. ;; (Normally the compiler warns when compiling a recursive diff --git a/src/compiler/macros.lisp b/src/compiler/macros.lisp index 0a5d134..197ffbe 100644 --- a/src/compiler/macros.lisp +++ b/src/compiler/macros.lisp @@ -447,66 +447,28 @@ ;;; 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 diff --git a/tests/compiler.pure.lisp b/tests/compiler.pure.lisp index c54e61e..07872ae 100644 --- a/tests/compiler.pure.lisp +++ b/tests/compiler.pure.lisp @@ -177,3 +177,19 @@ (let ((f (compile nil '(lambda (x) (make-array 1 :element-type '(0)))))) (assert (null (ignore-errors (funcall f))))) + +;;; the following functions must not be flushable +(dolist (form '((make-sequence 'fixnum 10) + (concatenate 'fixnum nil) + (map 'fixnum #'identity nil) + (merge 'fixnum nil nil #'<))) + (assert (not (eval `(locally (declare (optimize (safety 0))) + (ignore-errors (progn ,form t))))))) + +(dolist (form '(#+nil(values-list '(1 . 2)) ; This case still fails + (fboundp '(set bet)) + (atan #c(1 1) (car (list #c(2 2)))) + (nthcdr (car (list (floor (cos 3)))) '(1 2 3 4 5)) + (nthcdr (car (list 5)) '(1 2 . 3)))) + (assert (not (eval `(locally (declare (optimize (safety 3))) + (ignore-errors (progn ,form t))))))) diff --git a/version.lisp-expr b/version.lisp-expr index a977e77..0488bbc 100644 --- a/version.lisp-expr +++ b/version.lisp-expr @@ -18,4 +18,4 @@ ;;; internal versions off the main CVS branch, it gets hairier, e.g. ;;; "0.pre7.14.flaky4.13".) -"0.7.7.34" +"0.7.7.35" -- 1.7.10.4