From: Robert E. B. <bb...@sp...> - 2003-01-22 03:43:04
|
When I compile this code (defstruct trace-info (foo nil :type (or null function))) (defun good (x) (declare (optimize (speed 3) (safety 0))) (let ((wow (trace-info-foo x))) (and wow (funcall wow 1 2 3)))) (defun bad (x) (declare (optimize (speed 3) (safety 0))) (let ((wow (trace-info-foo x))) (or (not wow) (funcall wow 1 2 3)))) using SBCL version 0.7.11, the compiler generates the following warning: ; in: DEFUN BAD ; (FUNCALL WOW 1 2 3) ; --> SB-C::%FUNCALL ; ==> ; (SB-KERNEL:%COERCE-CALLABLE-TO-FUN FUNCTION) ; ; note: unable to ; optimize away possible call to FDEFINITION at runtime ; due to type uncertainty: ; The first argument is a (OR NULL FUNCTION), not a FUNCTION. No warning is generated for GOOD. In both cases, however, the compiler should be able to figure out that FUNCALL's first argument is a function. The two examples are symmetric. If there's a compiler pattern that understands the code in GOOD, there should also be one to recognize the code in BAD. |
From: Christophe R. <cs...@ca...> - 2003-01-22 09:25:51
|
"Robert E. Brown" <bb...@sp...> writes: > No warning is generated for GOOD. In both cases, however, the compiler > should be able to figure out that FUNCALL's first argument is a function. > The two examples are symmetric. If there's a compiler pattern that > understands the code in GOOD, there should also be one to recognize the code > in BAD. Alexey's added this case as #10 in the OPTIMIZATIONS file, which lists things we should do better; I just want to point out where the problem lies, and a possibly simple fix. * (macroexpand '(and x (funcall x))) (IF X (AND (FUNCALL X)) NIL) * (macroexpand '(or (not x) (funcall x))) (LET ((#:G1 (NOT X))) (IF #:G1 #:G1 (OR (FUNCALL X)))) So theh problem is presumably that Python is losing the constraint information that #:G1 is the negation of X (I haven't checked, but it's likely something along those lines). Obviously a complete solution to this is to improve the type inference engine to be smarter, but sometimes maybe a simple-minded solution is what is wanted [untested]: (defmacro-mundanely or (&rest forms) (cond ((endp forms) nil) ((endp (rest forms)) (first forms)) ((and (consp (first forms)) (eq (car (first forms)) 'not)) ;; FIXME: should signal an error if wrong number of args to NOT `(and ,(cadr (first forms)) (or ,@(rest forms)))) (t (let ((n-result (gensym))) `(let ((,n-result ,(first forms))) (if ,n-result ,n-result (or ,@(rest forms)))))))) Comments? Cheers, Christophe -- http://www-jcsu.jesus.cam.ac.uk/~csr21/ +44 1223 510 299/+44 7729 383 757 (set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b))) (defvar b "~&Just another Lisp hacker~%") (pprint #36rJesusCollegeCambridge) |