jon.recoil.org

Module Flambda2_simplify.Simplify_common

Miscellaneous utility functions and types used by the simplifier.

There are two (nested, higher-order) levels of continuations here:

In the future the first continuation might be removed by defunctionalisation.

rebuild and after_rebuild form the compiler-level continuation.

down_to_up is the term-level continuation.

Calling down_to_up doesn't mean that the downwards pass has been completely finished and we are ready to start the upwards pass. It means that the downwards pass has reached the end of some subexpression, at which point another subexpression can be traversed downwards, or (after all such subexpressions have been traversed) the upwards pass may begin.

The environments and accumulators for simplification are as follows:

  • Downwards_env, which operates like a normal typing environment following the scope of terms. It is discarded when the end of a given subexpression (a "terminator" expression, such as an Apply) is reached, upon which point the current down_to_up is called;
  • Downwards_acc, which contains Downwards_env in addition to extra information (not scope-based) that is accumulated across all subexpressions;
  • Upwards_env, which operates like a normal environment for the upwards pass, mainly used to record the handler expressions of continuations. It is discarded when the end of a given subexpression is reached.
  • Upwards_acc, which contains Upwards_env in addition to extra information that is accumulated across all subexpressions.

Upon changing from the downwards to the upwards pass, some information is propagated from the Downwards_acc to the Upwards_acc. (In fact the Upwards_acc contains the Downwards_acc from which it was created.)

val project_tuple : machine_width:Target_system.Machine_width.t -> dbg:Debuginfo.t -> size:int -> field:int -> Flambda2_term_basics.Simple.t -> Flambda2_terms.Flambda.Named.t

Create a projection from a tuple (assumed to be a size-tuple of OCaml values).

Split a direct over-application into a full application followed by the application of the leftover arguments.

type apply_cont_context =
  1. | Apply_cont_expr
  2. | Switch_branch
val clear_demoted_trap_action_and_patch_unused_exn_bucket : Flambda2_simplify.Upwards_acc.t -> Flambda2_terms.Flambda.Apply_cont.t -> Flambda2_terms.Flambda.Apply_cont.t

Warning: This function relies on T.meet_is_flat_float_array, which could return any kind for empty arrays. So this function is only safe for operations that are invalid on empty arrays.

General notes about symbol projections (applicable to Block_load and Project_value_slot primitives):

Projections from symbols bound to variables are important to remember, since if such a variable occurs in a set of closures environment or other value that can potentially be lifted, the knowledge that the variable is equal to a symbol projection can make the difference between being able to lift and not being able to lift. We try to avoid recording symbol projections whose answer is known (in particular the answer is a symbol or a constant), since such symbol projection knowledge doesn't affect lifting decisions.

We only need to record a projection if the defining expression remains as a Prim. In particular if the defining expression simplified to a variable (via the Simple constructor), then in the event that the variable is itself a symbol projection, the environment will already know this fact.

We don't need to record a projection if we are currently at toplevel, since any variable involved in a constant to be lifted from that position will also be at toplevel.