[m-rev.] for review: fix mantis bug 544

Julien Fischer jfischer at opturion.com
Mon Feb 7 17:19:16 AEDT 2022


Hi Zoltan,

Once this is committed, I'll set up a machine to bootcheck the trunk
in a bunch of hlc grades; provided that all passes I will merge it on to
the release branch -- the map fix will go on to the release branch
regardless.

On Mon, 7 Feb 2022, Zoltan Somogyi wrote:

> For review by Julien.
>
> As mentioned in a comment, we could eliminate one source
> of overhead added by this diff by adding a common_subset
> predicate to assoc_list.m. Would anyone object to this?

No objections; ideally map.m and assoc_list.map should support the same
(or at least a very similar) set of operations, both being map ADTs.

> Handle const_var_maps left by add_trail_ops.m.
> 
> This fixes Mantis bug #544.
> 
> The code of add_trail_ops.m can transform
>
>     <code that adds an entry to const_var_map>
> 
> into
>
>     (
>         ...
>         <code that adds an entry to const_var_map>
>         ...
>     ;
>         ...,
>         fail
>     )
> 
> where the const_var_map in the MLDS code generator records which variables'
> values are available as ground terms.
> 
> The MLDS code generator used to reset the const_var_map in its main data
> structure, the ml_gen_info, at the end of every disjunction (actually,
> at the end of every branched control structure) to the value it had
> at the start. This was intended to prevent the code following the branched
> structure from relying on const_var_map entries that were added to the
> const_var_map on *some* branches, but not others. However, in this case,
> it has the effect of forgetting the entry added by the first disjunct,
> even though
> 
> - the code after the disjunction can be reached *only* via the first disjunct,
>   and
> 
> - the code after the disjunction (legitimately, until add_trail_ops) depended
>   on that entry being available.
> 
> The fix is to allow the code after a branched control structure to depend
> on any const_var_map entry that is present in the final const_var_map
> in every branch of the branched control structure whose end is reachable.
> 
> The LLDS code generator was not affected by the bug, because it uses
> a totally separate system for keeping track of what variables' values
> are available statically. In particular, it does not rely on annotations
> left on unifications by the mark_static_term.m pass, having been written
> long before that module existed.

That's one reason the LLDS code generator is not affected; the other is
simply that it introduces trail operations directly and does not use
add_trail_ops.m.

...

> diff --git a/compiler/ml_code_gen.m b/compiler/ml_code_gen.m
> index d70c641be..7d9080d32 100644
> --- a/compiler/ml_code_gen.m
> +++ b/compiler/ml_code_gen.m
> @@ -436,17 +436,32 @@
>      ml_gen_info::in, ml_gen_info::out) is det.
>
>      % Generate code for a goal that is one branch of a branched control
> -    % structure. At the end of the branch, we need to forget what we learned
> +    % structure. At the end of the branch, we forget what we learned
>      % during the branch about which variables are bound to constants,
> -    % since those variables may not be bound to constants (at least not the
> -    % same constants) in parallel branches, or in code after the branched
> -    % control if control did not go through this branch.
> +    % in order to set up for generating code for other branches,
> +    % which should not have access to variable values bounds in earlier
> +    % branches. We do add the final const_var_map to the list of const_var_maps
> +    % if the end of the goal is actually reachable. Our callers should
> +    % thread this list through all the calls that generate code for all the
> +    % branches, and should then give the final list of const_var_maps to
> +    % ml_gen_record_consensus_const_var_map below to compute the const_var_map
> +    % that is appopriate for the program point immediately after the branched

s/appopriate/appropriate/

...


> diff --git a/library/map.m b/library/map.m
> index b5dd93d9c..955c3d4d5 100644
> --- a/library/map.m
> +++ b/library/map.m
> @@ -466,11 +466,11 @@
>
>  %---------------------%
> 
> -    % Given two maps M1 and M2, create a third map M3 that has only the
> -    % keys that occur in both M1 and M2. For keys that occur in both M1
> -    % and M2, compute the corresponding values. If they are the same,
> -    % include the key/value pair in M3. If they differ, do not include the
> -    % key in M3.
> +    % Given two maps MapA and Map3, create a third map CommonMap that

Typo: s/Map3/MapB/

> +    % has only the keys that occur in both MapA and MapB. For keys
> +    % that occur in both MapA and MapB, look up the corresponding values.
> +    % If they are the same, include the key/value pair in CommonMap.
> +    % If they differ, do not include the key in CommonMap.
>      %
>      % This predicate effectively considers the input maps to be sets of
>      % key/value pairs, computes the intersection of those two sets, and
> @@ -482,10 +482,10 @@
>      %
>  :- func common_subset(map(K, V), map(K, V)) = map(K, V).
> 
> -    % Given two maps M1 and M2, create a third map M3 that has only the
> -    % keys that occur in both M1 and M2. For keys that occur in both M1
> -    % and M2, compute the value in the final map by applying the supplied
> -    % predicate to the values associated with the key in M1 and M2.
> +    % Given two maps MapA and MapB, create a third map IntersectMap that has only the
> +    % keys that occur in both MapA and MapB. For keys that occur in both MapA
> +    % and MapB, compute the value in the final map by applying the supplied
> +    % predicate to the values associated with the key in MapA and MapB.
>      % Fail if and only if this predicate fails on the values associated
>      % with some common key.
>      %
> @@ -516,10 +516,11 @@
>
>  %---------------------%
> 
> -    % Given two maps M1 and M2, create a third map M3 that contains all
> -    % the keys that occur in either M1 and M2. For keys that occur in both M1
> -    % and M2, compute the value in the final map by applying the supplied
> -    % closure to the values associated with the key in M1 and M2.
> +    % Given two maps MapA and MapB, create a third map IntersectMap that contains all
> +    % the keys that occur in either MapA and MapB. For keys that occur in both
> +    % MapA
> +    % and MapB, compute the value in the final map by applying the supplied

Formatting.

> +    % closure to the values associated with the key in MapA and MapB.
>      % Fail if and only if this closure fails on the values associated
>      % with some common key.


More generally, I would note that there does not seem to be anything in the test
suite that exercises common_subset.

...

> diff --git a/trace/mercury_trace_cmd_browsing.c b/trace/mercury_trace_cmd_browsing.c
> index 93ab36475..5a39216a6 100644
> --- a/trace/mercury_trace_cmd_browsing.c
> +++ b/trace/mercury_trace_cmd_browsing.c
> @@ -847,6 +847,7 @@ MR_trace_cmd_dump(char **words, int word_count, MR_TraceCmdInfo *cmd,
>              const char  *name;
>
>              MR_convert_arg_to_var_spec(words[1], &var_spec);
> +            // MR_trace_parse_var_path
>              problem = MR_lookup_unambiguous_var_spec(var_spec,
>                  &type_info, &value, &name);
>              if (problem == NULL) {

Did you mean to add this?

The rest looks fine -- thanks for looking into that.

Julien.


More information about the reviews mailing list