Next: compiler unsafe primrefs, Previous: compiler refassig, Up: compiler [Index]
This optional compiler pass analyses the type of values returned by
expressions with the purpose of transforming funcall
recordised forms:
(funcall (primref ?prim-name) ?rand ...) (funcall ?rator ?rand ...)
into:
(funcall (primref ?prim-name) (known ?rand ?rand-type) ...) (funcall (known ?rator ?rator-type) (known ?rand ?rand-type) ...)
where: ?rator-type is the type description of the value returned
by ?rator; each ?rand-type is the type description of the
value returned by the corresponding ?rand; a primref
operator is left untouched. The type descriptions are records of type
core-type-tag
whose represented types are inferred by this
compiler pass.
The structs of type known
are annotation “tags” consumed by
the functions generating the implementation of the core primitive
operations; for example, given the recordised code:
(funcall (primref vector-length) ?rand)
which makes use of the primitive operation vector-length
:
vector-length
integrated at the call site must include a
validation of ?rand as vector object.
T:vector
is introduced for the operand:
(funcall (primref vector-length) (known ?rand T:vector))
the implementation of vector-length
integrated at the call site
does not include a validation of ?RAND as vector object.
NOTE At present (Jul 23, 2016), this compiler pass is performed only if the configured compiler’s optimisation level is ‘1’ or above. When Vicare is run with the option -O0: this compiler pass is skipped.
The following bindings are exported by the library (vicare
compiler)
.
Perform code transformations traversing the whole hierarchy in input, which must be a struct instance representing recordised code, and building a new hierarchy of recordised code; return the new hierarchy.
When true the pass core-type-inference
is performed, else it is
skipped. Defaults to #t
.
Let’s examine what happens when a variable reference is used as operand
for the primitive operation cdr
; the primitive cdr
accepts
a pair as operand. In the following standard code example the variable
x
is of unknown type, when its binding is created x
is
left untagged:
(let ((f (lambda (y) y)) (x (read))) (f (cdr x)) (f x))
but, after being used as argument for cdr
without raising an
exception: it is known that its type is T:pair
, so the second
reference to x
is tagged with T:pair
; the result of the
transformation is:
(bind ((f_0 (lambda (y_0) y_0)) (x_0 (funcall (primref read)))) (seq (funcall (known f_0 (T:procedure T:non-false T:nonimmediate T:object)) (funcall (primref cdr) x_0)) (funcall (known f_0 (T:procedure T:non-false T:nonimmediate T:object)) (known x_0 (T:pair T:non-false T:nonimmediate T:object)))))
We know that a “wrong operand type” exception is non–continuable; so
if cdr
raises an exception because x
is not a pair: the
control flow cannot come back. This allows us to determine type
informations and propagate them after the arguments have been validated.
Next: compiler unsafe primrefs, Previous: compiler refassig, Up: compiler [Index]