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

Peter Wang wangp at students.cs.mu.OZ.AU
Sun Jun 25 13:59:00 AEST 2006


On 2006-06-23, Julien Fischer <juliensf at cs.mu.OZ.AU> wrote:
> >
> > 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.

Ok.

> > +    % 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.

Not sure what you mean.

> > +    % 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?

Looking at it again it does seem ok, but I'm never sure about GoalInfos.

> > +:- 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.)

That's not too good.  I've changed it.

> > +    % Construct type promise(T) given type T.
> > +    %
> 
> In par_builtin the type is called prom(T) so fix the above comment.

Regarding the other message, 'future' is an alternative to 'promise'
so I'm going with that.

> > +:- 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?

Maybe later.

> > @@ -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.)

I'm not sure where it should be.  Zoltan suggested I put it fairly late.
But it's true that the primitives really should be inlined.

> > @@ -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.)

Yes.  In the future the module might be useful for other parallel
grades, but I've made it only import in low-level grades for now.

Interdiff follows.

Peter

--- dep_par.0.txt       2006-06-23 19:49:30.000000000 +1000
+++ dep_par.txt 2006-06-24 20:25:34.946507482 +1000
@@ -58,9 +58,14 @@
        conjunctions.

 compiler/mode_util.m:
+       Treat parallel and plain conjunctions equally when recomputing instmap
+       deltas.
+
 compiler/modes.m:
 compiler/unique_modes.m:
-       Update mode, uniqueness checking for dependent parallel conjunctions.
+       Treat parallel and plain conjunctions equally when checking modes and
+       uniqueness.  However, don't flatten parallel conjunctions into plain
+       conjunctions and vice versa.

 compiler/simplify.m:
        Don't reset instmaps and seen calls after each conjunct of a parallel


diff -u compiler/dep_par_conj.m compiler/dep_par_conj.m
--- compiler/dep_par_conj.m	22 Jun 2006 04:04:20 -0000
+++ compiler/dep_par_conj.m	25 Jun 2006 03:53:06 -0000
@@ -1,7 +1,7 @@
 %-----------------------------------------------------------------------------%
 % vim: ft=mercury ts=8 sw=4 et
 %-----------------------------------------------------------------------------%
-% Copyright (C) 2005-2006 The University of Melbourne.
+% Copyright (C) 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.
 %-----------------------------------------------------------------------------%
@@ -9,30 +9,40 @@
 % File: dep_par_conj.m.
 % Author: wangp.
 
+% This module transforms the HLDS to implement dependent parallel conjunction.
+% The transformation involves adding calls to the predicates defined in
+% library/par_builtin.m.
+% 
 % 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),
+%    par_builtin.new_future(FutureX),
 %    (
 %        (
 %            A(X),  % binds X
-%            impure par_builtin.signal(PromiseX, X)
+%            impure par_builtin.signal(FutureX, X)
 %        )
 %    &
 %        (
-%            par_builtin.wait(PromiseX, X1),
+%            par_builtin.wait(FutureX, 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
+% 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 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.
+%
+% TODO:
+% - move signal and wait calls into goals
+% - only run this pass if parallel conjunctions are present in a module
+% - reconsider when this pass is run; in particular par_builtin primitives
+%   ought to be inlined
 
 %-----------------------------------------------------------------------------%
 
@@ -204,8 +214,8 @@
             Goals0, Goals, !IO),
         conj_list_to_goal(Goals, GI, Goal)
     ;
-	ConjType = parallel_conj,
-	munge_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap,
+        ConjType = parallel_conj,
+        maybe_transform_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap,
             Goals0, GI, Goal, !IO)
     ).
 
@@ -239,38 +249,44 @@
 
 %-----------------------------------------------------------------------------%
 
-    % We found a parallel conjunction.  We have to check if there are
-    % dependencies between the conjuncts and insert the synchronisation.
+    % We found a parallel 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,
+:- pred maybe_transform_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.
 
