Next: , Previous: , Up: compiler   [Index]


17.13 Core type inference

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:

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).

Function: pass-core-type-inference input

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.

Parameter: perform-core-type-inference?

When true the pass core-type-inference is performed, else it is skipped. Defaults to #t.

Properties propagation through function arguments

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: , Previous: , Up: compiler   [Index]