X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=tests%2Fcompiler.pure.lisp;h=b809242c958b44d5dc82a021a99c09efc650af3e;hb=d84b1f2bb797f2e9d1d727e8424d01abe718a47c;hp=089871f560838aea639e9fb37d626c0c76824044;hpb=7485a0eb6bd09d24fd22c93c7ae713e3e5a245a2;p=sbcl.git diff --git a/tests/compiler.pure.lisp b/tests/compiler.pure.lisp index 089871f..b809242 100644 --- a/tests/compiler.pure.lisp +++ b/tests/compiler.pure.lisp @@ -2949,6 +2949,87 @@ `(lambda (x y z) (make-array '3 :initial-contents `(,x ,y ,z)))))))) +;;; optimizing array-in-bounds-p +(with-test (:name :optimize-array-in-bounds-p) + (locally + (macrolet ((find-callees (&body body) + `(ctu:find-named-callees + (compile nil + '(lambda () + ,@body)) + :name 'array-in-bounds-p)) + (must-optimize (&body exprs) + `(progn + ,@(loop for expr in exprs + collect `(assert (not (find-callees + ,expr)))))) + (must-not-optimize (&body exprs) + `(progn + ,@(loop for expr in exprs + collect `(assert (find-callees + ,expr)))))) + (must-optimize + ;; in bounds + (let ((a (make-array '(1)))) + (array-in-bounds-p a 0)) + ;; exceeds upper bound (constant) + (let ((a (make-array '(1)))) + (array-in-bounds-p a 1)) + ;; exceeds upper bound (interval) + (let ((a (make-array '(1)))) + (array-in-bounds-p a (+ 1 (random 2)))) + ;; negative lower bound (constant) + (let ((a (make-array '(1)))) + (array-in-bounds-p a -1)) + ;; negative lower bound (interval) + (let ((a (make-array 3)) + (i (- (random 1) 20))) + (array-in-bounds-p a i)) + ;; multiple known dimensions + (let ((a (make-array '(1 1)))) + (array-in-bounds-p a 0 0)) + ;; union types + (let ((s (the (simple-string 10) (eval "0123456789")))) + (array-in-bounds-p s 9))) + (must-not-optimize + ;; don't trust non-simple array length in safety=1 + (let ((a (the (array * (10)) (make-array 10 :adjustable t)))) + (eval `(adjust-array ,a 0)) + (array-in-bounds-p a 9)) + ;; same for a union type + (let ((s (the (string 10) (make-array 10 + :element-type 'character + :adjustable t)))) + (eval `(adjust-array ,s 0)) + (array-in-bounds-p s 9)) + ;; single unknown dimension + (let ((a (make-array (random 20)))) + (array-in-bounds-p a 10)) + ;; multiple unknown dimensions + (let ((a (make-array (list (random 20) (random 5))))) + (array-in-bounds-p a 5 2)) + ;; some other known dimensions + (let ((a (make-array (list 1 (random 5))))) + (array-in-bounds-p a 0 2)) + ;; subscript might be negative + (let ((a (make-array 5))) + (array-in-bounds-p a (- (random 3) 2))) + ;; subscript might be too large + (let ((a (make-array 5))) + (array-in-bounds-p a (random 6))) + ;; unknown upper bound + (let ((a (make-array 5))) + (array-in-bounds-p a (get-universal-time))) + ;; unknown lower bound + (let ((a (make-array 5))) + (array-in-bounds-p a (- (get-universal-time)))) + ;; in theory we should be able to optimize + ;; the following but the current implementation + ;; doesn't cut it because the array type's + ;; dimensions get reported as (* *). + (let ((a (make-array (list (random 20) 1)))) + (array-in-bounds-p a 5 2)))))) + ;;; optimizing (EXPT -1 INTEGER) (test-util:with-test (:name (expt minus-one integer)) (dolist (x '(-1 -1.0 -1.0d0)) @@ -3130,3 +3211,357 @@ (test `(lambda (x) (declare (double-float x)) (* x 2)) 123.45d0 246.9d0) (test `(lambda (x) (declare (double-float x)) (* x 2.0)) 543.21d0 1086.42d0) (test `(lambda (x) (declare (double-float x)) (* x 2.0d0)) 42.0d0 84.0d0))) + +(with-test (:name :bug-392203) + ;; Used to hit an AVER in COMVERT-MV-CALL. + (assert (zerop + (funcall + (compile nil + `(lambda () + (flet ((k (&rest x) (declare (ignore x)) 0)) + (multiple-value-call #'k #'k)))))))) + +(with-test (:name :allocate-closures-failing-aver) + (let ((f (compile nil `(lambda () + (labels ((k (&optional x) #'k))))))) + (assert (null (funcall f))))) + +(with-test (:name :flush-vector-creation) + (let ((f (compile nil `(lambda () + (dotimes (i 1024) + (vector i i i)) + t)))) + (ctu:assert-no-consing (funcall f)))) + +(with-test (:name :array-type-predicates) + (dolist (et sb-kernel::*specialized-array-element-types*) + (when et + (let* ((v (make-array 3 :element-type et)) + (fun (compile nil `(lambda () + (list + (if (typep ,v '(simple-array ,et (*))) + :good + :bad) + (if (typep (elt ,v 0) '(simple-array ,et (*))) + :bad + :good)))))) + (assert (equal '(:good :good) (funcall fun))))))) + +(with-test (:name :truncate-float) + (let ((s (compile nil `(lambda (x) + (declare (single-float x)) + (truncate x)))) + (d (compile nil `(lambda (x) + (declare (double-float x)) + (truncate x)))) + (s-inlined (compile nil '(lambda (x) + (declare (type (single-float 0.0s0 1.0s0) x)) + (truncate x)))) + (d-inlined (compile nil '(lambda (x) + (declare (type (double-float 0.0d0 1.0d0) x)) + (truncate x))))) + ;; Check that there is no generic arithmetic + (assert (not (search "GENERIC" + (with-output-to-string (out) + (disassemble s :stream out))))) + (assert (not (search "GENERIC" + (with-output-to-string (out) + (disassemble d :stream out))))) + ;; Check that we actually inlined the call when we were supposed to. + (assert (not (search "UNARY-TRUNCATE" + (with-output-to-string (out) + (disassemble s-inlined :stream out))))) + (assert (not (search "UNARY-TRUNCATE" + (with-output-to-string (out) + (disassemble d-inlined :stream out))))))) + +(with-test (:name :make-array-unnamed-dimension-leaf) + (let ((fun (compile nil `(lambda (stuff) + (make-array (map 'list 'length stuff)))))) + (assert (equalp #2A((0 0 0) (0 0 0)) + (funcall fun '((1 2) (1 2 3))))))) + +(with-test (:name :fp-decoding-funs-not-flushable-in-safe-code) + (dolist (name '(float-sign float-radix float-digits float-precision decode-float + integer-decode-float)) + (let ((fun (compile nil `(lambda (x) + (declare (optimize safety)) + (,name x) + nil)))) + (flet ((test (arg) + (unless (eq :error + (handler-case + (funcall fun arg) + (error () :error))) + (error "(~S ~S) did not error" + name arg)))) + ;; No error + (funcall fun 1.0) + ;; Error + (test 'not-a-float) + (when (member name '(decode-float integer-decode-float)) + (test sb-ext:single-float-positive-infinity)))))) + +(with-test (:name :sap-ref-16) + (let* ((fun (compile nil `(lambda (x y) + (declare (type sb-sys:system-area-pointer x) + (type (integer 0 100) y)) + (sb-sys:sap-ref-16 x (+ 4 y))))) + (vector (coerce '(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) + '(simple-array (unsigned-byte 8) (*)))) + (sap (sb-sys:vector-sap vector)) + (ret (funcall fun sap 0))) + ;; test for either endianness + (assert (or (= ret (+ (* 5 256) 4)) (= ret (+ (* 4 256) 5)))))) + +(with-test (:name :coerce-type-warning) + (dolist (type '(t (unsigned-byte 8) (unsigned-byte 16) (unsigned-byte 32) + (signed-byte 8) (signed-byte 16) (signed-byte 32))) + (multiple-value-bind (fun warningsp failurep) + (compile nil `(lambda (x) + (declare (type simple-vector x)) + (coerce x '(vector ,type)))) + (assert (null warningsp)) + (assert (null failurep)) + (assert (typep (funcall fun #(1)) `(simple-array ,type (*))))))) + +(with-test (:name :truncate-double-float) + (let ((fun (compile nil `(lambda (x) + (multiple-value-bind (q r) + (truncate (coerce x 'double-float)) + (declare (type unsigned-byte q) + (type double-float r)) + (list q r)))))) + (assert (equal (funcall fun 1.0d0) '(1 0.0d0))))) + +(with-test (:name :set-slot-value-no-warning) + (let ((notes 0)) + (handler-bind ((warning #'error) + (sb-ext:compiler-note (lambda (c) + (declare (ignore c)) + (incf notes)))) + (compile nil `(lambda (x y) + (declare (optimize speed safety)) + (setf (slot-value x 'bar) y)))) + (assert (= 1 notes)))) + +(with-test (:name :concatenate-string-opt) + (flet ((test (type grep) + (let* ((fun (compile nil `(lambda (a b c d e) + (concatenate ',type a b c d e)))) + (args '("foo" #(#\.) "bar" (#\-) "quux")) + (res (apply fun args))) + (assert (search grep (with-output-to-string (out) + (disassemble fun :stream out)))) + (assert (equal (apply #'concatenate type args) + res)) + (assert (typep res type))))) + (test 'string "%CONCATENATE-TO-STRING") + (test 'simple-string "%CONCATENATE-TO-STRING") + (test 'base-string "%CONCATENATE-TO-BASE-STRING") + (test 'simple-base-string "%CONCATENATE-TO-BASE-STRING"))) + +(with-test (:name :satisfies-no-local-fun) + (let ((fun (compile nil `(lambda (arg) + (labels ((local-not-global-bug (x) + t) + (bar (x) + (typep x '(satisfies local-not-global-bug)))) + (bar arg)))))) + (assert (eq 'local-not-global-bug + (handler-case + (funcall fun 42) + (undefined-function (c) + (cell-error-name c))))))) + +;;; Prior to 1.0.32.x, dumping a fasl with a function with a default +;;; argument that is a complex structure (needing make-load-form +;;; processing) failed an AVER. The first attempt at a fix caused +;;; doing the same in-core to break. +(with-test (:name :bug-310132) + (compile nil '(lambda (&optional (foo #p"foo/bar"))))) + +(with-test (:name :bug-309129) + (let* ((src '(lambda (v) (values (svref v 0) (vector-pop v)))) + (warningp nil) + (fun (handler-bind ((warning (lambda (c) + (setf warningp t) (muffle-warning c)))) + (compile nil src)))) + (assert warningp) + (handler-case (funcall fun #(1)) + (type-error (c) + ;; we used to put simply VECTOR into EXPECTED-TYPE, rather + ;; than explicitly (AND VECTOR (NOT SIMPLE-ARRAY)) + (assert (not (typep (type-error-datum c) (type-error-expected-type c))))) + (:no-error (&rest values) + (declare (ignore values)) + (error "no error"))))) + +(with-test (:name :unary-round-type-derivation) + (let* ((src '(lambda (zone) + (multiple-value-bind (h m) (truncate (abs zone) 1.0) + (declare (ignore h)) + (round (* 60.0 m))))) + (fun (compile nil src))) + (assert (= (funcall fun 0.5) 30)))) + +(with-test (:name :bug-525949) + (let* ((src '(lambda () + (labels ((always-one () 1) + (f (z) + (let ((n (funcall z))) + (declare (fixnum n)) + (the double-float (expt n 1.0d0))))) + (f #'always-one)))) + (warningp nil) + (fun (handler-bind ((warning (lambda (c) + (setf warningp t) (muffle-warning c)))) + (compile nil src)))) + (assert (not warningp)) + (assert (= 1.0d0 (funcall fun))))) + +(with-test (:name :%array-data-vector-type-derivation) + (let* ((f (compile nil + `(lambda (ary) + (declare (type (simple-array (unsigned-byte 32) (3 3)) ary)) + (setf (aref ary 0 0) 0)))) + (text (with-output-to-string (s) + (disassemble f :stream s)))) + (assert (not (search "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-BYTE-32-ERROR" text))))) + +(with-test (:name :array-storage-vector-type-derivation) + (let ((f (compile nil + `(lambda (ary) + (declare (type (simple-array (unsigned-byte 32) (3 3)) ary)) + (ctu:compiler-derived-type (array-storage-vector ary)))))) + (assert (equal '(simple-array (unsigned-byte 32) (9)) + (funcall f (make-array '(3 3) :element-type '(unsigned-byte 32))))))) + +(with-test (:name :bug-523612) + (let ((fun + (compile nil + `(lambda (&key toff) + (make-array 3 :element-type 'double-float + :initial-contents + (if toff (list toff 0d0 0d0) (list 0d0 0d0 0d0))))))) + (assert (equalp (vector 0.0d0 0.0d0 0.0d0) (funcall fun :toff nil))) + (assert (equalp (vector 2.3d0 0.0d0 0.0d0) (funcall fun :toff 2.3d0))))) + +(with-test (:name :bug-309788) + (let ((fun + (compile nil + `(lambda (x) + (declare (optimize speed)) + (let ((env nil)) + (typep x 'fixnum env)))))) + (assert (not (ctu:find-named-callees fun))))) + +(with-test (:name :bug-309124) + (let ((fun + (compile nil + `(lambda (x) + (declare (integer x)) + (declare (optimize speed)) + (cond ((typep x 'fixnum) + "hala") + ((typep x 'fixnum) + "buba") + ((typep x 'bignum) + "hip") + (t + "zuz")))))) + (assert (equal (list "hala" "hip") + (sort (ctu:find-code-constants fun :type 'string) + #'string<))))) + +(with-test (:name :bug-316078) + (let ((fun + (compile nil + `(lambda (x) + (declare (type (and simple-bit-vector (satisfies bar)) x) + (optimize speed)) + (elt x 5))))) + (assert (not (ctu:find-named-callees fun))) + (assert (= 1 (funcall fun #*000001))) + (assert (= 0 (funcall fun #*000010))))) + +(with-test (:name :mult-by-one-in-float-acc-zero) + (assert (eql 1.0 (funcall (compile nil `(lambda (x) + (declare (optimize (sb-c::float-accuracy 0))) + (* x 1.0))) + 1))) + (assert (eql -1.0 (funcall (compile nil `(lambda (x) + (declare (optimize (sb-c::float-accuracy 0))) + (* x -1.0))) + 1))) + (assert (eql 1.0d0 (funcall (compile nil `(lambda (x) + (declare (optimize (sb-c::float-accuracy 0))) + (* x 1.0d0))) + 1))) + (assert (eql -1.0d0 (funcall (compile nil `(lambda (x) + (declare (optimize (sb-c::float-accuracy 0))) + (* x -1.0d0))) + 1)))) + +(with-test (:name :dotimes-non-integer-counter-value) + (assert (raises-error? (dotimes (i 8.6)) type-error))) + +(with-test (:name :bug-454681) + ;; This used to break due to reference to a dead lambda-var during + ;; inline expansion. + (assert (compile nil + `(lambda () + (multiple-value-bind (iterator+977 getter+978) + (does-not-exist-but-does-not-matter) + (flet ((iterator+976 () + (funcall iterator+977))) + (declare (inline iterator+976)) + (let ((iterator+976 #'iterator+976)) + (funcall iterator+976)))))))) + +(with-test (:name :complex-float-local-fun-args) + ;; As of 1.0.27.14, the lambda below failed to compile due to the + ;; compiler attempting to pass unboxed complex floats to Z and the + ;; MOVE-ARG method not expecting the register being used as a + ;; temporary frame pointer. Reported by sykopomp in #lispgames, + ;; reduced test case provided by _3b`. + (compile nil '(lambda (a) + (labels ((z (b c) + (declare ((complex double-float) b c)) + (* b (z b c)))) + (loop for i below 10 do + (setf a (z a a))))))) + +(with-test (:name :bug-309130) + (assert (eq :warning + (handler-case + (compile nil `(lambda () (svref (make-array 8 :adjustable t) 1))) + ((and warning (not style-warning)) () + :warning)))) + (assert (eq :warning + (handler-case + (compile nil `(lambda (x) + (declare (optimize (debug 0))) + (declare (type vector x)) + (list (fill-pointer x) (svref x 1)))) + ((and warning (not style-warning)) () + :warning)))) + (assert (eq :warning + (handler-case + (compile nil `(lambda (x) + (list (vector-push (svref x 0) x)))) + ((and warning (not style-warning)) () + :warning)))) + (assert (eq :warning + (handler-case + (compile nil `(lambda (x) + (list (vector-push-extend (svref x 0) x)))) + ((and warning (not style-warning)) () + :warning))))) + +(with-test (:name :bug) + (assert 42 + (funcall + (compile nil + `(lambda () + (load-time-value (the (values fixnum) 42)))))))