-munge_par_conj(ModuleInfo, !VarSet, !VarTypes, InstMap,
+maybe_transform_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.
+    % Find the variables that are shared between 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),
+    % into plain conjunctions. Independent parallel conjunctions can be left
+    % as-is.
     (if
-        set.non_empty(SharedVars),
-        Target = target_c,
-        HighLevelCode = no,
-        Parallel = yes
+        set.empty(SharedVars)
     then
-        transform_conjunction(ModuleInfo, SharedVars,
-            Conjuncts, GoalInfo, NewGoal, InstMap, !VarSet, !VarTypes)
+        par_conj_list_to_goal(Conjuncts, GoalInfo, NewGoal)
     else
-        conj_list_to_goal(Conjuncts, GoalInfo, NewGoal)
+        globals.io_get_target(Target, !IO),
+        globals.io_lookup_bool_option(highlevel_code, HighLevelCode, !IO),
+        globals.io_lookup_bool_option(parallel, Parallel, !IO),
+        (if
+            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.
@@ -287,7 +303,7 @@
     %   consume(Y)  ==>  ( wait(PrY, Y), consume(Y) )
     %
     % References to shared variables need to be renamed apart so that the
-    % conjuncts only share promises.
+    % conjuncts only share futures.
     %
 :- pred transform_conjunction(module_info::in, set(prog_var)::in,
     hlds_goals::in, hlds_goal_info::in, hlds_goal::out, instmap::in,
@@ -295,20 +311,19 @@
 
 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),
+    allocate_futures(ModuleInfo, SharedVars, !VarTypes, !VarSet,
+        AllocateFutures, FutureMap),
+    list.map_foldl3(transform_conjunct(ModuleInfo, SharedVars, FutureMap),
         Goals, NewGoals, InstMap, _, !VarSet, !VarTypes),
-    % XXX not sure about GoalInfo
-    Conj = AllocatePromises ++ [conj(parallel_conj, NewGoals) - GoalInfo],
+    Conj = AllocateFutures ++ [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,
+    future_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,
+transform_conjunct(ModuleInfo, SharedVars, FutureMap, Goal0, Goal,
         !InstMap, !VarSet, !VarTypes) :-
     goal_get_nonlocals(Goal0, Nonlocals),
     set.intersect(Nonlocals, SharedVars, Intersect),
@@ -325,7 +340,7 @@
             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 in order to avoid having to rename references to
         % the original name following the parallel conjunction.
         create_variables(set.to_sorted_list(ConsumedVars),
             !.VarSet, !.VarTypes,
@@ -333,9 +348,9 @@
         rename_vars_in_goal(Renaming, Goal0, Goal1),
 
         % Make wait and signal goals.
-        list.map(make_wait(ModuleInfo, PromiseMap, Renaming),
+        list.map(make_wait(ModuleInfo, FutureMap, Renaming),
             set.to_sorted_list(ConsumedVars), WaitGoals),
-        list.map(make_signal(ModuleInfo, PromiseMap),
+        list.map(make_signal(ModuleInfo, FutureMap),
             set.to_sorted_list(ProducedVars), SignalGoals),
 
         % Insert signal goals after the conjunct and waits before the conjunct.
@@ -350,18 +365,18 @@
         update_instmap(Goal0, !InstMap)
     ).
 
-    % Make a goal to wait on a promise for a consumed variable to be produced.
+    % Make a goal to wait on a future for a consumed variable to be produced.
     %
-:- pred make_wait(module_info::in, promise_map::in,
+:- pred make_wait(module_info::in, future_map::in,
     prog_var_renaming::in, prog_var::in, hlds_goal::out) is det.
 
-make_wait(ModuleInfo, PromiseMap, Renaming, ConsumedVar, WaitGoal) :-
-    map.lookup(PromiseMap, ConsumedVar, PromiseVar),
+make_wait(ModuleInfo, FutureMap, Renaming, ConsumedVar, WaitGoal) :-
+    map.lookup(FutureMap, ConsumedVar, FutureVar),
     map.lookup(Renaming, ConsumedVar, WaitVar),
 
     ModuleName = mercury_par_builtin_module,
     PredName = "wait",
-    Args = [PromiseVar, WaitVar],
+    Args = [FutureVar, WaitVar],
     Features = [],
     InstMapSrc = [WaitVar - ground(shared, none)],
     Context = term.context_init,
@@ -371,15 +386,15 @@
 
     % Make a goal to signal that a variable is produced.
     %
-:- pred make_signal(module_info::in, promise_map::in,
+:- pred make_signal(module_info::in, future_map::in,
     prog_var::in, hlds_goal::out) is det.
 
-make_signal(ModuleInfo, PromiseMap, ProducedVar, SignalGoal) :-
-    map.lookup(PromiseMap, ProducedVar, PromiseVar),
+make_signal(ModuleInfo, FutureMap, ProducedVar, SignalGoal) :-
+    map.lookup(FutureMap, ProducedVar, FutureVar),
 
     ModuleName = mercury_par_builtin_module,
     PredName = "signal",
-    Args = [PromiseVar, ProducedVar],
+    Args = [FutureVar, ProducedVar],
     Features = [],
     InstMapSrc = [],
     Context = term.context_init,
@@ -458,7 +473,7 @@
 find_changed_vars(ModuleInfo, InstMapDeltas, UnboundVar, !SharedVars) :-
     (if
         % Is the unbound nonlocal bound in one of the conjuncts?
-        InstMapDelta `member` InstMapDeltas,
+        InstMapDelta `list.member` InstMapDeltas,
         instmap_delta_search_var(InstMapDelta, UnboundVar, Inst),
         inst_is_bound(ModuleInfo, Inst)
     then
@@ -469,61 +484,65 @@
 
 %-----------------------------------------------------------------------------%
 
-:- type promise_map == map(prog_var, prog_var).
+    % A map from a variable to the future object created for that variable.
+    % i.e. for variable X with future F, when X is bound to a value then F is
+    % signalled.  A consumer of X waits (blocks) on F until that happens.
+    %
+:- type future_map == map(prog_var, prog_var).
 
-    % Make goals to allocate promise objects for variables shared
+    % Make goals to allocate future 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,
+:- pred allocate_futures(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.
+    hlds_goals::out, future_map::out) is det.
 
-allocate_promises(ModuleInfo, SharedVars, !VarTypes, !VarSet,
-        AllocGoals, PromiseMap) :-
-    set.fold4(allocate_promise(ModuleInfo), SharedVars,
-        !VarTypes, !VarSet, [], AllocGoals, map.init, PromiseMap).
+allocate_futures(ModuleInfo, SharedVars, !VarTypes, !VarSet,
+        AllocGoals, FutureMap) :-
+    set.fold4(allocate_future(ModuleInfo), SharedVars,
+        !VarTypes, !VarSet, [], AllocGoals, map.init, FutureMap).
 
-:- pred allocate_promise(module_info::in, prog_var::in,
+:- pred allocate_future(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.
+    hlds_goals::in, hlds_goals::out, future_map::in, future_map::out) is det.
 
-allocate_promise(ModuleInfo, SharedVar, !VarTypes, !VarSet,
-        !AllocGoals, !PromiseMap) :-
+allocate_future(ModuleInfo, SharedVar, !VarTypes, !VarSet,
+        !AllocGoals, !FutureMap) :-
     map.lookup(!.VarTypes, SharedVar, SharedVarType),
-    make_promise(ModuleInfo, SharedVarType, SharedVar, !VarTypes, !VarSet,
-        AllocGoal, PromiseVar),
+    make_future(ModuleInfo, SharedVarType, SharedVar, !VarTypes, !VarSet,
+        AllocGoal, FutureVar),
     list.cons(AllocGoal, !AllocGoals),
-    svmap.det_insert(SharedVar, PromiseVar, !PromiseMap).
+    svmap.det_insert(SharedVar, FutureVar, !FutureMap).
 
-:- pred make_promise(module_info::in, mer_type::in, prog_var::in, vartypes::in,
+:- pred make_future(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),
+make_future(ModuleInfo, SharedVarType, SharedVar, !VarTypes, !VarSet,
+        AllocGoal, FutureVar) :-
+    construct_future_type(SharedVarType, FutureType),
     varset.lookup_name(!.VarSet, SharedVar, SharedVarName),
-    svvarset.new_named_var("Promise" ++ SharedVarName, PromiseVar, !VarSet),
-    svmap.det_insert(PromiseVar, PromiseType, !VarTypes),
+    svvarset.new_named_var("Future" ++ SharedVarName, FutureVar, !VarSet),
+    svmap.det_insert(FutureVar, FutureType, !VarTypes),
 
     ModuleName = mercury_par_builtin_module,
-    PredName = "new_promise",
-    Args = [PromiseVar],
+    PredName = "new_future",
+    Args = [FutureVar],
     Features = [],
-    InstMapSrc = [PromiseVar - ground(shared, none)],
+    InstMapSrc = [FutureVar - 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.
+    % Construct type future(T) given type T.
     %
-:- pred construct_promise_type(mer_type::in, mer_type::out) is det.
+:- pred construct_future_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).
+construct_future_type(T, FutureT) :-
+    Future = qualified(mercury_par_builtin_module, "future"),
+    FutureCtor = type_ctor(Future, 1),
+    construct_type(FutureCtor, [T], FutureT).
 
 %-----------------------------------------------------------------------------%
 
diff -u compiler/mode_util.m compiler/mode_util.m
--- compiler/mode_util.m	18 Jun 2006 08:19:48 -0000
+++ compiler/mode_util.m	23 Jun 2006 13:15:30 -0000
@@ -1008,18 +1008,10 @@
             VarTypes, InstMap, NonLocals, InstMapDelta, !RI)
     ).
 
-recompute_instmap_delta_2(Atomic, conj(ConjType, Goals0), GoalInfo,
+recompute_instmap_delta_2(Atomic, conj(ConjType, Goals0), _GoalInfo,
         conj(ConjType, Goals), VarTypes, InstMap, InstMapDelta, !RI) :-
-    (
-        ConjType = plain_conj,
-        recompute_instmap_delta_conj(Atomic, Goals0, Goals,
-            VarTypes, InstMap, InstMapDelta, !RI)
-    ;
-        ConjType = parallel_conj,
-        goal_info_get_nonlocals(GoalInfo, NonLocals),
-        recompute_instmap_delta_par_conj(Atomic, Goals0, Goals,
-            VarTypes, InstMap, NonLocals, InstMapDelta, !RI)
-    ).
+    recompute_instmap_delta_conj(Atomic, Goals0, Goals,
+        VarTypes, InstMap, InstMapDelta, !RI).
 
 recompute_instmap_delta_2(Atomic, disj(Goals0), GoalInfo, disj(Goals),
         VarTypes, InstMap, InstMapDelta, !RI) :-
@@ -1145,29 +1137,6 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred recompute_instmap_delta_par_conj(bool::in, list(hlds_goal)::in,
-    list(hlds_goal)::out, vartypes::in, instmap::in, set(prog_var)::in,
-    instmap_delta::out, recompute_info::in, recompute_info::out) is det.
-
-recompute_instmap_delta_par_conj(_, [], [], _, _, _, InstMapDelta, !RI) :-
-    instmap_delta_init_unreachable(InstMapDelta).
-recompute_instmap_delta_par_conj(Atomic, [Goal0], [Goal],
-        VarTypes, InstMap, _, InstMapDelta, !RI) :-
-    recompute_instmap_delta_1(Atomic, Goal0, Goal, VarTypes, InstMap,
-        InstMapDelta, !RI).
-recompute_instmap_delta_par_conj(Atomic, [Goal0 | Goals0], [Goal | Goals],
-        VarTypes, InstMap0, NonLocals, InstMapDelta, !RI) :-
-    Goals0 = [_ | _],
-    recompute_instmap_delta_1(Atomic, Goal0, Goal,
-        VarTypes, InstMap0, InstMapDelta0, !RI),
-    instmap.apply_instmap_delta(InstMap0, InstMapDelta0, InstMap1),
-    recompute_instmap_delta_par_conj(Atomic, Goals0, Goals,
-        VarTypes, InstMap1, NonLocals, InstMapDelta1, !RI),
-    instmap_delta_apply_instmap_delta(InstMapDelta0, InstMapDelta1,
-        large_overlay, InstMapDelta).
-
-%-----------------------------------------------------------------------------%
-
 :- pred recompute_instmap_delta_disj(bool::in, list(hlds_goal)::in,
     list(hlds_goal)::out, vartypes::in, instmap::in, set(prog_var)::in,
     instmap_delta::out, recompute_info::in, recompute_info::out) is det.
diff -u compiler/modes.m compiler/modes.m
--- compiler/modes.m	19 Jun 2006 04:19:03 -0000
+++ compiler/modes.m	23 Jun 2006 08:13:52 -0000
@@ -1293,7 +1293,7 @@
     ;
         ConjType = parallel_conj,
         mode_checkpoint(enter, "par_conj", !ModeInfo, !IO),
-        % empty parallel conjunction should not be a common case
+        % Empty parallel conjunction should not be a common case.
         modecheck_conj_list(ConjType, Goals0, Goals, !ModeInfo, !IO),
         par_conj_list_to_goal(Goals, GoalInfo0, Goal - _GoalInfo),
         mode_checkpoint(exit, "par_conj", !ModeInfo, !IO)
@@ -2016,7 +2016,7 @@
 
 :- type impurity_errors == list(mode_error_info).
 
-    % Flatten conjunctions as we go, as long as they are of the same type).
+    % Flatten conjunctions as we go, as long as they are of the same type.
     % Call modecheck_conj_list_3 to do the actual scheduling.
     %
 :- pred modecheck_conj_list_2(conj_type::in,
diff -u compiler/modules.m compiler/modules.m
--- compiler/modules.m	21 Jun 2006 06:35:35 -0000
+++ compiler/modules.m	23 Jun 2006 09:31:51 -0000
@@ -2795,12 +2795,17 @@
     ;
         true
     ),
+    globals.get_target(Globals, Target),
+    globals.lookup_bool_option(Globals, highlevel_code, HighLevelCode),
     globals.lookup_bool_option(Globals, parallel, Parallel),
     (
-        Parallel = yes,
+        Target = target_c,
+        HighLevelCode = no,
+        Parallel = yes
+    ->
         !:UseDeps = [MercuryParBuiltin | !.UseDeps]
     ;
-        Parallel = no
+        true
     ).
 
 :- pred contains_tabling_pragma(item_list::in) is semidet.
diff -u compiler/par_conj_gen.m compiler/par_conj_gen.m
--- compiler/par_conj_gen.m	19 Jun 2006 12:26:13 -0000
+++ compiler/par_conj_gen.m	23 Jun 2006 09:41:35 -0000
@@ -262,9 +262,9 @@
     % XXX at the moment we are copying back too much.  Conjuncts which
     % are only consumers of variable X should not be copying it back.
     %
-    % Also, variables which are shared (i.e. we allocate a promise for
+    % Also, variables which are shared (i.e. we allocate a future for
     % it) do not need copying back if we take the address of the
-    % shared variable and store it in the promise, then write
+    % shared variable and store it in the future, then write
     % to that address on `signal' or the last `wait'.
     %
 :- pred copy_outputs(code_info::in, list(prog_var)::in, lval::in,
diff -u library/par_builtin.m library/par_builtin.m
--- library/par_builtin.m	21 Jun 2006 09:17:49 -0000
+++ library/par_builtin.m	23 Jun 2006 10:52:52 -0000
@@ -28,11 +28,26 @@
 
 :- interface.
 
-:- type prom(T).
+:- type future(T).
 
-:- pred new_promise(prom(T)::uo) is det.
-:- pred wait(prom(T)::in, T::out) is det.
-:- impure pred signal(prom(T)::in, T::in) is det.
+    % Allocate a new future object.  A future acts as a intermediary for a
+    % shared variable between parallel conjuncts, when one conjunct produces
+    % the value for other conjuncts.
+    %
+:- pred new_future(future(T)::uo) is det.
+
+    % wait(Future, Value)
+    % Wait until Future is signalled, blocking if necessary.  Then the value
+    % bound to the variable associated with the future is bound to Value.
+    %
+:- pred wait(future(T)::in, T::out) is det.
+
+    % Notify that the variable associated with the given future has been bound
+    % to a value.  Threads waiting on the future will be woken.  Future waits
+    % on the future will succeed immediately.  A future can only be signalled
+    % once.
+    %
+:- impure pred signal(future(T)::in, T::in) is det.
 
 %-----------------------------------------------------------------------------%
 
@@ -40,14 +55,14 @@
 
 :- pragma foreign_decl("C",
 "
-    typedef struct MR_Promise MR_Promise;
+    typedef struct MR_Future MR_Future;
 
 #ifdef MR_THREAD_SAFE
 # ifdef MR_HAVE_SEMAPHORE_H
     /* POSIX 1003.1b semaphores available. */
     #include <semaphore.h>
 
-    struct MR_Promise {
+    struct MR_Future {
         sem_t   semaphore;
         MR_Word value;
     };
@@ -55,74 +70,75 @@
     /* Use POSIX thread mutexes and condition variables. */
     #include <pthread.h>
 
-    struct MR_Promise {
+    struct MR_Future {
         pthread_mutex_t mutex;
         pthread_cond_t cond;
         MR_Word value;
     };
 # endif /* !MR_HAVE_SEMAPHORE_H */
 #else /* !MR_THREAD_SAFE */
-    struct MR_Promise {
+    struct MR_Future {
     };
 #endif /* !MR_THREAD_SAFE */
 ").
 
-:- pragma foreign_type("C", prom(T), "MR_Promise *").
+:- pragma foreign_type("C", future(T), "MR_Future *",
+    [can_pass_as_mercury_type]).
 
     % Placeholder only.
-:- pragma foreign_type(il, prom(T), "class [mscorlib]System.Object").
+:- pragma foreign_type(il, future(T), "class [mscorlib]System.Object").
 
 :- pragma foreign_proc("C",
-    new_promise(Promise::uo),
+    new_future(Future::uo),
     [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail],
 "
 #ifdef MR_THREAD_SAFE
 # ifdef MR_HAVE_SEMAPHORE_H
-    Promise = MR_GC_NEW(MR_Promise);
-    sem_init(&Promise->semaphore, MR_NO, 0);
-    Promise->value = 0;
+    Future = MR_GC_NEW(MR_Future);
+    sem_init(&Future->semaphore, MR_NO, 0);
+    Future->value = 0;
 # else
-    Promise = MR_GC_NEW(MR_Promise);
-    pthread_mutex_init(&Promise->mutex, NULL);
-    pthread_cond_init(&Promise->cond, NULL);
-    Promise->value = 0;
+    Future = MR_GC_NEW(MR_Future);
+    pthread_mutex_init(&Future->mutex, NULL);
+    pthread_cond_init(&Future->cond, NULL);
+    Future->value = 0;
 # endif
 #endif
 ").
 
 :- pragma foreign_proc("C",
-    wait(Promise::in, Value::out),
+    wait(Future::in, Value::out),
     [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail],
 "
 #ifdef MR_THREAD_SAFE
 # ifdef MR_HAVE_SEMAPHORE_H
-    sem_wait(&Promise->semaphore);
-    sem_post(&Promise->semaphore);
-    Value = Promise->value;
+    sem_wait(&Future->semaphore);
+    sem_post(&Future->semaphore);
+    Value = Future->value;
 # else
-    pthread_mutex_lock(&Promise->mutex);
-    while (!Promise->pass) {
-        pthread_cond_wait(&Promise->cond, &Promise->mutex);
+    pthread_mutex_lock(&Future->mutex);
+    while (!Future->pass) {
+        pthread_cond_wait(&Future->cond, &Future->mutex);
     }
-    Value = Promise->value;
-    pthread_mutex_unlock(&Promise->mutex);
+    Value = Future->value;
+    pthread_mutex_unlock(&Future->mutex);
 # endif
 #endif
 ").
 
 :- pragma foreign_proc("C",
-    signal(Promise::in, Value::in),
+    signal(Future::in, Value::in),
     [will_not_call_mercury, thread_safe, will_not_modify_trail],
 "
 #ifdef MR_THREAD_SAFE
 # ifdef MR_HAVE_SEMAPHORE_H
-    Promise->value = Value;
-    sem_post(&Promise->semaphore);
+    Future->value = Value;
+    sem_post(&Future->semaphore);
 # else
-    pthread_mutex_lock(&Promise->mutex);
-    Value = Promise->value;
-    pthread_cond_broadcast(&Promise->cond);
-    pthread_mutex_unlock(&Promise->mutex);
+    pthread_mutex_lock(&Future->mutex);
+    Value = Future->value;
+    pthread_cond_broadcast(&Future->cond);
+    pthread_mutex_unlock(&Future->mutex);
 # endif
 #endif
 ").
diff -u library/private_builtin.m library/private_builtin.m
--- library/private_builtin.m	13 Jun 2006 15:46:40 -0000
+++ library/private_builtin.m	23 Jun 2006 08:28:55 -0000
@@ -16,7 +16,7 @@
 % implementing polymorphism, unification, compare/3, etc.
 % Note that the builtins used for tabling, deep profiling and parallelism are
 % in separate modules (table_builtin.m, profiling_builtin.m and
-% par_builting.m).
+% par_builtin.m).
 
 % This module is a private part of the Mercury implementation; user modules
 % should never explicitly import this module. The interface for this module
diff -u mdbcomp/program_representation.m mdbcomp/program_representation.m
--- mdbcomp/program_representation.m	18 Jun 2006 11:33:05 -0000
+++ mdbcomp/program_representation.m	23 Jun 2006 12:50:13 -0000
@@ -334,6 +334,13 @@
     % implemented by foreign language code in the standard library.
     % For some, but not all, the compiler generates code inline.
     %
+    % If you are adding a predicate to no_type_info_builtin, remember that
+    % this will only affect code built by a compiler linked with the new
+    % mdbcomp library.  e.g. if you add a predicate P to no_type_info_builtin,
+    % the compiler building the stage 1 library won't yet know about P.
+    % The stage 1 compiler _will_ know about P, so stage 2 is when P will
+    % be compiled differently.
+    %
 :- pred no_type_info_builtin(module_name::in, string::in, int::in) is semidet.
 
 %-----------------------------------------------------------------------------%
@@ -573,7 +580,7 @@
 no_type_info_builtin_2(table_builtin, "table_lookup_insert_typeinfo", 3).
 no_type_info_builtin_2(table_builtin, "table_lookup_insert_typeclassinfo", 3).
 no_type_info_builtin_2(term_size_prof_builtin, "increment_size", 2).
-no_type_info_builtin_2(par_builtin, "new_promise", 1).
+no_type_info_builtin_2(par_builtin, "new_future", 1).
 no_type_info_builtin_2(par_builtin, "wait", 2).
 no_type_info_builtin_2(par_builtin, "signal", 2).
 
--------------------------------------------------------------------------
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