RE: Problem with locally, let and optimization
However, don't you think it is strange that if I use "locally" to tell the
compiler that I want something to be as fast as possible, and tell it the
types, it winds up generating code that is slower than if I tell the
compiler the same thing, in a slightly different way?
There is a general problem, that makes people like me want to use "locally"
in this way: it is against the standard for CL to allow macros to expand
into declarations.
So far the best solution that I have seen to making things compile with
non-default settings is a macro that expands into "locally".
E.g.
(defun foo (a)
(fast ...rest of stuff ...)
But in my case (and I would guess for everyone else, unless my my private
patches ruin things), it doesn't work.
In the following transcript, I define a macro that expands into a
declaration. It doesn't work. But the version where I explicity expand it
does work. This is in keeping with the behavior the standard specifies, and
demonstrates that a version of "locally" that worked nicely (and I believe
it would be acceptable according to cltl2) would be very helpful. I believe
that the current implementation (which appears to ignore my locally declared
declaration) is acceptable according to cltl2 too --- the compiler doesn't
have to use the information that you declare.
CL-USER 1 > (defmacro speed-only () `(declare (optimize (speed 3))))
SPEED-ONLY
CL-USER 2 > (defun foo () (speed-only) (print 2))
Error: Syntactic error in form (SPEED-ONLY):
Unexpexted DECLARE.
1 (abort) Return to level 0.
2 Return to top loop level 0.
Type :b for backtrace, :c <option number> to proceed, or :? for other
options
CL-USER 3 : 1 > :c 2
CL-USER 4 > (eval `(defun foo () ,(macroexpand '(speed-only)) (print 2)))
FOO
CL-USER 5 > (foo)
2
2
CL-USER 6 >
Heath
> -----Original Message-----
> From: Tim Bradshaw [SMTP:tfb@cley.com]
> Sent: Friday, November 15, 2002 3:19 PM
> To: Putnam, Heath (ext.)
> Cc: lisp-hug@xanalys.com
> Subject: Re: Problem with locally, let and optimization
>
> * Heath Putnam Extern wrote:
>
> > Does everyone get the same output for the two these? Or do you get
> > different output, like I do. Shouldn't these give the same output?
>
> > ;; slow version
> > (disassemble (compile nil '(lambda (a b)
> > (locally
> > (declare (optimize (speed 3) (float 0) (safety 0))
> > (type double-float a)
> > (type double-float b))
> > (the double-float (+ a b))))))
>
> > ;; fast version -- only boxes the result.
> > (disassemble (compile nil '(lambda (a b)
> > (declare (optimize (speed 3) (float 0) (safety
> > 0))
> > (type double-float a)
> > (type double-float b))
> > (the double-float (+ a b))
> > )))
>
> It's not clear to me that they are the same from the point of view of
> the language. In something like:
>
> (lambda (a)
> (declare (type x a) ...)
> ...)
>
> The declaration refers to the binding of A established by LAMBDA. In
> something like:
>
> (lambda (a)
> (locally
> (declare (type x a) ...)
> ...))
>
> I think that the declaration is free - it declares something about the
> type of A within its scope, but it doesn't declare the type of the
> binding.
>
> I *think* that in the specific case you mention, then a compiler could
> treat these two cases as the same - it could `raise' the declaration
> up to apply to the binding. I guess that LW doesn't do this.
>
> --tim
>
>
RE: Problem with locally, let and optimization
* Heath Putnam Extern wrote:
> However, don't you think it is strange that if I use "locally" to tell the
> compiler that I want something to be as fast as possible, and tell it the
> types, it winds up generating code that is slower than if I tell the
> compiler the same thing, in a slightly different way?
Yes, I think it's irritating. It's often fairly hard to get compilers
to really generate good code, and superficially tiny differences can
make a large difference in performance. One day compilers will be
smarter, I hope!
*However* I've realised that there is actually a fairly large semantic
difference between the LOCALLY version and the DECLARE-inside-LAMBDA
version: something like this:
(defun foo (x y)
(locally (declare (optimize (safety 0) speed ...))
...))
Is asking that the function *call* should check its arguments &c with
whatever the prevailing optimisation settings when it was compiled
was. Only then should it optimise stuff. This is different than:
(defun foo (x y)
(declare (optimize (safety 0) speed ...))
...)
Which says things about how the function call should be compiled.
One trick, which seems to work for LW is to rebind things locally, and
then apply declarations to those - something like this might be
useful:
(defvar *default-locally-typing-declarations* `((optimize speed (safety 0))))
(defmacro locally-typing (vars/decls &body decls/forms)
(multiple-value-bind (rebindings decls)
(loop for (var type) in vars/decls
collect `(,var ,var) into rebindings
collect `(type var ,type) into decls
finally (return (values rebindings decls)))
`(let ,rebindings
,(if (eq (first (first decls/forms)) 'declare)
`(declare ,@decls)
`(declare ,*default-locally-typing-declarations*
,@decls))
,@decls/forms)))
(locally-typing ((x double-float)
(y double-float))
...)
--tim