diff --git a/.depend b/.depend index 35a39b8551c6..f92198db59b0 100644 --- a/.depend +++ b/.depend @@ -3895,6 +3895,16 @@ asmcomp/debug/reg_with_debug_info.cmx : \ asmcomp/debug/reg_with_debug_info.cmi : \ asmcomp/reg.cmi \ middle_end/backend_var.cmi +middle_end/flambda/compilenv_deps/coercion.cmo : \ + utils/misc.cmi \ + middle_end/flambda/compilenv_deps/flambda_colours.cmi \ + middle_end/flambda/compilenv_deps/coercion.cmi +middle_end/flambda/compilenv_deps/coercion.cmx : \ + utils/misc.cmx \ + middle_end/flambda/compilenv_deps/flambda_colours.cmx \ + middle_end/flambda/compilenv_deps/coercion.cmi +middle_end/flambda/compilenv_deps/coercion.cmi : \ + middle_end/flambda/compilenv_deps/rec_info.cmi middle_end/flambda/compilenv_deps/compilation_unit.cmo : \ utils/misc.cmi \ middle_end/flambda/compilenv_deps/linkage_name.cmi \ @@ -3949,13 +3959,11 @@ middle_end/flambda/compilenv_deps/patricia_tree.cmi : \ utils/numbers.cmi \ utils/identifiable.cmi middle_end/flambda/compilenv_deps/rec_info.cmo : \ - utils/numbers.cmi \ utils/misc.cmi \ utils/identifiable.cmi \ middle_end/flambda/compilenv_deps/flambda_colours.cmi \ middle_end/flambda/compilenv_deps/rec_info.cmi middle_end/flambda/compilenv_deps/rec_info.cmx : \ - utils/numbers.cmx \ utils/misc.cmx \ utils/identifiable.cmx \ middle_end/flambda/compilenv_deps/flambda_colours.cmx \ @@ -3966,7 +3974,6 @@ middle_end/flambda/compilenv_deps/reg_width_things.cmo : \ utils/targetint.cmi \ middle_end/flambda/compilenv_deps/target_imm.cmi \ middle_end/flambda/compilenv_deps/table_by_int_id.cmi \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ middle_end/flambda/compilenv_deps/patricia_tree.cmi \ utils/numbers.cmi \ utils/misc.cmi \ @@ -3975,12 +3982,12 @@ middle_end/flambda/compilenv_deps/reg_width_things.cmo : \ utils/identifiable.cmi \ middle_end/flambda/compilenv_deps/flambda_colours.cmi \ middle_end/flambda/compilenv_deps/compilation_unit.cmi \ + middle_end/flambda/compilenv_deps/coercion.cmi \ middle_end/flambda/compilenv_deps/reg_width_things.cmi middle_end/flambda/compilenv_deps/reg_width_things.cmx : \ utils/targetint.cmx \ middle_end/flambda/compilenv_deps/target_imm.cmx \ middle_end/flambda/compilenv_deps/table_by_int_id.cmx \ - middle_end/flambda/compilenv_deps/rec_info.cmx \ middle_end/flambda/compilenv_deps/patricia_tree.cmx \ utils/numbers.cmx \ utils/misc.cmx \ @@ -3989,16 +3996,17 @@ middle_end/flambda/compilenv_deps/reg_width_things.cmx : \ utils/identifiable.cmx \ middle_end/flambda/compilenv_deps/flambda_colours.cmx \ middle_end/flambda/compilenv_deps/compilation_unit.cmx \ + middle_end/flambda/compilenv_deps/coercion.cmx \ middle_end/flambda/compilenv_deps/reg_width_things.cmi middle_end/flambda/compilenv_deps/reg_width_things.cmi : \ utils/targetint.cmi \ middle_end/flambda/compilenv_deps/target_imm.cmi \ middle_end/flambda/compilenv_deps/table_by_int_id.cmi \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ utils/numbers.cmi \ middle_end/flambda/compilenv_deps/linkage_name.cmi \ utils/identifiable.cmi \ - middle_end/flambda/compilenv_deps/compilation_unit.cmi + middle_end/flambda/compilenv_deps/compilation_unit.cmi \ + middle_end/flambda/compilenv_deps/coercion.cmi middle_end/flambda/compilenv_deps/symbol.cmo : \ middle_end/flambda/compilenv_deps/reg_width_things.cmi \ utils/misc.cmi \ @@ -4424,17 +4432,20 @@ middle_end/flambda/basic/name.cmo : \ middle_end/flambda/compilenv_deps/symbol.cmi \ middle_end/flambda/compilenv_deps/reg_width_things.cmi \ utils/misc.cmi \ + utils/identifiable.cmi \ middle_end/flambda/basic/name.cmi middle_end/flambda/basic/name.cmx : \ middle_end/flambda/compilenv_deps/variable.cmx \ middle_end/flambda/compilenv_deps/symbol.cmx \ middle_end/flambda/compilenv_deps/reg_width_things.cmx \ utils/misc.cmx \ + utils/identifiable.cmx \ middle_end/flambda/basic/name.cmi middle_end/flambda/basic/name.cmi : \ middle_end/flambda/compilenv_deps/variable.cmi \ middle_end/flambda/compilenv_deps/symbol.cmi \ middle_end/flambda/compilenv_deps/reg_width_things.cmi \ + utils/identifiable.cmi \ middle_end/flambda/compilenv_deps/compilation_unit.cmi middle_end/flambda/basic/num_continuation_uses.cmo : \ middle_end/flambda/basic/num_continuation_uses.cmi @@ -4509,25 +4520,25 @@ middle_end/flambda/basic/simple.cmo : \ middle_end/flambda/naming/renaming.cmi \ middle_end/flambda/compilenv_deps/reg_width_things.cmi \ middle_end/flambda/basic/reg_width_const.cmi \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ middle_end/flambda/naming/name_occurrences.cmi \ middle_end/flambda/naming/name_mode.cmi \ middle_end/flambda/basic/name.cmi \ utils/misc.cmi \ utils/identifiable.cmi \ middle_end/flambda/types/kinds/flambda_kind.cmi \ + middle_end/flambda/compilenv_deps/coercion.cmi \ middle_end/flambda/basic/simple.cmi middle_end/flambda/basic/simple.cmx : \ middle_end/flambda/naming/renaming.cmx \ middle_end/flambda/compilenv_deps/reg_width_things.cmx \ middle_end/flambda/basic/reg_width_const.cmx \ - middle_end/flambda/compilenv_deps/rec_info.cmx \ middle_end/flambda/naming/name_occurrences.cmx \ middle_end/flambda/naming/name_mode.cmx \ middle_end/flambda/basic/name.cmx \ utils/misc.cmx \ utils/identifiable.cmx \ middle_end/flambda/types/kinds/flambda_kind.cmx \ + middle_end/flambda/compilenv_deps/coercion.cmx \ middle_end/flambda/basic/simple.cmi middle_end/flambda/basic/simple.cmi : \ middle_end/flambda/compilenv_deps/variable.cmi \ @@ -4535,12 +4546,12 @@ middle_end/flambda/basic/simple.cmi : \ middle_end/flambda/compilenv_deps/symbol.cmi \ middle_end/flambda/compilenv_deps/reg_width_things.cmi \ middle_end/flambda/basic/reg_width_const.cmi \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ middle_end/flambda/naming/name_occurrences.cmi \ middle_end/flambda/basic/name.cmi \ utils/identifiable.cmi \ middle_end/flambda/types/kinds/flambda_kind.cmi \ - middle_end/flambda/naming/contains_names.cmo + middle_end/flambda/naming/contains_names.cmo \ + middle_end/flambda/compilenv_deps/coercion.cmi middle_end/flambda/basic/symbol_scoping_rule.cmo : \ middle_end/flambda/basic/symbol_scoping_rule.cmi middle_end/flambda/basic/symbol_scoping_rule.cmx : \ @@ -5217,7 +5228,6 @@ middle_end/flambda/from_lambda/prepare_lambda.cmi : \ middle_end/flambda/inlining/inlining_decision.cmo : \ middle_end/flambda/simplify/env/upwards_env.cmi \ middle_end/flambda/simplify/env/upwards_acc.cmi \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ middle_end/flambda/inlining/inlining_transforms.cmi \ middle_end/flambda/types/inlining/inlining_state.cmi \ middle_end/flambda/types/inlining/inlining_arguments.cmi \ @@ -5231,7 +5241,6 @@ middle_end/flambda/inlining/inlining_decision.cmo : \ middle_end/flambda/inlining/inlining_decision.cmx : \ middle_end/flambda/simplify/env/upwards_env.cmx \ middle_end/flambda/simplify/env/upwards_acc.cmx \ - middle_end/flambda/compilenv_deps/rec_info.cmx \ middle_end/flambda/inlining/inlining_transforms.cmx \ middle_end/flambda/types/inlining/inlining_state.cmx \ middle_end/flambda/types/inlining/inlining_arguments.cmx \ @@ -5279,7 +5288,6 @@ middle_end/flambda/inlining/inlining_transforms.cmo : \ middle_end/flambda/simplify/simplify_import.cmi \ middle_end/flambda/basic/simple.cmi \ middle_end/flambda/naming/renaming.cmi \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ middle_end/flambda/naming/name_mode.cmi \ middle_end/flambda/basic/kinded_parameter.cmi \ middle_end/flambda/types/flambda_type.cmi \ @@ -5288,6 +5296,7 @@ middle_end/flambda/inlining/inlining_transforms.cmo : \ middle_end/flambda/simplify/env/downwards_acc.cmi \ lambda/debuginfo.cmi \ middle_end/flambda/basic/continuation.cmi \ + middle_end/flambda/compilenv_deps/coercion.cmi \ middle_end/flambda/naming/bindable_let_bound.cmi \ middle_end/flambda/inlining/inlining_transforms.cmi middle_end/flambda/inlining/inlining_transforms.cmx : \ @@ -5297,7 +5306,6 @@ middle_end/flambda/inlining/inlining_transforms.cmx : \ middle_end/flambda/simplify/simplify_import.cmx \ middle_end/flambda/basic/simple.cmx \ middle_end/flambda/naming/renaming.cmx \ - middle_end/flambda/compilenv_deps/rec_info.cmx \ middle_end/flambda/naming/name_mode.cmx \ middle_end/flambda/basic/kinded_parameter.cmx \ middle_end/flambda/types/flambda_type.cmx \ @@ -5306,6 +5314,7 @@ middle_end/flambda/inlining/inlining_transforms.cmx : \ middle_end/flambda/simplify/env/downwards_acc.cmx \ lambda/debuginfo.cmx \ middle_end/flambda/basic/continuation.cmx \ + middle_end/flambda/compilenv_deps/coercion.cmx \ middle_end/flambda/naming/bindable_let_bound.cmx \ middle_end/flambda/inlining/inlining_transforms.cmi middle_end/flambda/inlining/inlining_transforms.cmi : \ @@ -6042,6 +6051,7 @@ middle_end/flambda/simplify/common_subexpression_elimination.cmo : \ middle_end/flambda/compilenv_deps/flambda_features.cmi \ middle_end/flambda/basic/continuation_extra_params_and_args.cmi \ middle_end/flambda/basic/apply_cont_rewrite_id.cmi \ + middle_end/flambda/types/env/aliases.cmi \ middle_end/flambda/simplify/common_subexpression_elimination.cmi middle_end/flambda/simplify/common_subexpression_elimination.cmx : \ middle_end/flambda/compilenv_deps/variable.cmx \ @@ -6059,6 +6069,7 @@ middle_end/flambda/simplify/common_subexpression_elimination.cmx : \ middle_end/flambda/compilenv_deps/flambda_features.cmx \ middle_end/flambda/basic/continuation_extra_params_and_args.cmx \ middle_end/flambda/basic/apply_cont_rewrite_id.cmx \ + middle_end/flambda/types/env/aliases.cmx \ middle_end/flambda/simplify/common_subexpression_elimination.cmi middle_end/flambda/simplify/common_subexpression_elimination.cmi : \ middle_end/flambda/basic/simple.cmi \ @@ -9029,6 +9040,7 @@ middle_end/flambda/types/flambda_type.cmo : \ middle_end/flambda/naming/contains_names.cmo \ middle_end/flambda/cmx/contains_ids.cmo \ middle_end/flambda/compilenv_deps/compilation_unit.cmi \ + middle_end/flambda/compilenv_deps/coercion.cmi \ middle_end/flambda/basic/code_id.cmi \ middle_end/flambda/types/structures/code_age_relation.cmi \ middle_end/flambda/basic/closure_id.cmi \ @@ -9082,6 +9094,7 @@ middle_end/flambda/types/flambda_type.cmx : \ middle_end/flambda/naming/contains_names.cmx \ middle_end/flambda/cmx/contains_ids.cmx \ middle_end/flambda/compilenv_deps/compilation_unit.cmx \ + middle_end/flambda/compilenv_deps/coercion.cmx \ middle_end/flambda/basic/code_id.cmx \ middle_end/flambda/types/structures/code_age_relation.cmx \ middle_end/flambda/basic/closure_id.cmx \ @@ -9122,10 +9135,12 @@ middle_end/flambda/types/flambda_type.cmi : \ lambda/debuginfo.cmi \ middle_end/flambda/simplify/env/continuation_use_kind.cmi \ middle_end/flambda/compilenv_deps/compilation_unit.cmi \ + middle_end/flambda/compilenv_deps/coercion.cmi \ middle_end/flambda/basic/code_id.cmi \ middle_end/flambda/types/structures/code_age_relation.cmi \ middle_end/flambda/basic/closure_id.cmi \ - middle_end/flambda/basic/apply_cont_rewrite_id.cmi + middle_end/flambda/basic/apply_cont_rewrite_id.cmi \ + middle_end/flambda/types/env/aliases.cmi middle_end/flambda/types/resolved_type.rec.cmo : \ middle_end/flambda/basic/reg_width_const.cmi \ middle_end/flambda/types/basic/or_unknown_or_bottom.cmi \ @@ -9153,6 +9168,7 @@ middle_end/flambda/types/type_descr.rec.cmo : \ middle_end/flambda/cmx/ids_for_export.cmi \ middle_end/flambda/compilenv_deps/flambda_colours.cmi \ utils/clflags.cmi \ + middle_end/flambda/types/env/aliases.cmi \ middle_end/flambda/types/type_descr.rec.cmi middle_end/flambda/types/type_descr.rec.cmx : \ middle_end/flambda/naming/with_delayed_permutation.cmx \ @@ -9170,13 +9186,13 @@ middle_end/flambda/types/type_descr.rec.cmx : \ middle_end/flambda/cmx/ids_for_export.cmx \ middle_end/flambda/compilenv_deps/flambda_colours.cmx \ utils/clflags.cmx \ + middle_end/flambda/types/env/aliases.cmx \ middle_end/flambda/types/type_descr.rec.cmi middle_end/flambda/types/type_descr.rec.cmi : \ middle_end/flambda/types/type_head_intf.cmo \ middle_end/flambda/types/type_descr_intf.cmo middle_end/flambda/types/type_descr_intf.cmo : \ middle_end/flambda/basic/simple.cmi \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ utils/printing_cache.cmi \ middle_end/flambda/types/basic/or_unknown_or_bottom.cmi \ middle_end/flambda/types/basic/or_unknown.cmi \ @@ -9184,10 +9200,10 @@ middle_end/flambda/types/type_descr_intf.cmo : \ middle_end/flambda/basic/name.cmi \ middle_end/flambda/types/kinds/flambda_kind.cmi \ middle_end/flambda/naming/contains_names.cmo \ - middle_end/flambda/cmx/contains_ids.cmo + middle_end/flambda/cmx/contains_ids.cmo \ + middle_end/flambda/compilenv_deps/coercion.cmi middle_end/flambda/types/type_descr_intf.cmx : \ middle_end/flambda/basic/simple.cmx \ - middle_end/flambda/compilenv_deps/rec_info.cmx \ utils/printing_cache.cmx \ middle_end/flambda/types/basic/or_unknown_or_bottom.cmx \ middle_end/flambda/types/basic/or_unknown.cmx \ @@ -9195,7 +9211,8 @@ middle_end/flambda/types/type_descr_intf.cmx : \ middle_end/flambda/basic/name.cmx \ middle_end/flambda/types/kinds/flambda_kind.cmx \ middle_end/flambda/naming/contains_names.cmx \ - middle_end/flambda/cmx/contains_ids.cmx + middle_end/flambda/cmx/contains_ids.cmx \ + middle_end/flambda/compilenv_deps/coercion.cmx middle_end/flambda/types/type_grammar.rec.cmo : \ middle_end/flambda/compilenv_deps/variable.cmi \ middle_end/flambda/basic/var_within_closure.cmi \ @@ -9260,22 +9277,23 @@ middle_end/flambda/types/type_grammar.rec.cmi : \ lambda/debuginfo.cmi \ middle_end/flambda/naming/contains_names.cmo \ middle_end/flambda/cmx/contains_ids.cmo \ + middle_end/flambda/compilenv_deps/coercion.cmi \ middle_end/flambda/basic/code_id.cmi \ middle_end/flambda/basic/closure_id.cmi middle_end/flambda/types/type_head_intf.cmo : \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ utils/printing_cache.cmi \ middle_end/flambda/types/basic/or_unknown.cmi \ middle_end/flambda/types/basic/or_bottom.cmi \ middle_end/flambda/naming/contains_names.cmo \ - middle_end/flambda/cmx/contains_ids.cmo + middle_end/flambda/cmx/contains_ids.cmo \ + middle_end/flambda/compilenv_deps/coercion.cmi middle_end/flambda/types/type_head_intf.cmx : \ - middle_end/flambda/compilenv_deps/rec_info.cmx \ utils/printing_cache.cmx \ middle_end/flambda/types/basic/or_unknown.cmx \ middle_end/flambda/types/basic/or_bottom.cmx \ middle_end/flambda/naming/contains_names.cmx \ - middle_end/flambda/cmx/contains_ids.cmx + middle_end/flambda/cmx/contains_ids.cmx \ + middle_end/flambda/compilenv_deps/coercion.cmx middle_end/flambda/types/basic/closure_id_and_var_within_closure_set.cmo : \ middle_end/flambda/types/basic/var_within_closure_set.cmi \ middle_end/flambda/basic/var_within_closure.cmi \ @@ -9437,10 +9455,13 @@ middle_end/flambda/types/env/aliases.cmo : \ middle_end/flambda/compilenv_deps/variable.cmi \ middle_end/flambda/basic/simple.cmi \ middle_end/flambda/naming/renaming.cmi \ + middle_end/flambda/compilenv_deps/reg_width_things.cmi \ middle_end/flambda/naming/name_mode.cmi \ middle_end/flambda/basic/name.cmi \ utils/misc.cmi \ middle_end/flambda/cmx/ids_for_export.cmi \ + middle_end/flambda/compilenv_deps/flambda_colours.cmi \ + middle_end/flambda/compilenv_deps/coercion.cmi \ utils/clflags.cmi \ middle_end/flambda/types/env/binding_time.cmi \ middle_end/flambda/types/env/aliases.cmi @@ -9448,10 +9469,13 @@ middle_end/flambda/types/env/aliases.cmx : \ middle_end/flambda/compilenv_deps/variable.cmx \ middle_end/flambda/basic/simple.cmx \ middle_end/flambda/naming/renaming.cmx \ + middle_end/flambda/compilenv_deps/reg_width_things.cmx \ middle_end/flambda/naming/name_mode.cmx \ middle_end/flambda/basic/name.cmx \ utils/misc.cmx \ middle_end/flambda/cmx/ids_for_export.cmx \ + middle_end/flambda/compilenv_deps/flambda_colours.cmx \ + middle_end/flambda/compilenv_deps/coercion.cmx \ utils/clflags.cmx \ middle_end/flambda/types/env/binding_time.cmx \ middle_end/flambda/types/env/aliases.cmi @@ -9487,10 +9511,12 @@ middle_end/flambda/types/env/join_env.rec.cmi : \ middle_end/flambda/basic/simple.cmi middle_end/flambda/types/env/meet_env.rec.cmo : \ middle_end/flambda/basic/simple.cmi \ + middle_end/flambda/basic/name.cmi \ utils/misc.cmi \ middle_end/flambda/types/env/meet_env.rec.cmi middle_end/flambda/types/env/meet_env.rec.cmx : \ middle_end/flambda/basic/simple.cmx \ + middle_end/flambda/basic/name.cmx \ utils/misc.cmx \ middle_end/flambda/types/env/meet_env.rec.cmi middle_end/flambda/types/env/meet_env.rec.cmi : \ @@ -9502,7 +9528,6 @@ middle_end/flambda/types/env/typing_env.rec.cmo : \ middle_end/flambda/basic/simple.cmi \ middle_end/flambda/basic/scope.cmi \ middle_end/flambda/naming/renaming.cmi \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ utils/printing_cache.cmi \ middle_end/flambda/naming/name_occurrences.cmi \ middle_end/flambda/naming/name_mode.cmi \ @@ -9514,6 +9539,7 @@ middle_end/flambda/types/env/typing_env.rec.cmo : \ middle_end/flambda/types/kinds/flambda_kind.cmi \ middle_end/flambda/compilenv_deps/flambda_colours.cmi \ middle_end/flambda/compilenv_deps/compilation_unit.cmi \ + middle_end/flambda/compilenv_deps/coercion.cmi \ middle_end/flambda/types/structures/code_age_relation.cmi \ utils/clflags.cmi \ middle_end/flambda/types/env/binding_time.cmi \ @@ -9526,7 +9552,6 @@ middle_end/flambda/types/env/typing_env.rec.cmx : \ middle_end/flambda/basic/simple.cmx \ middle_end/flambda/basic/scope.cmx \ middle_end/flambda/naming/renaming.cmx \ - middle_end/flambda/compilenv_deps/rec_info.cmx \ utils/printing_cache.cmx \ middle_end/flambda/naming/name_occurrences.cmx \ middle_end/flambda/naming/name_mode.cmx \ @@ -9538,6 +9563,7 @@ middle_end/flambda/types/env/typing_env.rec.cmx : \ middle_end/flambda/types/kinds/flambda_kind.cmx \ middle_end/flambda/compilenv_deps/flambda_colours.cmx \ middle_end/flambda/compilenv_deps/compilation_unit.cmx \ + middle_end/flambda/compilenv_deps/coercion.cmx \ middle_end/flambda/types/structures/code_age_relation.cmx \ utils/clflags.cmx \ middle_end/flambda/types/env/binding_time.cmx \ @@ -9561,7 +9587,8 @@ middle_end/flambda/types/env/typing_env.rec.cmi : \ middle_end/flambda/compilenv_deps/compilation_unit.cmi \ middle_end/flambda/basic/code_id.cmi \ middle_end/flambda/types/structures/code_age_relation.cmi \ - middle_end/flambda/basic/apply_cont_rewrite_id.cmi + middle_end/flambda/basic/apply_cont_rewrite_id.cmi \ + middle_end/flambda/types/env/aliases.cmi middle_end/flambda/types/env/typing_env_extension.rec.cmo : \ middle_end/flambda/compilenv_deps/variable.cmi \ middle_end/flambda/naming/renaming.cmi \ @@ -9749,6 +9776,7 @@ middle_end/flambda/types/structures/function_declaration_type.rec.cmi : \ middle_end/flambda/types/basic/or_unknown_or_bottom.cmi \ middle_end/flambda/types/basic/or_bottom.cmi \ lambda/debuginfo.cmi \ + middle_end/flambda/compilenv_deps/coercion.cmi \ middle_end/flambda/basic/code_id.cmi middle_end/flambda/types/structures/product.rec.cmo : \ middle_end/flambda/basic/var_within_closure.cmi \ @@ -9894,20 +9922,20 @@ middle_end/flambda/types/structures/type_structure_intf.cmx : \ middle_end/flambda/naming/contains_names.cmx \ middle_end/flambda/cmx/contains_ids.cmx middle_end/flambda/types/type_of_kind/type_of_kind_naked_float0.rec.cmo : \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ middle_end/flambda/types/basic/or_unknown.cmi \ middle_end/flambda/types/basic/or_bottom.cmi \ utils/numbers.cmi \ middle_end/flambda/naming/name_occurrences.cmi \ middle_end/flambda/cmx/ids_for_export.cmi \ + middle_end/flambda/compilenv_deps/coercion.cmi \ middle_end/flambda/types/type_of_kind/type_of_kind_naked_float0.rec.cmi middle_end/flambda/types/type_of_kind/type_of_kind_naked_float0.rec.cmx : \ - middle_end/flambda/compilenv_deps/rec_info.cmx \ middle_end/flambda/types/basic/or_unknown.cmx \ middle_end/flambda/types/basic/or_bottom.cmx \ utils/numbers.cmx \ middle_end/flambda/naming/name_occurrences.cmx \ middle_end/flambda/cmx/ids_for_export.cmx \ + middle_end/flambda/compilenv_deps/coercion.cmx \ middle_end/flambda/types/type_of_kind/type_of_kind_naked_float0.rec.cmi middle_end/flambda/types/type_of_kind/type_of_kind_naked_float0.rec.cmi : \ middle_end/flambda/types/type_head_intf.cmo \ @@ -9915,98 +9943,98 @@ middle_end/flambda/types/type_of_kind/type_of_kind_naked_float0.rec.cmi : \ middle_end/flambda/types/type_of_kind/type_of_kind_naked_immediate0.rec.cmo : \ middle_end/flambda/compilenv_deps/target_imm.cmi \ lambda/tag.cmi \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ utils/printing_cache.cmi \ middle_end/flambda/types/basic/or_unknown.cmi \ middle_end/flambda/types/basic/or_bottom.cmi \ middle_end/flambda/naming/name_occurrences.cmi \ middle_end/flambda/cmx/ids_for_export.cmi \ + middle_end/flambda/compilenv_deps/coercion.cmi \ middle_end/flambda/types/type_of_kind/type_of_kind_naked_immediate0.rec.cmi middle_end/flambda/types/type_of_kind/type_of_kind_naked_immediate0.rec.cmx : \ middle_end/flambda/compilenv_deps/target_imm.cmx \ lambda/tag.cmx \ - middle_end/flambda/compilenv_deps/rec_info.cmx \ utils/printing_cache.cmx \ middle_end/flambda/types/basic/or_unknown.cmx \ middle_end/flambda/types/basic/or_bottom.cmx \ middle_end/flambda/naming/name_occurrences.cmx \ middle_end/flambda/cmx/ids_for_export.cmx \ + middle_end/flambda/compilenv_deps/coercion.cmx \ middle_end/flambda/types/type_of_kind/type_of_kind_naked_immediate0.rec.cmi middle_end/flambda/types/type_of_kind/type_of_kind_naked_immediate0.rec.cmi : \ middle_end/flambda/types/type_head_intf.cmo \ middle_end/flambda/compilenv_deps/target_imm.cmi middle_end/flambda/types/type_of_kind/type_of_kind_naked_int32_0.rec.cmo : \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ middle_end/flambda/types/basic/or_unknown.cmi \ middle_end/flambda/types/basic/or_bottom.cmi \ utils/numbers.cmi \ middle_end/flambda/naming/name_occurrences.cmi \ middle_end/flambda/cmx/ids_for_export.cmi \ + middle_end/flambda/compilenv_deps/coercion.cmi \ middle_end/flambda/types/type_of_kind/type_of_kind_naked_int32_0.rec.cmi middle_end/flambda/types/type_of_kind/type_of_kind_naked_int32_0.rec.cmx : \ - middle_end/flambda/compilenv_deps/rec_info.cmx \ middle_end/flambda/types/basic/or_unknown.cmx \ middle_end/flambda/types/basic/or_bottom.cmx \ utils/numbers.cmx \ middle_end/flambda/naming/name_occurrences.cmx \ middle_end/flambda/cmx/ids_for_export.cmx \ + middle_end/flambda/compilenv_deps/coercion.cmx \ middle_end/flambda/types/type_of_kind/type_of_kind_naked_int32_0.rec.cmi middle_end/flambda/types/type_of_kind/type_of_kind_naked_int32_0.rec.cmi : \ middle_end/flambda/types/type_head_intf.cmo middle_end/flambda/types/type_of_kind/type_of_kind_naked_int64_0.rec.cmo : \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ middle_end/flambda/types/basic/or_unknown.cmi \ middle_end/flambda/types/basic/or_bottom.cmi \ utils/numbers.cmi \ middle_end/flambda/naming/name_occurrences.cmi \ middle_end/flambda/cmx/ids_for_export.cmi \ + middle_end/flambda/compilenv_deps/coercion.cmi \ middle_end/flambda/types/type_of_kind/type_of_kind_naked_int64_0.rec.cmi middle_end/flambda/types/type_of_kind/type_of_kind_naked_int64_0.rec.cmx : \ - middle_end/flambda/compilenv_deps/rec_info.cmx \ middle_end/flambda/types/basic/or_unknown.cmx \ middle_end/flambda/types/basic/or_bottom.cmx \ utils/numbers.cmx \ middle_end/flambda/naming/name_occurrences.cmx \ middle_end/flambda/cmx/ids_for_export.cmx \ + middle_end/flambda/compilenv_deps/coercion.cmx \ middle_end/flambda/types/type_of_kind/type_of_kind_naked_int64_0.rec.cmi middle_end/flambda/types/type_of_kind/type_of_kind_naked_int64_0.rec.cmi : \ middle_end/flambda/types/type_head_intf.cmo middle_end/flambda/types/type_of_kind/type_of_kind_naked_nativeint0.rec.cmo : \ utils/targetint.cmi \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ middle_end/flambda/types/basic/or_unknown.cmi \ middle_end/flambda/types/basic/or_bottom.cmi \ middle_end/flambda/naming/name_occurrences.cmi \ middle_end/flambda/cmx/ids_for_export.cmi \ + middle_end/flambda/compilenv_deps/coercion.cmi \ middle_end/flambda/types/type_of_kind/type_of_kind_naked_nativeint0.rec.cmi middle_end/flambda/types/type_of_kind/type_of_kind_naked_nativeint0.rec.cmx : \ utils/targetint.cmx \ - middle_end/flambda/compilenv_deps/rec_info.cmx \ middle_end/flambda/types/basic/or_unknown.cmx \ middle_end/flambda/types/basic/or_bottom.cmx \ middle_end/flambda/naming/name_occurrences.cmx \ middle_end/flambda/cmx/ids_for_export.cmx \ + middle_end/flambda/compilenv_deps/coercion.cmx \ middle_end/flambda/types/type_of_kind/type_of_kind_naked_nativeint0.rec.cmi middle_end/flambda/types/type_of_kind/type_of_kind_naked_nativeint0.rec.cmi : \ middle_end/flambda/types/type_head_intf.cmo \ utils/targetint.cmi middle_end/flambda/types/type_of_kind/type_of_kind_value0.rec.cmo : \ middle_end/flambda/types/basic/string_info.cmi \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ utils/printing_cache.cmi \ middle_end/flambda/types/basic/or_unknown.cmi \ middle_end/flambda/types/basic/or_bottom.cmi \ middle_end/flambda/naming/name_occurrences.cmi \ middle_end/flambda/cmx/ids_for_export.cmi \ + middle_end/flambda/compilenv_deps/coercion.cmi \ middle_end/flambda/types/type_of_kind/type_of_kind_value0.rec.cmi middle_end/flambda/types/type_of_kind/type_of_kind_value0.rec.cmx : \ middle_end/flambda/types/basic/string_info.cmx \ - middle_end/flambda/compilenv_deps/rec_info.cmx \ utils/printing_cache.cmx \ middle_end/flambda/types/basic/or_unknown.cmx \ middle_end/flambda/types/basic/or_bottom.cmx \ middle_end/flambda/naming/name_occurrences.cmx \ middle_end/flambda/cmx/ids_for_export.cmx \ + middle_end/flambda/compilenv_deps/coercion.cmx \ middle_end/flambda/types/type_of_kind/type_of_kind_value0.rec.cmi middle_end/flambda/types/type_of_kind/type_of_kind_value0.rec.cmi : \ middle_end/flambda/types/type_head_intf.cmo \ @@ -10074,10 +10102,12 @@ middle_end/flambda/types/type_of_kind/boilerplate/type_of_kind_value.rec.cmi : \ middle_end/flambda/types/type_descr_intf.cmo middle_end/flambda/types/inlining/inlining_arguments.cmo : \ middle_end/flambda/types/basic/or_unknown.cmi \ + utils/misc.cmi \ utils/clflags.cmi \ middle_end/flambda/types/inlining/inlining_arguments.cmi middle_end/flambda/types/inlining/inlining_arguments.cmx : \ middle_end/flambda/types/basic/or_unknown.cmx \ + utils/misc.cmx \ utils/clflags.cmx \ middle_end/flambda/types/inlining/inlining_arguments.cmi middle_end/flambda/types/inlining/inlining_arguments.cmi : @@ -10098,6 +10128,7 @@ middle_end/flambda/unboxing/unbox_continuation_params.cmo : \ lambda/tag.cmi \ middle_end/flambda/simplify/simplify_import.cmi \ middle_end/flambda/basic/simple.cmi \ + middle_end/flambda/types/basic/or_unknown.cmi \ middle_end/flambda/types/basic/or_bottom.cmi \ middle_end/flambda/naming/name_mode.cmi \ middle_end/flambda/naming/name_in_binding_pos.cmi \ @@ -10117,6 +10148,7 @@ middle_end/flambda/unboxing/unbox_continuation_params.cmx : \ lambda/tag.cmx \ middle_end/flambda/simplify/simplify_import.cmx \ middle_end/flambda/basic/simple.cmx \ + middle_end/flambda/types/basic/or_unknown.cmx \ middle_end/flambda/types/basic/or_bottom.cmx \ middle_end/flambda/naming/name_mode.cmx \ middle_end/flambda/naming/name_in_binding_pos.cmx \ diff --git a/compilerlibs/Makefile.compilerlibs b/compilerlibs/Makefile.compilerlibs index cc8372dd617e..9433cde09b63 100644 --- a/compilerlibs/Makefile.compilerlibs +++ b/compilerlibs/Makefile.compilerlibs @@ -189,6 +189,7 @@ MIDDLE_END_FLAMBDA_COMPILENV_DEPS=\ middle_end/flambda/compilenv_deps/flambda_colours.cmo \ middle_end/flambda/compilenv_deps/compilation_unit.cmo \ middle_end/flambda/compilenv_deps/rec_info.cmo \ + middle_end/flambda/compilenv_deps/coercion.cmo \ middle_end/flambda/compilenv_deps/reg_width_things.cmo \ middle_end/flambda/compilenv_deps/symbol.cmo \ middle_end/flambda/compilenv_deps/variable.cmo \ diff --git a/middle_end/flambda/basic/kinded_parameter.ml b/middle_end/flambda/basic/kinded_parameter.ml index adf17eb9d340..f7ceeec23810 100644 --- a/middle_end/flambda/basic/kinded_parameter.ml +++ b/middle_end/flambda/basic/kinded_parameter.ml @@ -111,8 +111,6 @@ module List = struct let name_set t = Name.Set.of_list (List.map Name.var (vars t)) - let simple_set t = Simple.Set.of_list (simples t) - let rename t = List.map (fun t -> rename t) t let arity t = List.map (fun t -> Flambda_kind.With_subkind.kind (kind t)) t diff --git a/middle_end/flambda/basic/kinded_parameter.mli b/middle_end/flambda/basic/kinded_parameter.mli index 53c4f20e4d09..bc2a5533e0de 100644 --- a/middle_end/flambda/basic/kinded_parameter.mli +++ b/middle_end/flambda/basic/kinded_parameter.mli @@ -68,8 +68,6 @@ module List : sig (** As for [var_set] but returns a set of [Name]s. *) val name_set : t -> Name.Set.t - val simple_set : t -> Simple.Set.t - val equal_vars : t -> Variable.t list -> bool val rename : t -> t diff --git a/middle_end/flambda/basic/name.ml b/middle_end/flambda/basic/name.ml index 349b0c0e875e..73631dcee13a 100644 --- a/middle_end/flambda/basic/name.ml +++ b/middle_end/flambda/basic/name.ml @@ -104,3 +104,11 @@ let must_be_symbol_opt t = pattern_match t ~var:(fun _ -> None) ~symbol:(fun sym -> Some sym) + +module Pair = struct + include Identifiable.Make_pair + (Reg_width_things.Name) + (Reg_width_things.Name) + + type nonrec t = t * t +end diff --git a/middle_end/flambda/basic/name.mli b/middle_end/flambda/basic/name.mli index 2975d1f41d9c..3a1066112fd7 100644 --- a/middle_end/flambda/basic/name.mli +++ b/middle_end/flambda/basic/name.mli @@ -55,3 +55,10 @@ val must_be_var_opt : t -> Variable.t option val must_be_symbol_opt : t -> Symbol.t option val rename : t -> t + +module Pair : sig + type nonrec t = t * t + + include Identifiable.S with type t := t +end + diff --git a/middle_end/flambda/basic/simple.ml b/middle_end/flambda/basic/simple.ml index 72cf656c7673..11af38317ac3 100644 --- a/middle_end/flambda/basic/simple.ml +++ b/middle_end/flambda/basic/simple.ml @@ -53,25 +53,30 @@ let pattern_match' t ~var ~symbol ~const = let const_from_descr descr = const (RWC.of_descr descr) -let without_rec_info t = pattern_match t ~name ~const +let without_coercion t = pattern_match t ~name ~const -let merge_rec_info t ~newer_rec_info = - if is_const t then None +let apply_coercion t applied_coercion = + if Coercion.is_id applied_coercion then Some t else - match newer_rec_info with - | None -> Some t - | Some newer_rec_info -> - let rec_info = - match rec_info t with - | None -> newer_rec_info - | Some older_rec_info -> - Rec_info.merge older_rec_info ~newer:newer_rec_info - in - Some (with_rec_info (without_rec_info t) rec_info) + let coercion = + let existing_coercion = coercion t in + if Coercion.is_id existing_coercion then Some applied_coercion + else Coercion.compose existing_coercion ~then_:applied_coercion + in + coercion + |> Option.map (fun coercion -> with_coercion (without_coercion t) coercion) + +let apply_coercion_exn t applied_coercion = + match apply_coercion t applied_coercion with + | Some t -> t + | None -> + Misc.fatal_errorf "Cannot apply coercion %a to %a" + print t + Coercion.print applied_coercion (* CR mshinwell: Make naming consistent with [Name] re. the option type *) -(* CR mshinwell: Careful that Rec_info doesn't get dropped using the +(* CR mshinwell: Careful that coercions don't get dropped using the following *) let [@inline always] must_be_var t = @@ -86,7 +91,7 @@ let [@inline always] must_be_name t = let to_name t = match must_be_name t with | None -> None - | Some name -> Some (rec_info t, name) + | Some name -> Some (coercion t, name) let map_name t ~f = match must_be_name t with @@ -158,14 +163,6 @@ module List = struct else result end -module Pair = struct - include Identifiable.Make_pair - (Reg_width_things.Simple) - (Reg_width_things.Simple) - - type nonrec t = t * t -end - module With_kind = struct type nonrec t = t * Flambda_kind.t diff --git a/middle_end/flambda/basic/simple.mli b/middle_end/flambda/basic/simple.mli index 13cf022f211d..e91e42d75500 100644 --- a/middle_end/flambda/basic/simple.mli +++ b/middle_end/flambda/basic/simple.mli @@ -23,11 +23,13 @@ include module type of struct include Reg_width_things.Simple end include Contains_names.S with type t := t -val has_rec_info : t -> bool +val has_coercion : t -> bool -val merge_rec_info : t -> newer_rec_info:Rec_info.t option -> t option +val apply_coercion : t -> Coercion.t -> t option -val without_rec_info : t -> t +val apply_coercion_exn : t -> Coercion.t -> t + +val without_coercion : t -> t val must_be_var : t -> Variable.t option @@ -66,7 +68,7 @@ val const_from_descr : Reg_width_const.Descr.t -> t val map_name : t -> f:(Name.t -> Name.t) -> t -val to_name : t -> (Rec_info.t option * Name.t) option +val to_name : t -> (Coercion.t * Name.t) option (* CR mshinwell: remove these next two? *) val map_var : t -> f:(Variable.t -> Variable.t) -> t @@ -94,12 +96,6 @@ module List : sig include Identifiable.S with type t := t end -module Pair : sig - type nonrec t = t * t - - include Identifiable.S with type t := t -end - module With_kind : sig type nonrec t = t * Flambda_kind.t diff --git a/middle_end/flambda/cmx/flambda_cmx_format.ml b/middle_end/flambda/cmx/flambda_cmx_format.ml index 0c70ff5a4e5b..901f51b1257f 100644 --- a/middle_end/flambda/cmx/flambda_cmx_format.ml +++ b/middle_end/flambda/cmx/flambda_cmx_format.ml @@ -62,7 +62,7 @@ let create ~final_typing_env ~all_code ~exported_offsets ~used_closure_vars = Variable.Map.empty in let simples = - Simple.Set.fold (fun simple simples -> + Reg_width_things.Simple.Set.fold (fun simple simples -> Simple.Map.add simple (Simple.export simple) simples) exported_ids.simples Simple.Map.empty diff --git a/middle_end/flambda/cmx/ids_for_export.ml b/middle_end/flambda/cmx/ids_for_export.ml index 9e1192ea879c..487f56c9ef94 100644 --- a/middle_end/flambda/cmx/ids_for_export.ml +++ b/middle_end/flambda/cmx/ids_for_export.ml @@ -75,9 +75,9 @@ let add_name t name = let add_simple t simple = let simples = - match Simple.rec_info simple with - | None -> t.simples - | Some _ -> Simple.Set.add simple t.simples + match Simple.coercion simple with + | Id -> t.simples + | _ -> Simple.Set.add simple t.simples in let t = { t with simples; } in Simple.pattern_match simple @@ -90,14 +90,13 @@ let add_code_id t code_id = let add_continuation t continuation = { t with continuations = Continuation.Set.add continuation t.continuations } - let from_simple simple = let simples = - match Simple.rec_info simple with - | None -> + match Simple.coercion simple with + | Id -> (* This simple will not be in the grand_table_of_simples *) Simple.Set.empty - | Some _ -> Simple.Set.singleton simple + | _ -> Simple.Set.singleton simple in Simple.pattern_match simple ~const:(fun const -> diff --git a/middle_end/flambda/compare/compare.ml b/middle_end/flambda/compare/compare.ml index f80d9b7314dd..0ed6214e536c 100644 --- a/middle_end/flambda/compare/compare.ml +++ b/middle_end/flambda/compare/compare.ml @@ -766,6 +766,25 @@ let function_decls env decl1 decl2 : unit Comparison.t = else Different { approximant = () } ;; +(** Match up equal elements in two lists and iterate through both of them, + using [f] analogously to [Map.S.merge] *) +let iter2_merged l1 l2 ~compare ~f = + let l1 = List.sort compare l1 in + let l2 = List.sort compare l2 in + let rec go l1 l2 = + match l1, l2 with + | [] , [] -> () + | a1 :: l1, [] -> f (Some a1) None ; go l1 [] + | [] , a2 :: l2 -> f None (Some a2); go [] l2 + | a1 :: l1, a2 :: l2 -> + begin match compare a1 a2 with + | 0 -> f (Some a1) (Some a2); go l1 l2 + | c when c < 0 -> f (Some a1) None ; go l1 (a2 :: l2) + | _ -> f None (Some a2); go (a1 :: l1) l2 + end + in + go l1 l2 + let sets_of_closures env set1 set2 : Set_of_closures.t Comparison.t = (* Need to do unification on closure vars and closure ids, we we're going to * invert both maps, figuring the closure vars with the same value should be @@ -777,28 +796,28 @@ let sets_of_closures env set1 set2 : Set_of_closures.t Comparison.t = |> List.map (fun (var, value) -> subst_simple env value, var ) - |> Simple.Map.of_list in (* We want to process the whole map to find new correspondences between * closure vars, so we need to remember whether we've found any mismatches *) let ok = ref true in - (* Using merge here as a map version of [List.iter2]; always returning None - * means the returned map is always empty, so this shouldn't waste much *) - let _ : unit Simple.Map.t = - Simple.Map.merge (fun _value var1 var2 -> - begin - match var1, var2 with - | None, None -> () - | Some _, None | None, Some _ -> ok := false - | Some var1, Some var2 -> - begin - match closure_vars env var1 var2 with - | Equivalent -> () - | Different { approximant = _ } -> ok := false - end - end; - None - ) (closure_vars_by_value set1) (closure_vars_by_value set2) + let () = + let compare (value1, _var1) (value2, _var2) = + Simple.compare value1 value2 + in + iter2_merged (closure_vars_by_value set1) (closure_vars_by_value set2) + ~compare + ~f:(fun elt1 elt2 -> + begin + match elt1, elt2 with + | None, None -> () + | Some _, None | None, Some _ -> ok := false + | Some (_value1, var1), Some (_value2, var2) -> + begin + match closure_vars env var1 var2 with + | Equivalent -> () + | Different { approximant = _ } -> ok := false + end + end) in let closure_ids_and_fun_decls_by_code_id set = let map = Function_declarations.funs (Set_of_closures.function_decls set) in @@ -809,6 +828,8 @@ let sets_of_closures env set1 set2 : Set_of_closures.t Comparison.t = ) |> Code_id.Map.of_list in + (* Using merge here as a map version of [List.iter2]; always returning None + * means the returned map is always empty, so this shouldn't waste much *) let _ : unit Code_id.Map.t = Code_id.Map.merge (fun _code_id value1 value2 -> begin diff --git a/middle_end/flambda/compilenv_deps/coercion.ml b/middle_end/flambda/compilenv_deps/coercion.ml new file mode 100644 index 000000000000..2ac573a93674 --- /dev/null +++ b/middle_end/flambda/compilenv_deps/coercion.ml @@ -0,0 +1,74 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Mark Shinwell, Jane Street Europe *) +(* *) +(* Copyright 2019 Jane Street Group LLC *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +type t = + | Id + | Non_id of { + from_depth : int; + to_depth : int; + } + +let id = Id + +let change_depth ~from:from_depth ~to_:to_depth = + if from_depth = to_depth then Id else Non_id { from_depth; to_depth } + +let is_id = function + | Id -> true + | Non_id _ -> false + +let inverse = function + | Id -> Id + | Non_id { from_depth; to_depth } -> + Non_id { from_depth = to_depth; to_depth = from_depth } + +let print ppf = function + | Id -> + Format.fprintf ppf "@<0>%sid@<0>%s" + (Flambda_colours.elide ()) + (Flambda_colours.normal ()) + | Non_id { from_depth; to_depth; } -> + Format.fprintf ppf "@<0>%s@[(depth@ %d ->@ %d)@]@<0>%s" + (Flambda_colours.coercion ()) + from_depth to_depth + (Flambda_colours.normal ()) + +let compose t1 ~then_:t2 = + match t1, t2 with + | Id, _ -> Some t2 + | _, Id -> Some t1 + | Non_id { from_depth = from_depth1; to_depth = to_depth1 }, + Non_id { from_depth = from_depth2; to_depth = to_depth2 } -> + if to_depth1 = from_depth2 then + Some (change_depth ~from:from_depth1 ~to_:to_depth2) + else + None + +let compose_exn t1 ~then_:t2 = + match compose t1 ~then_:t2 with + | Some t -> t + | None -> + Misc.fatal_errorf "Invalid composition: %a@ >>@ %a" print t1 print t2 + +let equal t1 t2 = + match t1, t2 with + | Id, Id -> true + | Non_id { from_depth = from_depth1; to_depth = to_depth1 }, + Non_id { from_depth = from_depth2; to_depth = to_depth2 } -> + from_depth1 = from_depth2 && to_depth1 = to_depth2 + | _, _ -> false + +let hash = Hashtbl.hash + +let apply_to_rec_info _ rec_info = rec_info diff --git a/middle_end/flambda/compilenv_deps/coercion.mli b/middle_end/flambda/compilenv_deps/coercion.mli new file mode 100644 index 000000000000..da5a73f38f3c --- /dev/null +++ b/middle_end/flambda/compilenv_deps/coercion.mli @@ -0,0 +1,42 @@ +(**************************************************************************) +(* *) +(* OCaml *) +(* *) +(* Mark Shinwell, Jane Street Europe *) +(* *) +(* Copyright 2019 Jane Street Group LLC *) +(* *) +(* All rights reserved. This file is distributed under the terms of *) +(* the GNU Lesser General Public License version 2.1, with the *) +(* special exception on linking described in the file LICENSE. *) +(* *) +(**************************************************************************) + +[@@@ocaml.warning "+a-4-30-40-41-42"] + +type t = private + | Id + | Non_id of { + from_depth : int; + to_depth : int; + } + +val change_depth : from:int -> to_:int -> t + +val id : t + +val is_id : t -> bool + +val inverse : t -> t + +val compose : t -> then_:t -> t option + +val compose_exn : t -> then_:t -> t + +val print : Format.formatter -> t -> unit + +val equal : t -> t -> bool + +val hash : t -> int + +val apply_to_rec_info : t -> Rec_info.t -> Rec_info.t diff --git a/middle_end/flambda/compilenv_deps/flambda_colours.ml b/middle_end/flambda/compilenv_deps/flambda_colours.ml index 15587bb53aae..8a113fa32142 100644 --- a/middle_end/flambda/compilenv_deps/flambda_colours.ml +++ b/middle_end/flambda/compilenv_deps/flambda_colours.ml @@ -55,7 +55,9 @@ let continuation_annotation () = (C.fg_256 202) ^ (C.bg_256 237) let name_abstraction () = C.fg_256 172 -let rec_info () = C.fg_256 243 +let rec_info () = C.fg_256 249 + +let coercion () = C.fg_256 249 let error () = C.fg_256 160 diff --git a/middle_end/flambda/compilenv_deps/flambda_colours.mli b/middle_end/flambda/compilenv_deps/flambda_colours.mli index c739912f6902..6bfacfc74bc1 100644 --- a/middle_end/flambda/compilenv_deps/flambda_colours.mli +++ b/middle_end/flambda/compilenv_deps/flambda_colours.mli @@ -55,6 +55,8 @@ val name_abstraction : unit -> string val rec_info : unit -> string +val coercion : unit -> string + val elide : unit -> string val error : unit -> string diff --git a/middle_end/flambda/compilenv_deps/rec_info.ml b/middle_end/flambda/compilenv_deps/rec_info.ml index 0bf79e7561ae..ebc1d84e6544 100644 --- a/middle_end/flambda/compilenv_deps/rec_info.ml +++ b/middle_end/flambda/compilenv_deps/rec_info.ml @@ -13,54 +13,27 @@ (**************************************************************************) [@@@ocaml.warning "+a-4-30-40-41-42"] - -type t = { - depth : int; - unroll_to : int option; -} +type t = unit include Identifiable.Make (struct type nonrec t = t - let print ppf { depth; unroll_to; } = - Format.fprintf ppf "%s@[(\ - @[(depth@ %d)@]@ \ - @[(unroll_to@ %a)@]\ - )@]%s" - (Flambda_colours.rec_info ()) - depth - (Misc.Stdlib.Option.print Numbers.Int.print) unroll_to - (Flambda_colours.normal ()) + let print ppf () = + Format.fprintf ppf "@<0>%s()@<0>%s" + (Flambda_colours.rec_info ()) + (Flambda_colours.normal ()) - let compare t1 t2 = Stdlib.compare t1 t2 + let compare () () = 0 - let equal t1 t2 = (compare t1 t2 = 0) + let equal () () = true - let hash t = Hashtbl.hash t + let hash () = Hashtbl.hash () let output _ _ = Misc.fatal_error "Not yet implemented" end) -let create ~depth ~unroll_to = - { depth; - unroll_to; - } - -let depth t = t.depth -let unroll_to t = t.unroll_to - -let merge { depth = depth1; unroll_to = older_unroll_to; } ~newer = - let { depth = depth2; unroll_to = newer_unroll_to; } = newer in - let depth = depth1 + depth2 in - let unroll_to = - match newer_unroll_to with - | Some _ -> newer_unroll_to - | None -> older_unroll_to - in - { depth; - unroll_to; - } +let initial = () -let initial = create ~depth:0 ~unroll_to:None +let unknown = () -let is_initial t = equal t initial +let is_initial () = true diff --git a/middle_end/flambda/compilenv_deps/rec_info.mli b/middle_end/flambda/compilenv_deps/rec_info.mli index cb2c759b28e2..937570d92ba7 100644 --- a/middle_end/flambda/compilenv_deps/rec_info.mli +++ b/middle_end/flambda/compilenv_deps/rec_info.mli @@ -13,19 +13,13 @@ (**************************************************************************) [@@@ocaml.warning "+a-4-30-40-41-42"] - type t include Identifiable.S with type t := t -val create : depth:int -> unroll_to:int option -> t - -val depth : t -> int - -val unroll_to : t -> int option - -val merge : t -> newer:t -> t - val initial : t +val unknown : t + val is_initial : t -> bool + diff --git a/middle_end/flambda/compilenv_deps/reg_width_things.ml b/middle_end/flambda/compilenv_deps/reg_width_things.ml index 778a549e88cd..4ffdcc43daea 100644 --- a/middle_end/flambda/compilenv_deps/reg_width_things.ml +++ b/middle_end/flambda/compilenv_deps/reg_width_things.ml @@ -224,28 +224,28 @@ end module Simple_data = struct type t = { - simple : Id.t; (* always without [Rec_info] *) - rec_info : Rec_info.t; + simple : Id.t; (* always without [Coercion] *) + coercion : Coercion.t; } let flags = simple_flags - let print ppf { simple = _; rec_info; } = + let print ppf { simple = _; coercion; } = Format.fprintf ppf "@[\ - @[(rec_info@ %a)@]\ + @[(coercion@ %a)@]\ @]" - Rec_info.print rec_info + Coercion.print coercion - let hash { simple; rec_info; } = - Hashtbl.hash (Id.hash simple, Rec_info.hash rec_info) + let hash { simple; coercion; } = + Hashtbl.hash (Id.hash simple, Coercion.hash coercion) let equal t1 t2 = if t1 == t2 then true else - let { simple = simple1; rec_info = rec_info1; } = t1 in - let { simple = simple2; rec_info = rec_info2; } = t2 in + let { simple = simple1; coercion = coercion1; } = t1 in + let { simple = simple2; coercion = coercion2; } = t2 in Id.equal simple1 simple2 - && Rec_info.equal rec_info1 rec_info2 + && Coercion.equal coercion1 coercion2 end module Const = struct @@ -519,7 +519,7 @@ module Simple = struct let find_data t = Table.find !grand_table_of_simples t - let has_rec_info t = + let has_coercion t = Id.flags t = simple_flags let name n = n @@ -553,10 +553,10 @@ module Simple = struct in pattern_match t1 ~name ~const - let [@inline always] rec_info t = + let [@inline always] coercion t = let flags = Id.flags t in - if flags = simple_flags then Some ((find_data t).rec_info) - else None + if flags = simple_flags then (find_data t).coercion + else Coercion.id module T0 = struct let compare = Id.compare @@ -569,15 +569,12 @@ module Simple = struct ~name:(fun name -> Name.print ppf name) ~const:(fun cst -> Const.print ppf cst) in - match rec_info t with - | None -> print ppf t - | Some rec_info -> - Format.fprintf ppf "@[\ - @[(simple@ %a)@] \ - @[(rec_info@ %a)@]\ - @]" + match coercion t with + | Id -> print ppf t + | Non_id _ as coercion -> + Format.fprintf ppf "@[(coerce@ %a@ %a)@]" print t - Rec_info.print rec_info + Coercion.print coercion let output chan t = print (Format.formatter_of_out_channel chan) t @@ -589,16 +586,16 @@ module Simple = struct include T0 end - let with_rec_info t new_rec_info = - if Rec_info.is_initial new_rec_info then t + let with_coercion t new_coercion = + if Coercion.is_id new_coercion then t else - match rec_info t with - | None -> - let data : Simple_data.t = { simple = t; rec_info = new_rec_info; } in + match coercion t with + | Id -> + let data : Simple_data.t = { simple = t; coercion = new_coercion; } in Table.add !grand_table_of_simples data - | Some _ -> - Misc.fatal_errorf "Cannot add [Rec_info] to [Simple] %a that already \ - has [Rec_info]" + | Non_id _ -> + Misc.fatal_errorf "Cannot add [Coercion] to [Simple] %a that already \ + has non-identity [Coercion]" print t module Set = Patricia_tree.Make_set (struct let print = print end) diff --git a/middle_end/flambda/compilenv_deps/reg_width_things.mli b/middle_end/flambda/compilenv_deps/reg_width_things.mli index b3e23f93f93d..24270f9d1528 100644 --- a/middle_end/flambda/compilenv_deps/reg_width_things.mli +++ b/middle_end/flambda/compilenv_deps/reg_width_things.mli @@ -154,13 +154,15 @@ module Simple : sig val const : Const.t -> t - val rec_info : t -> Rec_info.t option + val coercion : t -> Coercion.t - val with_rec_info : t -> Rec_info.t -> t + val with_coercion : t -> Coercion.t -> t (* This does not consult the grand table of [Simple]s. *) - val has_rec_info : t -> bool + val has_coercion : t -> bool + (* CR lmaurer: Should make [name] and [const] take a [coercion] argument to + be sure we're not dropping coercions by accident. *) val pattern_match : t -> name:(Name.t -> 'a) @@ -168,7 +170,7 @@ module Simple : sig -> 'a (* [same s1 s2] returns true iff they represent the same name or const - i.e. [same s (with_rec_info s rec_info)] returns true *) + i.e. [same s (with_coercion s coercion)] returns true *) val same : t -> t -> bool val export : t -> exported diff --git a/middle_end/flambda/inlining/inlining_decision.ml b/middle_end/flambda/inlining/inlining_decision.ml index bac7aa2077c4..c50eb597efaa 100644 --- a/middle_end/flambda/inlining/inlining_decision.ml +++ b/middle_end/flambda/inlining/inlining_decision.ml @@ -396,34 +396,25 @@ let might_inline dacc ~apply ~function_decl ~simplify_expr ~return_arity Speculatively_not_inline { cost_metrics; evaluated_to; threshold } let make_decision_for_call_site dacc ~simplify_expr ~function_decl - ~function_decl_rec_info ~apply ~return_arity : Call_site_decision.t = + ~function_decl_rec_info:_ ~apply ~return_arity : Call_site_decision.t = let inline = Apply.inline apply in match inline with | Never_inline -> Never_inline_attribute | Default_inline | Unroll _ | Always_inline | Hint_inline -> - match Rec_info.unroll_to function_decl_rec_info with - | Some unroll_to -> - if Rec_info.depth function_decl_rec_info >= unroll_to then - Unrolling_depth_exceeded - else + let apply_inlining_state = Apply.inlining_state apply in + if Inlining_state.is_depth_exceeded apply_inlining_state + then + Max_inlining_depth_exceeded + else + match inline with + | Never_inline -> assert false + | Default_inline -> might_inline dacc ~apply ~function_decl ~simplify_expr ~return_arity - | None -> - let apply_inlining_state = Apply.inlining_state apply in - if Inlining_state.is_depth_exceeded apply_inlining_state - then - Max_inlining_depth_exceeded - else - match inline with - | Never_inline -> assert false - | Default_inline -> - if Rec_info.depth function_decl_rec_info >= max_rec_depth then - Recursion_depth_exceeded - else - might_inline dacc ~apply ~function_decl ~simplify_expr ~return_arity - | Unroll unroll_to -> - let unroll_to = - Rec_info.depth function_decl_rec_info + unroll_to - in - Attribute_unroll unroll_to - | Always_inline | Hint_inline -> - Attribute_always + | Unroll unroll_to -> + Attribute_unroll unroll_to + | Always_inline | Hint_inline -> + Attribute_always + +let _ = Call_site_decision.Unrolling_depth_exceeded +let _ = Call_site_decision.Recursion_depth_exceeded +let _ = max_rec_depth diff --git a/middle_end/flambda/inlining/inlining_transforms.ml b/middle_end/flambda/inlining/inlining_transforms.ml index 3c3bd9f5f3ee..71d42623c9aa 100644 --- a/middle_end/flambda/inlining/inlining_transforms.ml +++ b/middle_end/flambda/inlining/inlining_transforms.ml @@ -40,8 +40,8 @@ let make_inlined_body ~callee ~unroll_to ~params ~args ~my_closure ~body apply_exn_continuation in let callee = - Simple.merge_rec_info callee - ~newer_rec_info:(Some (Rec_info.create ~depth:1 ~unroll_to)) + (* CR xclerc for xclerc: build the proper coercion. *) + Simple.apply_coercion callee (ignore unroll_to; Coercion.id) |> Option.get (* CR mshinwell: improve *) in Expr.apply_renaming diff --git a/middle_end/flambda/naming/renaming.ml b/middle_end/flambda/naming/renaming.ml index 6eb02800c98e..cad33dc07fea 100644 --- a/middle_end/flambda/naming/renaming.ml +++ b/middle_end/flambda/naming/renaming.ml @@ -329,16 +329,13 @@ let apply_simple t simple = let [@inline always] name old_name = let new_name = apply_name t old_name in if old_name == new_name then simple - else - match Simple.rec_info simple with - | None -> Simple.name new_name - | Some rec_info -> Simple.with_rec_info (Simple.name new_name) rec_info + else Simple.with_coercion (Simple.name new_name) (Simple.coercion simple) in (* Constants are never permuted, only freshened upon import. *) Simple.pattern_match simple ~name ~const:(fun cst -> - assert (not (Simple.has_rec_info simple)); + assert (not (Simple.has_coercion simple)); Simple.const (apply_const t cst)) let closure_var_is_used t closure_var = diff --git a/middle_end/flambda/simplify/common_subexpression_elimination.ml b/middle_end/flambda/simplify/common_subexpression_elimination.ml index ae91a05d45cb..71ae7cb9bf7d 100644 --- a/middle_end/flambda/simplify/common_subexpression_elimination.ml +++ b/middle_end/flambda/simplify/common_subexpression_elimination.ml @@ -117,7 +117,12 @@ end let cse_with_eligible_lhs ~typing_env_at_fork ~cse_at_each_use ~params prev_cse (extra_bindings: EPA.t) extra_equations = - let params = KP.List.simple_set params in + let params = KP.List.name_set params in + let is_param simple = + Simple.pattern_match simple + ~name:(fun name -> Name.Set.mem name params) + ~const:(fun _ -> false) + in List.fold_left cse_at_each_use ~init:EP.Map.empty ~f:(fun eligible (env_at_use, id, cse) -> let find_new_name = @@ -185,15 +190,17 @@ let cse_with_eligible_lhs ~typing_env_at_fork ~cse_at_each_use ~params prev_cse since they are defined in [env_at_fork]. However these aren't bound at the use sites, so we must choose another alias that is. *) - if not (Simple.Set.mem bound_to params) then Some bound_to + if not (is_param bound_to) then Some bound_to else let aliases = TE.aliases_of_simple env_at_use ~min_name_mode:NM.normal bound_to - |> Simple.Set.filter (fun simple -> - not (Simple.Set.mem simple params)) + |> Aliases.Alias_set.filter ~f:(fun simple -> + not (is_param simple)) in - Simple.Set.get_singleton aliases + (* CR lmaurer: This could be using + [Aliases.Alias_set.find_best], I think? *) + Aliases.Alias_set.get_singleton aliases in match bound_to with | None -> eligible diff --git a/middle_end/flambda/simplify/simplify_apply_expr.ml b/middle_end/flambda/simplify/simplify_apply_expr.ml index dfd7ac5aab97..8f1e75f00ece 100644 --- a/middle_end/flambda/simplify/simplify_apply_expr.ml +++ b/middle_end/flambda/simplify/simplify_apply_expr.ml @@ -114,13 +114,13 @@ let simplify_direct_full_application ~simplify_expr dacc apply function_decl_opt definition)" end; None - | Some (function_decl, function_decl_rec_info) -> + | Some function_decl -> let decision = Inlining_decision.make_decision_for_call_site dacc ~simplify_expr ~apply ~function_decl - ~function_decl_rec_info + ~function_decl_rec_info:Rec_info.unknown ~return_arity:result_arity in let code_id = T.Function_declaration_type.Inlinable.code_id function_decl in @@ -641,14 +641,6 @@ let simplify_function_call ~simplify_expr dacc apply ~callee_ty | Indirect_unknown_arity | Indirect_known_arity _ -> None in - (* CR mshinwell: This should go in Typing_env (ditto logic for Rec_info - in Simplify_simple *) - let function_decl_rec_info = - let rec_info = I.rec_info inlinable in - match Simple.rec_info (Apply.callee apply) with - | None -> rec_info - | Some newer -> Rec_info.merge rec_info ~newer - in let callee's_code_id_from_type = I.code_id inlinable in let callee's_code = DE.find_code denv callee's_code_id_from_type in let must_be_detupled = call_must_be_detupled (I.is_tupled inlinable) in @@ -658,7 +650,7 @@ let simplify_function_call ~simplify_expr dacc apply ~callee_ty ~result_arity:(Code.result_arity callee's_code) ~recursive:(Code.recursive callee's_code) ~must_be_detupled - (Some (inlinable, function_decl_rec_info)) + (Some inlinable) ~down_to_up | Ok (Non_inlinable non_inlinable) -> let module N = T.Function_declaration_type.Non_inlinable in diff --git a/middle_end/flambda/simplify/simplify_set_of_closures.ml b/middle_end/flambda/simplify/simplify_set_of_closures.ml index c0eba90eb599..643568a149ae 100644 --- a/middle_end/flambda/simplify/simplify_set_of_closures.ml +++ b/middle_end/flambda/simplify/simplify_set_of_closures.ml @@ -151,7 +151,6 @@ end = struct closure_element_types_inside_function) -> let function_decls = Set_of_closures.function_decls set_of_closures in let all_function_decls_in_set = - (* CR mshinwell: [Rec_info] may be wrong. *) Closure_id.Map.map (fun function_decl -> let new_code_id = Code_id.Map.find (FD.code_id function_decl) @@ -162,7 +161,7 @@ end = struct denv function_decl ~code_id:new_code_id ~cost_metrics_source:From_denv - (Rec_info.create ~depth:1 ~unroll_to:None)) + Rec_info.unknown) (Function_declarations.funs function_decls) in Closure_id.Map.mapi (fun closure_id _function_decl -> @@ -500,7 +499,7 @@ let simplify_function context ~used_closure_vars ~shareable_constants ~pass:Inlining_report.After_simplify ~cost_metrics_source:(Metrics cost_metrics) (DA.denv dacc_after_body) function_decl - Rec_info.initial + Rec_info.unknown in { function_decl; new_code_id; diff --git a/middle_end/flambda/simplify/simplify_unary_primitive.ml b/middle_end/flambda/simplify/simplify_unary_primitive.ml index 16d70fa85d5e..c730f6292709 100644 --- a/middle_end/flambda/simplify/simplify_unary_primitive.ml +++ b/middle_end/flambda/simplify/simplify_unary_primitive.ml @@ -38,12 +38,12 @@ module Int64 = Numbers.Int64 {(thd3/0 (Ok (Inlinable (code_id thd3_0_tuple_stub/2) (param_arity 𝕍) (result_arity 𝕍) (stub true) (dbg ) (inline Default_inline) - (is_a_functor false) (recursive Non_recursive) (rec_info ((depth 1) (unroll_to None)))))) + (is_a_functor false) (recursive Non_recursive) (coercion ((depth 1) (unroll_to None)))))) (thd3/1 (Ok (Inlinable (code_id thd3_0/3) (param_arity 𝕍 ⨯ 𝕍 ⨯ 𝕍) (result_arity 𝕍) (stub false) (dbg tuple_stub.ml:1,9--20) (inline Default_inline) (is_a_functor false) (recursive Non_recursive) - (rec_info ((depth 1) (unroll_to None))))))}) + (coercion ((depth 1) (unroll_to None))))))}) (closure_types ((components_by_index {(thd3/0 (Val (= Tuple_stub.camlTuple_stub__thd3_2))) (thd3/1 (Val (= Tuple_stub.camlTuple_stub__thd3_3)))}))) (closure_var_types ((components_by_index {})))))}) (other_tags Bottom))) unboxed_version/48 : (Val (= Tuple_stub.camlTuple_stub__thd3_3))))) diff --git a/middle_end/flambda/types/env/aliases.ml b/middle_end/flambda/types/env/aliases.ml index a863a366fda4..9fd3a46335c0 100644 --- a/middle_end/flambda/types/env/aliases.ml +++ b/middle_end/flambda/types/env/aliases.ml @@ -14,6 +14,48 @@ [@@@ocaml.warning "+a-4-30-40-41-42"] +module Const = Reg_width_things.Const + +type coercion_to_canonical = Coercion.t +type map_to_canonical = coercion_to_canonical Name.Map.t + +let compose_map_values_exn map ~then_:coercion = + if Coercion.is_id coercion then map else + Name.Map.map (fun old_coercion -> + Coercion.compose_exn old_coercion ~then_:coercion + ) map + +let fatal_inconsistent ~func_name elt coercion1 coercion2 = + Misc.fatal_errorf "[%s] maps with inconsistent element/coercion couples; \ + %a has coercions %a and %a" + func_name + Name.print elt + Coercion.print coercion1 + Coercion.print coercion2 + +let map_inter map1 map2 = + Name.Map.merge (fun elt coercion1 coercion2 -> + match coercion1, coercion2 with + | None, None | Some _, None | None, Some _ -> None + | Some coercion1, Some coercion2 -> + if Coercion.equal coercion1 coercion2 then + Some coercion1 + else + fatal_inconsistent ~func_name:"Aliases.map_inter" elt coercion1 coercion2) + map1 + map2 + +let map_union map1 map2 = + Name.Map.union (fun elt coercion1 coercion2 -> + match coercion1, coercion2 with + | coercion1, coercion2 -> + if Coercion.equal coercion1 coercion2 then + Some coercion1 + else + fatal_inconsistent ~func_name:"Aliases.map_union" elt coercion1 coercion2) + map1 + map2 + module Aliases_of_canonical_element : sig type t @@ -24,61 +66,81 @@ module Aliases_of_canonical_element : sig val empty : t val is_empty : t -> bool - val add : t -> Simple.t -> Name_mode.t -> t + val add : t -> Name.t -> coercion_to_canonical:Coercion.t -> Name_mode.t -> t val find_earliest_candidates : t - -> filter_by_scope:(Name_mode.t -> Simple.Set.t -> Simple.Set.t) + -> filter_by_scope:(Name_mode.t -> map_to_canonical -> map_to_canonical) -> min_name_mode:Name_mode.t - -> Simple.Set.t option + -> map_to_canonical option - val all : t -> Simple.Set.t + val all : t -> map_to_canonical - val mem : t -> Simple.t -> bool + val mem : t -> Name.t -> bool val union : t -> t -> t val inter : t -> t -> t - val rename : (Simple.t -> Simple.t) -> t -> t + val rename : (Name.t -> Name.t) -> t -> t val merge : t -> t -> t + + val compose : t -> then_:Coercion.t -> t end = struct type t = { - aliases : Simple.Set.t Name_mode.Map.t; - all : Simple.Set.t; + aliases : map_to_canonical Name_mode.Map.t; + all : map_to_canonical; } - let invariant _t = () + let invariant { aliases; all; } = + (* The elements in [aliases] have disjoint set of keys. *) + let aliases_union : map_to_canonical = + Name_mode.Map.fold (fun _name_mode map acc -> + Name.Map.union (fun elt _coercion1 _coercion2 -> + Misc.fatal_errorf "[Aliases_of_canonical_element.invariant]: \ + element %a appears in several modes" + Name.print elt) + map + acc) + aliases + Name.Map.empty + in + (* [all] is the union of all elements in [aliases] *) + if Name.Map.equal Coercion.equal all aliases_union then + () + else + Misc.fatal_errorf "[Aliases_of_canonical_element.invariant]: \ + [aliases] and [all] are not consistent" let print ppf { aliases; all = _; } = - Name_mode.Map.print Simple.Set.print ppf aliases + Name_mode.Map.print (Name.Map.print Coercion.print) ppf aliases let empty = { aliases = Name_mode.Map.empty; - all = Simple.Set.empty; + all = Name.Map.empty; } - let is_empty t = Simple.Set.is_empty t.all + let is_empty t = Name.Map.is_empty t.all - let add t elt name_mode = - if Simple.Set.mem elt t.all then begin + let add t elt ~coercion_to_canonical name_mode = + if Name.Map.mem elt t.all then begin Misc.fatal_errorf "%a already added to [Aliases_of_canonical_element]: \ - %a" - Simple.print elt + %a" + Name.print elt print t end; let aliases = Name_mode.Map.update name_mode (function - | None -> Some (Simple.Set.singleton elt) + | None -> Some (Name.Map.singleton elt coercion_to_canonical) | Some elts -> if !Clflags.flambda_invariant_checks then begin - assert (not (Simple.Set.mem elt elts)) + assert (not (Name.Map.mem elt elts)) end; - Some (Simple.Set.add elt elts)) + Some (Name.Map.add elt coercion_to_canonical elts)) t.aliases in - let all = Simple.Set.add elt t.all in + let all = Name.Map.add elt coercion_to_canonical t.all in { aliases; all; } @@ -96,137 +158,302 @@ end = struct | Some result -> if result >= 0 then let aliases = filter_by_scope order aliases in - if Simple.Set.is_empty aliases then None else Some aliases + if Name.Map.is_empty aliases then None else Some aliases else None end) t.aliases None let mem t elt = - Simple.Set.mem elt t.all + Name.Map.mem elt t.all let all t = t.all let union t1 t2 = - let aliases = + let aliases : map_to_canonical Name_mode.Map.t= Name_mode.Map.union (fun _order elts1 elts2 -> - Some (Simple.Set.union elts1 elts2)) + Some (map_union elts1 elts2)) t1.aliases t2.aliases in let t = { aliases; - all = Simple.Set.union t1.all t2.all; + all = map_union t1.all t2.all; } in - invariant t; + invariant t; (* CR xclerc for xclerc: not guaranteed to hold *) t let inter t1 t2 = let aliases = Name_mode.Map.merge (fun _order elts1 elts2 -> - match elts1, elts2 with - | None, None | Some _, None | None, Some _ -> None - | Some elts1, Some elts2 -> Some (Simple.Set.inter elts1 elts2)) + match elts1, elts2 with + | None, None | Some _, None | None, Some _ -> None + | Some elts1, Some elts2 -> + Some (map_inter elts1 elts2)) t1.aliases t2.aliases in let t = { aliases; - all = Simple.Set.inter t1.all t2.all; + all = map_inter t1.all t2.all; } in invariant t; t - let rename rename_simple { aliases; all } = - let aliases = - Name_mode.Map.map (fun elts -> Simple.Set.map rename_simple elts) - aliases + let rename rename_name { aliases; all } = + let map_name elts = + Name.Map.fold (fun elt coercion acc -> + Name.Map.add (rename_name elt) coercion acc) + elts + Name.Map.empty in - let all = Simple.Set.map rename_simple all in - { aliases; all } + let aliases = Name_mode.Map.map map_name aliases in + let all = map_name all in + let t = { aliases; all } in + invariant t; (* CR xclerc for xclerc: not guaranteed to hold *) + t let merge t1 t2 = let aliases = - Name_mode.Map.union (fun _mode set1 set2 -> - Some (Simple.Set.union set1 set2)) + Name_mode.Map.union (fun _mode map1 map2 -> + Some (map_union map1 map2) + ) t1.aliases t2.aliases in - let all = Simple.Set.union t1.all t2.all in + let all = map_union t1.all t2.all in + let t = { aliases; all; } in + invariant t; (* CR xclerc for xclerc: not guaranteed to hold *) + t + + let compose { aliases; all; } ~then_ = + let f m = + Name.Map.map (Coercion.compose_exn ~then_) m + in + let aliases = Name_mode.Map.map f aliases in + let all = f all in { aliases; all; } end +module Alias_set = struct + type t = { + const : Const.t option; + names : map_to_canonical; + } + + let empty = { const = None; names = Name.Map.empty; } + + let singleton simple = + Simple.pattern_match simple + ~const:(fun const -> + { const = Some const; names = Name.Map.empty; }) + ~name:(fun name -> + { const = None; names = Name.Map.singleton name Coercion.id }) + + let get_singleton { const; names; } = + match const with + | Some const -> + if Name.Map.is_empty names then Some (Simple.const const) else None + | None -> + Name.Map.get_singleton names + |> Option.map (fun (name, coercion) -> + Simple.with_coercion (Simple.name name) coercion) + + let print ppf { const; names; } = + let none ppf () = + Format.fprintf ppf "@<0>%s()" (Flambda_colours.elide ()) + in + Format.fprintf ppf + "@[(\ + @[(const@ %a)@]@ \ + @[(names@ %a)@]@ \ + @]" + (Format.pp_print_option Const.print ~none) const + (Name.Map.print Coercion.print) names + + let inter + { const = const1; names = names1; } + { const = const2; names = names2; } = + let const = + match const1, const2 with + | Some const1, Some const2 when Const.equal const1 const2 -> Some const1 + | _, _ -> None + in + let names = map_inter names1 names2 in + { const; names; } + + let filter { const; names; } ~f = + let const = + match const with + | Some const when f (Simple.const const) -> Some const + | _ -> None + in + let names = + Name.Map.filter (fun name coercion -> + let simple = Simple.with_coercion (Simple.name name) coercion in + f simple + ) names + in + { const; names; } + + let find_best { const; names; } = + match const with + | Some const -> Some (Simple.const const) + | None -> + let key_is_symbol key _data = Name.is_symbol key in + let (symbols, vars) = Name.Map.partition key_is_symbol names in + match Name.Map.min_binding_opt symbols with + | Some (symbol, coercion) -> + Some (Simple.with_coercion (Simple.name symbol) coercion) + | None -> + match Name.Map.min_binding_opt vars with + | Some (var, coercion) -> + Some (Simple.with_coercion (Simple.name var) coercion) + | None -> + None +end + + type t = { - canonical_elements : Simple.t Simple.Map.t; + canonical_elements : (Simple.t * coercion_to_canonical) Name.Map.t; (* Canonical elements that have no known aliases are not included in [canonical_elements]. *) - aliases_of_canonical_elements : Aliases_of_canonical_element.t Simple.Map.t; - (* For [elt |-> aliases] in [aliases_of_canonical_elements], then + aliases_of_canonical_names : Aliases_of_canonical_element.t Name.Map.t; + (* For [elt |-> aliases] in [aliases_of_canonical_names], then [aliases] never includes [elt]. *) (* CR mshinwell: check this always holds *) - binding_times_and_modes : Binding_time.With_name_mode.t Simple.Map.t; + aliases_of_consts : Aliases_of_canonical_element.t Const.Map.t; + binding_times_and_modes : Binding_time.With_name_mode.t Name.Map.t; (* Binding times and name modes define an order on the elements. The canonical element for a set of aliases is always the minimal element for this order, which is different from the order used for creating sets and maps. *) } -let print ppf { canonical_elements; aliases_of_canonical_elements; - binding_times_and_modes; } = +(* Canonical elements can be seen as a collection of star graphs: + + canon_i <--[coercion_i_0]-- elem_i_0 + ^ ^--[...]-- ... + \--[coercion_i_m]-- elem_i_m + + ... + + canon_j <--[coercion_j_0]-- elem_j_0 + ^ ^--[...]-- ... + \--[coercion_j_n]-- elem_j_n + + + stored as a map: + + canonical_elements[elem_i_0] = (canon_i, coercion_i_0) + ... + canonical_elements[elem_i_m] = (canon_i, coercion_i_m) + + ... + + canonical_elements[elem_j_0] = (canon_j, coercion_j_0) + ... + canonical_elements[elem_j_n] = (canon_j, coercion_j_n) +*) + +let print ppf { canonical_elements; aliases_of_canonical_names; + aliases_of_consts; binding_times_and_modes; } = + let print_element_and_coercion ppf (elt, coercion) = + Format.fprintf ppf "@[(\ + %a@ \ + @[@<0>%s(coercion@ %a)@<0>%s@]\ + )@]" + Simple.print elt + (if Coercion.is_id coercion + then Flambda_colours.elide () + else Flambda_colours.normal ()) + Coercion.print coercion + (Flambda_colours.normal ()) + in Format.fprintf ppf "@[(\ - @[(canonical_elements@ %a)@]@ \ - @[(aliases_of_canonical_elements@ %a)@]@ \ - @[(binding_times_and_modes@ %a)@]\ - )@]" - (Simple.Map.print Simple.print) canonical_elements - (Simple.Map.print Aliases_of_canonical_element.print) - aliases_of_canonical_elements - (Simple.Map.print Binding_time.With_name_mode.print) + @[(canonical_elements@ %a)@]@ \ + @[(aliases_of_canonical_names@ %a)@]@ \ + @[(aliases_of_consts@ %a)@]@ \ + @[(binding_times_and_modes@ %a)@]\ + )@]" + (Name.Map.print print_element_and_coercion) canonical_elements + (Name.Map.print Aliases_of_canonical_element.print) + aliases_of_canonical_names + (Const.Map.print Aliases_of_canonical_element.print) + aliases_of_consts + (Name.Map.print Binding_time.With_name_mode.print) binding_times_and_modes -let defined_earlier t alias ~than = - let info1 = Simple.Map.find alias t.binding_times_and_modes in - let info2 = Simple.Map.find than t.binding_times_and_modes in +let name_defined_earlier t alias ~than = + let info1 = Name.Map.find alias t.binding_times_and_modes in + let info2 = Name.Map.find than t.binding_times_and_modes in Binding_time.strictly_earlier (Binding_time.With_name_mode.binding_time info1) ~than:(Binding_time.With_name_mode.binding_time info2) +let defined_earlier t alias ~than = + Simple.pattern_match than + ~const:(fun _ -> false) + ~name:(fun than -> + Simple.pattern_match alias + ~const:(fun _ -> true) + ~name:(fun alias -> name_defined_earlier t alias ~than)) + +let binding_time_and_name_mode t elt = + Simple.pattern_match elt + ~const:(fun _ -> + Binding_time.With_name_mode.create + Binding_time.consts_and_discriminants + Name_mode.normal) + ~name:(fun elt -> Name.Map.find elt t.binding_times_and_modes) + let name_mode_unscoped t elt = - Binding_time.With_name_mode.name_mode - (Simple.Map.find elt t.binding_times_and_modes) + Binding_time.With_name_mode.name_mode (binding_time_and_name_mode t elt) let name_mode t elt ~min_binding_time = Binding_time.With_name_mode.scoped_name_mode - (Simple.Map.find elt t.binding_times_and_modes) + (binding_time_and_name_mode t elt) ~min_binding_time let invariant t = if !Clflags.flambda_invariant_checks then begin - let _all_aliases : Simple.Set.t = - Simple.Map.fold (fun canonical_element aliases all_aliases -> + let all_aliases_of_names : map_to_canonical = + Name.Map.fold (fun canonical_element aliases all_aliases -> Aliases_of_canonical_element.invariant aliases; let aliases = Aliases_of_canonical_element.all aliases in - if not (Simple.Set.for_all (fun elt -> - defined_earlier t canonical_element ~than:elt) aliases) + if not (Name.Map.for_all (fun elt _coercion -> + name_defined_earlier t canonical_element ~than:elt) aliases) then begin Misc.fatal_errorf "Canonical element %a is not earlier than \ all of its aliases:@ %a" - Simple.print canonical_element + Name.print canonical_element print t end; - if Simple.Set.mem canonical_element aliases then begin + if Name.Map.mem canonical_element aliases then begin Misc.fatal_errorf "Canonical element %a occurs in alias set:@ %a" - Simple.print canonical_element - Simple.Set.print aliases + Name.print canonical_element + (Name.Map.print Coercion.print) aliases + end; + if Name.Map.inter_domain_is_non_empty aliases all_aliases then + begin + Misc.fatal_errorf "Overlapping alias sets:@ %a" print t end; - if not (Simple.Set.is_empty (Simple.Set.inter aliases all_aliases)) then + map_union aliases all_aliases) + t.aliases_of_canonical_names + Name.Map.empty + in + let _all_aliases : map_to_canonical = + Const.Map.fold (fun _const aliases all_aliases -> + Aliases_of_canonical_element.invariant aliases; + let aliases = Aliases_of_canonical_element.all aliases in + if Name.Map.inter_domain_is_non_empty aliases all_aliases then begin Misc.fatal_errorf "Overlapping alias sets:@ %a" print t end; - Simple.Set.union aliases all_aliases) - t.aliases_of_canonical_elements - Simple.Set.empty + Name.Map.disjoint_union aliases all_aliases) + t.aliases_of_consts + all_aliases_of_names in () end @@ -234,193 +461,453 @@ let invariant t = let empty = { (* CR mshinwell: Rename canonical_elements, maybe to aliases_to_canonical_elements. *) - canonical_elements = Simple.Map.empty; - aliases_of_canonical_elements = Simple.Map.empty; - binding_times_and_modes = Simple.Map.empty; + canonical_elements = Name.Map.empty; + aliases_of_canonical_names = Name.Map.empty; + aliases_of_consts = Const.Map.empty; + binding_times_and_modes = Name.Map.empty; } type canonical = - | Is_canonical of Simple.t - | Alias_of_canonical of { element : Simple.t; canonical_element : Simple.t; } + | Is_canonical + | Alias_of_canonical of { + canonical_element : Simple.t; + coercion_to_canonical : coercion_to_canonical; + } let canonical t element : canonical = - match Simple.Map.find element t.canonical_elements with - | exception Not_found -> Is_canonical element - | canonical_element -> - if !Clflags.flambda_invariant_checks then begin - assert (not (Simple.equal element canonical_element)) - end; - Alias_of_canonical { element; canonical_element; } + Simple.pattern_match element + ~const:(fun _ -> Is_canonical) + ~name:(fun name -> + match Name.Map.find name t.canonical_elements with + | exception Not_found -> Is_canonical + | canonical_element, coercion_to_canonical -> + if !Clflags.flambda_invariant_checks then begin + assert (not (Simple.equal element canonical_element)) + end; + Alias_of_canonical { canonical_element; coercion_to_canonical; }) let get_aliases_of_canonical_element t ~canonical_element = - match Simple.Map.find canonical_element t.aliases_of_canonical_elements with + let name name = + Name.Map.find name t.aliases_of_canonical_names + in + let const const = + Const.Map.find const t.aliases_of_consts + in + match Simple.pattern_match canonical_element ~name ~const with | exception Not_found -> Aliases_of_canonical_element.empty | aliases -> aliases -let add_alias_between_canonical_elements t ~canonical_element ~to_be_demoted = - if Simple.equal canonical_element to_be_demoted then - t - else +(* + before + ~~~~~~ + canonical_element <--[coercion_ce_0]-- ce_0 + ^ ^--[...]-- ... + \--[coercion_ce_m]-- ce_m + to_be_demoted <--[coercion_tbd_0]-- tbd_0 + ^ ^--[...]-- ... + \--[coercion_tbd_n]-- tbd_n + + i.e. + + canonical_elements[ce_0] = (canonical_element, coercion_ce_0) + ... + canonical_elements[ce_m] = (canonical_element, coercion_ce_m) + canonical_elements[tbd_0] = (to_be_demoted, coercion_tbd_0) + ... + canonical_elements[tbd_n] = (to_be_demoted, coercion_tbd_n) + + + after + ~~~~~ + canonical_element <--[coercion_ce_0]-- ce_0 + ^ ^ ^ ^ ^ ^--[...]-- ... + | | | | \--[coercion_ce_m]-- ce_m + | | | \--[coercion_to_canonical]-- to_be_demoted + | | \--[compose(coercion_tbd_0, coercion_to_canonical)]-- tbd_0 + | \--[...]-- ... + \--[compose(coercion_tbd_n, coercion_to_canonical)]-- tbd_n + + i.e. + + canonical_elements[ce_0] = (canonical_element, coercion_ce_0) + ... + canonical_elements[ce_m] = (canonical_element, coercion_ce_m) + canonical_elements[to_be_demoted] = (canonical_element, coercion_to_canonical) + canonical_elements[tbd_0] = (canonical_element, compose(coercion_tbd_0, coercion_to_canonical)) + ... + canonical_elements[tbd_n] = (canonical_element, compose(coercion_tbd_n, coercion_to_canonical)) + +*) +let add_alias_between_canonical_elements t ~canonical_element + ~coercion_to_canonical:coercion_to_canonical ~to_be_demoted = + if Simple.equal canonical_element to_be_demoted then begin + if Coercion.is_id coercion_to_canonical then begin + t + end else + Misc.fatal_errorf + "Cannot add an alias of %a@ to itself with a non-identity coercion@ %a" + Simple.print canonical_element + Coercion.print coercion_to_canonical + end else + let name_to_be_demoted = + Simple.pattern_match to_be_demoted + ~const:(fun c -> + Misc.fatal_errorf + "Can't demote const %a@ (while adding alias to@ %a)" + Const.print c + Simple.print canonical_element) + ~name:(fun name -> name) + in let aliases_of_to_be_demoted = get_aliases_of_canonical_element t ~canonical_element:to_be_demoted in if !Clflags.flambda_invariant_checks then begin - assert (not (Aliases_of_canonical_element.mem - aliases_of_to_be_demoted canonical_element)) + Simple.pattern_match canonical_element + ~const:(fun _ -> ()) + ~name:(fun canonical_element -> + assert (not (Aliases_of_canonical_element.mem + aliases_of_to_be_demoted canonical_element))) end; let canonical_elements = t.canonical_elements - |> Simple.Set.fold (fun alias canonical_elements -> - Simple.Map.add alias canonical_element canonical_elements) + |> Name.Map.fold (fun alias coercion_to_to_be_demoted canonical_elements -> + let coercion_to_canonical = + Coercion.compose_exn coercion_to_to_be_demoted ~then_:coercion_to_canonical + in + Name.Map.add alias (canonical_element, coercion_to_canonical) canonical_elements) (Aliases_of_canonical_element.all aliases_of_to_be_demoted) - |> Simple.Map.add to_be_demoted canonical_element + |> Name.Map.add name_to_be_demoted (canonical_element, coercion_to_canonical) in let aliases_of_canonical_element = get_aliases_of_canonical_element t ~canonical_element in if !Clflags.flambda_invariant_checks then begin assert (not (Aliases_of_canonical_element.mem - aliases_of_canonical_element to_be_demoted)); + aliases_of_canonical_element name_to_be_demoted)); assert (Aliases_of_canonical_element.is_empty ( Aliases_of_canonical_element.inter aliases_of_canonical_element aliases_of_to_be_demoted)) end; let aliases = Aliases_of_canonical_element.add - (Aliases_of_canonical_element.union aliases_of_to_be_demoted - aliases_of_canonical_element) - to_be_demoted (name_mode_unscoped t to_be_demoted) + (Aliases_of_canonical_element.union + (Aliases_of_canonical_element.compose aliases_of_to_be_demoted ~then_:coercion_to_canonical) + aliases_of_canonical_element) + name_to_be_demoted + ~coercion_to_canonical + (name_mode_unscoped t to_be_demoted) in - let aliases_of_canonical_elements = - t.aliases_of_canonical_elements - |> Simple.Map.remove to_be_demoted - |> Simple.Map.add (* replace *) canonical_element aliases + let aliases_of_canonical_names = + Name.Map.remove name_to_be_demoted t.aliases_of_canonical_names in + let aliases_of_canonical_names, aliases_of_consts = + Simple.pattern_match canonical_element + ~name:(fun name -> + Name.Map.add (* replace *) name aliases aliases_of_canonical_names, + t.aliases_of_consts) + ~const:(fun const -> + aliases_of_canonical_names, + Const.Map.add (* replace *) const aliases t.aliases_of_consts) + in + let res = { canonical_elements; - aliases_of_canonical_elements; + aliases_of_canonical_names; + aliases_of_consts; binding_times_and_modes = t.binding_times_and_modes; - } + } in + invariant res; + res -type to_be_demoted = { - canonical_element : Simple.t; - to_be_demoted : Simple.t; -} +type to_be_demoted = Demote_canonical_element1 | Demote_canonical_element2 let choose_canonical_element_to_be_demoted t ~canonical_element1 ~canonical_element2 = if defined_earlier t canonical_element1 ~than:canonical_element2 - then - { canonical_element = canonical_element1; - to_be_demoted = canonical_element2; - } - else - { canonical_element = canonical_element2; - to_be_demoted = canonical_element1; - } + then Demote_canonical_element2 else Demote_canonical_element1 (* CR mshinwell: add submodule *) type add_result = { t : t; canonical_element : Simple.t; - alias_of : Simple.t; + alias_of_demoted_element : Simple.t; } -let invariant_add_result ~original_t { canonical_element; alias_of; t; } = +let invariant_add_result ~original_t { canonical_element; alias_of_demoted_element; t; } = if !Clflags.flambda_invariant_checks then begin invariant t; - if not (Simple.equal canonical_element alias_of) then begin - if not (defined_earlier t canonical_element ~than:alias_of) then begin - Misc.fatal_errorf "Canonical element %a should be defined earlier \ - than %a after alias addition.@ Original alias tracker:@ %a@ \ + if not (defined_earlier t canonical_element ~than:alias_of_demoted_element) then begin + Misc.fatal_errorf "Canonical element %a should be defined earlier \ + than %a after alias addition.@ Original alias tracker:@ %a@ \ + Resulting alias tracker:@ %a" + Simple.print canonical_element + Simple.print alias_of_demoted_element + print original_t + print t + end; + match canonical t alias_of_demoted_element with + | Is_canonical -> + Misc.fatal_errorf "Alias %a must not be must not be canonical \ + anymore.@ \ + Original alias tracker:@ %a@ \ Resulting alias tracker:@ %a" - Simple.print canonical_element - Simple.print alias_of + Simple.print alias_of_demoted_element print original_t print t - end - end + | Alias_of_canonical _ -> () end -let add_alias t element1 element2 = +(* +let debugging () = !Clflags.dump_rawflambda +let andop = "\u{2227}" +let canonop = "\u{21e5}" + +let debugf fmt = + let k go = if debugging () then go Format.err_formatter else () in + Format.kdprintf k fmt +*) + +let add_alias t ~element1 ~coercion_from_element2_to_element1 ~element2 = +(* + debugf "@[add_alias@ ~element1:%a@ ~element2:%a@]@." + Simple.print element1 + Simple.print element2; + (fun ({ canonical_element; alias_of_demoted_element = alias_of; t = _ } as ans) -> + debugf "Decision: %a %s %a@." + Simple.print alias_of + canonop + Simple.print canonical_element; + ans + ) @@ begin + let canon elt = + match canonical t elt with + | Is_canonical -> elt + | Alias_of_canonical { canonical_element; _ } -> canonical_element + in + begin match canon element1, canon element2 with + | (canonical_element1, canonical_element2) + -> + debugf "@[%a %s %a@ %s@ %a %s %a@]@." + Simple.print element1 + canonop + Simple.print canonical_element1 + andop + Simple.print element2 + canonop + Simple.print canonical_element2; + end; +*) + let add ~canonical_element1 ~canonical_element2 + ~coercion_from_element1_to_canonical_element1 + ~coercion_from_element2_to_canonical_element2 + ~coercion_from_canonical_element2_to_canonical_element1 = + if Simple.equal canonical_element1 canonical_element2 + then + let canonical_element = canonical_element1 in + (* According to the contract for [add], [alias_of_demoted_element] must + not be canonical. Usually this is fine, but what if [element1] or + [element2] is *itself* canonical? This is true iff that element is + equal to [canonical_element1]. In that case, we can safely pick the + other element. (They cannot both be canonical because then they'd both + be equal to [canonical_element1] and we assume that [element1] and + [element2] are different.) *) + (* CR lmaurer: We should just bail out in this case; since [element1] and + [element2] have the same canonical, they're already aliases, so + [Typing_env.add_equation] doesn't actually need to do anything at all + IIUC. *) + let alias_of_demoted_element = + if Simple.equal element1 canonical_element then element2 else element1 + in + { t; canonical_element; alias_of_demoted_element; } + else + let canonical_element, demoted_canonical, alias_of_demoted_element, + coercion_from_demoted_canonical_to_canonical, + coercion_from_demoted_alias_to_demoted_canonical = + let which_element = + choose_canonical_element_to_be_demoted t + ~canonical_element1 ~canonical_element2 + in + match which_element with + | Demote_canonical_element1 -> + let coercion_from_canonical_element1_to_canonical_element2 = + Coercion.inverse + coercion_from_canonical_element2_to_canonical_element1 + in + canonical_element2, canonical_element1, element1, + coercion_from_canonical_element1_to_canonical_element2, + coercion_from_element1_to_canonical_element1 + | Demote_canonical_element2 -> + canonical_element1, canonical_element2, element2, + coercion_from_canonical_element2_to_canonical_element1, + coercion_from_element2_to_canonical_element2 + in + let t = + add_alias_between_canonical_elements + t + ~canonical_element + ~coercion_to_canonical:coercion_from_demoted_canonical_to_canonical + ~to_be_demoted:demoted_canonical + in + let coercion_from_demoted_alias_to_canonical = + Coercion.compose_exn + coercion_from_demoted_alias_to_demoted_canonical + ~then_:coercion_from_demoted_canonical_to_canonical + in + let alias_of_demoted_element = + Simple.with_coercion alias_of_demoted_element + coercion_from_demoted_alias_to_canonical + in + { t; + canonical_element; + alias_of_demoted_element; + } + in match canonical t element1, canonical t element2 with - | Is_canonical canonical_element1, Is_canonical canonical_element2 -> - let { canonical_element; to_be_demoted; } = - choose_canonical_element_to_be_demoted t ~canonical_element1 - ~canonical_element2 - in - let t = - add_alias_between_canonical_elements t ~canonical_element - ~to_be_demoted - in - { t; - canonical_element; - (* CR mshinwell: [alias_of] is not a good name. *) - alias_of = to_be_demoted; - } - | Alias_of_canonical - { element = element1; canonical_element = canonical_element1; }, - Is_canonical canonical_element2 - | Is_canonical canonical_element2, - Alias_of_canonical - { element = element1; canonical_element = canonical_element1; } -> - let { canonical_element; to_be_demoted; } = - choose_canonical_element_to_be_demoted t ~canonical_element1 - ~canonical_element2 - in - let alias_of = - if Simple.equal to_be_demoted canonical_element1 then element1 - else canonical_element2 - in - let t = - add_alias_between_canonical_elements t ~canonical_element - ~to_be_demoted + | Is_canonical, Is_canonical -> + let canonical_element1 = element1 in + let canonical_element2 = element2 in + let coercion_from_element1_to_canonical_element1 = Coercion.id in + let coercion_from_element2_to_canonical_element2 = Coercion.id in + let coercion_from_canonical_element2_to_canonical_element1 = + coercion_from_element2_to_element1 in - { t; - canonical_element; - alias_of; - } - | Alias_of_canonical - { element = element1; canonical_element = canonical_element1; }, - Alias_of_canonical - { element = element2; canonical_element = canonical_element2; } - -> - let { canonical_element; to_be_demoted; } = - choose_canonical_element_to_be_demoted t ~canonical_element1 - ~canonical_element2 + add ~canonical_element1 ~canonical_element2 + ~coercion_from_element1_to_canonical_element1 + ~coercion_from_element2_to_canonical_element2 + ~coercion_from_canonical_element2_to_canonical_element1 + | Alias_of_canonical { + canonical_element = canonical_element1; + coercion_to_canonical = coercion_from_element1_to_canonical_element1; + }, + Is_canonical -> + let canonical_element2 = element2 in + let coercion_from_element2_to_canonical_element2 = Coercion.id in + (* element1 <--[c]-- canonical_element2=element2 + + + canonical_element1 <--[c1] element1 + ~> + canonical_element1 <--[c1 << c]-- canonical_element2 *) + let coercion_from_canonical_element2_to_canonical_element1 = + Coercion.compose_exn coercion_from_element2_to_element1 + ~then_:coercion_from_element1_to_canonical_element1 in - let alias_of = - if Simple.equal to_be_demoted canonical_element1 then element1 - else element2 + add ~canonical_element1 ~canonical_element2 + ~coercion_from_element1_to_canonical_element1 + ~coercion_from_element2_to_canonical_element2 + ~coercion_from_canonical_element2_to_canonical_element1 + | Is_canonical, + Alias_of_canonical { + canonical_element = canonical_element2; + coercion_to_canonical = coercion_from_element2_to_canonical_element2; + } -> + let canonical_element1 = element1 in + let coercion_from_element1_to_canonical_element1 = Coercion.id in + let coercion_from_canonical_element2_to_canonical_element1 = + (* canonical_element1=element1 <--[c]-- element2 + + + canonical_element2 <--[c2]-- element2 + ~> + element2 <--[c2^-1]-- canonical_element2 + ~> + canonical_element1 <--[c << c2^-1]-- canonical_element2 + *) + Coercion.compose_exn + (Coercion.inverse coercion_from_element2_to_canonical_element2) + ~then_:coercion_from_element2_to_element1 in - let t = - add_alias_between_canonical_elements t ~canonical_element - ~to_be_demoted + add ~canonical_element1 ~canonical_element2 + ~coercion_from_element1_to_canonical_element1 + ~coercion_from_element2_to_canonical_element2 + ~coercion_from_canonical_element2_to_canonical_element1 + | Alias_of_canonical { + canonical_element = canonical_element1; + coercion_to_canonical = coercion_from_element1_to_canonical_element1; + }, + Alias_of_canonical { + canonical_element = canonical_element2; + coercion_to_canonical = coercion_from_element2_to_canonical_element2; + } -> + let coercion_from_canonical_element2_to_canonical_element1 = + (* canonical_element1 <--[c1]-- element1 + canonical_element2 <--[c2]-- element2 + + + element1 <--[c]-- element2 + ~> + element2 <--[c2^-1]-- canonical_element2 + ~> + canonical_element1 <--[c1 << c << c2^-1]-- canonical_element2 + *) + Coercion.compose_exn + (Coercion.inverse coercion_from_element2_to_canonical_element2) + ~then_:(Coercion.compose_exn + coercion_from_element2_to_element1 + ~then_:coercion_from_element1_to_canonical_element1) in - { t; - canonical_element; - alias_of; - } + add ~canonical_element1 ~canonical_element2 + ~coercion_from_element1_to_canonical_element1 + ~coercion_from_element2_to_canonical_element2 + ~coercion_from_canonical_element2_to_canonical_element1 +(* + end +*) -let add t element1 binding_time_and_mode1 - element2 binding_time_and_mode2 = +let add t ~element1:element1_with_coercion ~binding_time_and_mode1 + ~element2:element2_with_coercion ~binding_time_and_mode2 = let original_t = t in - let element1 = Simple.without_rec_info element1 in - let element2 = Simple.without_rec_info element2 in + (* element1_with_coercion <--[c1]-- element1 + + + element2_with_coercion <--[c2]-- element2 + ~ + element1 <--[c1^-1]-- element1_with_coercion + ~ + element1 <--[c1^-1 << c2]-- element2 + *) + let element1 = element1_with_coercion |> Simple.without_coercion in + let element2 = element2_with_coercion |> Simple.without_coercion in + let coercion_from_element2_to_element1 = + Coercion.compose_exn (Simple.coercion element2_with_coercion) + ~then_:(Coercion.inverse (Simple.coercion element1_with_coercion)) + in + if !Clflags.flambda_invariant_checks then begin + if Simple.equal element1 element2 then begin + Misc.fatal_errorf + "Cannot alias an element to itself: %a" Simple.print element1 + end; + Simple.pattern_match element1 + ~name:(fun _ -> ()) + ~const:(fun const1 -> + Simple.pattern_match element2 + ~name:(fun _ -> ()) + ~const:(fun const2 -> + Misc.fatal_errorf + "Cannot add alias between two consts: %a, %a" + Const.print const1 + Const.print const2 + )); + end; + let add_if_name simple data map = + Simple.pattern_match simple + ~const:(fun _ -> map) + ~name:(fun name -> Name.Map.add name data map) + in let t = { t with binding_times_and_modes = - Simple.Map.add element1 binding_time_and_mode1 - (Simple.Map.add element2 binding_time_and_mode2 + add_if_name element1 binding_time_and_mode1 + (add_if_name element2 binding_time_and_mode2 t.binding_times_and_modes); } in - let add_result = add_alias t element1 element2 in + let add_result = add_alias t ~element1 ~coercion_from_element2_to_element1 ~element2 in if !Clflags.flambda_invariant_checks then begin invariant_add_result ~original_t add_result end; add_result let mem t element = - Simple.Map.mem element t.binding_times_and_modes + Simple.pattern_match element + ~const:(fun const -> + Const.Map.mem const t.aliases_of_consts) + ~name:(fun name -> + Name.Map.mem name t.binding_times_and_modes) (* CR mshinwell: This needs documenting. For the moment we allow relations between canonical elements that are actually incomparable @@ -446,190 +933,274 @@ let mem t element = let get_canonical_element_exn t element elt_name_mode ~min_name_mode ~min_binding_time = - match Simple.Map.find element t.canonical_elements with - | exception Not_found -> - begin match - Name_mode.compare_partial_order elt_name_mode min_name_mode - with - | None -> raise Not_found - | Some c -> - if c >= 0 then element - else raise Not_found - end - | canonical_element -> + let canonical_element, name_mode, coercion_from_canonical_to_element = + match canonical t element with + | Is_canonical -> + element, elt_name_mode, Coercion.id + | Alias_of_canonical { canonical_element; coercion_to_canonical; } -> + let name_mode = name_mode t canonical_element ~min_binding_time in + canonical_element, name_mode, Coercion.inverse coercion_to_canonical + in (* Format.eprintf "looking for canonical for %a, candidate canonical %a, min order %a\n%!" Simple.print element Simple.print canonical_element Name_mode.print min_name_mode; *) - let find_earliest () = - let aliases = get_aliases_of_canonical_element t ~canonical_element in - let filter_by_scope name_mode simples = - if Name_mode.equal name_mode Name_mode.in_types then simples - else - Simple.Set.filter (fun simple -> - let binding_time_and_mode = - Simple.Map.find simple t.binding_times_and_modes - in - let scoped_name_mode = - Binding_time.With_name_mode.scoped_name_mode - binding_time_and_mode - ~min_binding_time - in - Name_mode.equal name_mode scoped_name_mode) - simples - in - match - Aliases_of_canonical_element.find_earliest_candidates aliases - ~filter_by_scope ~min_name_mode - with - | Some at_earliest_mode -> - (* Aliases_of_canonical_element.find_earliest_candidates only returns - non-empty sets *) - assert (not (Simple.Set.is_empty at_earliest_mode)); - Simple.Set.fold (fun elt min_elt -> - if defined_earlier t elt ~than:min_elt - then elt - else min_elt) - at_earliest_mode - (Simple.Set.min_elt at_earliest_mode) - | None -> raise Not_found + let find_earliest () = + (* There used to be a shortcut that avoided a consulting the aliases in the + common case that [element] is itself canonical and has no aliases, since + then it does not appear in [canonical_elements]. However, this shortcut + was broken: a canonical element *with* known aliases may still not appea + + in [canonical_elements]. See tests/flambda2-aliases for a test that gave + incorrect output (saying x/39 had no aliases). It may be worth restoring + the shortcut, perhaps by returning more information from [canonical]. *) + let aliases = get_aliases_of_canonical_element t ~canonical_element in + let filter_by_scope name_mode names = + if Name_mode.equal name_mode Name_mode.in_types then names + else + Name.Map.filter (fun name _coercion -> + let binding_time_and_mode = + Name.Map.find name t.binding_times_and_modes + in + let scoped_name_mode = + Binding_time.With_name_mode.scoped_name_mode + binding_time_and_mode + ~min_binding_time + in + Name_mode.equal name_mode scoped_name_mode) + names in match - Name_mode.compare_partial_order - (name_mode t canonical_element ~min_binding_time) - min_name_mode + Aliases_of_canonical_element.find_earliest_candidates aliases + ~filter_by_scope ~min_name_mode with - | None -> find_earliest () - | Some c -> - if c >= 0 then canonical_element - else find_earliest () + | Some at_earliest_mode -> + (* Aliases_of_canonical_element.find_earliest_candidates only returns + non-empty sets *) + assert (not (Name.Map.is_empty at_earliest_mode)); + let earliest, coercion_from_earliest_to_canonical = + Name.Map.fold (fun elt coercion ((min_elt, _min_coercion) as min_binding) -> + if name_defined_earlier t elt ~than:min_elt + then elt, coercion + else min_binding) + at_earliest_mode + (Name.Map.min_binding at_earliest_mode) + in + let coercion_from_earliest_to_element = + Coercion.compose_exn coercion_from_earliest_to_canonical + ~then_:coercion_from_canonical_to_element + in + Simple.with_coercion (Simple.name earliest) coercion_from_earliest_to_element + | None -> raise Not_found + in + match + Name_mode.compare_partial_order name_mode min_name_mode + with + | None -> find_earliest () + | Some c -> + if c >= 0 then + Simple.with_coercion canonical_element coercion_from_canonical_to_element + else find_earliest () let get_aliases t element = + let create_alias_set + ~canonical_element + ~coercion_from_canonical_to_element + ~(names_with_coercions_to_element : Coercion.t Name.Map.t) = + Simple.pattern_match canonical_element + ~const:(fun canonical_const -> + let const = Some canonical_const in + let names = names_with_coercions_to_element in + { Alias_set.const; names }) + ~name:(fun canonical_name -> + let names = + Name.Map.add canonical_name coercion_from_canonical_to_element + names_with_coercions_to_element + in + { Alias_set.const = None; names }) + in match canonical t element with - | Is_canonical canonical_element -> - let aliases = + | Is_canonical -> + let canonical_element = element in + let names_with_coercions_to_canonical = Aliases_of_canonical_element.all (get_aliases_of_canonical_element t ~canonical_element) in - Simple.Set.add element aliases - | Alias_of_canonical { element = _; canonical_element; } -> + let names_with_coercions_to_element = + names_with_coercions_to_canonical + in + let coercion_from_canonical_to_element = Coercion.id in + create_alias_set + ~canonical_element + ~coercion_from_canonical_to_element + ~names_with_coercions_to_element + | Alias_of_canonical { canonical_element; + coercion_to_canonical = coercion_from_element_to_canonical; } -> if !Clflags.flambda_invariant_checks then begin assert (not (Simple.equal element canonical_element)) end; - let aliases = + let names_with_coercions_to_canonical = Aliases_of_canonical_element.all (get_aliases_of_canonical_element t ~canonical_element) in + let coercion_from_canonical_to_element = + Coercion.inverse coercion_from_element_to_canonical + in + (* If any composition fails, then our coercions are inconsistent somehow, + which should only happen when meeting *) + let names_with_coercions_to_element = + compose_map_values_exn names_with_coercions_to_canonical + ~then_:coercion_from_canonical_to_element + in + if !Clflags.flambda_invariant_checks then begin - assert (Simple.Set.mem element aliases) + let element_coerced_to_canonical = + Simple.apply_coercion_exn element coercion_from_element_to_canonical + in + (* These aliases are all equivalent to the canonical element, and so is + our original [element] if we coerce it first, so the coerced form of + [element] should be among the aliases. *) + assert (Name.Map.exists + (fun name coercion_from_name_to_canonical -> + let name_coerced_to_canonical = + Simple.apply_coercion_exn + (Simple.name name) + coercion_from_name_to_canonical + in + Simple.equal element_coerced_to_canonical name_coerced_to_canonical + ) names_with_coercions_to_canonical) end; - Simple.Set.add canonical_element aliases + create_alias_set + ~canonical_element + ~coercion_from_canonical_to_element + ~names_with_coercions_to_element let all_ids_for_export { canonical_elements = _; - aliases_of_canonical_elements = _; + aliases_of_canonical_names = _; + aliases_of_consts = _; binding_times_and_modes; } = - Simple.Map.fold (fun simple _binding_time_and_mode ids -> - Ids_for_export.add_simple ids simple) + Name.Map.fold (fun elt _binding_time_and_mode ids -> + Ids_for_export.add_name ids elt) binding_times_and_modes Ids_for_export.empty let apply_renaming { canonical_elements; - aliases_of_canonical_elements; + aliases_of_canonical_names; + aliases_of_consts; binding_times_and_modes; } renaming = + let rename_name = Renaming.apply_name renaming in let rename_simple = Renaming.apply_simple renaming in let canonical_elements = - Simple.Map.fold (fun elt canonical acc -> - Simple.Map.add (rename_simple elt) (rename_simple canonical) acc) + Name.Map.fold (fun elt (canonical, coercion) acc -> + Name.Map.add (rename_name elt) (rename_simple canonical, coercion) acc) canonical_elements - Simple.Map.empty + Name.Map.empty in - let aliases_of_canonical_elements = - Simple.Map.fold (fun canonical aliases acc -> - Simple.Map.add (rename_simple canonical) - (Aliases_of_canonical_element.rename rename_simple aliases) + let aliases_of_canonical_names = + Name.Map.fold (fun canonical aliases acc -> + Name.Map.add (rename_name canonical) + (Aliases_of_canonical_element.rename rename_name aliases) acc) - aliases_of_canonical_elements - Simple.Map.empty + aliases_of_canonical_names + Name.Map.empty + in + let aliases_of_consts = + Const.Map.map (Aliases_of_canonical_element.rename rename_name) + aliases_of_consts in let binding_times_and_modes = - Simple.Map.fold (fun simple binding_time_and_mode acc -> - Simple.Map.add (rename_simple simple) binding_time_and_mode acc) + Name.Map.fold (fun name binding_time_and_mode acc -> + Name.Map.add (rename_name name) binding_time_and_mode acc) binding_times_and_modes - Simple.Map.empty + Name.Map.empty in { canonical_elements; - aliases_of_canonical_elements; + aliases_of_canonical_names; + aliases_of_consts; binding_times_and_modes; } let merge t1 t2 = let canonical_elements = - Simple.Map.disjoint_union + Name.Map.disjoint_union t1.canonical_elements t2.canonical_elements in - let aliases_of_canonical_elements = - (* Warning: here the keys of the map can come from other - compilation units, so we cannot assume the keys are disjoint *) - Simple.Map.union (fun _simple aliases1 aliases2 -> - Some (Aliases_of_canonical_element.merge aliases1 aliases2)) - t1.aliases_of_canonical_elements - t2.aliases_of_canonical_elements + (* Warning: we assume that the aliases in the two alias trackers are disjoint, + but nothing stops them from sharing a canonical element. For instance, if + multiple compilation units define aliases to the same canonical symbol, + that symbol will be a canonical element in both of the units' alias + trackers, and thus their [aliases_of_canonical_names] will have a key in + common. *) + let merge_aliases _canonical aliases1 aliases2 = + Some (Aliases_of_canonical_element.merge aliases1 aliases2) + in + let aliases_of_canonical_names = + Name.Map.union merge_aliases + t1.aliases_of_canonical_names + t2.aliases_of_canonical_names in + let aliases_of_consts = + Const.Map.union merge_aliases + t1.aliases_of_consts + t2.aliases_of_consts + in + let symbol_data = Binding_time.With_name_mode.create Binding_time.symbols Name_mode.normal in let binding_times_and_modes = - Simple.Map.union (fun simple data1 data2 -> - Simple.pattern_match simple - ~const:(fun _ -> - assert (Binding_time.With_name_mode.equal data1 data2); - Some data1) - ~name:(fun name -> - Name.pattern_match name - ~var:(fun var -> - (* TODO: filter variables on export and restore fatal_error *) - if Binding_time.(equal (With_name_mode.binding_time data1) - imported_variables) - then Some data2 - else if Binding_time.(equal (With_name_mode.binding_time data2) - imported_variables) - then Some data1 - else - Misc.fatal_errorf - "Variable %a is present in multiple environments" - Variable.print var) - ~symbol:(fun _sym -> - assert (Binding_time.With_name_mode.equal data1 symbol_data); - assert (Binding_time.With_name_mode.equal data2 symbol_data); - Some data1))) + Name.Map.union (fun name data1 data2 -> + Name.pattern_match name + ~var:(fun var -> + (* TODO: filter variables on export and restore fatal_error *) + if Binding_time.(equal (With_name_mode.binding_time data1) + imported_variables) + then Some data2 + else if Binding_time.(equal (With_name_mode.binding_time data2) + imported_variables) + then Some data1 + else + Misc.fatal_errorf + "Variable %a is present in multiple environments" + Variable.print var) + ~symbol:(fun _sym -> + assert (Binding_time.With_name_mode.equal data1 symbol_data); + assert (Binding_time.With_name_mode.equal data2 symbol_data); + Some data1)) t1.binding_times_and_modes t2.binding_times_and_modes in { canonical_elements; - aliases_of_canonical_elements; + aliases_of_canonical_names; + aliases_of_consts; binding_times_and_modes; } let get_canonical_ignoring_name_mode t name = - let simple = Simple.name name in - match canonical t simple with - | Is_canonical _ -> simple - | Alias_of_canonical { canonical_element; _ } -> canonical_element + let elt = Simple.name name in + match canonical t elt with + | Is_canonical -> + elt + | Alias_of_canonical { canonical_element; coercion_to_canonical } -> + let coercion_from_canonical = Coercion.inverse coercion_to_canonical in + Simple.apply_coercion_exn canonical_element coercion_from_canonical let clean_for_export { canonical_elements; - aliases_of_canonical_elements; + aliases_of_canonical_names; + aliases_of_consts; binding_times_and_modes; } = (* CR vlaviron: This function is kept as a reminder that we'd like to remove unreachable entries at some point. *) { canonical_elements; - aliases_of_canonical_elements; + aliases_of_canonical_names; + aliases_of_consts; binding_times_and_modes; } diff --git a/middle_end/flambda/types/env/aliases.mli b/middle_end/flambda/types/env/aliases.mli index 518e03d42024..246044b6a0e1 100644 --- a/middle_end/flambda/types/env/aliases.mli +++ b/middle_end/flambda/types/env/aliases.mli @@ -14,7 +14,32 @@ (** Union-find-like structure for keeping track of equivalence classes, used for alias resolution in the typing environment, with support for - associating orderings to aliases of canonical elements. *) + associating orderings to aliases of canonical elements. + + The concept of "alias" needs to be broadened where coercions are involved. + A coercion is a sort of fudge factor---if [x] is equal to [(coerce y c)], + then [x] and [y] are {i essentially} equal, close enough that we want to + think of [y] as an alias of [x]. + + If the words "fudge factor" sound like we're being imprecise, happily we can + be precise about our imprecision. Let [x ~ y] mean [x] and [y] are _equal up + to coercion_, which is to say, there exists a coercion [c] such that [x = + (coerce y c)]. Coercions form a _groupoid_, meaning they have just the + right properties to let [~] be an equivalence relation: + + + There is an identity coercion, so [x = (coerce x id)], meaning [x ~ x]. + + Coercions can be inverted, so if [x ~ y], meaning [x = (coerce y c)], + then (writing [c^-1] for the inverse) we have [y = (coerce x c^-1)], + meaning [y ~ x]. + + Coercions can be composed, so if [x ~ y] and [y ~ z], meaning + [x = (coerce y c_xy)] and [y = (coerce z c_yz)], then (using [>>] as + the composition operator) we have [x = (coerce z (c_xy >> c_yz))] and + [x ~ z]. + + Therefore we can safely redefine "alias" to mean [x ~ y] rather than [x = + y], and the coercions keep track of the precise sense in which [x] and [y] + are "equal enough." In particular, this module keeps track of aliases in + this looser sense. *) [@@@ocaml.warning "+a-4-30-40-41-42"] @@ -28,18 +53,35 @@ val invariant : t -> unit val empty : t +(** The result of calling [add] to state that two [Simple.t]s are now + aliases. *) type add_result = private { t : t; + (** The new state of the alias tracker. *) canonical_element : Simple.t; - alias_of : Simple.t; + (** The canonical element of the combined equivalence class. In the type + environment, this will be the name (if it is a name) that is assigned a + concrete type. Does not carry a coercion. *) + alias_of_demoted_element : Simple.t; + (** Whichever argument to [add] had its equivalence class consumed and its + canonical element demoted to an alias. It is this name that needs its type + to change to record the new canonical element. Its coercion has been + adjusted so that it is properly an alias of [canonical_element]. *) } +(** Add an alias relationship to the tracker. The two simple expressions + must be different and not both constants. If [add t s1 mode1 s2 mode2] + returns [{ t = t'; canonical_element; alias_of_demoted_element }], then + according to [t'], + - [canonical_element] is the canonical element of both [s1] and [s2]; + - [alias_of_demoted_element] is either [s1] or [s2]; and + - [alias_of_demoted_element] is no longer canonical. *) val add : t - -> Simple.t - -> Binding_time.With_name_mode.t - -> Simple.t - -> Binding_time.With_name_mode.t + -> element1:Simple.t + -> binding_time_and_mode1:Binding_time.With_name_mode.t + -> element2:Simple.t + -> binding_time_and_mode2:Binding_time.With_name_mode.t -> add_result val mem : t -> Simple.t -> bool @@ -54,8 +96,32 @@ val get_canonical_element_exn -> min_binding_time:Binding_time.t -> Simple.t +module Alias_set : sig + (** The set of aliases of one particular [Simple.t], or an intersection of + such sets. *) + type t + + val empty : t + + val singleton : Simple.t -> t + + val get_singleton : t -> Simple.t option + + val inter : t -> t -> t + + val filter : t -> f:(Simple.t -> bool) -> t + + (** Return the best alias in the set, where constants are better than + symbols, which are better than variables, and ties are broken + (arbitrarily) by [Simple.compare]. Returns [None] if the alias set is + empty. *) + val find_best : t -> Simple.t option + + val print : Format.formatter -> t -> unit +end + (** [get_aliases] always returns the supplied element in the result set. *) -val get_aliases : t -> Simple.t -> Simple.Set.t +val get_aliases : t -> Simple.t -> Alias_set.t val get_canonical_ignoring_name_mode : t -> Name.t -> Simple.t diff --git a/middle_end/flambda/types/env/meet_env.rec.ml b/middle_end/flambda/types/env/meet_env.rec.ml index 84c8dc0332f4..6eed5395eb6c 100644 --- a/middle_end/flambda/types/env/meet_env.rec.ml +++ b/middle_end/flambda/types/env/meet_env.rec.ml @@ -18,7 +18,7 @@ type t = { env : Typing_env.t; - already_meeting : Simple.Pair.Set.t; + already_meeting : Name.Pair.Set.t; } let print ppf { env; already_meeting; } = @@ -27,33 +27,45 @@ let print ppf { env; already_meeting; } = @[(env@ %a)@]@ \ @[(already_meeting@ %a)@])@]" Typing_env.print env - Simple.Pair.Set.print already_meeting + Name.Pair.Set.print already_meeting let create env = { env; - already_meeting = Simple.Pair.Set.empty; + already_meeting = Name.Pair.Set.empty; } let env t = t.env + +let already_meeting_names t name1 name2 = + Name.Pair.Set.mem (name1, name2) t.already_meeting + || Name.Pair.Set.mem (name2, name1) t.already_meeting let already_meeting t simple1 simple2 = - Simple.Pair.Set.mem (simple1, simple2) t.already_meeting - || Simple.Pair.Set.mem (simple2, simple1) t.already_meeting + let const _const = false in + Simple.pattern_match simple1 ~const ~name:(fun name1 -> + Simple.pattern_match simple2 ~const ~name:(fun name2 -> + already_meeting_names t name1 name2)) -let now_meeting t simple1 simple2 = - if already_meeting t simple1 simple2 then begin +let now_meeting_names t name1 name2 = + if already_meeting_names t name1 name2 then begin Misc.fatal_errorf "Already meeting %a and %a:@ %a" - Simple.print simple1 - Simple.print simple2 + Name.print name1 + Name.print name2 print t end; let already_meeting = - Simple.Pair.Set.add (simple1, simple2) t.already_meeting + Name.Pair.Set.add (name1, name2) t.already_meeting in { t with already_meeting; } +let now_meeting t simple1 simple2 = + let const _const = t in + Simple.pattern_match simple1 ~const ~name:(fun name1 -> + Simple.pattern_match simple2 ~const ~name:(fun name2 -> + now_meeting_names t name1 name2)) + (* let with_typing_env t typing_env = * { t with * env = typing_env; diff --git a/middle_end/flambda/types/env/typing_env.rec.ml b/middle_end/flambda/types/env/typing_env.rec.ml index 7263444762c1..4d2fe39d2af4 100644 --- a/middle_end/flambda/types/env/typing_env.rec.ml +++ b/middle_end/flambda/types/env/typing_env.rec.ml @@ -896,7 +896,10 @@ let rec add_equation0 t aliases name ty = | _ -> false in if is_concrete then begin - let canonical = Aliases.get_canonical_ignoring_name_mode aliases name in + let canonical = + Aliases.get_canonical_ignoring_name_mode aliases name + |> Simple.without_coercion + in if not (Simple.equal canonical (Simple.name name)) then begin Misc.fatal_errorf "Trying to add equation giving concrete type on %a \ which is not canonical (its canonical is %a): %a" @@ -986,7 +989,7 @@ and add_equation t name ty = end) ~const:(fun _ -> ()) end; - let aliases, simple, t, ty = + let aliases, lhs, t, ty = let aliases = aliases t in match Type_grammar.get_alias_exn ty with | exception Not_found -> @@ -994,23 +997,39 @@ and add_equation t name ty = element as known by the alias tracker (the actual canonical, ignoring any name modes). *) let canonical = Aliases.get_canonical_ignoring_name_mode aliases name in - aliases, canonical, t, ty + let lhs = canonical in + aliases, lhs, t, ty | alias_of -> - let alias_of = Simple.without_rec_info alias_of in + (* Forget where [name] and [alias_of] came from---our job is now to + record that they're equal. In general, they have canonical expressions + [c_n] and [c_a], respectively, so what we ultimately need to record is + that [c_n] = [c_a]. Clearly, only one of them can remain canonical, so + we pick whichever was bound earlier. If [c_a] was bound earlier, then + we demote [c_n] and give [name] the type "= c_a" (which will always be + valid since [c_a] was bound earlier). Otherwise, we demote [c_a] and + give [alias_of] the type "= c_n". *) let alias = Simple.name name in let kind = Type_grammar.kind ty in let binding_time_and_mode_alias = binding_time_and_mode t name in let binding_time_and_mode_alias_of = binding_time_and_mode_of_simple t alias_of in - let ({ canonical_element; alias_of; t = aliases; } : Aliases.add_result) = - Aliases.add aliases alias binding_time_and_mode_alias - alias_of binding_time_and_mode_alias_of + let ({ canonical_element; alias_of_demoted_element; t = aliases; } + : Aliases.add_result) = + Aliases.add + aliases + ~element1:alias + ~binding_time_and_mode1:binding_time_and_mode_alias + ~element2:alias_of + ~binding_time_and_mode2:binding_time_and_mode_alias_of in + (* We need to change the demoted alias's type to point to the new + canonical element. *) + let lhs = alias_of_demoted_element in let ty = Type_grammar.alias_type_of kind canonical_element in - aliases, alias_of, t, ty + aliases, lhs, t, ty in (* Beware: if we're about to add the equation on a name which is different from the one that the caller passed in, then we need to make sure that the @@ -1036,10 +1055,22 @@ and add_equation t name ty = | Ok (meet_ty, env_extension) -> meet_ty, add_env_extension t env_extension in - Simple.pattern_match simple ~name ~const:(fun _ -> ty, t) + Simple.pattern_match lhs ~name ~const:(fun _ -> ty, t) + in + (* We have [(coerce ) : ]. + Thus [ : (coerce ^-1)]. *) + let bare_lhs = Simple.without_coercion lhs in + let coercion_from_bare_lhs_to_ty = Simple.coercion lhs in + let coercion_from_ty_to_bare_lhs = + Coercion.inverse coercion_from_bare_lhs_to_ty + in + let ty = + match Type_grammar.apply_coercion ty coercion_from_ty_to_bare_lhs with + | Bottom -> Type_grammar.bottom (Type_grammar.kind ty) + | Ok ty -> ty in let [@inline always] name name = add_equation0 t aliases name ty in - Simple.pattern_match simple ~name ~const:(fun _ -> t) + Simple.pattern_match bare_lhs ~name ~const:(fun _ -> t) and add_env_extension t (env_extension : Typing_env_extension.t) = Typing_env_extension.fold @@ -1324,13 +1355,12 @@ let get_canonical_simple_exn t ?min_name_mode ?name_mode_of_existing_simple let get_alias_then_canonical_simple_exn t ?min_name_mode ?name_mode_of_existing_simple typ = let simple = Type_grammar.get_alias_exn typ in - let simple = Simple.without_rec_info simple in get_canonical_simple_exn t ?min_name_mode ?name_mode_of_existing_simple simple let aliases_of_simple t ~min_name_mode simple = Aliases.get_aliases (aliases t) simple - |> Simple.Set.filter (fun alias -> + |> Aliases.Alias_set.filter ~f:(fun alias -> let name_mode = Binding_time.With_name_mode.name_mode (binding_time_and_mode_of_simple t alias) diff --git a/middle_end/flambda/types/env/typing_env.rec.mli b/middle_end/flambda/types/env/typing_env.rec.mli index b29889f569b0..14418ce6f9ce 100644 --- a/middle_end/flambda/types/env/typing_env.rec.mli +++ b/middle_end/flambda/types/env/typing_env.rec.mli @@ -124,9 +124,9 @@ val aliases_of_simple : t -> min_name_mode:Name_mode.t -> Simple.t - -> Simple.Set.t + -> Aliases.Alias_set.t -val aliases_of_simple_allowable_in_types : t -> Simple.t -> Simple.Set.t +val aliases_of_simple_allowable_in_types : t -> Simple.t -> Aliases.Alias_set.t val add_to_code_age_relation : t -> newer:Code_id.t -> older:Code_id.t -> t diff --git a/middle_end/flambda/types/flambda_type.mli b/middle_end/flambda/types/flambda_type.mli index f441fd0bae89..b707a3f914de 100644 --- a/middle_end/flambda/types/flambda_type.mli +++ b/middle_end/flambda/types/flambda_type.mli @@ -189,7 +189,7 @@ module Typing_env : sig : t -> min_name_mode:Name_mode.t -> Simple.t - -> Simple.Set.t + -> Aliases.Alias_set.t val clean_for_export : t -> reachable_names:Name_occurrences.t -> t @@ -243,7 +243,6 @@ module Function_declaration_type : sig val code_id : t -> Code_id.t val dbg : t -> Debuginfo.t - val rec_info : t -> Rec_info.t val is_tupled : t -> bool end @@ -288,7 +287,7 @@ val make_suitable_for_environment -> bind_to:Name.t -> Typing_env_extension.With_extra_variables.t -val apply_rec_info : flambda_type -> Rec_info.t -> flambda_type Or_bottom.t +val apply_coercion : flambda_type -> Coercion.t -> flambda_type Or_bottom.t (* Remove any information from the inside of the type, leaving only its outer structure, and in some cases leaving only "Unknown". Alias types diff --git a/middle_end/flambda/types/inlining/inlining_state.ml b/middle_end/flambda/types/inlining/inlining_state.ml index 66bc9dec7037..4755404d596a 100644 --- a/middle_end/flambda/types/inlining/inlining_state.ml +++ b/middle_end/flambda/types/inlining/inlining_state.ml @@ -36,7 +36,10 @@ let print ppf t = Inlining_arguments.print t.arguments let is_depth_exceeded t = - t.depth >= (Inlining_arguments.max_inlining_depth t.arguments) + (* CR-soon lmaurer: Fix this once rec_info is functional again; hardcoding + depth of 1 until then *) + if true then t.depth >= 1 else + t.depth >= (Inlining_arguments.max_inlining_depth t.arguments) let meet t1 t2 = { depth = t1.depth + t2.depth; diff --git a/middle_end/flambda/types/structures/function_declaration_type.rec.ml b/middle_end/flambda/types/structures/function_declaration_type.rec.ml index aef74ee304ae..9d985a1d2837 100644 --- a/middle_end/flambda/types/structures/function_declaration_type.rec.ml +++ b/middle_end/flambda/types/structures/function_declaration_type.rec.ml @@ -32,7 +32,7 @@ module Inlinable = struct "@[(Inlinable@ \ @[(code_id@ %a)@]@ \ @[(dbg@ %a)@] \ - @[(rec_info@ %a)@]\ + @[(rec_info@ %a)@] \ @[ let typing_env = Meet_env.env env in @@ -187,12 +186,11 @@ let meet (env : Meet_env.t) (t1 : t) (t2 : t) Ok (Ok (Inlinable { code_id; dbg = dbg1; - rec_info = _rec_info1; + rec_info = Rec_info.unknown; is_tupled = is_tupled1; }), TEE.empty ()) in - (* CR mshinwell: What about [rec_info]? *) begin match Code_age_relation.meet target_code_age_rel ~resolver code_id1 code_id2 with @@ -241,13 +239,13 @@ let join (env : Join_env.t) (t1 : t) (t2 : t) : t = | Ok (Inlinable { code_id = code_id1; dbg = dbg1; - rec_info = _rec_info1; + rec_info = _; is_tupled = is_tupled1; }), Ok (Inlinable { code_id = code_id2; dbg = dbg2; - rec_info = _rec_info2; + rec_info = _; is_tupled = is_tupled2; }) -> let typing_env = Join_env.target_join_env env in @@ -259,11 +257,10 @@ let join (env : Join_env.t) (t1 : t) (t2 : t) : t = Ok (Inlinable { code_id; dbg = dbg1; - rec_info = _rec_info1; + rec_info = Rec_info.unknown; is_tupled = is_tupled1; }) in - (* CR mshinwell: What about [rec_info]? *) let code_age_rel1 = TE.code_age_relation (Join_env.left_join_env env) in @@ -278,14 +275,5 @@ let join (env : Join_env.t) (t1 : t) (t2 : t) : t = | Unknown -> Unknown end -let apply_rec_info (t : t) rec_info : t Or_bottom.t = - match t with - | Ok (Inlinable { code_id; dbg; rec_info = rec_info'; is_tupled; }) -> - let rec_info = Rec_info.merge rec_info' ~newer:rec_info in - Ok (Ok (Inlinable { code_id; - dbg; - rec_info; - is_tupled; - })) - | Ok (Non_inlinable { code_id = _; is_tupled = _; }) -> Ok t - | Unknown | Bottom -> Ok t +let apply_coercion (t : t) _coercion : t Or_bottom.t = + Ok t diff --git a/middle_end/flambda/types/structures/function_declaration_type.rec.mli b/middle_end/flambda/types/structures/function_declaration_type.rec.mli index 9ad697af5925..33cce78e78a3 100644 --- a/middle_end/flambda/types/structures/function_declaration_type.rec.mli +++ b/middle_end/flambda/types/structures/function_declaration_type.rec.mli @@ -28,7 +28,6 @@ module Inlinable : sig val code_id : t -> Code_id.t val dbg : t -> Debuginfo.t - val rec_info : t -> Rec_info.t val is_tupled : t -> bool end @@ -60,4 +59,4 @@ include Type_structure_intf.S with type join_env := Join_env.t with type typing_env_extension := Typing_env_extension.t -val apply_rec_info : t -> Rec_info.t -> t Or_bottom.t +val apply_coercion : t -> Coercion.t -> t Or_bottom.t diff --git a/middle_end/flambda/types/template/flambda_type.templ.ml b/middle_end/flambda/types/template/flambda_type.templ.ml index 01b8c030611d..dcb6fee2adca 100644 --- a/middle_end/flambda/types/template/flambda_type.templ.ml +++ b/middle_end/flambda/types/template/flambda_type.templ.ml @@ -975,7 +975,7 @@ let reify ?allowed_if_free_vars_defined_in ?additional_free_var_criterion | Bottom | Unknown | Ok (Non_inlinable _) -> function_decls_with_closure_vars | Ok (Inlinable inlinable_decl) -> - (* CR mshinwell: We're ignoring [rec_info] *) + (* CR mshinwell: We're ignoring [coercion] *) let closure_var_types = Closures_entry.closure_var_types closures_entry in diff --git a/middle_end/flambda/types/type_descr.rec.ml b/middle_end/flambda/types/type_descr.rec.ml index 713e2c0599e9..e9f4099f817a 100644 --- a/middle_end/flambda/types/type_descr.rec.ml +++ b/middle_end/flambda/types/type_descr.rec.ml @@ -129,18 +129,17 @@ module Make (Head : Type_head_intf.S | Equals alias -> alias | No_alias _ -> assert false - let apply_rec_info t rec_info : _ Or_bottom.t = + let apply_coercion t coercion : _ Or_bottom.t = match descr t with | Equals simple -> - let newer_rec_info = Some rec_info in - begin match Simple.merge_rec_info simple ~newer_rec_info with + begin match Simple.apply_coercion simple coercion with | None -> Bottom | Some simple -> Ok (create_equals simple) end | No_alias Unknown -> Ok t | No_alias Bottom -> Bottom | No_alias (Ok head) -> - Or_bottom.map (Head.apply_rec_info head rec_info) + Or_bottom.map (Head.apply_coercion head coercion) ~f:(fun head -> create head) let force_to_head ~force_to_kind t = @@ -178,16 +177,16 @@ module Make (Head : Type_head_intf.S | No_alias Bottom -> Bottom | No_alias Unknown -> Unknown | No_alias (Ok head) -> Ok head - (* CR mshinwell: Fix Rec_info - begin match rec_info with + (* CR mshinwell: Fix coercion + begin match coercion with | None -> Ok head - | Some rec_info -> - (* CR mshinwell: check rec_info handling is correct, after + | Some coercion -> + (* CR mshinwell: check coercion handling is correct, after recent changes in this area *) - (* [simple] already has [rec_info] applied to it (see + (* [simple] already has [coercion] applied to it (see [get_canonical_simple], above). However we also need to apply it to the expanded head of the type. *) - match Head.apply_rec_info head rec_info with + match Head.apply_coercion head coercion with | Bottom -> Bottom | Ok head -> Ok head end @@ -236,18 +235,17 @@ module Make (Head : Type_head_intf.S let all_aliases_of env simple_opt ~in_env = match simple_opt with - | None -> Simple.Set.empty + | None -> Aliases.Alias_set.empty | Some simple -> let simples = - Simple.Set.add simple ( - TE.aliases_of_simple_allowable_in_types env simple) + TE.aliases_of_simple_allowable_in_types env simple in (* Format.eprintf "Aliases of %a are: %a\n%!" Simple.print simple Simple.Set.print simples; *) - Simple.Set.filter (fun simple -> + Aliases.Alias_set.filter ~f:(fun simple -> Typing_env.mem_simple in_env simple) simples @@ -471,47 +469,23 @@ module Make (Head : Type_head_intf.S ~right_env:(Join_env.right_join_env join_env) ~right_ty:t2 in - let choose_shared_alias ~shared_aliases = - match Simple.Set.elements shared_aliases with - | [] -> None - | shared_aliases -> - (* We prefer [Const]s, and if not, [Symbol]s. *) - (* CR mshinwell: Add this as a supported ordering in [Simple] *) - let shared_aliases = - List.sort (fun simple1 simple2 -> - let is_const1 = Simple.is_const simple1 in - let is_const2 = Simple.is_const simple2 in - match is_const1, is_const2 with - | true, false -> -1 - | false, true -> 1 - | true, true | false, false -> - let is_symbol1 = Simple.is_symbol simple1 in - let is_symbol2 = Simple.is_symbol simple2 in - match is_symbol1, is_symbol2 with - | true, false -> -1 - | false, true -> 1 - | true, true | false, false -> - Simple.compare simple1 simple2) - shared_aliases - in - Some (create_equals (List.hd shared_aliases)) - in + (* CR mshinwell: Add shortcut when the canonical simples are equal *) let shared_aliases = let shared_aliases = match canonical_simple1, head1, canonical_simple2, head2 with | None, _, None, _ | None, (Ok _ | Unknown), _, _ - | _, _, None, (Ok _ | Unknown) -> Simple.Set.empty + | _, _, None, (Ok _ | Unknown) -> Aliases.Alias_set.empty | Some simple1, _, _, Bottom -> - Simple.Set.singleton simple1 + Aliases.Alias_set.singleton simple1 | _, Bottom, Some simple2, _ -> - Simple.Set.singleton simple2 + Aliases.Alias_set.singleton simple2 | Some simple1, _, Some simple2, _ -> if Simple.same simple1 simple2 - then Simple.Set.singleton simple1 + then Aliases.Alias_set.singleton simple1 else - Simple.Set.inter + Aliases.Alias_set.inter (all_aliases_of (Join_env.left_join_env join_env) canonical_simple1 ~in_env:(Join_env.target_join_env join_env)) @@ -524,8 +498,8 @@ module Make (Head : Type_head_intf.S | Some bound_name -> (* CR vlaviron: this ensures that we're not creating an alias to a different simple that is just bound_name with different - rec_info. Such an alias is forbidden. *) - Simple.Set.filter (fun simple -> + coercion. Such an alias is forbidden. *) + Aliases.Alias_set.filter ~f:(fun simple -> not (Simple.same simple (Simple.name bound_name))) shared_aliases in @@ -533,8 +507,8 @@ module Make (Head : Type_head_intf.S Format.eprintf "Shared aliases:@ %a\n%!" Simple.Set.print shared_aliases; *) - match choose_shared_alias ~shared_aliases with - | Some joined_ty -> Known (to_type joined_ty) + match Aliases.Alias_set.find_best shared_aliases with + | Some alias -> Known (to_type (create_equals alias)) | None -> match canonical_simple1, canonical_simple2 with | Some simple1, Some simple2 diff --git a/middle_end/flambda/types/type_descr_intf.ml b/middle_end/flambda/types/type_descr_intf.ml index aae949412eb6..64b88c6a8eca 100644 --- a/middle_end/flambda/types/type_descr_intf.ml +++ b/middle_end/flambda/types/type_descr_intf.ml @@ -62,7 +62,7 @@ module type S = sig include Contains_ids.S with type t := t - val apply_rec_info : t -> Rec_info.t -> t Or_bottom.t + val apply_coercion : t -> Coercion.t -> t Or_bottom.t val eviscerate : force_to_kind:(flambda_type -> t) (* CR mshinwell: "of_type"? *) diff --git a/middle_end/flambda/types/type_grammar.rec.ml b/middle_end/flambda/types/type_grammar.rec.ml index 014e1e6fc4e4..5f1d395ef84e 100644 --- a/middle_end/flambda/types/type_grammar.rec.ml +++ b/middle_end/flambda/types/type_grammar.rec.ml @@ -158,35 +158,35 @@ let all_ids_for_export t = | Naked_int64 ty -> T_N64.all_ids_for_export ty | Naked_nativeint ty -> T_NN.all_ids_for_export ty -let apply_rec_info t rec_info : _ Or_bottom.t = +let apply_coercion t coercion : _ Or_bottom.t = match t with | Value ty -> - begin match T_V.apply_rec_info ty rec_info with + begin match T_V.apply_coercion ty coercion with | Ok ty -> Ok (Value ty) | Bottom -> Bottom end | Naked_immediate ty -> - begin match T_NI.apply_rec_info ty rec_info with + begin match T_NI.apply_coercion ty coercion with | Ok ty -> Ok (Naked_immediate ty) | Bottom -> Bottom end | Naked_float ty -> - begin match T_Nf.apply_rec_info ty rec_info with + begin match T_Nf.apply_coercion ty coercion with | Ok ty -> Ok (Naked_float ty) | Bottom -> Bottom end | Naked_int32 ty -> - begin match T_N32.apply_rec_info ty rec_info with + begin match T_N32.apply_coercion ty coercion with | Ok ty -> Ok (Naked_int32 ty) | Bottom -> Bottom end | Naked_int64 ty -> - begin match T_N64.apply_rec_info ty rec_info with + begin match T_N64.apply_coercion ty coercion with | Ok ty -> Ok (Naked_int64 ty) | Bottom -> Bottom end | Naked_nativeint ty -> - begin match T_NN.apply_rec_info ty rec_info with + begin match T_NN.apply_coercion ty coercion with | Ok ty -> Ok (Naked_nativeint ty) | Bottom -> Bottom end diff --git a/middle_end/flambda/types/type_grammar.rec.mli b/middle_end/flambda/types/type_grammar.rec.mli index dcff2ab015ea..da6d3f4fcab5 100644 --- a/middle_end/flambda/types/type_grammar.rec.mli +++ b/middle_end/flambda/types/type_grammar.rec.mli @@ -39,7 +39,7 @@ val kind : t -> Flambda_kind.t val alias_type_of : Flambda_kind.t -> Simple.t -> t -val apply_rec_info : t -> Rec_info.t -> t Or_bottom.t +val apply_coercion : t -> Coercion.t -> t Or_bottom.t val eviscerate : t -> Typing_env.t -> t diff --git a/middle_end/flambda/types/type_head_intf.ml b/middle_end/flambda/types/type_head_intf.ml index 549d5a51ef02..1d5ef3ade5f3 100644 --- a/middle_end/flambda/types/type_head_intf.ml +++ b/middle_end/flambda/types/type_head_intf.ml @@ -43,7 +43,7 @@ module type S = sig -> t -> t Or_unknown.t - val apply_rec_info : t -> Rec_info.t -> t Or_bottom.t + val apply_coercion : t -> Coercion.t -> t Or_bottom.t val eviscerate : t -> t Or_unknown.t end diff --git a/middle_end/flambda/types/type_of_kind/type_of_kind_naked_float0.rec.ml b/middle_end/flambda/types/type_of_kind/type_of_kind_naked_float0.rec.ml index a3845342eda3..9a410512198f 100644 --- a/middle_end/flambda/types/type_of_kind/type_of_kind_naked_float0.rec.ml +++ b/middle_end/flambda/types/type_of_kind/type_of_kind_naked_float0.rec.ml @@ -32,8 +32,8 @@ let free_names _t = Name_occurrences.empty let all_ids_for_export _t = Ids_for_export.empty -let apply_rec_info t rec_info : _ Or_bottom.t = - if Rec_info.is_initial rec_info then Ok t +let apply_coercion t coercion : _ Or_bottom.t = + if Coercion.is_id coercion then Ok t else Bottom let eviscerate _ : _ Or_unknown.t = Unknown diff --git a/middle_end/flambda/types/type_of_kind/type_of_kind_naked_immediate0.rec.ml b/middle_end/flambda/types/type_of_kind/type_of_kind_naked_immediate0.rec.ml index f8d42aa4b8f6..06f3f26909df 100644 --- a/middle_end/flambda/types/type_of_kind/type_of_kind_naked_immediate0.rec.ml +++ b/middle_end/flambda/types/type_of_kind/type_of_kind_naked_immediate0.rec.ml @@ -61,8 +61,8 @@ let all_ids_for_export t = | Naked_immediates _ -> Ids_for_export.empty | Is_int ty | Get_tag ty -> T.all_ids_for_export ty -let apply_rec_info t rec_info : _ Or_bottom.t = - if Rec_info.is_initial rec_info then Ok t +let apply_coercion t coercion : _ Or_bottom.t = + if Coercion.is_id coercion then Ok t else Bottom let eviscerate _ : _ Or_unknown.t = Unknown diff --git a/middle_end/flambda/types/type_of_kind/type_of_kind_naked_int32_0.rec.ml b/middle_end/flambda/types/type_of_kind/type_of_kind_naked_int32_0.rec.ml index 32a75f3fb0e0..97971212904f 100644 --- a/middle_end/flambda/types/type_of_kind/type_of_kind_naked_int32_0.rec.ml +++ b/middle_end/flambda/types/type_of_kind/type_of_kind_naked_int32_0.rec.ml @@ -32,8 +32,8 @@ let free_names _t = Name_occurrences.empty let all_ids_for_export _t = Ids_for_export.empty -let apply_rec_info t rec_info : _ Or_bottom.t = - if Rec_info.is_initial rec_info then Ok t +let apply_coercion t coercion : _ Or_bottom.t = + if Coercion.is_id coercion then Ok t else Bottom let eviscerate _ : _ Or_unknown.t = Unknown diff --git a/middle_end/flambda/types/type_of_kind/type_of_kind_naked_int64_0.rec.ml b/middle_end/flambda/types/type_of_kind/type_of_kind_naked_int64_0.rec.ml index 99c62b898067..f27d517cf0f8 100644 --- a/middle_end/flambda/types/type_of_kind/type_of_kind_naked_int64_0.rec.ml +++ b/middle_end/flambda/types/type_of_kind/type_of_kind_naked_int64_0.rec.ml @@ -32,8 +32,8 @@ let free_names _t = Name_occurrences.empty let all_ids_for_export _t = Ids_for_export.empty -let apply_rec_info t rec_info : _ Or_bottom.t = - if Rec_info.is_initial rec_info then Ok t +let apply_coercion t coercion : _ Or_bottom.t = + if Coercion.is_id coercion then Ok t else Bottom let eviscerate _ : _ Or_unknown.t = Unknown diff --git a/middle_end/flambda/types/type_of_kind/type_of_kind_naked_nativeint0.rec.ml b/middle_end/flambda/types/type_of_kind/type_of_kind_naked_nativeint0.rec.ml index fd9c4724f95e..04eaac4913d4 100644 --- a/middle_end/flambda/types/type_of_kind/type_of_kind_naked_nativeint0.rec.ml +++ b/middle_end/flambda/types/type_of_kind/type_of_kind_naked_nativeint0.rec.ml @@ -31,8 +31,8 @@ let free_names _t = Name_occurrences.empty let all_ids_for_export _t = Ids_for_export.empty -let apply_rec_info t rec_info : _ Or_bottom.t = - if Rec_info.is_initial rec_info then Ok t +let apply_coercion t coercion : _ Or_bottom.t = + if Coercion.is_id coercion then Ok t else Bottom let eviscerate _ : _ Or_unknown.t = Unknown diff --git a/middle_end/flambda/types/type_of_kind/type_of_kind_value0.rec.ml b/middle_end/flambda/types/type_of_kind/type_of_kind_value0.rec.ml index 3692b3c3bb3f..a63b6ce25f86 100644 --- a/middle_end/flambda/types/type_of_kind/type_of_kind_value0.rec.ml +++ b/middle_end/flambda/types/type_of_kind/type_of_kind_value0.rec.ml @@ -156,7 +156,7 @@ let all_ids_for_export t = | String _ -> Ids_for_export.empty | Array { length; } -> T.all_ids_for_export length -let apply_rec_info t rec_info : _ Or_bottom.t = +let apply_coercion t coercion : _ Or_bottom.t = match t with | Closures { by_closure_id; } -> Or_bottom.map @@ -164,7 +164,7 @@ let apply_rec_info t rec_info : _ Or_bottom.t = map_function_decl_types by_closure_id ~f:(fun (decl : Function_declaration_type.t) : _ Or_bottom.t -> - Function_declaration_type.apply_rec_info decl rec_info)) + Function_declaration_type.apply_coercion decl coercion)) ~f:(fun by_closure_id -> Closures { by_closure_id; }) | Variant _ | Boxed_float _ @@ -173,7 +173,7 @@ let apply_rec_info t rec_info : _ Or_bottom.t = | Boxed_nativeint _ | String _ | Array _ -> - if Rec_info.is_initial rec_info then Ok t + if Coercion.is_id coercion then Ok t else Bottom let eviscerate t : _ Or_unknown.t = diff --git a/ocamltest/ocaml_modifiers.ml b/ocamltest/ocaml_modifiers.ml index c310cf3629eb..1a2ad2d0fdcb 100644 --- a/ocamltest/ocaml_modifiers.ml +++ b/ocamltest/ocaml_modifiers.ml @@ -104,6 +104,36 @@ let compilerlibs_subdirs = "file_formats"; "lambda"; "middle_end"; + "middle_end/closure"; + "middle_end/flambda"; + "middle_end/flambda/cmx"; + "middle_end/flambda/compilenv_deps"; + "middle_end/flambda/types"; + "middle_end/flambda/types/structures"; + "middle_end/flambda/types/kinds"; + "middle_end/flambda/types/type_of_kind"; + "middle_end/flambda/types/type_of_kind/boilerplate"; + "middle_end/flambda/types/template"; + "middle_end/flambda/types/basic"; + "middle_end/flambda/types/env"; + "middle_end/flambda/unboxing"; + "middle_end/flambda/to_cmm"; + "middle_end/flambda/terms"; + "middle_end/flambda/terms/template"; + "middle_end/flambda/tests"; + "middle_end/flambda/basic"; + "middle_end/flambda/parser"; + "middle_end/flambda/from_lambda"; + "middle_end/flambda/naming"; + "middle_end/flambda/scripts"; + "middle_end/flambda/compare"; + "middle_end/flambda/lifting"; + "middle_end/flambda/simplify"; + "middle_end/flambda/simplify/typing_helpers"; + "middle_end/flambda/simplify/template"; + "middle_end/flambda/simplify/basic"; + "middle_end/flambda/simplify/env"; + "middle_end/flambda/inlining"; "parsing"; "toplevel"; "typing"; diff --git a/testsuite/tests/flambda2-aliases/test.ml b/testsuite/tests/flambda2-aliases/test.ml new file mode 100644 index 000000000000..727488403cf2 --- /dev/null +++ b/testsuite/tests/flambda2-aliases/test.ml @@ -0,0 +1,622 @@ +(* TEST + include ocamlcommon + include ocamlmiddleend + * bytecode +*) + +let () = Clflags.flambda_invariant_checks := true +let () = Clflags.dump_rawflambda := true +let () = Misc.Color.setup (Some Never) + +let compilation_unit = + let dummy = "compilation_unit" in + Compilation_unit.create + (Ident.create_persistent dummy) + (Linkage_name.create dummy) + +let () = Compilation_unit.set_current compilation_unit + +let next_time : ?mode:Name_mode.t -> unit -> Binding_time.With_name_mode.t = + let next = ref Binding_time.earliest_var in + fun ?(mode = Name_mode.normal) () -> + let time = !next in + next := Binding_time.succ time; + Binding_time.With_name_mode.create time mode + +let mk_var name = Variable.create name +let mk_simple name = Simple.var (mk_var name) +let mk_coercion from to_ = Coercion.change_depth ~from ~to_ + +let mk_symbol : string -> Symbol.t = + let next = ref 0 in + fun name -> + let tag = !next in + incr next; + let full_name = Format.sprintf "%s_%d" name tag in + Symbol.create compilation_unit (full_name |> Linkage_name.create) + +let of_ok = function + | Or_bottom.Ok a -> a + | Or_bottom.Bottom -> Misc.fatal_errorf "of_ok Bottom" + +let get_canonical aliases simple name_mode ~min_name_mode = + (* Punt on testing by min_binding_time but that's going away soon *) + let min_binding_time = Binding_time.consts_and_discriminants in + match + Aliases.get_canonical_element_exn aliases simple name_mode + ~min_binding_time ~min_name_mode + with + | exception Not_found -> None + | canonical -> Some canonical + +let add_alias + ppf + aliases + ~element1 + ~binding_time_and_mode1 + ~coercion_from_element2_to_element1 + ~element2 + ~binding_time_and_mode2 = + let element2 = + Simple.with_coercion element2 coercion_from_element2_to_element1 + in + let { Aliases.t; canonical_element; alias_of_demoted_element } = + Aliases.add + aliases + ~element1 + ~binding_time_and_mode1 + ~element2 + ~binding_time_and_mode2 + in + let coercion_from_alias_of_demoted_to_canonical = + Simple.coercion alias_of_demoted_element + in + let alias_of_demoted_element = + Simple.without_coercion alias_of_demoted_element + in + let pp_name_mode ppf binding_time_and_mode = + let name_mode = + Binding_time.With_name_mode.name_mode binding_time_and_mode + in + if Name_mode.is_normal name_mode then () else + Format.fprintf ppf ("@ (%a)") + Name_mode.print name_mode + in + Format.fprintf ppf "[added] @[%a%a@] <--[%a]-- @[%a%a@]@." + Simple.print canonical_element + pp_name_mode binding_time_and_mode1 + Coercion.print coercion_from_alias_of_demoted_to_canonical + Simple.print alias_of_demoted_element + pp_name_mode binding_time_and_mode2; + t + +let pp_opt_or_none f ppf = function + | Some a -> f ppf a + | None -> Format.pp_print_string ppf "" + +let test msg ~f = + Format.printf "*** %s@." msg; + f Format.std_formatter; + Format.pp_print_newline Format.std_formatter (); + Format.pp_print_newline Format.std_formatter () + +let () = test "empty" ~f:(fun ppf -> + let aliases = Aliases.empty in + Aliases.print ppf aliases) + +let () = test "single alias" ~f:(fun ppf -> + let aliases = Aliases.empty in + let t_x = next_time () in + let t_y = next_time () in + let x = mk_simple "x" in + let y = mk_simple "y" in + (* x <--[f]-- y *) + let aliases = + add_alias + ppf + aliases + ~element1:x + ~binding_time_and_mode1:t_x + ~coercion_from_element2_to_element1:(mk_coercion 1 0) + ~element2:y + ~binding_time_and_mode2:t_y + in + Aliases.print ppf aliases) + +let () = test "single alias (inverse)" ~f:(fun ppf -> + let aliases = Aliases.empty in + let t_y = next_time () in + let t_x = next_time () in + let x = mk_simple "x" in + let y = mk_simple "y" in + (* x <--[f]-- y + ~> + y <--[F]-- x *) + let aliases = + add_alias + ppf + aliases + ~element1:x + ~binding_time_and_mode1:t_x + ~coercion_from_element2_to_element1:(mk_coercion 1 0) + ~element2:y + ~binding_time_and_mode2:t_y + in + Aliases.print ppf aliases) + +let () = test "two aliases (independent)" ~f:(fun ppf -> + let aliases = Aliases.empty in + let t_x = next_time () in + let t_y = next_time () in + let t_z = next_time () in + let x = mk_simple "x" in + let y = mk_simple "y" in + let z = mk_simple "z" in + (* x <--[f]-- y + + + x <--[g]-- z + ~> + x <--[f]-- y + ^--[g]-- z *) + let aliases = + add_alias + ppf + aliases + ~element1:x + ~binding_time_and_mode1:t_x + ~coercion_from_element2_to_element1:(mk_coercion 1 0) + ~element2:y + ~binding_time_and_mode2:t_y + in + let aliases = + add_alias + ppf + aliases + ~element1:x + ~binding_time_and_mode1:t_x + ~coercion_from_element2_to_element1:(mk_coercion 2 0) + ~element2:z + ~binding_time_and_mode2:t_z + in + Aliases.print ppf aliases) + +let () = test "two aliases (simple chain)" ~f:(fun ppf -> + let aliases = Aliases.empty in + let t_x = next_time () in + let t_y = next_time () in + let t_z = next_time () in + let x = mk_simple "x" in + let y = mk_simple "y" in + let z = mk_simple "z" in + (* x <--[f]-- y + + + y <--[g]-- z + ~> + x <--[f]-- y + ^--[fg]-- z *) + let aliases = + add_alias + ppf + aliases + ~element1:x + ~binding_time_and_mode1:t_x + ~coercion_from_element2_to_element1:(mk_coercion 1 0) + ~element2:y + ~binding_time_and_mode2:t_y + in + let aliases = + add_alias + ppf + aliases + ~element1:y + ~binding_time_and_mode1:t_y + ~coercion_from_element2_to_element1:(mk_coercion 2 1) + ~element2:z + ~binding_time_and_mode2:t_z + in + Aliases.print ppf aliases) + +let () = test "two aliases (two inverses)" ~f:(fun ppf -> + let aliases = Aliases.empty in + let t_z = next_time () in + let t_x = next_time () in + let t_y = next_time () in + let x = mk_simple "x" in + let y = mk_simple "y" in + let z = mk_simple "z" in + (* x <--[f]-- y + + + y <--[g]-- z + ~> + z <--[GF]-- x + ^--[G]-- y *) + let aliases = + add_alias + ppf + aliases + ~element1:x + ~binding_time_and_mode1:t_x + ~coercion_from_element2_to_element1:(mk_coercion 1 0) + ~element2:y + ~binding_time_and_mode2:t_y + in + let aliases = + add_alias + ppf + aliases + ~element1:y + ~binding_time_and_mode1:t_y + ~coercion_from_element2_to_element1:(mk_coercion 2 1) + ~element2:z + ~binding_time_and_mode2:t_z + in + Aliases.print ppf aliases) + +let () = test "two aliases (one inverse)" ~f:(fun ppf -> + let aliases = Aliases.empty in + let t_z = next_time () in + let t_x = next_time () in + let t_y = next_time () in + let x = mk_simple "x" in + let y = mk_simple "y" in + let z = mk_simple "z" in + (* x <--[f]-- y + + + z <--[g]-- y + ~> + z <--[gF]-- x + ^--[g]-- y *) + let aliases = + add_alias + ppf + aliases + ~element1:x + ~binding_time_and_mode1:t_x + ~coercion_from_element2_to_element1:(mk_coercion 1 0) + ~element2:y + ~binding_time_and_mode2:t_y + in + let aliases = + add_alias + ppf + aliases + ~element1:z + ~binding_time_and_mode1:t_z + ~coercion_from_element2_to_element1:(mk_coercion 1 2) + ~element2:y + ~binding_time_and_mode2:t_y + in + Aliases.print ppf aliases) + +let () = test "two aliases (one inverse)" ~f:(fun ppf -> + let aliases = Aliases.empty in + let t_x = next_time () in + let t_y = next_time () in + let t_z = next_time () in + let x = mk_simple "x" in + let y = mk_simple "y" in + let z = mk_simple "z" in + (* x <--[f]-- y + + + z <--[g]-- y + ~> + x <--[f]-- y + ^--[fG]-- z *) + let aliases = + add_alias + ppf + aliases + ~element1:x + ~binding_time_and_mode1:t_x + ~coercion_from_element2_to_element1:(mk_coercion 1 0) + ~element2:y + ~binding_time_and_mode2:t_y + in + let aliases = + add_alias + ppf + aliases + ~element1:z + ~binding_time_and_mode1:t_z + ~coercion_from_element2_to_element1:(mk_coercion 1 2) + ~element2:y + ~binding_time_and_mode2:t_y + in + Aliases.print ppf aliases) + +let () = test "three aliases (one inverse)" ~f:(fun ppf -> + let aliases = Aliases.empty in + let t_x = next_time () in + let t_y = next_time () in + let t_z = next_time () in + let t_t = next_time () in + let x = mk_simple "x" in + let y = mk_simple "y" in + let z = mk_simple "z" in + let t = mk_simple "t" in + (* x <--[f]-- y + + + z <--[g]-- t + + + y <--[h]-- t + ~> + x <--[f]-- y + ^^--[fhG]-- z + \--[fh]-- t *) + let aliases = + add_alias + ppf + aliases + ~element1:x + ~binding_time_and_mode1:t_x + ~coercion_from_element2_to_element1:(mk_coercion 1 0) + ~element2:y + ~binding_time_and_mode2:t_y + in + let aliases = + add_alias + ppf + aliases + ~element1:z + ~binding_time_and_mode1:t_z + ~coercion_from_element2_to_element1:(mk_coercion 3 2) + ~element2:t + ~binding_time_and_mode2:t_t + in + let aliases = + add_alias + ppf + aliases + ~element1:y + ~binding_time_and_mode1:t_y + ~coercion_from_element2_to_element1:(mk_coercion 3 1) + ~element2:t + ~binding_time_and_mode2:t_t + in + Aliases.print ppf aliases) + +let () = test "three aliases (two inverses)" ~f:(fun ppf -> + let aliases = Aliases.empty in + let t_z = next_time () in + let t_x = next_time () in + let t_y = next_time () in + let t_t = next_time () in + let x = mk_simple "x" in + let y = mk_simple "y" in + let z = mk_simple "z" in + let t = mk_simple "t" in + (* x <--[f]-- y + + + z <--[g]-- t + + + y <--[h]-- t + ~> + z <--[gHF]-- x + ^^--[gH]-- y + \--[g]-- t *) + let aliases = + add_alias + ppf + aliases + ~element1:x + ~binding_time_and_mode1:t_x + ~coercion_from_element2_to_element1:(mk_coercion 1 0) + ~element2:y + ~binding_time_and_mode2:t_y + in + let aliases = + add_alias + ppf + aliases + ~element1:z + ~binding_time_and_mode1:t_z + ~coercion_from_element2_to_element1:(mk_coercion 3 2) + ~element2:t + ~binding_time_and_mode2:t_t + in + let aliases = + add_alias + ppf + aliases + ~element1:y + ~binding_time_and_mode1:t_y + ~coercion_from_element2_to_element1:(mk_coercion 3 1) + ~element2:t + ~binding_time_and_mode2:t_t + in + Aliases.print ppf aliases) + +let () = test "three aliases of const (two inverses)" ~f:(fun ppf -> + let aliases = Aliases.empty in + let t_z = + Binding_time.With_name_mode.create + Binding_time.consts_and_discriminants + Name_mode.normal + in + let t_x = next_time () in + let t_y = next_time () in + let t_t = next_time () in + let x = mk_simple "x" in + let y = mk_simple "y" in + let z = Reg_width_things.Const.untagged_const_true |> Simple.const in + let t = mk_simple "t" in + (* x <--[f]-- y + + + z <--[g]-- t + + + y <--[h]-- t + ~> + z <--[gHF]-- x + ^^--[gH]-- y + \--[g]-- t *) + let aliases = + add_alias + ppf + aliases + ~element1:x + ~binding_time_and_mode1:t_x + ~coercion_from_element2_to_element1:(mk_coercion 1 0) + ~element2:y + ~binding_time_and_mode2:t_y + in + let aliases = + add_alias + ppf + aliases + ~element1:z + ~binding_time_and_mode1:t_z + ~coercion_from_element2_to_element1:(mk_coercion 3 2) + ~element2:t + ~binding_time_and_mode2:t_t + in + let aliases = + add_alias + ppf + aliases + ~element1:y + ~binding_time_and_mode1:t_y + ~coercion_from_element2_to_element1:(mk_coercion 3 1) + ~element2:t + ~binding_time_and_mode2:t_t + in + Aliases.print ppf aliases) + + +let two_var_name_mode_test name mode_x mode_y min_name_mode = + test name ~f:(fun ppf -> + let aliases = Aliases.empty in + let t_x = next_time () ~mode:mode_x in + let t_y = next_time () ~mode:mode_y in + let v_x = mk_var "x" in + let v_y = mk_var "y" in + let x = Simple.var v_x in + let y = Simple.var v_y in + (* x <--[f]-- y *) + let aliases = + add_alias + ppf + aliases + ~element1:x + ~binding_time_and_mode1:t_x + ~coercion_from_element2_to_element1:(mk_coercion 1 0) + ~element2:y + ~binding_time_and_mode2:t_y + in + Format.fprintf ppf + "Canonical for %a: %a@.\ + ... with mode >= %a: %a@.\ + Aliases of %a: %a" + Simple.print y + Simple.print + (Aliases.get_canonical_ignoring_name_mode aliases (Name.var v_y)) + Name_mode.print min_name_mode + (pp_opt_or_none Simple.print) + (get_canonical aliases y mode_y ~min_name_mode) + Simple.print x + Aliases.Alias_set.print (Aliases.get_aliases aliases x)) + +let () = + two_var_name_mode_test "name mode: phantom = phantom" + Name_mode.phantom Name_mode.phantom Name_mode.phantom + +let () = + two_var_name_mode_test "name mode: normal > phantom" + Name_mode.normal Name_mode.phantom Name_mode.phantom + +let () = + two_var_name_mode_test "name mode: phantom !>= in_types (fail)" + Name_mode.phantom Name_mode.phantom Name_mode.in_types + +let () = + two_var_name_mode_test "name mode: phantom !>= in_types (return same)" + Name_mode.phantom Name_mode.in_types Name_mode.in_types + +let () = + two_var_name_mode_test "name mode: normal > in_types" + Name_mode.normal Name_mode.phantom Name_mode.in_types + +let () = + two_var_name_mode_test "name mode: phantom !>= normal" + Name_mode.phantom Name_mode.phantom Name_mode.normal + +let () = test "three aliases (one inverse) /w modes" ~f:(fun ppf -> + let aliases = Aliases.empty in + let t_x = next_time () ~mode:Name_mode.in_types in + let t_y = next_time () ~mode:Name_mode.in_types in + let t_z = next_time () ~mode:Name_mode.phantom in + let t_t = next_time () ~mode:Name_mode.normal in + let v_x = mk_var "x" in + let v_y = mk_var "y" in + let v_z = mk_var "z" in + let v_t = mk_var "t" in + let x = Simple.var v_x in + let y = Simple.var v_y in + let z = Simple.var v_z in + let t = Simple.var v_t in + (* x <--[f]-- y + + + z <--[g]-- t + + + y <--[h]-- t + ~> + x <--[f]-- y + ^^--[fhG]-- z + \--[fh]-- t *) + let aliases = + add_alias + ppf + aliases + ~element1:x + ~binding_time_and_mode1:t_x + ~coercion_from_element2_to_element1:(mk_coercion 1 0) + ~element2:y + ~binding_time_and_mode2:t_y + in + let aliases = + add_alias + ppf + aliases + ~element1:z + ~binding_time_and_mode1:t_z + ~coercion_from_element2_to_element1:(mk_coercion 3 2) + ~element2:t + ~binding_time_and_mode2:t_t + in + let aliases = + add_alias + ppf + aliases + ~element1:y + ~binding_time_and_mode1:t_y + ~coercion_from_element2_to_element1:(mk_coercion 3 1) + ~element2:t + ~binding_time_and_mode2:t_t + in + let show_canonicals simple var mode = + Format.fprintf ppf + "@.Canonical for %a: %a@.\ + ... with mode >= Phantom: %a@.\ + ... >= In_types: %a@.\ + ... >= Normal: %a@.\ + " + Simple.print simple + Simple.print + (Aliases.get_canonical_ignoring_name_mode aliases (Name.var var)) + (pp_opt_or_none Simple.print) + (get_canonical aliases simple mode ~min_name_mode:Name_mode.phantom) + (pp_opt_or_none Simple.print) + (get_canonical aliases simple mode ~min_name_mode:Name_mode.in_types) + (pp_opt_or_none Simple.print) + (get_canonical aliases simple mode ~min_name_mode:Name_mode.normal) + in + show_canonicals x v_x Name_mode.in_types; + show_canonicals y v_y Name_mode.in_types; + show_canonicals z v_z Name_mode.phantom; + show_canonicals t v_t Name_mode.normal; + Format.fprintf ppf "@.Aliases of %a: %a@.@.%a" + Simple.print z + Aliases.Alias_set.print (Aliases.get_aliases aliases x) + Aliases.print aliases) + + +let () = print_endline "OK." diff --git a/testsuite/tests/flambda2-aliases/test.reference b/testsuite/tests/flambda2-aliases/test.reference new file mode 100644 index 000000000000..a12cdb279c30 --- /dev/null +++ b/testsuite/tests/flambda2-aliases/test.reference @@ -0,0 +1,214 @@ +*** empty +((canonical_elements {}) (aliases_of_canonical_names {}) + (aliases_of_consts {}) (binding_times_and_modes {})) + +*** single alias +[added] x/0 <--[(depth 1 -> 0)]-- y/1 +((canonical_elements {(y/1 (x/0 (coercion (depth 1 -> 0))))}) + (aliases_of_canonical_names {(x/0 {(Normal {(y/1 (depth 1 -> 0))})})}) + (aliases_of_consts {}) + (binding_times_and_modes + {(y/1 (bound at time 4 Normal)) (x/0 (bound at time 3 Normal))})) + +*** single alias (inverse) +[added] y/3 <--[(depth 0 -> 1)]-- x/2 +((canonical_elements {(x/2 (y/3 (coercion (depth 0 -> 1))))}) + (aliases_of_canonical_names {(y/3 {(Normal {(x/2 (depth 0 -> 1))})})}) + (aliases_of_consts {}) + (binding_times_and_modes + {(x/2 (bound at time 6 Normal)) (y/3 (bound at time 5 Normal))})) + +*** two aliases (independent) +[added] x/4 <--[(depth 1 -> 0)]-- y/5 +[added] x/4 <--[(depth 2 -> 0)]-- z/6 +((canonical_elements + {(y/5 (x/4 (coercion (depth 1 -> 0)))) + (z/6 (x/4 (coercion (depth 2 -> 0))))}) + (aliases_of_canonical_names + {(x/4 {(Normal {(y/5 (depth 1 -> 0)) (z/6 (depth 2 -> 0))})})}) + (aliases_of_consts {}) + (binding_times_and_modes + {(x/4 (bound at time 7 Normal)) (y/5 (bound at time 8 Normal)) + (z/6 (bound at time 9 Normal))})) + +*** two aliases (simple chain) +[added] x/7 <--[(depth 1 -> 0)]-- y/8 +[added] x/7 <--[(depth 2 -> 0)]-- z/9 +((canonical_elements + {(z/9 (x/7 (coercion (depth 2 -> 0)))) + (y/8 (x/7 (coercion (depth 1 -> 0))))}) + (aliases_of_canonical_names + {(x/7 {(Normal {(z/9 (depth 2 -> 0)) (y/8 (depth 1 -> 0))})})}) + (aliases_of_consts {}) + (binding_times_and_modes + {(z/9 (bound at time 12 Normal)) (x/7 (bound at time 10 Normal)) + (y/8 (bound at time 11 Normal))})) + +*** two aliases (two inverses) +[added] x/10 <--[(depth 1 -> 0)]-- y/11 +[added] z/12 <--[(depth 1 -> 2)]-- y/11 +((canonical_elements + {(x/10 (z/12 (coercion (depth 0 -> 2)))) + (y/11 (z/12 (coercion (depth 1 -> 2))))}) + (aliases_of_canonical_names + {(z/12 {(Normal {(x/10 (depth 0 -> 2)) (y/11 (depth 1 -> 2))})})}) + (aliases_of_consts {}) + (binding_times_and_modes + {(x/10 (bound at time 14 Normal)) (z/12 (bound at time 13 Normal)) + (y/11 (bound at time 15 Normal))})) + +*** two aliases (one inverse) +[added] x/13 <--[(depth 1 -> 0)]-- y/14 +[added] z/15 <--[(depth 1 -> 2)]-- y/14 +((canonical_elements + {(x/13 (z/15 (coercion (depth 0 -> 2)))) + (y/14 (z/15 (coercion (depth 1 -> 2))))}) + (aliases_of_canonical_names + {(z/15 {(Normal {(x/13 (depth 0 -> 2)) (y/14 (depth 1 -> 2))})})}) + (aliases_of_consts {}) + (binding_times_and_modes + {(z/15 (bound at time 16 Normal)) (x/13 (bound at time 17 Normal)) + (y/14 (bound at time 18 Normal))})) + +*** two aliases (one inverse) +[added] x/16 <--[(depth 1 -> 0)]-- y/17 +[added] x/16 <--[(depth 2 -> 0)]-- z/18 +((canonical_elements + {(y/17 (x/16 (coercion (depth 1 -> 0)))) + (z/18 (x/16 (coercion (depth 2 -> 0))))}) + (aliases_of_canonical_names + {(x/16 {(Normal {(y/17 (depth 1 -> 0)) (z/18 (depth 2 -> 0))})})}) + (aliases_of_consts {}) + (binding_times_and_modes + {(x/16 (bound at time 19 Normal)) (y/17 (bound at time 20 Normal)) + (z/18 (bound at time 21 Normal))})) + +*** three aliases (one inverse) +[added] x/19 <--[(depth 1 -> 0)]-- y/20 +[added] z/21 <--[(depth 3 -> 2)]-- t/22 +[added] x/19 <--[(depth 3 -> 0)]-- t/22 +((canonical_elements + {(y/20 (x/19 (coercion (depth 1 -> 0)))) + (z/21 (x/19 (coercion (depth 2 -> 0)))) + (t/22 (x/19 (coercion (depth 3 -> 0))))}) + (aliases_of_canonical_names + {(x/19 + {(Normal + {(y/20 (depth 1 -> 0)) (z/21 (depth 2 -> 0)) (t/22 (depth 3 -> 0))})})}) + (aliases_of_consts {}) + (binding_times_and_modes + {(x/19 (bound at time 22 Normal)) (y/20 (bound at time 23 Normal)) + (z/21 (bound at time 24 Normal)) (t/22 (bound at time 25 Normal))})) + +*** three aliases (two inverses) +[added] x/23 <--[(depth 1 -> 0)]-- y/24 +[added] z/25 <--[(depth 3 -> 2)]-- t/26 +[added] z/25 <--[(depth 1 -> 2)]-- y/24 +((canonical_elements + {(x/23 (z/25 (coercion (depth 0 -> 2)))) + (y/24 (z/25 (coercion (depth 1 -> 2)))) + (t/26 (z/25 (coercion (depth 3 -> 2))))}) + (aliases_of_canonical_names + {(z/25 + {(Normal + {(x/23 (depth 0 -> 2)) (y/24 (depth 1 -> 2)) (t/26 (depth 3 -> 2))})})}) + (aliases_of_consts {}) + (binding_times_and_modes + {(x/23 (bound at time 27 Normal)) (z/25 (bound at time 26 Normal)) + (y/24 (bound at time 28 Normal)) (t/26 (bound at time 29 Normal))})) + +*** three aliases of const (two inverses) +[added] x/27 <--[(depth 1 -> 0)]-- y/28 +[added] #1 <--[(depth 3 -> 2)]-- t/29 +[added] #1 <--[(depth 1 -> 2)]-- y/28 +((canonical_elements + {(y/28 (#1 (coercion (depth 1 -> 2)))) + (t/29 (#1 (coercion (depth 3 -> 2)))) + (x/27 (#1 (coercion (depth 0 -> 2))))}) (aliases_of_canonical_names {}) + (aliases_of_consts + {(#1 + {(Normal + {(y/28 (depth 1 -> 2)) (t/29 (depth 3 -> 2)) (x/27 (depth 0 -> 2))})})}) + (binding_times_and_modes + {(y/28 (bound at time 31 Normal)) (t/29 (bound at time 32 Normal)) + (x/27 (bound at time 30 Normal))})) + +*** name mode: phantom = phantom +[added] x/30 (Phantom) <--[(depth 1 -> 0)]-- y/31 (Phantom) +Canonical for y/31: (coerce x/30 (depth 0 -> 1)) +... with mode >= Phantom: (coerce x/30 (depth 0 -> 1)) +Aliases of x/30: ((const ()) (names {(x/30 id) (y/31 (depth 1 -> 0))}) + +*** name mode: normal > phantom +[added] x/32 <--[(depth 1 -> 0)]-- y/33 (Phantom) +Canonical for y/33: (coerce x/32 (depth 0 -> 1)) +... with mode >= Phantom: (coerce x/32 (depth 0 -> 1)) +Aliases of x/32: ((const ()) (names {(y/33 (depth 1 -> 0)) (x/32 id)}) + +*** name mode: phantom !>= in_types (fail) +[added] x/34 (Phantom) <--[(depth 1 -> 0)]-- y/35 (Phantom) +Canonical for y/35: (coerce x/34 (depth 0 -> 1)) +... with mode >= In_types: +Aliases of x/34: ((const ()) (names {(x/34 id) (y/35 (depth 1 -> 0))}) + +*** name mode: phantom !>= in_types (return same) +[added] x/36 (Phantom) <--[(depth 1 -> 0)]-- y/37 (In_types) +Canonical for y/37: (coerce x/36 (depth 0 -> 1)) +... with mode >= In_types: y/37 +Aliases of x/36: ((const ()) (names {(x/36 id) (y/37 (depth 1 -> 0))}) + +*** name mode: normal > in_types +[added] x/38 <--[(depth 1 -> 0)]-- y/39 (Phantom) +Canonical for y/39: (coerce x/38 (depth 0 -> 1)) +... with mode >= In_types: (coerce x/38 (depth 0 -> 1)) +Aliases of x/38: ((const ()) (names {(x/38 id) (y/39 (depth 1 -> 0))}) + +*** name mode: phantom !>= normal +[added] x/40 (Phantom) <--[(depth 1 -> 0)]-- y/41 (Phantom) +Canonical for y/41: (coerce x/40 (depth 0 -> 1)) +... with mode >= Normal: +Aliases of x/40: ((const ()) (names {(y/41 (depth 1 -> 0)) (x/40 id)}) + +*** three aliases (one inverse) /w modes +[added] x/42 (In_types) <--[(depth 1 -> 0)]-- y/43 (In_types) +[added] z/44 (Phantom) <--[(depth 3 -> 2)]-- t/45 +[added] x/42 (In_types) <--[(depth 3 -> 0)]-- t/45 + +Canonical for x/42: x/42 +... with mode >= Phantom: (coerce z/44 (depth 2 -> 0)) +... >= In_types: x/42 +... >= Normal: (coerce t/45 (depth 3 -> 0)) + +Canonical for y/43: (coerce x/42 (depth 0 -> 1)) +... with mode >= Phantom: (coerce z/44 (depth 2 -> 1)) +... >= In_types: (coerce x/42 (depth 0 -> 1)) +... >= Normal: (coerce t/45 (depth 3 -> 1)) + +Canonical for z/44: (coerce x/42 (depth 0 -> 2)) +... with mode >= Phantom: z/44 +... >= In_types: (coerce x/42 (depth 0 -> 2)) +... >= Normal: (coerce t/45 (depth 3 -> 2)) + +Canonical for t/45: (coerce x/42 (depth 0 -> 3)) +... with mode >= Phantom: (coerce z/44 (depth 2 -> 3)) +... >= In_types: (coerce x/42 (depth 0 -> 3)) +... >= Normal: t/45 + +Aliases of z/44: ((const ()) + (names + {(y/43 (depth 1 -> 0)) (x/42 id) (t/45 (depth 3 -> 0)) + (z/44 (depth 2 -> 0))}) + +((canonical_elements + {(y/43 (x/42 (coercion (depth 1 -> 0)))) + (t/45 (x/42 (coercion (depth 3 -> 0)))) + (z/44 (x/42 (coercion (depth 2 -> 0))))}) + (aliases_of_canonical_names + {(x/42 + {(Phantom {(z/44 (depth 2 -> 0))}) (In_types {(y/43 (depth 1 -> 0))}) + (Normal {(t/45 (depth 3 -> 0))})})}) (aliases_of_consts {}) + (binding_times_and_modes + {(y/43 (bound at time 46 In_types)) (x/42 (bound at time 45 In_types)) + (t/45 (bound at time 48 Normal)) (z/44 (bound at time 47 Phantom))})) + +OK.