[m-rev.] for review: dependent parallel conjunctions (1/2)

Julien Fischer juliensf at cs.mu.OZ.AU
Fri Jun 23 17:26:57 AEST 2006


On Thu, 22 Jun 2006, Peter Wang wrote:

> Estimated hours taken: 40
> Branches: main
>
> This patch adds preliminary support for deterministic, dependent
> parallel conjunctions to the low-level backend.  In other backends
> dependent parallel conjunctions are converted into plain conjunctions.
>
> For a parallel conjunction (A & B), if the goal B is dependent on a variable
> X which is bound by goal A, we transform the conjunction such that
> goal B must wait for the value to be produced by A before it begins
> executing.  This transformation is not yet useful in practice (you might as
> well use a sequential conjunction).  A later version of this transformation
> will move the synchronisation deeper into the goals so that B can execute as
> much as possible before it waits for the value from A.
>
> There is no coroutining support yet so if there are not enough threads
> available then dependent parallel conjunctions can cause the program to
> deadlock.
>
>
> configure.in:
> runtime/mercury_conf.h.in:
> 	Check for existence of semaphore.h and #define MR_HAVE_SEMAPHORE_H
> 	if it does.
>
> library/library.m:
> library/par_builtin.m:
> library/private_builtin.m:
> mdbcomp/prim_data.m:
> mdbcomp/program_representation.m:
> 	Add a new module `par_builtin' to hold synchronisation primitives.
>
> compiler/modules.m:
> 	Import `par_builtin' module in parallel grades.
>
> compiler/dep_par_conj.m:
> compiler/transform_hlds.m:
> compiler/mercury_compile.m:
> 	Add a transformation to detect dependent parallel conjunctions
> 	and insert the necessary synchronisation code.
>
> compiler/hlds_goal.m:
> 	Consider empty parallel conjunctions as atomic, the same as plain
> 	conjunctions.
>
> compiler/inlining.m:
> 	Flatten parallel conjunctions when inlining, as for plain conjunctions.
>
> compiler/live_vars.m:
> 	Fix build_live_sets_in_par_conj to handle dependent parallel
> 	conjunctions.
>
> compiler/liveness.m:
> 	Delay deaths in parallel conjunctions the same way as for plain
> 	conjunctions.
>
> 	Update detect_resume_points_in_par_conj for dependent parallel
> 	conjunctions.
>
> compiler/mode_util.m:
> compiler/modes.m:
> compiler/unique_modes.m:
> 	Update mode, uniqueness checking for dependent parallel conjunctions.

Please provide more details about how the mode checking of parallel
conjunctions has changed here.

> compiler/simplify.m:
> 	Don't reset instmaps and seen calls after each conjunct of a parallel
> 	conjunction.
>
> compiler/store_alloc.m:
> 	Update allocation for dependent parallel conjunctions.
>
> compiler/switch_detection.m:
> 	Detect switches in parallel conjunctions the same as plain
> 	conjunctions.
>
> compiler/par_conj_gen.m:
> 	Add a todo comment.
...

> Index: compiler/dep_par_conj.m
> ===================================================================
> RCS file: compiler/dep_par_conj.m
> diff -N compiler/dep_par_conj.m
> --- /dev/null	1 Jan 1970 00:00:00 -0000
> +++ compiler/dep_par_conj.m	22 Jun 2006 04:04:20 -0000
> @@ -0,0 +1,544 @@
> +%-----------------------------------------------------------------------------%
> +% vim: ft=mercury ts=8 sw=4 et
> +%-----------------------------------------------------------------------------%
> +% Copyright (C) 2005-2006 The University of Melbourne.
> +% This file may only be copied under the terms of the GNU General
> +% Public License - see the file COPYING in the Mercury distribution.
> +%-----------------------------------------------------------------------------%

2005?

> +
> +% File: dep_par_conj.m.
> +% Author: wangp.
> +

A little more description would help here, e.g.

	This module transforms the HLDS to implement dependent parallel
	conjunction.  The transformation involves adding calls to the
	predicates defined in library/par_builtin.m.

	... then describe the transformation as below

