Design of CMU Common Lisp.pdf - Common Lisp.net
Design of CMU Common Lisp.pdf - Common Lisp.net
Design of CMU Common Lisp.pdf - Common Lisp.net
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
Chapter 9<br />
Type checking<br />
We need to do a pretty good job <strong>of</strong> guessing when a type check will ultimately need to be done. Generic<br />
arithmetic, for example: In the absence <strong>of</strong> declarations, we will use the safe variant, but if we don’t know this,<br />
we will generate a check for NUMBER anyway. We need to look at the fast-safe templates and guess if any <strong>of</strong><br />
them could apply.<br />
We compute a function type from the VOP arguments and assertions on those arguments. This can be<br />
used with Valid-Function-Use to see which templates do or might apply to a particular call. If we guess that<br />
a safe implementation will be used, then we mark the continuation so as to force a safe implementation to be<br />
chosen. [This will happen if ICR optimize doesn’t run to completion, so the ICR optimization after type check<br />
generation can discover new type information. Since we won’t redo type check at that point, there could be a<br />
call that has applicable unsafe templates, but isn’t type checkable.]<br />
[### A better and more general optimization <strong>of</strong> structure type checks: in type check conversion, we look<br />
at the *original derived* type <strong>of</strong> the continuation: if the difference between the proven type and the asserted<br />
type is a simple type check, then check for the negation <strong>of</strong> the difference. e.g. if we want a FOO and we know<br />
we’ve got (OR FOO NULL), then test for (NOT NULL). This is a very important optimization for linked lists <strong>of</strong><br />
structures, but can also apply in other situations.]<br />
If after ICR phases, we have a continuation with check-type set in a context where it seems likely a check will<br />
be emitted, and the type is too hairy to be easily checked (i.e. no CHECK-xxx VOP), then we do a transformation<br />
on the ICR equivalent to:<br />
(... (the hair ) ...)<br />
==><br />
(... (funcall \#’(lambda (\#:val)<br />
(if (typep \#:val ’hair)<br />
\#:val<br />
(%type-check-error \#:val ’hair)))<br />
)<br />
...)<br />
This way, we guarantee that VMR conversion never has to emit type checks for hairy types.<br />
[Actually, we need to do a MV-bind and several type checks when there is a MV continuation. And some<br />
values types are just too hairy to check. We really can’t check any assertion for a non-fixed number <strong>of</strong> values,<br />
since there isn’t any efficient way to bind arbitrary numbers <strong>of</strong> values. (could be done with MV-call <strong>of</strong> a morearg<br />
function, I guess...) ]<br />
[Perhaps only use CHECK-xxx VOPs for types equivalent to a ptype? Exceptions for CONS and SYMBOL?<br />
Anyway, no point in going to trouble to implement and emit rarely used CHECK-xxx vops.]<br />
One potential lose in converting a type check to explicit conditionals rather than to a CHECK-xxx VOP is<br />
that VMR code motion optimizations won’t be able to do anything. This shouldn’t be much <strong>of</strong> an issue, though,<br />
since type constraint propagation has already done global optimization <strong>of</strong> type checks.<br />
This phase is optional, but should be done if anything is more important than compile speed.<br />
Type check is responsible for reconciling the continuation asserted and derived types, emitting type checks<br />
if appropriate. If the derived type is a subtype <strong>of</strong> the asserted type, then we don’t need to do anything.<br />
28