+
;;;; various compiler tests without side effects
;;;; This software is part of the SBCL system. See the README file for
;;; on the PPC, we got the magic numbers in undefined_tramp wrong for
;;; a while; fixed by CSR 2002-07-18
-(multiple-value-bind (value error)
- (ignore-errors (some-undefined-function))
- (assert (null value))
- (assert (eq (cell-error-name error) 'some-undefined-function)))
+(with-test (:name :undefined-function-error)
+ (multiple-value-bind (value error)
+ (ignore-errors (some-undefined-function))
+ (assert (null value))
+ (assert (eq (cell-error-name error) 'some-undefined-function))))
;;; Non-symbols shouldn't be allowed as VARs in lambda lists. (Where VAR
;;; is a variable name, as in section 3.4.1 of the ANSI spec.)
(declare (type (alien (* (unsigned 8))) a)
(type (unsigned-byte 32) i))
(deref a i))))
- (compiler-note () (error "The code is not optimized.")))
+ (compiler-note (c)
+ (unless (search "%ASH/RIGHT" (first (simple-condition-format-arguments c)))
+ (error "The code is not optimized."))))
(handler-case
(compile nil '(lambda (x)
(array-in-bounds-p a 5 2))))))
;;; optimizing (EXPT -1 INTEGER)
-(test-util:with-test (:name (expt minus-one integer))
+(with-test (:name (expt minus-one integer))
(dolist (x '(-1 -1.0 -1.0d0))
(let ((fun (compile nil `(lambda (x) (expt ,x (the fixnum x))))))
(assert (not (ctu:find-named-callees fun)))
(let ((test-cases
'((lambda () (append 10)) (integer 10 10)
(lambda () (append nil 10)) (integer 10 10)
- (lambda (x) (append x 10)) t
+ (lambda (x) (append x 10)) (or (integer 10 10) cons)
(lambda (x) (append x (cons 1 2))) cons
(lambda (x y) (append x (cons 1 2) y)) cons
(lambda (x y) (nconc x (the list y) x)) t
- (lambda (x y) (print (length y)) (append x y)) sequence)))
+ (lambda (x y) (nconc (the atom x) y)) t
+ (lambda (x y) (nconc (the (or null (eql 10)) x) y)) t
+ (lambda (x y) (nconc (the (or cons vector) x) y)) cons
+ (lambda (x y) (nconc (the sequence x) y)) t
+ (lambda (x y) (print (length y)) (append x y)) sequence
+ (lambda (x y) (print (length y)) (append x y)) sequence
+ (lambda (x y) (append (the (member (a) (b)) x) y)) cons
+ (lambda (x y) (append (the (member (a) (b) c) x) y)) cons
+ (lambda (x y) (append (the (member (a) (b) nil) x) y)) t)))
(loop for (function result-type) on test-cases by #'cddr
- do (assert (equal (car (cdaddr (sb-kernel:%simple-fun-type
- (compile nil function))))
- result-type)))))
+ do (assert (sb-kernel:type= (sb-kernel:specifier-type
+ (car (cdaddr (sb-kernel:%simple-fun-type
+ (compile nil function)))))
+ (sb-kernel:specifier-type result-type))))))
(with-test (:name :bug-504121)
(compile nil `(lambda (s)
(let ((hash #xD13CCD13))
(setf hash (logand most-positive-word
(ash hash 5)))))))
+
+(with-test (:name (local-&optional-recursive-inline :bug-1180992))
+ (compile nil
+ `(lambda ()
+ (labels ((called (&optional a))
+ (recursed (&optional b)
+ (called)
+ (recursed)))
+ (declare (inline recursed called))
+ (recursed)))))
+
+(with-test (:name :constant-fold-logtest)
+ (assert (equal (sb-kernel:%simple-fun-type
+ (compile nil `(lambda (x)
+ (declare (type (mod 1024) x)
+ (optimize speed))
+ (logtest x 2048))))
+ '(function ((unsigned-byte 10)) (values null &optional)))))
+
+;; type mismatches on LVARs with multiple potential sources used to
+;; be reported as mismatches with the value NIL. Make sure we get
+;; a warning, but that it doesn't complain about a constant NIL ...
+;; of type FIXNUM.
+(with-test (:name (:multiple-use-lvar-interpreted-as-NIL cast))
+ (block nil
+ (handler-bind ((sb-int:type-warning
+ (lambda (c)
+ (assert
+ (not (search "Constant "
+ (simple-condition-format-control
+ c))))
+ (return))))
+ (compile nil `(lambda (x y z)
+ (declare (type fixnum y z))
+ (aref (if x y z) 0))))
+ (error "Where's my warning?")))
+
+(with-test (:name (:multiple-use-lvar-interpreted-as-NIL catch))
+ (block nil
+ (handler-bind ((style-warning
+ (lambda (c)
+ (assert
+ (not (position
+ nil
+ (simple-condition-format-arguments c))))
+ (return))))
+ (compile nil `(lambda (x y z f)
+ (declare (type fixnum y z))
+ (catch (if x y z) (funcall f)))))
+ (error "Where's my style-warning?")))
+
+;; Smoke test for rightward shifts
+(with-test (:name (:ash/right-signed))
+ (let* ((f (compile nil `(lambda (x y)
+ (declare (type (mod ,(* 2 sb-vm:n-word-bits)) y)
+ (type sb-vm:signed-word x)
+ (optimize speed))
+ (ash x (- y)))))
+ (max (ash most-positive-word -1))
+ (min (- -1 max)))
+ (flet ((test (x y)
+ (assert (= (ash x (- y))
+ (funcall f x y)))))
+ (dotimes (x 32)
+ (dotimes (y (* 2 sb-vm:n-word-bits))
+ (test x y)
+ (test (- x) y)
+ (test (- max x) y)
+ (test (+ min x) y))))))
+
+(with-test (:name (:ash/right-unsigned))
+ (let ((f (compile nil `(lambda (x y)
+ (declare (type (mod ,(* 2 sb-vm:n-word-bits)) y)
+ (type word x)
+ (optimize speed))
+ (ash x (- y)))))
+ (max most-positive-word))
+ (flet ((test (x y)
+ (assert (= (ash x (- y))
+ (funcall f x y)))))
+ (dotimes (x 32)
+ (dotimes (y (* 2 sb-vm:n-word-bits))
+ (test x y)
+ (test (- max x) y))))))
+
+(with-test (:name (:ash/right-fixnum))
+ (let ((f (compile nil `(lambda (x y)
+ (declare (type (mod ,(* 2 sb-vm:n-word-bits)) y)
+ (type fixnum x)
+ (optimize speed))
+ (ash x (- y))))))
+ (flet ((test (x y)
+ (assert (= (ash x (- y))
+ (funcall f x y)))))
+ (dotimes (x 32)
+ (dotimes (y (* 2 sb-vm:n-word-bits))
+ (test x y)
+ (test (- x) y)
+ (test (- most-positive-fixnum x) y)
+ (test (+ most-negative-fixnum x) y))))))
+
+;; expected failure
+(with-test (:name :fold-index-addressing-positive-offset)
+ (let ((f (compile nil `(lambda (i)
+ (if (typep i '(integer -31 31))
+ (aref #. (make-array 63) (+ i 31))
+ (error "foo"))))))
+ (funcall f -31)))
+
+;; 5d3a728 broke something like this in CL-PPCRE
+(with-test (:name :fold-index-addressing-potentially-negative-index)
+ (compile nil `(lambda (index vector)
+ (declare (optimize speed (safety 0))
+ ((simple-array character (*)) vector)
+ ((unsigned-byte 24) index))
+ (aref vector (1+ (mod index (1- (length vector))))))))
+
+(with-test (:name :constant-fold-ash/right-fixnum)
+ (compile nil `(lambda (a b)
+ (declare (type fixnum a)
+ (type (integer * -84) b))
+ (ash a b))))
+
+(with-test (:name :constant-fold-ash/right-word)
+ (compile nil `(lambda (a b)
+ (declare (type word a)
+ (type (integer * -84) b))
+ (ash a b))))
+
+(with-test (:name :nconc-derive-type)
+ (let ((function (compile nil `(lambda (x y)
+ (declare (type (or cons fixnum) x))
+ (nconc x y)))))
+ (assert (equal (sb-kernel:%simple-fun-type function)
+ '(function ((or cons fixnum) t) (values cons &optional))))))
+
+;; make sure that all data-vector-ref-with-offset VOPs are either
+;; specialised on a 0 offset or accept signed indices
+(with-test (:name :data-vector-ref-with-offset-signed-index)
+ (let ((dvr (find-symbol "DATA-VECTOR-REF-WITH-OFFSET" "SB-KERNEL")))
+ (when dvr
+ (assert
+ (null
+ (loop for info in (sb-c::fun-info-templates
+ (sb-c::fun-info-or-lose dvr))
+ for (nil second-arg third-arg) = (sb-c::vop-info-arg-types info)
+ unless (or (typep second-arg '(cons (eql :constant)))
+ (find '(integer 0 0) third-arg :test 'equal)
+ (equal second-arg
+ `(:or ,(sb-c::primitive-type-or-lose
+ 'sb-vm::positive-fixnum)
+ ,(sb-c::primitive-type-or-lose
+ 'fixnum))))
+ collect info))))))
+
+(with-test (:name :data-vector-set-with-offset-signed-index)
+ (let ((dvr (find-symbol "DATA-VECTOR-SET-WITH-OFFSET" "SB-KERNEL")))
+ (when dvr
+ (assert
+ (null
+ (loop for info in (sb-c::fun-info-templates
+ (sb-c::fun-info-or-lose dvr))
+ for (nil second-arg third-arg) = (sb-c::vop-info-arg-types info)
+ unless (or (typep second-arg '(cons (eql :constant)))
+ (find '(integer 0 0) third-arg :test 'equal)
+ (equal second-arg
+ `(:or ,(sb-c::primitive-type-or-lose
+ 'sb-vm::positive-fixnum)
+ ,(sb-c::primitive-type-or-lose
+ 'fixnum))))
+ collect info))))))
+
+(with-test (:name :maybe-inline-ref-to-dead-lambda)
+ (compile nil `(lambda (string)
+ (declare (optimize speed (space 0)))
+ (cond ((every #'digit-char-p string)
+ nil)
+ ((some (lambda (c)
+ (digit-char-p c))
+ string))))))
+
+;; the x87 backend used to sometimes signal FP errors during boxing,
+;; because converting between double and single float values was a
+;; noop (fixed), and no doubt many remaining issues. We now store
+;; the value outside pseudo-atomic, so any SIGFPE should be handled
+;; corrrectly.
+;;
+;; When it fails, this test lands into ldb.
+(with-test (:name :no-overflow-during-allocation)
+ (handler-case (eval '(cosh 90))
+ (floating-point-overflow ()
+ t)))
+
+;; unbounded integer types could break integer arithmetic.
+(with-test (:name :bug-1199127)
+ (compile nil `(lambda (b)
+ (declare (type (integer -1225923945345 -832450738898) b))
+ (declare (optimize (speed 3) (space 3) (safety 2)
+ (debug 0) (compilation-speed 1)))
+ (loop for lv1 below 3
+ sum (logorc2
+ (if (>= 0 lv1)
+ (ash b (min 25 lv1))
+ 0)
+ -2)))))
+
+;; non-trivial modular arithmetic operations would evaluate to wider results
+;; than expected, and never be cut to the right final bitwidth.
+(with-test (:name :bug-1199428-1)
+ (let ((f1 (compile nil `(lambda (a c)
+ (declare (type (integer -2 1217810089) a))
+ (declare (type (integer -6895591104928 -561736648588) c))
+ (declare (optimize (speed 2) (space 0) (safety 2) (debug 0)
+ (compilation-speed 3)))
+ (logandc1 (gcd c)
+ (+ (- a c)
+ (loop for lv2 below 1 count t))))))
+ (f2 (compile nil `(lambda (a c)
+ (declare (notinline - + gcd logandc1))
+ (declare (optimize (speed 1) (space 1) (safety 0) (debug 1)
+ (compilation-speed 3)))
+ (logandc1 (gcd c)
+ (+ (- a c)
+ (loop for lv2 below 1 count t)))))))
+ (let ((a 530436387)
+ (c -4890629672277))
+ (assert (eql (funcall f1 a c)
+ (funcall f2 a c))))))
+
+(with-test (:name :bug-1199428-2)
+ (let ((f1 (compile nil `(lambda (a b)
+ (declare (type (integer -1869232508 -6939151) a))
+ (declare (type (integer -11466348357 -2645644006) b))
+ (declare (optimize (speed 1) (space 0) (safety 2) (debug 2)
+ (compilation-speed 2)))
+ (logand (lognand a -6) (* b -502823994)))))
+ (f2 (compile nil `(lambda (a b)
+ (logand (lognand a -6) (* b -502823994))))))
+ (let ((a -1491588365)
+ (b -3745511761))
+ (assert (eql (funcall f1 a b)
+ (funcall f2 a b))))))
+
+;; win32 is very specific about the order in which catch blocks
+;; must be allocated on the stack
+(with-test (:name :bug-121581169)
+ (let ((f (compile nil
+ `(lambda ()
+ (STRING=
+ (LET ((% 23))
+ (WITH-OUTPUT-TO-STRING (G13908)
+ (PRINC
+ (LET ()
+ (DECLARE (OPTIMIZE (SB-EXT:INHIBIT-WARNINGS 3)))
+ (HANDLER-CASE
+ (WITH-OUTPUT-TO-STRING (G13909) (PRINC %A%B% G13909) G13909)
+ (UNBOUND-VARIABLE NIL
+ (HANDLER-CASE
+ (WITH-OUTPUT-TO-STRING (G13914)
+ (PRINC %A%B% G13914)
+ (PRINC "" G13914)
+ G13914)
+ (UNBOUND-VARIABLE NIL
+ (HANDLER-CASE
+ (WITH-OUTPUT-TO-STRING (G13913)
+ (PRINC %A%B G13913)
+ (PRINC "%" G13913)
+ G13913)
+ (UNBOUND-VARIABLE NIL
+ (HANDLER-CASE
+ (WITH-OUTPUT-TO-STRING (G13912)
+ (PRINC %A% G13912)
+ (PRINC "b%" G13912)
+ G13912)
+ (UNBOUND-VARIABLE NIL
+ (HANDLER-CASE
+ (WITH-OUTPUT-TO-STRING (G13911)
+ (PRINC %A G13911)
+ (PRINC "%b%" G13911)
+ G13911)
+ (UNBOUND-VARIABLE NIL
+ (HANDLER-CASE
+ (WITH-OUTPUT-TO-STRING (G13910)
+ (PRINC % G13910)
+ (PRINC "a%b%" G13910)
+ G13910)
+ (UNBOUND-VARIABLE NIL
+ (ERROR "Interpolation error in \"%a%b%\"
+"))))))))))))))
+ G13908)))
+ "23a%b%")))))
+ (assert (funcall f))))