> +% For a parallel conjunction (A & B), if the goal B is dependent on a variable
> +% X which is bound by goal A, we transform the conjunction into the following:
> +%
> +%    par_builtin.new_promise(PromiseX),
> +%    (
> +%        (
> +%            A(X),  % binds X
> +%            impure par_builtin.signal(PromiseX, X)
> +%        )
> +%    &
> +%        (
> +%            par_builtin.wait(PromiseX, X1),
> +%            B(X1)  % uses X
> +%        )
> +%    )
> +%
> +% That is, goal B must wait for the value to be produced by A before it begins
> +% executing.  This transformation is not just useful in practice (you might as

Delete "just".

> +% well use a sequential conjunction).  A later version of this transformation
> +% will move signal and wait calls into goals to, hopefully, actually allow
> +% parallelism.
> +%
> +% If building in a non-parallel grade then dependent parallel conjunctions
> +% are simply converted into sequential conjunctions.
> +

There should be a todo list at the head of this module mentioning several of
the things above.

...

> +:- pred search_goal_for_par_conj(module_info::in,
> +    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
> +    instmap::in, instmap::out, hlds_goal::in, hlds_goal::out,
> +    io::di, io::uo) is det.
> +
> +search_goal_for_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap0, InstMap,
> +        Goal0, Goal, !IO) :-
> +    search_goal_for_par_conj_2(ModuleInfo, !VarSet, !VarTypes, InstMap0,
> +        Goal0, Goal, !IO),
> +    update_instmap(Goal0, InstMap0, InstMap).
> +
> +:- pred search_goal_for_par_conj_2(module_info::in,
> +    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
> +    instmap::in, hlds_goal::in, hlds_goal::out, io::di, io::uo) is det.
> +
> +search_goal_for_par_conj_2(_ModuleInfo, !VarSet, !VarTypes, _InstMap,
> +        G @ (Goal - _), G, !IO) :-
> +    Goal = unify(_, _, _, _Kind, _).
> +search_goal_for_par_conj_2(_ModuleInfo, !VarSet, !VarTypes, _InstMap,
> +        G @ (Goal - _), G, !IO) :-
> +    Goal = call(_CallPredId, _CallProcId, _CallArgs, _, _, _).
> +search_goal_for_par_conj_2(_ModuleInfo, !VarSet, !VarTypes, _InstMap,
> +        G @ (Goal - _), G, !IO) :-
> +    Goal = generic_call(_Details, _Args, _ArgModes, _).
> +search_goal_for_par_conj_2(ModuleInfo, !VarSet, !VarTypes, InstMap,
> +        not(Goal0) - GI, not(Goal) - GI, !IO) :-
> +    search_goal_for_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap, _,
> +        Goal0, Goal, !IO).
> +search_goal_for_par_conj_2(ModuleInfo, !VarSet, !VarTypes, InstMap,
> +        Goal0 - GI, Goal - GI, !IO) :-
> +    Goal0 = scope(Reason, ScopeGoal0),
> +    search_goal_for_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap, _,
> +        ScopeGoal0, ScopeGoal, !IO),
> +    Goal = scope(Reason, ScopeGoal).
> +search_goal_for_par_conj_2(_ModuleInfo, !VarSet, !VarTypes, _InstMap,
> +        G @ (Goal - _), G, !IO) :-
> +    Goal = foreign_proc(_Attributes, _, _, _, _, _).
> +search_goal_for_par_conj_2(_, _,_, _,_, _, shorthand(_) - _, _, _,_) :-
> +    unexpected(this_file,
> +        "shorthand goal encountered during dependent parallel " ++
> +        "conjunction transformation.").
> +search_goal_for_par_conj_2(ModuleInfo, !VarSet, !VarTypes, InstMap,
> +        Goal0 - GI, Goal - GI, !IO) :-
> +    Goal0 = switch(Var, CanFail, Cases0),
> +    search_cases_for_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap,
> +        Cases0, Cases, !IO),
> +    Goal = switch(Var, CanFail, Cases).
> +search_goal_for_par_conj_2(ModuleInfo, !VarSet, !VarTypes, InstMap0,
> +        Goal0 - GI, Goal - GI, !IO) :-
> +    Goal0 = if_then_else(Quant, If0, Then0, Else0),
> +    search_goal_for_par_conj(ModuleInfo, !VarSet, !VarTypes,
> +        InstMap0, InstMap1, If0, If, !IO),
> +    search_goal_for_par_conj(ModuleInfo, !VarSet, !VarTypes,
> +        InstMap1, _InstMap2, Then0, Then, !IO),
> +    search_goal_for_par_conj(ModuleInfo, !VarSet, !VarTypes,
> +        InstMap0, _InstMap3, Else0, Else, !IO),
> +    Goal = if_then_else(Quant, If, Then, Else).
> +search_goal_for_par_conj_2(ModuleInfo, !VarSet, !VarTypes, InstMap,
> +        Goal0 - GI, Goal - GI, !IO) :-
> +    Goal0 = disj(Goals0),
> +    search_goals_for_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap,
> +        Goals0, Goals, !IO),
> +    Goal = disj(Goals).
> +search_goal_for_par_conj_2(ModuleInfo, !VarSet, !VarTypes, InstMap,
> +        Goal0 - GI, Goal, !IO) :-
> +    Goal0 = conj(ConjType, Goals0),
> +    (
> +        ConjType = plain_conj,
> +        search_goals_for_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap,
> +            Goals0, Goals, !IO),
> +        conj_list_to_goal(Goals, GI, Goal)
> +    ;
> +	ConjType = parallel_conj,
> +	munge_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap,
> +            Goals0, GI, Goal, !IO)

