8.3 Forward ICR optimizations
In the forward pass, we scan the code in forward depth-first order. We examine each call to a known function, and:
- Eliminate any bindings for unused variables.
- Do top-down type assertion propagation. In local calls, we propagate asserted and derived types between the call and the called lambda.
- Replace calls of foldable functions with constant arguments with the result. We don't have to actually delete the call node, since Top-Down optimize will delete it now that its value is unused.
- Run any Optimizer for the current function. The optimizer does arbitrary transformations by hacking directly on the IR. This is useful primarily for arithmetic simplification and similar things that may need to examine and modify calls other than the current call. The optimizer is responsible for recording any changes that it makes. An optimizer can inhibit further optimization of the node during the current pass by returning true. This is useful when deleting the node.
- Do ICR transformations, replacing a global function call with equivalent inline lisp code.
- Do bottom-up type propagation/inferencing. For some functions such as Coerce we will dispatch to a function to find the result type. The Derive-Type function just returns a type structure, and we check if it is different from the old type in order to see if there was a change.
- Eliminate IFs with predicates known to be true or false.
- Substitute the value for unset let variables that are bound to constants, unset lambda variables or functionals.
- Propagate types from local call args to var refs.
We use type info from the function continuation to find result types for functions that don't have a derive-type method.