[armedbear-devel] compiler problem

Alan Ruttenberg alanruttenberg at gmail.com
Fri Jan 8 02:38:24 UTC 2010

On Thu, Jan 7, 2010 at 5:44 PM, Erik Huelsmann <ehuels at gmail.com> wrote:
> Hi Alan,
> On Thu, Jan 7, 2010 at 12:02 AM, Alan Ruttenberg
> <alanruttenberg at gmail.com> wrote:
>>> The error turned out to be in PRECOMPILE-LAMBDA and
>>> PRECOMPILE-NAMED-LAMBDA. Committed the fix in r12340 in trunk. This
>>> will be in 0.18.
>>> I think it would be a good idea to extend your inline-lambda-rewriter
>>> to be able to parse/rewrite all lambda lists, not only the ones with
>>> &rest arguments (did I see correctly that you restricted to that
>>> case?).
>> I did, for expediency. I don't know whether it will be worth doing it
>> for all lambda lists, and full lambda list processing is complicated.
>> I know that my code was using these forms - it might be worth seeing
>> whether there are any uses of more complicated forms. At some point
>> the additional cost of doing the lambda list processing relative to
>> the extra function call might not be worth it.
> But doesn't DESTRUCTURING-BIND already give us lambda-list processing
> for "free"? I mean, it's too lenient with processing the lambda list
> because it will allow all kinds of forms ordinary lambda lists won't
> allow, but it definitely parses them.
>> Don't mind doing a bit more on it if there are known cases that would benefit.
> I don't know which software uses this a lot, but I think it's just
> very nice to support the general case, if there's support to be
> written anyway.

Here are a couple of tests manually doing the transform. The tradeoff
for the simplistic version of this is that there will always be more

(defun lvd-restarg ()
  (declare (optimize (speed 3) (safety 0)))
  (let* ((a1 (random 100))
	 (b1 (1+ a1))
	 (c1 (1+ b1))
	 (d1 (1+ c1)))
    (flet ((bar (x y z) (setq s (+ x y (car z) (second z)) )))
      (time (dotimes (i 200000) ((lambda (a b &rest c &aux) (bar a b
c))  a1 b1 c1 d1))) ; force off current optimization
      (time (dotimes (i 200000) ((lambda (a b &rest c) (bar a b c))
a1 b1 c1 d1))) ; with current
      (time (dotimes (i 200000) (destructuring-bind (a b &rest c)
(list a1 b1 c1 d1) (bar a b c))))) ; proposed

(defun lvd-no-restarg ()
  (declare (optimize (speed 3) (safety 0)))
  (let* ((v1 (random 100))
	 (v2 (1+ v1))
	 (v3 (1+ v2))
	 (args (list v1 v2 :c v3))
	 (s nil))
    (time (setq s (dotimes (i 200000)
		    ((lambda (a &optional (b 2 b-supplied) &key (c 2)) (if
b-supplied (+ a b c))) v1  v2 :c v3))))
    (time (setq s (dotimes (i 200000)
		    (destructuring-bind (a &optional (b 2 b-supplied) &key (c 2))
args (+ a b c)))))

CL-USER> (jvm::lvd-no-restarg)
0.734 seconds real time
6 cons cells
0.181 seconds real time
200074 cons cells

1.486 seconds real time
400012 cons cells
0.663 seconds real time
400076 cons cells
0.653 seconds real time
800080 cons cells

The excess consing could be avoided if the expansion of the
destructuring bind (or a transform of it) could be smarter.

(destructuring-bind (a b &rest c) (list a1 b1 c1 d1) (bar a b c))
(LET ((#:ARG-LIST-30182 (LIST A1 B1 C1 D1)))
  (LET* ()
    (LET* ((A (CAR #:ARG-LIST-30182))
           (B (CAR (CDR #:ARG-LIST-30182)))
           (C (CDR (CDR #:ARG-LIST-30182))))
      (BAR A B C))))

The thing to notice is that
(CAR #:ARG-LIST-30182) -> (car (list a1 b1 c1 d1)) -> a1, etc.

I think it would be definitely worth doing the transform to
destructuring bind if the optimization to remove unnecessary consing
was done.

If not, I'm not sure. What do you or others think - is the time
savings worth the consing?

I will think about what's involved in doing that optimization.


More information about the armedbear-devel mailing list