That needs to be indented another level.

...

> +    % We found a parallel conjunction.  We have to check if there are
> +    % dependencies between the conjuncts and insert the synchronisation.
> +    %

How about:

	% We have found a parllel conjunction.  We need to check there
	% any dependencies between the conjuncts and, if so, insert
	% sychronisation primitives.

> +:- pred munge_par_conj(module_info::in, prog_varset::in, prog_varset::out,
> +    vartypes::in, vartypes::out, instmap::in,
> +    hlds_goals::in, hlds_goal_info::in, hlds_goal::out, io::di, io::uo) is det.
> +

I suggest calling that maybe_transform_par_conj, rather than munge_par_conj.

> +munge_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap,
> +        Conjuncts0, GoalInfo, NewGoal, !IO) :-
> +    % Search subgoals for nested parallel conjunctions.
> +    search_goals_for_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap,
> +        Conjuncts0, Conjuncts, !IO),
> +
> +    % Find the variables that are shared between conjunctions.

s/conjunctions/conjuncts/

> +    find_shared_variables(ModuleInfo, InstMap, Conjuncts, SharedVars),
> +
> +    % Dependent parallel conjunctions only supported on lowlevel C parallel
> +    % grades.  For other grades convert any dependent parallel conjunctions
> +    % into plain conjunctions.
> +    globals.io_get_target(Target, !IO),
> +    globals.io_lookup_bool_option(highlevel_code, HighLevelCode, !IO),
> +    globals.io_lookup_bool_option(parallel, Parallel, !IO),
> +    (if
> +        set.non_empty(SharedVars),
> +        Target = target_c,
> +        HighLevelCode = no,
> +        Parallel = yes
> +    then
> +        transform_conjunction(ModuleInfo, SharedVars,
> +            Conjuncts, GoalInfo, NewGoal, InstMap, !VarSet, !VarTypes)
> +    else
> +        conj_list_to_goal(Conjuncts, GoalInfo, NewGoal)
> +    ).
> +
> +    % Transforming the parallel conjunction.
> +    %
> +    % As a simple first step, all we do is insert waits and signals directly
> +    % into the conjunction.  If a conjunct produces a shared variable we turn
> +    % that conjunct into a sequential conjunction:
> +    %
> +    %   prod(Y)  ==>  ( prod(Y), impure signal(PrY, Y) )
> +    %
> +    % If the conjunct consumes a shared variable we will turn that conjunct
> +    % into a sequential conjunction:
> +    %
> +    %   consume(Y)  ==>  ( wait(PrY, Y), consume(Y) )
> +    %

