From 059d0b40078e33257f7d187fd03d5945574a74f9 Mon Sep 17 00:00:00 2001 From: xclerc Date: Wed, 28 Oct 2020 16:25:02 +0000 Subject: [PATCH 01/16] Rec_info part 1: aliases. --- .depend | 135 +-- compilerlibs/Makefile.compilerlibs | 1 + middle_end/flambda/basic/simple.ml | 28 +- middle_end/flambda/basic/simple.mli | 6 +- middle_end/flambda/cmx/ids_for_export.ml | 8 +- middle_end/flambda/compilenv_deps/coercion.ml | 26 + .../flambda/compilenv_deps/coercion.mli | 28 + .../flambda/compilenv_deps/flambda_colours.ml | 2 +- .../compilenv_deps/flambda_colours.mli | 2 +- middle_end/flambda/compilenv_deps/rec_info.ml | 3 +- .../flambda/compilenv_deps/rec_info.mli | 3 +- .../compilenv_deps/reg_width_things.ml | 46 +- .../compilenv_deps/reg_width_things.mli | 6 +- .../flambda/inlining/inlining_decision.ml | 10 +- .../flambda/inlining/inlining_decision.mli | 2 +- .../flambda/inlining/inlining_transforms.ml | 5 +- .../common_subexpression_elimination.ml | 4 +- .../simplify/simplify_apply_expr.rec.ml | 18 +- .../simplify/simplify_set_of_closures.rec.ml | 10 +- .../flambda/simplify/simplify_simple.ml | 12 +- .../simplify/simplify_unary_primitive.ml | 4 +- middle_end/flambda/types/env/aliases.ml | 833 ++++++++++++------ middle_end/flambda/types/env/aliases.mli | 75 +- .../flambda/types/env/typing_env.rec.ml | 116 ++- .../flambda/types/env/typing_env.rec.mli | 4 +- middle_end/flambda/types/flambda_type.mli | 8 +- .../function_declaration_type.rec.ml | 48 +- .../function_declaration_type.rec.mli | 6 +- .../types/template/flambda_type.templ.ml | 2 +- middle_end/flambda/types/type_descr.rec.ml | 38 +- middle_end/flambda/types/type_descr_intf.ml | 2 +- middle_end/flambda/types/type_grammar.rec.ml | 18 +- middle_end/flambda/types/type_grammar.rec.mli | 4 +- middle_end/flambda/types/type_head_intf.ml | 2 +- .../type_of_kind_naked_float0.rec.ml | 4 +- .../type_of_kind_naked_immediate0.rec.ml | 4 +- .../type_of_kind_naked_int32_0.rec.ml | 4 +- .../type_of_kind_naked_int64_0.rec.ml | 4 +- .../type_of_kind_naked_nativeint0.rec.ml | 4 +- .../type_of_kind/type_of_kind_value0.rec.ml | 6 +- ocamltest/ocaml_modifiers.ml | 30 + testsuite/tests/flambda2-aliases/test.ml | 580 ++++++++++++ .../tests/flambda2-aliases/test.reference | 131 +++ 43 files changed, 1736 insertions(+), 546 deletions(-) create mode 100644 middle_end/flambda/compilenv_deps/coercion.ml create mode 100644 middle_end/flambda/compilenv_deps/coercion.mli create mode 100644 testsuite/tests/flambda2-aliases/test.ml create mode 100644 testsuite/tests/flambda2-aliases/test.reference diff --git a/.depend b/.depend index 0c0eef940789..fb551126f885 100644 --- a/.depend +++ b/.depend @@ -3895,6 +3895,11 @@ 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 : \ + middle_end/flambda/compilenv_deps/coercion.cmi +middle_end/flambda/compilenv_deps/coercion.cmx : \ + middle_end/flambda/compilenv_deps/coercion.cmi +middle_end/flambda/compilenv_deps/coercion.cmi : middle_end/flambda/compilenv_deps/compilation_unit.cmo : \ utils/misc.cmi \ middle_end/flambda/compilenv_deps/linkage_name.cmi \ @@ -3949,24 +3954,14 @@ 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 \ middle_end/flambda/compilenv_deps/rec_info.cmi -middle_end/flambda/compilenv_deps/rec_info.cmi : \ - utils/identifiable.cmi +middle_end/flambda/compilenv_deps/rec_info.cmi : 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 +3970,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 +3984,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 \ @@ -4508,7 +4504,6 @@ middle_end/flambda/basic/set_of_closures_origin.cmi : \ middle_end/flambda/basic/simple.cmo : \ 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_permutation.cmi \ middle_end/flambda/naming/name_occurrences.cmi \ middle_end/flambda/naming/name_mode.cmi \ @@ -4516,11 +4511,11 @@ middle_end/flambda/basic/simple.cmo : \ 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/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_permutation.cmx \ middle_end/flambda/naming/name_occurrences.cmx \ middle_end/flambda/naming/name_mode.cmx \ @@ -4528,6 +4523,7 @@ middle_end/flambda/basic/simple.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 +4531,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 : \ @@ -5199,7 +5195,6 @@ middle_end/flambda/inlining/inlining_cost.cmi : \ middle_end/flambda/terms/flambda.cmi \ middle_end/flambda/simplify/env/downwards_env.cmi middle_end/flambda/inlining/inlining_decision.cmo : \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ utils/numbers.cmi \ utils/misc.cmi \ middle_end/flambda/types/inlining/inlining_state.cmi \ @@ -5208,10 +5203,10 @@ middle_end/flambda/inlining/inlining_decision.cmo : \ middle_end/flambda/terms/function_declaration.cmi \ middle_end/flambda/terms/flambda.cmi \ middle_end/flambda/simplify/env/downwards_env.cmi \ + middle_end/flambda/compilenv_deps/coercion.cmi \ utils/clflags.cmi \ middle_end/flambda/inlining/inlining_decision.cmi middle_end/flambda/inlining/inlining_decision.cmx : \ - middle_end/flambda/compilenv_deps/rec_info.cmx \ utils/numbers.cmx \ utils/misc.cmx \ middle_end/flambda/types/inlining/inlining_state.cmx \ @@ -5220,16 +5215,17 @@ middle_end/flambda/inlining/inlining_decision.cmx : \ middle_end/flambda/terms/function_declaration.cmx \ middle_end/flambda/terms/flambda.cmx \ middle_end/flambda/simplify/env/downwards_env.cmx \ + middle_end/flambda/compilenv_deps/coercion.cmx \ utils/clflags.cmx \ middle_end/flambda/inlining/inlining_decision.cmi middle_end/flambda/inlining/inlining_decision.cmi : \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ middle_end/flambda/types/inlining/inlining_state.cmi \ middle_end/flambda/inlining/inlining_cost.cmi \ middle_end/flambda/basic/inline_attribute.cmi \ middle_end/flambda/terms/function_declaration.cmi \ middle_end/flambda/terms/flambda.cmi \ - middle_end/flambda/simplify/env/downwards_env.cmi + middle_end/flambda/simplify/env/downwards_env.cmi \ + middle_end/flambda/compilenv_deps/coercion.cmi middle_end/flambda/inlining/inlining_report.cmo : \ utils/misc.cmi \ middle_end/flambda/inlining/inlining_decision.cmi \ @@ -5256,7 +5252,6 @@ middle_end/flambda/inlining/inlining_transforms.cmo : \ middle_end/flambda/basic/trap_action.cmi \ middle_end/flambda/simplify/simplify_import.cmi \ middle_end/flambda/basic/simple.cmi \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ middle_end/flambda/naming/name_permutation.cmi \ middle_end/flambda/naming/name_mode.cmi \ middle_end/flambda/basic/kinded_parameter.cmi \ @@ -5267,6 +5262,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 : \ @@ -5275,7 +5271,6 @@ middle_end/flambda/inlining/inlining_transforms.cmx : \ middle_end/flambda/basic/trap_action.cmx \ middle_end/flambda/simplify/simplify_import.cmx \ middle_end/flambda/basic/simple.cmx \ - middle_end/flambda/compilenv_deps/rec_info.cmx \ middle_end/flambda/naming/name_permutation.cmx \ middle_end/flambda/naming/name_mode.cmx \ middle_end/flambda/basic/kinded_parameter.cmx \ @@ -5286,6 +5281,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 : \ @@ -6123,7 +6119,6 @@ middle_end/flambda/simplify/simplify.cmo : \ middle_end/flambda/lifting/reification.cmi \ middle_end/flambda/basic/reg_width_const.cmi \ middle_end/flambda/basic/recursive.cmi \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ utils/profile.cmi \ middle_end/flambda/basic/or_variable.cmi \ middle_end/flambda/types/basic/or_bottom.cmi \ @@ -6161,6 +6156,7 @@ middle_end/flambda/simplify/simplify.cmo : \ middle_end/flambda/simplify/env/continuation_env_and_param_types.cmi \ middle_end/flambda/basic/continuation.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 \ @@ -6196,7 +6192,6 @@ middle_end/flambda/simplify/simplify.cmx : \ middle_end/flambda/lifting/reification.cmx \ middle_end/flambda/basic/reg_width_const.cmx \ middle_end/flambda/basic/recursive.cmx \ - middle_end/flambda/compilenv_deps/rec_info.cmx \ utils/profile.cmx \ middle_end/flambda/basic/or_variable.cmx \ middle_end/flambda/types/basic/or_bottom.cmx \ @@ -6234,6 +6229,7 @@ middle_end/flambda/simplify/simplify.cmx : \ middle_end/flambda/simplify/env/continuation_env_and_param_types.cmx \ middle_end/flambda/basic/continuation.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 \ @@ -6289,7 +6285,6 @@ middle_end/flambda/simplify/simplify_apply_expr.rec.cmo : \ middle_end/flambda/simplify/simplify_common.cmi \ middle_end/flambda/basic/simple.cmi \ middle_end/flambda/terms/set_of_closures.cmi \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ middle_end/flambda/types/basic/or_bottom.cmi \ middle_end/flambda/naming/name_mode.cmi \ utils/misc.cmi \ @@ -6306,6 +6301,7 @@ middle_end/flambda/simplify/simplify_apply_expr.rec.cmo : \ lambda/debuginfo.cmi \ middle_end/flambda/basic/continuation.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 \ @@ -6322,7 +6318,6 @@ middle_end/flambda/simplify/simplify_apply_expr.rec.cmx : \ middle_end/flambda/simplify/simplify_common.cmx \ middle_end/flambda/basic/simple.cmx \ middle_end/flambda/terms/set_of_closures.cmx \ - middle_end/flambda/compilenv_deps/rec_info.cmx \ middle_end/flambda/types/basic/or_bottom.cmx \ middle_end/flambda/naming/name_mode.cmx \ utils/misc.cmx \ @@ -6339,6 +6334,7 @@ middle_end/flambda/simplify/simplify_apply_expr.rec.cmx : \ lambda/debuginfo.cmx \ middle_end/flambda/basic/continuation.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 \ @@ -6716,7 +6712,6 @@ middle_end/flambda/simplify/simplify_set_of_closures.rec.cmo : \ middle_end/flambda/basic/simple.cmi \ middle_end/flambda/terms/set_of_closures.cmi \ middle_end/flambda/basic/scope.cmi \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ utils/profile.cmi \ middle_end/flambda/naming/name_occurrences.cmi \ middle_end/flambda/naming/name_mode.cmi \ @@ -6736,6 +6731,7 @@ middle_end/flambda/simplify/simplify_set_of_closures.rec.cmo : \ middle_end/flambda/simplify/env/downwards_acc.cmi \ middle_end/flambda/basic/continuation.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 \ @@ -6756,7 +6752,6 @@ middle_end/flambda/simplify/simplify_set_of_closures.rec.cmx : \ middle_end/flambda/basic/simple.cmx \ middle_end/flambda/terms/set_of_closures.cmx \ middle_end/flambda/basic/scope.cmx \ - middle_end/flambda/compilenv_deps/rec_info.cmx \ utils/profile.cmx \ middle_end/flambda/naming/name_occurrences.cmx \ middle_end/flambda/naming/name_mode.cmx \ @@ -6776,6 +6771,7 @@ middle_end/flambda/simplify/simplify_set_of_closures.rec.cmx : \ middle_end/flambda/simplify/env/downwards_acc.cmx \ middle_end/flambda/basic/continuation.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 \ @@ -8860,7 +8856,6 @@ middle_end/flambda/types/flambda_type.cmo : \ middle_end/flambda/basic/scope.cmi \ middle_end/flambda/types/structures/row_like_maps_to_intf.cmo \ middle_end/flambda/basic/reg_width_const.cmi \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ middle_end/flambda/types/structures/product_intf.cmo \ utils/printing_cache.cmi \ middle_end/flambda/types/basic/or_unknown_or_bottom.cmi \ @@ -8884,6 +8879,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 \ @@ -8913,7 +8909,6 @@ middle_end/flambda/types/flambda_type.cmx : \ middle_end/flambda/basic/scope.cmx \ middle_end/flambda/types/structures/row_like_maps_to_intf.cmx \ middle_end/flambda/basic/reg_width_const.cmx \ - middle_end/flambda/compilenv_deps/rec_info.cmx \ middle_end/flambda/types/structures/product_intf.cmx \ utils/printing_cache.cmx \ middle_end/flambda/types/basic/or_unknown_or_bottom.cmx \ @@ -8937,6 +8932,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 \ @@ -8958,7 +8954,6 @@ middle_end/flambda/types/flambda_type.cmi : \ middle_end/flambda/basic/simple.cmi \ middle_end/flambda/basic/scope.cmi \ middle_end/flambda/basic/reg_width_const.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 \ @@ -8976,10 +8971,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 \ @@ -9006,7 +9003,9 @@ middle_end/flambda/types/type_descr.rec.cmo : \ 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/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 \ @@ -9023,14 +9022,15 @@ middle_end/flambda/types/type_descr.rec.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/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 \ @@ -9038,10 +9038,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 \ @@ -9049,7 +9049,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 \ @@ -9104,7 +9105,6 @@ middle_end/flambda/types/type_grammar.rec.cmi : \ lambda/tag.cmi \ middle_end/flambda/basic/simple.cmi \ middle_end/flambda/basic/reg_width_const.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 \ @@ -9114,22 +9114,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 \ @@ -9288,28 +9289,32 @@ middle_end/flambda/types/basic/var_within_closure_set.cmi : \ utils/identifiable.cmi middle_end/flambda/types/env/aliases.cmo : \ middle_end/flambda/compilenv_deps/variable.cmi \ - middle_end/flambda/basic/simple.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 \ + utils/identifiable.cmi \ utils/clflags.cmi \ middle_end/flambda/types/env/binding_time.cmi \ middle_end/flambda/types/env/aliases.cmi middle_end/flambda/types/env/aliases.cmx : \ middle_end/flambda/compilenv_deps/variable.cmx \ - middle_end/flambda/basic/simple.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 \ + utils/identifiable.cmx \ utils/clflags.cmx \ middle_end/flambda/types/env/binding_time.cmx \ middle_end/flambda/types/env/aliases.cmi middle_end/flambda/types/env/aliases.cmi : \ - middle_end/flambda/basic/simple.cmi \ + middle_end/flambda/compilenv_deps/reg_width_things.cmi \ middle_end/flambda/naming/name_mode.cmi \ middle_end/flambda/basic/name.cmi \ + middle_end/flambda/cmx/ids_for_export.cmi \ + utils/identifiable.cmi \ middle_end/flambda/cmx/contains_ids.cmo \ middle_end/flambda/types/env/binding_time.cmi middle_end/flambda/types/env/binding_time.cmo : \ @@ -9347,7 +9352,6 @@ middle_end/flambda/types/env/typing_env.rec.cmo : \ middle_end/flambda/compilenv_deps/symbol.cmi \ middle_end/flambda/basic/simple.cmi \ middle_end/flambda/basic/scope.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 \ @@ -9359,6 +9363,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 \ @@ -9370,7 +9375,6 @@ middle_end/flambda/types/env/typing_env.rec.cmx : \ middle_end/flambda/compilenv_deps/symbol.cmx \ middle_end/flambda/basic/simple.cmx \ middle_end/flambda/basic/scope.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 \ @@ -9382,6 +9386,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 \ @@ -9402,9 +9407,11 @@ middle_end/flambda/types/env/typing_env.rec.cmi : \ middle_end/flambda/types/kinds/flambda_kind.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/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/types/basic/or_bottom.cmi \ @@ -9556,7 +9563,6 @@ middle_end/flambda/types/structures/code_age_relation.cmi : \ middle_end/flambda/compilenv_deps/compilation_unit.cmi \ middle_end/flambda/basic/code_id.cmi middle_end/flambda/types/structures/function_declaration_type.rec.cmo : \ - middle_end/flambda/compilenv_deps/rec_info.cmi \ middle_end/flambda/types/basic/or_unknown_or_bottom.cmi \ middle_end/flambda/types/basic/or_bottom.cmi \ middle_end/flambda/naming/name_permutation.cmi \ @@ -9564,11 +9570,11 @@ middle_end/flambda/types/structures/function_declaration_type.rec.cmo : \ middle_end/flambda/naming/name_mode.cmi \ middle_end/flambda/cmx/ids_for_export.cmi \ lambda/debuginfo.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/types/structures/function_declaration_type.rec.cmi middle_end/flambda/types/structures/function_declaration_type.rec.cmx : \ - middle_end/flambda/compilenv_deps/rec_info.cmx \ middle_end/flambda/types/basic/or_unknown_or_bottom.cmx \ middle_end/flambda/types/basic/or_bottom.cmx \ middle_end/flambda/naming/name_permutation.cmx \ @@ -9576,15 +9582,16 @@ middle_end/flambda/types/structures/function_declaration_type.rec.cmx : \ middle_end/flambda/naming/name_mode.cmx \ middle_end/flambda/cmx/ids_for_export.cmx \ lambda/debuginfo.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/types/structures/function_declaration_type.rec.cmi middle_end/flambda/types/structures/function_declaration_type.rec.cmi : \ middle_end/flambda/types/structures/type_structure_intf.cmo \ - middle_end/flambda/compilenv_deps/rec_info.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 \ @@ -9720,20 +9727,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 \ @@ -9741,98 +9748,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 \ diff --git a/compilerlibs/Makefile.compilerlibs b/compilerlibs/Makefile.compilerlibs index a241627d6601..b9d16b43d2e9 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/simple.ml b/middle_end/flambda/basic/simple.ml index 3f7634411f4e..17336efcd575 100644 --- a/middle_end/flambda/basic/simple.ml +++ b/middle_end/flambda/basic/simple.ml @@ -53,25 +53,25 @@ 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 = +let compose_coercion t ~newer_coercion = if is_const t then None else - match newer_rec_info with + match newer_coercion 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 + | Some newer_coercion -> + let coercion = + match coercion t with + | None -> newer_coercion + | Some older_coercion -> + Coercion.compose older_coercion ~newer:newer_coercion in - Some (with_rec_info (without_rec_info t) rec_info) + Some (with_coercion (without_coercion t) 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 Coercion doesn't get dropped using the following *) let [@inline always] must_be_var t = @@ -86,7 +86,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 @@ -118,9 +118,9 @@ let apply_name_permutation t perm = let new_name = Name_permutation.apply_name perm old_name in if old_name == new_name then t else - match rec_info t with + match coercion t with | None -> name new_name - | Some rec_info -> with_rec_info (name new_name) rec_info + | Some coercion -> with_coercion (name new_name) coercion in pattern_match t ~const:(fun _ -> t) ~name diff --git a/middle_end/flambda/basic/simple.mli b/middle_end/flambda/basic/simple.mli index 0cd720c1ed16..64ef9a129f66 100644 --- a/middle_end/flambda/basic/simple.mli +++ b/middle_end/flambda/basic/simple.mli @@ -23,9 +23,9 @@ include module type of struct include Reg_width_things.Simple end include Contains_names.S with type t := t -val merge_rec_info : t -> newer_rec_info:Rec_info.t option -> t option +val compose_coercion : t -> newer_coercion:Coercion.t option -> t option -val without_rec_info : t -> t +val without_coercion : t -> t val must_be_var : t -> Variable.t option @@ -64,7 +64,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 option * Name.t) option (* CR mshinwell: remove these next two? *) val map_var : t -> f:(Variable.t -> Variable.t) -> t diff --git a/middle_end/flambda/cmx/ids_for_export.ml b/middle_end/flambda/cmx/ids_for_export.ml index 8d186d09b143..91fbf3a72d6f 100644 --- a/middle_end/flambda/cmx/ids_for_export.ml +++ b/middle_end/flambda/cmx/ids_for_export.ml @@ -74,7 +74,7 @@ let add_name t name = let add_simple t simple = let simples = - match Simple.rec_info simple with + match Simple.coercion simple with | None -> t.simples | Some _ -> Simple.Set.add simple t.simples in @@ -91,7 +91,7 @@ let add_continuation t continuation = let from_simple simple = let simples = - match Simple.rec_info simple with + match Simple.coercion simple with | None -> (* This simple will not be in the grand_table_of_simples *) Simple.Set.empty @@ -199,12 +199,12 @@ module Import_map = struct match Simple.Map.find simple t.simples with | simple -> simple | exception Not_found -> - begin match Simple.rec_info simple with + begin match Simple.coercion simple with | None -> Simple.pattern_match simple ~name:(fun n -> Simple.name (name t n)) ~const:(fun c -> Simple.const (const t c)) - | Some _rec_info -> simple + | Some _coercion -> simple end let closure_var_is_used t var = diff --git a/middle_end/flambda/compilenv_deps/coercion.ml b/middle_end/flambda/compilenv_deps/coercion.ml new file mode 100644 index 000000000000..4a675a4f4285 --- /dev/null +++ b/middle_end/flambda/compilenv_deps/coercion.ml @@ -0,0 +1,26 @@ +(**************************************************************************) +(* *) +(* 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 = unit + +let id = () +let is_id () = true +let inverse () = () +let compose () ~newer:() = () +let print ppf () = Format.fprintf ppf "id" +let equal () () = true +let hash () = 0 + +let unroll_to () = None +let depth () = 1 diff --git a/middle_end/flambda/compilenv_deps/coercion.mli b/middle_end/flambda/compilenv_deps/coercion.mli new file mode 100644 index 000000000000..0dfc1118f294 --- /dev/null +++ b/middle_end/flambda/compilenv_deps/coercion.mli @@ -0,0 +1,28 @@ +(**************************************************************************) +(* *) +(* 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 + +val id : t +val is_id : t -> bool +val inverse : t -> t +val compose : t -> newer:t -> t +val print : Format.formatter -> t -> unit +val equal : t -> t -> bool +val hash : t -> int + +val unroll_to : t -> int option +val depth : t -> int diff --git a/middle_end/flambda/compilenv_deps/flambda_colours.ml b/middle_end/flambda/compilenv_deps/flambda_colours.ml index 15587bb53aae..74bd8464143a 100644 --- a/middle_end/flambda/compilenv_deps/flambda_colours.ml +++ b/middle_end/flambda/compilenv_deps/flambda_colours.ml @@ -55,7 +55,7 @@ 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 coercion () = C.fg_256 243 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..b2e661c94fa9 100644 --- a/middle_end/flambda/compilenv_deps/flambda_colours.mli +++ b/middle_end/flambda/compilenv_deps/flambda_colours.mli @@ -53,7 +53,7 @@ val continuation_annotation : unit -> string val name_abstraction : unit -> string -val rec_info : unit -> string +val coercion : unit -> string val elide : unit -> string diff --git a/middle_end/flambda/compilenv_deps/rec_info.ml b/middle_end/flambda/compilenv_deps/rec_info.ml index 0bf79e7561ae..3708080647f1 100644 --- a/middle_end/flambda/compilenv_deps/rec_info.ml +++ b/middle_end/flambda/compilenv_deps/rec_info.ml @@ -13,7 +13,7 @@ (**************************************************************************) [@@@ocaml.warning "+a-4-30-40-41-42"] - +(* type t = { depth : int; unroll_to : int option; @@ -64,3 +64,4 @@ let merge { depth = depth1; unroll_to = older_unroll_to; } ~newer = let initial = create ~depth:0 ~unroll_to:None let is_initial t = equal t initial +*) diff --git a/middle_end/flambda/compilenv_deps/rec_info.mli b/middle_end/flambda/compilenv_deps/rec_info.mli index cb2c759b28e2..fe43ec929616 100644 --- a/middle_end/flambda/compilenv_deps/rec_info.mli +++ b/middle_end/flambda/compilenv_deps/rec_info.mli @@ -13,7 +13,7 @@ (**************************************************************************) [@@@ocaml.warning "+a-4-30-40-41-42"] - +(* type t include Identifiable.S with type t := t @@ -29,3 +29,4 @@ val merge : t -> newer:t -> t val initial : 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 613b03aacd3c..41083a48d8e5 100644 --- a/middle_end/flambda/compilenv_deps/reg_width_things.ml +++ b/middle_end/flambda/compilenv_deps/reg_width_things.ml @@ -221,28 +221,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 @@ -547,9 +547,9 @@ 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) + if flags = simple_flags then Some ((find_data t).coercion) else None module T0 = struct @@ -563,15 +563,15 @@ module Simple = struct ~name:(fun name -> Name.print ppf name) ~const:(fun cst -> Const.print ppf cst) in - match rec_info t with + match coercion t with | None -> print ppf t - | Some rec_info -> + | Some coercion -> Format.fprintf ppf "@[\ @[(simple@ %a)@] \ - @[(rec_info@ %a)@]\ + @[(coercion@ %a)@]\ @]" print t - Rec_info.print rec_info + Coercion.print coercion let output chan t = print (Format.formatter_of_out_channel chan) t @@ -583,16 +583,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 + match coercion t with | None -> - let data : Simple_data.t = { simple = t; rec_info = new_rec_info; } in + 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]" + Misc.fatal_errorf "Cannot add [Coercion] to [Simple] %a that already \ + has [Coercion]" print t module Set = Patricia_tree.Make_set (struct let print = print end) @@ -604,7 +604,7 @@ module Simple = struct let import map (data : exported) = let simple = map data.simple in let data : Simple_data.t = - { simple; rec_info = data.rec_info; } + { simple; coercion = data.coercion; } in Table.add !grand_table_of_simples data diff --git a/middle_end/flambda/compilenv_deps/reg_width_things.mli b/middle_end/flambda/compilenv_deps/reg_width_things.mli index 8e32a3a53ade..e1d0eed0300d 100644 --- a/middle_end/flambda/compilenv_deps/reg_width_things.mli +++ b/middle_end/flambda/compilenv_deps/reg_width_things.mli @@ -154,9 +154,9 @@ module Simple : sig val const : Const.t -> t - val rec_info : t -> Rec_info.t option + val coercion : t -> Coercion.t option - val with_rec_info : t -> Rec_info.t -> t + val with_coercion : t -> Coercion.t -> t val pattern_match : t @@ -165,7 +165,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 5f9c1b375cea..c51005b5c117 100644 --- a/middle_end/flambda/inlining/inlining_decision.ml +++ b/middle_end/flambda/inlining/inlining_decision.ml @@ -218,7 +218,7 @@ end (* CR mshinwell: This parameter needs to be configurable *) let max_rec_depth = 1 -let make_decision_for_call_site denv ~function_decl_rec_info +let make_decision_for_call_site denv ~function_decl_coercion ~apply_inlining_state (inline : Inline_attribute.t) : Call_site_decision.t = if (not (DE.can_inline denv)) then @@ -227,9 +227,9 @@ let make_decision_for_call_site denv ~function_decl_rec_info 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 + match Coercion.unroll_to function_decl_coercion with | Some unroll_to -> - if Rec_info.depth function_decl_rec_info >= unroll_to then + if Coercion.depth function_decl_coercion >= unroll_to then Unrolling_depth_exceeded else Inline { attribute = None; unroll_to = None; } @@ -241,13 +241,13 @@ let make_decision_for_call_site denv ~function_decl_rec_info match inline with | Never_inline -> assert false | Default_inline -> - if Rec_info.depth function_decl_rec_info >= max_rec_depth then + if Coercion.depth function_decl_coercion >= max_rec_depth then Recursion_depth_exceeded else Inline { attribute = None; unroll_to = None; } | Unroll unroll_to -> let unroll_to = - Rec_info.depth function_decl_rec_info + unroll_to + Coercion.depth function_decl_coercion + unroll_to in Inline { attribute = Some Unroll; unroll_to = Some unroll_to; } | Always_inline | Hint_inline -> diff --git a/middle_end/flambda/inlining/inlining_decision.mli b/middle_end/flambda/inlining/inlining_decision.mli index 3ea6f4106e79..2e7f438e168e 100644 --- a/middle_end/flambda/inlining/inlining_decision.mli +++ b/middle_end/flambda/inlining/inlining_decision.mli @@ -67,7 +67,7 @@ end val make_decision_for_call_site : Downwards_env.t - -> function_decl_rec_info:Rec_info.t + -> function_decl_coercion:Coercion.t -> apply_inlining_state:Inlining_state.t -> Inline_attribute.t -> Call_site_decision.t diff --git a/middle_end/flambda/inlining/inlining_transforms.ml b/middle_end/flambda/inlining/inlining_transforms.ml index b4687ce02899..62aa30f56740 100644 --- a/middle_end/flambda/inlining/inlining_transforms.ml +++ b/middle_end/flambda/inlining/inlining_transforms.ml @@ -40,8 +40,9 @@ 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.compose_coercion callee + ~newer_coercion:(ignore unroll_to; Some Coercion.id) |> Option.get (* CR mshinwell: improve *) in Expr.apply_name_permutation diff --git a/middle_end/flambda/simplify/common_subexpression_elimination.ml b/middle_end/flambda/simplify/common_subexpression_elimination.ml index 021180c5a606..50bdf87a860b 100644 --- a/middle_end/flambda/simplify/common_subexpression_elimination.ml +++ b/middle_end/flambda/simplify/common_subexpression_elimination.ml @@ -187,10 +187,10 @@ let cse_with_eligible_lhs ~typing_env_at_fork ~cse_at_each_use ~params prev_cse let aliases = TE.aliases_of_simple env_at_use ~min_name_mode:NM.normal bound_to - |> Simple.Set.filter (fun simple -> + |> Simple.Map.filter (fun simple _coercion -> not (Simple.Set.mem simple params)) in - Simple.Set.get_singleton aliases + Simple.Map.get_singleton aliases |> Option.map fst in match bound_to with | None -> eligible diff --git a/middle_end/flambda/simplify/simplify_apply_expr.rec.ml b/middle_end/flambda/simplify/simplify_apply_expr.rec.ml index 716bbd025ac1..a4e7eaf3ea93 100644 --- a/middle_end/flambda/simplify/simplify_apply_expr.rec.ml +++ b/middle_end/flambda/simplify/simplify_apply_expr.rec.ml @@ -101,11 +101,11 @@ let simplify_direct_full_application dacc apply function_decl_opt "[@inlined] attribute was not used on this function application \ (the optimizer decided not to inline the function given its definition)"; None - | Some (function_decl, function_decl_rec_info) -> + | Some (function_decl, function_decl_coercion) -> let apply_inlining_state = Apply.inlining_state apply in let decision = Inlining_decision.make_decision_for_call_site (DA.denv dacc) - ~function_decl_rec_info + ~function_decl_coercion ~apply_inlining_state (Apply.inline apply) in @@ -587,13 +587,13 @@ let simplify_function_call 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 + (* CR mshinwell: This should go in Typing_env (ditto logic for Coercion 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 + let function_decl_coercion = + let coercion = I.coercion inlinable in + match Simple.coercion (Apply.callee apply) with + | None -> coercion + | Some newer -> Coercion.compose coercion ~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 @@ -603,7 +603,7 @@ let simplify_function_call 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, function_decl_coercion)) ~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.rec.ml b/middle_end/flambda/simplify/simplify_set_of_closures.rec.ml index dd9d29cb46e6..bf122fbb4f3e 100644 --- a/middle_end/flambda/simplify/simplify_set_of_closures.rec.ml +++ b/middle_end/flambda/simplify/simplify_set_of_closures.rec.ml @@ -26,7 +26,7 @@ open! Simplify_import file tail recursive, although it probably isn't necessary, as excessive levels of nesting of functions seems unlikely. *) -let function_decl_type ~pass denv function_decl ?code_id ?params_and_body rec_info = +let function_decl_type ~pass denv function_decl ?code_id ?params_and_body coercion = let decision = Inlining_decision.make_decision_for_function_declaration denv ?params_and_body function_decl @@ -40,7 +40,7 @@ let function_decl_type ~pass denv function_decl ?code_id ?params_and_body rec_in ~code_id ~dbg:(FD.dbg function_decl) ~is_tupled:(FD.is_tupled function_decl) - ~rec_info + ~coercion else T.create_non_inlinable_function_declaration ~code_id @@ -144,7 +144,7 @@ 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. *) + (* CR mshinwell: [coercion] may be wrong. *) Closure_id.Map.map (fun function_decl -> let new_code_id = Code_id.Map.find (FD.code_id function_decl) @@ -154,7 +154,7 @@ end = struct ~pass:Inlining_report.Before_simplify denv function_decl ~code_id:new_code_id - (Rec_info.create ~depth:1 ~unroll_to:None)) + Coercion.id) (Function_declarations.funs function_decls) in Closure_id.Map.mapi (fun closure_id _function_decl -> @@ -466,7 +466,7 @@ let simplify_function context ~used_closure_vars ~shareable_constants function_decl_type ~pass:Inlining_report.After_simplify (DA.denv dacc_after_body) function_decl - ~params_and_body Rec_info.initial + ~params_and_body Coercion.id in { function_decl; new_code_id; diff --git a/middle_end/flambda/simplify/simplify_simple.ml b/middle_end/flambda/simplify/simplify_simple.ml index 4196bca8168a..308cceb13829 100644 --- a/middle_end/flambda/simplify/simplify_simple.ml +++ b/middle_end/flambda/simplify/simplify_simple.ml @@ -25,19 +25,19 @@ module TE = T.Typing_env (* CR mshinwell: avoid having two functions *) let type_for_simple simple kind : _ Or_bottom.t = let ty = T.alias_type_of kind simple in - match Simple.rec_info simple with + match Simple.coercion simple with | None -> Ok (simple, ty) - | Some rec_info -> - match T.apply_rec_info ty rec_info with + | Some coercion -> + match T.apply_coercion ty coercion with | Bottom -> Bottom | Ok ty -> Ok (simple, ty) let type_for_simple' simple kind : _ Or_bottom.t * _ = let ty = T.alias_type_of kind simple in - match Simple.rec_info simple with + match Simple.coercion simple with | None -> Ok simple, ty - | Some rec_info -> - match T.apply_rec_info ty rec_info with + | Some coercion -> + match T.apply_coercion ty coercion with | Bottom -> Bottom, T.bottom (T.kind ty) | Ok ty -> Ok simple, ty 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 08dfc0bc36b3..6bb85d959227 100644 --- a/middle_end/flambda/types/env/aliases.ml +++ b/middle_end/flambda/types/env/aliases.ml @@ -14,78 +14,181 @@ [@@@ocaml.warning "+a-4-30-40-41-42"] -module Aliases_of_canonical_element : sig - type t +type 'a coercion_to_canonical = { + coercion_to_canonical : 'a; +} [@@ocaml.unboxed] +module type Coercion = sig + type t + val equal : t -> t -> bool + val inverse : t -> t + val id : t + val is_id : t -> bool + val compose : t -> newer:t -> t val print : Format.formatter -> t -> unit +end - val invariant : t -> unit +module type Element = sig + type t + val name : Name.t -> t + val is_var : t -> bool + val without_coercion : t -> t + val pattern_match + : t + -> name:(Reg_width_things.Name.t -> 'a) + -> const:(Reg_width_things.Const.t -> 'a) + -> 'a + include Identifiable.S with type t := t +end +module type Export = sig + type e + type t + val add : t -> e -> t val empty : t - val is_empty : t -> bool + val to_ids_for_export : t -> Ids_for_export.t + module Import_map : sig + type t + val of_import_map : Ids_for_export.Import_map.t -> t + val simple : t -> e -> e + end +end - val add : t -> Simple.t -> Name_mode.t -> t +module Make (C : Coercion) (E : Element) (Exp : Export with type e = E.t) = struct + + type nonrec coercion_to_canonical = C.t coercion_to_canonical + + let print_coercion_to_canonical ppf { coercion_to_canonical; } = + C.print ppf coercion_to_canonical + + let equal_coercion_to_canonical c1 c2 = + C.equal c1.coercion_to_canonical c2.coercion_to_canonical + + type map_to_canonical = coercion_to_canonical E.Map.t + + 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 + E.print elt + C.print coercion1 + C.print coercion2 + + let map_inter map1 map2 = + E.Map.merge (fun elt coercion1 coercion2 -> + match coercion1, coercion2 with + | None, None | Some _, None | None, Some _ -> None + | Some { coercion_to_canonical = coercion1; }, Some { coercion_to_canonical = coercion2; } -> + if C.equal coercion1 coercion2 then + Some { coercion_to_canonical = coercion1; } + else + fatal_inconsistent ~func_name:"Aliases.map_inter" elt coercion1 coercion2) + map1 + map2 + + let map_union map1 map2 = + E.Map.union (fun elt coercion1 coercion2 -> + match coercion1, coercion2 with + | { coercion_to_canonical = coercion1; }, { coercion_to_canonical = coercion2; } -> + if C.equal coercion1 coercion2 then + Some { coercion_to_canonical = coercion1; } + else + fatal_inconsistent ~func_name:"Aliases.map_union" elt coercion1 coercion2) + map1 + map2 - val find_earliest_candidates - : t - -> min_name_mode:Name_mode.t - -> Simple.Set.t option + module Aliases_of_canonical_element : sig + type t - val all : t -> Simple.Set.t + val print : Format.formatter -> t -> unit - val mem : t -> Simple.t -> bool + val invariant : t -> unit - val union : t -> t -> t - val inter : t -> t -> t + val empty : t + val is_empty : t -> bool - val import : (Simple.t -> Simple.t) -> t -> t + val add : t -> E.t -> coercion_to_canonical:C.t -> Name_mode.t -> t - val merge : t -> t -> t + val find_earliest_candidates + : t + -> min_name_mode:Name_mode.t + -> map_to_canonical option - val move_variables_to_mode_in_types : t -> t -end = struct - type t = { - aliases : Simple.Set.t Name_mode.Map.t; - all : Simple.Set.t; - } + val all : t -> map_to_canonical - let invariant _t = () + val mem : t -> E.t -> bool - let print ppf { aliases; all = _; } = - Name_mode.Map.print Simple.Set.print ppf aliases + val union : t -> t -> t + val inter : t -> t -> t - let empty = { - aliases = Name_mode.Map.empty; - all = Simple.Set.empty; - } + val import : (E.t -> E.t) -> t -> t - let is_empty t = Simple.Set.is_empty t.all + val merge : t -> t -> t - let add t elt name_mode = - if Simple.Set.mem elt t.all then begin - Misc.fatal_errorf "%a already added to [Aliases_of_canonical_element]: \ - %a" - Simple.print elt - print t - end; - let aliases = - Name_mode.Map.update name_mode - (function - | None -> Some (Simple.Set.singleton elt) - | Some elts -> - if !Clflags.flambda_invariant_checks then begin - assert (not (Simple.Set.mem elt elts)) - end; - Some (Simple.Set.add elt elts)) - t.aliases - in - let all = Simple.Set.add elt t.all in - { aliases; - all; + val move_variables_to_mode_in_types : t -> t + + val compose : t -> newer:C.t -> t + end = struct + type t = { + aliases : map_to_canonical Name_mode.Map.t; + all : map_to_canonical; } - let find_earliest_candidates t ~min_name_mode = - Name_mode.Map.fold (fun order aliases res_opt -> + 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 -> + E.Map.union (fun elt _coercion1 _coercion2 -> + Misc.fatal_errorf "[Aliases_of_canonical_element.invariant]: \ + element %a appears in several modes" + E.print elt) + map + acc) + aliases + E.Map.empty + in + (* [all] is the union of all elements in [aliases] *) + if E.Map.equal equal_coercion_to_canonical 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 (E.Map.print print_coercion_to_canonical) ppf aliases + + let empty = { + aliases = Name_mode.Map.empty; + all = E.Map.empty; + } + + let is_empty t = E.Map.is_empty t.all + + let add t elt ~coercion_to_canonical name_mode = + if E.Map.mem elt t.all then begin + Misc.fatal_errorf "%a already added to [Aliases_of_canonical_element]: \ + %a" + E.print elt + print t + end; + let aliases = + Name_mode.Map.update name_mode + (function + | None -> Some (E.Map.singleton elt { coercion_to_canonical; }) + | Some elts -> + if !Clflags.flambda_invariant_checks then begin + assert (not (E.Map.mem elt elts)) + end; + Some (E.Map.add elt { coercion_to_canonical; } elts)) + t.aliases + in + let all = E.Map.add elt { coercion_to_canonical; } t.all in + { aliases; + all; + } + + let find_earliest_candidates t ~min_name_mode = + Name_mode.Map.fold (fun order aliases res_opt -> match res_opt with | Some _ -> res_opt | None -> @@ -100,150 +203,202 @@ end = struct t.aliases None - let mem t elt = - Simple.Set.mem elt t.all - - let all t = t.all - - let union t1 t2 = - let aliases = - Name_mode.Map.union (fun _order elts1 elts2 -> - Some (Simple.Set.union elts1 elts2)) - t1.aliases t2.aliases - in - let t = - { aliases; - all = Simple.Set.union t1.all t2.all; - } - in - invariant t; - t - - let inter t1 t2 = - let aliases = - Name_mode.Map.merge (fun _order elts1 elts2 -> + let mem t elt = + E.Map.mem elt t.all + + let all t = t.all + + let union t1 t2 = + let aliases : map_to_canonical Name_mode.Map.t= + Name_mode.Map.union (fun _order elts1 elts2 -> + Some (map_union elts1 elts2)) + t1.aliases t2.aliases + in + let t = + { aliases; + all = map_union t1.all t2.all; + } + in + 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)) - t1.aliases t2.aliases - in - let t = - { aliases; - all = Simple.Set.inter t1.all t2.all; - } - in - invariant t; - t - - let import import_simple { aliases; all } = - let aliases = - Name_mode.Map.map (fun elts -> Simple.Set.map import_simple elts) - aliases - in - let all = Simple.Set.map import_simple all in - { aliases; all } - - let merge t1 t2 = - let aliases = - Name_mode.Map.union (fun _mode set1 set2 -> - Some (Simple.Set.union set1 set2)) - t1.aliases - t2.aliases - in - let all = Simple.Set.union t1.all t2.all in - { aliases; all; } - - let move_variables_to_mode_in_types { aliases; all; } = - let (no_vars_aliases, all_variables) = - Name_mode.Map.fold (fun mode aliases (no_vars_aliases, all_variables) -> - let (vars, non_vars) = Simple.Set.partition Simple.is_var aliases in - let no_vars_aliases = - if Simple.Set.is_empty non_vars then no_vars_aliases - else Name_mode.Map.add mode non_vars no_vars_aliases - in - no_vars_aliases, Simple.Set.union vars all_variables) - aliases - (Name_mode.Map.empty, Simple.Set.empty) - in - let aliases = - if Name_mode.Map.mem Name_mode.in_types no_vars_aliases - then Misc.fatal_errorf "move_variables_to_mode_in_types: \ - The following non-vars have mode In_types:@ %a" - Simple.Set.print - (Name_mode.Map.find Name_mode.in_types no_vars_aliases) - else - if Simple.Set.is_empty all_variables then no_vars_aliases - else Name_mode.Map.add Name_mode.in_types all_variables no_vars_aliases - in - { aliases; all; } -end + | Some elts1, Some elts2 -> + Some (map_inter elts1 elts2)) + t1.aliases t2.aliases + in + let t = + { aliases; + all = map_inter t1.all t2.all; + } + in + invariant t; + t + + let import import_simple { aliases; all } = + let map_simple elts = + E.Map.fold (fun elt coercion acc -> + E.Map.add (import_simple elt) coercion acc) + elts + E.Map.empty + in + let aliases = Name_mode.Map.map map_simple aliases in + let all = map_simple 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 map1 map2 -> + Some (map_union map1 map2) + ) + t1.aliases + t2.aliases + 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; } ~newer = + let f m = + E.Map.map + (fun { coercion_to_canonical; } -> + { coercion_to_canonical = C.compose coercion_to_canonical ~newer; }) + m + in + let aliases = Name_mode.Map.map f aliases in + let all = f all in + { aliases; all; } + + let move_variables_to_mode_in_types { aliases; all; } = + let (no_vars_aliases, all_variables) = + Name_mode.Map.fold (fun mode aliases (no_vars_aliases, all_variables) -> + let key_is_var key _ = E.is_var key in + let (vars, non_vars) = E.Map.partition key_is_var aliases in + let no_vars_aliases = + if E.Map.is_empty non_vars then no_vars_aliases + else Name_mode.Map.add mode non_vars no_vars_aliases + in + no_vars_aliases, map_union vars all_variables) + aliases + (Name_mode.Map.empty, E.Map.empty) + in + let aliases = + if Name_mode.Map.mem Name_mode.in_types no_vars_aliases + then Misc.fatal_errorf "move_variables_to_mode_in_types: \ + The following non-vars have mode In_types:@ %a" + (E.Map.print print_coercion_to_canonical) + (Name_mode.Map.find Name_mode.in_types no_vars_aliases) + else + if E.Map.is_empty all_variables then no_vars_aliases + else Name_mode.Map.add Name_mode.in_types all_variables no_vars_aliases + in + { aliases; all; } + end type t = { - canonical_elements : Simple.t Simple.Map.t; + canonical_elements : (E.t * coercion_to_canonical) E.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; + aliases_of_canonical_elements : Aliases_of_canonical_element.t E.Map.t; (* For [elt |-> aliases] in [aliases_of_canonical_elements], then [aliases] never includes [elt]. *) (* CR mshinwell: check this always holds *) - binding_times_and_modes : Binding_time.With_name_mode.t Simple.Map.t; + binding_times_and_modes : Binding_time.With_name_mode.t E.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. *) } +(* 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_elements; binding_times_and_modes; } = + let print_element_and_coercion ppf (elt, coercion) = + Format.fprintf ppf "%a (%a)" + E.print elt + print_coercion_to_canonical coercion + 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) + @[(canonical_elements@ %a)@]@ \ + @[(aliases_of_canonical_elements@ %a)@]@ \ + @[(binding_times_and_modes@ %a)@]\ + )@]" + (E.Map.print print_element_and_coercion) canonical_elements + (E.Map.print Aliases_of_canonical_element.print) aliases_of_canonical_elements - (Simple.Map.print Binding_time.With_name_mode.print) + (E.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 info1 = E.Map.find alias t.binding_times_and_modes in + let info2 = E.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 name_mode t elt = Binding_time.With_name_mode.name_mode - (Simple.Map.find elt t.binding_times_and_modes) + (E.Map.find elt t.binding_times_and_modes) 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 : map_to_canonical = + E.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 -> + if not (E.Map.for_all (fun elt _coercion -> 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 + E.print canonical_element print t end; - if Simple.Set.mem canonical_element aliases then begin + if E.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 + E.print canonical_element + (E.Map.print print_coercion_to_canonical) aliases end; - if not (Simple.Set.is_empty (Simple.Set.inter aliases all_aliases)) then + if not (E.Map.is_empty (map_inter aliases all_aliases)) then begin Misc.fatal_errorf "Overlapping alias sets:@ %a" print t end; - Simple.Set.union aliases all_aliases) + map_union aliases all_aliases) t.aliases_of_canonical_elements - Simple.Set.empty + E.Map.empty in () end @@ -251,33 +406,81 @@ 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 = E.Map.empty; + aliases_of_canonical_elements = E.Map.empty; + binding_times_and_modes = E.Map.empty; } type canonical = - | Is_canonical of Simple.t - | Alias_of_canonical of { element : Simple.t; canonical_element : Simple.t; } + | Is_canonical of E.t + | Alias_of_canonical of { + element : E.t; + canonical_element : E.t; + coercion_to_canonical : coercion_to_canonical; + } let canonical t element : canonical = - match Simple.Map.find element t.canonical_elements with + match E.Map.find element t.canonical_elements with | exception Not_found -> Is_canonical element - | canonical_element -> + | canonical_element, coercion_to_canonical -> if !Clflags.flambda_invariant_checks then begin - assert (not (Simple.equal element canonical_element)) + assert (not (E.equal element canonical_element)) end; - Alias_of_canonical { element; canonical_element; } + Alias_of_canonical { element; 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 + match E.Map.find canonical_element t.aliases_of_canonical_elements 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 E.equal canonical_element to_be_demoted then begin + if C.is_id coercion_to_canonical then begin + t + end else + Misc.fatal_errorf "Cannot add an alias to itself with a non-identity coercion" + end else let aliases_of_to_be_demoted = get_aliases_of_canonical_element t ~canonical_element:to_be_demoted in @@ -287,10 +490,13 @@ let add_alias_between_canonical_elements t ~canonical_element ~to_be_demoted = end; let canonical_elements = t.canonical_elements - |> Simple.Set.fold (fun alias canonical_elements -> - Simple.Map.add alias canonical_element canonical_elements) + |> E.Map.fold (fun alias { coercion_to_canonical = coercion_to_to_be_demoted; } canonical_elements -> + let coercion_to_canonical = + C.compose coercion_to_to_be_demoted ~newer:coercion_to_canonical + in + E.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 + |> E.Map.add to_be_demoted (canonical_element, { coercion_to_canonical; }) in let aliases_of_canonical_element = get_aliases_of_canonical_element t ~canonical_element @@ -304,23 +510,29 @@ let add_alias_between_canonical_elements t ~canonical_element ~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 t to_be_demoted) + (Aliases_of_canonical_element.union + (Aliases_of_canonical_element.compose aliases_of_to_be_demoted ~newer:coercion_to_canonical) + aliases_of_canonical_element) + to_be_demoted + ~coercion_to_canonical + (name_mode 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 + |> E.Map.remove to_be_demoted + |> E.Map.add (* replace *) canonical_element aliases in + let res = { canonical_elements; aliases_of_canonical_elements; 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; + canonical_element : E.t; + to_be_demoted : E.t; } let choose_canonical_element_to_be_demoted t ~canonical_element1 @@ -338,106 +550,189 @@ let choose_canonical_element_to_be_demoted t ~canonical_element1 (* CR mshinwell: add submodule *) type add_result = { t : t; - canonical_element : Simple.t; - alias_of : Simple.t; + canonical_element : E.t; + alias_of : E.t; + coerce_alias_of_to_canonical_element : C.t; } -let invariant_add_result ~original_t { canonical_element; alias_of; t; } = +let invariant_add_result ~original_t { canonical_element; alias_of; t; coerce_alias_of_to_canonical_element = _; } = if !Clflags.flambda_invariant_checks then begin invariant t; - if not (Simple.equal canonical_element alias_of) then begin + if not (E.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@ \ - Resulting alias tracker:@ %a" - Simple.print canonical_element - Simple.print alias_of + than %a after alias addition.@ Original alias tracker:@ %a@ \ + Resulting alias tracker:@ %a" + E.print canonical_element + E.print alias_of print original_t print t end end end -let add_alias t element1 element2 = - 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 add_alias t ~element1 ~coerce_from_element2_to_element1 ~element2 = + let wrap ~canonical_element ~coercion_to_canonical ~to_be_demoted = let t = - add_alias_between_canonical_elements t ~canonical_element + add_alias_between_canonical_elements + t + ~canonical_element + ~coercion_to_canonical:{ coercion_to_canonical; } ~to_be_demoted in { t; canonical_element; (* CR mshinwell: [alias_of] is not a good name. *) alias_of = to_be_demoted; + coerce_alias_of_to_canonical_element = coercion_to_canonical; } - | 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; } -> + 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 alias_of = - if Simple.equal to_be_demoted canonical_element1 then element1 - else canonical_element2 + let coercion_to_canonical = + if E.equal to_be_demoted canonical_element1 then + (* canonical_element1=element1 <--[c]-- canonical_element2=element2 + ~> + canonical_element2 <--[inverse(c)]-- canonical_element1 *) + C.inverse coerce_from_element2_to_element1 + else + (* canonical_element1=element1 <--[c]-- canonical_element2=element2 + ~> + canonical_element1 <--[c]-- canonical_element2 *) + coerce_from_element2_to_element1 in + wrap ~canonical_element ~coercion_to_canonical ~to_be_demoted + | Alias_of_canonical { + element = _element1; + canonical_element = canonical_element1; + coercion_to_canonical = { coercion_to_canonical = coercion_from_element1_to_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 + let coercion_to_canonical = + if E.equal to_be_demoted canonical_element1 then + (* canonical_element1 <--[c1]-- element1 + + + element1 <--[c]-- canonical_element2=element2 + ~> + canonical_element2 <--[compose(inverse(c1),inverse(c))]-- canonical_element1 *) + C.compose + (C.inverse coercion_from_element1_to_canonical_element1) + ~newer:(C.inverse coerce_from_element2_to_element1) + else + (* canonical_element1 <--[c1]-- element1 + + + element1 <--[c]-- canonical_element2=element2 + ~> + canonical_element1 <--[compose(c, c1)]-- canonical_element2 *) + C.compose + coerce_from_element2_to_element1 + ~newer:coercion_from_element1_to_canonical_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; } - -> + wrap ~canonical_element ~coercion_to_canonical ~to_be_demoted + | Is_canonical canonical_element1, + Alias_of_canonical { + element = _element2; + canonical_element = canonical_element2; + coercion_to_canonical = { coercion_to_canonical = coercion_from_element2_to_canonical_element2; }; + } -> 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 element2 + let coercion_to_canonical = + if E.equal to_be_demoted canonical_element1 then + (* canonical_element1=element1 + canonical_element2 <--[c2]-- element2 + + + element1 <--[c]-- element2 + ~> + canonical_element2 <--[compose(inverse(c), c2)]-- canonical_element1 + *) + C.compose + (C.inverse coerce_from_element2_to_element1) + ~newer:coercion_from_element2_to_canonical_element2 + else + (* canonical_element1=element1 + canonical_element2 <--[c2]-- element2 + + + element1 <--[c]-- element2 + ~> + canonical_element1 <--[compose(inverse(c2), c)]-- canonical_element2 *) + C.compose + (C.inverse coercion_from_element2_to_canonical_element2) + ~newer:coerce_from_element2_to_element1 in - let t = - add_alias_between_canonical_elements t ~canonical_element - ~to_be_demoted + wrap ~canonical_element ~coercion_to_canonical ~to_be_demoted + | Alias_of_canonical { + element = _element1; + canonical_element = canonical_element1; + coercion_to_canonical = { coercion_to_canonical = coercion_from_element1_to_canonical_element1; }; + }, + Alias_of_canonical { + element = _element2; + canonical_element = canonical_element2; + coercion_to_canonical = { coercion_to_canonical = coercion_from_element2_to_canonical_element2; }; + } -> + let { canonical_element; to_be_demoted; } = + choose_canonical_element_to_be_demoted t ~canonical_element1 + ~canonical_element2 in - { t; - canonical_element; - alias_of; - } + let coercion_to_canonical = + if E.equal to_be_demoted canonical_element1 then + (* canonical_element1 <--[c1]-- element1 + canonical_element2 <--[c2]-- element2 + + + element1 <--[c]-- element2 + ~> + canonical_element2 <--[compose(inverse(c1), compose(inverse(c), c2))]--canonical_element1 *) + C.compose + (C.inverse coercion_from_element1_to_canonical_element1) + ~newer:(C.compose + (C.inverse coerce_from_element2_to_element1) + ~newer:coercion_from_element2_to_canonical_element2) + else + (* canonical_element1 <--[c1]-- element1 + canonical_element2 <--[c2]-- element2 + + + element1 <--[c]-- element2 + ~> + canonical_element1 <--[compose(inverse(c2), compose(c, c1))]--canonical_element2 *) + C.compose + (C.inverse coercion_from_element2_to_canonical_element2) + ~newer:(C.compose + coerce_from_element2_to_element1 + ~newer:coercion_from_element1_to_canonical_element1) + in + wrap ~canonical_element ~coercion_to_canonical ~to_be_demoted -let add t element1 binding_time_and_mode1 - element2 binding_time_and_mode2 = +let add t ~element1 ~binding_time_and_mode1 + ~coerce_from_element2_to_element1 + ~element2 ~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 + let element1 = E.without_coercion element1 in + let element2 = E.without_coercion element2 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 + E.Map.add element1 binding_time_and_mode1 + (E.Map.add 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 ~coerce_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 + E.Map.mem element t.binding_times_and_modes (* CR mshinwell: This needs documenting. For the moment we allow relations between canonical elements that are actually incomparable @@ -462,17 +757,17 @@ let mem t element = *) let get_canonical_element_exn t element elt_name_mode ~min_name_mode = - match Simple.Map.find element t.canonical_elements with + match E.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 + if c >= 0 then element, { coercion_to_canonical = C.id; } else raise Not_found end - | canonical_element -> + | canonical_element, coercion_to_canonical -> (* Format.eprintf "looking for canonical for %a, candidate canonical %a, min order %a\n%!" Simple.print element @@ -488,13 +783,13 @@ Format.eprintf "looking for canonical for %a, candidate canonical %a, min order | 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 -> + assert (not (E.Map.is_empty at_earliest_mode)); + E.Map.fold (fun elt coercion ((min_elt, _min_coercion) as min_binding) -> if defined_earlier t elt ~than:min_elt - then elt - else min_elt) + then elt, coercion + else min_binding) at_earliest_mode - (Simple.Set.min_elt at_earliest_mode) + (E.Map.min_binding at_earliest_mode) | None -> raise Not_found in match @@ -504,7 +799,7 @@ Format.eprintf "looking for canonical for %a, candidate canonical %a, min order with | None -> find_earliest () | Some c -> - if c >= 0 then canonical_element + if c >= 0 then canonical_element, coercion_to_canonical else find_earliest () let get_aliases t element = @@ -514,51 +809,53 @@ let get_aliases t element = 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; } -> + E.Map.add element { coercion_to_canonical = C.id; } aliases + | Alias_of_canonical { element = _; canonical_element; coercion_to_canonical; } -> if !Clflags.flambda_invariant_checks then begin - assert (not (Simple.equal element canonical_element)) + assert (not (E.equal element canonical_element)) end; let aliases = Aliases_of_canonical_element.all (get_aliases_of_canonical_element t ~canonical_element) in if !Clflags.flambda_invariant_checks then begin - assert (Simple.Set.mem element aliases) + assert (E.Map.mem element aliases) end; - Simple.Set.add canonical_element aliases + E.Map.add canonical_element coercion_to_canonical aliases let all_ids_for_export { canonical_elements = _; aliases_of_canonical_elements = _; binding_times_and_modes; } = - Simple.Map.fold (fun simple _binding_time_and_mode ids -> - Ids_for_export.add_simple ids simple) + E.Map.fold (fun elt _binding_time_and_mode ids -> + Exp.add ids elt) binding_times_and_modes - Ids_for_export.empty + Exp.empty + |> Exp.to_ids_for_export let import import_map { canonical_elements; aliases_of_canonical_elements; binding_times_and_modes; } = - let import_simple = Ids_for_export.Import_map.simple import_map in + let import_map = Exp.Import_map.of_import_map import_map in + let import_simple x = Exp.Import_map.simple import_map x in let canonical_elements = - Simple.Map.fold (fun elt canonical acc -> - Simple.Map.add (import_simple elt) (import_simple canonical) acc) + E.Map.fold (fun elt (canonical, coercion) acc -> + E.Map.add (import_simple elt) (import_simple canonical, coercion) acc) canonical_elements - Simple.Map.empty + E.Map.empty in let aliases_of_canonical_elements = - Simple.Map.fold (fun canonical aliases acc -> - Simple.Map.add (import_simple canonical) + E.Map.fold (fun canonical aliases acc -> + E.Map.add (import_simple canonical) (Aliases_of_canonical_element.import import_simple aliases) acc) aliases_of_canonical_elements - Simple.Map.empty + E.Map.empty in let binding_times_and_modes = - Simple.Map.fold (fun simple binding_time_and_mode acc -> - Simple.Map.add (import_simple simple) binding_time_and_mode acc) + E.Map.fold (fun simple binding_time_and_mode acc -> + E.Map.add (import_simple simple) binding_time_and_mode acc) binding_times_and_modes - Simple.Map.empty + E.Map.empty in { canonical_elements; aliases_of_canonical_elements; @@ -567,14 +864,14 @@ let import import_map { canonical_elements; let merge t1 t2 = let canonical_elements = - Simple.Map.disjoint_union + E.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 -> + E.Map.union (fun _simple aliases1 aliases2 -> Some (Aliases_of_canonical_element.merge aliases1 aliases2)) t1.aliases_of_canonical_elements t2.aliases_of_canonical_elements @@ -585,8 +882,8 @@ let merge t1 t2 = Name_mode.normal in let binding_times_and_modes = - Simple.Map.union (fun simple data1 data2 -> - Simple.pattern_match simple + E.Map.union (fun simple data1 data2 -> + E.pattern_match simple ~const:(fun _ -> assert (Binding_time.With_name_mode.equal data1 data2); Some data1) @@ -617,9 +914,9 @@ let merge t1 t2 = } let get_canonical_ignoring_name_mode t name = - let simple = Simple.name name in - match canonical t simple with - | Is_canonical _ -> simple + let elt = E.name name in + match canonical t elt with + | Is_canonical _ -> elt | Alias_of_canonical { canonical_element; _ } -> canonical_element let clean_for_export @@ -627,10 +924,10 @@ let clean_for_export aliases_of_canonical_elements; binding_times_and_modes; } = let binding_times_and_modes = - Simple.Map.mapi (fun simple binding_time_and_mode -> + E.Map.mapi (fun simple binding_time_and_mode -> let module BTM = Binding_time.With_name_mode in let new_mode = - if Simple.is_var simple then Name_mode.in_types + if E.is_var simple then Name_mode.in_types else BTM.name_mode binding_time_and_mode in BTM.create (BTM.binding_time binding_time_and_mode) new_mode) @@ -640,10 +937,12 @@ let clean_for_export (* Note: the relative order of the aliases and of their canonical element will be unchanged, as it only depends on the binding times. *) - Simple.Map.map Aliases_of_canonical_element.move_variables_to_mode_in_types + E.Map.map Aliases_of_canonical_element.move_variables_to_mode_in_types aliases_of_canonical_elements in { canonical_elements; aliases_of_canonical_elements; binding_times_and_modes; } + +end[@@inline always] diff --git a/middle_end/flambda/types/env/aliases.mli b/middle_end/flambda/types/env/aliases.mli index 37292dcfcfae..a9a85151d1d9 100644 --- a/middle_end/flambda/types/env/aliases.mli +++ b/middle_end/flambda/types/env/aliases.mli @@ -18,6 +18,55 @@ [@@@ocaml.warning "+a-4-30-40-41-42"] +(* CR xclerc for xclerc: this module provides a functor rather than "direct" + access to alias handling to simplify testing. This could be reconsidered + once we trust the code to be correct, in particular because the indirection + makes the code extremely slow. *) + +type 'a coercion_to_canonical = { + coercion_to_canonical : 'a; +} [@@ocaml.unboxed] + +module type Coercion = sig + type t + val equal : t -> t -> bool + val inverse : t -> t + val id : t + val is_id : t -> bool + val compose : t -> newer:t -> t + val print : Format.formatter -> t -> unit +end + +module type Element = sig + type t + val name : Name.t -> t + val is_var : t -> bool + val without_coercion : t -> t + val pattern_match + : t + -> name:(Reg_width_things.Name.t -> 'a) + -> const:(Reg_width_things.Const.t -> 'a) + -> 'a + include Identifiable.S with type t := t +end + +module type Export = sig + type e + type t + val add : t -> e -> t + val empty : t + val to_ids_for_export : t -> Ids_for_export.t + module Import_map : sig + type t + val of_import_map : Ids_for_export.Import_map.t -> t + val simple : t -> e -> e + end +end + +module Make (C : Coercion) (E : Element) (_ : Export with type e = E.t) : sig + +type nonrec coercion_to_canonical = C.t coercion_to_canonical + type t include Contains_ids.S with type t := t @@ -30,34 +79,38 @@ val empty : t type add_result = private { t : t; - canonical_element : Simple.t; - alias_of : Simple.t; + canonical_element : E.t; + alias_of : E.t; + coerce_alias_of_to_canonical_element : C.t; } val add : t - -> Simple.t - -> Binding_time.With_name_mode.t - -> Simple.t - -> Binding_time.With_name_mode.t + -> element1:E.t + -> binding_time_and_mode1:Binding_time.With_name_mode.t + -> coerce_from_element2_to_element1:C.t + -> element2:E.t + -> binding_time_and_mode2:Binding_time.With_name_mode.t -> add_result -val mem : t -> Simple.t -> bool +val mem : t -> E.t -> bool (** [get_canonical_element] returns [None] only when the [min_order_within_equiv_class] cannot be satisfied. *) val get_canonical_element_exn : t - -> Simple.t + -> E.t -> Name_mode.t -> min_name_mode:Name_mode.t - -> Simple.t + -> E.t * coercion_to_canonical (** [get_aliases] always returns the supplied element in the result set. *) -val get_aliases : t -> Simple.t -> Simple.Set.t +val get_aliases : t -> E.t -> coercion_to_canonical E.Map.t -val get_canonical_ignoring_name_mode : t -> Name.t -> Simple.t +val get_canonical_ignoring_name_mode : t -> Name.t -> E.t val merge : t -> t -> t val clean_for_export : t -> t + +end diff --git a/middle_end/flambda/types/env/typing_env.rec.ml b/middle_end/flambda/types/env/typing_env.rec.ml index 8772883b050f..54af6f2ce287 100644 --- a/middle_end/flambda/types/env/typing_env.rec.ml +++ b/middle_end/flambda/types/env/typing_env.rec.ml @@ -16,6 +16,19 @@ [@@@ocaml.warning "+a-4-30-40-41-42"] +module Ids_for_export = struct + include Ids_for_export + type e = Simple.t + let add = Ids_for_export.add_simple + let to_ids_for_export x = x + module Import_map = struct + include Ids_for_export.Import_map + let of_import_map x = x + end +end + +module Aliases = Aliases.Make (Coercion) (Simple) (Ids_for_export) + module K = Flambda_kind (* CR mshinwell: Add signatures to these submodules. *) @@ -985,7 +998,7 @@ and add_equation t name ty = end) ~const:(fun _ -> ()) end; - let aliases, simple, rec_info, t, ty = + let aliases, simple, coercion, t, ty = let aliases = aliases t in match Type_grammar.get_alias_exn ty with | exception Not_found -> @@ -998,18 +1011,26 @@ and add_equation t name ty = 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 rec_info = Simple.rec_info alias_of in + let coercion = Simple.coercion alias_of 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; + t = aliases; + coerce_alias_of_to_canonical_element = coercion; } : Aliases.add_result) = + Aliases.add + aliases + ~element1:alias + ~binding_time_and_mode1:binding_time_and_mode_alias + ~coerce_from_element2_to_element1:(Option.value coercion ~default:Coercion.id) + ~element2:alias_of + ~binding_time_and_mode2:binding_time_and_mode_alias_of in let ty = Type_grammar.alias_type_of kind canonical_element in - aliases, alias_of, rec_info, t, ty + aliases, alias_of, Some coercion, 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 @@ -1038,12 +1059,17 @@ and add_equation t name ty = Simple.pattern_match simple ~name ~const:(fun _ -> ty, t) in let ty = - match rec_info with + match coercion with | None -> ty - | Some rec_info -> - match Type_grammar.apply_rec_info ty rec_info with - | Bottom -> Type_grammar.bottom (Type_grammar.kind ty) - | Ok ty -> ty + | Some coercion -> + (* CR xclerc for xclerc: an alternative would be to ensure "everywhere" + that applying the identity coercion is always legal. *) + if Coercion.is_id coercion then + ty + else + match Type_grammar.apply_coercion ty coercion 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) @@ -1188,21 +1214,21 @@ let cut_and_n_way_join definition_typing_env ts_and_use_ids ~params let get_canonical_simple_with_kind_exn t ?min_name_mode simple = let kind = kind_of_simple t simple in - let newer_rec_info = - let newer_rec_info = Simple.rec_info simple in - match newer_rec_info with + let newer_coercion = + let newer_coercion = Simple.coercion simple in + match newer_coercion with | None -> None - | Some newer_rec_info -> + | Some newer_coercion -> Simple.pattern_match simple - ~const:(fun _ -> Some newer_rec_info) + ~const:(fun _ -> Some newer_coercion) ~name:(fun name -> match Type_grammar.get_alias_exn (find t name (Some kind)) with - | exception Not_found -> Some newer_rec_info + | exception Not_found -> Some newer_coercion | simple -> - match Simple.rec_info simple with - | None -> Some newer_rec_info - | Some rec_info -> - Some (Rec_info.merge rec_info ~newer:newer_rec_info)) + match Simple.coercion simple with + | None -> Some newer_coercion + | Some coercion -> + Some (Coercion.compose coercion ~newer:newer_coercion)) in let aliases_for_simple = if Aliases.mem (aliases t) simple then aliases t @@ -1248,33 +1274,33 @@ let get_canonical_simple_with_kind_exn t ?min_name_mode simple = print t end; raise Misc.Fatal_error - | alias -> - match newer_rec_info with + | alias, _coercion (* CR xclerc for xclerc: use the coercion. *) -> + match newer_coercion with | None -> alias, kind | Some _ -> - match Simple.merge_rec_info alias ~newer_rec_info with + match Simple.compose_coercion alias ~newer_coercion with | None -> raise Not_found | Some simple -> simple, kind let get_canonical_simple_exn t ?min_name_mode simple = (* Duplicated from above to eliminate the allocation of the returned pair. *) - let newer_rec_info = - let newer_rec_info = Simple.rec_info simple in - match newer_rec_info with + let newer_coercion = + let newer_coercion = Simple.coercion simple in + match newer_coercion with | None -> None - | Some newer_rec_info -> + | Some newer_coercion -> Simple.pattern_match simple - ~const:(fun _ -> Some newer_rec_info) + ~const:(fun _ -> Some newer_coercion) ~name:(fun name -> - if variable_is_from_missing_cmx_file t name then Some newer_rec_info + if variable_is_from_missing_cmx_file t name then Some newer_coercion else match Type_grammar.get_alias_exn (find t name None) with - | exception Not_found -> Some newer_rec_info + | exception Not_found -> Some newer_coercion | simple -> - match Simple.rec_info simple with - | None -> Some newer_rec_info - | Some rec_info -> - Some (Rec_info.merge rec_info ~newer:newer_rec_info)) + match Simple.coercion simple with + | None -> Some newer_coercion + | Some coercion -> + Some (Coercion.compose coercion ~newer:newer_coercion)) in let aliases_for_simple = if Aliases.mem (aliases t) simple then aliases t @@ -1351,11 +1377,11 @@ let get_canonical_simple_exn t ?min_name_mode simple = print t end; raise Misc.Fatal_error - | alias -> - match newer_rec_info with + | alias, _ -> + match newer_coercion with | None -> alias | Some _ -> - match Simple.merge_rec_info alias ~newer_rec_info with + match Simple.compose_coercion alias ~newer_coercion with | None -> raise Not_found | Some simple -> simple @@ -1366,7 +1392,7 @@ let get_alias_then_canonical_simple_exn t ?min_name_mode typ = let aliases_of_simple t ~min_name_mode simple = let aliases = Aliases.get_aliases (aliases t) simple - |> Simple.Set.filter (fun alias -> + |> Simple.Map.filter (fun alias _coercion (* CR xclerc for xclerc: use the coercion. *) -> let name_mode = Binding_time.With_name_mode.name_mode (binding_time_and_mode_of_simple t alias) @@ -1375,16 +1401,16 @@ let aliases_of_simple t ~min_name_mode simple = | None -> false | Some c -> c >= 0) in - let newer_rec_info = Simple.rec_info simple in - match newer_rec_info with + let newer_coercion = Simple.coercion simple in + match newer_coercion with | None -> aliases | Some _ -> - Simple.Set.fold (fun simple simples -> - match Simple.merge_rec_info simple ~newer_rec_info with + Simple.Map.fold (fun simple coercion simples -> + match Simple.compose_coercion simple ~newer_coercion with | None -> simples - | Some simple -> Simple.Set.add simple simples) + | Some simple -> Simple.Map.add simple coercion simples) aliases - Simple.Set.empty + Simple.Map.empty let aliases_of_simple_allowable_in_types t simple = aliases_of_simple t ~min_name_mode:Name_mode.in_types simple diff --git a/middle_end/flambda/types/env/typing_env.rec.mli b/middle_end/flambda/types/env/typing_env.rec.mli index 77d7121ed8de..e5ddde839a6f 100644 --- a/middle_end/flambda/types/env/typing_env.rec.mli +++ b/middle_end/flambda/types/env/typing_env.rec.mli @@ -120,9 +120,9 @@ val aliases_of_simple : t -> min_name_mode:Name_mode.t -> Simple.t - -> Simple.Set.t + -> Coercion.t Aliases.coercion_to_canonical Simple.Map.t -val aliases_of_simple_allowable_in_types : t -> Simple.t -> Simple.Set.t +val aliases_of_simple_allowable_in_types : t -> Simple.t -> Coercion.t Aliases.coercion_to_canonical Simple.Map.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 a9db6f6e9412..976f8890a36d 100644 --- a/middle_end/flambda/types/flambda_type.mli +++ b/middle_end/flambda/types/flambda_type.mli @@ -178,7 +178,7 @@ module Typing_env : sig : t -> min_name_mode:Name_mode.t -> Simple.t - -> Simple.Set.t + -> Coercion.t Aliases.coercion_to_canonical Simple.Map.t val clean_for_export : t -> reachable_names:Name_occurrences.t -> t @@ -232,7 +232,7 @@ 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 coercion : t -> Coercion.t val is_tupled : t -> bool end @@ -277,7 +277,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 @@ -401,7 +401,7 @@ val mutable_string : size:int -> t val create_inlinable_function_declaration : code_id:Code_id.t -> dbg:Debuginfo.t - -> rec_info:Rec_info.t + -> coercion:Coercion.t -> is_tupled:bool -> Function_declaration_type.t 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 b75ad30e1792..46fdf430f591 100644 --- a/middle_end/flambda/types/structures/function_declaration_type.rec.ml +++ b/middle_end/flambda/types/structures/function_declaration_type.rec.ml @@ -23,37 +23,37 @@ module Inlinable = struct type t = { code_id : Code_id.t; dbg : Debuginfo.t; - rec_info : Rec_info.t; + coercion : Coercion.t; is_tupled : bool; } - let print ppf { code_id; dbg; rec_info; is_tupled; } = + let print ppf { code_id; dbg; coercion; is_tupled; } = Format.fprintf ppf "@[(Inlinable@ \ @[(code_id@ %a)@]@ \ @[(dbg@ %a)@] \ - @[(rec_info@ %a)@]\ + @[(coercion@ %a)@]\ @[ Name_occurrences.empty - | Ok (Inlinable { code_id; dbg = _; rec_info = _; is_tupled = _; }) + | Ok (Inlinable { code_id; dbg = _; coercion = _; is_tupled = _; }) | Ok (Non_inlinable { code_id; is_tupled = _; }) -> Name_occurrences.add_code_id Name_occurrences.empty code_id Name_mode.in_types @@ -117,16 +117,16 @@ let free_names (t : t) = let all_ids_for_export (t : t) = match t with | Bottom | Unknown -> Ids_for_export.empty - | Ok (Inlinable { code_id; dbg = _; rec_info = _; is_tupled = _; }) + | Ok (Inlinable { code_id; dbg = _; coercion = _; is_tupled = _; }) | Ok (Non_inlinable { code_id; is_tupled = _; }) -> Ids_for_export.add_code_id Ids_for_export.empty code_id let import import_map (t : t) : t = match t with | Bottom | Unknown -> t - | Ok (Inlinable { code_id; dbg; rec_info; is_tupled; }) -> + | Ok (Inlinable { code_id; dbg; coercion; is_tupled; }) -> let code_id = Ids_for_export.Import_map.code_id import_map code_id in - Ok (Inlinable { code_id; dbg; rec_info; is_tupled; }) + Ok (Inlinable { code_id; dbg; coercion; is_tupled; }) | Ok (Non_inlinable { code_id; is_tupled; }) -> let code_id = Ids_for_export.Import_map.code_id import_map code_id in Ok (Non_inlinable { code_id; is_tupled; }) @@ -179,13 +179,13 @@ let meet (env : Meet_env.t) (t1 : t) (t2 : t) | Ok (Inlinable { code_id = code_id1; dbg = dbg1; - rec_info = _rec_info1; + coercion = _coercion1; is_tupled = is_tupled1; }), Ok (Inlinable { code_id = code_id2; dbg = dbg2; - rec_info = _rec_info2; + coercion = _coercion2; is_tupled = is_tupled2; }) -> let typing_env = Meet_env.env env in @@ -197,12 +197,12 @@ let meet (env : Meet_env.t) (t1 : t) (t2 : t) Ok (Ok (Inlinable { code_id; dbg = dbg1; - rec_info = _rec_info1; + coercion = _coercion1; is_tupled = is_tupled1; }), TEE.empty ()) in - (* CR mshinwell: What about [rec_info]? *) + (* CR mshinwell: What about [coercion]? *) begin match Code_age_relation.meet target_code_age_rel ~resolver code_id1 code_id2 with @@ -251,13 +251,13 @@ let join (env : Join_env.t) (t1 : t) (t2 : t) : t = | Ok (Inlinable { code_id = code_id1; dbg = dbg1; - rec_info = _rec_info1; + coercion = _coercion1; is_tupled = is_tupled1; }), Ok (Inlinable { code_id = code_id2; dbg = dbg2; - rec_info = _rec_info2; + coercion = _coercion2; is_tupled = is_tupled2; }) -> let typing_env = Join_env.target_join_env env in @@ -269,11 +269,11 @@ let join (env : Join_env.t) (t1 : t) (t2 : t) : t = Ok (Inlinable { code_id; dbg = dbg1; - rec_info = _rec_info1; + coercion = _coercion1; is_tupled = is_tupled1; }) in - (* CR mshinwell: What about [rec_info]? *) + (* CR mshinwell: What about [coercion]? *) let code_age_rel1 = TE.code_age_relation (Join_env.left_join_env env) in @@ -288,13 +288,13 @@ 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 = +let apply_coercion (t : t) coercion : 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 (Inlinable { code_id; dbg; coercion = coercion'; is_tupled; }) -> + let coercion = Coercion.compose coercion' ~newer:coercion in Ok (Ok (Inlinable { code_id; dbg; - rec_info; + coercion; is_tupled; })) | Ok (Non_inlinable { code_id = _; is_tupled = _; }) -> 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..e002f06e5613 100644 --- a/middle_end/flambda/types/structures/function_declaration_type.rec.mli +++ b/middle_end/flambda/types/structures/function_declaration_type.rec.mli @@ -22,13 +22,13 @@ module Inlinable : sig val create : code_id:Code_id.t -> dbg:Debuginfo.t - -> rec_info:Rec_info.t + -> coercion:Coercion.t -> is_tupled:bool -> t val code_id : t -> Code_id.t val dbg : t -> Debuginfo.t - val rec_info : t -> Rec_info.t + val coercion : t -> Coercion.t val is_tupled : t -> bool end @@ -60,4 +60,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 2f246c137779..b6975c5f0f12 100644 --- a/middle_end/flambda/types/template/flambda_type.templ.ml +++ b/middle_end/flambda/types/template/flambda_type.templ.ml @@ -945,7 +945,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 e8f014763d9d..f5cc8bdadbdb 100644 --- a/middle_end/flambda/types/type_descr.rec.ml +++ b/middle_end/flambda/types/type_descr.rec.ml @@ -137,18 +137,18 @@ 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 + let newer_coercion = Some coercion in + begin match Simple.compose_coercion simple ~newer_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 = @@ -186,16 +186,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 @@ -244,10 +244,10 @@ 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 -> Simple.Map.empty | Some simple -> let simples = - Simple.Set.add simple ( + Simple.Map.add simple { Aliases.coercion_to_canonical = Coercion.id; } ( TE.aliases_of_simple_allowable_in_types env simple) in (* @@ -255,7 +255,7 @@ module Make (Head : Type_head_intf.S Simple.print simple Simple.Set.print simples; *) - Simple.Set.filter (fun simple -> + Simple.Map.filter (fun simple _ -> Typing_env.mem_simple in_env simple) simples @@ -513,20 +513,26 @@ module Make (Head : Type_head_intf.S if Simple.same simple1 simple2 then Simple.Set.singleton simple1 else + let map_keys m = + Simple.Map.fold (fun simple _ acc -> + Simple.Set.add simple acc) + m + Simple.Set.empty + in Simple.Set.inter (all_aliases_of (Join_env.left_join_env join_env) canonical_simple1 - ~in_env:(Join_env.target_join_env join_env)) + ~in_env:(Join_env.target_join_env join_env) |> map_keys) (all_aliases_of (Join_env.right_join_env join_env) canonical_simple2 - ~in_env:(Join_env.target_join_env join_env)) + ~in_env:(Join_env.target_join_env join_env) |> map_keys) in match bound_name with | None -> shared_aliases | 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. *) + coercion. Such an alias is forbidden. *) Simple.Set.filter (fun simple -> not (Simple.same simple (Simple.name bound_name))) shared_aliases 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 f5031dfc81d7..25ae138bdb27 100644 --- a/middle_end/flambda/types/type_grammar.rec.ml +++ b/middle_end/flambda/types/type_grammar.rec.ml @@ -167,35 +167,35 @@ let import import_map t = | Naked_int64 ty -> Naked_int64 (T_N64.import import_map ty) | Naked_nativeint ty -> Naked_nativeint (T_NN.import import_map 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 @@ -613,10 +613,10 @@ let any_boxed_int32 () = box_int32 (any_naked_int32 ()) let any_boxed_int64 () = box_int64 (any_naked_int64 ()) let any_boxed_nativeint () = box_nativeint (any_naked_nativeint ()) -let create_inlinable_function_declaration ~code_id ~dbg ~rec_info ~is_tupled +let create_inlinable_function_declaration ~code_id ~dbg ~coercion ~is_tupled : Function_declaration_type.t = Ok (Inlinable ( - Function_declaration_type.Inlinable.create ~code_id ~dbg ~rec_info ~is_tupled)) + Function_declaration_type.Inlinable.create ~code_id ~dbg ~coercion ~is_tupled)) let create_non_inlinable_function_declaration ~code_id ~is_tupled : Function_declaration_type.t = diff --git a/middle_end/flambda/types/type_grammar.rec.mli b/middle_end/flambda/types/type_grammar.rec.mli index bfe9db7c2e29..d093d2c3d0ab 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 @@ -162,7 +162,7 @@ val kind_for_const : Reg_width_const.t -> Flambda_kind.t val create_inlinable_function_declaration : code_id:Code_id.t -> dbg:Debuginfo.t - -> rec_info:Rec_info.t + -> coercion:Coercion.t -> is_tupled:bool -> Function_declaration_type.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 42951245bfd5..30ca8d1264e4 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 @@ -34,8 +34,8 @@ let all_ids_for_export _t = Ids_for_export.empty let import _import_map t = t -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 2015ededb093..c29bd88dd49e 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 @@ -67,8 +67,8 @@ let import import_map t = | Is_int ty -> Is_int (T.import import_map ty) | Get_tag ty -> Get_tag (T.import import_map 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 0ff87ea98959..ade553e9c238 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 @@ -34,8 +34,8 @@ let all_ids_for_export _t = Ids_for_export.empty let import _import_map t = t -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 54822d0abea5..3498f4aaa4d0 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 @@ -34,8 +34,8 @@ let all_ids_for_export _t = Ids_for_export.empty let import _import_map t = t -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 2c3077a2e048..c5e24720d080 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 @@ -33,8 +33,8 @@ let all_ids_for_export _t = Ids_for_export.empty let import _import_map t = t -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 5090e918e0aa..0097aac7fd8b 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 @@ -175,7 +175,7 @@ let import import_map t = | (String _) as t -> t | Array { length; } -> Array { length = T.import import_map 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 @@ -183,7 +183,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 _ @@ -192,7 +192,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..b86874811a06 --- /dev/null +++ b/testsuite/tests/flambda2-aliases/test.ml @@ -0,0 +1,580 @@ +(* TEST + include ocamlcommon + include ocamlmiddleend + * bytecode +*) + +let () = Clflags.flambda_invariant_checks := true + +let () = + let dummy = "compilation_unit" in + Compilation_unit.set_current + (Compilation_unit.create + (Ident.create_persistent dummy) + (Linkage_name.create dummy)) + +module Coercion : sig + include Aliases.Coercion + val make : char -> t +end = struct + type t = string + let make c = String.make 1 c + let equal = String.equal + let change_case ch = + if Char.equal ch (Char.lowercase_ascii ch) then + Char.uppercase_ascii ch + else + Char.lowercase_ascii ch + let simplify s = + let len = String.length s in + let buff = Buffer.create len in + let i = ref 0 in + while !i < len do + if succ !i < len && Char.equal s.[!i] (change_case s.[succ !i]) then begin + incr i; + incr i; + end else begin + Buffer.add_char buff s.[!i]; + incr i; + end + done; + Buffer.contents buff + let inverse c = + let len = String.length c in + let res = String.init len (fun i -> change_case c.[len - i - 1]) in + simplify res + let id = "" + let is_id c = equal id c + let compose c ~newer = simplify (c ^ newer) + let print ppf c = Format.fprintf ppf "coercion:%S" c +end + +module Element : sig + include Aliases.Element + val make : string -> t +end = struct + type t = string + let make x = x + let name n = + Name.pattern_match + n + ~var:(fun v -> Variable.name v) + ~symbol:(fun _ -> assert false) + let without_coercion e = e + let pattern_match _ ~name:_ ~const:_ = assert false + let print ppf e = Format.fprintf ppf "element:%S" e + include Identifiable.Make (struct + type nonrec t = t + let compare = String.compare + let equal = String.equal + let hash = Hashtbl.hash + let output _ _ = assert false + let print = print + end) +end + +module Export : sig + include Aliases.Export with type e = Element.t +end = struct + type e = Element.t + type t = unit + let add _ _ = assert false + let empty = () + let to_ids_for_export _ = assert false + module Import_map = struct + type t + let of_import_map _ = assert false + let simple _ _ = assert false + end +end + +module Aliases = Aliases.Make (Coercion) (Element) (Export) + +let next_time : unit -> Binding_time.With_name_mode.t = + let next = ref Binding_time.earliest_var in + fun () -> + let time = !next in + next := Binding_time.succ time; + Binding_time.With_name_mode.create time Name_mode.normal + +let add_alias + ppf + aliases + ~element1 + ~binding_time_and_mode1 + ~coerce_from_element2_to_element1 + ~element2 + ~binding_time_and_mode2 = + let { Aliases.t; canonical_element; alias_of; coerce_alias_of_to_canonical_element; } = + Aliases.add + aliases + ~element1 + ~binding_time_and_mode1 + ~coerce_from_element2_to_element1 + ~element2 + ~binding_time_and_mode2 + in + Format.fprintf ppf "[added] %a <--[%a]-- %a@." + Element.print canonical_element + Coercion.print coerce_alias_of_to_canonical_element + Element.print alias_of; + t + +(* CR xclerc for xclerc: remove the `expect` parameter. + (It currently allows one to use this module without relying upon ocamltest.) *) +let test msg ~f ~expect = + let buff = Buffer.create 1024 in + let ppf = Format.formatter_of_buffer buff in + print_string "*** "; + print_endline msg; + f ppf; + Format.pp_print_flush ppf (); + let got = Buffer.contents buff in + if String.equal got expect then begin + print_endline got; + print_newline (); + end else begin + prerr_endline "*** error, expected:"; + prerr_endline expect; + prerr_endline "*** but got:"; + prerr_endline got; + assert false + end + +let () = test "empty" ~f:(fun ppf -> + let aliases = Aliases.empty in + Aliases.print ppf aliases) + ~expect:{|((canonical_elements {}) (aliases_of_canonical_elements {}) + (binding_times_and_modes {}))|} + +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 = Element.make "x" in + let y = Element.make "y" in + (* x <--[f]-- y *) + let aliases = + add_alias + ppf + aliases + ~element1:x + ~binding_time_and_mode1:t_x + ~coerce_from_element2_to_element1:(Coercion.make 'f') + ~element2:y + ~binding_time_and_mode2:t_y + in + Aliases.print ppf aliases) + ~expect:{|[added] element:"x" <--[coercion:"f"]-- element:"y" +((canonical_elements {(element:"y" element:"x" (coercion:"f"))}) + (aliases_of_canonical_elements + {(element:"x" {(Normal {(element:"y" coercion:"f")})})}) + (binding_times_and_modes + {(element:"x" (bound at time 3 Normal)) + (element:"y" (bound at time 4 Normal))}))|} + +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 = Element.make "x" in + let y = Element.make "y" in + (* x <--[f]-- y + ~> + y <--[F]-- x *) + let aliases = + add_alias + ppf + aliases + ~element1:x + ~binding_time_and_mode1:t_x + ~coerce_from_element2_to_element1:(Coercion.make 'f') + ~element2:y + ~binding_time_and_mode2:t_y + in + Aliases.print ppf aliases) + ~expect:{|[added] element:"y" <--[coercion:"F"]-- element:"x" +((canonical_elements {(element:"x" element:"y" (coercion:"F"))}) + (aliases_of_canonical_elements + {(element:"y" {(Normal {(element:"x" coercion:"F")})})}) + (binding_times_and_modes + {(element:"x" (bound at time 6 Normal)) + (element:"y" (bound at time 5 Normal))}))|} + +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 = Element.make "x" in + let y = Element.make "y" in + let z = Element.make "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 + ~coerce_from_element2_to_element1:(Coercion.make 'f') + ~element2:y + ~binding_time_and_mode2:t_y + in + let aliases = + add_alias + ppf + aliases + ~element1:x + ~binding_time_and_mode1:t_x + ~coerce_from_element2_to_element1:(Coercion.make 'g') + ~element2:z + ~binding_time_and_mode2:t_z + in + Aliases.print ppf aliases) + ~expect:{|[added] element:"x" <--[coercion:"f"]-- element:"y" +[added] element:"x" <--[coercion:"g"]-- element:"z" +((canonical_elements + {(element:"y" element:"x" (coercion:"f")) + (element:"z" element:"x" (coercion:"g"))}) + (aliases_of_canonical_elements + {(element:"x" + {(Normal {(element:"y" coercion:"f") (element:"z" coercion:"g")})})}) + (binding_times_and_modes + {(element:"x" (bound at time 7 Normal)) + (element:"y" (bound at time 8 Normal)) + (element:"z" (bound at time 9 Normal))}))|} + +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 = Element.make "x" in + let y = Element.make "y" in + let z = Element.make "z" in + (* x <--[f]-- y + + + y <--[g]-- z + ~> + x <--[f]-- y + ^--[gf]-- z *) + let aliases = + add_alias + ppf + aliases + ~element1:x + ~binding_time_and_mode1:t_x + ~coerce_from_element2_to_element1:(Coercion.make 'f') + ~element2:y + ~binding_time_and_mode2:t_y + in + let aliases = + add_alias + ppf + aliases + ~element1:y + ~binding_time_and_mode1:t_y + ~coerce_from_element2_to_element1:(Coercion.make 'g') + ~element2:z + ~binding_time_and_mode2:t_z + in + Aliases.print ppf aliases) + ~expect:{|[added] element:"x" <--[coercion:"f"]-- element:"y" +[added] element:"x" <--[coercion:"gf"]-- element:"z" +((canonical_elements + {(element:"y" element:"x" (coercion:"f")) + (element:"z" element:"x" (coercion:"gf"))}) + (aliases_of_canonical_elements + {(element:"x" + {(Normal {(element:"y" coercion:"f") (element:"z" coercion:"gf")})})}) + (binding_times_and_modes + {(element:"x" (bound at time 10 Normal)) + (element:"y" (bound at time 11 Normal)) + (element:"z" (bound at time 12 Normal))}))|} + +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 = Element.make "x" in + let y = Element.make "y" in + let z = Element.make "z" in + (* x <--[f]-- y + + + y <--[g]-- z + ~> + z <--[FG]-- x + ^--[G]-- y *) + let aliases = + add_alias + ppf + aliases + ~element1:x + ~binding_time_and_mode1:t_x + ~coerce_from_element2_to_element1:(Coercion.make 'f') + ~element2:y + ~binding_time_and_mode2:t_y + in + let aliases = + add_alias + ppf + aliases + ~element1:y + ~binding_time_and_mode1:t_y + ~coerce_from_element2_to_element1:(Coercion.make 'g') + ~element2:z + ~binding_time_and_mode2:t_z + in + Aliases.print ppf aliases) + ~expect:{|[added] element:"x" <--[coercion:"f"]-- element:"y" +[added] element:"z" <--[coercion:"FG"]-- element:"x" +((canonical_elements + {(element:"x" element:"z" (coercion:"FG")) + (element:"y" element:"z" (coercion:"G"))}) + (aliases_of_canonical_elements + {(element:"z" + {(Normal {(element:"x" coercion:"FG") (element:"y" coercion:"G")})})}) + (binding_times_and_modes + {(element:"x" (bound at time 14 Normal)) + (element:"y" (bound at time 15 Normal)) + (element:"z" (bound at time 13 Normal))}))|} + +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 = Element.make "x" in + let y = Element.make "y" in + let z = Element.make "z" in + (* x <--[f]-- y + + + z <--[g]-- y + ~> + z <--[Fg]-- x + ^--[g]-- y *) + let aliases = + add_alias + ppf + aliases + ~element1:x + ~binding_time_and_mode1:t_x + ~coerce_from_element2_to_element1:(Coercion.make 'f') + ~element2:y + ~binding_time_and_mode2:t_y + in + let aliases = + add_alias + ppf + aliases + ~element1:z + ~binding_time_and_mode1:t_z + ~coerce_from_element2_to_element1:(Coercion.make 'g') + ~element2:y + ~binding_time_and_mode2:t_y + in + Aliases.print ppf aliases) + ~expect:{|[added] element:"x" <--[coercion:"f"]-- element:"y" +[added] element:"z" <--[coercion:"Fg"]-- element:"x" +((canonical_elements + {(element:"x" element:"z" (coercion:"Fg")) + (element:"y" element:"z" (coercion:"g"))}) + (aliases_of_canonical_elements + {(element:"z" + {(Normal {(element:"x" coercion:"Fg") (element:"y" coercion:"g")})})}) + (binding_times_and_modes + {(element:"x" (bound at time 17 Normal)) + (element:"y" (bound at time 18 Normal)) + (element:"z" (bound at time 16 Normal))}))|} + +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 = Element.make "x" in + let y = Element.make "y" in + let z = Element.make "z" in + (* x <--[f]-- y + + + z <--[g]-- y + ~> + x <--[f]-- y + ^--[Gf]-- z *) + let aliases = + add_alias + ppf + aliases + ~element1:x + ~binding_time_and_mode1:t_x + ~coerce_from_element2_to_element1:(Coercion.make 'f') + ~element2:y + ~binding_time_and_mode2:t_y + in + let aliases = + add_alias + ppf + aliases + ~element1:z + ~binding_time_and_mode1:t_z + ~coerce_from_element2_to_element1:(Coercion.make 'g') + ~element2:y + ~binding_time_and_mode2:t_y + in + Aliases.print ppf aliases) + ~expect:{|[added] element:"x" <--[coercion:"f"]-- element:"y" +[added] element:"x" <--[coercion:"Gf"]-- element:"z" +((canonical_elements + {(element:"y" element:"x" (coercion:"f")) + (element:"z" element:"x" (coercion:"Gf"))}) + (aliases_of_canonical_elements + {(element:"x" + {(Normal {(element:"y" coercion:"f") (element:"z" coercion:"Gf")})})}) + (binding_times_and_modes + {(element:"x" (bound at time 19 Normal)) + (element:"y" (bound at time 20 Normal)) + (element:"z" (bound at time 21 Normal))}))|} + +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 = Element.make "x" in + let y = Element.make "y" in + let z = Element.make "z" in + let t = Element.make "t" in + (* x <--[f]-- y + + + z <--[g]-- t + + + y <--[h]-- t + ~> + x <--[f]-- y + ^^--[Ghf]-- z + \--[hf]-- t *) + let aliases = + add_alias + ppf + aliases + ~element1:x + ~binding_time_and_mode1:t_x + ~coerce_from_element2_to_element1:(Coercion.make 'f') + ~element2:y + ~binding_time_and_mode2:t_y + in + let aliases = + add_alias + ppf + aliases + ~element1:z + ~binding_time_and_mode1:t_z + ~coerce_from_element2_to_element1:(Coercion.make 'g') + ~element2:t + ~binding_time_and_mode2:t_t + in + let aliases = + add_alias + ppf + aliases + ~element1:y + ~binding_time_and_mode1:t_y + ~coerce_from_element2_to_element1:(Coercion.make 'h') + ~element2:t + ~binding_time_and_mode2:t_t + in + Aliases.print ppf aliases) + ~expect:{|[added] element:"x" <--[coercion:"f"]-- element:"y" +[added] element:"z" <--[coercion:"g"]-- element:"t" +[added] element:"x" <--[coercion:"Ghf"]-- element:"z" +((canonical_elements + {(element:"t" element:"x" (coercion:"hf")) + (element:"y" element:"x" (coercion:"f")) + (element:"z" element:"x" (coercion:"Ghf"))}) + (aliases_of_canonical_elements + {(element:"x" + {(Normal + {(element:"t" coercion:"hf") (element:"y" coercion:"f") + (element:"z" coercion:"Ghf")})})}) + (binding_times_and_modes + {(element:"t" (bound at time 25 Normal)) + (element:"x" (bound at time 22 Normal)) + (element:"y" (bound at time 23 Normal)) + (element:"z" (bound at time 24 Normal))}))|} + +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 = Element.make "x" in + let y = Element.make "y" in + let z = Element.make "z" in + let t = Element.make "t" in + (* x <--[f]-- y + + + z <--[g]-- t + + + y <--[h]-- t + ~> + z <--[FHg]-- x + ^^--[Hg]-- y + \--[g]-- t *) + let aliases = + add_alias + ppf + aliases + ~element1:x + ~binding_time_and_mode1:t_x + ~coerce_from_element2_to_element1:(Coercion.make 'f') + ~element2:y + ~binding_time_and_mode2:t_y + in + let aliases = + add_alias + ppf + aliases + ~element1:z + ~binding_time_and_mode1:t_z + ~coerce_from_element2_to_element1:(Coercion.make 'g') + ~element2:t + ~binding_time_and_mode2:t_t + in + let aliases = + add_alias + ppf + aliases + ~element1:y + ~binding_time_and_mode1:t_y + ~coerce_from_element2_to_element1:(Coercion.make 'h') + ~element2:t + ~binding_time_and_mode2:t_t + in + Aliases.print ppf aliases) + ~expect:{|[added] element:"x" <--[coercion:"f"]-- element:"y" +[added] element:"z" <--[coercion:"g"]-- element:"t" +[added] element:"z" <--[coercion:"FHg"]-- element:"x" +((canonical_elements + {(element:"t" element:"z" (coercion:"g")) + (element:"x" element:"z" (coercion:"FHg")) + (element:"y" element:"z" (coercion:"Hg"))}) + (aliases_of_canonical_elements + {(element:"z" + {(Normal + {(element:"t" coercion:"g") (element:"x" coercion:"FHg") + (element:"y" coercion:"Hg")})})}) + (binding_times_and_modes + {(element:"t" (bound at time 29 Normal)) + (element:"x" (bound at time 27 Normal)) + (element:"y" (bound at time 28 Normal)) + (element:"z" (bound at time 26 Normal))}))|} + +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..00c702f9fa12 --- /dev/null +++ b/testsuite/tests/flambda2-aliases/test.reference @@ -0,0 +1,131 @@ +*** empty +((canonical_elements {}) (aliases_of_canonical_elements {}) + (binding_times_and_modes {})) + +*** single alias +[added] element:"x" <--[coercion:"f"]-- element:"y" +((canonical_elements {(element:"y" element:"x" (coercion:"f"))}) + (aliases_of_canonical_elements + {(element:"x" {(Normal {(element:"y" coercion:"f")})})}) + (binding_times_and_modes + {(element:"x" (bound at time 3 Normal)) + (element:"y" (bound at time 4 Normal))})) + +*** single alias (inverse) +[added] element:"y" <--[coercion:"F"]-- element:"x" +((canonical_elements {(element:"x" element:"y" (coercion:"F"))}) + (aliases_of_canonical_elements + {(element:"y" {(Normal {(element:"x" coercion:"F")})})}) + (binding_times_and_modes + {(element:"x" (bound at time 6 Normal)) + (element:"y" (bound at time 5 Normal))})) + +*** two aliases (independent) +[added] element:"x" <--[coercion:"f"]-- element:"y" +[added] element:"x" <--[coercion:"g"]-- element:"z" +((canonical_elements + {(element:"y" element:"x" (coercion:"f")) + (element:"z" element:"x" (coercion:"g"))}) + (aliases_of_canonical_elements + {(element:"x" + {(Normal {(element:"y" coercion:"f") (element:"z" coercion:"g")})})}) + (binding_times_and_modes + {(element:"x" (bound at time 7 Normal)) + (element:"y" (bound at time 8 Normal)) + (element:"z" (bound at time 9 Normal))})) + +*** two aliases (simple chain) +[added] element:"x" <--[coercion:"f"]-- element:"y" +[added] element:"x" <--[coercion:"gf"]-- element:"z" +((canonical_elements + {(element:"y" element:"x" (coercion:"f")) + (element:"z" element:"x" (coercion:"gf"))}) + (aliases_of_canonical_elements + {(element:"x" + {(Normal {(element:"y" coercion:"f") (element:"z" coercion:"gf")})})}) + (binding_times_and_modes + {(element:"x" (bound at time 10 Normal)) + (element:"y" (bound at time 11 Normal)) + (element:"z" (bound at time 12 Normal))})) + +*** two aliases (two inverses) +[added] element:"x" <--[coercion:"f"]-- element:"y" +[added] element:"z" <--[coercion:"FG"]-- element:"x" +((canonical_elements + {(element:"x" element:"z" (coercion:"FG")) + (element:"y" element:"z" (coercion:"G"))}) + (aliases_of_canonical_elements + {(element:"z" + {(Normal {(element:"x" coercion:"FG") (element:"y" coercion:"G")})})}) + (binding_times_and_modes + {(element:"x" (bound at time 14 Normal)) + (element:"y" (bound at time 15 Normal)) + (element:"z" (bound at time 13 Normal))})) + +*** two aliases (one inverse) +[added] element:"x" <--[coercion:"f"]-- element:"y" +[added] element:"z" <--[coercion:"Fg"]-- element:"x" +((canonical_elements + {(element:"x" element:"z" (coercion:"Fg")) + (element:"y" element:"z" (coercion:"g"))}) + (aliases_of_canonical_elements + {(element:"z" + {(Normal {(element:"x" coercion:"Fg") (element:"y" coercion:"g")})})}) + (binding_times_and_modes + {(element:"x" (bound at time 17 Normal)) + (element:"y" (bound at time 18 Normal)) + (element:"z" (bound at time 16 Normal))})) + +*** two aliases (one inverse) +[added] element:"x" <--[coercion:"f"]-- element:"y" +[added] element:"x" <--[coercion:"Gf"]-- element:"z" +((canonical_elements + {(element:"y" element:"x" (coercion:"f")) + (element:"z" element:"x" (coercion:"Gf"))}) + (aliases_of_canonical_elements + {(element:"x" + {(Normal {(element:"y" coercion:"f") (element:"z" coercion:"Gf")})})}) + (binding_times_and_modes + {(element:"x" (bound at time 19 Normal)) + (element:"y" (bound at time 20 Normal)) + (element:"z" (bound at time 21 Normal))})) + +*** three aliases (one inverse) +[added] element:"x" <--[coercion:"f"]-- element:"y" +[added] element:"z" <--[coercion:"g"]-- element:"t" +[added] element:"x" <--[coercion:"Ghf"]-- element:"z" +((canonical_elements + {(element:"t" element:"x" (coercion:"hf")) + (element:"y" element:"x" (coercion:"f")) + (element:"z" element:"x" (coercion:"Ghf"))}) + (aliases_of_canonical_elements + {(element:"x" + {(Normal + {(element:"t" coercion:"hf") (element:"y" coercion:"f") + (element:"z" coercion:"Ghf")})})}) + (binding_times_and_modes + {(element:"t" (bound at time 25 Normal)) + (element:"x" (bound at time 22 Normal)) + (element:"y" (bound at time 23 Normal)) + (element:"z" (bound at time 24 Normal))})) + +*** three aliases (two inverses) +[added] element:"x" <--[coercion:"f"]-- element:"y" +[added] element:"z" <--[coercion:"g"]-- element:"t" +[added] element:"z" <--[coercion:"FHg"]-- element:"x" +((canonical_elements + {(element:"t" element:"z" (coercion:"g")) + (element:"x" element:"z" (coercion:"FHg")) + (element:"y" element:"z" (coercion:"Hg"))}) + (aliases_of_canonical_elements + {(element:"z" + {(Normal + {(element:"t" coercion:"g") (element:"x" coercion:"FHg") + (element:"y" coercion:"Hg")})})}) + (binding_times_and_modes + {(element:"t" (bound at time 29 Normal)) + (element:"x" (bound at time 27 Normal)) + (element:"y" (bound at time 28 Normal)) + (element:"z" (bound at time 26 Normal))})) + +OK. \ No newline at end of file From f5a3c1a1b79af98535c8e235b70f3c8a5f443838 Mon Sep 17 00:00:00 2001 From: xclerc Date: Fri, 6 Nov 2020 16:06:45 +0000 Subject: [PATCH 02/16] Print aliases for debug. --- middle_end/flambda/types/env/typing_env.rec.ml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/middle_end/flambda/types/env/typing_env.rec.ml b/middle_end/flambda/types/env/typing_env.rec.ml index 54af6f2ce287..823731106489 100644 --- a/middle_end/flambda/types/env/typing_env.rec.ml +++ b/middle_end/flambda/types/env/typing_env.rec.ml @@ -457,10 +457,13 @@ let print_with_cache ~cache ppf @[(defined_symbols@ %a)@]@ \ @[(code_age_relation@ %a)@]@ \ @[(levels@ %a)@]\ + @[(aliases@ %a)@]\ )@]" Symbol.Set.print defined_symbols Code_age_relation.print code_age_relation - (Scope.Map.print (One_level.print_with_cache ~cache)) levels) + (Scope.Map.print (One_level.print_with_cache ~cache)) levels + Aliases.print (Cached.aliases current_level.just_after_level)) + let print ppf t = print_with_cache ~cache:(Printing_cache.create ()) ppf t From 1a4420bdeeb7d7f86edcd4a569f680622119f1e2 Mon Sep 17 00:00:00 2001 From: Luke Maurer Date: Mon, 8 Mar 2021 11:13:31 +0000 Subject: [PATCH 03/16] Various improvements * Use `Coercion.t` rather than `Coercion.t option` in many places * Use `Rec_info.t` again where sensible (in making inlining decisions, for instance), but redefine it as `unit` pending the next phase of `Rec_info` overhaul * Add simple `int` fields to `Coercion.t` for changing recursion depth; this is simpler than what we'll actually need but specific enough that we can test meaningfully (e.g., we can tell whether coercions are composed in the right order) --- .depend | 53 +- middle_end/flambda/basic/simple.ml | 35 +- middle_end/flambda/basic/simple.mli | 6 +- middle_end/flambda/cmx/ids_for_export.ml | 12 +- middle_end/flambda/compilenv_deps/coercion.ml | 72 +- .../flambda/compilenv_deps/coercion.mli | 15 +- .../flambda/compilenv_deps/flambda_colours.ml | 2 + .../compilenv_deps/flambda_colours.mli | 2 + middle_end/flambda/compilenv_deps/rec_info.ml | 50 +- .../flambda/compilenv_deps/rec_info.mli | 13 +- .../compilenv_deps/reg_width_things.ml | 19 +- .../compilenv_deps/reg_width_things.mli | 2 +- .../flambda/inlining/inlining_decision.ml | 41 +- .../flambda/inlining/inlining_decision.mli | 2 +- .../flambda/inlining/inlining_transforms.ml | 3 +- .../simplify/simplify_apply_expr.rec.ml | 14 +- .../simplify/simplify_set_of_closures.rec.ml | 9 +- .../flambda/simplify/simplify_simple.ml | 18 +- middle_end/flambda/types/env/aliases.ml | 926 +++++++++--------- middle_end/flambda/types/env/aliases.mli | 77 +- .../flambda/types/env/typing_env.rec.ml | 107 +- .../flambda/types/env/typing_env.rec.mli | 7 +- middle_end/flambda/types/flambda_type.mli | 5 +- .../flambda/types/inlining/inlining_state.ml | 6 +- .../function_declaration_type.rec.ml | 50 +- .../function_declaration_type.rec.mli | 3 +- middle_end/flambda/types/type_descr.rec.ml | 3 +- middle_end/flambda/types/type_grammar.rec.ml | 4 +- middle_end/flambda/types/type_grammar.rec.mli | 2 +- testsuite/tests/flambda2-aliases/test.ml | 323 ++---- .../tests/flambda2-aliases/test.reference | 148 ++- 31 files changed, 844 insertions(+), 1185 deletions(-) diff --git a/.depend b/.depend index fb551126f885..207ecfc0d9d3 100644 --- a/.depend +++ b/.depend @@ -3896,10 +3896,15 @@ 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/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 \ @@ -3954,10 +3959,17 @@ middle_end/flambda/compilenv_deps/patricia_tree.cmi : \ utils/numbers.cmi \ utils/identifiable.cmi middle_end/flambda/compilenv_deps/rec_info.cmo : \ + 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/misc.cmx \ + utils/identifiable.cmx \ + middle_end/flambda/compilenv_deps/flambda_colours.cmx \ middle_end/flambda/compilenv_deps/rec_info.cmi -middle_end/flambda/compilenv_deps/rec_info.cmi : +middle_end/flambda/compilenv_deps/rec_info.cmi : \ + utils/identifiable.cmi middle_end/flambda/compilenv_deps/reg_width_things.cmo : \ utils/targetint.cmi \ middle_end/flambda/compilenv_deps/target_imm.cmi \ @@ -5203,7 +5215,6 @@ middle_end/flambda/inlining/inlining_decision.cmo : \ middle_end/flambda/terms/function_declaration.cmi \ middle_end/flambda/terms/flambda.cmi \ middle_end/flambda/simplify/env/downwards_env.cmi \ - middle_end/flambda/compilenv_deps/coercion.cmi \ utils/clflags.cmi \ middle_end/flambda/inlining/inlining_decision.cmi middle_end/flambda/inlining/inlining_decision.cmx : \ @@ -5215,17 +5226,16 @@ middle_end/flambda/inlining/inlining_decision.cmx : \ middle_end/flambda/terms/function_declaration.cmx \ middle_end/flambda/terms/flambda.cmx \ middle_end/flambda/simplify/env/downwards_env.cmx \ - middle_end/flambda/compilenv_deps/coercion.cmx \ utils/clflags.cmx \ middle_end/flambda/inlining/inlining_decision.cmi middle_end/flambda/inlining/inlining_decision.cmi : \ + middle_end/flambda/compilenv_deps/rec_info.cmi \ middle_end/flambda/types/inlining/inlining_state.cmi \ middle_end/flambda/inlining/inlining_cost.cmi \ middle_end/flambda/basic/inline_attribute.cmi \ middle_end/flambda/terms/function_declaration.cmi \ middle_end/flambda/terms/flambda.cmi \ - middle_end/flambda/simplify/env/downwards_env.cmi \ - middle_end/flambda/compilenv_deps/coercion.cmi + middle_end/flambda/simplify/env/downwards_env.cmi middle_end/flambda/inlining/inlining_report.cmo : \ utils/misc.cmi \ middle_end/flambda/inlining/inlining_decision.cmi \ @@ -6156,7 +6166,6 @@ middle_end/flambda/simplify/simplify.cmo : \ middle_end/flambda/simplify/env/continuation_env_and_param_types.cmi \ middle_end/flambda/basic/continuation.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 \ @@ -6229,7 +6238,6 @@ middle_end/flambda/simplify/simplify.cmx : \ middle_end/flambda/simplify/env/continuation_env_and_param_types.cmx \ middle_end/flambda/basic/continuation.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 \ @@ -6301,7 +6309,6 @@ middle_end/flambda/simplify/simplify_apply_expr.rec.cmo : \ lambda/debuginfo.cmi \ middle_end/flambda/basic/continuation.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 \ @@ -6334,7 +6341,6 @@ middle_end/flambda/simplify/simplify_apply_expr.rec.cmx : \ lambda/debuginfo.cmx \ middle_end/flambda/basic/continuation.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 \ @@ -6731,7 +6737,6 @@ middle_end/flambda/simplify/simplify_set_of_closures.rec.cmo : \ middle_end/flambda/simplify/env/downwards_acc.cmi \ middle_end/flambda/basic/continuation.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 \ @@ -6771,7 +6776,6 @@ middle_end/flambda/simplify/simplify_set_of_closures.rec.cmx : \ middle_end/flambda/simplify/env/downwards_acc.cmx \ middle_end/flambda/basic/continuation.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 \ @@ -8856,6 +8860,7 @@ middle_end/flambda/types/flambda_type.cmo : \ middle_end/flambda/basic/scope.cmi \ middle_end/flambda/types/structures/row_like_maps_to_intf.cmo \ middle_end/flambda/basic/reg_width_const.cmi \ + middle_end/flambda/compilenv_deps/rec_info.cmi \ middle_end/flambda/types/structures/product_intf.cmo \ utils/printing_cache.cmi \ middle_end/flambda/types/basic/or_unknown_or_bottom.cmi \ @@ -8909,6 +8914,7 @@ middle_end/flambda/types/flambda_type.cmx : \ middle_end/flambda/basic/scope.cmx \ middle_end/flambda/types/structures/row_like_maps_to_intf.cmx \ middle_end/flambda/basic/reg_width_const.cmx \ + middle_end/flambda/compilenv_deps/rec_info.cmx \ middle_end/flambda/types/structures/product_intf.cmx \ utils/printing_cache.cmx \ middle_end/flambda/types/basic/or_unknown_or_bottom.cmx \ @@ -8954,6 +8960,7 @@ middle_end/flambda/types/flambda_type.cmi : \ middle_end/flambda/basic/simple.cmi \ middle_end/flambda/basic/scope.cmi \ middle_end/flambda/basic/reg_width_const.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 \ @@ -9105,6 +9112,7 @@ middle_end/flambda/types/type_grammar.rec.cmi : \ lambda/tag.cmi \ middle_end/flambda/basic/simple.cmi \ middle_end/flambda/basic/reg_width_const.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 \ @@ -9289,33 +9297,34 @@ middle_end/flambda/types/basic/var_within_closure_set.cmi : \ utils/identifiable.cmi middle_end/flambda/types/env/aliases.cmo : \ middle_end/flambda/compilenv_deps/variable.cmi \ - middle_end/flambda/compilenv_deps/reg_width_things.cmi \ + middle_end/flambda/basic/simple.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 \ - utils/identifiable.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 middle_end/flambda/types/env/aliases.cmx : \ middle_end/flambda/compilenv_deps/variable.cmx \ - middle_end/flambda/compilenv_deps/reg_width_things.cmx \ + middle_end/flambda/basic/simple.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 \ - utils/identifiable.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 middle_end/flambda/types/env/aliases.cmi : \ - middle_end/flambda/compilenv_deps/reg_width_things.cmi \ + middle_end/flambda/basic/simple.cmi \ middle_end/flambda/naming/name_mode.cmi \ middle_end/flambda/basic/name.cmi \ - middle_end/flambda/cmx/ids_for_export.cmi \ - utils/identifiable.cmi \ middle_end/flambda/cmx/contains_ids.cmo \ + middle_end/flambda/compilenv_deps/coercion.cmi \ middle_end/flambda/types/env/binding_time.cmi middle_end/flambda/types/env/binding_time.cmo : \ utils/numbers.cmi \ @@ -9407,7 +9416,6 @@ middle_end/flambda/types/env/typing_env.rec.cmi : \ middle_end/flambda/types/kinds/flambda_kind.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/apply_cont_rewrite_id.cmi \ @@ -9563,6 +9571,7 @@ middle_end/flambda/types/structures/code_age_relation.cmi : \ middle_end/flambda/compilenv_deps/compilation_unit.cmi \ middle_end/flambda/basic/code_id.cmi middle_end/flambda/types/structures/function_declaration_type.rec.cmo : \ + middle_end/flambda/compilenv_deps/rec_info.cmi \ middle_end/flambda/types/basic/or_unknown_or_bottom.cmi \ middle_end/flambda/types/basic/or_bottom.cmi \ middle_end/flambda/naming/name_permutation.cmi \ @@ -9570,11 +9579,11 @@ middle_end/flambda/types/structures/function_declaration_type.rec.cmo : \ middle_end/flambda/naming/name_mode.cmi \ middle_end/flambda/cmx/ids_for_export.cmi \ lambda/debuginfo.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/types/structures/function_declaration_type.rec.cmi middle_end/flambda/types/structures/function_declaration_type.rec.cmx : \ + middle_end/flambda/compilenv_deps/rec_info.cmx \ middle_end/flambda/types/basic/or_unknown_or_bottom.cmx \ middle_end/flambda/types/basic/or_bottom.cmx \ middle_end/flambda/naming/name_permutation.cmx \ @@ -9582,12 +9591,12 @@ middle_end/flambda/types/structures/function_declaration_type.rec.cmx : \ middle_end/flambda/naming/name_mode.cmx \ middle_end/flambda/cmx/ids_for_export.cmx \ lambda/debuginfo.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/types/structures/function_declaration_type.rec.cmi middle_end/flambda/types/structures/function_declaration_type.rec.cmi : \ middle_end/flambda/types/structures/type_structure_intf.cmo \ + middle_end/flambda/compilenv_deps/rec_info.cmi \ middle_end/flambda/types/basic/or_unknown_or_bottom.cmi \ middle_end/flambda/types/basic/or_bottom.cmi \ lambda/debuginfo.cmi \ diff --git a/middle_end/flambda/basic/simple.ml b/middle_end/flambda/basic/simple.ml index 17336efcd575..60893c307321 100644 --- a/middle_end/flambda/basic/simple.ml +++ b/middle_end/flambda/basic/simple.ml @@ -55,23 +55,28 @@ let const_from_descr descr = const (RWC.of_descr descr) let without_coercion t = pattern_match t ~name ~const -let compose_coercion t ~newer_coercion = - if is_const t then None +let apply_coercion t applied_coercion = + if Coercion.is_id applied_coercion then Some t else - match newer_coercion with - | None -> Some t - | Some newer_coercion -> - let coercion = - match coercion t with - | None -> newer_coercion - | Some older_coercion -> - Coercion.compose older_coercion ~newer:newer_coercion - in - Some (with_coercion (without_coercion t) coercion) + 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 Coercion 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 = @@ -118,9 +123,7 @@ let apply_name_permutation t perm = let new_name = Name_permutation.apply_name perm old_name in if old_name == new_name then t else - match coercion t with - | None -> name new_name - | Some coercion -> with_coercion (name new_name) coercion + with_coercion (name new_name) (coercion t) in pattern_match t ~const:(fun _ -> t) ~name diff --git a/middle_end/flambda/basic/simple.mli b/middle_end/flambda/basic/simple.mli index 64ef9a129f66..439a57af4e4b 100644 --- a/middle_end/flambda/basic/simple.mli +++ b/middle_end/flambda/basic/simple.mli @@ -23,7 +23,9 @@ include module type of struct include Reg_width_things.Simple end include Contains_names.S with type t := t -val compose_coercion : t -> newer_coercion:Coercion.t option -> t option +val apply_coercion : t -> Coercion.t -> t option + +val apply_coercion_exn : t -> Coercion.t -> t val without_coercion : t -> t @@ -64,7 +66,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 -> (Coercion.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 diff --git a/middle_end/flambda/cmx/ids_for_export.ml b/middle_end/flambda/cmx/ids_for_export.ml index 91fbf3a72d6f..c8668b22fdde 100644 --- a/middle_end/flambda/cmx/ids_for_export.ml +++ b/middle_end/flambda/cmx/ids_for_export.ml @@ -75,8 +75,8 @@ let add_name t name = let add_simple t simple = let simples = match Simple.coercion simple with - | None -> t.simples - | Some _ -> Simple.Set.add simple t.simples + | Id -> t.simples + | _ -> Simple.Set.add simple t.simples in let t = { t with simples; } in Simple.pattern_match simple @@ -92,10 +92,10 @@ let add_continuation t continuation = let from_simple simple = let simples = match Simple.coercion simple with - | None -> + | 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 -> @@ -200,11 +200,11 @@ module Import_map = struct | simple -> simple | exception Not_found -> begin match Simple.coercion simple with - | None -> + | Id -> Simple.pattern_match simple ~name:(fun n -> Simple.name (name t n)) ~const:(fun c -> Simple.const (const t c)) - | Some _coercion -> simple + | _ -> simple end let closure_var_is_used t var = diff --git a/middle_end/flambda/compilenv_deps/coercion.ml b/middle_end/flambda/compilenv_deps/coercion.ml index 4a675a4f4285..f71a0f29fbe3 100644 --- a/middle_end/flambda/compilenv_deps/coercion.ml +++ b/middle_end/flambda/compilenv_deps/coercion.ml @@ -12,15 +12,63 @@ (* *) (**************************************************************************) -type t = unit - -let id = () -let is_id () = true -let inverse () = () -let compose () ~newer:() = () -let print ppf () = Format.fprintf ppf "id" -let equal () () = true -let hash () = 0 - -let unroll_to () = None -let depth () = 1 +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 index 0dfc1118f294..a08d54b7013e 100644 --- a/middle_end/flambda/compilenv_deps/coercion.mli +++ b/middle_end/flambda/compilenv_deps/coercion.mli @@ -14,15 +14,22 @@ [@@@ocaml.warning "+a-4-30-40-41-42"] -type t +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 -> newer: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 unroll_to : t -> int option -val depth : 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 74bd8464143a..837933a92986 100644 --- a/middle_end/flambda/compilenv_deps/flambda_colours.ml +++ b/middle_end/flambda/compilenv_deps/flambda_colours.ml @@ -55,6 +55,8 @@ let continuation_annotation () = (C.fg_256 202) ^ (C.bg_256 237) let name_abstraction () = C.fg_256 172 +let rec_info () = C.fg_256 249 + let coercion () = C.fg_256 243 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 b2e661c94fa9..6bfacfc74bc1 100644 --- a/middle_end/flambda/compilenv_deps/flambda_colours.mli +++ b/middle_end/flambda/compilenv_deps/flambda_colours.mli @@ -53,6 +53,8 @@ val continuation_annotation : unit -> string val name_abstraction : unit -> string +val rec_info : unit -> string + val coercion : unit -> string val elide : unit -> string diff --git a/middle_end/flambda/compilenv_deps/rec_info.ml b/middle_end/flambda/compilenv_deps/rec_info.ml index 3708080647f1..da6b4f446e42 100644 --- a/middle_end/flambda/compilenv_deps/rec_info.ml +++ b/middle_end/flambda/compilenv_deps/rec_info.ml @@ -13,55 +13,25 @@ (**************************************************************************) [@@@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 initial = () -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 = create ~depth:0 ~unroll_to:None - -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 fe43ec929616..c644cc4716a5 100644 --- a/middle_end/flambda/compilenv_deps/rec_info.mli +++ b/middle_end/flambda/compilenv_deps/rec_info.mli @@ -13,20 +13,11 @@ (**************************************************************************) [@@@ocaml.warning "+a-4-30-40-41-42"] -(* -type t +type t = unit 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 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 41083a48d8e5..f1eb3b411259 100644 --- a/middle_end/flambda/compilenv_deps/reg_width_things.ml +++ b/middle_end/flambda/compilenv_deps/reg_width_things.ml @@ -549,8 +549,8 @@ module Simple = struct let [@inline always] coercion t = let flags = Id.flags t in - if flags = simple_flags then Some ((find_data t).coercion) - else None + if flags = simple_flags then (find_data t).coercion + else Coercion.id module T0 = struct let compare = Id.compare @@ -564,12 +564,9 @@ module Simple = struct ~const:(fun cst -> Const.print ppf cst) in match coercion t with - | None -> print ppf t - | Some coercion -> - Format.fprintf ppf "@[\ - @[(simple@ %a)@] \ - @[(coercion@ %a)@]\ - @]" + | Id -> print ppf t + | Non_id _ as coercion -> + Format.fprintf ppf "@[(coerce@ %a@ %a)@]" print t Coercion.print coercion @@ -587,12 +584,12 @@ module Simple = struct if Coercion.is_id new_coercion then t else match coercion t with - | None -> + | Id -> let data : Simple_data.t = { simple = t; coercion = new_coercion; } in Table.add !grand_table_of_simples data - | Some _ -> + | Non_id _ -> Misc.fatal_errorf "Cannot add [Coercion] to [Simple] %a that already \ - has [Coercion]" + 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 e1d0eed0300d..26925f102200 100644 --- a/middle_end/flambda/compilenv_deps/reg_width_things.mli +++ b/middle_end/flambda/compilenv_deps/reg_width_things.mli @@ -154,7 +154,7 @@ module Simple : sig val const : Const.t -> t - val coercion : t -> Coercion.t option + val coercion : t -> Coercion.t val with_coercion : t -> Coercion.t -> t diff --git a/middle_end/flambda/inlining/inlining_decision.ml b/middle_end/flambda/inlining/inlining_decision.ml index c51005b5c117..2497007d1b66 100644 --- a/middle_end/flambda/inlining/inlining_decision.ml +++ b/middle_end/flambda/inlining/inlining_decision.ml @@ -218,7 +218,7 @@ end (* CR mshinwell: This parameter needs to be configurable *) let max_rec_depth = 1 -let make_decision_for_call_site denv ~function_decl_coercion +let make_decision_for_call_site denv ~function_decl_rec_info:() ~apply_inlining_state (inline : Inline_attribute.t) : Call_site_decision.t = if (not (DE.can_inline denv)) then @@ -227,28 +227,19 @@ let make_decision_for_call_site denv ~function_decl_coercion match inline with | Never_inline -> Never_inline_attribute | Default_inline | Unroll _ | Always_inline | Hint_inline -> - match Coercion.unroll_to function_decl_coercion with - | Some unroll_to -> - if Coercion.depth function_decl_coercion >= unroll_to then - Unrolling_depth_exceeded - else + if Inlining_state.is_depth_exceeded apply_inlining_state + then + Max_inlining_depth_exceeded + else + match inline with + | Never_inline -> assert false + | Default_inline -> Inline { attribute = None; unroll_to = None; } - | None -> - 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 Coercion.depth function_decl_coercion >= max_rec_depth then - Recursion_depth_exceeded - else - Inline { attribute = None; unroll_to = None; } - | Unroll unroll_to -> - let unroll_to = - Coercion.depth function_decl_coercion + unroll_to - in - Inline { attribute = Some Unroll; unroll_to = Some unroll_to; } - | Always_inline | Hint_inline -> - Inline { attribute = Some Always; unroll_to = None; } + | Unroll unroll_to -> + Inline { attribute = Some Unroll; unroll_to = Some unroll_to; } + | Always_inline | Hint_inline -> + Inline { attribute = Some Always; unroll_to = None; } + +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_decision.mli b/middle_end/flambda/inlining/inlining_decision.mli index 2e7f438e168e..3ea6f4106e79 100644 --- a/middle_end/flambda/inlining/inlining_decision.mli +++ b/middle_end/flambda/inlining/inlining_decision.mli @@ -67,7 +67,7 @@ end val make_decision_for_call_site : Downwards_env.t - -> function_decl_coercion:Coercion.t + -> function_decl_rec_info:Rec_info.t -> apply_inlining_state:Inlining_state.t -> Inline_attribute.t -> Call_site_decision.t diff --git a/middle_end/flambda/inlining/inlining_transforms.ml b/middle_end/flambda/inlining/inlining_transforms.ml index 62aa30f56740..7db91d9a4827 100644 --- a/middle_end/flambda/inlining/inlining_transforms.ml +++ b/middle_end/flambda/inlining/inlining_transforms.ml @@ -41,8 +41,7 @@ let make_inlined_body ~callee ~unroll_to ~params ~args ~my_closure ~body in let callee = (* CR xclerc for xclerc: build the proper coercion. *) - Simple.compose_coercion callee - ~newer_coercion:(ignore unroll_to; Some Coercion.id) + Simple.apply_coercion callee (ignore unroll_to; Coercion.id) |> Option.get (* CR mshinwell: improve *) in Expr.apply_name_permutation diff --git a/middle_end/flambda/simplify/simplify_apply_expr.rec.ml b/middle_end/flambda/simplify/simplify_apply_expr.rec.ml index a4e7eaf3ea93..d24f9a703a59 100644 --- a/middle_end/flambda/simplify/simplify_apply_expr.rec.ml +++ b/middle_end/flambda/simplify/simplify_apply_expr.rec.ml @@ -101,11 +101,11 @@ let simplify_direct_full_application dacc apply function_decl_opt "[@inlined] attribute was not used on this function application \ (the optimizer decided not to inline the function given its definition)"; None - | Some (function_decl, function_decl_coercion) -> + | Some function_decl -> let apply_inlining_state = Apply.inlining_state apply in let decision = Inlining_decision.make_decision_for_call_site (DA.denv dacc) - ~function_decl_coercion + ~function_decl_rec_info:() ~apply_inlining_state (Apply.inline apply) in @@ -587,14 +587,6 @@ let simplify_function_call dacc apply ~callee_ty | Indirect_unknown_arity | Indirect_known_arity _ -> None in - (* CR mshinwell: This should go in Typing_env (ditto logic for Coercion - in Simplify_simple *) - let function_decl_coercion = - let coercion = I.coercion inlinable in - match Simple.coercion (Apply.callee apply) with - | None -> coercion - | Some newer -> Coercion.compose coercion ~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 @@ -603,7 +595,7 @@ let simplify_function_call 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_coercion)) + (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.rec.ml b/middle_end/flambda/simplify/simplify_set_of_closures.rec.ml index bf122fbb4f3e..26472037560c 100644 --- a/middle_end/flambda/simplify/simplify_set_of_closures.rec.ml +++ b/middle_end/flambda/simplify/simplify_set_of_closures.rec.ml @@ -26,7 +26,7 @@ open! Simplify_import file tail recursive, although it probably isn't necessary, as excessive levels of nesting of functions seems unlikely. *) -let function_decl_type ~pass denv function_decl ?code_id ?params_and_body coercion = +let function_decl_type ~pass denv function_decl ?code_id ?params_and_body rec_info = let decision = Inlining_decision.make_decision_for_function_declaration denv ?params_and_body function_decl @@ -40,7 +40,7 @@ let function_decl_type ~pass denv function_decl ?code_id ?params_and_body coerci ~code_id ~dbg:(FD.dbg function_decl) ~is_tupled:(FD.is_tupled function_decl) - ~coercion + ~rec_info else T.create_non_inlinable_function_declaration ~code_id @@ -144,7 +144,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: [coercion] may be wrong. *) Closure_id.Map.map (fun function_decl -> let new_code_id = Code_id.Map.find (FD.code_id function_decl) @@ -154,7 +153,7 @@ end = struct ~pass:Inlining_report.Before_simplify denv function_decl ~code_id:new_code_id - Coercion.id) + ()) (Function_declarations.funs function_decls) in Closure_id.Map.mapi (fun closure_id _function_decl -> @@ -466,7 +465,7 @@ let simplify_function context ~used_closure_vars ~shareable_constants function_decl_type ~pass:Inlining_report.After_simplify (DA.denv dacc_after_body) function_decl - ~params_and_body Coercion.id + ~params_and_body () in { function_decl; new_code_id; diff --git a/middle_end/flambda/simplify/simplify_simple.ml b/middle_end/flambda/simplify/simplify_simple.ml index 308cceb13829..1ba265bf658d 100644 --- a/middle_end/flambda/simplify/simplify_simple.ml +++ b/middle_end/flambda/simplify/simplify_simple.ml @@ -25,21 +25,15 @@ module TE = T.Typing_env (* CR mshinwell: avoid having two functions *) let type_for_simple simple kind : _ Or_bottom.t = let ty = T.alias_type_of kind simple in - match Simple.coercion simple with - | None -> Ok (simple, ty) - | Some coercion -> - match T.apply_coercion ty coercion with - | Bottom -> Bottom - | Ok ty -> Ok (simple, ty) + match T.apply_coercion ty (Simple.coercion simple) with + | Bottom -> Bottom + | Ok ty -> Ok (simple, ty) let type_for_simple' simple kind : _ Or_bottom.t * _ = let ty = T.alias_type_of kind simple in - match Simple.coercion simple with - | None -> Ok simple, ty - | Some coercion -> - match T.apply_coercion ty coercion with - | Bottom -> Bottom, T.bottom (T.kind ty) - | Ok ty -> Ok simple, ty + match T.apply_coercion ty (Simple.coercion simple) with + | Bottom -> Bottom, T.bottom (T.kind ty) + | Ok ty -> Ok simple, ty let simplify_simple dacc simple ~min_name_mode : _ Or_bottom.t * _ = let typing_env = DA.typing_env dacc in diff --git a/middle_end/flambda/types/env/aliases.ml b/middle_end/flambda/types/env/aliases.ml index 6bb85d959227..6b3cb5b8c85f 100644 --- a/middle_end/flambda/types/env/aliases.ml +++ b/middle_end/flambda/types/env/aliases.ml @@ -14,303 +14,268 @@ [@@@ocaml.warning "+a-4-30-40-41-42"] -type 'a coercion_to_canonical = { - coercion_to_canonical : 'a; +type coercion_to_canonical = { + coercion_to_canonical : Coercion.t; } [@@ocaml.unboxed] -module type Coercion = sig - type t - val equal : t -> t -> bool - val inverse : t -> t - val id : t - val is_id : t -> bool - val compose : t -> newer:t -> t - val print : Format.formatter -> t -> unit -end +let print_coercion_to_canonical ppf { coercion_to_canonical; } = + Coercion.print ppf coercion_to_canonical -module type Element = sig - type t - val name : Name.t -> t - val is_var : t -> bool - val without_coercion : t -> t - val pattern_match - : t - -> name:(Reg_width_things.Name.t -> 'a) - -> const:(Reg_width_things.Const.t -> 'a) - -> 'a - include Identifiable.S with type t := t -end +let equal_coercion_to_canonical c1 c2 = + Coercion.equal c1.coercion_to_canonical c2.coercion_to_canonical -module type Export = sig - type e - type t - val add : t -> e -> t - val empty : t - val to_ids_for_export : t -> Ids_for_export.t - module Import_map : sig - type t - val of_import_map : Ids_for_export.Import_map.t -> t - val simple : t -> e -> e - end -end +type map_to_canonical = coercion_to_canonical Simple.Map.t + +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 + Simple.print elt + Coercion.print coercion1 + Coercion.print coercion2 -module Make (C : Coercion) (E : Element) (Exp : Export with type e = E.t) = struct - - type nonrec coercion_to_canonical = C.t coercion_to_canonical - - let print_coercion_to_canonical ppf { coercion_to_canonical; } = - C.print ppf coercion_to_canonical - - let equal_coercion_to_canonical c1 c2 = - C.equal c1.coercion_to_canonical c2.coercion_to_canonical - - type map_to_canonical = coercion_to_canonical E.Map.t - - 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 - E.print elt - C.print coercion1 - C.print coercion2 - - let map_inter map1 map2 = - E.Map.merge (fun elt coercion1 coercion2 -> - match coercion1, coercion2 with - | None, None | Some _, None | None, Some _ -> None - | Some { coercion_to_canonical = coercion1; }, Some { coercion_to_canonical = coercion2; } -> - if C.equal coercion1 coercion2 then - Some { coercion_to_canonical = coercion1; } - else - fatal_inconsistent ~func_name:"Aliases.map_inter" elt coercion1 coercion2) - map1 - map2 - - let map_union map1 map2 = - E.Map.union (fun elt coercion1 coercion2 -> - match coercion1, coercion2 with - | { coercion_to_canonical = coercion1; }, { coercion_to_canonical = coercion2; } -> - if C.equal coercion1 coercion2 then +let map_inter map1 map2 = + Simple.Map.merge (fun elt coercion1 coercion2 -> + match coercion1, coercion2 with + | None, None | Some _, None | None, Some _ -> None + | Some { coercion_to_canonical = coercion1; }, Some { coercion_to_canonical = coercion2; } -> + if Coercion.equal coercion1 coercion2 then Some { coercion_to_canonical = coercion1; } else - fatal_inconsistent ~func_name:"Aliases.map_union" elt coercion1 coercion2) - map1 - map2 - - module Aliases_of_canonical_element : sig - type t + fatal_inconsistent ~func_name:"Aliases.map_inter" elt coercion1 coercion2) + map1 + map2 + +let map_union map1 map2 = + Simple.Map.union (fun elt coercion1 coercion2 -> + match coercion1, coercion2 with + | { coercion_to_canonical = coercion1; }, { coercion_to_canonical = coercion2; } -> + if Coercion.equal coercion1 coercion2 then + Some { coercion_to_canonical = coercion1; } + else + fatal_inconsistent ~func_name:"Aliases.map_union" elt coercion1 coercion2) + map1 + map2 + +module Aliases_of_canonical_element : sig + type t - val print : Format.formatter -> t -> unit + val print : Format.formatter -> t -> unit - val invariant : t -> unit + val invariant : t -> unit - val empty : t - val is_empty : t -> bool + val empty : t + val is_empty : t -> bool - val add : t -> E.t -> coercion_to_canonical:C.t -> Name_mode.t -> t + val add : t -> Simple.t -> coercion_to_canonical:Coercion.t -> Name_mode.t -> t - val find_earliest_candidates - : t - -> min_name_mode:Name_mode.t - -> map_to_canonical option + val find_earliest_candidates + : t + -> min_name_mode:Name_mode.t + -> map_to_canonical option - val all : t -> map_to_canonical + val all : t -> map_to_canonical - val mem : t -> E.t -> bool + val mem : t -> Simple.t -> bool - val union : t -> t -> t - val inter : t -> t -> t + val union : t -> t -> t + val inter : t -> t -> t - val import : (E.t -> E.t) -> t -> t + val import : (Simple.t -> Simple.t) -> t -> t - val merge : t -> t -> t + val merge : t -> t -> t - val move_variables_to_mode_in_types : t -> t + val move_variables_to_mode_in_types : t -> t - val compose : t -> newer:C.t -> t - end = struct - type t = { - aliases : map_to_canonical Name_mode.Map.t; - all : map_to_canonical; - } + val compose : t -> newer:Coercion.t -> t +end = struct + type t = { + aliases : map_to_canonical Name_mode.Map.t; + all : map_to_canonical; + } - 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 -> - E.Map.union (fun elt _coercion1 _coercion2 -> - Misc.fatal_errorf "[Aliases_of_canonical_element.invariant]: \ - element %a appears in several modes" - E.print elt) - map - acc) - aliases - E.Map.empty - in - (* [all] is the union of all elements in [aliases] *) - if E.Map.equal equal_coercion_to_canonical all aliases_union then - () - else - Misc.fatal_errorf "[Aliases_of_canonical_element.invariant]: \ - [aliases] and [all] are not consistent" + 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 -> + Simple.Map.union (fun elt _coercion1 _coercion2 -> + Misc.fatal_errorf "[Aliases_of_canonical_element.invariant]: \ + element %a appears in several modes" + Simple.print elt) + map + acc) + aliases + Simple.Map.empty + in + (* [all] is the union of all elements in [aliases] *) + if Simple.Map.equal equal_coercion_to_canonical 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.Map.print print_coercion_to_canonical) ppf aliases + + let empty = { + aliases = Name_mode.Map.empty; + all = Simple.Map.empty; + } - let print ppf { aliases; all = _; } = - Name_mode.Map.print (E.Map.print print_coercion_to_canonical) ppf aliases + let is_empty t = Simple.Map.is_empty t.all - let empty = { - aliases = Name_mode.Map.empty; - all = E.Map.empty; + let add t elt ~coercion_to_canonical name_mode = + if Simple.Map.mem elt t.all then begin + Misc.fatal_errorf "%a already added to [Aliases_of_canonical_element]: \ + %a" + Simple.print elt + print t + end; + let aliases = + Name_mode.Map.update name_mode + (function + | None -> Some (Simple.Map.singleton elt { coercion_to_canonical; }) + | Some elts -> + if !Clflags.flambda_invariant_checks then begin + assert (not (Simple.Map.mem elt elts)) + end; + Some (Simple.Map.add elt { coercion_to_canonical; } elts)) + t.aliases + in + let all = Simple.Map.add elt { coercion_to_canonical; } t.all in + { aliases; + all; } - let is_empty t = E.Map.is_empty t.all - - let add t elt ~coercion_to_canonical name_mode = - if E.Map.mem elt t.all then begin - Misc.fatal_errorf "%a already added to [Aliases_of_canonical_element]: \ - %a" - E.print elt - print t - end; - let aliases = - Name_mode.Map.update name_mode - (function - | None -> Some (E.Map.singleton elt { coercion_to_canonical; }) - | Some elts -> - if !Clflags.flambda_invariant_checks then begin - assert (not (E.Map.mem elt elts)) - end; - Some (E.Map.add elt { coercion_to_canonical; } elts)) - t.aliases - in - let all = E.Map.add elt { coercion_to_canonical; } t.all in + let find_earliest_candidates t ~min_name_mode = + Name_mode.Map.fold (fun order aliases res_opt -> + match res_opt with + | Some _ -> res_opt + | None -> + begin match + Name_mode.compare_partial_order + order min_name_mode + with + | None -> None + | Some result -> + if result >= 0 then Some aliases else None + end) + t.aliases + None + + let mem t elt = + Simple.Map.mem elt t.all + + let all t = t.all + + let union t1 t2 = + let aliases : map_to_canonical Name_mode.Map.t= + Name_mode.Map.union (fun _order elts1 elts2 -> + Some (map_union elts1 elts2)) + t1.aliases t2.aliases + in + let t = { aliases; - all; + all = map_union t1.all t2.all; } + in + invariant t; (* CR xclerc for xclerc: not guaranteed to hold *) + t - let find_earliest_candidates t ~min_name_mode = - Name_mode.Map.fold (fun order aliases res_opt -> - match res_opt with - | Some _ -> res_opt - | None -> - begin match - Name_mode.compare_partial_order - order min_name_mode - with - | None -> None - | Some result -> - if result >= 0 then Some aliases else None - end) - t.aliases - None - - let mem t elt = - E.Map.mem elt t.all - - let all t = t.all - - let union t1 t2 = - let aliases : map_to_canonical Name_mode.Map.t= - Name_mode.Map.union (fun _order elts1 elts2 -> - Some (map_union elts1 elts2)) - t1.aliases t2.aliases - in - let t = - { aliases; - all = map_union t1.all t2.all; - } - in - 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 (map_inter elts1 elts2)) - t1.aliases t2.aliases - in - let t = - { aliases; - all = map_inter t1.all t2.all; - } - in - invariant t; - t - - let import import_simple { aliases; all } = - let map_simple elts = - E.Map.fold (fun elt coercion acc -> - E.Map.add (import_simple elt) coercion acc) - elts - E.Map.empty - in - let aliases = Name_mode.Map.map map_simple aliases in - let all = map_simple 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 map1 map2 -> - Some (map_union map1 map2) - ) - t1.aliases - t2.aliases - 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 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 (map_inter elts1 elts2)) + t1.aliases t2.aliases + in + let t = + { aliases; + all = map_inter t1.all t2.all; + } + in + invariant t; + t + + let import import_simple { aliases; all } = + let map_simple elts = + Simple.Map.fold (fun elt coercion acc -> + Simple.Map.add (import_simple elt) coercion acc) + elts + Simple.Map.empty + in + let aliases = Name_mode.Map.map map_simple aliases in + let all = map_simple all in + let t = { aliases; all } in + invariant t; (* CR xclerc for xclerc: not guaranteed to hold *) + t - let compose { aliases; all; } ~newer = - let f m = - E.Map.map - (fun { coercion_to_canonical; } -> - { coercion_to_canonical = C.compose coercion_to_canonical ~newer; }) - m - in - let aliases = Name_mode.Map.map f aliases in - let all = f all in - { aliases; all; } - - let move_variables_to_mode_in_types { aliases; all; } = - let (no_vars_aliases, all_variables) = - Name_mode.Map.fold (fun mode aliases (no_vars_aliases, all_variables) -> - let key_is_var key _ = E.is_var key in - let (vars, non_vars) = E.Map.partition key_is_var aliases in - let no_vars_aliases = - if E.Map.is_empty non_vars then no_vars_aliases - else Name_mode.Map.add mode non_vars no_vars_aliases - in - no_vars_aliases, map_union vars all_variables) - aliases - (Name_mode.Map.empty, E.Map.empty) - in - let aliases = - if Name_mode.Map.mem Name_mode.in_types no_vars_aliases - then Misc.fatal_errorf "move_variables_to_mode_in_types: \ - The following non-vars have mode In_types:@ %a" - (E.Map.print print_coercion_to_canonical) - (Name_mode.Map.find Name_mode.in_types no_vars_aliases) - else - if E.Map.is_empty all_variables then no_vars_aliases - else Name_mode.Map.add Name_mode.in_types all_variables no_vars_aliases - in - { aliases; all; } - end + let merge t1 t2 = + let aliases = + Name_mode.Map.union (fun _mode map1 map2 -> + Some (map_union map1 map2) + ) + t1.aliases + t2.aliases + 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; } ~newer = + let f m = + Simple.Map.map + (fun { coercion_to_canonical; } -> + (* CR lmaurer: This seems like the wrong way around to me, but + possibly only because I'm confused. At least, this function and/or + its argument should have a more descriptive name to make it + clearer what's going on - [newer] is not descriptive! *) + { coercion_to_canonical = + Coercion.compose_exn coercion_to_canonical ~then_:newer; }) + m + in + let aliases = Name_mode.Map.map f aliases in + let all = f all in + { aliases; all; } + + let move_variables_to_mode_in_types { aliases; all; } = + let (no_vars_aliases, all_variables) = + Name_mode.Map.fold (fun mode aliases (no_vars_aliases, all_variables) -> + let key_is_var key _ = Simple.is_var key in + let (vars, non_vars) = Simple.Map.partition key_is_var aliases in + let no_vars_aliases = + if Simple.Map.is_empty non_vars then no_vars_aliases + else Name_mode.Map.add mode non_vars no_vars_aliases + in + no_vars_aliases, map_union vars all_variables) + aliases + (Name_mode.Map.empty, Simple.Map.empty) + in + let aliases = + if Name_mode.Map.mem Name_mode.in_types no_vars_aliases + then Misc.fatal_errorf "move_variables_to_mode_in_types: \ + The following non-vars have mode In_types:@ %a" + (Simple.Map.print print_coercion_to_canonical) + (Name_mode.Map.find Name_mode.in_types no_vars_aliases) + else + if Simple.Map.is_empty all_variables then no_vars_aliases + else Name_mode.Map.add Name_mode.in_types all_variables no_vars_aliases + in + { aliases; all; } +end type t = { - canonical_elements : (E.t * coercion_to_canonical) E.Map.t; + canonical_elements : (Simple.t * coercion_to_canonical) Simple.Map.t; (* Canonical elements that have no known aliases are not included in [canonical_elements]. *) - aliases_of_canonical_elements : Aliases_of_canonical_element.t E.Map.t; + aliases_of_canonical_elements : Aliases_of_canonical_element.t Simple.Map.t; (* For [elt |-> aliases] in [aliases_of_canonical_elements], then [aliases] never includes [elt]. *) (* CR mshinwell: check this always holds *) - binding_times_and_modes : Binding_time.With_name_mode.t E.Map.t; + binding_times_and_modes : Binding_time.With_name_mode.t Simple.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 @@ -346,9 +311,16 @@ type t = { let print ppf { canonical_elements; aliases_of_canonical_elements; binding_times_and_modes; } = let print_element_and_coercion ppf (elt, coercion) = - Format.fprintf ppf "%a (%a)" - E.print elt + Format.fprintf ppf "@[(\ + %a@ \ + @[@<0>%s(coercion@ %a)@<0>%s@]\ + )@]" + Simple.print elt + (if Coercion.is_id coercion.coercion_to_canonical + then Flambda_colours.elide () + else Flambda_colours.normal ()) print_coercion_to_canonical coercion + (Flambda_colours.normal ()) in Format.fprintf ppf "@[(\ @@ -356,49 +328,49 @@ let print ppf { canonical_elements; aliases_of_canonical_elements; @[(aliases_of_canonical_elements@ %a)@]@ \ @[(binding_times_and_modes@ %a)@]\ )@]" - (E.Map.print print_element_and_coercion) canonical_elements - (E.Map.print Aliases_of_canonical_element.print) + (Simple.Map.print print_element_and_coercion) canonical_elements + (Simple.Map.print Aliases_of_canonical_element.print) aliases_of_canonical_elements - (E.Map.print Binding_time.With_name_mode.print) + (Simple.Map.print Binding_time.With_name_mode.print) binding_times_and_modes let defined_earlier t alias ~than = - let info1 = E.Map.find alias t.binding_times_and_modes in - let info2 = E.Map.find than t.binding_times_and_modes in + let info1 = Simple.Map.find alias t.binding_times_and_modes in + let info2 = Simple.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 name_mode t elt = Binding_time.With_name_mode.name_mode - (E.Map.find elt t.binding_times_and_modes) + (Simple.Map.find elt t.binding_times_and_modes) let invariant t = if !Clflags.flambda_invariant_checks then begin let _all_aliases : map_to_canonical = - E.Map.fold (fun canonical_element aliases all_aliases -> + Simple.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 (E.Map.for_all (fun elt _coercion -> + if not (Simple.Map.for_all (fun elt _coercion -> 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" - E.print canonical_element + Simple.print canonical_element print t end; - if E.Map.mem canonical_element aliases then begin + if Simple.Map.mem canonical_element aliases then begin Misc.fatal_errorf "Canonical element %a occurs in alias set:@ %a" - E.print canonical_element - (E.Map.print print_coercion_to_canonical) aliases + Simple.print canonical_element + (Simple.Map.print print_coercion_to_canonical) aliases end; - if not (E.Map.is_empty (map_inter aliases all_aliases)) then + if not (Simple.Map.is_empty (map_inter aliases all_aliases)) then begin Misc.fatal_errorf "Overlapping alias sets:@ %a" print t end; map_union aliases all_aliases) t.aliases_of_canonical_elements - E.Map.empty + Simple.Map.empty in () end @@ -406,30 +378,29 @@ let invariant t = let empty = { (* CR mshinwell: Rename canonical_elements, maybe to aliases_to_canonical_elements. *) - canonical_elements = E.Map.empty; - aliases_of_canonical_elements = E.Map.empty; - binding_times_and_modes = E.Map.empty; + canonical_elements = Simple.Map.empty; + aliases_of_canonical_elements = Simple.Map.empty; + binding_times_and_modes = Simple.Map.empty; } type canonical = - | Is_canonical of E.t + | Is_canonical | Alias_of_canonical of { - element : E.t; - canonical_element : E.t; + canonical_element : Simple.t; coercion_to_canonical : coercion_to_canonical; } let canonical t element : canonical = - match E.Map.find element t.canonical_elements with - | exception Not_found -> Is_canonical element + match Simple.Map.find element t.canonical_elements with + | exception Not_found -> Is_canonical | canonical_element, coercion_to_canonical -> if !Clflags.flambda_invariant_checks then begin - assert (not (E.equal element canonical_element)) + assert (not (Simple.equal element canonical_element)) end; - Alias_of_canonical { element; canonical_element; coercion_to_canonical; } + Alias_of_canonical { canonical_element; coercion_to_canonical; } let get_aliases_of_canonical_element t ~canonical_element = - match E.Map.find canonical_element t.aliases_of_canonical_elements with + match Simple.Map.find canonical_element t.aliases_of_canonical_elements with | exception Not_found -> Aliases_of_canonical_element.empty | aliases -> aliases @@ -475,8 +446,8 @@ let get_aliases_of_canonical_element t ~canonical_element = *) let add_alias_between_canonical_elements t ~canonical_element ~coercion_to_canonical:{ coercion_to_canonical; } ~to_be_demoted = - if E.equal canonical_element to_be_demoted then begin - if C.is_id coercion_to_canonical then begin + 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 to itself with a non-identity coercion" @@ -490,13 +461,13 @@ let add_alias_between_canonical_elements t ~canonical_element ~coercion_to_canon end; let canonical_elements = t.canonical_elements - |> E.Map.fold (fun alias { coercion_to_canonical = coercion_to_to_be_demoted; } canonical_elements -> + |> Simple.Map.fold (fun alias { coercion_to_canonical = coercion_to_to_be_demoted; } canonical_elements -> let coercion_to_canonical = - C.compose coercion_to_to_be_demoted ~newer:coercion_to_canonical + Coercion.compose_exn coercion_to_to_be_demoted ~then_:coercion_to_canonical in - E.Map.add alias (canonical_element, { coercion_to_canonical; }) canonical_elements) + Simple.Map.add alias (canonical_element, { coercion_to_canonical; }) canonical_elements) (Aliases_of_canonical_element.all aliases_of_to_be_demoted) - |> E.Map.add to_be_demoted (canonical_element, { coercion_to_canonical; }) + |> Simple.Map.add to_be_demoted (canonical_element, { coercion_to_canonical; }) in let aliases_of_canonical_element = get_aliases_of_canonical_element t ~canonical_element @@ -519,8 +490,8 @@ let add_alias_between_canonical_elements t ~canonical_element ~coercion_to_canon in let aliases_of_canonical_elements = t.aliases_of_canonical_elements - |> E.Map.remove to_be_demoted - |> E.Map.add (* replace *) canonical_element aliases + |> Simple.Map.remove to_be_demoted + |> Simple.Map.add (* replace *) canonical_element aliases in let res = { canonical_elements; @@ -530,209 +501,209 @@ let add_alias_between_canonical_elements t ~canonical_element ~coercion_to_canon invariant res; res -type to_be_demoted = { - canonical_element : E.t; - to_be_demoted : E.t; -} +type to_be_demoted = Demote_element1 | Demote_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_element2 else Demote_element1 (* CR mshinwell: add submodule *) type add_result = { t : t; - canonical_element : E.t; - alias_of : E.t; - coerce_alias_of_to_canonical_element : C.t; + canonical_element : Simple.t; + alias_of_demoted_element : Simple.t; + coercion_from_alias_of_demoted_to_canonical : Coercion.t; } -let invariant_add_result ~original_t { canonical_element; alias_of; t; coerce_alias_of_to_canonical_element = _; } = +let invariant_add_result ~original_t { canonical_element; alias_of_demoted_element; t; coercion_from_alias_of_demoted_to_canonical = _; } = if !Clflags.flambda_invariant_checks then begin invariant t; - if not (E.equal canonical_element alias_of) then begin - if not (defined_earlier t canonical_element ~than:alias_of) then begin + if not (Simple.equal canonical_element alias_of_demoted_element) then begin + 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" - E.print canonical_element - E.print alias_of + Simple.print canonical_element + Simple.print alias_of_demoted_element print original_t print t end end end -let add_alias t ~element1 ~coerce_from_element2_to_element1 ~element2 = - let wrap ~canonical_element ~coercion_to_canonical ~to_be_demoted = - let t = +let add_alias t ~element1 ~coercion_from_element2_to_element1 ~element2 = + 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 = + let canonical_element, to_be_demoted, alias_of_demoted_element, + coercion_from_demoted_to_canonical, + coercion_from_alias_of_demoted_to_demoted = + let which_element = + choose_canonical_element_to_be_demoted t + ~canonical_element1 ~canonical_element2 + in + match which_element with + | Demote_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_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_to_canonical; } + ~coercion_to_canonical: + { coercion_to_canonical = coercion_from_demoted_to_canonical; } ~to_be_demoted in + let coercion_from_alias_of_demoted_to_canonical = + Coercion.compose_exn + coercion_from_alias_of_demoted_to_demoted + ~then_:coercion_from_demoted_to_canonical + in { t; canonical_element; - (* CR mshinwell: [alias_of] is not a good name. *) - alias_of = to_be_demoted; - coerce_alias_of_to_canonical_element = coercion_to_canonical; + alias_of_demoted_element; + coercion_from_alias_of_demoted_to_canonical; } 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 + | 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 - let coercion_to_canonical = - if E.equal to_be_demoted canonical_element1 then - (* canonical_element1=element1 <--[c]-- canonical_element2=element2 - ~> - canonical_element2 <--[inverse(c)]-- canonical_element1 *) - C.inverse coerce_from_element2_to_element1 - else - (* canonical_element1=element1 <--[c]-- canonical_element2=element2 - ~> - canonical_element1 <--[c]-- canonical_element2 *) - coerce_from_element2_to_element1 in - wrap ~canonical_element ~coercion_to_canonical ~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 { - element = _element1; canonical_element = canonical_element1; - coercion_to_canonical = { coercion_to_canonical = coercion_from_element1_to_canonical_element1; }; + coercion_to_canonical = { + coercion_to_canonical = coercion_from_element1_to_canonical_element1; + }; }, - Is_canonical canonical_element2 -> - let { canonical_element; to_be_demoted; } = - choose_canonical_element_to_be_demoted t ~canonical_element1 - ~canonical_element2 + 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 coercion_to_canonical = - if E.equal to_be_demoted canonical_element1 then - (* canonical_element1 <--[c1]-- element1 - + - element1 <--[c]-- canonical_element2=element2 - ~> - canonical_element2 <--[compose(inverse(c1),inverse(c))]-- canonical_element1 *) - C.compose - (C.inverse coercion_from_element1_to_canonical_element1) - ~newer:(C.inverse coerce_from_element2_to_element1) - else - (* canonical_element1 <--[c1]-- element1 - + - element1 <--[c]-- canonical_element2=element2 - ~> - canonical_element1 <--[compose(c, c1)]-- canonical_element2 *) - C.compose - coerce_from_element2_to_element1 - ~newer:coercion_from_element1_to_canonical_element1 - in - wrap ~canonical_element ~coercion_to_canonical ~to_be_demoted - | Is_canonical canonical_element1, + 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 { - element = _element2; canonical_element = canonical_element2; - coercion_to_canonical = { coercion_to_canonical = coercion_from_element2_to_canonical_element2; }; + coercion_to_canonical = { + coercion_to_canonical = coercion_from_element2_to_canonical_element2; + }; } -> - let { canonical_element; to_be_demoted; } = - choose_canonical_element_to_be_demoted t ~canonical_element1 - ~canonical_element2 - in - let coercion_to_canonical = - if E.equal to_be_demoted canonical_element1 then - (* canonical_element1=element1 - canonical_element2 <--[c2]-- element2 - + - element1 <--[c]-- element2 - ~> - canonical_element2 <--[compose(inverse(c), c2)]-- canonical_element1 - *) - C.compose - (C.inverse coerce_from_element2_to_element1) - ~newer:coercion_from_element2_to_canonical_element2 - else - (* canonical_element1=element1 - canonical_element2 <--[c2]-- element2 - + - element1 <--[c]-- element2 - ~> - canonical_element1 <--[compose(inverse(c2), c)]-- canonical_element2 *) - C.compose - (C.inverse coercion_from_element2_to_canonical_element2) - ~newer:coerce_from_element2_to_element1 + 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 - wrap ~canonical_element ~coercion_to_canonical ~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 { - element = _element1; canonical_element = canonical_element1; - coercion_to_canonical = { coercion_to_canonical = coercion_from_element1_to_canonical_element1; }; + coercion_to_canonical = { + coercion_to_canonical = coercion_from_element1_to_canonical_element1; + }; }, Alias_of_canonical { - element = _element2; canonical_element = canonical_element2; - coercion_to_canonical = { coercion_to_canonical = coercion_from_element2_to_canonical_element2; }; + coercion_to_canonical = { + coercion_to_canonical = coercion_from_element2_to_canonical_element2; + }; } -> - let { canonical_element; to_be_demoted; } = - choose_canonical_element_to_be_demoted t ~canonical_element1 - ~canonical_element2 - in - let coercion_to_canonical = - if E.equal to_be_demoted canonical_element1 then - (* canonical_element1 <--[c1]-- element1 - canonical_element2 <--[c2]-- element2 - + - element1 <--[c]-- element2 - ~> - canonical_element2 <--[compose(inverse(c1), compose(inverse(c), c2))]--canonical_element1 *) - C.compose - (C.inverse coercion_from_element1_to_canonical_element1) - ~newer:(C.compose - (C.inverse coerce_from_element2_to_element1) - ~newer:coercion_from_element2_to_canonical_element2) - else - (* canonical_element1 <--[c1]-- element1 - canonical_element2 <--[c2]-- element2 - + - element1 <--[c]-- element2 - ~> - canonical_element1 <--[compose(inverse(c2), compose(c, c1))]--canonical_element2 *) - C.compose - (C.inverse coercion_from_element2_to_canonical_element2) - ~newer:(C.compose - coerce_from_element2_to_element1 - ~newer:coercion_from_element1_to_canonical_element1) + 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 - wrap ~canonical_element ~coercion_to_canonical ~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 -let add t ~element1 ~binding_time_and_mode1 - ~coerce_from_element2_to_element1 - ~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 = E.without_coercion element1 in - let element2 = E.without_coercion 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 let t = { t with binding_times_and_modes = - E.Map.add element1 binding_time_and_mode1 - (E.Map.add element2 binding_time_and_mode2 + Simple.Map.add element1 binding_time_and_mode1 + (Simple.Map.add element2 binding_time_and_mode2 t.binding_times_and_modes); } in - let add_result = add_alias t ~element1 ~coerce_from_element2_to_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 = - E.Map.mem element t.binding_times_and_modes + Simple.Map.mem element t.binding_times_and_modes (* CR mshinwell: This needs documenting. For the moment we allow relations between canonical elements that are actually incomparable @@ -757,14 +728,14 @@ let mem t element = *) let get_canonical_element_exn t element elt_name_mode ~min_name_mode = - match E.Map.find element t.canonical_elements with + 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, { coercion_to_canonical = C.id; } + if c >= 0 then element, { coercion_to_canonical = Coercion.id; } else raise Not_found end | canonical_element, coercion_to_canonical -> @@ -783,13 +754,13 @@ Format.eprintf "looking for canonical for %a, candidate canonical %a, min order | Some at_earliest_mode -> (* Aliases_of_canonical_element.find_earliest_candidates only returns non-empty sets *) - assert (not (E.Map.is_empty at_earliest_mode)); - E.Map.fold (fun elt coercion ((min_elt, _min_coercion) as min_binding) -> + assert (not (Simple.Map.is_empty at_earliest_mode)); + Simple.Map.fold (fun elt coercion ((min_elt, _min_coercion) as min_binding) -> if defined_earlier t elt ~than:min_elt then elt, coercion else min_binding) at_earliest_mode - (E.Map.min_binding at_earliest_mode) + (Simple.Map.min_binding at_earliest_mode) | None -> raise Not_found in match @@ -804,58 +775,57 @@ Format.eprintf "looking for canonical for %a, candidate canonical %a, min order let get_aliases t element = match canonical t element with - | Is_canonical canonical_element -> + | Is_canonical -> + let canonical_element = element in let aliases = Aliases_of_canonical_element.all (get_aliases_of_canonical_element t ~canonical_element) in - E.Map.add element { coercion_to_canonical = C.id; } aliases - | Alias_of_canonical { element = _; canonical_element; coercion_to_canonical; } -> + Simple.Map.add element { coercion_to_canonical = Coercion.id; } aliases + | Alias_of_canonical { canonical_element; coercion_to_canonical; } -> if !Clflags.flambda_invariant_checks then begin - assert (not (E.equal element canonical_element)) + assert (not (Simple.equal element canonical_element)) end; let aliases = Aliases_of_canonical_element.all (get_aliases_of_canonical_element t ~canonical_element) in if !Clflags.flambda_invariant_checks then begin - assert (E.Map.mem element aliases) + assert (Simple.Map.mem element aliases) end; - E.Map.add canonical_element coercion_to_canonical aliases + Simple.Map.add canonical_element coercion_to_canonical aliases let all_ids_for_export { canonical_elements = _; aliases_of_canonical_elements = _; binding_times_and_modes; } = - E.Map.fold (fun elt _binding_time_and_mode ids -> - Exp.add ids elt) + Simple.Map.fold (fun elt _binding_time_and_mode ids -> + Ids_for_export.add_simple ids elt) binding_times_and_modes - Exp.empty - |> Exp.to_ids_for_export + Ids_for_export.empty let import import_map { canonical_elements; aliases_of_canonical_elements; binding_times_and_modes; } = - let import_map = Exp.Import_map.of_import_map import_map in - let import_simple x = Exp.Import_map.simple import_map x in + let import_simple x = Ids_for_export.Import_map.simple import_map x in let canonical_elements = - E.Map.fold (fun elt (canonical, coercion) acc -> - E.Map.add (import_simple elt) (import_simple canonical, coercion) acc) + Simple.Map.fold (fun elt (canonical, coercion) acc -> + Simple.Map.add (import_simple elt) (import_simple canonical, coercion) acc) canonical_elements - E.Map.empty + Simple.Map.empty in let aliases_of_canonical_elements = - E.Map.fold (fun canonical aliases acc -> - E.Map.add (import_simple canonical) + Simple.Map.fold (fun canonical aliases acc -> + Simple.Map.add (import_simple canonical) (Aliases_of_canonical_element.import import_simple aliases) acc) aliases_of_canonical_elements - E.Map.empty + Simple.Map.empty in let binding_times_and_modes = - E.Map.fold (fun simple binding_time_and_mode acc -> - E.Map.add (import_simple simple) binding_time_and_mode acc) + Simple.Map.fold (fun simple binding_time_and_mode acc -> + Simple.Map.add (import_simple simple) binding_time_and_mode acc) binding_times_and_modes - E.Map.empty + Simple.Map.empty in { canonical_elements; aliases_of_canonical_elements; @@ -864,14 +834,14 @@ let import import_map { canonical_elements; let merge t1 t2 = let canonical_elements = - E.Map.disjoint_union + Simple.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 *) - E.Map.union (fun _simple aliases1 aliases2 -> + 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 @@ -882,8 +852,8 @@ let merge t1 t2 = Name_mode.normal in let binding_times_and_modes = - E.Map.union (fun simple data1 data2 -> - E.pattern_match simple + Simple.Map.union (fun simple data1 data2 -> + Simple.pattern_match simple ~const:(fun _ -> assert (Binding_time.With_name_mode.equal data1 data2); Some data1) @@ -914,20 +884,22 @@ let merge t1 t2 = } let get_canonical_ignoring_name_mode t name = - let elt = E.name name in + let elt = Simple.name name in match canonical t elt with - | Is_canonical _ -> elt - | Alias_of_canonical { canonical_element; _ } -> canonical_element + | Is_canonical -> + elt, { coercion_to_canonical = Coercion.id } + | Alias_of_canonical { canonical_element; coercion_to_canonical } -> + canonical_element, coercion_to_canonical let clean_for_export { canonical_elements; aliases_of_canonical_elements; binding_times_and_modes; } = let binding_times_and_modes = - E.Map.mapi (fun simple binding_time_and_mode -> + Simple.Map.mapi (fun simple binding_time_and_mode -> let module BTM = Binding_time.With_name_mode in let new_mode = - if E.is_var simple then Name_mode.in_types + if Simple.is_var simple then Name_mode.in_types else BTM.name_mode binding_time_and_mode in BTM.create (BTM.binding_time binding_time_and_mode) new_mode) @@ -937,12 +909,10 @@ let clean_for_export (* Note: the relative order of the aliases and of their canonical element will be unchanged, as it only depends on the binding times. *) - E.Map.map Aliases_of_canonical_element.move_variables_to_mode_in_types + Simple.Map.map Aliases_of_canonical_element.move_variables_to_mode_in_types aliases_of_canonical_elements in { canonical_elements; aliases_of_canonical_elements; binding_times_and_modes; } - -end[@@inline always] diff --git a/middle_end/flambda/types/env/aliases.mli b/middle_end/flambda/types/env/aliases.mli index a9a85151d1d9..fb7f81159af1 100644 --- a/middle_end/flambda/types/env/aliases.mli +++ b/middle_end/flambda/types/env/aliases.mli @@ -18,55 +18,12 @@ [@@@ocaml.warning "+a-4-30-40-41-42"] -(* CR xclerc for xclerc: this module provides a functor rather than "direct" - access to alias handling to simplify testing. This could be reconsidered - once we trust the code to be correct, in particular because the indirection - makes the code extremely slow. *) - -type 'a coercion_to_canonical = { - coercion_to_canonical : 'a; +(* CR lmaurer: Maybe we should similarly have a type [canonical] isomorphic + to [Simple.t]? *) +type coercion_to_canonical = { + coercion_to_canonical : Coercion.t; } [@@ocaml.unboxed] -module type Coercion = sig - type t - val equal : t -> t -> bool - val inverse : t -> t - val id : t - val is_id : t -> bool - val compose : t -> newer:t -> t - val print : Format.formatter -> t -> unit -end - -module type Element = sig - type t - val name : Name.t -> t - val is_var : t -> bool - val without_coercion : t -> t - val pattern_match - : t - -> name:(Reg_width_things.Name.t -> 'a) - -> const:(Reg_width_things.Const.t -> 'a) - -> 'a - include Identifiable.S with type t := t -end - -module type Export = sig - type e - type t - val add : t -> e -> t - val empty : t - val to_ids_for_export : t -> Ids_for_export.t - module Import_map : sig - type t - val of_import_map : Ids_for_export.Import_map.t -> t - val simple : t -> e -> e - end -end - -module Make (C : Coercion) (E : Element) (_ : Export with type e = E.t) : sig - -type nonrec coercion_to_canonical = C.t coercion_to_canonical - type t include Contains_ids.S with type t := t @@ -79,38 +36,38 @@ val empty : t type add_result = private { t : t; - canonical_element : E.t; - alias_of : E.t; - coerce_alias_of_to_canonical_element : C.t; + canonical_element : Simple.t; + alias_of_demoted_element : Simple.t; + coercion_from_alias_of_demoted_to_canonical : Coercion.t; } val add : t - -> element1:E.t + -> element1:Simple.t -> binding_time_and_mode1:Binding_time.With_name_mode.t - -> coerce_from_element2_to_element1:C.t - -> element2:E.t + -> element2:Simple.t -> binding_time_and_mode2:Binding_time.With_name_mode.t -> add_result -val mem : t -> E.t -> bool +val mem : t -> Simple.t -> bool (** [get_canonical_element] returns [None] only when the [min_order_within_equiv_class] cannot be satisfied. *) val get_canonical_element_exn : t - -> E.t + -> Simple.t -> Name_mode.t -> min_name_mode:Name_mode.t - -> E.t * coercion_to_canonical + -> Simple.t * coercion_to_canonical (** [get_aliases] always returns the supplied element in the result set. *) -val get_aliases : t -> E.t -> coercion_to_canonical E.Map.t +val get_aliases : t -> Simple.t -> coercion_to_canonical Simple.Map.t -val get_canonical_ignoring_name_mode : t -> Name.t -> E.t +val get_canonical_ignoring_name_mode + : t + -> Name.t + -> Simple.t * coercion_to_canonical val merge : t -> t -> t val clean_for_export : t -> t - -end diff --git a/middle_end/flambda/types/env/typing_env.rec.ml b/middle_end/flambda/types/env/typing_env.rec.ml index 823731106489..ee0cf51231ff 100644 --- a/middle_end/flambda/types/env/typing_env.rec.ml +++ b/middle_end/flambda/types/env/typing_env.rec.ml @@ -16,19 +16,6 @@ [@@@ocaml.warning "+a-4-30-40-41-42"] -module Ids_for_export = struct - include Ids_for_export - type e = Simple.t - let add = Ids_for_export.add_simple - let to_ids_for_export x = x - module Import_map = struct - include Ids_for_export.Import_map - let of_import_map x = x - end -end - -module Aliases = Aliases.Make (Coercion) (Simple) (Ids_for_export) - module K = Flambda_kind (* CR mshinwell: Add signatures to these submodules. *) @@ -895,7 +882,9 @@ 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 + 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" @@ -1008,32 +997,32 @@ and add_equation t name ty = (* Equations giving concrete types may only be added to the canonical 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, None, t, ty + let canonical, { Aliases.coercion_to_canonical = coercion } = + Aliases.get_canonical_ignoring_name_mode aliases name + in + aliases, canonical, coercion, t, ty | alias_of -> 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 coercion = Simple.coercion alias_of in let binding_time_and_mode_alias_of = binding_time_and_mode_of_simple t alias_of in let ({ canonical_element; - alias_of; + alias_of_demoted_element; t = aliases; - coerce_alias_of_to_canonical_element = coercion; } : Aliases.add_result) = + coercion_from_alias_of_demoted_to_canonical = coercion; } : Aliases.add_result) = Aliases.add aliases ~element1:alias ~binding_time_and_mode1:binding_time_and_mode_alias - ~coerce_from_element2_to_element1:(Option.value coercion ~default:Coercion.id) ~element2:alias_of ~binding_time_and_mode2:binding_time_and_mode_alias_of in let ty = Type_grammar.alias_type_of kind canonical_element in - aliases, alias_of, Some coercion, t, ty + aliases, alias_of_demoted_element, coercion, 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 @@ -1062,17 +1051,9 @@ and add_equation t name ty = Simple.pattern_match simple ~name ~const:(fun _ -> ty, t) in let ty = - match coercion with - | None -> ty - | Some coercion -> - (* CR xclerc for xclerc: an alternative would be to ensure "everywhere" - that applying the identity coercion is always legal. *) - if Coercion.is_id coercion then - ty - else - match Type_grammar.apply_coercion ty coercion with - | Bottom -> Type_grammar.bottom (Type_grammar.kind ty) - | Ok ty -> ty + match Type_grammar.apply_coercion ty coercion 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) @@ -1217,22 +1198,6 @@ let cut_and_n_way_join definition_typing_env ts_and_use_ids ~params let get_canonical_simple_with_kind_exn t ?min_name_mode simple = let kind = kind_of_simple t simple in - let newer_coercion = - let newer_coercion = Simple.coercion simple in - match newer_coercion with - | None -> None - | Some newer_coercion -> - Simple.pattern_match simple - ~const:(fun _ -> Some newer_coercion) - ~name:(fun name -> - match Type_grammar.get_alias_exn (find t name (Some kind)) with - | exception Not_found -> Some newer_coercion - | simple -> - match Simple.coercion simple with - | None -> Some newer_coercion - | Some coercion -> - Some (Coercion.compose coercion ~newer:newer_coercion)) - in let aliases_for_simple = if Aliases.mem (aliases t) simple then aliases t else @@ -1277,34 +1242,17 @@ let get_canonical_simple_with_kind_exn t ?min_name_mode simple = print t end; raise Misc.Fatal_error - | alias, _coercion (* CR xclerc for xclerc: use the coercion. *) -> - match newer_coercion with - | None -> alias, kind - | Some _ -> - match Simple.compose_coercion alias ~newer_coercion with + | alias, { coercion_to_canonical = coercion } -> + match Coercion.compose coercion ~then_:(Simple.coercion simple) with + | None -> raise Not_found + | Some coercion -> + begin match Simple.apply_coercion alias coercion with | None -> raise Not_found | Some simple -> simple, kind + end let get_canonical_simple_exn t ?min_name_mode simple = (* Duplicated from above to eliminate the allocation of the returned pair. *) - let newer_coercion = - let newer_coercion = Simple.coercion simple in - match newer_coercion with - | None -> None - | Some newer_coercion -> - Simple.pattern_match simple - ~const:(fun _ -> Some newer_coercion) - ~name:(fun name -> - if variable_is_from_missing_cmx_file t name then Some newer_coercion - else - match Type_grammar.get_alias_exn (find t name None) with - | exception Not_found -> Some newer_coercion - | simple -> - match Simple.coercion simple with - | None -> Some newer_coercion - | Some coercion -> - Some (Coercion.compose coercion ~newer:newer_coercion)) - in let aliases_for_simple = if Aliases.mem (aliases t) simple then aliases t else @@ -1380,13 +1328,14 @@ let get_canonical_simple_exn t ?min_name_mode simple = print t end; raise Misc.Fatal_error - | alias, _ -> - match newer_coercion with - | None -> alias - | Some _ -> - match Simple.compose_coercion alias ~newer_coercion with + | alias, { coercion_to_canonical = coercion } -> + match Coercion.compose coercion ~then_:(Simple.coercion simple) with + | None -> raise Not_found + | Some coercion -> + begin match Simple.apply_coercion alias coercion with | None -> raise Not_found | Some simple -> simple + end let get_alias_then_canonical_simple_exn t ?min_name_mode typ = Type_grammar.get_alias_exn typ @@ -1406,10 +1355,10 @@ let aliases_of_simple t ~min_name_mode simple = in let newer_coercion = Simple.coercion simple in match newer_coercion with - | None -> aliases - | Some _ -> + | Id -> aliases + | _ -> Simple.Map.fold (fun simple coercion simples -> - match Simple.compose_coercion simple ~newer_coercion with + match Simple.apply_coercion simple newer_coercion with | None -> simples | Some simple -> Simple.Map.add simple coercion simples) aliases diff --git a/middle_end/flambda/types/env/typing_env.rec.mli b/middle_end/flambda/types/env/typing_env.rec.mli index e5ddde839a6f..1a99ff5d94c7 100644 --- a/middle_end/flambda/types/env/typing_env.rec.mli +++ b/middle_end/flambda/types/env/typing_env.rec.mli @@ -120,9 +120,12 @@ val aliases_of_simple : t -> min_name_mode:Name_mode.t -> Simple.t - -> Coercion.t Aliases.coercion_to_canonical Simple.Map.t + -> Aliases.coercion_to_canonical Simple.Map.t -val aliases_of_simple_allowable_in_types : t -> Simple.t -> Coercion.t Aliases.coercion_to_canonical Simple.Map.t +val aliases_of_simple_allowable_in_types + : t + -> Simple.t + -> Aliases.coercion_to_canonical Simple.Map.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 976f8890a36d..ee69e2d20e12 100644 --- a/middle_end/flambda/types/flambda_type.mli +++ b/middle_end/flambda/types/flambda_type.mli @@ -178,7 +178,7 @@ module Typing_env : sig : t -> min_name_mode:Name_mode.t -> Simple.t - -> Coercion.t Aliases.coercion_to_canonical Simple.Map.t + -> Aliases.coercion_to_canonical Simple.Map.t val clean_for_export : t -> reachable_names:Name_occurrences.t -> t @@ -232,7 +232,6 @@ module Function_declaration_type : sig val code_id : t -> Code_id.t val dbg : t -> Debuginfo.t - val coercion : t -> Coercion.t val is_tupled : t -> bool end @@ -401,7 +400,7 @@ val mutable_string : size:int -> t val create_inlinable_function_declaration : code_id:Code_id.t -> dbg:Debuginfo.t - -> coercion:Coercion.t + -> rec_info:Rec_info.t -> is_tupled:bool -> Function_declaration_type.t diff --git a/middle_end/flambda/types/inlining/inlining_state.ml b/middle_end/flambda/types/inlining/inlining_state.ml index 2aadf609614d..4c274c765ff6 100644 --- a/middle_end/flambda/types/inlining/inlining_state.ml +++ b/middle_end/flambda/types/inlining/inlining_state.ml @@ -26,7 +26,11 @@ let create ~depth = { depth } let print ppf t = Format.fprintf ppf "@[(depth@ %d)@]" t.depth -let is_depth_exceeded t = t.depth >= !Clflags.Flambda.Expert.max_inlining_depth +let is_depth_exceeded t = + (* 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 >= !Clflags.Flambda.Expert.max_inlining_depth let merge 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 46fdf430f591..5e5b0742c8f3 100644 --- a/middle_end/flambda/types/structures/function_declaration_type.rec.ml +++ b/middle_end/flambda/types/structures/function_declaration_type.rec.ml @@ -23,37 +23,36 @@ module Inlinable = struct type t = { code_id : Code_id.t; dbg : Debuginfo.t; - coercion : Coercion.t; + rec_info : Rec_info.t; is_tupled : bool; } - let print ppf { code_id; dbg; coercion; is_tupled; } = + let print ppf { code_id; dbg; rec_info; is_tupled; } = Format.fprintf ppf "@[(Inlinable@ \ @[(code_id@ %a)@]@ \ @[(dbg@ %a)@] \ - @[(coercion@ %a)@]\ + @[(rec_info@ %a)@] \ @[ Name_occurrences.empty - | Ok (Inlinable { code_id; dbg = _; coercion = _; is_tupled = _; }) + | Ok (Inlinable { code_id; dbg = _; rec_info = (); is_tupled = _; }) | Ok (Non_inlinable { code_id; is_tupled = _; }) -> Name_occurrences.add_code_id Name_occurrences.empty code_id Name_mode.in_types @@ -117,16 +116,16 @@ let free_names (t : t) = let all_ids_for_export (t : t) = match t with | Bottom | Unknown -> Ids_for_export.empty - | Ok (Inlinable { code_id; dbg = _; coercion = _; is_tupled = _; }) + | Ok (Inlinable { code_id; dbg = _; rec_info = (); is_tupled = _; }) | Ok (Non_inlinable { code_id; is_tupled = _; }) -> Ids_for_export.add_code_id Ids_for_export.empty code_id let import import_map (t : t) : t = match t with | Bottom | Unknown -> t - | Ok (Inlinable { code_id; dbg; coercion; is_tupled; }) -> + | Ok (Inlinable { code_id; dbg; rec_info; is_tupled; }) -> let code_id = Ids_for_export.Import_map.code_id import_map code_id in - Ok (Inlinable { code_id; dbg; coercion; is_tupled; }) + Ok (Inlinable { code_id; dbg; rec_info; is_tupled; }) | Ok (Non_inlinable { code_id; is_tupled; }) -> let code_id = Ids_for_export.Import_map.code_id import_map code_id in Ok (Non_inlinable { code_id; is_tupled; }) @@ -179,13 +178,13 @@ let meet (env : Meet_env.t) (t1 : t) (t2 : t) | Ok (Inlinable { code_id = code_id1; dbg = dbg1; - coercion = _coercion1; + rec_info = (); is_tupled = is_tupled1; }), Ok (Inlinable { code_id = code_id2; dbg = dbg2; - coercion = _coercion2; + rec_info = (); is_tupled = is_tupled2; }) -> let typing_env = Meet_env.env env in @@ -197,12 +196,11 @@ let meet (env : Meet_env.t) (t1 : t) (t2 : t) Ok (Ok (Inlinable { code_id; dbg = dbg1; - coercion = _coercion1; + rec_info = (); is_tupled = is_tupled1; }), TEE.empty ()) in - (* CR mshinwell: What about [coercion]? *) begin match Code_age_relation.meet target_code_age_rel ~resolver code_id1 code_id2 with @@ -251,13 +249,13 @@ let join (env : Join_env.t) (t1 : t) (t2 : t) : t = | Ok (Inlinable { code_id = code_id1; dbg = dbg1; - coercion = _coercion1; + rec_info = (); is_tupled = is_tupled1; }), Ok (Inlinable { code_id = code_id2; dbg = dbg2; - coercion = _coercion2; + rec_info = (); is_tupled = is_tupled2; }) -> let typing_env = Join_env.target_join_env env in @@ -269,11 +267,10 @@ let join (env : Join_env.t) (t1 : t) (t2 : t) : t = Ok (Inlinable { code_id; dbg = dbg1; - coercion = _coercion1; + rec_info = (); is_tupled = is_tupled1; }) in - (* CR mshinwell: What about [coercion]? *) let code_age_rel1 = TE.code_age_relation (Join_env.left_join_env env) in @@ -288,14 +285,5 @@ let join (env : Join_env.t) (t1 : t) (t2 : t) : t = | Unknown -> Unknown end -let apply_coercion (t : t) coercion : t Or_bottom.t = - match t with - | Ok (Inlinable { code_id; dbg; coercion = coercion'; is_tupled; }) -> - let coercion = Coercion.compose coercion' ~newer:coercion in - Ok (Ok (Inlinable { code_id; - dbg; - coercion; - 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 e002f06e5613..33cce78e78a3 100644 --- a/middle_end/flambda/types/structures/function_declaration_type.rec.mli +++ b/middle_end/flambda/types/structures/function_declaration_type.rec.mli @@ -22,13 +22,12 @@ module Inlinable : sig val create : code_id:Code_id.t -> dbg:Debuginfo.t - -> coercion:Coercion.t + -> rec_info:Rec_info.t -> is_tupled:bool -> t val code_id : t -> Code_id.t val dbg : t -> Debuginfo.t - val coercion : t -> Coercion.t val is_tupled : t -> bool end diff --git a/middle_end/flambda/types/type_descr.rec.ml b/middle_end/flambda/types/type_descr.rec.ml index f5cc8bdadbdb..40fdaa11b7d2 100644 --- a/middle_end/flambda/types/type_descr.rec.ml +++ b/middle_end/flambda/types/type_descr.rec.ml @@ -140,8 +140,7 @@ module Make (Head : Type_head_intf.S let apply_coercion t coercion : _ Or_bottom.t = match descr t with | Equals simple -> - let newer_coercion = Some coercion in - begin match Simple.compose_coercion simple ~newer_coercion with + begin match Simple.apply_coercion simple coercion with | None -> Bottom | Some simple -> Ok (create_equals simple) end diff --git a/middle_end/flambda/types/type_grammar.rec.ml b/middle_end/flambda/types/type_grammar.rec.ml index 25ae138bdb27..1317f4d79d8e 100644 --- a/middle_end/flambda/types/type_grammar.rec.ml +++ b/middle_end/flambda/types/type_grammar.rec.ml @@ -613,10 +613,10 @@ let any_boxed_int32 () = box_int32 (any_naked_int32 ()) let any_boxed_int64 () = box_int64 (any_naked_int64 ()) let any_boxed_nativeint () = box_nativeint (any_naked_nativeint ()) -let create_inlinable_function_declaration ~code_id ~dbg ~coercion ~is_tupled +let create_inlinable_function_declaration ~code_id ~dbg ~rec_info ~is_tupled : Function_declaration_type.t = Ok (Inlinable ( - Function_declaration_type.Inlinable.create ~code_id ~dbg ~coercion ~is_tupled)) + Function_declaration_type.Inlinable.create ~code_id ~dbg ~rec_info ~is_tupled)) let create_non_inlinable_function_declaration ~code_id ~is_tupled : Function_declaration_type.t = diff --git a/middle_end/flambda/types/type_grammar.rec.mli b/middle_end/flambda/types/type_grammar.rec.mli index d093d2c3d0ab..7f05f34214a5 100644 --- a/middle_end/flambda/types/type_grammar.rec.mli +++ b/middle_end/flambda/types/type_grammar.rec.mli @@ -162,7 +162,7 @@ val kind_for_const : Reg_width_const.t -> Flambda_kind.t val create_inlinable_function_declaration : code_id:Code_id.t -> dbg:Debuginfo.t - -> coercion:Coercion.t + -> rec_info:Rec_info.t -> is_tupled:bool -> Function_declaration_type.t diff --git a/testsuite/tests/flambda2-aliases/test.ml b/testsuite/tests/flambda2-aliases/test.ml index b86874811a06..08e5154412ca 100644 --- a/testsuite/tests/flambda2-aliases/test.ml +++ b/testsuite/tests/flambda2-aliases/test.ml @@ -5,6 +5,8 @@ *) let () = Clflags.flambda_invariant_checks := true +let () = Clflags.dump_rawflambda := true +let () = Misc.Color.setup (Some Never) let () = let dummy = "compilation_unit" in @@ -13,83 +15,6 @@ let () = (Ident.create_persistent dummy) (Linkage_name.create dummy)) -module Coercion : sig - include Aliases.Coercion - val make : char -> t -end = struct - type t = string - let make c = String.make 1 c - let equal = String.equal - let change_case ch = - if Char.equal ch (Char.lowercase_ascii ch) then - Char.uppercase_ascii ch - else - Char.lowercase_ascii ch - let simplify s = - let len = String.length s in - let buff = Buffer.create len in - let i = ref 0 in - while !i < len do - if succ !i < len && Char.equal s.[!i] (change_case s.[succ !i]) then begin - incr i; - incr i; - end else begin - Buffer.add_char buff s.[!i]; - incr i; - end - done; - Buffer.contents buff - let inverse c = - let len = String.length c in - let res = String.init len (fun i -> change_case c.[len - i - 1]) in - simplify res - let id = "" - let is_id c = equal id c - let compose c ~newer = simplify (c ^ newer) - let print ppf c = Format.fprintf ppf "coercion:%S" c -end - -module Element : sig - include Aliases.Element - val make : string -> t -end = struct - type t = string - let make x = x - let name n = - Name.pattern_match - n - ~var:(fun v -> Variable.name v) - ~symbol:(fun _ -> assert false) - let without_coercion e = e - let pattern_match _ ~name:_ ~const:_ = assert false - let print ppf e = Format.fprintf ppf "element:%S" e - include Identifiable.Make (struct - type nonrec t = t - let compare = String.compare - let equal = String.equal - let hash = Hashtbl.hash - let output _ _ = assert false - let print = print - end) -end - -module Export : sig - include Aliases.Export with type e = Element.t -end = struct - type e = Element.t - type t = unit - let add _ _ = assert false - let empty = () - let to_ids_for_export _ = assert false - module Import_map = struct - type t - let of_import_map _ = assert false - let simple _ _ = assert false - end -end - -module Aliases = Aliases.Make (Coercion) (Element) (Export) - let next_time : unit -> Binding_time.With_name_mode.t = let next = ref Binding_time.earliest_var in fun () -> @@ -97,62 +22,50 @@ let next_time : unit -> Binding_time.With_name_mode.t = next := Binding_time.succ time; Binding_time.With_name_mode.create time Name_mode.normal +let mk_simple name = Simple.var (Variable.create name) +let mk_coercion from to_ = Coercion.change_depth ~from ~to_ + let add_alias ppf aliases ~element1 ~binding_time_and_mode1 - ~coerce_from_element2_to_element1 + ~coercion_from_element2_to_element1 ~element2 ~binding_time_and_mode2 = - let { Aliases.t; canonical_element; alias_of; coerce_alias_of_to_canonical_element; } = + let element2 = + Simple.with_coercion element2 coercion_from_element2_to_element1 + in + let { Aliases.t; canonical_element; alias_of_demoted_element; coercion_from_alias_of_demoted_to_canonical; } = Aliases.add aliases ~element1 ~binding_time_and_mode1 - ~coerce_from_element2_to_element1 ~element2 ~binding_time_and_mode2 in Format.fprintf ppf "[added] %a <--[%a]-- %a@." - Element.print canonical_element - Coercion.print coerce_alias_of_to_canonical_element - Element.print alias_of; + Simple.print canonical_element + Coercion.print coercion_from_alias_of_demoted_to_canonical + Simple.print alias_of_demoted_element; t -(* CR xclerc for xclerc: remove the `expect` parameter. - (It currently allows one to use this module without relying upon ocamltest.) *) -let test msg ~f ~expect = - let buff = Buffer.create 1024 in - let ppf = Format.formatter_of_buffer buff in - print_string "*** "; - print_endline msg; - f ppf; - Format.pp_print_flush ppf (); - let got = Buffer.contents buff in - if String.equal got expect then begin - print_endline got; - print_newline (); - end else begin - prerr_endline "*** error, expected:"; - prerr_endline expect; - prerr_endline "*** but got:"; - prerr_endline got; - assert false - end +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) - ~expect:{|((canonical_elements {}) (aliases_of_canonical_elements {}) - (binding_times_and_modes {}))|} 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 = Element.make "x" in - let y = Element.make "y" in + let x = mk_simple "x" in + let y = mk_simple "y" in (* x <--[f]-- y *) let aliases = add_alias @@ -160,25 +73,18 @@ let () = test "single alias" ~f:(fun ppf -> aliases ~element1:x ~binding_time_and_mode1:t_x - ~coerce_from_element2_to_element1:(Coercion.make 'f') + ~coercion_from_element2_to_element1:(mk_coercion 1 0) ~element2:y ~binding_time_and_mode2:t_y in Aliases.print ppf aliases) - ~expect:{|[added] element:"x" <--[coercion:"f"]-- element:"y" -((canonical_elements {(element:"y" element:"x" (coercion:"f"))}) - (aliases_of_canonical_elements - {(element:"x" {(Normal {(element:"y" coercion:"f")})})}) - (binding_times_and_modes - {(element:"x" (bound at time 3 Normal)) - (element:"y" (bound at time 4 Normal))}))|} 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 = Element.make "x" in - let y = Element.make "y" in + let x = mk_simple "x" in + let y = mk_simple "y" in (* x <--[f]-- y ~> y <--[F]-- x *) @@ -188,27 +94,20 @@ let () = test "single alias (inverse)" ~f:(fun ppf -> aliases ~element1:x ~binding_time_and_mode1:t_x - ~coerce_from_element2_to_element1:(Coercion.make 'f') + ~coercion_from_element2_to_element1:(mk_coercion 1 0) ~element2:y ~binding_time_and_mode2:t_y in Aliases.print ppf aliases) - ~expect:{|[added] element:"y" <--[coercion:"F"]-- element:"x" -((canonical_elements {(element:"x" element:"y" (coercion:"F"))}) - (aliases_of_canonical_elements - {(element:"y" {(Normal {(element:"x" coercion:"F")})})}) - (binding_times_and_modes - {(element:"x" (bound at time 6 Normal)) - (element:"y" (bound at time 5 Normal))}))|} 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 = Element.make "x" in - let y = Element.make "y" in - let z = Element.make "z" 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 @@ -221,7 +120,7 @@ let () = test "two aliases (independent)" ~f:(fun ppf -> aliases ~element1:x ~binding_time_and_mode1:t_x - ~coerce_from_element2_to_element1:(Coercion.make 'f') + ~coercion_from_element2_to_element1:(mk_coercion 1 0) ~element2:y ~binding_time_and_mode2:t_y in @@ -231,32 +130,20 @@ let () = test "two aliases (independent)" ~f:(fun ppf -> aliases ~element1:x ~binding_time_and_mode1:t_x - ~coerce_from_element2_to_element1:(Coercion.make 'g') + ~coercion_from_element2_to_element1:(mk_coercion 2 0) ~element2:z ~binding_time_and_mode2:t_z in Aliases.print ppf aliases) - ~expect:{|[added] element:"x" <--[coercion:"f"]-- element:"y" -[added] element:"x" <--[coercion:"g"]-- element:"z" -((canonical_elements - {(element:"y" element:"x" (coercion:"f")) - (element:"z" element:"x" (coercion:"g"))}) - (aliases_of_canonical_elements - {(element:"x" - {(Normal {(element:"y" coercion:"f") (element:"z" coercion:"g")})})}) - (binding_times_and_modes - {(element:"x" (bound at time 7 Normal)) - (element:"y" (bound at time 8 Normal)) - (element:"z" (bound at time 9 Normal))}))|} 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 = Element.make "x" in - let y = Element.make "y" in - let z = Element.make "z" 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 @@ -269,7 +156,7 @@ let () = test "two aliases (simple chain)" ~f:(fun ppf -> aliases ~element1:x ~binding_time_and_mode1:t_x - ~coerce_from_element2_to_element1:(Coercion.make 'f') + ~coercion_from_element2_to_element1:(mk_coercion 1 0) ~element2:y ~binding_time_and_mode2:t_y in @@ -279,37 +166,25 @@ let () = test "two aliases (simple chain)" ~f:(fun ppf -> aliases ~element1:y ~binding_time_and_mode1:t_y - ~coerce_from_element2_to_element1:(Coercion.make 'g') + ~coercion_from_element2_to_element1:(mk_coercion 2 1) ~element2:z ~binding_time_and_mode2:t_z in Aliases.print ppf aliases) - ~expect:{|[added] element:"x" <--[coercion:"f"]-- element:"y" -[added] element:"x" <--[coercion:"gf"]-- element:"z" -((canonical_elements - {(element:"y" element:"x" (coercion:"f")) - (element:"z" element:"x" (coercion:"gf"))}) - (aliases_of_canonical_elements - {(element:"x" - {(Normal {(element:"y" coercion:"f") (element:"z" coercion:"gf")})})}) - (binding_times_and_modes - {(element:"x" (bound at time 10 Normal)) - (element:"y" (bound at time 11 Normal)) - (element:"z" (bound at time 12 Normal))}))|} 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 = Element.make "x" in - let y = Element.make "y" in - let z = Element.make "z" 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 <--[FG]-- x + z <--[GF]-- x ^--[G]-- y *) let aliases = add_alias @@ -317,7 +192,7 @@ let () = test "two aliases (two inverses)" ~f:(fun ppf -> aliases ~element1:x ~binding_time_and_mode1:t_x - ~coerce_from_element2_to_element1:(Coercion.make 'f') + ~coercion_from_element2_to_element1:(mk_coercion 1 0) ~element2:y ~binding_time_and_mode2:t_y in @@ -327,32 +202,20 @@ let () = test "two aliases (two inverses)" ~f:(fun ppf -> aliases ~element1:y ~binding_time_and_mode1:t_y - ~coerce_from_element2_to_element1:(Coercion.make 'g') + ~coercion_from_element2_to_element1:(mk_coercion 2 1) ~element2:z ~binding_time_and_mode2:t_z in Aliases.print ppf aliases) - ~expect:{|[added] element:"x" <--[coercion:"f"]-- element:"y" -[added] element:"z" <--[coercion:"FG"]-- element:"x" -((canonical_elements - {(element:"x" element:"z" (coercion:"FG")) - (element:"y" element:"z" (coercion:"G"))}) - (aliases_of_canonical_elements - {(element:"z" - {(Normal {(element:"x" coercion:"FG") (element:"y" coercion:"G")})})}) - (binding_times_and_modes - {(element:"x" (bound at time 14 Normal)) - (element:"y" (bound at time 15 Normal)) - (element:"z" (bound at time 13 Normal))}))|} 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 = Element.make "x" in - let y = Element.make "y" in - let z = Element.make "z" 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 @@ -365,7 +228,7 @@ let () = test "two aliases (one inverse)" ~f:(fun ppf -> aliases ~element1:x ~binding_time_and_mode1:t_x - ~coerce_from_element2_to_element1:(Coercion.make 'f') + ~coercion_from_element2_to_element1:(mk_coercion 1 0) ~element2:y ~binding_time_and_mode2:t_y in @@ -375,32 +238,20 @@ let () = test "two aliases (one inverse)" ~f:(fun ppf -> aliases ~element1:z ~binding_time_and_mode1:t_z - ~coerce_from_element2_to_element1:(Coercion.make 'g') + ~coercion_from_element2_to_element1:(mk_coercion 1 2) ~element2:y ~binding_time_and_mode2:t_y in Aliases.print ppf aliases) - ~expect:{|[added] element:"x" <--[coercion:"f"]-- element:"y" -[added] element:"z" <--[coercion:"Fg"]-- element:"x" -((canonical_elements - {(element:"x" element:"z" (coercion:"Fg")) - (element:"y" element:"z" (coercion:"g"))}) - (aliases_of_canonical_elements - {(element:"z" - {(Normal {(element:"x" coercion:"Fg") (element:"y" coercion:"g")})})}) - (binding_times_and_modes - {(element:"x" (bound at time 17 Normal)) - (element:"y" (bound at time 18 Normal)) - (element:"z" (bound at time 16 Normal))}))|} 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 = Element.make "x" in - let y = Element.make "y" in - let z = Element.make "z" 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 @@ -413,7 +264,7 @@ let () = test "two aliases (one inverse)" ~f:(fun ppf -> aliases ~element1:x ~binding_time_and_mode1:t_x - ~coerce_from_element2_to_element1:(Coercion.make 'f') + ~coercion_from_element2_to_element1:(mk_coercion 1 0) ~element2:y ~binding_time_and_mode2:t_y in @@ -423,23 +274,11 @@ let () = test "two aliases (one inverse)" ~f:(fun ppf -> aliases ~element1:z ~binding_time_and_mode1:t_z - ~coerce_from_element2_to_element1:(Coercion.make 'g') + ~coercion_from_element2_to_element1:(mk_coercion 1 2) ~element2:y ~binding_time_and_mode2:t_y in Aliases.print ppf aliases) - ~expect:{|[added] element:"x" <--[coercion:"f"]-- element:"y" -[added] element:"x" <--[coercion:"Gf"]-- element:"z" -((canonical_elements - {(element:"y" element:"x" (coercion:"f")) - (element:"z" element:"x" (coercion:"Gf"))}) - (aliases_of_canonical_elements - {(element:"x" - {(Normal {(element:"y" coercion:"f") (element:"z" coercion:"Gf")})})}) - (binding_times_and_modes - {(element:"x" (bound at time 19 Normal)) - (element:"y" (bound at time 20 Normal)) - (element:"z" (bound at time 21 Normal))}))|} let () = test "three aliases (one inverse)" ~f:(fun ppf -> let aliases = Aliases.empty in @@ -447,10 +286,10 @@ let () = test "three aliases (one inverse)" ~f:(fun ppf -> let t_y = next_time () in let t_z = next_time () in let t_t = next_time () in - let x = Element.make "x" in - let y = Element.make "y" in - let z = Element.make "z" in - let t = Element.make "t" 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 @@ -466,7 +305,7 @@ let () = test "three aliases (one inverse)" ~f:(fun ppf -> aliases ~element1:x ~binding_time_and_mode1:t_x - ~coerce_from_element2_to_element1:(Coercion.make 'f') + ~coercion_from_element2_to_element1:(mk_coercion 1 0) ~element2:y ~binding_time_and_mode2:t_y in @@ -476,7 +315,7 @@ let () = test "three aliases (one inverse)" ~f:(fun ppf -> aliases ~element1:z ~binding_time_and_mode1:t_z - ~coerce_from_element2_to_element1:(Coercion.make 'g') + ~coercion_from_element2_to_element1:(mk_coercion 3 2) ~element2:t ~binding_time_and_mode2:t_t in @@ -486,28 +325,11 @@ let () = test "three aliases (one inverse)" ~f:(fun ppf -> aliases ~element1:y ~binding_time_and_mode1:t_y - ~coerce_from_element2_to_element1:(Coercion.make 'h') + ~coercion_from_element2_to_element1:(mk_coercion 3 1) ~element2:t ~binding_time_and_mode2:t_t in Aliases.print ppf aliases) - ~expect:{|[added] element:"x" <--[coercion:"f"]-- element:"y" -[added] element:"z" <--[coercion:"g"]-- element:"t" -[added] element:"x" <--[coercion:"Ghf"]-- element:"z" -((canonical_elements - {(element:"t" element:"x" (coercion:"hf")) - (element:"y" element:"x" (coercion:"f")) - (element:"z" element:"x" (coercion:"Ghf"))}) - (aliases_of_canonical_elements - {(element:"x" - {(Normal - {(element:"t" coercion:"hf") (element:"y" coercion:"f") - (element:"z" coercion:"Ghf")})})}) - (binding_times_and_modes - {(element:"t" (bound at time 25 Normal)) - (element:"x" (bound at time 22 Normal)) - (element:"y" (bound at time 23 Normal)) - (element:"z" (bound at time 24 Normal))}))|} let () = test "three aliases (two inverses)" ~f:(fun ppf -> let aliases = Aliases.empty in @@ -515,10 +337,10 @@ let () = test "three aliases (two inverses)" ~f:(fun ppf -> let t_x = next_time () in let t_y = next_time () in let t_t = next_time () in - let x = Element.make "x" in - let y = Element.make "y" in - let z = Element.make "z" in - let t = Element.make "t" 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 @@ -534,7 +356,7 @@ let () = test "three aliases (two inverses)" ~f:(fun ppf -> aliases ~element1:x ~binding_time_and_mode1:t_x - ~coerce_from_element2_to_element1:(Coercion.make 'f') + ~coercion_from_element2_to_element1:(mk_coercion 1 0) ~element2:y ~binding_time_and_mode2:t_y in @@ -544,7 +366,7 @@ let () = test "three aliases (two inverses)" ~f:(fun ppf -> aliases ~element1:z ~binding_time_and_mode1:t_z - ~coerce_from_element2_to_element1:(Coercion.make 'g') + ~coercion_from_element2_to_element1:(mk_coercion 3 2) ~element2:t ~binding_time_and_mode2:t_t in @@ -554,27 +376,10 @@ let () = test "three aliases (two inverses)" ~f:(fun ppf -> aliases ~element1:y ~binding_time_and_mode1:t_y - ~coerce_from_element2_to_element1:(Coercion.make 'h') + ~coercion_from_element2_to_element1:(mk_coercion 3 1) ~element2:t ~binding_time_and_mode2:t_t in Aliases.print ppf aliases) - ~expect:{|[added] element:"x" <--[coercion:"f"]-- element:"y" -[added] element:"z" <--[coercion:"g"]-- element:"t" -[added] element:"z" <--[coercion:"FHg"]-- element:"x" -((canonical_elements - {(element:"t" element:"z" (coercion:"g")) - (element:"x" element:"z" (coercion:"FHg")) - (element:"y" element:"z" (coercion:"Hg"))}) - (aliases_of_canonical_elements - {(element:"z" - {(Normal - {(element:"t" coercion:"g") (element:"x" coercion:"FHg") - (element:"y" coercion:"Hg")})})}) - (binding_times_and_modes - {(element:"t" (bound at time 29 Normal)) - (element:"x" (bound at time 27 Normal)) - (element:"y" (bound at time 28 Normal)) - (element:"z" (bound at time 26 Normal))}))|} let () = print_endline "OK." diff --git a/testsuite/tests/flambda2-aliases/test.reference b/testsuite/tests/flambda2-aliases/test.reference index 00c702f9fa12..1beacc021fdc 100644 --- a/testsuite/tests/flambda2-aliases/test.reference +++ b/testsuite/tests/flambda2-aliases/test.reference @@ -3,129 +3,109 @@ (binding_times_and_modes {})) *** single alias -[added] element:"x" <--[coercion:"f"]-- element:"y" -((canonical_elements {(element:"y" element:"x" (coercion:"f"))}) - (aliases_of_canonical_elements - {(element:"x" {(Normal {(element:"y" coercion:"f")})})}) +[added] x/0 <--[(depth 1 -> 0)]-- y/1 +((canonical_elements {(y/1 (x/0 (coercion (depth 1 -> 0))))}) + (aliases_of_canonical_elements {(x/0 {(Normal {(y/1 (depth 1 -> 0))})})}) (binding_times_and_modes - {(element:"x" (bound at time 3 Normal)) - (element:"y" (bound at time 4 Normal))})) + {(x/0 (bound at time 3 Normal)) (y/1 (bound at time 4 Normal))})) *** single alias (inverse) -[added] element:"y" <--[coercion:"F"]-- element:"x" -((canonical_elements {(element:"x" element:"y" (coercion:"F"))}) - (aliases_of_canonical_elements - {(element:"y" {(Normal {(element:"x" coercion:"F")})})}) +[added] y/3 <--[(depth 0 -> 1)]-- x/2 +((canonical_elements {(x/2 (y/3 (coercion (depth 0 -> 1))))}) + (aliases_of_canonical_elements {(y/3 {(Normal {(x/2 (depth 0 -> 1))})})}) (binding_times_and_modes - {(element:"x" (bound at time 6 Normal)) - (element:"y" (bound at time 5 Normal))})) + {(x/2 (bound at time 6 Normal)) (y/3 (bound at time 5 Normal))})) *** two aliases (independent) -[added] element:"x" <--[coercion:"f"]-- element:"y" -[added] element:"x" <--[coercion:"g"]-- element:"z" +[added] x/4 <--[(depth 1 -> 0)]-- y/5 +[added] x/4 <--[(depth 2 -> 0)]-- z/6 ((canonical_elements - {(element:"y" element:"x" (coercion:"f")) - (element:"z" element:"x" (coercion:"g"))}) + {(y/5 (x/4 (coercion (depth 1 -> 0)))) + (z/6 (x/4 (coercion (depth 2 -> 0))))}) (aliases_of_canonical_elements - {(element:"x" - {(Normal {(element:"y" coercion:"f") (element:"z" coercion:"g")})})}) + {(x/4 {(Normal {(y/5 (depth 1 -> 0)) (z/6 (depth 2 -> 0))})})}) (binding_times_and_modes - {(element:"x" (bound at time 7 Normal)) - (element:"y" (bound at time 8 Normal)) - (element:"z" (bound at time 9 Normal))})) + {(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] element:"x" <--[coercion:"f"]-- element:"y" -[added] element:"x" <--[coercion:"gf"]-- element:"z" +[added] x/7 <--[(depth 1 -> 0)]-- y/8 +[added] x/7 <--[(depth 2 -> 0)]-- z/9 ((canonical_elements - {(element:"y" element:"x" (coercion:"f")) - (element:"z" element:"x" (coercion:"gf"))}) + {(z/9 (x/7 (coercion (depth 2 -> 0)))) + (y/8 (x/7 (coercion (depth 1 -> 0))))}) (aliases_of_canonical_elements - {(element:"x" - {(Normal {(element:"y" coercion:"f") (element:"z" coercion:"gf")})})}) + {(x/7 {(Normal {(z/9 (depth 2 -> 0)) (y/8 (depth 1 -> 0))})})}) (binding_times_and_modes - {(element:"x" (bound at time 10 Normal)) - (element:"y" (bound at time 11 Normal)) - (element:"z" (bound at time 12 Normal))})) + {(x/7 (bound at time 10 Normal)) (z/9 (bound at time 12 Normal)) + (y/8 (bound at time 11 Normal))})) *** two aliases (two inverses) -[added] element:"x" <--[coercion:"f"]-- element:"y" -[added] element:"z" <--[coercion:"FG"]-- element:"x" +[added] x/10 <--[(depth 1 -> 0)]-- y/11 +[added] z/12 <--[(depth 1 -> 2)]-- y/11 ((canonical_elements - {(element:"x" element:"z" (coercion:"FG")) - (element:"y" element:"z" (coercion:"G"))}) + {(x/10 (z/12 (coercion (depth 0 -> 2)))) + (y/11 (z/12 (coercion (depth 1 -> 2))))}) (aliases_of_canonical_elements - {(element:"z" - {(Normal {(element:"x" coercion:"FG") (element:"y" coercion:"G")})})}) + {(z/12 {(Normal {(x/10 (depth 0 -> 2)) (y/11 (depth 1 -> 2))})})}) (binding_times_and_modes - {(element:"x" (bound at time 14 Normal)) - (element:"y" (bound at time 15 Normal)) - (element:"z" (bound at time 13 Normal))})) + {(z/12 (bound at time 13 Normal)) (x/10 (bound at time 14 Normal)) + (y/11 (bound at time 15 Normal))})) *** two aliases (one inverse) -[added] element:"x" <--[coercion:"f"]-- element:"y" -[added] element:"z" <--[coercion:"Fg"]-- element:"x" +[added] x/13 <--[(depth 1 -> 0)]-- y/14 +[added] z/15 <--[(depth 1 -> 2)]-- y/14 ((canonical_elements - {(element:"x" element:"z" (coercion:"Fg")) - (element:"y" element:"z" (coercion:"g"))}) + {(x/13 (z/15 (coercion (depth 0 -> 2)))) + (y/14 (z/15 (coercion (depth 1 -> 2))))}) (aliases_of_canonical_elements - {(element:"z" - {(Normal {(element:"x" coercion:"Fg") (element:"y" coercion:"g")})})}) + {(z/15 {(Normal {(x/13 (depth 0 -> 2)) (y/14 (depth 1 -> 2))})})}) (binding_times_and_modes - {(element:"x" (bound at time 17 Normal)) - (element:"y" (bound at time 18 Normal)) - (element:"z" (bound at time 16 Normal))})) + {(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] element:"x" <--[coercion:"f"]-- element:"y" -[added] element:"x" <--[coercion:"Gf"]-- element:"z" +[added] x/16 <--[(depth 1 -> 0)]-- y/17 +[added] x/16 <--[(depth 2 -> 0)]-- z/18 ((canonical_elements - {(element:"y" element:"x" (coercion:"f")) - (element:"z" element:"x" (coercion:"Gf"))}) + {(y/17 (x/16 (coercion (depth 1 -> 0)))) + (z/18 (x/16 (coercion (depth 2 -> 0))))}) (aliases_of_canonical_elements - {(element:"x" - {(Normal {(element:"y" coercion:"f") (element:"z" coercion:"Gf")})})}) + {(x/16 {(Normal {(y/17 (depth 1 -> 0)) (z/18 (depth 2 -> 0))})})}) (binding_times_and_modes - {(element:"x" (bound at time 19 Normal)) - (element:"y" (bound at time 20 Normal)) - (element:"z" (bound at time 21 Normal))})) + {(y/17 (bound at time 20 Normal)) (x/16 (bound at time 19 Normal)) + (z/18 (bound at time 21 Normal))})) *** three aliases (one inverse) -[added] element:"x" <--[coercion:"f"]-- element:"y" -[added] element:"z" <--[coercion:"g"]-- element:"t" -[added] element:"x" <--[coercion:"Ghf"]-- element:"z" +[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 - {(element:"t" element:"x" (coercion:"hf")) - (element:"y" element:"x" (coercion:"f")) - (element:"z" element:"x" (coercion:"Ghf"))}) + {(z/21 (x/19 (coercion (depth 2 -> 0)))) + (y/20 (x/19 (coercion (depth 1 -> 0)))) + (t/22 (x/19 (coercion (depth 3 -> 0))))}) (aliases_of_canonical_elements - {(element:"x" + {(x/19 {(Normal - {(element:"t" coercion:"hf") (element:"y" coercion:"f") - (element:"z" coercion:"Ghf")})})}) + {(z/21 (depth 2 -> 0)) (y/20 (depth 1 -> 0)) (t/22 (depth 3 -> 0))})})}) (binding_times_and_modes - {(element:"t" (bound at time 25 Normal)) - (element:"x" (bound at time 22 Normal)) - (element:"y" (bound at time 23 Normal)) - (element:"z" (bound at time 24 Normal))})) + {(z/21 (bound at time 24 Normal)) (y/20 (bound at time 23 Normal)) + (x/19 (bound at time 22 Normal)) (t/22 (bound at time 25 Normal))})) *** three aliases (two inverses) -[added] element:"x" <--[coercion:"f"]-- element:"y" -[added] element:"z" <--[coercion:"g"]-- element:"t" -[added] element:"z" <--[coercion:"FHg"]-- element:"x" +[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 - {(element:"t" element:"z" (coercion:"g")) - (element:"x" element:"z" (coercion:"FHg")) - (element:"y" element:"z" (coercion:"Hg"))}) + {(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_elements - {(element:"z" + {(z/25 {(Normal - {(element:"t" coercion:"g") (element:"x" coercion:"FHg") - (element:"y" coercion:"Hg")})})}) + {(x/23 (depth 0 -> 2)) (y/24 (depth 1 -> 2)) (t/26 (depth 3 -> 2))})})}) (binding_times_and_modes - {(element:"t" (bound at time 29 Normal)) - (element:"x" (bound at time 27 Normal)) - (element:"y" (bound at time 28 Normal)) - (element:"z" (bound at time 26 Normal))})) + {(z/25 (bound at time 26 Normal)) (x/23 (bound at time 27 Normal)) + (y/24 (bound at time 28 Normal)) (t/26 (bound at time 29 Normal))})) -OK. \ No newline at end of file +OK. From 0417117e1002e43e0b6c7d909df35216fe41b6b8 Mon Sep 17 00:00:00 2001 From: Luke Maurer Date: Mon, 8 Mar 2021 12:27:35 +0000 Subject: [PATCH 04/16] Address a CR --- middle_end/flambda/types/env/aliases.ml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/middle_end/flambda/types/env/aliases.ml b/middle_end/flambda/types/env/aliases.ml index 6b3cb5b8c85f..176e2c206d62 100644 --- a/middle_end/flambda/types/env/aliases.ml +++ b/middle_end/flambda/types/env/aliases.ml @@ -87,7 +87,7 @@ module Aliases_of_canonical_element : sig val move_variables_to_mode_in_types : t -> t - val compose : t -> newer:Coercion.t -> t + val compose : t -> then_:Coercion.t -> t end = struct type t = { aliases : map_to_canonical Name_mode.Map.t; @@ -225,16 +225,12 @@ end = struct invariant t; (* CR xclerc for xclerc: not guaranteed to hold *) t - let compose { aliases; all; } ~newer = + let compose { aliases; all; } ~then_ = let f m = Simple.Map.map (fun { coercion_to_canonical; } -> - (* CR lmaurer: This seems like the wrong way around to me, but - possibly only because I'm confused. At least, this function and/or - its argument should have a more descriptive name to make it - clearer what's going on - [newer] is not descriptive! *) { coercion_to_canonical = - Coercion.compose_exn coercion_to_canonical ~then_:newer; }) + Coercion.compose_exn coercion_to_canonical ~then_; }) m in let aliases = Name_mode.Map.map f aliases in @@ -482,7 +478,7 @@ let add_alias_between_canonical_elements t ~canonical_element ~coercion_to_canon let aliases = Aliases_of_canonical_element.add (Aliases_of_canonical_element.union - (Aliases_of_canonical_element.compose aliases_of_to_be_demoted ~newer:coercion_to_canonical) + (Aliases_of_canonical_element.compose aliases_of_to_be_demoted ~then_:coercion_to_canonical) aliases_of_canonical_element) to_be_demoted ~coercion_to_canonical From 29b542050c3ad5143ca0ae89fdd0084a668e353d Mon Sep 17 00:00:00 2001 From: Luke Maurer Date: Thu, 11 Mar 2021 16:16:29 +0000 Subject: [PATCH 05/16] Update .depend --- .depend | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.depend b/.depend index 207ecfc0d9d3..4b2d812d7c8c 100644 --- a/.depend +++ b/.depend @@ -6940,7 +6940,6 @@ middle_end/flambda/simplify/simplify_unary_primitive.cmo : \ middle_end/flambda/basic/simple.cmi \ utils/numbers.cmi \ middle_end/flambda/simplify/typing_helpers/number_adjuncts.cmi \ - middle_end/flambda/naming/name_in_binding_pos.cmi \ middle_end/flambda/basic/name.cmi \ middle_end/flambda/basic/closure_id.cmi \ middle_end/flambda/simplify/simplify_unary_primitive.cmi @@ -6955,7 +6954,6 @@ middle_end/flambda/simplify/simplify_unary_primitive.cmx : \ middle_end/flambda/basic/simple.cmx \ utils/numbers.cmx \ middle_end/flambda/simplify/typing_helpers/number_adjuncts.cmx \ - middle_end/flambda/naming/name_in_binding_pos.cmx \ middle_end/flambda/basic/name.cmx \ middle_end/flambda/basic/closure_id.cmx \ middle_end/flambda/simplify/simplify_unary_primitive.cmi @@ -9649,6 +9647,7 @@ middle_end/flambda/types/structures/product_intf.cmx : \ utils/identifiable.cmx \ middle_end/flambda/types/kinds/flambda_kind.cmx middle_end/flambda/types/structures/row_like.rec.cmo : \ + middle_end/flambda/basic/var_within_closure.cmi \ utils/targetint.cmi \ middle_end/flambda/compilenv_deps/target_imm.cmi \ middle_end/flambda/types/basic/tag_or_unknown_and_size.cmi \ @@ -9669,6 +9668,7 @@ middle_end/flambda/types/structures/row_like.rec.cmo : \ utils/clflags.cmi \ middle_end/flambda/types/structures/row_like.rec.cmi middle_end/flambda/types/structures/row_like.rec.cmx : \ + middle_end/flambda/basic/var_within_closure.cmx \ utils/targetint.cmx \ middle_end/flambda/compilenv_deps/target_imm.cmx \ middle_end/flambda/types/basic/tag_or_unknown_and_size.cmx \ @@ -9689,6 +9689,7 @@ middle_end/flambda/types/structures/row_like.rec.cmx : \ utils/clflags.cmx \ middle_end/flambda/types/structures/row_like.rec.cmi middle_end/flambda/types/structures/row_like.rec.cmi : \ + middle_end/flambda/basic/var_within_closure.cmi \ middle_end/flambda/types/structures/type_structure_intf.cmo \ utils/targetint.cmi \ middle_end/flambda/compilenv_deps/target_imm.cmi \ From 98168413a709df5cb8b99575992d2d7c914a48a9 Mon Sep 17 00:00:00 2001 From: Luke Maurer Date: Thu, 18 Mar 2021 10:50:16 +0000 Subject: [PATCH 06/16] Overhaul Aliases_of_canonical_element; add Alias_set Also return Bottom from more places (generally anything involved in a meet). --- .depend | 9 +- compilerlibs/Makefile.compilerlibs | 2 +- middle_end/flambda/basic/kinded_parameter.ml | 2 - middle_end/flambda/basic/kinded_parameter.mli | 2 - middle_end/flambda/compilenv_deps/coercion.ml | 2 +- .../flambda/compilenv_deps/coercion.mli | 7 + .../flambda/compilenv_deps/flambda_colours.ml | 2 +- .../compilenv_deps/reg_width_things.mli | 2 + .../common_subexpression_elimination.ml | 17 +- middle_end/flambda/types/env/aliases.ml | 1261 +++++++++++------ middle_end/flambda/types/env/aliases.mli | 49 +- .../flambda/types/env/typing_env.rec.ml | 112 +- .../flambda/types/env/typing_env.rec.mli | 4 +- middle_end/flambda/types/flambda_type.mli | 2 +- middle_end/flambda/types/type_descr.rec.ml | 66 +- testsuite/tests/flambda2-aliases/test.ml | 265 +++- .../tests/flambda2-aliases/test.reference | 236 ++- 17 files changed, 1449 insertions(+), 591 deletions(-) diff --git a/.depend b/.depend index 4b2d812d7c8c..1c78f2c0920d 100644 --- a/.depend +++ b/.depend @@ -6002,6 +6002,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 \ @@ -6019,6 +6020,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 \ @@ -9008,7 +9010,6 @@ middle_end/flambda/types/type_descr.rec.cmo : \ 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/aliases.cmi \ middle_end/flambda/types/type_descr.rec.cmi @@ -9027,7 +9028,6 @@ middle_end/flambda/types/type_descr.rec.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/aliases.cmx \ middle_end/flambda/types/type_descr.rec.cmi @@ -9296,6 +9296,8 @@ middle_end/flambda/types/basic/var_within_closure_set.cmi : \ middle_end/flambda/types/env/aliases.cmo : \ middle_end/flambda/compilenv_deps/variable.cmi \ middle_end/flambda/basic/simple.cmi \ + middle_end/flambda/compilenv_deps/reg_width_things.cmi \ + middle_end/flambda/types/basic/or_bottom.cmi \ middle_end/flambda/naming/name_mode.cmi \ middle_end/flambda/basic/name.cmi \ utils/misc.cmi \ @@ -9308,6 +9310,8 @@ middle_end/flambda/types/env/aliases.cmo : \ middle_end/flambda/types/env/aliases.cmx : \ middle_end/flambda/compilenv_deps/variable.cmx \ middle_end/flambda/basic/simple.cmx \ + middle_end/flambda/compilenv_deps/reg_width_things.cmx \ + middle_end/flambda/types/basic/or_bottom.cmx \ middle_end/flambda/naming/name_mode.cmx \ middle_end/flambda/basic/name.cmx \ utils/misc.cmx \ @@ -9319,6 +9323,7 @@ middle_end/flambda/types/env/aliases.cmx : \ middle_end/flambda/types/env/aliases.cmi middle_end/flambda/types/env/aliases.cmi : \ middle_end/flambda/basic/simple.cmi \ + middle_end/flambda/types/basic/or_bottom.cmi \ middle_end/flambda/naming/name_mode.cmi \ middle_end/flambda/basic/name.cmi \ middle_end/flambda/cmx/contains_ids.cmo \ diff --git a/compilerlibs/Makefile.compilerlibs b/compilerlibs/Makefile.compilerlibs index b9d16b43d2e9..3a411c26d66b 100644 --- a/compilerlibs/Makefile.compilerlibs +++ b/compilerlibs/Makefile.compilerlibs @@ -224,6 +224,7 @@ MIDDLE_END_FLAMBDA_BASIC=\ middle_end/flambda/basic/coeffects.cmo \ middle_end/flambda/basic/effects.cmo \ middle_end/flambda/basic/export_id.cmo \ + middle_end/flambda/types/basic/or_bottom.cmo \ middle_end/flambda/types/basic/or_unknown.cmo \ middle_end/flambda/terms/flambda_primitive.cmo \ middle_end/flambda/basic/recursive.cmo \ @@ -260,7 +261,6 @@ MIDDLE_END_FLAMBDA_TYPES=\ middle_end/flambda/types/env/binding_time.cmo \ middle_end/flambda/types/env/aliases.cmo \ middle_end/flambda/types/basic/meet_or_join_op.cmo \ - middle_end/flambda/types/basic/or_bottom.cmo \ middle_end/flambda/types/basic/string_info.cmo \ middle_end/flambda/types/basic/or_unknown_or_bottom.cmo \ middle_end/flambda/types/structures/code_age_relation.cmo \ diff --git a/middle_end/flambda/basic/kinded_parameter.ml b/middle_end/flambda/basic/kinded_parameter.ml index b6490f90a31c..a4635033a8b1 100644 --- a/middle_end/flambda/basic/kinded_parameter.ml +++ b/middle_end/flambda/basic/kinded_parameter.ml @@ -115,8 +115,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/compilenv_deps/coercion.ml b/middle_end/flambda/compilenv_deps/coercion.ml index f71a0f29fbe3..2ac573a93674 100644 --- a/middle_end/flambda/compilenv_deps/coercion.ml +++ b/middle_end/flambda/compilenv_deps/coercion.ml @@ -43,7 +43,7 @@ let print ppf = function (Flambda_colours.coercion ()) from_depth to_depth (Flambda_colours.normal ()) - + let compose t1 ~then_:t2 = match t1, t2 with | Id, _ -> Some t2 diff --git a/middle_end/flambda/compilenv_deps/coercion.mli b/middle_end/flambda/compilenv_deps/coercion.mli index a08d54b7013e..da5a73f38f3c 100644 --- a/middle_end/flambda/compilenv_deps/coercion.mli +++ b/middle_end/flambda/compilenv_deps/coercion.mli @@ -24,12 +24,19 @@ type t = private 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 837933a92986..8a113fa32142 100644 --- a/middle_end/flambda/compilenv_deps/flambda_colours.ml +++ b/middle_end/flambda/compilenv_deps/flambda_colours.ml @@ -57,7 +57,7 @@ let name_abstraction () = C.fg_256 172 let rec_info () = C.fg_256 249 -let coercion () = C.fg_256 243 +let coercion () = C.fg_256 249 let error () = C.fg_256 160 diff --git a/middle_end/flambda/compilenv_deps/reg_width_things.mli b/middle_end/flambda/compilenv_deps/reg_width_things.mli index 26925f102200..b4cc31004a51 100644 --- a/middle_end/flambda/compilenv_deps/reg_width_things.mli +++ b/middle_end/flambda/compilenv_deps/reg_width_things.mli @@ -158,6 +158,8 @@ module Simple : sig val with_coercion : t -> Coercion.t -> t + (* 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) diff --git a/middle_end/flambda/simplify/common_subexpression_elimination.ml b/middle_end/flambda/simplify/common_subexpression_elimination.ml index 50bdf87a860b..7f69ae5cb500 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 = @@ -182,15 +187,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.Map.filter (fun simple _coercion -> - not (Simple.Set.mem simple params)) + |> Aliases.Alias_set.filter ~f:(fun simple -> + not (is_param simple)) in - Simple.Map.get_singleton aliases |> Option.map fst + (* 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/types/env/aliases.ml b/middle_end/flambda/types/env/aliases.ml index 176e2c206d62..e37fa83b0fe2 100644 --- a/middle_end/flambda/types/env/aliases.ml +++ b/middle_end/flambda/types/env/aliases.ml @@ -14,264 +14,482 @@ [@@@ocaml.warning "+a-4-30-40-41-42"] -type coercion_to_canonical = { - coercion_to_canonical : Coercion.t; -} [@@ocaml.unboxed] - -let print_coercion_to_canonical ppf { coercion_to_canonical; } = - Coercion.print ppf coercion_to_canonical - -let equal_coercion_to_canonical c1 c2 = - Coercion.equal c1.coercion_to_canonical c2.coercion_to_canonical - -type map_to_canonical = coercion_to_canonical Simple.Map.t - -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 - Simple.print elt - Coercion.print coercion1 - Coercion.print coercion2 - -let map_inter map1 map2 = - Simple.Map.merge (fun elt coercion1 coercion2 -> - match coercion1, coercion2 with - | None, None | Some _, None | None, Some _ -> None - | Some { coercion_to_canonical = coercion1; }, Some { coercion_to_canonical = coercion2; } -> - if Coercion.equal coercion1 coercion2 then - Some { coercion_to_canonical = coercion1; } - else - fatal_inconsistent ~func_name:"Aliases.map_inter" elt coercion1 coercion2) - map1 - map2 - -let map_union map1 map2 = - Simple.Map.union (fun elt coercion1 coercion2 -> - match coercion1, coercion2 with - | { coercion_to_canonical = coercion1; }, { coercion_to_canonical = coercion2; } -> - if Coercion.equal coercion1 coercion2 then - Some { coercion_to_canonical = coercion1; } - else - fatal_inconsistent ~func_name:"Aliases.map_union" elt coercion1 coercion2) - map1 - map2 +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 compose_map_values map ~then_:coercion : _ Name.Map.t Or_bottom.t = + if Coercion.is_id coercion then Ok map else + let exception Return_bottom in + match + Name.Map.map (fun old_coercion -> + match Coercion.compose old_coercion ~then_:coercion with + | Some c -> c + | None -> raise Return_bottom + ) map + with + | exception Return_bottom -> Bottom + | map -> Ok map + +(* CR lmaurer: This should be in [Patricia_tree] *) +let map_keys f m = + Name.Map.fold (fun name value acc -> + Name.Map.add (f name) value acc) + m + Name.Map.empty module Aliases_of_canonical_element : sig type t val print : Format.formatter -> t -> unit - val invariant : t -> unit + val invariant + : t + -> binding_times_and_modes:(Binding_time.With_name_mode.t Name.Map.t) + -> unit val empty : t - val is_empty : t -> bool - val add : t -> Simple.t -> coercion_to_canonical:Coercion.t -> Name_mode.t -> t + val add + : t + -> Name.t + -> coercion_to_canonical + -> Binding_time.With_name_mode.t + -> t - val find_earliest_candidates - : t - -> min_name_mode:Name_mode.t - -> map_to_canonical option + val earliest_alias : + t -> min_name_mode:Name_mode.t option -> (Name.t * Coercion.t) option val all : t -> map_to_canonical - val mem : t -> Simple.t -> bool - - val union : t -> t -> t - val inter : t -> t -> t + val mem : t -> Name.t -> bool - val import : (Simple.t -> Simple.t) -> t -> t + val union : t -> t -> t Or_bottom.t - val merge : t -> t -> t + val disjoint : t -> t -> bool + + val import : (Name.t -> Name.t) -> t -> t val move_variables_to_mode_in_types : t -> t - val compose : t -> then_:Coercion.t -> t + val apply_coercion_to_all : t -> Coercion.t -> t Or_bottom.t end = struct + module Earliest_alias : sig + type t = + | Earliest of { + name : Name.t; + coercion_to_canonical : Coercion.t; + binding_time : Binding_time.t + } + | No_alias + + val exists : t -> bool + val update : t -> Name.t -> coercion_to_canonical -> Binding_time.t -> t + val union : t -> t -> t + val map_name : t -> f:(Name.t -> Name.t) -> t + val map_coercion : t -> f:(Coercion.t -> Coercion.t) -> t + val print : Format.formatter -> t -> unit + end = struct + type t = + | Earliest of { + name : Name.t; + coercion_to_canonical : Coercion.t; + binding_time : Binding_time.t; + } + | No_alias + + let exists = function + | Earliest _ -> true + | No_alias -> false + + let update t new_name coercion_to_canonical binding_time = + match t with + | No_alias -> + Earliest { name = new_name; coercion_to_canonical; binding_time } + | Earliest { binding_time = old_binding_time; _ } -> + if Binding_time.strictly_earlier binding_time ~than:old_binding_time + then Earliest { name = new_name; coercion_to_canonical; binding_time } + else t + + let union t1 t2 = + match t2 with + | No_alias -> t1 + | Earliest { name; coercion_to_canonical; binding_time } -> + update t1 name coercion_to_canonical binding_time + + let map_name t ~f = + match t with + | Earliest e -> + let name = f e.name in + Earliest { e with name } + | No_alias -> No_alias + + let map_coercion t ~f = + match t with + | Earliest e -> + let coercion_to_canonical = f e.coercion_to_canonical in + Earliest { e with coercion_to_canonical } + | No_alias -> No_alias + + let print ppf = function + | Earliest { name; coercion_to_canonical; binding_time } -> + Format.fprintf ppf + "@[(%a@ \ + @[@<0>%s(coercion_to_canonical@ %a)@<0>%s@]@ \ + @[(binding_time@ %a)@])@]" + Name.print name + (if Coercion.is_id coercion_to_canonical + then Flambda_colours.elide () + else Flambda_colours.normal ()) + Coercion.print coercion_to_canonical + (Flambda_colours.normal ()) + Binding_time.print binding_time + | No_alias -> + Format.pp_print_string ppf "" + end + type t = { - aliases : map_to_canonical Name_mode.Map.t; all : map_to_canonical; + earliest : Earliest_alias.t; + earliest_normal : Earliest_alias.t; + (* Earliest alias whose name mode >= phantom (that is, normal or phantom) *) + earliest_ge_phantom : Earliest_alias.t; + (* Earliest alias whose name mode >= in-types *) + earliest_ge_in_types : Earliest_alias.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 -> - Simple.Map.union (fun elt _coercion1 _coercion2 -> - Misc.fatal_errorf "[Aliases_of_canonical_element.invariant]: \ - element %a appears in several modes" - Simple.print elt) - map - acc) - aliases - Simple.Map.empty - in - (* [all] is the union of all elements in [aliases] *) - if Simple.Map.equal equal_coercion_to_canonical 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.Map.print print_coercion_to_canonical) ppf aliases - let empty = { - aliases = Name_mode.Map.empty; - all = Simple.Map.empty; + all = Name.Map.empty; + earliest = No_alias; + earliest_normal = No_alias; + earliest_ge_phantom = No_alias; + earliest_ge_in_types = No_alias; } - let is_empty t = Simple.Map.is_empty t.all - - let add t elt ~coercion_to_canonical name_mode = - if Simple.Map.mem elt t.all then begin + let print ppf + { earliest; earliest_normal; earliest_ge_phantom; earliest_ge_in_types; + all } = + let pp_earliest field_name ppf (earliest : Earliest_alias.t) = + Format.fprintf ppf "@[@<0>%s(%s@ %a)@<0>%s@]" + (if Earliest_alias.exists earliest + then Flambda_colours.normal () + else Flambda_colours.elide ()) + field_name + Earliest_alias.print earliest + (Flambda_colours.normal ()) + in + Format.fprintf ppf + "@[(\ + %a@ %a@ %a@ %a@ \ + @[(all@ %a)@])\ + @]" + (pp_earliest "earliest") earliest + (pp_earliest "earliest_normal") earliest_normal + (pp_earliest "earliest_ge_phantom") earliest_ge_phantom + (pp_earliest "earliest_ge_in_types") earliest_ge_in_types + (Name.Map.print Coercion.print) all + + let add t new_name coercion_to_canonical binding_time_and_name_mode = + if Name.Map.mem new_name t.all then begin Misc.fatal_errorf "%a already added to [Aliases_of_canonical_element]: \ %a" - Simple.print elt + Name.print new_name print t end; - let aliases = - Name_mode.Map.update name_mode - (function - | None -> Some (Simple.Map.singleton elt { coercion_to_canonical; }) - | Some elts -> - if !Clflags.flambda_invariant_checks then begin - assert (not (Simple.Map.mem elt elts)) - end; - Some (Simple.Map.add elt { coercion_to_canonical; } elts)) - t.aliases - in - let all = Simple.Map.add elt { coercion_to_canonical; } t.all in - { aliases; - all; - } + let binding_time, name_mode = + Binding_time.With_name_mode.( + binding_time binding_time_and_name_mode, + name_mode binding_time_and_name_mode) + in + let update earliest = + Earliest_alias.update earliest new_name coercion_to_canonical + binding_time + in + let update_if_mode_ge mode earliest = + match Name_mode.compare_partial_order name_mode mode with + | Some c when c >= 0 -> update earliest + | _ -> earliest + in + let earliest = update t.earliest in + let earliest_normal = + update_if_mode_ge Name_mode.normal t.earliest_normal + in + let earliest_ge_phantom = + update_if_mode_ge Name_mode.phantom t.earliest_ge_phantom + in + let earliest_ge_in_types = + update_if_mode_ge Name_mode.in_types t.earliest_ge_in_types + in + let all = Name.Map.add new_name coercion_to_canonical t.all in + { earliest; earliest_normal; earliest_ge_phantom; earliest_ge_in_types; + all } + + let find_earliest t ~(min_name_mode : Name_mode.t option) = + match min_name_mode with + | None -> t.earliest + | Some min_name_mode -> + begin match Name_mode.descr min_name_mode with + | Normal -> t.earliest_normal + | Phantom -> t.earliest_ge_phantom + | In_types -> t.earliest_ge_in_types + end - let find_earliest_candidates t ~min_name_mode = - Name_mode.Map.fold (fun order aliases res_opt -> - match res_opt with - | Some _ -> res_opt - | None -> - begin match - Name_mode.compare_partial_order - order min_name_mode - with - | None -> None - | Some result -> - if result >= 0 then Some aliases else None - end) - t.aliases - None + let invariant t ~binding_times_and_modes = + let describe_field name_mode = + match name_mode with + | None -> "overall" + | Some name_mode -> + begin match Name_mode.descr name_mode with + | Normal -> "normal" + | Phantom -> "phantom (or normal)" + | In_types -> "in-types (or normal)" + end + in + let check name binding_time name_mode (earliest : Earliest_alias.t) = + match earliest with + | No_alias -> () + | Earliest e as earliest_as_recorded -> + if Binding_time.compare binding_time e.binding_time < 0 then + Misc.fatal_errorf + "@[Earliest %s alias %a@ has binding time %a,@ \ + earlier than %a@ in %a\ + @]" + (describe_field name_mode) + Name.print name + Binding_time.print binding_time + Earliest_alias.print earliest_as_recorded + print t + in + Name.Map.iter (fun name _coercion -> + let binding_time_and_mode = + Name.Map.find name binding_times_and_modes + in + let binding_time, name_mode = + Binding_time.With_name_mode.( + binding_time binding_time_and_mode, + name_mode binding_time_and_mode) + in + check name binding_time None t.earliest; + let earliest_in_mode = find_earliest t ~min_name_mode:(Some name_mode) in + check name binding_time (Some name_mode) earliest_in_mode + ) t.all; + let check_earliest min_name_mode = + match find_earliest t ~min_name_mode with + | No_alias -> () + | Earliest e as earliest -> + let in_map = + match Name.Map.find_opt e.name t.all with + | None -> false + | Some coercion -> Coercion.equal coercion e.coercion_to_canonical + in + if not in_map then begin + Misc.fatal_errorf + "@[Aliases_of_canonical_element: Earliest %s not in map@ \ + @[Alias: %a@ Map: %a@]@]" + (describe_field min_name_mode) + Earliest_alias.print earliest + (Name.Map.print Coercion.print) t.all + end + in + List.iter check_earliest + [ None; + Some Name_mode.normal; + Some Name_mode.phantom; + Some Name_mode.in_types ] let mem t elt = - Simple.Map.mem elt t.all + Name.Map.mem elt t.all let all t = t.all - let union t1 t2 = - let aliases : map_to_canonical Name_mode.Map.t= - Name_mode.Map.union (fun _order elts1 elts2 -> - Some (map_union elts1 elts2)) - t1.aliases t2.aliases - in - let t = - { aliases; - all = map_union t1.all t2.all; - } - in - invariant t; (* CR xclerc for xclerc: not guaranteed to hold *) - t + let earliest_alias t ~min_name_mode : (Name.t * Coercion.t) option = + match find_earliest t ~min_name_mode with + | Earliest { name; coercion_to_canonical; binding_time = _ } -> + Some (name, coercion_to_canonical) + | No_alias -> None - 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 (map_inter elts1 elts2)) - t1.aliases t2.aliases - in - let t = - { aliases; - all = map_inter t1.all t2.all; - } - in - invariant t; + let union t1 t2 : t Or_bottom.t = + let exception Return_bottom in + match + Name.Map.merge (fun _name coercion1 coercion2 -> + match coercion1, coercion2 with + | None, None -> assert false + | Some coercion, None + | None, Some coercion -> Some coercion + | Some coercion1, Some coercion2 -> + if Coercion.equal coercion1 coercion2 then Some coercion1 + else raise Return_bottom + ) t1.all t2.all + with + | exception Return_bottom -> Bottom + | all -> + let earliest = + Earliest_alias.union t1.earliest t2.earliest + in + let earliest_normal = + Earliest_alias.union t1.earliest_normal t2.earliest_normal + in + let earliest_ge_phantom = + Earliest_alias.union t1.earliest_ge_phantom t2.earliest_ge_phantom + in + let earliest_ge_in_types = + Earliest_alias.union t1.earliest_ge_in_types t2.earliest_ge_in_types + in + Ok { all; earliest; earliest_normal; earliest_ge_phantom; + earliest_ge_in_types; } + + let disjoint t1 t2 = + not (Name.Map.inter_domain_is_non_empty t1.all t2.all) + + let update_all_earliest + { all; earliest; earliest_normal; + earliest_ge_phantom; earliest_ge_in_types; } ~f = + let earliest = f earliest in + let earliest_normal = f earliest_normal in + let earliest_ge_phantom = f earliest_ge_phantom in + let earliest_ge_in_types = f earliest_ge_in_types in + { all; earliest; earliest_normal; earliest_ge_phantom; + earliest_ge_in_types; } + + let import import_name + ({ all; earliest = _; earliest_normal = _; earliest_ge_phantom = _; + earliest_ge_in_types = _ } as t) = + let all = map_keys import_name all in + let t = { t with all; } in + let t = update_all_earliest t ~f:(Earliest_alias.map_name ~f:import_name) in t - let import import_simple { aliases; all } = - let map_simple elts = - Simple.Map.fold (fun elt coercion acc -> - Simple.Map.add (import_simple elt) coercion acc) - elts - Simple.Map.empty - in - let aliases = Name_mode.Map.map map_simple aliases in - let all = map_simple all in - let t = { aliases; all } in - invariant t; (* CR xclerc for xclerc: not guaranteed to hold *) - t + let apply_coercion_to_all t coercion : t Or_bottom.t = + compose_map_values t.all ~then_:coercion + |> + Or_bottom.map ~f:(fun all -> + let t = { t with all; } in + let t = update_all_earliest t ~f:(fun earliest -> + (* This composition must succeed if coerce_map did *) + Earliest_alias.map_coercion earliest ~f:(fun coercion_to_canonical -> + Coercion.compose_exn coercion_to_canonical ~then_:coercion)) + in + t) - let merge t1 t2 = - let aliases = - Name_mode.Map.union (fun _mode map1 map2 -> - Some (map_union map1 map2) - ) - t1.aliases - t2.aliases - 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 move_variables_to_mode_in_types t = + update_all_earliest t ~f:(fun earliest -> + match earliest with + | Earliest { name; _ } when Name.is_var name -> No_alias + | _ -> earliest) +end - let compose { aliases; all; } ~then_ = - let f m = - Simple.Map.map - (fun { coercion_to_canonical; } -> - { coercion_to_canonical = - Coercion.compose_exn coercion_to_canonical ~then_; }) - m - in - let aliases = Name_mode.Map.map f aliases in - let all = f all in - { aliases; all; } - - let move_variables_to_mode_in_types { aliases; all; } = - let (no_vars_aliases, all_variables) = - Name_mode.Map.fold (fun mode aliases (no_vars_aliases, all_variables) -> - let key_is_var key _ = Simple.is_var key in - let (vars, non_vars) = Simple.Map.partition key_is_var aliases in - let no_vars_aliases = - if Simple.Map.is_empty non_vars then no_vars_aliases - else Name_mode.Map.add mode non_vars no_vars_aliases - in - no_vars_aliases, map_union vars all_variables) - aliases - (Name_mode.Map.empty, Simple.Map.empty) +module Alias_set = struct + type t = { + const : Const.t option; + names : Coercion.t Name.Map.t; + } + + 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 -> + let coercion = Simple.coercion simple in + { const = None; names = Name.Map.singleton name coercion }) + + 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 - let aliases = - if Name_mode.Map.mem Name_mode.in_types no_vars_aliases - then Misc.fatal_errorf "move_variables_to_mode_in_types: \ - The following non-vars have mode In_types:@ %a" - (Simple.Map.print print_coercion_to_canonical) - (Name_mode.Map.find Name_mode.in_types no_vars_aliases) - else - if Simple.Map.is_empty all_variables then no_vars_aliases - else Name_mode.Map.add Name_mode.in_types all_variables no_vars_aliases - in - { aliases; all; } + Format.fprintf ppf + "@[(\ + @[(const@ %a)@]@ \ + @[(names@ %a)@]@ \ + @]" + (Format.pp_print_option Const.print ~none) const + (Name.Map.print Coercion.print) names + + let apply_coercion_to_all { const; names; } coercion = + compose_map_values names ~then_:coercion + |> + Or_bottom.map ~f:(fun names -> { const; 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 = + Name.Map.merge (fun _name coercion1 coercion2 -> + match coercion1, coercion2 with + | Some coercion1, Some coercion2 + when Coercion.equal coercion1 coercion2 -> Some coercion1 + | _, _ -> None + ) 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 _ = Name.is_symbol key in + let (symbols, vars) = Name.Map.partition key_is_symbol names in + let simple_of_binding (name, coercion) = + Simple.with_coercion (Simple.name name) coercion + in + match Name.Map.min_binding_opt symbols with + | Some binding -> + Some (binding |> simple_of_binding) + | None -> + match Name.Map.min_binding_opt vars with + | Some binding -> + Some (binding |> simple_of_binding) + | None -> + None end type t = { - canonical_elements : (Simple.t * coercion_to_canonical) Simple.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 + canonical_elements : (Simple.t * coercion_to_canonical) Name.Map.t; + (* Canonical elements that have no known aliases may not be included in + [canonical_elements]. (This comment used to say "are not included," but + this was not the case; any code that relied on this invariant should be + fixed.) *) + 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 @@ -304,69 +522,94 @@ type t = { canonical_elements[elem_j_n] = (canon_j, coercion_j_n) *) -let print ppf { canonical_elements; aliases_of_canonical_elements; - binding_times_and_modes; } = +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.coercion_to_canonical + (if Coercion.is_id coercion then Flambda_colours.elide () else Flambda_colours.normal ()) - print_coercion_to_canonical coercion + Coercion.print coercion (Flambda_colours.normal ()) in Format.fprintf ppf "@[(\ @[(canonical_elements@ %a)@]@ \ - @[(aliases_of_canonical_elements@ %a)@]@ \ + @[(aliases_of_canonical_names@ %a)@]@ \ + @[(aliases_of_consts@ %a)@]@ \ @[(binding_times_and_modes@ %a)@]\ )@]" - (Simple.Map.print print_element_and_coercion) canonical_elements - (Simple.Map.print Aliases_of_canonical_element.print) - aliases_of_canonical_elements - (Simple.Map.print Binding_time.With_name_mode.print) + (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 name_mode t elt = - Binding_time.With_name_mode.name_mode - (Simple.Map.find elt t.binding_times_and_modes) + Simple.pattern_match elt + ~const:(fun _ -> Name_mode.normal) + ~name:(fun elt -> + Binding_time.With_name_mode.name_mode + (Name.Map.find elt t.binding_times_and_modes)) + +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 invariant t = if !Clflags.flambda_invariant_checks then begin let _all_aliases : map_to_canonical = - Simple.Map.fold (fun canonical_element aliases all_aliases -> - Aliases_of_canonical_element.invariant aliases; + Name.Map.fold (fun canonical_element aliases all_aliases -> + Aliases_of_canonical_element.invariant aliases + ~binding_times_and_modes:t.binding_times_and_modes; let aliases = Aliases_of_canonical_element.all aliases in - if not (Simple.Map.for_all (fun elt _coercion -> - defined_earlier t canonical_element ~than:elt) aliases) + if not (Name.Map.for_all (fun elt _coercion -> + defined_earlier t (Simple.name canonical_element) + ~than:(Simple.name 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.Map.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.Map.print print_coercion_to_canonical) aliases + Name.print canonical_element + (Name.Map.print Coercion.print) aliases end; - if not (Simple.Map.is_empty (map_inter aliases all_aliases)) then + if Name.Map.inter_domain_is_non_empty aliases all_aliases then begin Misc.fatal_errorf "Overlapping alias sets:@ %a" print t end; - map_union aliases all_aliases) - t.aliases_of_canonical_elements - Simple.Map.empty + Name.Map.disjoint_union aliases all_aliases) + t.aliases_of_canonical_names + Name.Map.empty in () end @@ -374,9 +617,10 @@ 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 = @@ -387,16 +631,37 @@ type canonical = } let canonical t element : canonical = - match Simple.Map.find element 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; } + 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_from_name_to_canonical_element -> + let coercion_from_name_to_element = Simple.coercion element in + if !Clflags.flambda_invariant_checks then begin + assert (not (Simple.equal element canonical_element)) + end; + let coercion_from_element_to_canonical_element = + Coercion.compose_exn + (Coercion.inverse coercion_from_name_to_element) + ~then_:coercion_from_name_to_canonical_element + in + let coercion_to_canonical = + coercion_from_element_to_canonical_element + in + 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 + if !Clflags.flambda_invariant_checks then begin + assert (Coercion.is_id (Simple.coercion canonical_element)) + end; + 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 @@ -441,68 +706,102 @@ let get_aliases_of_canonical_element t ~canonical_element = 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 = +let add_alias_between_canonical_elements t ~canonical_element ~coercion_to_canonical ~to_be_demoted + : _ Or_bottom.t = if Simple.equal canonical_element to_be_demoted then begin if Coercion.is_id coercion_to_canonical then begin - t + Ok t end else - Misc.fatal_errorf "Cannot add an alias to itself with a non-identity coercion" + 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 be demoting 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.Map.fold (fun alias { coercion_to_canonical = coercion_to_to_be_demoted; } canonical_elements -> - let coercion_to_canonical = - Coercion.compose_exn coercion_to_to_be_demoted ~then_:coercion_to_canonical - in - Simple.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, { 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)); - assert (Aliases_of_canonical_element.is_empty ( - Aliases_of_canonical_element.inter - aliases_of_canonical_element aliases_of_to_be_demoted)) + aliases_of_canonical_element name_to_be_demoted)); + assert (Aliases_of_canonical_element.disjoint + aliases_of_canonical_element aliases_of_to_be_demoted) end; + let ( let* ) x f = Or_bottom.bind x ~f in + let* aliases = + Aliases_of_canonical_element.apply_coercion_to_all + aliases_of_to_be_demoted coercion_to_canonical + in + let* aliases = + Aliases_of_canonical_element.union aliases aliases_of_canonical_element + in let aliases = Aliases_of_canonical_element.add - (Aliases_of_canonical_element.union - (Aliases_of_canonical_element.compose aliases_of_to_be_demoted ~then_:coercion_to_canonical) - aliases_of_canonical_element) - to_be_demoted - ~coercion_to_canonical - (name_mode 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 + aliases + name_to_be_demoted + coercion_to_canonical + (binding_time_and_name_mode t to_be_demoted) + in + 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 canonical_elements = + t.canonical_elements + |> Name.Map.fold (fun alias coercion_to_to_be_demoted canonical_elements -> + let coercion_to_canonical = + (* This shouldn't throw an exception, since the previous + compositions succeeded *) + 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) + |> Name.Map.add name_to_be_demoted + (canonical_element, coercion_to_canonical) 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 + Ok res -type to_be_demoted = Demote_element1 | Demote_element2 +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 Demote_element2 else Demote_element1 + then Demote_canonical_element2 else Demote_canonical_element1 (* CR mshinwell: add submodule *) type add_result = { @@ -542,7 +841,7 @@ let add_alias t ~element1 ~coercion_from_element2_to_element1 ~element2 = ~canonical_element1 ~canonical_element2 in match which_element with - | Demote_element1 -> + | Demote_canonical_element1 -> let coercion_from_canonical_element1_to_canonical_element2 = Coercion.inverse coercion_from_canonical_element2_to_canonical_element1 @@ -550,7 +849,7 @@ let add_alias t ~element1 ~coercion_from_element2_to_element1 ~element2 = canonical_element2, canonical_element1, element1, coercion_from_canonical_element1_to_canonical_element2, coercion_from_element1_to_canonical_element1 - | Demote_element2 -> + | Demote_canonical_element2 -> canonical_element1, canonical_element2, element2, coercion_from_canonical_element2_to_canonical_element1, coercion_from_element2_to_canonical_element2 @@ -559,8 +858,7 @@ let add_alias t ~element1 ~coercion_from_element2_to_element1 ~element2 = add_alias_between_canonical_elements t ~canonical_element - ~coercion_to_canonical: - { coercion_to_canonical = coercion_from_demoted_to_canonical; } + ~coercion_to_canonical:coercion_from_demoted_to_canonical ~to_be_demoted in let coercion_from_alias_of_demoted_to_canonical = @@ -568,11 +866,12 @@ let add_alias t ~element1 ~coercion_from_element2_to_element1 ~element2 = coercion_from_alias_of_demoted_to_demoted ~then_:coercion_from_demoted_to_canonical in - { t; - canonical_element; - alias_of_demoted_element; - coercion_from_alias_of_demoted_to_canonical; - } + Or_bottom.map t ~f:(fun t -> + { t; + canonical_element; + alias_of_demoted_element; + coercion_from_alias_of_demoted_to_canonical; + }) in match canonical t element1, canonical t element2 with | Is_canonical, Is_canonical -> @@ -589,9 +888,7 @@ let add_alias t ~element1 ~coercion_from_element2_to_element1 ~element2 = ~coercion_from_canonical_element2_to_canonical_element1 | Alias_of_canonical { canonical_element = canonical_element1; - coercion_to_canonical = { - coercion_to_canonical = coercion_from_element1_to_canonical_element1; - }; + coercion_to_canonical = coercion_from_element1_to_canonical_element1; }, Is_canonical -> let canonical_element2 = element2 in @@ -612,9 +909,7 @@ let add_alias t ~element1 ~coercion_from_element2_to_element1 ~element2 = | Is_canonical, Alias_of_canonical { canonical_element = canonical_element2; - coercion_to_canonical = { - coercion_to_canonical = coercion_from_element2_to_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 @@ -637,15 +932,11 @@ let add_alias t ~element1 ~coercion_from_element2_to_element1 ~element2 = ~coercion_from_canonical_element2_to_canonical_element1 | Alias_of_canonical { canonical_element = canonical_element1; - coercion_to_canonical = { - coercion_to_canonical = coercion_from_element1_to_canonical_element1; - }; + coercion_to_canonical = coercion_from_element1_to_canonical_element1; }, Alias_of_canonical { canonical_element = canonical_element2; - coercion_to_canonical = { - coercion_to_canonical = coercion_from_element2_to_canonical_element2; - }; + coercion_to_canonical = coercion_from_element2_to_canonical_element2; } -> let coercion_from_canonical_element2_to_canonical_element1 = (* canonical_element1 <--[c1]-- element1 @@ -670,6 +961,18 @@ let add_alias t ~element1 ~coercion_from_element2_to_element1 ~element2 = let add t ~element1:element1_with_coercion ~binding_time_and_mode1 ~element2:element2_with_coercion ~binding_time_and_mode2 = + Simple.pattern_match element1_with_coercion + ~name:(fun _ -> ()) + ~const:(fun const1 -> + Simple.pattern_match element2_with_coercion + ~name:(fun _ -> ()) + ~const:(fun const2 -> + if not (Const.equal const1 const2) then begin + Misc.fatal_errorf + "Cannot add alias between two non-equal consts: %a <> %a" + Const.print const1 + Const.print const2 + end)); let original_t = t in (* element1_with_coercion <--[c1]-- element1 + @@ -685,21 +988,34 @@ let add t ~element1:element1_with_coercion ~binding_time_and_mode1 Coercion.compose_exn (Simple.coercion element2_with_coercion) ~then_:(Coercion.inverse (Simple.coercion element1_with_coercion)) in + 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 ~coercion_from_element2_to_element1 ~element2 in + let add_result : add_result Or_bottom.t = + 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 + match add_result with + | Ok add_result -> invariant_add_result ~original_t add_result + | Bottom -> () 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 @@ -724,123 +1040,221 @@ let mem t element = *) let get_canonical_element_exn t element elt_name_mode ~min_name_mode = - 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, { coercion_to_canonical = Coercion.id; } - else raise Not_found - end - | canonical_element, coercion_to_canonical -> + 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 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 - match - Aliases_of_canonical_element.find_earliest_candidates aliases - ~min_name_mode - with - | Some at_earliest_mode -> - (* Aliases_of_canonical_element.find_earliest_candidates only returns - non-empty sets *) - assert (not (Simple.Map.is_empty at_earliest_mode)); - Simple.Map.fold (fun elt coercion ((min_elt, _min_coercion) as min_binding) -> - if defined_earlier t elt ~than:min_elt - then elt, coercion - else min_binding) - at_earliest_mode - (Simple.Map.min_binding at_earliest_mode) - | None -> raise Not_found - in + if !Clflags.flambda_invariant_checks then 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 () = + (* 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 appear + 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 match - Name_mode.compare_partial_order - (name_mode t canonical_element) - min_name_mode + Aliases_of_canonical_element.earliest_alias aliases + ~min_name_mode:(Some min_name_mode) with - | None -> find_earliest () - | Some c -> - if c >= 0 then canonical_element, coercion_to_canonical - else find_earliest () + | Some (earliest, coercion_from_earliest_to_canonical) -> + 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 make_get_aliases_result + ~element:_ + ~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 }) let get_aliases t element = match canonical t element with | Is_canonical -> let canonical_element = element in - let aliases = + let names_with_coercions_to_canonical = Aliases_of_canonical_element.all (get_aliases_of_canonical_element t ~canonical_element) in - Simple.Map.add element { coercion_to_canonical = Coercion.id; } aliases - | Alias_of_canonical { canonical_element; coercion_to_canonical; } -> + let names_with_coercions_to_element = + names_with_coercions_to_canonical + in + let coercion_from_canonical_to_element = Coercion.id in + make_get_aliases_result + ~element + ~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) + (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.Map.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.Map.add canonical_element coercion_to_canonical aliases + + make_get_aliases_result + ~element + ~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 elt _binding_time_and_mode ids -> - Ids_for_export.add_simple ids elt) - binding_times_and_modes - Ids_for_export.empty + let ids = Ids_for_export.empty in + let ids = + Name.Map.fold (fun elt _binding_time_and_mode ids -> + Ids_for_export.add_name ids elt) + binding_times_and_modes + ids + in + let ids = + Const.Map.fold (fun elt _aliases ids -> + Ids_for_export.add_const ids elt) + aliases_of_consts + ids + in + ids let import import_map { canonical_elements; - aliases_of_canonical_elements; - binding_times_and_modes; } = + aliases_of_canonical_names; + aliases_of_consts; + binding_times_and_modes } = let import_simple x = Ids_for_export.Import_map.simple import_map x in + let import_name x = Ids_for_export.Import_map.name import_map x in + let import_const c = Ids_for_export.Import_map.const import_map c in let canonical_elements = - Simple.Map.fold (fun elt (canonical, coercion) acc -> - Simple.Map.add (import_simple elt) (import_simple canonical, coercion) acc) + Name.Map.fold (fun elt (canonical, coercion) acc -> + Name.Map.add (import_name elt) (import_simple canonical, coercion) acc) canonical_elements - Simple.Map.empty + Name.Map.empty + in + let aliases_of_canonical_names = + Name.Map.fold (fun canonical aliases acc -> + Name.Map.add (import_name canonical) + (Aliases_of_canonical_element.import import_name aliases) + acc) + aliases_of_canonical_names + Name.Map.empty in - let aliases_of_canonical_elements = - Simple.Map.fold (fun canonical aliases acc -> - Simple.Map.add (import_simple canonical) - (Aliases_of_canonical_element.import import_simple aliases) + let aliases_of_consts = + Const.Map.fold (fun const aliases acc -> + Const.Map.add (import_const const) + (Aliases_of_canonical_element.import import_name aliases) acc) - aliases_of_canonical_elements - Simple.Map.empty + aliases_of_consts + Const.Map.empty in let binding_times_and_modes = - Simple.Map.fold (fun simple binding_time_and_mode acc -> - Simple.Map.add (import_simple simple) binding_time_and_mode acc) - binding_times_and_modes - Simple.Map.empty + map_keys import_name binding_times_and_modes in - { canonical_elements; - aliases_of_canonical_elements; - binding_times_and_modes; - } + let t = + { canonical_elements; + aliases_of_canonical_names; + aliases_of_consts; + binding_times_and_modes; + } + in + invariant t; + t 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 = + match Aliases_of_canonical_element.union aliases1 aliases2 with + | Ok aliases -> Some aliases + | Bottom -> + (* CR lmaurer: This is actually possible, if probably exceedingly rare, + so we should be returting Bottom in this case. *) + Misc.fatal_errorf "Conflicting aliases:@ %a@ vs.@ %a" + print t1 + print t2 + 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 @@ -848,34 +1262,30 @@ let merge t1 t2 = 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; } @@ -883,32 +1293,39 @@ let get_canonical_ignoring_name_mode t name = let elt = Simple.name name in match canonical t elt with | Is_canonical -> - elt, { coercion_to_canonical = Coercion.id } - | Alias_of_canonical { canonical_element; coercion_to_canonical } -> - canonical_element, coercion_to_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; } = let binding_times_and_modes = - Simple.Map.mapi (fun simple binding_time_and_mode -> + Name.Map.mapi (fun name binding_time_and_mode -> let module BTM = Binding_time.With_name_mode in let new_mode = - if Simple.is_var simple then Name_mode.in_types + if Name.is_var name then Name_mode.in_types else BTM.name_mode binding_time_and_mode in BTM.create (BTM.binding_time binding_time_and_mode) new_mode) binding_times_and_modes in - let aliases_of_canonical_elements = + let aliases_of_canonical_names = (* Note: the relative order of the aliases and of their canonical element will be unchanged, as it only depends on the binding times. *) - Simple.Map.map Aliases_of_canonical_element.move_variables_to_mode_in_types - aliases_of_canonical_elements + Name.Map.map Aliases_of_canonical_element.move_variables_to_mode_in_types + aliases_of_canonical_names + in + let aliases_of_consts = + Const.Map.map Aliases_of_canonical_element.move_variables_to_mode_in_types + aliases_of_consts in { 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 fb7f81159af1..ce1147975448 100644 --- a/middle_end/flambda/types/env/aliases.mli +++ b/middle_end/flambda/types/env/aliases.mli @@ -18,12 +18,6 @@ [@@@ocaml.warning "+a-4-30-40-41-42"] -(* CR lmaurer: Maybe we should similarly have a type [canonical] isomorphic - to [Simple.t]? *) -type coercion_to_canonical = { - coercion_to_canonical : Coercion.t; -} [@@ocaml.unboxed] - type t include Contains_ids.S with type t := t @@ -36,8 +30,8 @@ val empty : t type add_result = private { t : t; - canonical_element : Simple.t; - alias_of_demoted_element : Simple.t; + canonical_element : Simple.t; (* has no coercion *) + alias_of_demoted_element : Simple.t; (* has no coercion *) coercion_from_alias_of_demoted_to_canonical : Coercion.t; } @@ -47,7 +41,7 @@ val add -> 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 + -> add_result Or_bottom.t val mem : t -> Simple.t -> bool @@ -58,15 +52,44 @@ val get_canonical_element_exn -> Simple.t -> Name_mode.t -> min_name_mode:Name_mode.t - -> Simple.t * coercion_to_canonical + -> 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 apply_coercion_to_all : t -> Coercion.t -> t Or_bottom.t -(** [get_aliases] always returns the supplied element in the result set. *) -val get_aliases : t -> Simple.t -> coercion_to_canonical Simple.Map.t + 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 includes the supplied element in the alias set. *) +val get_aliases + : t + -> Simple.t + -> Alias_set.t val get_canonical_ignoring_name_mode : t -> Name.t - -> Simple.t * coercion_to_canonical + -> Simple.t val merge : t -> t -> t diff --git a/middle_end/flambda/types/env/typing_env.rec.ml b/middle_end/flambda/types/env/typing_env.rec.ml index ee0cf51231ff..46a24c165783 100644 --- a/middle_end/flambda/types/env/typing_env.rec.ml +++ b/middle_end/flambda/types/env/typing_env.rec.ml @@ -443,7 +443,7 @@ let print_with_cache ~cache ppf "@[(\ @[(defined_symbols@ %a)@]@ \ @[(code_age_relation@ %a)@]@ \ - @[(levels@ %a)@]\ + @[(levels@ %a)@]@ \ @[(aliases@ %a)@]\ )@]" Symbol.Set.print defined_symbols @@ -882,8 +882,9 @@ let rec add_equation0 t aliases name ty = | _ -> false in if is_concrete then begin - let canonical, _ = + 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 \ @@ -990,39 +991,60 @@ and add_equation t name ty = end) ~const:(fun _ -> ()) end; - let aliases, simple, coercion, t, ty = + let aliases, lhs, t, ty = let aliases = aliases t in match Type_grammar.get_alias_exn ty with | exception Not_found -> (* Equations giving concrete types may only be added to the canonical element as known by the alias tracker (the actual canonical, ignoring any name modes). *) - let canonical, { Aliases.coercion_to_canonical = coercion } = + let canonical = Aliases.get_canonical_ignoring_name_mode aliases name in - aliases, canonical, coercion, t, ty + let lhs = canonical in + aliases, lhs, t, ty | alias_of -> + (* 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_demoted_element; - t = aliases; - coercion_from_alias_of_demoted_to_canonical = coercion; } : Aliases.add_result) = + match 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 - let ty = - Type_grammar.alias_type_of kind canonical_element - in - aliases, alias_of_demoted_element, coercion, t, ty + with + | Bottom -> + let canonical = + Aliases.get_canonical_ignoring_name_mode aliases name + in + let lhs = canonical in + let ty = Type_grammar.bottom_like ty in + aliases, lhs, t, ty + | Ok { canonical_element; + alias_of_demoted_element; + t = aliases; + coercion_from_alias_of_demoted_to_canonical; } -> + let lhs = + Simple.with_coercion alias_of_demoted_element + coercion_from_alias_of_demoted_to_canonical + in + let ty = + Type_grammar.alias_type_of kind canonical_element + in + 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 @@ -1048,15 +1070,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 with + 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 @@ -1242,14 +1271,8 @@ let get_canonical_simple_with_kind_exn t ?min_name_mode simple = print t end; raise Misc.Fatal_error - | alias, { coercion_to_canonical = coercion } -> - match Coercion.compose coercion ~then_:(Simple.coercion simple) with - | None -> raise Not_found - | Some coercion -> - begin match Simple.apply_coercion alias coercion with - | None -> raise Not_found - | Some simple -> simple, kind - end + | canonical -> + canonical, kind let get_canonical_simple_exn t ?min_name_mode simple = (* Duplicated from above to eliminate the allocation of the returned pair. *) @@ -1328,41 +1351,22 @@ let get_canonical_simple_exn t ?min_name_mode simple = print t end; raise Misc.Fatal_error - | alias, { coercion_to_canonical = coercion } -> - match Coercion.compose coercion ~then_:(Simple.coercion simple) with - | None -> raise Not_found - | Some coercion -> - begin match Simple.apply_coercion alias coercion with - | None -> raise Not_found - | Some simple -> simple - end + | canonical -> canonical let get_alias_then_canonical_simple_exn t ?min_name_mode typ = Type_grammar.get_alias_exn typ |> get_canonical_simple_exn t ?min_name_mode let aliases_of_simple t ~min_name_mode simple = - let aliases = - Aliases.get_aliases (aliases t) simple - |> Simple.Map.filter (fun alias _coercion (* CR xclerc for xclerc: use the coercion. *) -> - let name_mode = - Binding_time.With_name_mode.name_mode - (binding_time_and_mode_of_simple t alias) - in - match Name_mode.compare_partial_order name_mode min_name_mode with - | None -> false - | Some c -> c >= 0) - in - let newer_coercion = Simple.coercion simple in - match newer_coercion with - | Id -> aliases - | _ -> - Simple.Map.fold (fun simple coercion simples -> - match Simple.apply_coercion simple newer_coercion with - | None -> simples - | Some simple -> Simple.Map.add simple coercion simples) - aliases - Simple.Map.empty + Aliases.get_aliases (aliases t) simple + |> 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) + in + match Name_mode.compare_partial_order name_mode min_name_mode with + | None -> false + | Some c -> c >= 0) let aliases_of_simple_allowable_in_types t simple = aliases_of_simple t ~min_name_mode:Name_mode.in_types simple diff --git a/middle_end/flambda/types/env/typing_env.rec.mli b/middle_end/flambda/types/env/typing_env.rec.mli index 1a99ff5d94c7..40dfebce2f4c 100644 --- a/middle_end/flambda/types/env/typing_env.rec.mli +++ b/middle_end/flambda/types/env/typing_env.rec.mli @@ -120,12 +120,12 @@ val aliases_of_simple : t -> min_name_mode:Name_mode.t -> Simple.t - -> Aliases.coercion_to_canonical Simple.Map.t + -> Aliases.Alias_set.t val aliases_of_simple_allowable_in_types : t -> Simple.t - -> Aliases.coercion_to_canonical Simple.Map.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 ee69e2d20e12..47b3e4769dfa 100644 --- a/middle_end/flambda/types/flambda_type.mli +++ b/middle_end/flambda/types/flambda_type.mli @@ -178,7 +178,7 @@ module Typing_env : sig : t -> min_name_mode:Name_mode.t -> Simple.t - -> Aliases.coercion_to_canonical Simple.Map.t + -> Aliases.Alias_set.t val clean_for_export : t -> reachable_names:Name_occurrences.t -> t diff --git a/middle_end/flambda/types/type_descr.rec.ml b/middle_end/flambda/types/type_descr.rec.ml index 40fdaa11b7d2..c657f5fbe202 100644 --- a/middle_end/flambda/types/type_descr.rec.ml +++ b/middle_end/flambda/types/type_descr.rec.ml @@ -243,20 +243,19 @@ module Make (Head : Type_head_intf.S let all_aliases_of env simple_opt ~in_env = match simple_opt with - | None -> Simple.Map.empty + | None -> + Aliases.Alias_set.empty | Some simple -> let simples = - Simple.Map.add simple { Aliases.coercion_to_canonical = Coercion.id; } ( - 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.Map.filter (fun simple _ -> - Typing_env.mem_simple in_env simple) - simples + Aliases.Alias_set.filter simples ~f:(fun simple -> + Typing_env.mem_simple in_env simple) let [@inline always] get_canonical_simples_and_expand_heads ~force_to_kind ~to_type kind ~left_env ~left_ty ~right_env ~right_ty = @@ -478,53 +477,27 @@ 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 = + (* CR lmaurer: Seems a bit hacky to be constructing alias sets here in + the trivial cases, and "find me a shared alias" sounds like a fine + operation to be in [Aliases], so we should figure out how to move + some of this logic over there. *) match canonical_simple1, canonical_simple2 with - | None, _ | _, None -> Simple.Set.empty + | None, _ | _, None -> Aliases.Alias_set.empty | Some simple1, Some simple2 -> if Simple.same simple1 simple2 - then Simple.Set.singleton simple1 + then Aliases.Alias_set.singleton simple1 else - let map_keys m = - Simple.Map.fold (fun simple _ acc -> - Simple.Set.add simple acc) - m - Simple.Set.empty - in - 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) |> map_keys) + ~in_env:(Join_env.target_join_env join_env)) (all_aliases_of (Join_env.right_join_env join_env) canonical_simple2 - ~in_env:(Join_env.target_join_env join_env) |> map_keys) + ~in_env:(Join_env.target_join_env join_env)) in match bound_name with | None -> shared_aliases @@ -532,16 +505,15 @@ module Make (Head : Type_head_intf.S (* CR vlaviron: this ensures that we're not creating an alias to a different simple that is just bound_name with different coercion. Such an alias is forbidden. *) - Simple.Set.filter (fun simple -> + Aliases.Alias_set.filter shared_aliases ~f:(fun simple -> not (Simple.same simple (Simple.name bound_name))) - shared_aliases in (* Format.eprintf "Shared aliases:@ %a\n%!" - Simple.Set.print shared_aliases; + Aliases.Alias_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/testsuite/tests/flambda2-aliases/test.ml b/testsuite/tests/flambda2-aliases/test.ml index 08e5154412ca..6130f3b3d6d8 100644 --- a/testsuite/tests/flambda2-aliases/test.ml +++ b/testsuite/tests/flambda2-aliases/test.ml @@ -8,23 +8,44 @@ let () = Clflags.flambda_invariant_checks := true let () = Clflags.dump_rawflambda := true let () = Misc.Color.setup (Some Never) -let () = +let compilation_unit = let dummy = "compilation_unit" in - Compilation_unit.set_current - (Compilation_unit.create - (Ident.create_persistent dummy) - (Linkage_name.create dummy)) + Compilation_unit.create + (Ident.create_persistent dummy) + (Linkage_name.create dummy) + +let () = Compilation_unit.set_current compilation_unit -let next_time : unit -> Binding_time.With_name_mode.t = +let next_time : ?mode:Name_mode.t -> unit -> Binding_time.With_name_mode.t = let next = ref Binding_time.earliest_var in - fun () -> + fun ?(mode = Name_mode.normal) () -> let time = !next in next := Binding_time.succ time; - Binding_time.With_name_mode.create time Name_mode.normal + Binding_time.With_name_mode.create time mode -let mk_simple name = Simple.var (Variable.create name) +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 = + match + Aliases.get_canonical_element_exn aliases simple name_mode ~min_name_mode + with + | exception Not_found -> None + | canonical -> Some canonical + let add_alias ppf aliases @@ -43,13 +64,28 @@ let add_alias ~binding_time_and_mode1 ~element2 ~binding_time_and_mode2 + |> of_ok + 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@." + 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; + 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; @@ -149,7 +185,7 @@ let () = test "two aliases (simple chain)" ~f:(fun ppf -> y <--[g]-- z ~> x <--[f]-- y - ^--[gf]-- z *) + ^--[fg]-- z *) let aliases = add_alias ppf @@ -220,7 +256,7 @@ let () = test "two aliases (one inverse)" ~f:(fun ppf -> + z <--[g]-- y ~> - z <--[Fg]-- x + z <--[gF]-- x ^--[g]-- y *) let aliases = add_alias @@ -257,7 +293,7 @@ let () = test "two aliases (one inverse)" ~f:(fun ppf -> z <--[g]-- y ~> x <--[f]-- y - ^--[Gf]-- z *) + ^--[fG]-- z *) let aliases = add_alias ppf @@ -297,8 +333,8 @@ let () = test "three aliases (one inverse)" ~f:(fun ppf -> y <--[h]-- t ~> x <--[f]-- y - ^^--[Ghf]-- z - \--[hf]-- t *) + ^^--[fhG]-- z + \--[fh]-- t *) let aliases = add_alias ppf @@ -347,8 +383,63 @@ let () = test "three aliases (two inverses)" ~f:(fun ppf -> + y <--[h]-- t ~> - z <--[FHg]-- x - ^^--[Hg]-- y + 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 @@ -382,4 +473,142 @@ let () = test "three aliases (two inverses)" ~f:(fun ppf -> 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 index 1beacc021fdc..6134263e0022 100644 --- a/testsuite/tests/flambda2-aliases/test.reference +++ b/testsuite/tests/flambda2-aliases/test.reference @@ -1,18 +1,36 @@ *** empty -((canonical_elements {}) (aliases_of_canonical_elements {}) - (binding_times_and_modes {})) +((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_elements {(x/0 {(Normal {(y/1 (depth 1 -> 0))})})}) + (aliases_of_canonical_names + {(x/0 + ((earliest (y/1 (coercion_to_canonical (depth 1 -> 0)) (binding_time 4))) + (earliest_normal + (y/1 (coercion_to_canonical (depth 1 -> 0)) (binding_time 4))) + (earliest_ge_phantom + (y/1 (coercion_to_canonical (depth 1 -> 0)) (binding_time 4))) + (earliest_ge_in_types + (y/1 (coercion_to_canonical (depth 1 -> 0)) (binding_time 4))) + (all {(y/1 (depth 1 -> 0))})))}) (aliases_of_consts {}) (binding_times_and_modes {(x/0 (bound at time 3 Normal)) (y/1 (bound at time 4 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_elements {(y/3 {(Normal {(x/2 (depth 0 -> 1))})})}) + (aliases_of_canonical_names + {(y/3 + ((earliest (x/2 (coercion_to_canonical (depth 0 -> 1)) (binding_time 6))) + (earliest_normal + (x/2 (coercion_to_canonical (depth 0 -> 1)) (binding_time 6))) + (earliest_ge_phantom + (x/2 (coercion_to_canonical (depth 0 -> 1)) (binding_time 6))) + (earliest_ge_in_types + (x/2 (coercion_to_canonical (depth 0 -> 1)) (binding_time 6))) + (all {(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))})) @@ -22,8 +40,17 @@ ((canonical_elements {(y/5 (x/4 (coercion (depth 1 -> 0)))) (z/6 (x/4 (coercion (depth 2 -> 0))))}) - (aliases_of_canonical_elements - {(x/4 {(Normal {(y/5 (depth 1 -> 0)) (z/6 (depth 2 -> 0))})})}) + (aliases_of_canonical_names + {(x/4 + ((earliest (y/5 (coercion_to_canonical (depth 1 -> 0)) (binding_time 8))) + (earliest_normal + (y/5 (coercion_to_canonical (depth 1 -> 0)) (binding_time 8))) + (earliest_ge_phantom + (y/5 (coercion_to_canonical (depth 1 -> 0)) (binding_time 8))) + (earliest_ge_in_types + (y/5 (coercion_to_canonical (depth 1 -> 0)) (binding_time 8))) + (all {(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))})) @@ -34,8 +61,18 @@ ((canonical_elements {(z/9 (x/7 (coercion (depth 2 -> 0)))) (y/8 (x/7 (coercion (depth 1 -> 0))))}) - (aliases_of_canonical_elements - {(x/7 {(Normal {(z/9 (depth 2 -> 0)) (y/8 (depth 1 -> 0))})})}) + (aliases_of_canonical_names + {(x/7 + ((earliest + (y/8 (coercion_to_canonical (depth 1 -> 0)) (binding_time 11))) + (earliest_normal + (y/8 (coercion_to_canonical (depth 1 -> 0)) (binding_time 11))) + (earliest_ge_phantom + (y/8 (coercion_to_canonical (depth 1 -> 0)) (binding_time 11))) + (earliest_ge_in_types + (y/8 (coercion_to_canonical (depth 1 -> 0)) (binding_time 11))) + (all {(z/9 (depth 2 -> 0)) (y/8 (depth 1 -> 0))})))}) + (aliases_of_consts {}) (binding_times_and_modes {(x/7 (bound at time 10 Normal)) (z/9 (bound at time 12 Normal)) (y/8 (bound at time 11 Normal))})) @@ -46,8 +83,18 @@ ((canonical_elements {(x/10 (z/12 (coercion (depth 0 -> 2)))) (y/11 (z/12 (coercion (depth 1 -> 2))))}) - (aliases_of_canonical_elements - {(z/12 {(Normal {(x/10 (depth 0 -> 2)) (y/11 (depth 1 -> 2))})})}) + (aliases_of_canonical_names + {(z/12 + ((earliest + (x/10 (coercion_to_canonical (depth 0 -> 2)) (binding_time 14))) + (earliest_normal + (x/10 (coercion_to_canonical (depth 0 -> 2)) (binding_time 14))) + (earliest_ge_phantom + (x/10 (coercion_to_canonical (depth 0 -> 2)) (binding_time 14))) + (earliest_ge_in_types + (x/10 (coercion_to_canonical (depth 0 -> 2)) (binding_time 14))) + (all {(x/10 (depth 0 -> 2)) (y/11 (depth 1 -> 2))})))}) + (aliases_of_consts {}) (binding_times_and_modes {(z/12 (bound at time 13 Normal)) (x/10 (bound at time 14 Normal)) (y/11 (bound at time 15 Normal))})) @@ -58,8 +105,18 @@ ((canonical_elements {(x/13 (z/15 (coercion (depth 0 -> 2)))) (y/14 (z/15 (coercion (depth 1 -> 2))))}) - (aliases_of_canonical_elements - {(z/15 {(Normal {(x/13 (depth 0 -> 2)) (y/14 (depth 1 -> 2))})})}) + (aliases_of_canonical_names + {(z/15 + ((earliest + (x/13 (coercion_to_canonical (depth 0 -> 2)) (binding_time 17))) + (earliest_normal + (x/13 (coercion_to_canonical (depth 0 -> 2)) (binding_time 17))) + (earliest_ge_phantom + (x/13 (coercion_to_canonical (depth 0 -> 2)) (binding_time 17))) + (earliest_ge_in_types + (x/13 (coercion_to_canonical (depth 0 -> 2)) (binding_time 17))) + (all {(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))})) @@ -70,8 +127,18 @@ ((canonical_elements {(y/17 (x/16 (coercion (depth 1 -> 0)))) (z/18 (x/16 (coercion (depth 2 -> 0))))}) - (aliases_of_canonical_elements - {(x/16 {(Normal {(y/17 (depth 1 -> 0)) (z/18 (depth 2 -> 0))})})}) + (aliases_of_canonical_names + {(x/16 + ((earliest + (y/17 (coercion_to_canonical (depth 1 -> 0)) (binding_time 20))) + (earliest_normal + (y/17 (coercion_to_canonical (depth 1 -> 0)) (binding_time 20))) + (earliest_ge_phantom + (y/17 (coercion_to_canonical (depth 1 -> 0)) (binding_time 20))) + (earliest_ge_in_types + (y/17 (coercion_to_canonical (depth 1 -> 0)) (binding_time 20))) + (all {(y/17 (depth 1 -> 0)) (z/18 (depth 2 -> 0))})))}) + (aliases_of_consts {}) (binding_times_and_modes {(y/17 (bound at time 20 Normal)) (x/16 (bound at time 19 Normal)) (z/18 (bound at time 21 Normal))})) @@ -84,10 +151,19 @@ {(z/21 (x/19 (coercion (depth 2 -> 0)))) (y/20 (x/19 (coercion (depth 1 -> 0)))) (t/22 (x/19 (coercion (depth 3 -> 0))))}) - (aliases_of_canonical_elements + (aliases_of_canonical_names {(x/19 - {(Normal - {(z/21 (depth 2 -> 0)) (y/20 (depth 1 -> 0)) (t/22 (depth 3 -> 0))})})}) + ((earliest + (y/20 (coercion_to_canonical (depth 1 -> 0)) (binding_time 23))) + (earliest_normal + (y/20 (coercion_to_canonical (depth 1 -> 0)) (binding_time 23))) + (earliest_ge_phantom + (y/20 (coercion_to_canonical (depth 1 -> 0)) (binding_time 23))) + (earliest_ge_in_types + (y/20 (coercion_to_canonical (depth 1 -> 0)) (binding_time 23))) + (all + {(z/21 (depth 2 -> 0)) (y/20 (depth 1 -> 0)) (t/22 (depth 3 -> 0))})))}) + (aliases_of_consts {}) (binding_times_and_modes {(z/21 (bound at time 24 Normal)) (y/20 (bound at time 23 Normal)) (x/19 (bound at time 22 Normal)) (t/22 (bound at time 25 Normal))})) @@ -100,12 +176,132 @@ {(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_elements + (aliases_of_canonical_names {(z/25 - {(Normal - {(x/23 (depth 0 -> 2)) (y/24 (depth 1 -> 2)) (t/26 (depth 3 -> 2))})})}) + ((earliest + (x/23 (coercion_to_canonical (depth 0 -> 2)) (binding_time 27))) + (earliest_normal + (x/23 (coercion_to_canonical (depth 0 -> 2)) (binding_time 27))) + (earliest_ge_phantom + (x/23 (coercion_to_canonical (depth 0 -> 2)) (binding_time 27))) + (earliest_ge_in_types + (x/23 (coercion_to_canonical (depth 0 -> 2)) (binding_time 27))) + (all + {(x/23 (depth 0 -> 2)) (y/24 (depth 1 -> 2)) (t/26 (depth 3 -> 2))})))}) + (aliases_of_consts {}) (binding_times_and_modes {(z/25 (bound at time 26 Normal)) (x/23 (bound at time 27 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 + {(x/27 (#1 (coercion (depth 0 -> 2)))) + (y/28 (#1 (coercion (depth 1 -> 2)))) + (t/29 (#1 (coercion (depth 3 -> 2))))}) (aliases_of_canonical_names {}) + (aliases_of_consts + {(#1 + ((earliest + (x/27 (coercion_to_canonical (depth 0 -> 2)) (binding_time 30))) + (earliest_normal + (x/27 (coercion_to_canonical (depth 0 -> 2)) (binding_time 30))) + (earliest_ge_phantom + (x/27 (coercion_to_canonical (depth 0 -> 2)) (binding_time 30))) + (earliest_ge_in_types + (x/27 (coercion_to_canonical (depth 0 -> 2)) (binding_time 30))) + (all + {(x/27 (depth 0 -> 2)) (y/28 (depth 1 -> 2)) (t/29 (depth 3 -> 2))})))}) + (binding_times_and_modes + {(x/27 (bound at time 30 Normal)) (y/28 (bound at time 31 Normal)) + (t/29 (bound at time 32 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 {(y/31 (depth 1 -> 0)) (x/30 id)}) + +*** 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 {(x/32 id) (y/33 (depth 1 -> 0))}) + +*** 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 {(y/37 (depth 1 -> 0)) (x/36 id)}) + +*** 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 + {(t/45 (depth 3 -> 0)) (x/42 id) (z/44 (depth 2 -> 0)) + (y/43 (depth 1 -> 0))}) + +((canonical_elements + {(t/45 (x/42 (coercion (depth 3 -> 0)))) + (z/44 (x/42 (coercion (depth 2 -> 0)))) + (y/43 (x/42 (coercion (depth 1 -> 0))))}) + (aliases_of_canonical_names + {(x/42 + ((earliest + (y/43 (coercion_to_canonical (depth 1 -> 0)) (binding_time 46))) + (earliest_normal + (t/45 (coercion_to_canonical (depth 3 -> 0)) (binding_time 48))) + (earliest_ge_phantom + (z/44 (coercion_to_canonical (depth 2 -> 0)) (binding_time 47))) + (earliest_ge_in_types + (y/43 (coercion_to_canonical (depth 1 -> 0)) (binding_time 46))) + (all + {(t/45 (depth 3 -> 0)) (z/44 (depth 2 -> 0)) (y/43 (depth 1 -> 0))})))}) + (aliases_of_consts {}) + (binding_times_and_modes + {(t/45 (bound at time 48 Normal)) (x/42 (bound at time 45 In_types)) + (z/44 (bound at time 47 Phantom)) (y/43 (bound at time 46 In_types))})) + OK. From 54fbf2712707134cfd49f3e4ab3f027ee128817a Mon Sep 17 00:00:00 2001 From: Luke Maurer Date: Thu, 1 Apr 2021 13:38:02 +0100 Subject: [PATCH 07/16] Use Rec_info.unknown instead of unit --- .depend | 6 ++++++ middle_end/flambda/compilenv_deps/rec_info.ml | 2 ++ .../flambda/compilenv_deps/rec_info.mli | 4 +++- .../flambda/inlining/inlining_decision.ml | 2 +- .../simplify/simplify_apply_expr.rec.ml | 2 +- .../simplify/simplify_set_of_closures.rec.ml | 4 ++-- .../function_declaration_type.rec.ml | 20 +++++++++---------- 7 files changed, 25 insertions(+), 15 deletions(-) diff --git a/.depend b/.depend index 1c78f2c0920d..a4e86b6b9e79 100644 --- a/.depend +++ b/.depend @@ -6131,6 +6131,7 @@ middle_end/flambda/simplify/simplify.cmo : \ middle_end/flambda/lifting/reification.cmi \ middle_end/flambda/basic/reg_width_const.cmi \ middle_end/flambda/basic/recursive.cmi \ + middle_end/flambda/compilenv_deps/rec_info.cmi \ utils/profile.cmi \ middle_end/flambda/basic/or_variable.cmi \ middle_end/flambda/types/basic/or_bottom.cmi \ @@ -6203,6 +6204,7 @@ middle_end/flambda/simplify/simplify.cmx : \ middle_end/flambda/lifting/reification.cmx \ middle_end/flambda/basic/reg_width_const.cmx \ middle_end/flambda/basic/recursive.cmx \ + middle_end/flambda/compilenv_deps/rec_info.cmx \ utils/profile.cmx \ middle_end/flambda/basic/or_variable.cmx \ middle_end/flambda/types/basic/or_bottom.cmx \ @@ -6295,6 +6297,7 @@ middle_end/flambda/simplify/simplify_apply_expr.rec.cmo : \ middle_end/flambda/simplify/simplify_common.cmi \ middle_end/flambda/basic/simple.cmi \ middle_end/flambda/terms/set_of_closures.cmi \ + middle_end/flambda/compilenv_deps/rec_info.cmi \ middle_end/flambda/types/basic/or_bottom.cmi \ middle_end/flambda/naming/name_mode.cmi \ utils/misc.cmi \ @@ -6327,6 +6330,7 @@ middle_end/flambda/simplify/simplify_apply_expr.rec.cmx : \ middle_end/flambda/simplify/simplify_common.cmx \ middle_end/flambda/basic/simple.cmx \ middle_end/flambda/terms/set_of_closures.cmx \ + middle_end/flambda/compilenv_deps/rec_info.cmx \ middle_end/flambda/types/basic/or_bottom.cmx \ middle_end/flambda/naming/name_mode.cmx \ utils/misc.cmx \ @@ -6720,6 +6724,7 @@ middle_end/flambda/simplify/simplify_set_of_closures.rec.cmo : \ middle_end/flambda/basic/simple.cmi \ middle_end/flambda/terms/set_of_closures.cmi \ middle_end/flambda/basic/scope.cmi \ + middle_end/flambda/compilenv_deps/rec_info.cmi \ utils/profile.cmi \ middle_end/flambda/naming/name_occurrences.cmi \ middle_end/flambda/naming/name_mode.cmi \ @@ -6759,6 +6764,7 @@ middle_end/flambda/simplify/simplify_set_of_closures.rec.cmx : \ middle_end/flambda/basic/simple.cmx \ middle_end/flambda/terms/set_of_closures.cmx \ middle_end/flambda/basic/scope.cmx \ + middle_end/flambda/compilenv_deps/rec_info.cmx \ utils/profile.cmx \ middle_end/flambda/naming/name_occurrences.cmx \ middle_end/flambda/naming/name_mode.cmx \ diff --git a/middle_end/flambda/compilenv_deps/rec_info.ml b/middle_end/flambda/compilenv_deps/rec_info.ml index da6b4f446e42..ebc1d84e6544 100644 --- a/middle_end/flambda/compilenv_deps/rec_info.ml +++ b/middle_end/flambda/compilenv_deps/rec_info.ml @@ -34,4 +34,6 @@ end) let initial = () +let unknown = () + 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 c644cc4716a5..937570d92ba7 100644 --- a/middle_end/flambda/compilenv_deps/rec_info.mli +++ b/middle_end/flambda/compilenv_deps/rec_info.mli @@ -13,11 +13,13 @@ (**************************************************************************) [@@@ocaml.warning "+a-4-30-40-41-42"] -type t = unit +type t include Identifiable.S with type t := t val initial : t +val unknown : t + val is_initial : t -> bool diff --git a/middle_end/flambda/inlining/inlining_decision.ml b/middle_end/flambda/inlining/inlining_decision.ml index 2497007d1b66..131b0c7b51b3 100644 --- a/middle_end/flambda/inlining/inlining_decision.ml +++ b/middle_end/flambda/inlining/inlining_decision.ml @@ -218,7 +218,7 @@ end (* CR mshinwell: This parameter needs to be configurable *) let max_rec_depth = 1 -let make_decision_for_call_site denv ~function_decl_rec_info:() +let make_decision_for_call_site denv ~function_decl_rec_info:_ ~apply_inlining_state (inline : Inline_attribute.t) : Call_site_decision.t = if (not (DE.can_inline denv)) then diff --git a/middle_end/flambda/simplify/simplify_apply_expr.rec.ml b/middle_end/flambda/simplify/simplify_apply_expr.rec.ml index d24f9a703a59..889d5c5907a1 100644 --- a/middle_end/flambda/simplify/simplify_apply_expr.rec.ml +++ b/middle_end/flambda/simplify/simplify_apply_expr.rec.ml @@ -105,7 +105,7 @@ let simplify_direct_full_application dacc apply function_decl_opt let apply_inlining_state = Apply.inlining_state apply in let decision = Inlining_decision.make_decision_for_call_site (DA.denv dacc) - ~function_decl_rec_info:() + ~function_decl_rec_info:Rec_info.unknown ~apply_inlining_state (Apply.inline apply) in diff --git a/middle_end/flambda/simplify/simplify_set_of_closures.rec.ml b/middle_end/flambda/simplify/simplify_set_of_closures.rec.ml index 26472037560c..e616fac26bbf 100644 --- a/middle_end/flambda/simplify/simplify_set_of_closures.rec.ml +++ b/middle_end/flambda/simplify/simplify_set_of_closures.rec.ml @@ -153,7 +153,7 @@ end = struct ~pass:Inlining_report.Before_simplify denv function_decl ~code_id:new_code_id - ()) + Rec_info.unknown) (Function_declarations.funs function_decls) in Closure_id.Map.mapi (fun closure_id _function_decl -> @@ -465,7 +465,7 @@ let simplify_function context ~used_closure_vars ~shareable_constants function_decl_type ~pass:Inlining_report.After_simplify (DA.denv dacc_after_body) function_decl - ~params_and_body () + ~params_and_body Rec_info.unknown in { function_decl; new_code_id; 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 5e5b0742c8f3..52499c5289c8 100644 --- a/middle_end/flambda/types/structures/function_declaration_type.rec.ml +++ b/middle_end/flambda/types/structures/function_declaration_type.rec.ml @@ -52,10 +52,10 @@ module Inlinable = struct let is_tupled t = t.is_tupled let apply_name_permutation - ({ code_id; dbg = _; rec_info = (); is_tupled = _; } as t) perm = + ({ code_id; dbg = _; rec_info = _; is_tupled = _; } as t) perm = let code_id' = Name_permutation.apply_code_id perm code_id in if code_id == code_id' then t - else { t with code_id = code_id'; } + else { t with code_id = code_id'; rec_info = Rec_info.unknown } end @@ -108,7 +108,7 @@ let print ppf t = let free_names (t : t) = match t with | Bottom | Unknown -> Name_occurrences.empty - | Ok (Inlinable { code_id; dbg = _; rec_info = (); is_tupled = _; }) + | Ok (Inlinable { code_id; dbg = _; rec_info = _; is_tupled = _; }) | Ok (Non_inlinable { code_id; is_tupled = _; }) -> Name_occurrences.add_code_id Name_occurrences.empty code_id Name_mode.in_types @@ -116,7 +116,7 @@ let free_names (t : t) = let all_ids_for_export (t : t) = match t with | Bottom | Unknown -> Ids_for_export.empty - | Ok (Inlinable { code_id; dbg = _; rec_info = (); is_tupled = _; }) + | Ok (Inlinable { code_id; dbg = _; rec_info = _; is_tupled = _; }) | Ok (Non_inlinable { code_id; is_tupled = _; }) -> Ids_for_export.add_code_id Ids_for_export.empty code_id @@ -178,13 +178,13 @@ let meet (env : Meet_env.t) (t1 : t) (t2 : t) | Ok (Inlinable { code_id = code_id1; dbg = dbg1; - rec_info = (); + rec_info = _; is_tupled = is_tupled1; }), Ok (Inlinable { code_id = code_id2; dbg = dbg2; - rec_info = (); + rec_info = _; is_tupled = is_tupled2; }) -> let typing_env = Meet_env.env env in @@ -196,7 +196,7 @@ let meet (env : Meet_env.t) (t1 : t) (t2 : t) Ok (Ok (Inlinable { code_id; dbg = dbg1; - rec_info = (); + rec_info = Rec_info.unknown; is_tupled = is_tupled1; }), TEE.empty ()) @@ -249,13 +249,13 @@ let join (env : Join_env.t) (t1 : t) (t2 : t) : t = | Ok (Inlinable { code_id = code_id1; dbg = dbg1; - rec_info = (); + rec_info = _; is_tupled = is_tupled1; }), Ok (Inlinable { code_id = code_id2; dbg = dbg2; - rec_info = (); + rec_info = _; is_tupled = is_tupled2; }) -> let typing_env = Join_env.target_join_env env in @@ -267,7 +267,7 @@ let join (env : Join_env.t) (t1 : t) (t2 : t) : t = Ok (Inlinable { code_id; dbg = dbg1; - rec_info = (); + rec_info = Rec_info.unknown; is_tupled = is_tupled1; }) in From 27f4009be49caaa573fb652a5aefc96f540e8851 Mon Sep 17 00:00:00 2001 From: Luke Maurer Date: Thu, 1 Apr 2021 15:24:48 +0100 Subject: [PATCH 08/16] Add comments; simplify `Aliases` API a bit --- middle_end/flambda/types/env/aliases.ml | 34 ++++++++------- middle_end/flambda/types/env/aliases.mli | 42 +++++++++++++++++-- .../flambda/types/env/typing_env.rec.ml | 12 +++--- 3 files changed, 61 insertions(+), 27 deletions(-) diff --git a/middle_end/flambda/types/env/aliases.ml b/middle_end/flambda/types/env/aliases.ml index e37fa83b0fe2..6b2524ea15db 100644 --- a/middle_end/flambda/types/env/aliases.ml +++ b/middle_end/flambda/types/env/aliases.ml @@ -807,21 +807,20 @@ let choose_canonical_element_to_be_demoted t ~canonical_element1 type add_result = { t : t; canonical_element : Simple.t; - alias_of_demoted_element : Simple.t; - coercion_from_alias_of_demoted_to_canonical : Coercion.t; + demoted_alias : Simple.t; } -let invariant_add_result ~original_t { canonical_element; alias_of_demoted_element; t; coercion_from_alias_of_demoted_to_canonical = _; } = +let invariant_add_result ~original_t { canonical_element; demoted_alias; t; } = if !Clflags.flambda_invariant_checks then begin invariant t; - if not (Simple.equal canonical_element alias_of_demoted_element) then begin + if not (Simple.equal canonical_element demoted_alias) then begin if not (defined_earlier t canonical_element - ~than:alias_of_demoted_element) then begin + ~than:demoted_alias) 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 + Simple.print demoted_alias print original_t print t end @@ -833,9 +832,9 @@ let add_alias t ~element1 ~coercion_from_element2_to_element1 ~element2 = ~coercion_from_element1_to_canonical_element1 ~coercion_from_element2_to_canonical_element2 ~coercion_from_canonical_element2_to_canonical_element1 = - let canonical_element, to_be_demoted, alias_of_demoted_element, - coercion_from_demoted_to_canonical, - coercion_from_alias_of_demoted_to_demoted = + let canonical_element, demoted_canonical, demoted_alias, + 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 @@ -858,19 +857,22 @@ let add_alias t ~element1 ~coercion_from_element2_to_element1 ~element2 = add_alias_between_canonical_elements t ~canonical_element - ~coercion_to_canonical:coercion_from_demoted_to_canonical - ~to_be_demoted + ~coercion_to_canonical:coercion_from_demoted_canonical_to_canonical + ~to_be_demoted:demoted_canonical in - let coercion_from_alias_of_demoted_to_canonical = + let coercion_from_demoted_alias_to_canonical = Coercion.compose_exn - coercion_from_alias_of_demoted_to_demoted - ~then_:coercion_from_demoted_to_canonical + coercion_from_demoted_alias_to_demoted_canonical + ~then_:coercion_from_demoted_canonical_to_canonical + in + let demoted_alias = + Simple.with_coercion demoted_alias + coercion_from_demoted_alias_to_canonical in Or_bottom.map t ~f:(fun t -> { t; canonical_element; - alias_of_demoted_element; - coercion_from_alias_of_demoted_to_canonical; + demoted_alias; }) in match canonical t element1, canonical t element2 with diff --git a/middle_end/flambda/types/env/aliases.mli b/middle_end/flambda/types/env/aliases.mli index ce1147975448..dedbac3970dd 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,11 +53,20 @@ 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; - canonical_element : Simple.t; (* has no coercion *) - alias_of_demoted_element : Simple.t; (* has no coercion *) - coercion_from_alias_of_demoted_to_canonical : Coercion.t; + (** The new state of the alias tracker. *) + canonical_element : 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. *) + demoted_alias: 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]. *) } val add diff --git a/middle_end/flambda/types/env/typing_env.rec.ml b/middle_end/flambda/types/env/typing_env.rec.ml index 46a24c165783..fee94a82ae60 100644 --- a/middle_end/flambda/types/env/typing_env.rec.ml +++ b/middle_end/flambda/types/env/typing_env.rec.ml @@ -1034,13 +1034,11 @@ and add_equation t name ty = let ty = Type_grammar.bottom_like ty in aliases, lhs, t, ty | Ok { canonical_element; - alias_of_demoted_element; - t = aliases; - coercion_from_alias_of_demoted_to_canonical; } -> - let lhs = - Simple.with_coercion alias_of_demoted_element - coercion_from_alias_of_demoted_to_canonical - in + demoted_alias; + t = aliases; } -> + (* We need to change the demoted alias's type to point to the new + canonical element. *) + let lhs = demoted_alias in let ty = Type_grammar.alias_type_of kind canonical_element in From deb4d14ecc729e7f107c14e0a9fc029bc8e562ce Mon Sep 17 00:00:00 2001 From: Luke Maurer Date: Thu, 1 Apr 2021 11:33:40 +0100 Subject: [PATCH 09/16] Avoid sets, maps of simple expressions A `Name.Set.t` or `'a Name.Map.t` is a fine thing, but a `Simple.Set.t` or `'a Simple.Map.t` is much sketchier, since whether we want to treat two simples that differ only in `Rec_info.t` as equivalent depends on context. Fortunately, we usually just need a set or map of names. The one place where this gets tricky is in the uses of `Aliases.get_alias`, so there's now `Aliases.Alias_set.t` to encapsulate the needed operations. --- .depend | 20 +- middle_end/flambda/basic/kinded_parameter.ml | 2 - middle_end/flambda/basic/kinded_parameter.mli | 2 - .../common_subexpression_elimination.ml | 17 +- middle_end/flambda/types/env/aliases.ml | 653 +++++++++++------- middle_end/flambda/types/env/aliases.mli | 28 +- .../flambda/types/env/typing_env.rec.ml | 7 +- .../flambda/types/env/typing_env.rec.mli | 4 +- middle_end/flambda/types/flambda_type.mli | 2 +- middle_end/flambda/types/type_descr.rec.ml | 49 +- 10 files changed, 475 insertions(+), 309 deletions(-) diff --git a/.depend b/.depend index 35a39b8551c6..956e89cd9d46 100644 --- a/.depend +++ b/.depend @@ -6042,6 +6042,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 +6060,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 \ @@ -9125,7 +9127,8 @@ middle_end/flambda/types/flambda_type.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 +9156,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,6 +9174,7 @@ 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 \ @@ -9437,10 +9442,12 @@ 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 \ utils/clflags.cmi \ middle_end/flambda/types/env/binding_time.cmi \ middle_end/flambda/types/env/aliases.cmi @@ -9448,10 +9455,12 @@ 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 \ utils/clflags.cmx \ middle_end/flambda/types/env/binding_time.cmx \ middle_end/flambda/types/env/aliases.cmi @@ -9502,7 +9511,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 \ @@ -9526,7 +9534,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 \ @@ -9561,7 +9568,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 \ @@ -10074,10 +10082,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 +10108,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 +10128,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/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/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/types/env/aliases.ml b/middle_end/flambda/types/env/aliases.ml index a863a366fda4..32cdfed21aa4 100644 --- a/middle_end/flambda/types/env/aliases.ml +++ b/middle_end/flambda/types/env/aliases.ml @@ -14,6 +14,8 @@ [@@@ocaml.warning "+a-4-30-40-41-42"] +module Const = Reg_width_things.Const + module Aliases_of_canonical_element : sig type t @@ -24,61 +26,61 @@ 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 -> 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 -> Name.Set.t -> Name.Set.t) -> min_name_mode:Name_mode.t - -> Simple.Set.t option + -> Name.Set.t option - val all : t -> Simple.Set.t + val all : t -> Name.Set.t - 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 end = struct type t = { - aliases : Simple.Set.t Name_mode.Map.t; - all : Simple.Set.t; + aliases : Name.Set.t Name_mode.Map.t; + all : Name.Set.t; } let invariant _t = () let print ppf { aliases; all = _; } = - Name_mode.Map.print Simple.Set.print ppf aliases + Name_mode.Map.print Name.Set.print ppf aliases let empty = { aliases = Name_mode.Map.empty; - all = Simple.Set.empty; + all = Name.Set.empty; } - let is_empty t = Simple.Set.is_empty t.all + let is_empty t = Name.Set.is_empty t.all let add t elt name_mode = - if Simple.Set.mem elt t.all then begin + if Name.Set.mem elt t.all then begin Misc.fatal_errorf "%a already added to [Aliases_of_canonical_element]: \ %a" - Simple.print elt + Name.print elt print t end; let aliases = Name_mode.Map.update name_mode (function - | None -> Some (Simple.Set.singleton elt) + | None -> Some (Name.Set.singleton elt) | Some elts -> if !Clflags.flambda_invariant_checks then begin - assert (not (Simple.Set.mem elt elts)) + assert (not (Name.Set.mem elt elts)) end; - Some (Simple.Set.add elt elts)) + Some (Name.Set.add elt elts)) t.aliases in - let all = Simple.Set.add elt t.all in + let all = Name.Set.add elt t.all in { aliases; all; } @@ -96,26 +98,26 @@ 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.Set.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.Set.mem elt t.all let all t = t.all let union t1 t2 = let aliases = Name_mode.Map.union (fun _order elts1 elts2 -> - Some (Simple.Set.union elts1 elts2)) + Some (Name.Set.union elts1 elts2)) t1.aliases t2.aliases in let t = { aliases; - all = Simple.Set.union t1.all t2.all; + all = Name.Set.union t1.all t2.all; } in invariant t; @@ -126,107 +128,211 @@ end = struct 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)) + | Some elts1, Some elts2 -> Some (Name.Set.inter elts1 elts2)) t1.aliases t2.aliases in let t = { aliases; - all = Simple.Set.inter t1.all t2.all; + all = Name.Set.inter t1.all t2.all; } in invariant t; t - let rename rename_simple { aliases; all } = + let rename rename_name { aliases; all } = let aliases = - Name_mode.Map.map (fun elts -> Simple.Set.map rename_simple elts) + Name_mode.Map.map (fun elts -> Name.Set.map rename_name elts) aliases in - let all = Simple.Set.map rename_simple all in + let all = Name.Set.map rename_name all in { aliases; all } let merge t1 t2 = let aliases = Name_mode.Map.union (fun _mode set1 set2 -> - Some (Simple.Set.union set1 set2)) + Some (Name.Set.union set1 set2)) t1.aliases t2.aliases in - let all = Simple.Set.union t1.all t2.all in + let all = Name.Set.union t1.all t2.all in { aliases; all; } end +module Alias_set = struct + type t = { + const : Const.t option; + names : Name.Set.t; + } + + let empty = { const = None; names = Name.Set.empty; } + + let singleton simple = + Simple.pattern_match simple + ~const:(fun const -> + { const = Some const; names = Name.Set.empty; }) + ~name:(fun name -> + { const = None; names = Name.Set.singleton name }) + + let get_singleton { const; names; } = + match const with + | Some const -> + if Name.Set.is_empty names then Some (Simple.const const) else None + | None -> + Name.Set.get_singleton names + |> Option.map Simple.name + + 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.Set.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 = Name.Set.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.Set.filter (fun name -> f (Simple.name name)) names + in + { const; names; } + + let find_best { const; names; } = + match const with + | Some const -> Some (Simple.const const) + | None -> + let (symbols, vars) = Name.Set.partition Name.is_symbol names in + match Name.Set.min_elt_opt symbols with + | Some symbol -> + Some (Simple.name symbol) + | None -> + match Name.Set.min_elt_opt vars with + | Some var -> + Some (Simple.name var) + | None -> + None +end + + type t = { - canonical_elements : Simple.t Simple.Map.t; + canonical_elements : Simple.t 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; } = +let print ppf { canonical_elements; aliases_of_canonical_names; + aliases_of_consts; binding_times_and_modes; } = Format.fprintf ppf "@[(\ @[(canonical_elements@ %a)@]@ \ - @[(aliases_of_canonical_elements@ %a)@]@ \ + @[(aliases_of_canonical_names@ %a)@]@ \ + @[(aliases_of_consts@ %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) + (Name.Map.print Simple.print) 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 : Name.Set.t = + 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.Set.for_all (fun elt -> + 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.Set.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.Set.print aliases end; - if not (Simple.Set.is_empty (Simple.Set.inter aliases all_aliases)) then + if not (Name.Set.intersection_is_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.Set.union aliases all_aliases) + t.aliases_of_canonical_names + Name.Set.empty + in + let _all_aliases : Name.Set.t = + Const.Map.fold (fun _const aliases all_aliases -> + Aliases_of_canonical_element.invariant aliases; + let aliases = Aliases_of_canonical_element.all aliases in + if not (Name.Set.intersection_is_empty aliases all_aliases) then + begin + Misc.fatal_errorf "Overlapping alias sets:@ %a" print t + end; + Name.Set.union aliases all_aliases) + t.aliases_of_consts + all_aliases_of_names in () end @@ -234,26 +340,36 @@ 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; } + | Alias_of_canonical of { element : Name.t; canonical_element : Simple.t; } 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 element) + ~name:(fun name -> + match Name.Map.find name 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 = name; canonical_element; }) 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 @@ -261,26 +377,38 @@ let add_alias_between_canonical_elements t ~canonical_element ~to_be_demoted = if Simple.equal canonical_element to_be_demoted then t 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.Set.fold (fun alias canonical_elements -> + Name.Map.add alias canonical_element 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 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)) @@ -289,52 +417,50 @@ let add_alias_between_canonical_elements t ~canonical_element ~to_be_demoted = 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) + name_to_be_demoted (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 { canonical_elements; - aliases_of_canonical_elements; + aliases_of_canonical_names; + aliases_of_consts; binding_times_and_modes = t.binding_times_and_modes; } -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 + if not (Simple.equal canonical_element alias_of_demoted_element) then begin + 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 + Simple.print alias_of_demoted_element print original_t print t end @@ -343,54 +469,28 @@ let invariant_add_result ~original_t { canonical_element; alias_of; t; } = let add_alias t element1 element2 = 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; - } + | Is_canonical canonical_element1, Is_canonical canonical_element2 | Alias_of_canonical - { element = element1; canonical_element = canonical_element1; }, + { element = _; 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 - in - { t; - canonical_element; - alias_of; - } + { element = _; canonical_element = canonical_element1; } | Alias_of_canonical - { element = element1; canonical_element = canonical_element1; }, + { element = _; canonical_element = canonical_element1; }, Alias_of_canonical - { element = element2; canonical_element = canonical_element2; } + { element = _; canonical_element = canonical_element2; } -> - 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 element2 + let canonical_element, to_be_demoted, alias_of_demoted_element = + let which_element = + choose_canonical_element_to_be_demoted t + ~canonical_element1 ~canonical_element2 + in + match which_element with + | Demote_canonical_element1 -> + canonical_element2, canonical_element1, element1 + | Demote_canonical_element2 -> + canonical_element1, canonical_element2, element2 in let t = add_alias_between_canonical_elements t ~canonical_element @@ -398,18 +498,35 @@ let add_alias t element1 element2 = in { t; canonical_element; - alias_of; + alias_of_demoted_element; } let add t element1 binding_time_and_mode1 element2 binding_time_and_mode2 = + Simple.pattern_match element1 + ~name:(fun _ -> ()) + ~const:(fun const1 -> + Simple.pattern_match element2 + ~name:(fun _ -> ()) + ~const:(fun const2 -> + if not (Const.equal const1 const2) then begin + Misc.fatal_errorf + "Cannot add alias between two non-equal consts: %a <> %a" + Const.print const1 + Const.print const2 + end)); let original_t = t in let element1 = Simple.without_rec_info element1 in let element2 = Simple.without_rec_info element2 in + 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 @@ -420,7 +537,11 @@ let add t element1 binding_time_and_mode1 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,174 +567,202 @@ 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 = + match canonical t element with + | Is_canonical _ -> + element, elt_name_mode + | Alias_of_canonical { canonical_element; _ } -> + let name_mode = name_mode t canonical_element ~min_binding_time in + canonical_element, name_mode + 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 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 appear + 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.Set.filter (fun name -> + 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.Set.is_empty at_earliest_mode)); + Name.Set.fold (fun elt min_elt -> + if name_defined_earlier t elt ~than:min_elt + then elt + else min_elt) + at_earliest_mode + (Name.Set.min_elt at_earliest_mode) + |> Simple.name + | 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 canonical_element + else find_earliest () let get_aliases t element = + let create_alias_set ~canonical_element ~names = + Simple.pattern_match canonical_element + ~const:(fun canonical_const -> + let const = Some canonical_const in + { Alias_set.const; names }) + ~name:(fun canonical_name -> + let names = Name.Set.add canonical_name names in + { Alias_set.const = None; names }) + in match canonical t element with | Is_canonical canonical_element -> - let aliases = + let names = 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; } -> + create_alias_set ~canonical_element ~names + | Alias_of_canonical { element; canonical_element; } -> if !Clflags.flambda_invariant_checks then begin - assert (not (Simple.equal element canonical_element)) + assert (not (Simple.equal (Simple.name element) canonical_element)) end; - let aliases = + let names = Aliases_of_canonical_element.all (get_aliases_of_canonical_element t ~canonical_element) in if !Clflags.flambda_invariant_checks then begin - assert (Simple.Set.mem element aliases) + assert (Name.Set.mem element names) end; - Simple.Set.add canonical_element aliases + create_alias_set ~canonical_element ~names 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 name _binding_time_and_mode ids -> + Ids_for_export.add_name ids name) 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 acc -> + Name.Map.add (rename_name elt) (rename_simple canonical) 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; } @@ -625,11 +774,13 @@ let get_canonical_ignoring_name_mode t name = 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..83f526d25239 100644 --- a/middle_end/flambda/types/env/aliases.mli +++ b/middle_end/flambda/types/env/aliases.mli @@ -31,7 +31,7 @@ val empty : t type add_result = private { t : t; canonical_element : Simple.t; - alias_of : Simple.t; + alias_of_demoted_element : Simple.t; } val add @@ -54,8 +54,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/typing_env.rec.ml b/middle_end/flambda/types/env/typing_env.rec.ml index 7263444762c1..a4c6e67ae31a 100644 --- a/middle_end/flambda/types/env/typing_env.rec.ml +++ b/middle_end/flambda/types/env/typing_env.rec.ml @@ -1003,14 +1003,15 @@ and add_equation t name ty = 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) = + let ({ canonical_element; alias_of_demoted_element; t = aliases; } + : Aliases.add_result) = Aliases.add aliases alias binding_time_and_mode_alias alias_of binding_time_and_mode_alias_of in let ty = Type_grammar.alias_type_of kind canonical_element in - aliases, alias_of, t, ty + aliases, alias_of_demoted_element, 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 @@ -1330,7 +1331,7 @@ let get_alias_then_canonical_simple_exn t ?min_name_mode 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..f9a087e6e8f2 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 diff --git a/middle_end/flambda/types/type_descr.rec.ml b/middle_end/flambda/types/type_descr.rec.ml index 713e2c0599e9..c232a08b2ac4 100644 --- a/middle_end/flambda/types/type_descr.rec.ml +++ b/middle_end/flambda/types/type_descr.rec.ml @@ -236,18 +236,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 +470,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)) @@ -525,7 +500,7 @@ module Make (Head : Type_head_intf.S (* 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 -> + Aliases.Alias_set.filter ~f:(fun simple -> not (Simple.same simple (Simple.name bound_name))) shared_aliases in @@ -533,8 +508,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 From fb5f7a16f793697d09ec7934639ebb6d59359182 Mon Sep 17 00:00:00 2001 From: Luke Maurer Date: Wed, 7 Apr 2021 14:23:28 +0100 Subject: [PATCH 10/16] Fix line-wrap glitch --- middle_end/flambda/types/env/aliases.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/middle_end/flambda/types/env/aliases.ml b/middle_end/flambda/types/env/aliases.ml index 32cdfed21aa4..a2d1b8eeaf95 100644 --- a/middle_end/flambda/types/env/aliases.ml +++ b/middle_end/flambda/types/env/aliases.ml @@ -198,7 +198,8 @@ module Alias_set = struct { const = const2; names = names2; } = let const = match const1, const2 with - | Some const1, Some const2 when Const.equal const1 const2 -> Some const1 | _, _ -> None + | Some const1, Some const2 when Const.equal const1 const2 -> Some const1 + | _, _ -> None in let names = Name.Set.inter names1 names2 in { const; names; } From 9e039bee7a025e2975f411269dbe8ef1dcdfecdf Mon Sep 17 00:00:00 2001 From: Luke Maurer Date: Wed, 7 Apr 2021 14:38:51 +0100 Subject: [PATCH 11/16] Remove more uses of `Simple.Set` and `Simple.Map` Everything is now gone except for a few stragglers in `cmx/` and `naming/`; these will be more easily dealt with after some changes to `Simple.t`. --- middle_end/flambda/basic/name.ml | 8 +++ middle_end/flambda/basic/name.mli | 7 +++ middle_end/flambda/basic/simple.ml | 8 --- middle_end/flambda/basic/simple.mli | 6 --- middle_end/flambda/cmx/flambda_cmx_format.ml | 2 +- middle_end/flambda/compare/compare.ml | 57 +++++++++++++------- middle_end/flambda/types/env/meet_env.rec.ml | 32 +++++++---- 7 files changed, 77 insertions(+), 43 deletions(-) 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..87a2d08ef23b 100644 --- a/middle_end/flambda/basic/simple.ml +++ b/middle_end/flambda/basic/simple.ml @@ -158,14 +158,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..2c353d341acf 100644 --- a/middle_end/flambda/basic/simple.mli +++ b/middle_end/flambda/basic/simple.mli @@ -94,12 +94,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/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/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; From 3616ad0f9881c9f18733b6ef17a5084aca980fc9 Mon Sep 17 00:00:00 2001 From: Luke Maurer Date: Wed, 7 Apr 2021 16:14:59 +0100 Subject: [PATCH 12/16] Update .depend --- .depend | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.depend b/.depend index 956e89cd9d46..349a1b063e48 100644 --- a/.depend +++ b/.depend @@ -4424,17 +4424,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 @@ -9496,10 +9499,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 : \ From 290cff334fd65cc9461a9a00824c51297ae2334d Mon Sep 17 00:00:00 2001 From: Luke Maurer Date: Tue, 20 Apr 2021 12:59:29 +0100 Subject: [PATCH 13/16] Fix bug --- middle_end/flambda/types/env/aliases.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/middle_end/flambda/types/env/aliases.ml b/middle_end/flambda/types/env/aliases.ml index a2d1b8eeaf95..b5d406899f2a 100644 --- a/middle_end/flambda/types/env/aliases.ml +++ b/middle_end/flambda/types/env/aliases.ml @@ -474,9 +474,9 @@ let add_alias t element1 element2 = | Alias_of_canonical { element = _; canonical_element = canonical_element1; }, Is_canonical canonical_element2 - | Is_canonical canonical_element2, + | Is_canonical canonical_element1, Alias_of_canonical - { element = _; canonical_element = canonical_element1; } + { element = _; canonical_element = canonical_element2; } | Alias_of_canonical { element = _; canonical_element = canonical_element1; }, Alias_of_canonical From 27cce5545b215f7858aea1bd358d00e16365530a Mon Sep 17 00:00:00 2001 From: Luke Maurer Date: Wed, 21 Apr 2021 19:08:38 +0100 Subject: [PATCH 14/16] Fix a bug in a corner case; tighten invariants a bit --- middle_end/flambda/types/env/aliases.ml | 147 +++++++++++++++++------ middle_end/flambda/types/env/aliases.mli | 7 ++ 2 files changed, 120 insertions(+), 34 deletions(-) diff --git a/middle_end/flambda/types/env/aliases.ml b/middle_end/flambda/types/env/aliases.ml index b5d406899f2a..3734f92277e3 100644 --- a/middle_end/flambda/types/env/aliases.ml +++ b/middle_end/flambda/types/env/aliases.ml @@ -455,20 +455,72 @@ type add_result = { 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_demoted_element) then begin - 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@ \ + 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_demoted_element print original_t print t - end - end + | Alias_of_canonical _ -> () end +(* +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 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 + begin match canonical t element1, canonical t element2 with + | Is_canonical canonical_element1, Is_canonical canonical_element2 + | Alias_of_canonical + { element = _; canonical_element = canonical_element1; }, + Is_canonical canonical_element2 + | Is_canonical canonical_element1, + Alias_of_canonical + { element = _; canonical_element = canonical_element2; } + | Alias_of_canonical + { element = _; canonical_element = canonical_element1; }, + Alias_of_canonical + { element = _; canonical_element = 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; +*) match canonical t element1, canonical t element2 with | Is_canonical canonical_element1, Is_canonical canonical_element2 | Alias_of_canonical @@ -482,40 +534,67 @@ let add_alias t element1 element2 = Alias_of_canonical { element = _; canonical_element = canonical_element2; } -> - let canonical_element, to_be_demoted, alias_of_demoted_element = - let which_element = - choose_canonical_element_to_be_demoted t - ~canonical_element1 ~canonical_element2 + 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 - match which_element with - | Demote_canonical_element1 -> - canonical_element2, canonical_element1, element1 - | Demote_canonical_element2 -> - canonical_element1, canonical_element2, element2 - in - let t = - add_alias_between_canonical_elements t ~canonical_element - ~to_be_demoted - in - { t; - canonical_element; - alias_of_demoted_element; - } + { t; canonical_element; alias_of_demoted_element; } + else + let canonical_element, to_be_demoted, alias_of_demoted_element = + let which_element = + choose_canonical_element_to_be_demoted t + ~canonical_element1 ~canonical_element2 + in + match which_element with + | Demote_canonical_element1 -> + canonical_element2, canonical_element1, element1 + | Demote_canonical_element2 -> + canonical_element1, canonical_element2, element2 + in + let t = + add_alias_between_canonical_elements t ~canonical_element + ~to_be_demoted + in + { t; + canonical_element; + alias_of_demoted_element; + } +(* + end +*) let add t element1 binding_time_and_mode1 element2 binding_time_and_mode2 = - Simple.pattern_match element1 - ~name:(fun _ -> ()) - ~const:(fun const1 -> - Simple.pattern_match element2 - ~name:(fun _ -> ()) - ~const:(fun const2 -> - if not (Const.equal const1 const2) then begin + 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 non-equal consts: %a <> %a" + "Cannot add alias between two consts: %a, %a" Const.print const1 Const.print const2 - end)); + )); + end; let original_t = t in let element1 = Simple.without_rec_info element1 in let element2 = Simple.without_rec_info element2 in diff --git a/middle_end/flambda/types/env/aliases.mli b/middle_end/flambda/types/env/aliases.mli index 83f526d25239..f7ce5db187dc 100644 --- a/middle_end/flambda/types/env/aliases.mli +++ b/middle_end/flambda/types/env/aliases.mli @@ -34,6 +34,13 @@ type add_result = private { alias_of_demoted_element : Simple.t; } +(** 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 From 8435b66f8bbfc524da1deb31c08e6903826afb51 Mon Sep 17 00:00:00 2001 From: Luke Maurer Date: Thu, 22 Apr 2021 14:13:16 +0100 Subject: [PATCH 15/16] Revert (most of) "Overhaul Aliases_of_canonical_element; add Alias_set" This reverts the parts of commit 98168413a709df5cb8b99575992d2d7c914a48a9 that have been split off into PRs #383 and #386, as well as the Bottom stuff (likely to be unnecessary as we're considering making `Coercion.compose` a total function). --- .depend | 16 +- compilerlibs/Makefile.compilerlibs | 2 +- middle_end/flambda/basic/kinded_parameter.ml | 2 + middle_end/flambda/basic/kinded_parameter.mli | 2 + .../common_subexpression_elimination.ml | 17 +- middle_end/flambda/types/env/aliases.ml | 1134 ++++++----------- middle_end/flambda/types/env/aliases.mli | 35 +- .../flambda/types/env/typing_env.rec.ml | 32 +- .../flambda/types/env/typing_env.rec.mli | 4 +- middle_end/flambda/types/flambda_type.mli | 2 +- middle_end/flambda/types/type_descr.rec.ml | 56 +- testsuite/tests/flambda2-aliases/test.ml | 15 +- .../tests/flambda2-aliases/test.reference | 178 +-- 13 files changed, 501 insertions(+), 994 deletions(-) diff --git a/.depend b/.depend index a4e86b6b9e79..1ba14b6f5850 100644 --- a/.depend +++ b/.depend @@ -6002,7 +6002,6 @@ 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 \ @@ -6020,7 +6019,6 @@ 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 \ @@ -8988,8 +8986,7 @@ middle_end/flambda/types/flambda_type.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/types/env/aliases.cmi + middle_end/flambda/basic/apply_cont_rewrite_id.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 \ @@ -9017,7 +9014,6 @@ 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 \ @@ -9035,7 +9031,6 @@ 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 \ @@ -9302,8 +9297,6 @@ middle_end/flambda/types/basic/var_within_closure_set.cmi : \ middle_end/flambda/types/env/aliases.cmo : \ middle_end/flambda/compilenv_deps/variable.cmi \ middle_end/flambda/basic/simple.cmi \ - middle_end/flambda/compilenv_deps/reg_width_things.cmi \ - middle_end/flambda/types/basic/or_bottom.cmi \ middle_end/flambda/naming/name_mode.cmi \ middle_end/flambda/basic/name.cmi \ utils/misc.cmi \ @@ -9316,8 +9309,6 @@ middle_end/flambda/types/env/aliases.cmo : \ middle_end/flambda/types/env/aliases.cmx : \ middle_end/flambda/compilenv_deps/variable.cmx \ middle_end/flambda/basic/simple.cmx \ - middle_end/flambda/compilenv_deps/reg_width_things.cmx \ - middle_end/flambda/types/basic/or_bottom.cmx \ middle_end/flambda/naming/name_mode.cmx \ middle_end/flambda/basic/name.cmx \ utils/misc.cmx \ @@ -9329,11 +9320,9 @@ middle_end/flambda/types/env/aliases.cmx : \ middle_end/flambda/types/env/aliases.cmi middle_end/flambda/types/env/aliases.cmi : \ middle_end/flambda/basic/simple.cmi \ - middle_end/flambda/types/basic/or_bottom.cmi \ middle_end/flambda/naming/name_mode.cmi \ middle_end/flambda/basic/name.cmi \ middle_end/flambda/cmx/contains_ids.cmo \ - middle_end/flambda/compilenv_deps/coercion.cmi \ middle_end/flambda/types/env/binding_time.cmi middle_end/flambda/types/env/binding_time.cmo : \ utils/numbers.cmi \ @@ -9427,8 +9416,7 @@ 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/types/env/aliases.cmi + middle_end/flambda/basic/apply_cont_rewrite_id.cmi middle_end/flambda/types/env/typing_env_extension.rec.cmo : \ middle_end/flambda/compilenv_deps/variable.cmi \ middle_end/flambda/types/basic/or_bottom.cmi \ diff --git a/compilerlibs/Makefile.compilerlibs b/compilerlibs/Makefile.compilerlibs index 3a411c26d66b..b9d16b43d2e9 100644 --- a/compilerlibs/Makefile.compilerlibs +++ b/compilerlibs/Makefile.compilerlibs @@ -224,7 +224,6 @@ MIDDLE_END_FLAMBDA_BASIC=\ middle_end/flambda/basic/coeffects.cmo \ middle_end/flambda/basic/effects.cmo \ middle_end/flambda/basic/export_id.cmo \ - middle_end/flambda/types/basic/or_bottom.cmo \ middle_end/flambda/types/basic/or_unknown.cmo \ middle_end/flambda/terms/flambda_primitive.cmo \ middle_end/flambda/basic/recursive.cmo \ @@ -261,6 +260,7 @@ MIDDLE_END_FLAMBDA_TYPES=\ middle_end/flambda/types/env/binding_time.cmo \ middle_end/flambda/types/env/aliases.cmo \ middle_end/flambda/types/basic/meet_or_join_op.cmo \ + middle_end/flambda/types/basic/or_bottom.cmo \ middle_end/flambda/types/basic/string_info.cmo \ middle_end/flambda/types/basic/or_unknown_or_bottom.cmo \ middle_end/flambda/types/structures/code_age_relation.cmo \ diff --git a/middle_end/flambda/basic/kinded_parameter.ml b/middle_end/flambda/basic/kinded_parameter.ml index a4635033a8b1..b6490f90a31c 100644 --- a/middle_end/flambda/basic/kinded_parameter.ml +++ b/middle_end/flambda/basic/kinded_parameter.ml @@ -115,6 +115,8 @@ 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 bc2a5533e0de..53c4f20e4d09 100644 --- a/middle_end/flambda/basic/kinded_parameter.mli +++ b/middle_end/flambda/basic/kinded_parameter.mli @@ -68,6 +68,8 @@ 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/simplify/common_subexpression_elimination.ml b/middle_end/flambda/simplify/common_subexpression_elimination.ml index 7f69ae5cb500..021180c5a606 100644 --- a/middle_end/flambda/simplify/common_subexpression_elimination.ml +++ b/middle_end/flambda/simplify/common_subexpression_elimination.ml @@ -117,12 +117,7 @@ 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.name_set params in - let is_param simple = - Simple.pattern_match simple - ~name:(fun name -> Name.Set.mem name params) - ~const:(fun _ -> false) - in + let params = KP.List.simple_set params in List.fold_left cse_at_each_use ~init:EP.Map.empty ~f:(fun eligible (env_at_use, id, cse) -> let find_new_name = @@ -187,17 +182,15 @@ 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 (is_param bound_to) then Some bound_to + if not (Simple.Set.mem bound_to params) then Some bound_to else let aliases = TE.aliases_of_simple env_at_use ~min_name_mode:NM.normal bound_to - |> Aliases.Alias_set.filter ~f:(fun simple -> - not (is_param simple)) + |> Simple.Set.filter (fun simple -> + not (Simple.Set.mem simple params)) in - (* CR lmaurer: This could be using - [Aliases.Alias_set.find_best], I think? *) - Aliases.Alias_set.get_singleton aliases + Simple.Set.get_singleton aliases in match bound_to with | None -> eligible diff --git a/middle_end/flambda/types/env/aliases.ml b/middle_end/flambda/types/env/aliases.ml index 6b2524ea15db..e3831cf3500e 100644 --- a/middle_end/flambda/types/env/aliases.ml +++ b/middle_end/flambda/types/env/aliases.ml @@ -14,482 +14,257 @@ [@@@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 +type map_to_canonical = coercion_to_canonical Simple.Map.t let compose_map_values_exn map ~then_:coercion = if Coercion.is_id coercion then map else - Name.Map.map (fun old_coercion -> + Simple.Map.map (fun old_coercion -> Coercion.compose_exn old_coercion ~then_:coercion ) map -let compose_map_values map ~then_:coercion : _ Name.Map.t Or_bottom.t = - if Coercion.is_id coercion then Ok map else - let exception Return_bottom in - match - Name.Map.map (fun old_coercion -> - match Coercion.compose old_coercion ~then_:coercion with - | Some c -> c - | None -> raise Return_bottom - ) map - with - | exception Return_bottom -> Bottom - | map -> Ok map - -(* CR lmaurer: This should be in [Patricia_tree] *) -let map_keys f m = - Name.Map.fold (fun name value acc -> - Name.Map.add (f name) value acc) - m - Name.Map.empty +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 + Simple.print elt + Coercion.print coercion1 + Coercion.print coercion2 + +let map_inter map1 map2 = + Simple.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 = + Simple.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 val print : Format.formatter -> t -> unit - val invariant - : t - -> binding_times_and_modes:(Binding_time.With_name_mode.t Name.Map.t) - -> unit + val invariant : t -> unit val empty : t + val is_empty : t -> bool - val add - : t - -> Name.t - -> coercion_to_canonical - -> Binding_time.With_name_mode.t - -> t + val add : t -> Simple.t -> coercion_to_canonical:Coercion.t -> Name_mode.t -> t - val earliest_alias : - t -> min_name_mode:Name_mode.t option -> (Name.t * Coercion.t) option + val find_earliest_candidates + : t + -> min_name_mode:Name_mode.t + -> map_to_canonical option val all : t -> map_to_canonical - val mem : t -> Name.t -> bool + val mem : t -> Simple.t -> bool - val union : t -> t -> t Or_bottom.t + val union : t -> t -> t + val inter : t -> t -> t - val disjoint : t -> t -> bool - - val import : (Name.t -> Name.t) -> t -> t + val import : (Simple.t -> Simple.t) -> t -> t + + val merge : t -> t -> t val move_variables_to_mode_in_types : t -> t - val apply_coercion_to_all : t -> Coercion.t -> t Or_bottom.t + val compose : t -> then_:Coercion.t -> t end = struct - module Earliest_alias : sig - type t = - | Earliest of { - name : Name.t; - coercion_to_canonical : Coercion.t; - binding_time : Binding_time.t - } - | No_alias - - val exists : t -> bool - val update : t -> Name.t -> coercion_to_canonical -> Binding_time.t -> t - val union : t -> t -> t - val map_name : t -> f:(Name.t -> Name.t) -> t - val map_coercion : t -> f:(Coercion.t -> Coercion.t) -> t - val print : Format.formatter -> t -> unit - end = struct - type t = - | Earliest of { - name : Name.t; - coercion_to_canonical : Coercion.t; - binding_time : Binding_time.t; - } - | No_alias - - let exists = function - | Earliest _ -> true - | No_alias -> false - - let update t new_name coercion_to_canonical binding_time = - match t with - | No_alias -> - Earliest { name = new_name; coercion_to_canonical; binding_time } - | Earliest { binding_time = old_binding_time; _ } -> - if Binding_time.strictly_earlier binding_time ~than:old_binding_time - then Earliest { name = new_name; coercion_to_canonical; binding_time } - else t - - let union t1 t2 = - match t2 with - | No_alias -> t1 - | Earliest { name; coercion_to_canonical; binding_time } -> - update t1 name coercion_to_canonical binding_time - - let map_name t ~f = - match t with - | Earliest e -> - let name = f e.name in - Earliest { e with name } - | No_alias -> No_alias - - let map_coercion t ~f = - match t with - | Earliest e -> - let coercion_to_canonical = f e.coercion_to_canonical in - Earliest { e with coercion_to_canonical } - | No_alias -> No_alias - - let print ppf = function - | Earliest { name; coercion_to_canonical; binding_time } -> - Format.fprintf ppf - "@[(%a@ \ - @[@<0>%s(coercion_to_canonical@ %a)@<0>%s@]@ \ - @[(binding_time@ %a)@])@]" - Name.print name - (if Coercion.is_id coercion_to_canonical - then Flambda_colours.elide () - else Flambda_colours.normal ()) - Coercion.print coercion_to_canonical - (Flambda_colours.normal ()) - Binding_time.print binding_time - | No_alias -> - Format.pp_print_string ppf "" - end - type t = { + aliases : map_to_canonical Name_mode.Map.t; all : map_to_canonical; - earliest : Earliest_alias.t; - earliest_normal : Earliest_alias.t; - (* Earliest alias whose name mode >= phantom (that is, normal or phantom) *) - earliest_ge_phantom : Earliest_alias.t; - (* Earliest alias whose name mode >= in-types *) - earliest_ge_in_types : Earliest_alias.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 -> + Simple.Map.union (fun elt _coercion1 _coercion2 -> + Misc.fatal_errorf "[Aliases_of_canonical_element.invariant]: \ + element %a appears in several modes" + Simple.print elt) + map + acc) + aliases + Simple.Map.empty + in + (* [all] is the union of all elements in [aliases] *) + if Simple.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.Map.print Coercion.print) ppf aliases + let empty = { - all = Name.Map.empty; - earliest = No_alias; - earliest_normal = No_alias; - earliest_ge_phantom = No_alias; - earliest_ge_in_types = No_alias; + aliases = Name_mode.Map.empty; + all = Simple.Map.empty; } - let print ppf - { earliest; earliest_normal; earliest_ge_phantom; earliest_ge_in_types; - all } = - let pp_earliest field_name ppf (earliest : Earliest_alias.t) = - Format.fprintf ppf "@[@<0>%s(%s@ %a)@<0>%s@]" - (if Earliest_alias.exists earliest - then Flambda_colours.normal () - else Flambda_colours.elide ()) - field_name - Earliest_alias.print earliest - (Flambda_colours.normal ()) - in - Format.fprintf ppf - "@[(\ - %a@ %a@ %a@ %a@ \ - @[(all@ %a)@])\ - @]" - (pp_earliest "earliest") earliest - (pp_earliest "earliest_normal") earliest_normal - (pp_earliest "earliest_ge_phantom") earliest_ge_phantom - (pp_earliest "earliest_ge_in_types") earliest_ge_in_types - (Name.Map.print Coercion.print) all - - let add t new_name coercion_to_canonical binding_time_and_name_mode = - if Name.Map.mem new_name t.all then begin + let is_empty t = Simple.Map.is_empty t.all + + let add t elt ~coercion_to_canonical name_mode = + if Simple.Map.mem elt t.all then begin Misc.fatal_errorf "%a already added to [Aliases_of_canonical_element]: \ %a" - Name.print new_name + Simple.print elt print t end; - let binding_time, name_mode = - Binding_time.With_name_mode.( - binding_time binding_time_and_name_mode, - name_mode binding_time_and_name_mode) - in - let update earliest = - Earliest_alias.update earliest new_name coercion_to_canonical - binding_time - in - let update_if_mode_ge mode earliest = - match Name_mode.compare_partial_order name_mode mode with - | Some c when c >= 0 -> update earliest - | _ -> earliest - in - let earliest = update t.earliest in - let earliest_normal = - update_if_mode_ge Name_mode.normal t.earliest_normal - in - let earliest_ge_phantom = - update_if_mode_ge Name_mode.phantom t.earliest_ge_phantom - in - let earliest_ge_in_types = - update_if_mode_ge Name_mode.in_types t.earliest_ge_in_types - in - let all = Name.Map.add new_name coercion_to_canonical t.all in - { earliest; earliest_normal; earliest_ge_phantom; earliest_ge_in_types; - all } - - let find_earliest t ~(min_name_mode : Name_mode.t option) = - match min_name_mode with - | None -> t.earliest - | Some min_name_mode -> - begin match Name_mode.descr min_name_mode with - | Normal -> t.earliest_normal - | Phantom -> t.earliest_ge_phantom - | In_types -> t.earliest_ge_in_types - end + let aliases = + Name_mode.Map.update name_mode + (function + | None -> Some (Simple.Map.singleton elt coercion_to_canonical) + | Some elts -> + if !Clflags.flambda_invariant_checks then begin + assert (not (Simple.Map.mem elt elts)) + end; + Some (Simple.Map.add elt coercion_to_canonical elts)) + t.aliases + in + let all = Simple.Map.add elt coercion_to_canonical t.all in + { aliases; + all; + } - let invariant t ~binding_times_and_modes = - let describe_field name_mode = - match name_mode with - | None -> "overall" - | Some name_mode -> - begin match Name_mode.descr name_mode with - | Normal -> "normal" - | Phantom -> "phantom (or normal)" - | In_types -> "in-types (or normal)" - end - in - let check name binding_time name_mode (earliest : Earliest_alias.t) = - match earliest with - | No_alias -> () - | Earliest e as earliest_as_recorded -> - if Binding_time.compare binding_time e.binding_time < 0 then - Misc.fatal_errorf - "@[Earliest %s alias %a@ has binding time %a,@ \ - earlier than %a@ in %a\ - @]" - (describe_field name_mode) - Name.print name - Binding_time.print binding_time - Earliest_alias.print earliest_as_recorded - print t - in - Name.Map.iter (fun name _coercion -> - let binding_time_and_mode = - Name.Map.find name binding_times_and_modes - in - let binding_time, name_mode = - Binding_time.With_name_mode.( - binding_time binding_time_and_mode, - name_mode binding_time_and_mode) - in - check name binding_time None t.earliest; - let earliest_in_mode = find_earliest t ~min_name_mode:(Some name_mode) in - check name binding_time (Some name_mode) earliest_in_mode - ) t.all; - let check_earliest min_name_mode = - match find_earliest t ~min_name_mode with - | No_alias -> () - | Earliest e as earliest -> - let in_map = - match Name.Map.find_opt e.name t.all with - | None -> false - | Some coercion -> Coercion.equal coercion e.coercion_to_canonical - in - if not in_map then begin - Misc.fatal_errorf - "@[Aliases_of_canonical_element: Earliest %s not in map@ \ - @[Alias: %a@ Map: %a@]@]" - (describe_field min_name_mode) - Earliest_alias.print earliest - (Name.Map.print Coercion.print) t.all - end - in - List.iter check_earliest - [ None; - Some Name_mode.normal; - Some Name_mode.phantom; - Some Name_mode.in_types ] + let find_earliest_candidates t ~min_name_mode = + Name_mode.Map.fold (fun order aliases res_opt -> + match res_opt with + | Some _ -> res_opt + | None -> + begin match + Name_mode.compare_partial_order + order min_name_mode + with + | None -> None + | Some result -> + if result >= 0 then Some aliases else None + end) + t.aliases + None let mem t elt = - Name.Map.mem elt t.all + Simple.Map.mem elt t.all let all t = t.all - let earliest_alias t ~min_name_mode : (Name.t * Coercion.t) option = - match find_earliest t ~min_name_mode with - | Earliest { name; coercion_to_canonical; binding_time = _ } -> - Some (name, coercion_to_canonical) - | No_alias -> None - - let union t1 t2 : t Or_bottom.t = - let exception Return_bottom in - match - Name.Map.merge (fun _name coercion1 coercion2 -> - match coercion1, coercion2 with - | None, None -> assert false - | Some coercion, None - | None, Some coercion -> Some coercion - | Some coercion1, Some coercion2 -> - if Coercion.equal coercion1 coercion2 then Some coercion1 - else raise Return_bottom - ) t1.all t2.all - with - | exception Return_bottom -> Bottom - | all -> - let earliest = - Earliest_alias.union t1.earliest t2.earliest - in - let earliest_normal = - Earliest_alias.union t1.earliest_normal t2.earliest_normal - in - let earliest_ge_phantom = - Earliest_alias.union t1.earliest_ge_phantom t2.earliest_ge_phantom - in - let earliest_ge_in_types = - Earliest_alias.union t1.earliest_ge_in_types t2.earliest_ge_in_types - in - Ok { all; earliest; earliest_normal; earliest_ge_phantom; - earliest_ge_in_types; } - - let disjoint t1 t2 = - not (Name.Map.inter_domain_is_non_empty t1.all t2.all) - - let update_all_earliest - { all; earliest; earliest_normal; - earliest_ge_phantom; earliest_ge_in_types; } ~f = - let earliest = f earliest in - let earliest_normal = f earliest_normal in - let earliest_ge_phantom = f earliest_ge_phantom in - let earliest_ge_in_types = f earliest_ge_in_types in - { all; earliest; earliest_normal; earliest_ge_phantom; - earliest_ge_in_types; } - - let import import_name - ({ all; earliest = _; earliest_normal = _; earliest_ge_phantom = _; - earliest_ge_in_types = _ } as t) = - let all = map_keys import_name all in - let t = { t with all; } in - let t = update_all_earliest t ~f:(Earliest_alias.map_name ~f:import_name) in + let union t1 t2 = + let aliases : map_to_canonical Name_mode.Map.t= + Name_mode.Map.union (fun _order elts1 elts2 -> + Some (map_union elts1 elts2)) + t1.aliases t2.aliases + in + let t = + { aliases; + all = map_union t1.all t2.all; + } + in + invariant t; (* CR xclerc for xclerc: not guaranteed to hold *) t - let apply_coercion_to_all t coercion : t Or_bottom.t = - compose_map_values t.all ~then_:coercion - |> - Or_bottom.map ~f:(fun all -> - let t = { t with all; } in - let t = update_all_earliest t ~f:(fun earliest -> - (* This composition must succeed if coerce_map did *) - Earliest_alias.map_coercion earliest ~f:(fun coercion_to_canonical -> - Coercion.compose_exn coercion_to_canonical ~then_:coercion)) - in - t) - - let move_variables_to_mode_in_types t = - update_all_earliest t ~f:(fun earliest -> - match earliest with - | Earliest { name; _ } when Name.is_var name -> No_alias - | _ -> earliest) -end + 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 (map_inter elts1 elts2)) + t1.aliases t2.aliases + in + let t = + { aliases; + all = map_inter t1.all t2.all; + } + in + invariant t; + t -module Alias_set = struct - type t = { - const : Const.t option; - names : Coercion.t Name.Map.t; - } + let import import_simple { aliases; all } = + let map_simple elts = + Simple.Map.fold (fun elt coercion acc -> + Simple.Map.add (import_simple elt) coercion acc) + elts + Simple.Map.empty + in + let aliases = Name_mode.Map.map map_simple aliases in + let all = map_simple all in + let t = { aliases; all } in + invariant t; (* CR xclerc for xclerc: not guaranteed to hold *) + t - 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 -> - let coercion = Simple.coercion simple in - { const = None; names = Name.Map.singleton name coercion }) - - 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 apply_coercion_to_all { const; names; } coercion = - compose_map_values names ~then_:coercion - |> - Or_bottom.map ~f:(fun names -> { const; 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 = - Name.Map.merge (fun _name coercion1 coercion2 -> - match coercion1, coercion2 with - | Some coercion1, Some coercion2 - when Coercion.equal coercion1 coercion2 -> Some coercion1 - | _, _ -> None - ) names1 names2 - in - { const; names; } + let merge t1 t2 = + let aliases = + Name_mode.Map.union (fun _mode map1 map2 -> + Some (map_union map1 map2) + ) + t1.aliases + t2.aliases + 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 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 + let compose { aliases; all; } ~then_ = + let f m = + Simple.Map.map (Coercion.compose_exn ~then_) m + in + let aliases = Name_mode.Map.map f aliases in + let all = f all in + { aliases; all; } + + let move_variables_to_mode_in_types { aliases; all; } = + let (no_vars_aliases, all_variables) = + Name_mode.Map.fold (fun mode aliases (no_vars_aliases, all_variables) -> + let key_is_var key _ = Simple.is_var key in + let (vars, non_vars) = Simple.Map.partition key_is_var aliases in + let no_vars_aliases = + if Simple.Map.is_empty non_vars then no_vars_aliases + else Name_mode.Map.add mode non_vars no_vars_aliases + in + no_vars_aliases, map_union vars all_variables) + aliases + (Name_mode.Map.empty, Simple.Map.empty) in - { const; names; } - - let find_best { const; names; } = - match const with - | Some const -> Some (Simple.const const) - | None -> - let key_is_symbol key _ = Name.is_symbol key in - let (symbols, vars) = Name.Map.partition key_is_symbol names in - let simple_of_binding (name, coercion) = - Simple.with_coercion (Simple.name name) coercion - in - match Name.Map.min_binding_opt symbols with - | Some binding -> - Some (binding |> simple_of_binding) - | None -> - match Name.Map.min_binding_opt vars with - | Some binding -> - Some (binding |> simple_of_binding) - | None -> - None + let aliases = + if Name_mode.Map.mem Name_mode.in_types no_vars_aliases + then Misc.fatal_errorf "move_variables_to_mode_in_types: \ + The following non-vars have mode In_types:@ %a" + (Simple.Map.print Coercion.print) + (Name_mode.Map.find Name_mode.in_types no_vars_aliases) + else + if Simple.Map.is_empty all_variables then no_vars_aliases + else Name_mode.Map.add Name_mode.in_types all_variables no_vars_aliases + in + { aliases; all; } end type t = { - canonical_elements : (Simple.t * coercion_to_canonical) Name.Map.t; - (* Canonical elements that have no known aliases may not be included in - [canonical_elements]. (This comment used to say "are not included," but - this was not the case; any code that relied on this invariant should be - fixed.) *) - aliases_of_canonical_names : Aliases_of_canonical_element.t Name.Map.t; - (* For [elt |-> aliases] in [aliases_of_canonical_names], then + canonical_elements : (Simple.t * coercion_to_canonical) Simple.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] never includes [elt]. *) (* CR mshinwell: check this always holds *) - 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_modes : Binding_time.With_name_mode.t Simple.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 @@ -522,8 +297,8 @@ type t = { 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 ppf { canonical_elements; aliases_of_canonical_elements; + binding_times_and_modes; } = let print_element_and_coercion ppf (elt, coercion) = Format.fprintf ppf "@[(\ %a@ \ @@ -539,77 +314,54 @@ let print ppf { canonical_elements; aliases_of_canonical_names; Format.fprintf ppf "@[(\ @[(canonical_elements@ %a)@]@ \ - @[(aliases_of_canonical_names@ %a)@]@ \ - @[(aliases_of_consts@ %a)@]@ \ + @[(aliases_of_canonical_elements@ %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) + (Simple.Map.print print_element_and_coercion) canonical_elements + (Simple.Map.print Aliases_of_canonical_element.print) + aliases_of_canonical_elements + (Simple.Map.print Binding_time.With_name_mode.print) binding_times_and_modes -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 +let defined_earlier t alias ~than = + let alias = Simple.without_coercion alias in + let than = Simple.without_coercion than in + let info1 = Simple.Map.find alias t.binding_times_and_modes in + let info2 = Simple.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 name_mode t elt = - Simple.pattern_match elt - ~const:(fun _ -> Name_mode.normal) - ~name:(fun elt -> - Binding_time.With_name_mode.name_mode - (Name.Map.find elt t.binding_times_and_modes)) - -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) + Binding_time.With_name_mode.name_mode + (Simple.Map.find elt t.binding_times_and_modes) let invariant t = if !Clflags.flambda_invariant_checks then begin let _all_aliases : map_to_canonical = - Name.Map.fold (fun canonical_element aliases all_aliases -> - Aliases_of_canonical_element.invariant aliases - ~binding_times_and_modes:t.binding_times_and_modes; + Simple.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 (Name.Map.for_all (fun elt _coercion -> - defined_earlier t (Simple.name canonical_element) - ~than:(Simple.name elt)) - aliases) + if not (Simple.Map.for_all (fun elt _coercion -> + 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" - Name.print canonical_element + Simple.print canonical_element print t end; - if Name.Map.mem canonical_element aliases then begin + if Simple.Map.mem canonical_element aliases then begin Misc.fatal_errorf "Canonical element %a occurs in alias set:@ %a" - Name.print canonical_element - (Name.Map.print Coercion.print) aliases + Simple.print canonical_element + (Simple.Map.print Coercion.print) aliases end; - if Name.Map.inter_domain_is_non_empty aliases all_aliases then + if not (Simple.Map.is_empty (map_inter aliases all_aliases)) then begin Misc.fatal_errorf "Overlapping alias sets:@ %a" print t end; - Name.Map.disjoint_union aliases all_aliases) - t.aliases_of_canonical_names - Name.Map.empty + map_union aliases all_aliases) + t.aliases_of_canonical_elements + Simple.Map.empty in () end @@ -617,10 +369,9 @@ let invariant t = let empty = { (* CR mshinwell: Rename canonical_elements, maybe to aliases_to_canonical_elements. *) - 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; + canonical_elements = Simple.Map.empty; + aliases_of_canonical_elements = Simple.Map.empty; + binding_times_and_modes = Simple.Map.empty; } type canonical = @@ -631,37 +382,16 @@ type canonical = } let canonical t element : canonical = - 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_from_name_to_canonical_element -> - let coercion_from_name_to_element = Simple.coercion element in - if !Clflags.flambda_invariant_checks then begin - assert (not (Simple.equal element canonical_element)) - end; - let coercion_from_element_to_canonical_element = - Coercion.compose_exn - (Coercion.inverse coercion_from_name_to_element) - ~then_:coercion_from_name_to_canonical_element - in - let coercion_to_canonical = - coercion_from_element_to_canonical_element - in - Alias_of_canonical { canonical_element; coercion_to_canonical; }) + match Simple.Map.find element 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 = - if !Clflags.flambda_invariant_checks then begin - assert (Coercion.is_id (Simple.coercion canonical_element)) - end; - 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 + match Simple.Map.find canonical_element t.aliases_of_canonical_elements with | exception Not_found -> Aliases_of_canonical_element.empty | aliases -> aliases @@ -706,102 +436,72 @@ let get_aliases_of_canonical_element t ~canonical_element = 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 ~to_be_demoted - : _ Or_bottom.t = +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 - Ok t + 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 be demoting 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 - 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))) + assert (not (Aliases_of_canonical_element.mem + aliases_of_to_be_demoted canonical_element)) end; + let canonical_elements = + t.canonical_elements + |> Simple.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 + Simple.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, 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 name_to_be_demoted)); - assert (Aliases_of_canonical_element.disjoint - aliases_of_canonical_element aliases_of_to_be_demoted) + aliases_of_canonical_element 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 ( let* ) x f = Or_bottom.bind x ~f in - let* aliases = - Aliases_of_canonical_element.apply_coercion_to_all - aliases_of_to_be_demoted coercion_to_canonical - in - let* aliases = - Aliases_of_canonical_element.union aliases aliases_of_canonical_element - in let aliases = Aliases_of_canonical_element.add - aliases - name_to_be_demoted - coercion_to_canonical - (binding_time_and_name_mode t to_be_demoted) - in - 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 canonical_elements = - t.canonical_elements - |> Name.Map.fold (fun alias coercion_to_to_be_demoted canonical_elements -> - let coercion_to_canonical = - (* This shouldn't throw an exception, since the previous - compositions succeeded *) - 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) - |> Name.Map.add name_to_be_demoted - (canonical_element, coercion_to_canonical) + (Aliases_of_canonical_element.union + (Aliases_of_canonical_element.compose aliases_of_to_be_demoted ~then_:coercion_to_canonical) + aliases_of_canonical_element) + to_be_demoted + ~coercion_to_canonical + (name_mode 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 in let res = { canonical_elements; - aliases_of_canonical_names; - aliases_of_consts; + aliases_of_canonical_elements; binding_times_and_modes = t.binding_times_and_modes; } in invariant res; - Ok res + res -type to_be_demoted = Demote_canonical_element1 | Demote_canonical_element2 +type to_be_demoted = Demote_element1 | Demote_element2 let choose_canonical_element_to_be_demoted t ~canonical_element1 ~canonical_element2 = if defined_earlier t canonical_element1 ~than:canonical_element2 - then Demote_canonical_element2 else Demote_canonical_element1 + then Demote_element2 else Demote_element1 (* CR mshinwell: add submodule *) type add_result = { @@ -840,7 +540,7 @@ let add_alias t ~element1 ~coercion_from_element2_to_element1 ~element2 = ~canonical_element1 ~canonical_element2 in match which_element with - | Demote_canonical_element1 -> + | Demote_element1 -> let coercion_from_canonical_element1_to_canonical_element2 = Coercion.inverse coercion_from_canonical_element2_to_canonical_element1 @@ -848,7 +548,7 @@ let add_alias t ~element1 ~coercion_from_element2_to_element1 ~element2 = canonical_element2, canonical_element1, element1, coercion_from_canonical_element1_to_canonical_element2, coercion_from_element1_to_canonical_element1 - | Demote_canonical_element2 -> + | Demote_element2 -> canonical_element1, canonical_element2, element2, coercion_from_canonical_element2_to_canonical_element1, coercion_from_element2_to_canonical_element2 @@ -869,11 +569,10 @@ let add_alias t ~element1 ~coercion_from_element2_to_element1 ~element2 = Simple.with_coercion demoted_alias coercion_from_demoted_alias_to_canonical in - Or_bottom.map t ~f:(fun t -> - { t; - canonical_element; - demoted_alias; - }) + { t; + canonical_element; + demoted_alias; + } in match canonical t element1, canonical t element2 with | Is_canonical, Is_canonical -> @@ -963,18 +662,6 @@ let add_alias t ~element1 ~coercion_from_element2_to_element1 ~element2 = let add t ~element1:element1_with_coercion ~binding_time_and_mode1 ~element2:element2_with_coercion ~binding_time_and_mode2 = - Simple.pattern_match element1_with_coercion - ~name:(fun _ -> ()) - ~const:(fun const1 -> - Simple.pattern_match element2_with_coercion - ~name:(fun _ -> ()) - ~const:(fun const2 -> - if not (Const.equal const1 const2) then begin - Misc.fatal_errorf - "Cannot add alias between two non-equal consts: %a <> %a" - Const.print const1 - Const.print const2 - end)); let original_t = t in (* element1_with_coercion <--[c1]-- element1 + @@ -990,34 +677,21 @@ let add t ~element1:element1_with_coercion ~binding_time_and_mode1 Coercion.compose_exn (Simple.coercion element2_with_coercion) ~then_:(Coercion.inverse (Simple.coercion element1_with_coercion)) in - 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 = - add_if_name element1 binding_time_and_mode1 - (add_if_name element2 binding_time_and_mode2 + Simple.Map.add element1 binding_time_and_mode1 + (Simple.Map.add element2 binding_time_and_mode2 t.binding_times_and_modes); } in - let add_result : add_result Or_bottom.t = - add_alias t ~element1 ~coercion_from_element2_to_element1 ~element2 - in + let add_result = add_alias t ~element1 ~coercion_from_element2_to_element1 ~element2 in if !Clflags.flambda_invariant_checks then begin - match add_result with - | Ok add_result -> invariant_add_result ~original_t add_result - | Bottom -> () + invariant_add_result ~original_t add_result end; add_result let mem t element = - 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) + Simple.Map.mem element t.binding_times_and_modes (* CR mshinwell: This needs documenting. For the moment we allow relations between canonical elements that are actually incomparable @@ -1051,36 +725,45 @@ let get_canonical_element_exn t element elt_name_mode ~min_name_mode = canonical_element, name_mode, Coercion.inverse coercion_to_canonical in (* - if !Clflags.flambda_invariant_checks then 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; - *) +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 () = (* 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 appear + 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 match - Aliases_of_canonical_element.earliest_alias aliases - ~min_name_mode:(Some min_name_mode) + Aliases_of_canonical_element.find_earliest_candidates aliases + ~min_name_mode with - | Some (earliest, coercion_from_earliest_to_canonical) -> + | Some at_earliest_mode -> + (* Aliases_of_canonical_element.find_earliest_candidates only returns + non-empty sets *) + assert (not (Simple.Map.is_empty at_earliest_mode)); + let earliest, coercion_from_earliest_to_canonical = + Simple.Map.fold (fun elt coercion ((min_elt, _min_coercion) as min_binding) -> + if defined_earlier t elt ~than:min_elt + then elt, coercion + else min_binding) + at_earliest_mode + (Simple.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 + Simple.with_coercion earliest coercion_from_earliest_to_element | None -> raise Not_found in - match - Name_mode.compare_partial_order name_mode min_name_mode - with + match Name_mode.compare_partial_order name_mode min_name_mode with | None -> find_earliest () | Some c -> if c >= 0 then @@ -1091,18 +774,12 @@ let make_get_aliases_result ~element:_ ~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 }) + ~(names_with_coercions_to_element : Coercion.t Simple.Map.t) = + Simple.Set.add + (Simple.with_coercion canonical_element coercion_from_canonical_to_element) + (Simple.Map.fold (fun simple coercion set -> + Simple.Set.add (Simple.with_coercion simple coercion) set + ) names_with_coercions_to_element Simple.Set.empty) let get_aliases t element = match canonical t element with @@ -1126,10 +803,9 @@ let get_aliases t element = if !Clflags.flambda_invariant_checks then begin assert (not (Simple.equal element canonical_element)) end; - - let names_with_coercions_to_canonical = + let aliases_with_coercions_to_canonical = Aliases_of_canonical_element.all - (get_aliases_of_canonical_element t ~canonical_element) + (get_aliases_of_canonical_element t ~canonical_element) in let coercion_from_canonical_to_element = Coercion.inverse coercion_from_element_to_canonical @@ -1137,10 +813,10 @@ let get_aliases t element = (* 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 + compose_map_values_exn aliases_with_coercions_to_canonical ~then_:coercion_from_canonical_to_element in - + if !Clflags.flambda_invariant_checks then begin let element_coerced_to_canonical = Simple.apply_coercion_exn element coercion_from_element_to_canonical @@ -1148,17 +824,16 @@ let get_aliases t element = (* 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 + assert (Simple.Map.exists (fun name coercion_from_name_to_canonical -> let name_coerced_to_canonical = Simple.apply_coercion_exn - (Simple.name name) + name coercion_from_name_to_canonical in Simple.equal element_coerced_to_canonical name_coerced_to_canonical - ) names_with_coercions_to_canonical) + ) aliases_with_coercions_to_canonical) end; - make_get_aliases_result ~element ~canonical_element @@ -1166,97 +841,62 @@ let get_aliases t element = ~names_with_coercions_to_element let all_ids_for_export { canonical_elements = _; - aliases_of_canonical_names = _; - aliases_of_consts; + aliases_of_canonical_elements = _; binding_times_and_modes; } = - let ids = Ids_for_export.empty in - let ids = - Name.Map.fold (fun elt _binding_time_and_mode ids -> - Ids_for_export.add_name ids elt) - binding_times_and_modes - ids - in - let ids = - Const.Map.fold (fun elt _aliases ids -> - Ids_for_export.add_const ids elt) - aliases_of_consts - ids - in - ids + Simple.Map.fold (fun elt _binding_time_and_mode ids -> + Ids_for_export.add_simple ids elt) + binding_times_and_modes + Ids_for_export.empty let import import_map { canonical_elements; - aliases_of_canonical_names; - aliases_of_consts; - binding_times_and_modes } = + aliases_of_canonical_elements; + binding_times_and_modes; } = let import_simple x = Ids_for_export.Import_map.simple import_map x in - let import_name x = Ids_for_export.Import_map.name import_map x in - let import_const c = Ids_for_export.Import_map.const import_map c in let canonical_elements = - Name.Map.fold (fun elt (canonical, coercion) acc -> - Name.Map.add (import_name elt) (import_simple canonical, coercion) acc) + Simple.Map.fold (fun elt (canonical, coercion) acc -> + Simple.Map.add (import_simple elt) (import_simple canonical, coercion) acc) canonical_elements - Name.Map.empty - in - let aliases_of_canonical_names = - Name.Map.fold (fun canonical aliases acc -> - Name.Map.add (import_name canonical) - (Aliases_of_canonical_element.import import_name aliases) - acc) - aliases_of_canonical_names - Name.Map.empty + Simple.Map.empty in - let aliases_of_consts = - Const.Map.fold (fun const aliases acc -> - Const.Map.add (import_const const) - (Aliases_of_canonical_element.import import_name aliases) + let 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. *) + Simple.Map.fold (fun canonical aliases acc -> + Simple.Map.add (import_simple canonical) + (Aliases_of_canonical_element.import import_simple aliases) acc) - aliases_of_consts - Const.Map.empty + aliases_of_canonical_elements + Simple.Map.empty in let binding_times_and_modes = - map_keys import_name binding_times_and_modes - in - let t = - { canonical_elements; - aliases_of_canonical_names; - aliases_of_consts; - binding_times_and_modes; - } + Simple.Map.fold (fun simple binding_time_and_mode acc -> + Simple.Map.add (import_simple simple) binding_time_and_mode acc) + binding_times_and_modes + Simple.Map.empty in - invariant t; - t + { canonical_elements; + aliases_of_canonical_elements; + binding_times_and_modes; + } let merge t1 t2 = let canonical_elements = - Name.Map.disjoint_union + Simple.Map.disjoint_union t1.canonical_elements t2.canonical_elements in - (* 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 = - match Aliases_of_canonical_element.union aliases1 aliases2 with - | Ok aliases -> Some aliases - | Bottom -> - (* CR lmaurer: This is actually possible, if probably exceedingly rare, - so we should be returting Bottom in this case. *) - Misc.fatal_errorf "Conflicting aliases:@ %a@ vs.@ %a" - print t1 - print t2 - 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 + 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 in let symbol_data = Binding_time.With_name_mode.create @@ -1264,30 +904,34 @@ let merge t1 t2 = Name_mode.normal in let binding_times_and_modes = - 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)) + 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))) t1.binding_times_and_modes t2.binding_times_and_modes in { canonical_elements; - aliases_of_canonical_names; - aliases_of_consts; + aliases_of_canonical_elements; binding_times_and_modes; } @@ -1296,38 +940,32 @@ let get_canonical_ignoring_name_mode t name = match canonical t elt with | Is_canonical -> elt - | Alias_of_canonical { canonical_element; coercion_to_canonical; } -> + | 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_names; - aliases_of_consts; + aliases_of_canonical_elements; binding_times_and_modes; } = let binding_times_and_modes = - Name.Map.mapi (fun name binding_time_and_mode -> + Simple.Map.mapi (fun simple binding_time_and_mode -> let module BTM = Binding_time.With_name_mode in let new_mode = - if Name.is_var name then Name_mode.in_types + if Simple.is_var simple then Name_mode.in_types else BTM.name_mode binding_time_and_mode in BTM.create (BTM.binding_time binding_time_and_mode) new_mode) binding_times_and_modes in - let aliases_of_canonical_names = + let aliases_of_canonical_elements = (* Note: the relative order of the aliases and of their canonical element will be unchanged, as it only depends on the binding times. *) - Name.Map.map Aliases_of_canonical_element.move_variables_to_mode_in_types - aliases_of_canonical_names - in - let aliases_of_consts = - Const.Map.map Aliases_of_canonical_element.move_variables_to_mode_in_types - aliases_of_consts + Simple.Map.map Aliases_of_canonical_element.move_variables_to_mode_in_types + aliases_of_canonical_elements in { canonical_elements; - aliases_of_canonical_names; - aliases_of_consts; + aliases_of_canonical_elements; binding_times_and_modes; } diff --git a/middle_end/flambda/types/env/aliases.mli b/middle_end/flambda/types/env/aliases.mli index dedbac3970dd..f229c374f325 100644 --- a/middle_end/flambda/types/env/aliases.mli +++ b/middle_end/flambda/types/env/aliases.mli @@ -75,7 +75,7 @@ val add -> 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 Or_bottom.t + -> add_result val mem : t -> Simple.t -> bool @@ -88,37 +88,8 @@ val get_canonical_element_exn -> min_name_mode:Name_mode.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 apply_coercion_to_all : t -> Coercion.t -> t Or_bottom.t - - 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 includes the supplied element in the alias set. *) -val get_aliases - : t - -> Simple.t - -> Alias_set.t +(** [get_aliases] always returns the supplied element in the result set. *) +val get_aliases : t -> Simple.t -> Simple.Set.t val get_canonical_ignoring_name_mode : t diff --git a/middle_end/flambda/types/env/typing_env.rec.ml b/middle_end/flambda/types/env/typing_env.rec.ml index fee94a82ae60..2c7460f26399 100644 --- a/middle_end/flambda/types/env/typing_env.rec.ml +++ b/middle_end/flambda/types/env/typing_env.rec.ml @@ -1018,31 +1018,23 @@ and add_equation t name ty = let binding_time_and_mode_alias_of = binding_time_and_mode_of_simple t alias_of in - match + let ({ canonical_element; + demoted_alias; + 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 - with - | Bottom -> - let canonical = - Aliases.get_canonical_ignoring_name_mode aliases name - in - let lhs = canonical in - let ty = Type_grammar.bottom_like ty in - aliases, lhs, t, ty - | Ok { canonical_element; - demoted_alias; - t = aliases; } -> - (* We need to change the demoted alias's type to point to the new - canonical element. *) - let lhs = demoted_alias in - let ty = - Type_grammar.alias_type_of kind canonical_element - in - aliases, lhs, t, ty + in + (* We need to change the demoted alias's type to point to the new + canonical element. *) + let lhs = demoted_alias in + let ty = + Type_grammar.alias_type_of kind canonical_element + in + 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 @@ -1357,7 +1349,7 @@ let get_alias_then_canonical_simple_exn t ?min_name_mode typ = let aliases_of_simple t ~min_name_mode simple = Aliases.get_aliases (aliases t) simple - |> Aliases.Alias_set.filter ~f:(fun alias -> + |> Simple.Set.filter (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 40dfebce2f4c..725e08f1696f 100644 --- a/middle_end/flambda/types/env/typing_env.rec.mli +++ b/middle_end/flambda/types/env/typing_env.rec.mli @@ -120,12 +120,12 @@ val aliases_of_simple : t -> min_name_mode:Name_mode.t -> Simple.t - -> Aliases.Alias_set.t + -> Simple.Set.t val aliases_of_simple_allowable_in_types : t -> Simple.t - -> Aliases.Alias_set.t + -> Simple.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 47b3e4769dfa..28a4443ddf89 100644 --- a/middle_end/flambda/types/flambda_type.mli +++ b/middle_end/flambda/types/flambda_type.mli @@ -178,7 +178,7 @@ module Typing_env : sig : t -> min_name_mode:Name_mode.t -> Simple.t - -> Aliases.Alias_set.t + -> Simple.Set.t val clean_for_export : t -> reachable_names:Name_occurrences.t -> t diff --git a/middle_end/flambda/types/type_descr.rec.ml b/middle_end/flambda/types/type_descr.rec.ml index c657f5fbe202..c4fe2e5486a9 100644 --- a/middle_end/flambda/types/type_descr.rec.ml +++ b/middle_end/flambda/types/type_descr.rec.ml @@ -243,19 +243,20 @@ module Make (Head : Type_head_intf.S let all_aliases_of env simple_opt ~in_env = match simple_opt with - | None -> - Aliases.Alias_set.empty + | None -> Simple.Set.empty | Some simple -> let simples = - TE.aliases_of_simple_allowable_in_types env simple + Simple.Set.add 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; *) - Aliases.Alias_set.filter simples ~f:(fun simple -> - Typing_env.mem_simple in_env simple) + Simple.Set.filter (fun simple -> + Typing_env.mem_simple in_env simple) + simples let [@inline always] get_canonical_simples_and_expand_heads ~force_to_kind ~to_type kind ~left_env ~left_ty ~right_env ~right_ty = @@ -477,21 +478,41 @@ 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 = - (* CR lmaurer: Seems a bit hacky to be constructing alias sets here in - the trivial cases, and "find me a shared alias" sounds like a fine - operation to be in [Aliases], so we should figure out how to move - some of this logic over there. *) match canonical_simple1, canonical_simple2 with - | None, _ | _, None -> Aliases.Alias_set.empty + | None, _ | _, None -> Simple.Set.empty | Some simple1, Some simple2 -> if Simple.same simple1 simple2 - then Aliases.Alias_set.singleton simple1 + then Simple.Set.singleton simple1 else - Aliases.Alias_set.inter + Simple.Set.inter (all_aliases_of (Join_env.left_join_env join_env) canonical_simple1 ~in_env:(Join_env.target_join_env join_env)) @@ -505,15 +526,16 @@ module Make (Head : Type_head_intf.S (* CR vlaviron: this ensures that we're not creating an alias to a different simple that is just bound_name with different coercion. Such an alias is forbidden. *) - Aliases.Alias_set.filter shared_aliases ~f:(fun simple -> + Simple.Set.filter (fun simple -> not (Simple.same simple (Simple.name bound_name))) + shared_aliases in (* Format.eprintf "Shared aliases:@ %a\n%!" - Aliases.Alias_set.print shared_aliases; + Simple.Set.print shared_aliases; *) - match Aliases.Alias_set.find_best shared_aliases with - | Some alias -> Known (to_type (create_equals alias)) + match choose_shared_alias ~shared_aliases with + | Some joined_ty -> Known (to_type joined_ty) | None -> match canonical_simple1, canonical_simple2 with | Some simple1, Some simple2 diff --git a/testsuite/tests/flambda2-aliases/test.ml b/testsuite/tests/flambda2-aliases/test.ml index 6130f3b3d6d8..0139f68c9fd2 100644 --- a/testsuite/tests/flambda2-aliases/test.ml +++ b/testsuite/tests/flambda2-aliases/test.ml @@ -57,15 +57,18 @@ let add_alias let element2 = Simple.with_coercion element2 coercion_from_element2_to_element1 in - let { Aliases.t; canonical_element; alias_of_demoted_element; coercion_from_alias_of_demoted_to_canonical; } = + let { Aliases.t; canonical_element; demoted_alias } = Aliases.add aliases ~element1 ~binding_time_and_mode1 ~element2 ~binding_time_and_mode2 - |> of_ok in + let coercion_from_demoted_alias_to_canonical_element = + Simple.coercion demoted_alias + in + let demoted_alias = Simple.without_coercion demoted_alias in let pp_name_mode ppf binding_time_and_mode = let name_mode = Binding_time.With_name_mode.name_mode binding_time_and_mode @@ -77,8 +80,8 @@ let add_alias 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 + Coercion.print coercion_from_demoted_alias_to_canonical_element + Simple.print demoted_alias pp_name_mode binding_time_and_mode2; t @@ -505,7 +508,7 @@ let two_var_name_mode_test name mode_x mode_y 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)) + Simple.Set.print (Aliases.get_aliases aliases x)) let () = two_var_name_mode_test "name mode: phantom = phantom" @@ -607,7 +610,7 @@ let () = test "three aliases (one inverse) /w modes" ~f:(fun ppf -> 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) + Simple.Set.print (Aliases.get_aliases aliases x) Aliases.print aliases) diff --git a/testsuite/tests/flambda2-aliases/test.reference b/testsuite/tests/flambda2-aliases/test.reference index 6134263e0022..eca696c9ac25 100644 --- a/testsuite/tests/flambda2-aliases/test.reference +++ b/testsuite/tests/flambda2-aliases/test.reference @@ -1,36 +1,18 @@ *** empty -((canonical_elements {}) (aliases_of_canonical_names {}) - (aliases_of_consts {}) (binding_times_and_modes {})) +((canonical_elements {}) (aliases_of_canonical_elements {}) + (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 - ((earliest (y/1 (coercion_to_canonical (depth 1 -> 0)) (binding_time 4))) - (earliest_normal - (y/1 (coercion_to_canonical (depth 1 -> 0)) (binding_time 4))) - (earliest_ge_phantom - (y/1 (coercion_to_canonical (depth 1 -> 0)) (binding_time 4))) - (earliest_ge_in_types - (y/1 (coercion_to_canonical (depth 1 -> 0)) (binding_time 4))) - (all {(y/1 (depth 1 -> 0))})))}) (aliases_of_consts {}) + (aliases_of_canonical_elements {(x/0 {(Normal {(y/1 (depth 1 -> 0))})})}) (binding_times_and_modes {(x/0 (bound at time 3 Normal)) (y/1 (bound at time 4 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 - ((earliest (x/2 (coercion_to_canonical (depth 0 -> 1)) (binding_time 6))) - (earliest_normal - (x/2 (coercion_to_canonical (depth 0 -> 1)) (binding_time 6))) - (earliest_ge_phantom - (x/2 (coercion_to_canonical (depth 0 -> 1)) (binding_time 6))) - (earliest_ge_in_types - (x/2 (coercion_to_canonical (depth 0 -> 1)) (binding_time 6))) - (all {(x/2 (depth 0 -> 1))})))}) (aliases_of_consts {}) + (aliases_of_canonical_elements {(y/3 {(Normal {(x/2 (depth 0 -> 1))})})}) (binding_times_and_modes {(x/2 (bound at time 6 Normal)) (y/3 (bound at time 5 Normal))})) @@ -40,17 +22,8 @@ ((canonical_elements {(y/5 (x/4 (coercion (depth 1 -> 0)))) (z/6 (x/4 (coercion (depth 2 -> 0))))}) - (aliases_of_canonical_names - {(x/4 - ((earliest (y/5 (coercion_to_canonical (depth 1 -> 0)) (binding_time 8))) - (earliest_normal - (y/5 (coercion_to_canonical (depth 1 -> 0)) (binding_time 8))) - (earliest_ge_phantom - (y/5 (coercion_to_canonical (depth 1 -> 0)) (binding_time 8))) - (earliest_ge_in_types - (y/5 (coercion_to_canonical (depth 1 -> 0)) (binding_time 8))) - (all {(y/5 (depth 1 -> 0)) (z/6 (depth 2 -> 0))})))}) - (aliases_of_consts {}) + (aliases_of_canonical_elements + {(x/4 {(Normal {(y/5 (depth 1 -> 0)) (z/6 (depth 2 -> 0))})})}) (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))})) @@ -61,18 +34,8 @@ ((canonical_elements {(z/9 (x/7 (coercion (depth 2 -> 0)))) (y/8 (x/7 (coercion (depth 1 -> 0))))}) - (aliases_of_canonical_names - {(x/7 - ((earliest - (y/8 (coercion_to_canonical (depth 1 -> 0)) (binding_time 11))) - (earliest_normal - (y/8 (coercion_to_canonical (depth 1 -> 0)) (binding_time 11))) - (earliest_ge_phantom - (y/8 (coercion_to_canonical (depth 1 -> 0)) (binding_time 11))) - (earliest_ge_in_types - (y/8 (coercion_to_canonical (depth 1 -> 0)) (binding_time 11))) - (all {(z/9 (depth 2 -> 0)) (y/8 (depth 1 -> 0))})))}) - (aliases_of_consts {}) + (aliases_of_canonical_elements + {(x/7 {(Normal {(z/9 (depth 2 -> 0)) (y/8 (depth 1 -> 0))})})}) (binding_times_and_modes {(x/7 (bound at time 10 Normal)) (z/9 (bound at time 12 Normal)) (y/8 (bound at time 11 Normal))})) @@ -83,18 +46,8 @@ ((canonical_elements {(x/10 (z/12 (coercion (depth 0 -> 2)))) (y/11 (z/12 (coercion (depth 1 -> 2))))}) - (aliases_of_canonical_names - {(z/12 - ((earliest - (x/10 (coercion_to_canonical (depth 0 -> 2)) (binding_time 14))) - (earliest_normal - (x/10 (coercion_to_canonical (depth 0 -> 2)) (binding_time 14))) - (earliest_ge_phantom - (x/10 (coercion_to_canonical (depth 0 -> 2)) (binding_time 14))) - (earliest_ge_in_types - (x/10 (coercion_to_canonical (depth 0 -> 2)) (binding_time 14))) - (all {(x/10 (depth 0 -> 2)) (y/11 (depth 1 -> 2))})))}) - (aliases_of_consts {}) + (aliases_of_canonical_elements + {(z/12 {(Normal {(x/10 (depth 0 -> 2)) (y/11 (depth 1 -> 2))})})}) (binding_times_and_modes {(z/12 (bound at time 13 Normal)) (x/10 (bound at time 14 Normal)) (y/11 (bound at time 15 Normal))})) @@ -105,18 +58,8 @@ ((canonical_elements {(x/13 (z/15 (coercion (depth 0 -> 2)))) (y/14 (z/15 (coercion (depth 1 -> 2))))}) - (aliases_of_canonical_names - {(z/15 - ((earliest - (x/13 (coercion_to_canonical (depth 0 -> 2)) (binding_time 17))) - (earliest_normal - (x/13 (coercion_to_canonical (depth 0 -> 2)) (binding_time 17))) - (earliest_ge_phantom - (x/13 (coercion_to_canonical (depth 0 -> 2)) (binding_time 17))) - (earliest_ge_in_types - (x/13 (coercion_to_canonical (depth 0 -> 2)) (binding_time 17))) - (all {(x/13 (depth 0 -> 2)) (y/14 (depth 1 -> 2))})))}) - (aliases_of_consts {}) + (aliases_of_canonical_elements + {(z/15 {(Normal {(x/13 (depth 0 -> 2)) (y/14 (depth 1 -> 2))})})}) (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))})) @@ -127,18 +70,8 @@ ((canonical_elements {(y/17 (x/16 (coercion (depth 1 -> 0)))) (z/18 (x/16 (coercion (depth 2 -> 0))))}) - (aliases_of_canonical_names - {(x/16 - ((earliest - (y/17 (coercion_to_canonical (depth 1 -> 0)) (binding_time 20))) - (earliest_normal - (y/17 (coercion_to_canonical (depth 1 -> 0)) (binding_time 20))) - (earliest_ge_phantom - (y/17 (coercion_to_canonical (depth 1 -> 0)) (binding_time 20))) - (earliest_ge_in_types - (y/17 (coercion_to_canonical (depth 1 -> 0)) (binding_time 20))) - (all {(y/17 (depth 1 -> 0)) (z/18 (depth 2 -> 0))})))}) - (aliases_of_consts {}) + (aliases_of_canonical_elements + {(x/16 {(Normal {(y/17 (depth 1 -> 0)) (z/18 (depth 2 -> 0))})})}) (binding_times_and_modes {(y/17 (bound at time 20 Normal)) (x/16 (bound at time 19 Normal)) (z/18 (bound at time 21 Normal))})) @@ -151,19 +84,10 @@ {(z/21 (x/19 (coercion (depth 2 -> 0)))) (y/20 (x/19 (coercion (depth 1 -> 0)))) (t/22 (x/19 (coercion (depth 3 -> 0))))}) - (aliases_of_canonical_names + (aliases_of_canonical_elements {(x/19 - ((earliest - (y/20 (coercion_to_canonical (depth 1 -> 0)) (binding_time 23))) - (earliest_normal - (y/20 (coercion_to_canonical (depth 1 -> 0)) (binding_time 23))) - (earliest_ge_phantom - (y/20 (coercion_to_canonical (depth 1 -> 0)) (binding_time 23))) - (earliest_ge_in_types - (y/20 (coercion_to_canonical (depth 1 -> 0)) (binding_time 23))) - (all - {(z/21 (depth 2 -> 0)) (y/20 (depth 1 -> 0)) (t/22 (depth 3 -> 0))})))}) - (aliases_of_consts {}) + {(Normal + {(z/21 (depth 2 -> 0)) (y/20 (depth 1 -> 0)) (t/22 (depth 3 -> 0))})})}) (binding_times_and_modes {(z/21 (bound at time 24 Normal)) (y/20 (bound at time 23 Normal)) (x/19 (bound at time 22 Normal)) (t/22 (bound at time 25 Normal))})) @@ -176,19 +100,10 @@ {(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 + (aliases_of_canonical_elements {(z/25 - ((earliest - (x/23 (coercion_to_canonical (depth 0 -> 2)) (binding_time 27))) - (earliest_normal - (x/23 (coercion_to_canonical (depth 0 -> 2)) (binding_time 27))) - (earliest_ge_phantom - (x/23 (coercion_to_canonical (depth 0 -> 2)) (binding_time 27))) - (earliest_ge_in_types - (x/23 (coercion_to_canonical (depth 0 -> 2)) (binding_time 27))) - (all - {(x/23 (depth 0 -> 2)) (y/24 (depth 1 -> 2)) (t/26 (depth 3 -> 2))})))}) - (aliases_of_consts {}) + {(Normal + {(x/23 (depth 0 -> 2)) (y/24 (depth 1 -> 2)) (t/26 (depth 3 -> 2))})})}) (binding_times_and_modes {(z/25 (bound at time 26 Normal)) (x/23 (bound at time 27 Normal)) (y/24 (bound at time 28 Normal)) (t/26 (bound at time 29 Normal))})) @@ -200,58 +115,50 @@ ((canonical_elements {(x/27 (#1 (coercion (depth 0 -> 2)))) (y/28 (#1 (coercion (depth 1 -> 2)))) - (t/29 (#1 (coercion (depth 3 -> 2))))}) (aliases_of_canonical_names {}) - (aliases_of_consts + (t/29 (#1 (coercion (depth 3 -> 2))))}) + (aliases_of_canonical_elements {(#1 - ((earliest - (x/27 (coercion_to_canonical (depth 0 -> 2)) (binding_time 30))) - (earliest_normal - (x/27 (coercion_to_canonical (depth 0 -> 2)) (binding_time 30))) - (earliest_ge_phantom - (x/27 (coercion_to_canonical (depth 0 -> 2)) (binding_time 30))) - (earliest_ge_in_types - (x/27 (coercion_to_canonical (depth 0 -> 2)) (binding_time 30))) - (all - {(x/27 (depth 0 -> 2)) (y/28 (depth 1 -> 2)) (t/29 (depth 3 -> 2))})))}) + {(Normal + {(x/27 (depth 0 -> 2)) (y/28 (depth 1 -> 2)) (t/29 (depth 3 -> 2))})})}) (binding_times_and_modes - {(x/27 (bound at time 30 Normal)) (y/28 (bound at time 31 Normal)) - (t/29 (bound at time 32 Normal))})) + {(#1 (bound at time 0 Normal)) (x/27 (bound at time 30 Normal)) + (y/28 (bound at time 31 Normal)) (t/29 (bound at time 32 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 {(y/31 (depth 1 -> 0)) (x/30 id)}) +Aliases of x/30: { x/30 (coerce 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 {(x/32 id) (y/33 (depth 1 -> 0))}) +Aliases of x/32: { x/32 (coerce y/33 (depth 1 -> 0)) } *** 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))}) +Aliases of x/34: { x/34 (coerce 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 {(y/37 (depth 1 -> 0)) (x/36 id)}) +Aliases of x/36: { x/36 (coerce 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))}) +Aliases of x/38: { x/38 (coerce 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)}) +Aliases of x/40: { x/40 (coerce y/41 (depth 1 -> 0)) } *** three aliases (one inverse) /w modes [added] x/42 (In_types) <--[(depth 1 -> 0)]-- y/43 (In_types) @@ -278,28 +185,17 @@ Canonical for t/45: (coerce x/42 (depth 0 -> 3)) ... >= In_types: (coerce x/42 (depth 0 -> 3)) ... >= Normal: t/45 -Aliases of z/44: ((const ()) - (names - {(t/45 (depth 3 -> 0)) (x/42 id) (z/44 (depth 2 -> 0)) - (y/43 (depth 1 -> 0))}) +Aliases of z/44: { x/42 (coerce z/44 (depth 2 -> 0)) + (coerce y/43 (depth 1 -> 0)) (coerce t/45 (depth 3 -> 0)) } ((canonical_elements {(t/45 (x/42 (coercion (depth 3 -> 0)))) (z/44 (x/42 (coercion (depth 2 -> 0)))) (y/43 (x/42 (coercion (depth 1 -> 0))))}) - (aliases_of_canonical_names + (aliases_of_canonical_elements {(x/42 - ((earliest - (y/43 (coercion_to_canonical (depth 1 -> 0)) (binding_time 46))) - (earliest_normal - (t/45 (coercion_to_canonical (depth 3 -> 0)) (binding_time 48))) - (earliest_ge_phantom - (z/44 (coercion_to_canonical (depth 2 -> 0)) (binding_time 47))) - (earliest_ge_in_types - (y/43 (coercion_to_canonical (depth 1 -> 0)) (binding_time 46))) - (all - {(t/45 (depth 3 -> 0)) (z/44 (depth 2 -> 0)) (y/43 (depth 1 -> 0))})))}) - (aliases_of_consts {}) + {(Phantom {(z/44 (depth 2 -> 0))}) (In_types {(y/43 (depth 1 -> 0))}) + (Normal {(t/45 (depth 3 -> 0))})})}) (binding_times_and_modes {(t/45 (bound at time 48 Normal)) (x/42 (bound at time 45 In_types)) (z/44 (bound at time 47 Phantom)) (y/43 (bound at time 46 In_types))})) From 1450b147392a8ec6addd4e7a877f55019cded256 Mon Sep 17 00:00:00 2001 From: Luke Maurer Date: Thu, 29 Apr 2021 14:48:50 +0100 Subject: [PATCH 16/16] Empty commit in order to request checks manually request-checks: true