Module Flambda2_simplify.Simplify_common
Miscellaneous utility functions and types used by the simplifier.
There are two (nested, higher-order) levels of continuations here:
- one of them, the "term-level continuation" expresses the traversal order (enabling values to be held in the closures corresponding to meta-level continuations until they are needed later);
- the other, the "compiler-level continuation" ensures that the simplifier is tail recursive.
In the future the first continuation might be removed by defunctionalisation.
rebuild and after_rebuild form the compiler-level continuation.
type 'a after_rebuild =
Flambda2_simplify.Rebuilt_expr.t ->
Flambda2_simplify.Upwards_acc.t ->
'atype 'a rebuild =
Flambda2_simplify.Upwards_acc.t ->
after_rebuild:'a Flambda2_simplify.Simplify_common.after_rebuild ->
'atype ('a, 'b) down_to_up =
Flambda2_simplify.Downwards_acc.t ->
rebuild:'a Flambda2_simplify.Simplify_common.rebuild ->
'bdown_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.
type 'a expr_simplifier =
Flambda2_simplify.Downwards_acc.t ->
'a ->
down_to_up:
(Flambda2_simplify.Rebuilt_expr.t * Flambda2_simplify.Upwards_acc.t,
Flambda2_simplify.Rebuilt_expr.t * Flambda2_simplify.Upwards_acc.t)
Flambda2_simplify.Simplify_common.down_to_up ->
Flambda2_simplify.Rebuilt_expr.t * Flambda2_simplify.Upwards_acc.tThe 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 anApply) is reached, upon which point the currentdown_to_upis called;
Downwards_acc, which containsDownwards_envin 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 containsUpwards_envin 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.)
type simplify_toplevel =
Flambda2_simplify.Downwards_acc.t ->
Flambda2_terms.Flambda.Expr.t ->
return_continuation:Flambda2_identifiers.Continuation.t ->
return_arity:[ `Unarized ] Flambda2_kinds.Flambda_arity.t ->
exn_continuation:Flambda2_identifiers.Continuation.t ->
Flambda2_simplify.Rebuilt_expr.t * Flambda2_simplify.Upwards_acc.ttype simplify_function_body =
Flambda2_simplify.Downwards_acc.t ->
Flambda2_terms.Flambda.Expr.t ->
return_continuation:Flambda2_identifiers.Continuation.t ->
return_arity:[ `Unarized ] Flambda2_kinds.Flambda_arity.t ->
exn_continuation:Flambda2_identifiers.Continuation.t ->
loopify_state:Flambda2_simplify.Loopify_state.t ->
params:Flambda2_bound_identifiers.Bound_parameters.t ->
implicit_params:Flambda2_bound_identifiers.Bound_parameters.t ->
Flambda2_simplify.Rebuilt_expr.t * Flambda2_simplify.Upwards_acc.tval simplify_projection :
Flambda2_simplify.Downwards_acc.t ->
original_term:Flambda2_terms.Flambda.Named.t ->
deconstructing:Flambda2_types.t ->
shape:Flambda2_types.t ->
result_var:Flambda2_bound_identifiers.Bound_var.t ->
result_kind:Flambda2_kinds.Flambda_kind.t ->
Flambda2_simplify.Simplify_primitive_result.tval update_exn_continuation_extra_args :
Flambda2_simplify.Upwards_acc.t ->
exn_cont_use_id:Flambda2_identifiers.Apply_cont_rewrite_id.t ->
Flambda2_terms.Apply_expr.t ->
Flambda2_terms.Apply_expr.tval 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.tCreate a projection from a tuple (assumed to be a size-tuple of OCaml values).
val split_direct_over_application :
Flambda2_terms.Apply_expr.t ->
apply_alloc_mode:Flambda2_term_basics.Alloc_mode.For_applications.t ->
callee's_code_id:Flambda2_identifiers.Code_id.t ->
callee's_code_metadata:Flambda2_terms.Code_metadata.t ->
Flambda2_terms.Flambda.Expr.tSplit a direct over-application into a full application followed by the application of the leftover arguments.
val apply_cont_use_kind :
context:Flambda2_simplify.Simplify_common.apply_cont_context ->
Flambda2_terms.Flambda.Apply_cont.t ->
Flambda2_term_basics.Continuation_use_kind.tval 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.tval specialise_array_kind :
Flambda2_simplify.Downwards_acc.t ->
Flambda2_terms.Flambda_primitive.Array_kind.t ->
array_ty:Flambda2_types.t ->
Flambda2_terms.Flambda_primitive.Array_kind.t Flambda2_lattices.Or_bottom.tWarning: 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.
val add_symbol_projection :
Flambda2_simplify.Downwards_acc.t ->
projected_from:Flambda2_term_basics.Simple.t ->
Flambda2_term_basics.Symbol_projection.Projection.t ->
projection_bound_to:Flambda2_bound_identifiers.Bound_var.t ->
kind:Flambda2_kinds.Flambda_kind.With_subkind.t ->
Flambda2_simplify.Downwards_acc.tGeneral 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.