I think it would be worth documenting the transformtion for an actual
conjunction as well as specifying the transformation for individual conjuncts.

> +    % References to shared variables need to be renamed apart so that the
> +    % conjuncts only share promises.
> +    %
> +:- pred transform_conjunction(module_info::in, set(prog_var)::in,
> +    hlds_goals::in, hlds_goal_info::in, hlds_goal::out, instmap::in,
> +    prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
> +
> +transform_conjunction(ModuleInfo, SharedVars, Goals, GoalInfo, NewGoal,
> +        InstMap, !VarSet, !VarTypes) :-
> +    allocate_promises(ModuleInfo, SharedVars, !VarTypes, !VarSet,
> +        AllocatePromises, PromiseMap),
> +    list.map_foldl3(transform_conjunct(ModuleInfo, SharedVars, PromiseMap),
> +        Goals, NewGoals, InstMap, _, !VarSet, !VarTypes),
> +    % XXX not sure about GoalInfo

What are you not sure about the GoalInfo?

> +    Conj = AllocatePromises ++ [conj(parallel_conj, NewGoals) - GoalInfo],
> +    conj_list_to_goal(Conj, GoalInfo, NewGoal).
> +
> +:- pred transform_conjunct(module_info::in, set(prog_var)::in,
> +    promise_map::in, hlds_goal::in, hlds_goal::out,
> +    instmap::in, instmap::out, prog_varset::in, prog_varset::out,
> +    vartypes::in, vartypes::out) is det.
> +
> +transform_conjunct(ModuleInfo, SharedVars, PromiseMap, Goal0, Goal,
> +        !InstMap, !VarSet, !VarTypes) :-
> +    goal_get_nonlocals(Goal0, Nonlocals),
> +    set.intersect(Nonlocals, SharedVars, Intersect),
> +    (if set.empty(Intersect) then
> +        Goal = Goal0,
> +        update_instmap(Goal, !InstMap)
> +    else
> +        Goal0 = (_ - GoalInfo0),
> +        goal_info_get_instmap_delta(GoalInfo0, InstMapDelta0),
> +
> +        % Divide shared variables into those that are produced by this
> +        % conjunction, and those that are consumed.
> +        set.divide(produced_variable(ModuleInfo, !.InstMap, InstMapDelta0),
> +            Intersect, ProducedVars, ConsumedVars),
> +
> +        % Rename references to consumed variables.  We let the producer keep
> +        % the original name.  This helps because there may be references to
> +        % the original name following the parallel conjunction.

That last bit should be something like:

	We let the producer keep the original name in order to avoid having
	to rename references to the original name following the parallel
	conjunction.

...

> +    % If a variable is nonlocal to a conjunct, and appears in the
> +    % instmap_delta of a _different_ conjunct, then we say that variable is
> +    % shared.
> +    %
> +    % (1) A variable must be nonlocal to a conjunct if it is shared.
> +    % (2) If the variable does not appear in the instmap_delta
> +    %     of any of the conjuncts of the parallel conjunction
> +    %     then it could not have been further instantiated within
> +    %     by the conjunction as a whole.
> +    %
> +    % XXX this code is probably too complicated.  I think Thomas already had a
> +    % more elegant way to find the shared variables somewhere, using multisets.
> +    %
> +:- pred find_shared_variables(module_info::in, instmap::in, hlds_goals::in,
> +    set(prog_var)::out) is det.
> +
> +find_shared_variables(ModuleInfo, InstMap, Goals, SharedVars) :-
> +    list.map2(get_nonlocals_and_instmaps, Goals, Nonlocals, InstMapDeltas),
> +    find_shared_variables_2(ModuleInfo, 0, Nonlocals, InstMap, InstMapDeltas,
> +        set.init, SharedVars).
> +
> +:- pred get_nonlocals_and_instmaps(hlds_goal::in,
> +    set(prog_var)::out, instmap_delta::out) is det.
> +
> +get_nonlocals_and_instmaps(_Goal - GoalInfo, Nonlocals, InstMapDelta) :-
> +    goal_info_get_nonlocals(GoalInfo, Nonlocals),
> +    goal_info_get_instmap_delta(GoalInfo, InstMapDelta).
> +
> +:- pred find_shared_variables_2(module_info::in, int::in,
> +    list(set(prog_var))::in, instmap::in, list(instmap_delta)::in,
> +    set(prog_var)::in, set(prog_var)::out) is det.
> +
> +find_shared_variables_2(_ModuleInfo, _ConjunctIndex,
> +        [], _InstMap, _InstMapDeltas, !SharedVars).
> +find_shared_variables_2(ModuleInfo, ConjunctIndex,
> +        [Nonlocals | MoreNonlocals], InstMap, InstMapDeltas, !SharedVars) :-
> +    det_delete_nth(ConjunctIndex, InstMapDeltas, InstMapDeltasB),
> +    % Keep only nonlocals which were not already bound at the start of the
> +    % parallel conjunction.
> +    Filter = (pred(Var::in) is semidet :-
> +        not (
> +            instmap.lookup_var(InstMap, Var, VarInst),
> +            inst_is_bound(ModuleInfo, VarInst)
> +        )
> +    ),
> +    set.filter(Filter, Nonlocals) = UnboundNonlocals,
> +    set.fold(find_changed_vars(ModuleInfo, InstMapDeltasB),
> +        UnboundNonlocals, !SharedVars),
> +    find_shared_variables_2(ModuleInfo, ConjunctIndex+1, MoreNonlocals,
> +        InstMap, InstMapDeltas, !SharedVars).
> +
> +:- pred find_changed_vars(module_info::in, list(instmap_delta)::in,
> +    prog_var::in, set(prog_var)::in, set(prog_var)::out) is det.
> +
> +find_changed_vars(ModuleInfo, InstMapDeltas, UnboundVar, !SharedVars) :-
> +    (if
> +        % Is the unbound nonlocal bound in one of the conjuncts?
> +        InstMapDelta `member` InstMapDeltas,


s/member/list.member/
(There may be ambiguity problems building the compiler with
--intermodule-optization otherwise.)

> +        instmap_delta_search_var(InstMapDelta, UnboundVar, Inst),
> +        inst_is_bound(ModuleInfo, Inst)
> +    then
> +        svset.insert(UnboundVar, !SharedVars)
> +    else
> +        true
> +    ).
> +
> +%-----------------------------------------------------------------------------%
> +
> +:- type promise_map == map(prog_var, prog_var).

What does this type do?  Please add a comment.

> +    % Make goals to allocate promise objects for variables shared
> +    % between two parallel conjuncts (a producer and one or more consumers).
> +    %
> +:- pred allocate_promises(module_info::in, set(prog_var)::in,
> +    vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
> +    hlds_goals::out, promise_map::out) is det.
> +
> +allocate_promises(ModuleInfo, SharedVars, !VarTypes, !VarSet,
> +        AllocGoals, PromiseMap) :-
> +    set.fold4(allocate_promise(ModuleInfo), SharedVars,
> +        !VarTypes, !VarSet, [], AllocGoals, map.init, PromiseMap).
> +
> +:- pred allocate_promise(module_info::in, prog_var::in,
> +    vartypes::in, vartypes::out, prog_varset::in, prog_varset::out,
> +    hlds_goals::in, hlds_goals::out, promise_map::in, promise_map::out) is det.
> +
> +allocate_promise(ModuleInfo, SharedVar, !VarTypes, !VarSet,
> +        !AllocGoals, !PromiseMap) :-
> +    map.lookup(!.VarTypes, SharedVar, SharedVarType),
> +    make_promise(ModuleInfo, SharedVarType, SharedVar, !VarTypes, !VarSet,
> +        AllocGoal, PromiseVar),
> +    list.cons(AllocGoal, !AllocGoals),
> +    svmap.det_insert(SharedVar, PromiseVar, !PromiseMap).
> +
> +:- pred make_promise(module_info::in, mer_type::in, prog_var::in, vartypes::in,
> +    vartypes::out, prog_varset::in, prog_varset::out, hlds_goal::out,
> +    prog_var::out) is det.
> +
> +make_promise(ModuleInfo, SharedVarType, SharedVar, !VarTypes, !VarSet,
> +        AllocGoal, PromiseVar) :-
> +    construct_promise_type(SharedVarType, PromiseType),
> +    varset.lookup_name(!.VarSet, SharedVar, SharedVarName),
> +    svvarset.new_named_var("Promise" ++ SharedVarName, PromiseVar, !VarSet),
> +    svmap.det_insert(PromiseVar, PromiseType, !VarTypes),
> +
> +    ModuleName = mercury_par_builtin_module,
> +    PredName = "new_promise",
> +    Args = [PromiseVar],
> +    Features = [],
> +    InstMapSrc = [PromiseVar - ground(shared, none)],
> +    Context = term.context_init,
> +    goal_util.generate_simple_call(ModuleName, PredName, predicate,
> +        only_mode, det, Args, Features, InstMapSrc, ModuleInfo,
> +        Context, AllocGoal).
> +
> +    % Construct type promise(T) given type T.
> +    %

In par_builtin the type is called prom(T) so fix the above comment.

> +:- pred construct_promise_type(mer_type::in, mer_type::out) is det.
> +
> +construct_promise_type(T, PromiseT) :-
> +    Prom = qualified(mercury_private_builtin_module, "prom"),
> +    PromiseCtor = type_ctor(Prom, 1),
> +    construct_type(PromiseCtor, [T], PromiseT).
> +
> +%-----------------------------------------------------------------------------%
> +
> +:- pred det_delete_nth(int::in, list(T)::in, list(T)::out) is det.
> +
> +det_delete_nth(N, List0, List) :-
> +    list.det_split_list(N, List0, Left, Right),
> +    List = Left ++ det_tail(Right).

Perhaps one for the standard library?

...

> Index: compiler/mercury_compile.m
> ===================================================================
> RCS file: /home/mercury1/repository/mercury/compiler/mercury_compile.m,v
> retrieving revision 1.391
> diff -u -r1.391 mercury_compile.m
> --- compiler/mercury_compile.m	14 Jun 2006 08:14:49 -0000	1.391
> +++ compiler/mercury_compile.m	21 Jun 2006 07:04:21 -0000
> @@ -94,6 +94,7 @@
>  :- import_module transform_hlds.ctgc.structure_reuse.analysis.
>  :- import_module transform_hlds.ctgc.structure_sharing.
>  :- import_module transform_hlds.ctgc.structure_sharing.analysis.
> +:- import_module transform_hlds.dep_par_conj.
>  :- import_module transform_hlds.size_prof.
>  :- import_module ll_backend.deep_profiling.
>
> @@ -2431,6 +2432,9 @@
>
>      maybe_structure_reuse_analysis(Verbose, Stats, !HLDS, !IO),
>      maybe_dump_hlds(!.HLDS, 212, "structure_reuse", !DumpInfo, !IO),
> +
> +    maybe_dependent_par_conj(Verbose, Stats, !HLDS, !IO),
> +    maybe_dump_hlds(!.HLDS, 214, "dependent_par_conj", !DumpInfo, !IO),

Is this the right spot for this?  Can it be performed any earlier or must it
be done here?

(Note: this occurs well after inlining so none of the calls to the service
predicates in par_builtin will be inlined.  At this stage I don't think it's
important, but you add a comment at the top of dep_par_conj.m that it should
be looked at again in the future.)

...

> @@ -1286,43 +1286,16 @@
>              Goal = conj(plain_conj, [])
>          ;
>              Goals0 = [_ | _],
> -            modecheck_conj_list(Goals0, Goals, !ModeInfo, !IO),
> +            modecheck_conj_list(ConjType, Goals0, Goals, !ModeInfo, !IO),
>              conj_list_to_goal(Goals, GoalInfo0, Goal - _GoalInfo)
>          ),
>          mode_checkpoint(exit, "conj", !ModeInfo, !IO)
>      ;
>          ConjType = parallel_conj,
> -        % To modecheck a parallel conjunction, we modecheck each
> -        % conjunct independently (just like for disjunctions).
> -        % To make sure that we don't try to bind a variable more than
> -        % once (by binding it in more than one conjunct), we maintain a
> -        % datastructure that keeps track of three things:
> -        %
> -        % - the set of variables that are nonlocal to the conjuncts
> -        %   (which may be a superset of the nonlocals of the par_conj
> -        %   as a whole);
> -        % - the set of nonlocal variables that have been bound in the
> -        %   current conjunct; and
> -        % - the set of variables that were bound in previous conjuncts.
> -        %
> -        % When binding a variable, we check that it wasn't in the set of
> -        % variables bound in other conjuncts, and we add it to the set of
> -        % variables bound in this conjunct.
> -        %
> -        % At the end of the conjunct, we add the set of variables bound in
> -        % this conjunct to the set of variables bound in previous conjuncts
> -        % and set the set of variables bound in the current conjunct to
> -        % empty.
> -        %
> -        % A stack of these structures is maintained to handle nested parallel
> -        % conjunctions properly.
> -        %
>          mode_checkpoint(enter, "par_conj", !ModeInfo, !IO),
> -        goal_info_get_nonlocals(GoalInfo0, NonLocals),
> -        modecheck_par_conj_list(Goals0, Goals, NonLocals, InstMapNonlocalList,
> -            !ModeInfo, !IO),
> -        Goal = conj(parallel_conj, Goals),
> -        instmap_unify(NonLocals, InstMapNonlocalList, !ModeInfo),
> +        % empty parallel conjunction should not be a common case

Sentences begin with a capital letter and end with a full stop.

> +        modecheck_conj_list(ConjType, Goals0, Goals, !ModeInfo, !IO),
> +        par_conj_list_to_goal(Goals, GoalInfo0, Goal - _GoalInfo),
>          mode_checkpoint(exit, "par_conj", !ModeInfo, !IO)
>      ).
>
> @@ -1750,7 +1723,7 @@
>          % is not, the main unification will be delayed until after the
>          % argument unifications, which turns them into assignments,
>          % and we end up repeating the process forever.
> -        mode_info_add_goals_live_vars(GoalList0, !ModeInfo),
> +        mode_info_add_goals_live_vars(plain_conj, GoalList0, !ModeInfo),
>          modecheck_conj_list_no_delay(GoalList0, GoalList, !ModeInfo, !IO),
>          Goal = conj(plain_conj, GoalList),
>          mode_info_set_checking_extra_goals(no, !ModeInfo),

