[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: constant folding/smashing
- To: Kent M Pitman <KMP@STONY-BROOK.SCRC.Symbolics.COM>
- Subject: Re: constant folding/smashing
- From: Brad Miller <miller@ACORN.CS.ROCHESTER.EDU>
- Date: Wed, 8 Jun 88 16:49 EDT
- Cc: Common-Lisp@SAIL.Stanford.EDU, firstname.lastname@example.org, NGALL@g.bbn.com, email@example.com
- In-reply-to: <880607180851.3.KMP@PEWEE.SCRC.Symbolics.COM>
- Organization: University of Rochester, Department of Computer Science
- Phone: 716-275-1118
- Postal-address: 610 CS Building, Comp Sci Dept., U. Rochester, Rochester NY 14627
- Reply-to: firstname.lastname@example.org
- Sender: email@example.com
Date: Tue, 7 Jun 88 18:08 EDT
From: Kent M Pitman <KMP@STONY-BROOK.SCRC.Symbolics.COM>
I don't know what these primitives should be called, exactly, but here
are some straw-men for people to discuss:
#1: (QUOTE x) might mean X is not evaluated and is also read-only
and (IMMEDIATE x) might mean X is not evaluated but is NOT read-only.
#2: (QUOTE x) might mean X is not evaluated and NOT read-only
(CONSTANT x) might mean X is not evaluated and is also read-only.
How about #3: (QUOTE x) means X is not evaluated and is NOT read-only
(CONSTANT x) means X *is* evaluated and is read-only.
Thus the resulting objects from:
(CONSTANT '(A B C)) is a read-only list
'(A B C) isn't.
(constant (foo x)) evals the function and the result is read-only.
(foo x) has a non-read-only result (unless the function
foo DECLARED it to be read-only)
I don't particularly care for the  syntax, but only because those have
been marked as explicitly reserved to the user and never to be defined by
It is still an open question, however, as to when the compiler is allowed to
take advantage of read-only objects and treat them as inline. That is,
(defun foo () (constant '(a b c))
(defun mumble () (foo))
is the compiler allowed to collapse mumble into the equivalent of foo? If
so, foo cannot be incrementally recompiled, and debugging mumble gives some
non-intuitive results since the function call on foo may represent a logical
partition of the problem space. (Thus one gives up some of the advantage of
source level debugging...) So, while we have introduced a syntactic
construct to allow the user to distinguish between the eval/ro distinction,
we still have a foldability distiction that we may want to control on a
finer level than the OPTIMIZE switches will allow, and we may not be able to
just define it syntactically (though a FOLDABLE or DONT-FOLD construction
similar to the QUOTE/CONSTANT might be a step).
Here is a side example of this folding problem that declarations may not
help (due to firstname.lastname@example.org):
(foo (CONSTANT '(NIL)) (CONSTANT (CONS NIL NIL)))
Now, are the first and second arguments to foo EQ or not? The point is, that
just because two objects are read-only and EQUAL does not mean that we
necessarily want to imply that they are EQ, and further that whatever is
decided we don't want different implementations doing different things here.
It seems to me that the default should be NOT eq, because if the programmer
had INTENDED eqness, they should have done something along the lines of:
(let ((bar (constant '(nil))))
(foo bar bar))
and now the EQness is explicit and obvious. The point is, there is a
distinction between ACCIDENTAL EQness and INTENTIONAL EQness. The compiler
and interpreter probably should never take advantage of ACCIDENTAL
EQness. If the programmer had intended two objects to be EQ, he should have
cons'd them that way.
Another question, is defun the rough equivalent of
(setf (symbol-function x) ...) or
(setf (symbol-function x) (CONSTANT ...))
or <<very roughly>> (setf (CONSTANT (symbol-function x)) ...)
or (setf (CONSTANT (symbol-function x)) (CONSTANT ...))
i.e. to say that this symbol's functional value happens to evaluate to this
function, or this symbol's functional value happens to evaluate to this
constant function, or this symbol's functional value *will always* evaluate
to this function/ constant function. In the first two cases, we are allowing
the symbol to be associated with new functions later (e.g. incremental
compiles), and in the latter two this is prevented. The semantic difference
between the second and forth and the first and third is whether the function
Currently, my opinion is along the lines of: Yes, we do need to make a
distinction as KMP suggests, because these are different things, and the
programmer should be able to represent them explicitly. However, compilers
should not take advantage of anything that has a cost in terms of debugging
or loss of incremental compiling. Both *can* be maintained, of course, if
we want to carry around a list of all the references to a function that has
been folded, but the performance cost of so doing may be significant.
Further this syntactic issue still hasn't addressed a more fundamental
problem, namely the necessity of being able to control the compilers
behavior when it crosses objects that are accidentally equivalent in
some agreed upon sense (e.g. EQUAL).
: (unless, of course one is doing optimize safety 0, speed 3, stupidity
Brad Miller U. Rochester Comp Sci Dept.