...

>  :- type impurity_errors == list(mode_error_info).
>
> -    % Flatten conjunctions as we go.  Call modecheck_conj_list_3 to do
> -    % the actual scheduling.
> +    % Flatten conjunctions as we go, as long as they are of the same type).

There's an unmatched parenthesis in that comment.

...

> Index: compiler/modules.m
> ===================================================================
> RCS file: /home/mercury1/repository/mercury/compiler/modules.m,v
> retrieving revision 1.394
> diff -u -r1.394 modules.m
> --- compiler/modules.m	15 Jun 2006 19:37:05 -0000	1.394
> +++ compiler/modules.m	21 Jun 2006 06:35:35 -0000
> @@ -2754,6 +2754,7 @@
>      mercury_table_builtin_module(MercuryTableBuiltin),
>      mercury_profiling_builtin_module(MercuryProfilingBuiltin),
>      mercury_term_size_prof_builtin_module(MercuryTermSizeProfBuiltin),
> +    mercury_par_builtin_module(MercuryParBuiltin),
>      !:ImportDeps = [MercuryPublicBuiltin | !.ImportDeps],
>      !:UseDeps = [MercuryPrivateBuiltin | !.UseDeps],
>      (
> @@ -2793,6 +2794,13 @@
>          !:UseDeps = [MercuryTermSizeProfBuiltin | !.UseDeps]
>      ;
>          true
> +    ),
> +    globals.lookup_bool_option(Globals, parallel, Parallel),
> +    (
> +        Parallel = yes,
> +        !:UseDeps = [MercuryParBuiltin | !.UseDeps]
> +    ;
> +        Parallel = no
>      ).

Won't that also implicitly import the par_builtin module in the high-level
parallel grades?  (I thought that par_builtin was only needed by the
low-level grades.)

Julien.
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list