[m-rev.] for post-commit review: speed up the compilation of large predicates

Zoltan Somogyi zs at cs.mu.OZ.AU
Wed May 25 16:02:42 AEST 2005


On 23-May-2005, Zoltan Somogyi <zs at cs.mu.OZ.AU> wrote:
> There are at least three other performance problems left. The fourth is
> the same as the third, except for unique mode checking. The fifth is in
> simplification, and the sixth is in equiv_type_hlds. I'll work on those next.

For review by anyone.

Zoltan.

Fix the remaining performance problems that arose when compiling
predicates defined by lots of facts.

The third performance problem I reported previously was the quadratic or
worse behavior of the mode checker when merging the instmaps of disjuncts
at the ends of large disjunctions. The fix was a new pragma,
mode_check_clauses, that causes the mode checker to check each clause
individually. This diff extends that solution to predicates whose main
goal is a switch as well as disj, for use in case mode analysis is rerun
after common subexpression elimination.

The fourth performance problem I reported was the same as the third,
only applied to unique mode checking. The fix is also analogous.

The fifth performance problem I reported was in simplify. Simplify also
had quadratic or worse code to merge the instmap_deltas of disjunctions and
switches. The fix is in two parts. One part is to mark the main goals of
mode_check_clauses predicates with a new feature, and have simplify refrain
from recomputing the instmap_deltas of goals with that feature. This required
also making mode_check_clauses predicate non-inlineable, since after inlining
other compiler passes could push code into the branches of the disj or switch
goal, leaving the original instmap_delta invalid. The second part was to make
mode_util.m respect this flag in the same way. This also fixed the sixth
performance problem in equiv_type_hlds.m.

This diff, and the one before it, collectively reduce the time to compile
the benchmark with the 16000 clause predicate from 792s to 21s, a factor of 36.

User level documentation will follow soon after more tests.

compiler/modes.m:
	Implement separate mode checking of clauses for switch goals.

	Implement separate unique mode checking of clauses, for both disj
	and switch goals.

	Attach markers to the pieces of code whose functionality the new code
	in modes.m broadly duplicates to indicate the duplication.

	Factor out some repeated tests of a condition.

	Fix the format of some comments.

compiler/unique_modes.m:
	Factor out some code into separate predicates, and export existing
	predicates, for use by the new code in modes.m.

	Attach markers to the pieces of code whose functionality the new code
	in modes.m broadly duplicates to indicate the duplication.

compiler/hlds_goal.m:
	Add the new mode_check_clauses_goal feature.

compiler/simplify.m:
	Attach the mode_check_clauses_goal feature to the top level disj or
	switch goal of mode_check_clauses predicates, and avoid recomputing
	the instmap_deltas of goals with this feature.

compiler/mode_util.m:
	Avoid recomputing the instmap_deltas of goals with the
	mode_check_clauses_goal feature.

compiler/saved_vars.m:
	Conform to the change in hlds_goal.m.

compiler/modules.m:
	Fix another problem that caused excessive nondet stack usage in debug
	grades when working on programs with many clauses.

cvs diff: Diffing .
cvs diff: Diffing analysis
cvs diff: Diffing bindist
cvs diff: Diffing boehm_gc
cvs diff: Diffing boehm_gc/Mac_files
cvs diff: Diffing boehm_gc/cord
cvs diff: Diffing boehm_gc/cord/private
cvs diff: Diffing boehm_gc/doc
cvs diff: Diffing boehm_gc/include
cvs diff: Diffing boehm_gc/include/private
cvs diff: Diffing boehm_gc/tests
cvs diff: Diffing browser
cvs diff: Diffing bytecode
cvs diff: Diffing compiler
Index: compiler/hlds_goal.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/hlds_goal.m,v
retrieving revision 1.130
diff -u -b -r1.130 hlds_goal.m
--- compiler/hlds_goal.m	10 May 2005 04:58:30 -0000	1.130
+++ compiler/hlds_goal.m	24 May 2005 12:13:46 -0000
@@ -918,7 +918,7 @@
 				% is known to be bound to a given constant,
 				% then the second variable should be set
 				% to the corresponding local tag value.
-	;	dont_warn_singleton.
+	;	dont_warn_singleton
 				% Don't warn about singletons in this goal.
 				% Intended to be used by the state variable
 				% transformation, for situations such as the
@@ -951,6 +951,15 @@
 				% of quantification as well, we simply make it
 				% mark the unifications it creates, and get
 				% the singleton warning code to respect it.
+	;	mode_check_clauses_goal.
+				% This goal is the main disjunction of a
+				% predicate with the mode_check_clauses pragma.
+				% No compiler pass should try to invoke
+				% quadratic or worse algorithms on the arms
+				% of this goal, since it probably has many
+				% arms (possibly several thousand). This
+				% feature may be attached to switches as well
+				% as disjunctions.
 
 	% We can think of the goal that defines a procedure to be a tree,
 	% whose leaves are primitive goals and whose interior nodes are
Index: compiler/make_hlds.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/make_hlds.m,v
retrieving revision 1.513
diff -u -b -r1.513 make_hlds.m
--- compiler/make_hlds.m	23 May 2005 03:15:36 -0000	1.513
+++ compiler/make_hlds.m	25 May 2005 03:44:25 -0000
@@ -890,7 +890,15 @@
     ;
         Pragma = mode_check_clauses(Name, Arity),
         add_pred_marker("mode_check_clauses", Name, Arity, ImportStatus,
-            Context, mode_check_clauses, [], !ModuleInfo, !IO)
+            Context, mode_check_clauses, [], !ModuleInfo, !IO),
+
+        % Allowing the predicate to be inlined could lead to code generator
+        % aborts. This is because the caller that inlines this predicate may
+        % then push other code into the disjunction or switch's branches,
+        % which would invalidate the instmap_deltas that the mode_check_clauses
+        % feature prevents the recomputation of.
+        add_pred_marker("mode_check_clauses", Name, Arity, ImportStatus,
+            Context, no_inline, [inline], !ModuleInfo, !IO)
     ).
 add_item_decl_pass_2(Item, _Context, !Status, !ModuleInfo, !IO) :-
     Item = pred_or_func(_TypeVarSet, _InstVarSet, _ExistQVars,
Index: compiler/mode_util.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/mode_util.m,v
retrieving revision 1.165
diff -u -b -r1.165 mode_util.m
--- compiler/mode_util.m	24 Mar 2005 05:34:09 -0000	1.165
+++ compiler/mode_util.m	24 May 2005 14:56:34 -0000
@@ -945,9 +945,14 @@
 recompute_instmap_delta_2(Atomic, switch(Var, Det, Cases0), GoalInfo,
 		switch(Var, Det, Cases), VarTypes, InstMap, InstMapDelta,
 		!RI) :-
+	( goal_info_has_feature(GoalInfo, mode_check_clauses_goal) ->
+		Cases = Cases0,
+		goal_info_get_instmap_delta(GoalInfo, InstMapDelta)
+	;
 	goal_info_get_nonlocals(GoalInfo, NonLocals),
 	recompute_instmap_delta_cases(Atomic, Var, Cases0, Cases,
-		VarTypes, InstMap, NonLocals, InstMapDelta, !RI).
+			VarTypes, InstMap, NonLocals, InstMapDelta, !RI)
+	).
 
 recompute_instmap_delta_2(Atomic, conj(Goals0), _, conj(Goals),
 		VarTypes, InstMap, InstMapDelta, !RI) :-
@@ -962,9 +967,14 @@
 
 recompute_instmap_delta_2(Atomic, disj(Goals0), GoalInfo, disj(Goals),
 		VarTypes, InstMap, InstMapDelta, !RI) :-
+	( goal_info_has_feature(GoalInfo, mode_check_clauses_goal) ->
+		Goals = Goals0,
+		goal_info_get_instmap_delta(GoalInfo, InstMapDelta)
+	;
 	goal_info_get_nonlocals(GoalInfo, NonLocals),
 	recompute_instmap_delta_disj(Atomic, Goals0, Goals,
-		VarTypes, InstMap, NonLocals, InstMapDelta, !RI).
+			VarTypes, InstMap, NonLocals, InstMapDelta, !RI)
+	).
 
 recompute_instmap_delta_2(Atomic, not(Goal0), _, not(Goal),
 		VarTypes, InstMap, InstMapDelta, !RI) :-
@@ -1133,8 +1143,8 @@
 		InstMap0), InstMap, !RI),
 	recompute_instmap_delta_1(Atomic, Goal0, Goal, VarTypes, InstMap,
 		InstMapDelta0, !RI),
-	update_module_info(instmap_delta_bind_var_to_functor(Var, Type, Functor,
-		InstMap0, InstMapDelta0), InstMapDelta1, !RI),
+	update_module_info(instmap_delta_bind_var_to_functor(Var, Type,
+		Functor, InstMap0, InstMapDelta0), InstMapDelta1, !RI),
 	Case = case(Functor, Goal),
 	recompute_instmap_delta_cases(Atomic, Var, Cases0, Cases,
 		VarTypes, InstMap0, NonLocals, InstMapDelta2, !RI),
Index: compiler/modes.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/modes.m,v
retrieving revision 1.298
diff -u -b -r1.298 modes.m
--- compiler/modes.m	23 May 2005 03:15:38 -0000	1.298
+++ compiler/modes.m	24 May 2005 11:42:43 -0000
@@ -31,7 +31,7 @@
 % How does it all work?  Well, mode checking/inference is basically a
 % process of abstract interpretation.  To perform this abstract
 % interpretation on a procedure body, we need to know the initial insts of
-% the arguments; then we can abstractly interpretet the goal to compute the
+% the arguments; then we can abstractly interpret the goal to compute the
 % final insts.  For mode checking, we then just compare the inferred final
 % insts with the declared final insts, and that's about all there is to it.
 %
@@ -812,11 +812,17 @@
         mode_list_get_final_insts(ArgModes0, !.ModuleInfo, ArgFinalInsts0),
 
         (
-            WhatToCheck = check_modes,
             InferModes = no,
             check_marker(Markers, mode_check_clauses),
+            (
             Body0 = disj(Disjuncts0) - BodyGoalInfo0,
             Disjuncts0 = [_ | _],
+                ClausesForm0 = clause_disj(Disjuncts0)
+            ;
+                Body0 = switch(SwitchVar0, CanFail0, Cases0) - BodyGoalInfo0,
+                Cases0 = [_ | _],
+                ClausesForm0 = clause_switch(SwitchVar0, CanFail0, Cases0)
+            ),
             goal_info_get_nonlocals(BodyGoalInfo0, BodyNonLocals),
             mode_info_get_var_types(!.ModeInfo, VarTypes0),
             SolverNonLocals = list__filter(
@@ -832,13 +838,61 @@
                 mode_info_set_context(BodyContext, !ModeInfo)
             ),
 
+            % Modecheck each clause of the procedure body separately.
             (
                 WhatToCheck = check_modes,
-                % Modecheck each clause of the procedure body separately.
-                Disjuncts1 = flatten_disjs(Disjuncts0),
+                (
+                    ClausesForm0 = clause_disj(Disjuncts1),
+                    Disjuncts2 = flatten_disjs(Disjuncts1),
                 list__map_foldl2(
-                    modecheck_clause(HeadVars, InstMap0, ArgFinalInsts0),
-                    Disjuncts1, Disjuncts, !ModeInfo, !IO),
+                        modecheck_clause_disj(HeadVars, InstMap0,
+                            ArgFinalInsts0),
+                        Disjuncts2, Disjuncts, !ModeInfo, !IO),
+                    NewGoalExpr = disj(Disjuncts)
+                ;
+                    ClausesForm0 = clause_switch(SwitchVar, CanFail, Cases1),
+                    list__map_foldl2(
+                        modecheck_clause_switch(HeadVars, InstMap0,
+                            ArgFinalInsts0, SwitchVar),
+                        Cases1, Cases, !ModeInfo, !IO),
+                    NewGoalExpr = switch(SwitchVar, CanFail, Cases)
+                )
+            ;
+                WhatToCheck = check_unique_modes,
+                mode_info_get_nondet_live_vars(!.ModeInfo, NondetLiveVars0),
+                goal_info_get_determinism(BodyGoalInfo0, Detism),
+                goal_info_get_nonlocals(BodyGoalInfo0, NonLocals),
+                ( determinism_components(Detism, _, at_most_many) ->
+                    true
+                ;
+                    mode_info_set_nondet_live_vars(bag__init, !ModeInfo)
+                ),
+                (
+                    ClausesForm0 = clause_disj(Disjuncts1),
+                    Disjuncts2 = flatten_disjs(Disjuncts1),
+                    ( determinism_components(Detism, _, at_most_many) ->
+                        mode_info_add_live_vars(NonLocals, !ModeInfo),
+                        make_all_nondet_live_vars_mostly_uniq(!ModeInfo),
+                        mode_info_remove_live_vars(NonLocals, !ModeInfo)
+                    ;
+                        true
+                    ),
+                    list__map_foldl2(
+                        unique_modecheck_clause_disj(HeadVars, InstMap0,
+                            ArgFinalInsts0, Detism, NonLocals,
+                            NondetLiveVars0),
+                        Disjuncts2, Disjuncts, !ModeInfo, !IO),
+                    NewGoalExpr = disj(Disjuncts)
+                ;
+                    ClausesForm0 = clause_switch(SwitchVar, CanFail, Cases1),
+                    list__map_foldl2(
+                        unique_modecheck_clause_switch(HeadVars, InstMap0,
+                            ArgFinalInsts0, SwitchVar),
+                        Cases1, Cases, !ModeInfo, !IO),
+                    NewGoalExpr = switch(SwitchVar, CanFail, Cases)
+                )
+                % error("do_modecheck_proc: unexpected check_unique_modes")
+            ),
 
                 % Manufacture an instmap_delta for the disjunction as a whole.
                 assoc_list__from_corresponding_lists(HeadVars, ArgFinalInsts0,
@@ -848,13 +902,9 @@
                     DeltaInstMap),
                 goal_info_set_instmap_delta(BodyGoalInfo0, DeltaInstMap,
                     BodyGoalInfo),
-                Body = disj(Disjuncts) - BodyGoalInfo,
+            Body = NewGoalExpr - BodyGoalInfo,
                 ArgFinalInsts = ArgFinalInsts0
             ;
-                WhatToCheck = check_unique_modes,
-                error("do_modecheck_proc: unexpected check_unique_modes")
-            )
-        ;
             % Modecheck the procedure body as a single goal.
             (
                 WhatToCheck = check_modes,
@@ -900,20 +950,106 @@
         proc_info_set_argmodes(ArgModes, !ProcInfo)
     ).
 
-:- pred modecheck_clause(list(prog_var)::in, instmap::in, list(inst)::in,
+%-----------------------------------------------------------------------------%
+
+:- type clause_form
+    --->    clause_disj(list(hlds_goal))
+    ;       clause_switch(prog_var, can_fail, list(case)).
+
+:- pred modecheck_clause_disj(list(prog_var)::in, instmap::in, list(inst)::in,
     hlds_goal::in, hlds_goal::out, mode_info::in, mode_info::out,
     io::di, io::uo) is det.
 
-modecheck_clause(HeadVars, InstMap0, ArgFinalInsts0, Disjunct0, Disjunct,
+modecheck_clause_disj(HeadVars, InstMap0, ArgFinalInsts0, Disjunct0, Disjunct,
         !ModeInfo, !IO) :-
     mode_info_set_instmap(InstMap0, !ModeInfo),
     modecheck_goal(Disjunct0, Disjunct1, !ModeInfo, !IO),
 
-        % Check that final insts match those specified in the
-        % mode declaration.
+    % Check that final insts match those specified in the mode declaration.
+    modecheck_final_insts(HeadVars, no, ArgFinalInsts0,
+        _ArgFinalInsts, Disjunct1, Disjunct, !ModeInfo).
+
+:- pred modecheck_clause_switch(list(prog_var)::in, instmap::in,
+    list(inst)::in, prog_var::in, case::in, case::out,
+    mode_info::in, mode_info::out, io::di, io::uo) is det.
+
+modecheck_clause_switch(HeadVars, InstMap0, ArgFinalInsts0, Var, Case0, Case,
+        !ModeInfo, !IO) :-
+    Case0 = case(ConsId, Goal0),
+    mode_info_set_instmap(InstMap0, !ModeInfo),
+
+    modecheck_functor_test(Var, ConsId, !ModeInfo),
+
+    % Modecheck this case (if it is reachable).
+    mode_info_get_instmap(!.ModeInfo, InstMap1),
+    ( instmap__is_reachable(InstMap1) ->
+        modecheck_goal(Goal0, Goal1, !ModeInfo, !IO),
+        mode_info_get_instmap(!.ModeInfo, InstMap)
+    ;
+        % We should not mode-analyse the goal, since it is unreachable.
+        % Instead we optimize the goal away, so that later passes
+        % won't complain about it not having mode information.
+        true_goal(Goal1),
+        InstMap = InstMap1
+    ),
+
+    % Don't lose the information added by the functor test above.
+    fixup_switch_var(Var, InstMap0, InstMap, Goal1, Goal2),
+
+    % Check that final insts match those specified in the mode declaration.
+    modecheck_final_insts(HeadVars, no, ArgFinalInsts0,
+        _ArgFinalInsts, Goal2, Goal, !ModeInfo),
+    Case = case(ConsId, Goal).
+
+:- pred unique_modecheck_clause_disj(list(prog_var)::in, instmap::in,
+    list(inst)::in, determinism::in, set(prog_var)::in, bag(prog_var)::in,
+    hlds_goal::in, hlds_goal::out, mode_info::in, mode_info::out,
+    io::di, io::uo) is det.
+
+unique_modecheck_clause_disj(HeadVars, InstMap0, ArgFinalInsts0, DisjDetism,
+        DisjNonLocals, NondetLiveVars0, Disjunct0, Disjunct, !ModeInfo, !IO) :-
+    mode_info_set_instmap(InstMap0, !ModeInfo),
+    mode_info_set_nondet_live_vars(NondetLiveVars0, !ModeInfo),
+    unique_modes__prepare_for_disjunct(Disjunct0, DisjDetism, DisjNonLocals,
+        !ModeInfo),
+    unique_modes__check_goal(Disjunct0, Disjunct1, !ModeInfo, !IO),
+
+    % Check that final insts match those specified in the mode declaration.
     modecheck_final_insts(HeadVars, no, ArgFinalInsts0,
         _ArgFinalInsts, Disjunct1, Disjunct, !ModeInfo).
 
+:- pred unique_modecheck_clause_switch(list(prog_var)::in, instmap::in,
+    list(inst)::in, prog_var::in, case::in, case::out,
+    mode_info::in, mode_info::out, io::di, io::uo) is det.
+
+unique_modecheck_clause_switch(HeadVars, InstMap0, ArgFinalInsts0, Var,
+        Case0, Case, !ModeInfo, !IO) :-
+    Case0 = case(ConsId, Goal0),
+    mode_info_set_instmap(InstMap0, !ModeInfo),
+
+    modecheck_functor_test(Var, ConsId, !ModeInfo),
+
+    mode_info_get_instmap(!.ModeInfo, InstMap1),
+    ( instmap__is_reachable(InstMap1) ->
+        unique_modes__check_goal(Goal0, Goal1, !ModeInfo, !IO)
+    ;
+        % We should not mode-analyse the goal, since it is unreachable.
+        % Instead we optimize the goal away, so that later passes
+        % won't complain about it not having mode information.
+        true_goal(Goal1)
+    ),
+
+    % Don't lose the information added by the functor test above.
+    mode_info_get_instmap(!.ModeInfo, InstMap),
+    fixup_switch_var(Var, InstMap0, InstMap, Goal1, Goal2),
+
+    % Check that final insts match those specified in the mode declaration.
+    modecheck_final_insts(HeadVars, no, ArgFinalInsts0, _ArgFinalInsts,
+        Goal2, Goal, !ModeInfo),
+    Case = case(ConsId, Goal).
+
+%-----------------------------------------------------------------------------%
+
     % Modecheck_final_insts for a lambda expression.
     %
 modecheck_lambda_final_insts(HeadVars, ArgFinalInsts, !Goal, !ModeInfo) :-
@@ -1141,9 +1277,11 @@
 
 modecheck_goal_expr(conj(List0), GoalInfo0, Goal, !ModeInfo, !IO) :-
     mode_checkpoint(enter, "conj", !ModeInfo, !IO),
-    ( List0 = [] -> % for efficiency, optimize common case
+    (
+        List0 = [],         % for efficiency, optimize common case
         Goal = conj([])
     ;
+        List0 = [_ | _],
         modecheck_conj_list(List0, List, !ModeInfo, !IO),
         conj_list_to_goal(List, GoalInfo0, Goal - _GoalInfo)
     ),
@@ -1192,7 +1330,7 @@
         mode_info_set_instmap(InstMap, !ModeInfo)
     ;
         % If you modify this code, you may also need to modify
-        % modecheck_clause or the code that calls it.
+        % modecheck_clause_disj or the code that calls it.
 
         Disjs0 = [_ | _],
         goal_info_get_nonlocals(GoalInfo0, NonLocals),
@@ -1439,6 +1577,9 @@
         instmap__init_unreachable(InstMap),
         mode_info_set_instmap(InstMap, !ModeInfo)
     ;
+        % If you modify this code, you may also need to modify
+        % modecheck_clause_switch or the code that calls it.
+
         Cases0 = [_ | _],
         goal_info_get_nonlocals(GoalInfo0, NonLocals),
         modecheck_case_list(Cases0, Var, Cases, InstMapList,
@@ -1773,16 +1914,7 @@
     list__append(OldErrors, NewErrors, Errors),
     mode_info_set_errors(Errors, !ModeInfo),
 
-    (
-        DelayedGoals = [_ | _],
-        % the variables in the delayed goals should not longer
-        % be considered live (the conjunction itself will
-        % delay, and its nonlocals will be made live)
-        mode_info_set_live_vars(LiveVars1, !ModeInfo)
-    ;
-        DelayedGoals = []
-    ),
-    % we only report impurity errors if there were no other errors
+    % We only report impurity errors if there were no other errors.
     (
         DelayedGoals = [],
         %
@@ -1794,13 +1926,21 @@
         list__append(Errors5, ImpurityErrors, Errors6),
         mode_info_set_errors(Errors6, !ModeInfo)
     ;
-        DelayedGoals = [delayed_goal(_DVars, Error, _DGoal)],
+        DelayedGoals = [FirstDelayedGoal | MoreDelayedGoals],
+        % The variables in the delayed goals should not longer
+        % be considered live (the conjunction itself will
+        % delay, and its nonlocals will be made live).
+        mode_info_set_live_vars(LiveVars1, !ModeInfo),
+        (
+            MoreDelayedGoals = [],
+            FirstDelayedGoal = delayed_goal(_DVars, Error, _DGoal),
         mode_info_add_error(Error, !ModeInfo)
     ;
-        DelayedGoals = [_, _ | _],
+            MoreDelayedGoals = [_ | _],
         get_all_waiting_vars(DelayedGoals, Vars),
-        mode_info_error(Vars, mode_error_conj(DelayedGoals, conj_floundered),
-            !ModeInfo)
+            mode_info_error(Vars,
+                mode_error_conj(DelayedGoals, conj_floundered), !ModeInfo)
+        )
     ),
         % Restore the value of the may_initialise_solver_vars flag.
     mode_info_set_may_initialise_solver_vars(MayInitEntryValue, !ModeInfo).
@@ -2344,16 +2484,15 @@
 hlds_goal_from_delayed_goal(delayed_goal(_WaitingVars, _ModeError, Goal)) =
     Goal.
 
-%  check whether there are any delayed goals (other than headvar unifications)
-%  at the point where we are about to schedule an impure goal.  If so, that is
-%  an error.  Headvar unifications are allowed to be delayed because in the
-%  case of output arguments, they cannot be scheduled until the variable value
-%  is known.  If headvar unifications couldn't be delayed past impure goals,
-%  impure predicates wouldn't be able to have outputs!
-%
-%  (Note that we first try to schedule any delayed solver goals waiting for
-%  initialisation.)
-
+    % Check whether there are any delayed goals (other than headvar
+    % unifications) at the point where we are about to schedule an impure goal.
+    % If so, that is an error. Headvar unifications are allowed to be delayed
+    % because in the case of output arguments, they cannot be scheduled
+    % until the variable value is known. If headvar unifications couldn't be
+    % delayed past impure goals, impure predicates wouldn't be able to have
+    % outputs! (Note that we first try to schedule any delayed solver goals
+    % waiting for initialisation.)
+    %
 :- pred check_for_impurity_error(hlds_goal::in, list(hlds_goal)::out,
     impurity_errors::in, impurity_errors::out,
     mode_info::in, mode_info::out, io::di, io::uo) is det.
@@ -2460,14 +2599,13 @@
 modecheck_case_list([Case0 | Cases0], Var, [Case | Cases],
         [InstMap | InstMaps], !ModeInfo, !IO) :-
     Case0 = case(ConsId, Goal0),
-    Case = case(ConsId, Goal),
     mode_info_get_instmap(!.ModeInfo, InstMap0),
 
-    % record the fact that Var was bound to ConsId in the
-    % instmap before processing this case
+    % Record the fact that Var was bound to ConsId in the
+    % instmap before processing this case.
     modecheck_functor_test(Var, ConsId, !ModeInfo),
 
-    % modecheck this case (if it is reachable)
+    % Modecheck this case (if it is reachable).
     mode_info_get_instmap(!.ModeInfo, InstMap1),
     ( instmap__is_reachable(InstMap1) ->
         modecheck_goal(Goal0, Goal1, !ModeInfo, !IO),
@@ -2482,13 +2620,14 @@
 
     % Don't lose the information added by the functor test above.
     fixup_switch_var(Var, InstMap0, InstMap, Goal1, Goal),
+    Case = case(ConsId, Goal),
 
     mode_info_set_instmap(InstMap0, !ModeInfo),
     modecheck_case_list(Cases0, Var, Cases, InstMaps, !ModeInfo, !IO).
 
     % modecheck_functor_test(ConsId, Var):
-    %   update the instmap to reflect the fact that
-    %   Var was bound to ConsId.
+    %
+    % Update the instmap to reflect the fact that Var was bound to ConsId.
     % This is used for the functor tests in `switch' statements.
     %
 modecheck_functor_test(Var, ConsId, !ModeInfo) :-
@@ -2548,8 +2687,7 @@
 
 %-----------------------------------------------------------------------------%
 
-    %
-    % calculate the argument number offset that needs to be passed to
+    % Calculate the argument number offset that needs to be passed to
     % modecheck_var_list_is_live, modecheck_var_has_inst_list, and
     % modecheck_set_var_inst_list.  This offset number is calculated
     % so that real arguments get positive argument numbers and
@@ -2566,7 +2704,7 @@
     % Given a list of variables and a list of expected livenesses,
     % ensure the liveness of each variable satisfies the corresponding
     % expected liveness.
-
+    %
 modecheck_var_list_is_live([_ | _], [], _, _, !ModeInfo) :-
     error("modecheck_var_list_is_live: length mismatch").
 modecheck_var_list_is_live([], [_ | _], _, _, !ModeInfo) :-
@@ -2590,7 +2728,7 @@
     % which is live to a predicate that expects the variable to
     % be dead; the predicate may use destructive update to clobber
     % the variable, so we must be sure that it is dead after the call.
-
+    %
 modecheck_var_is_live(VarId, ExpectedIsLive, NeedExactMatch, !ModeInfo) :-
     mode_info_var_is_live(!.ModeInfo, VarId, VarIsLive),
     (
@@ -2609,7 +2747,7 @@
     % Given a list of variables and a list of initial insts, ensure
     % that the inst of each variable matches the corresponding initial
     % inst.
-
+    %
 modecheck_var_has_inst_list(Vars, Insts, NeedEaxctMatch, ArgNum, Subst,
         !ModeInfo) :-
     modecheck_var_has_inst_list_2(Vars, Insts, NeedEaxctMatch, ArgNum,
@@ -2782,8 +2920,7 @@
         ->
             set__singleton_set(WaitingVars, Var0),
             mode_info_error(WaitingVars,
-                mode_error_bind_var(Reason0, Var0, Inst0, Inst), !ModeInfo
-            )
+                mode_error_bind_var(Reason0, Var0, Inst0, Inst), !ModeInfo)
         ;
             instmap__set(InstMap0, Var0, Inst, InstMap),
             mode_info_set_instmap(InstMap, !ModeInfo),
@@ -2994,9 +3131,9 @@
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
-% check that the evaluation method is OK for the given mode(s).
-% we also check the mode of main/2 here.
-
+    % Check that the evaluation method is OK for the given mode(s).
+    % We also check the mode of main/2 here.
+    %
 :- pred check_eval_methods(module_info::in, module_info::out,
     io::di, io::uo) is det.
 
Index: compiler/modules.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/modules.m,v
retrieving revision 1.333
diff -u -b -r1.333 modules.m
--- compiler/modules.m	25 May 2005 02:38:32 -0000	1.333
+++ compiler/modules.m	25 May 2005 05:25:10 -0000
@@ -7120,11 +7120,15 @@
     is det.
 
 get_foreign_self_imports(Items, Langs) :-
-    solutions(
-        (pred(Lang::out) is nondet :-
-            list__member(Item - _, Items),
-            item_needs_foreign_imports(Item, Lang)
-        ), Langs).
+    list.foldl(accumulate_item_foreign_import_langs, Items, set.init, LangSet),
+    set.to_sorted_list(LangSet, Langs).
+
+:- pred accumulate_item_foreign_import_langs(item_and_context::in,
+    set(foreign_language)::in, set(foreign_language)::out) is det.
+
+accumulate_item_foreign_import_langs(Item - _, !LangSet) :-
+    solutions(item_needs_foreign_imports(Item), Langs),
+    set.insert_list(!.LangSet, Langs, !:LangSet).
 
 :- pred get_interface_and_implementation_2(bool::in, item_list::in, bool::in,
     item_list::in, item_list::out,
Index: compiler/saved_vars.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/saved_vars.m,v
retrieving revision 1.48
diff -u -b -r1.48 saved_vars.m
--- compiler/saved_vars.m	26 Apr 2005 03:57:49 -0000	1.48
+++ compiler/saved_vars.m	24 May 2005 12:28:07 -0000
@@ -211,6 +211,7 @@
 ok_to_duplicate(keep_constant_binding) = no.
 ok_to_duplicate(save_deep_excp_vars) = no.
 ok_to_duplicate(dont_warn_singleton) = yes.
+ok_to_duplicate(mode_check_clauses_goal) = yes.
 
 	% Divide a list of goals into an initial subsequence of goals
 	% that construct constants, and all other goals.
Index: compiler/simplify.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/simplify.m,v
retrieving revision 1.140
diff -u -b -r1.140 simplify.m
--- compiler/simplify.m	18 May 2005 05:49:11 -0000	1.140
+++ compiler/simplify.m	25 May 2005 03:44:25 -0000
@@ -196,7 +196,22 @@
     simplify_info_init(DetInfo0, Simplifications, InstMap0, !.ProcInfo, Info0),
     proc_info_goal(!.ProcInfo, Goal0),
 
-    simplify__process_goal(Goal0, Goal, Info0, Info),
+    simplify_info_get_pred_info(Info0, PredInfo),
+    pred_info_get_markers(PredInfo, Markers),
+    (
+        check_marker(Markers, mode_check_clauses),
+        Goal0 = GoalExpr0 - GoalInfo0,
+        ( GoalExpr0 = disj(_)
+        ; GoalExpr0 = switch(_, _, _)
+        )
+    ->
+        goal_info_add_feature(GoalInfo0, mode_check_clauses_goal, GoalInfo1),
+        Goal1 = GoalExpr0 - GoalInfo1
+    ;
+        Goal1 = Goal0
+    ),
+
+    simplify__process_goal(Goal1, Goal, Info0, Info),
 
     simplify_info_get_varset(Info, VarSet),
     simplify_info_get_var_types(Info, VarTypes),
@@ -577,6 +592,11 @@
     ;
         Disjuncts = [_, _ | _],
         Goal = disj(Disjuncts),
+        ( goal_info_has_feature(GoalInfo0, mode_check_clauses_goal) ->
+            % Recomputing the instmap delta would take very long and is
+            % very unlikely to get any better precision.
+            GoalInfo = GoalInfo0
+        ;
         simplify_info_get_module_info(!.Info, ModuleInfo1),
         goal_info_get_nonlocals(GoalInfo0, NonLocals),
         simplify_info_get_var_types(!.Info, VarTypes),
@@ -584,6 +604,7 @@
             NewDelta, ModuleInfo1, ModuleInfo2),
         simplify_info_set_module_info(ModuleInfo2, !Info),
         goal_info_set_instmap_delta(GoalInfo0, NewDelta, GoalInfo)
+        )
     ),
     list__length(Disjuncts, DisjunctsLength),
     list__length(Disjuncts0, Disjuncts0Length),
@@ -638,12 +659,10 @@
             MaybeConsIds \= yes([ConsId])
         ->
             %
-            % Don't optimize in the case of an existentially
-            % typed constructor because currently
-            % simplify__create_test_unification does not
-            % handle the existential type variables
-            % in the types of the constructor arguments
-            % or their type-infos.
+            % Don't optimize in the case of an existentially typed constructor
+            % because currently simplify__create_test_unification does not
+            % handle the existential type variables in the types of the
+            % constructor arguments or their typeinfos.
             %
             simplify_info_get_var_types(!.Info, VarTypes1),
             map__lookup(VarTypes1, Var, Type),
@@ -694,6 +713,11 @@
     ;
         Cases = [_, _ | _],
         Goal = switch(Var, SwitchCanFail, Cases),
+        ( goal_info_has_feature(GoalInfo0, mode_check_clauses_goal) ->
+            % Recomputing the instmap delta would take very long and is
+            % very unlikely to get any better precision.
+            GoalInfo = GoalInfo0
+        ;
         simplify_info_get_module_info(!.Info, ModuleInfo1),
         goal_info_get_nonlocals(GoalInfo0, NonLocals),
         simplify_info_get_var_types(!.Info, VarTypes),
@@ -701,6 +725,7 @@
             NewDelta, ModuleInfo1, ModuleInfo2),
         simplify_info_set_module_info(ModuleInfo2, !Info),
         goal_info_set_instmap_delta(GoalInfo0, NewDelta, GoalInfo)
+        )
     ),
     list__length(Cases0, Cases0Length),
     list__length(Cases, CasesLength),
Index: compiler/unique_modes.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/unique_modes.m,v
retrieving revision 1.89
diff -u -b -r1.89 unique_modes.m
--- compiler/unique_modes.m	23 May 2005 03:15:42 -0000	1.89
+++ compiler/unique_modes.m	24 May 2005 11:37:42 -0000
@@ -40,9 +40,11 @@
 :- import_module hlds__hlds_goal.
 :- import_module hlds__hlds_module.
 :- import_module hlds__hlds_pred.
+:- import_module parse_tree__prog_data.
 
 :- import_module bool.
 :- import_module io.
+:- import_module set.
 
 	% Check every predicate in a module.
 	%
@@ -59,6 +61,17 @@
 :- pred unique_modes__check_goal(hlds_goal::in, hlds_goal::out,
 	mode_info::in, mode_info::out, io::di, io::uo) is det.
 
+	% Prepare for checking a disjunct in a disjunction.
+	%
+:- pred unique_modes__prepare_for_disjunct(hlds_goal::in, determinism::in,
+	set(prog_var)::in, mode_info::in, mode_info::out) is det.
+
+	% Make all nondet-live variables whose current inst
+	% is `unique' become `mostly_unique'.
+	%
+:- pred make_all_nondet_live_vars_mostly_uniq(mode_info::in, mode_info::out)
+	is det.
+
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
@@ -78,7 +91,6 @@
 :- import_module hlds__instmap.
 :- import_module hlds__passes_aux.
 :- import_module parse_tree__mercury_to_mercury.
-:- import_module parse_tree__prog_data.
 :- import_module parse_tree__prog_mode.
 :- import_module parse_tree__prog_out.
 :- import_module mdbcomp__prim_data.
@@ -89,7 +101,6 @@
 :- import_module list.
 :- import_module map.
 :- import_module require.
-:- import_module set.
 :- import_module std_util.
 :- import_module string.
 :- import_module term.
@@ -168,12 +179,6 @@
 
 	Goal = GoalExpr - GoalInfo.
 
-	% Make all nondet-live variables whose current inst
-	% is `unique' become `mostly_unique'.
-	%
-:- pred make_all_nondet_live_vars_mostly_uniq(mode_info::in, mode_info::out)
-	is det.
-
 make_all_nondet_live_vars_mostly_uniq(ModeInfo0, ModeInfo) :-
 	mode_info_get_instmap(ModeInfo0, FullInstMap0),
 	( instmap__is_reachable(FullInstMap0) ->
@@ -800,6 +805,19 @@
 unique_modes__check_disj([Goal0 | Goals0], DisjDetism, DisjNonLocals,
 		[Goal | Goals], [InstMap | InstMaps], !ModeInfo, !IO) :-
 	mode_info_get_instmap(!.ModeInfo, InstMap0),
+	% If you modify this code, you may also need to modify
+	% unique_modecheck_clause_disj or the code that calls it.
+
+	unique_modes__prepare_for_disjunct(Goal0, DisjDetism, DisjNonLocals,
+		!ModeInfo),
+	unique_modes__check_goal(Goal0, Goal, !ModeInfo, !IO),
+	mode_info_get_instmap(!.ModeInfo, InstMap),
+	mode_info_set_instmap(InstMap0, !ModeInfo),
+	unique_modes__check_disj(Goals0, DisjDetism, DisjNonLocals,
+		Goals, InstMaps, !ModeInfo, !IO).
+
+unique_modes__prepare_for_disjunct(Goal0, DisjDetism, DisjNonLocals,
+		!ModeInfo) :-
 	(
 		%
 		% If the disjunction was model_nondet, then we already marked
@@ -824,12 +842,7 @@
 		mode_info_remove_live_vars(DisjNonLocals, !ModeInfo)
 	;
 		true
-	),
-	unique_modes__check_goal(Goal0, Goal, !ModeInfo, !IO),
-	mode_info_get_instmap(!.ModeInfo, InstMap),
-	mode_info_set_instmap(InstMap0, !ModeInfo),
-	unique_modes__check_disj(Goals0, DisjDetism, DisjNonLocals,
-		Goals, InstMaps, !ModeInfo, !IO).
+	).
 
 %-----------------------------------------------------------------------------%
 
@@ -844,8 +857,11 @@
 	Case = case(ConsId, Goal),
 	mode_info_get_instmap(!.ModeInfo, InstMap0),
 
-	% record the fact that Var was bound to ConsId in the
-	% instmap before processing this case
+	% If you modify this code, you may also need to modify
+	% unique_modecheck_clause_switch or the code that calls it.
+
+	% Record the fact that Var was bound to ConsId in the
+	% instmap before processing this case.
 	modecheck_functor_test(Var, ConsId, !ModeInfo),
 
 	mode_info_get_instmap(!.ModeInfo, InstMap1),
cvs diff: Diffing compiler/notes
cvs diff: Diffing debian
cvs diff: Diffing deep_profiler
cvs diff: Diffing deep_profiler/notes
cvs diff: Diffing doc
cvs diff: Diffing extras
cvs diff: Diffing extras/aditi
cvs diff: Diffing extras/cgi
cvs diff: Diffing extras/complex_numbers
cvs diff: Diffing extras/complex_numbers/samples
cvs diff: Diffing extras/complex_numbers/tests
cvs diff: Diffing extras/concurrency
cvs diff: Diffing extras/curs
cvs diff: Diffing extras/curs/samples
cvs diff: Diffing extras/curses
cvs diff: Diffing extras/curses/sample
cvs diff: Diffing extras/dynamic_linking
cvs diff: Diffing extras/error
cvs diff: Diffing extras/graphics
cvs diff: Diffing extras/graphics/easyx
cvs diff: Diffing extras/graphics/easyx/samples
cvs diff: Diffing extras/graphics/mercury_glut
cvs diff: Diffing extras/graphics/mercury_opengl
cvs diff: Diffing extras/graphics/mercury_tcltk
cvs diff: Diffing extras/graphics/samples
cvs diff: Diffing extras/graphics/samples/calc
cvs diff: Diffing extras/graphics/samples/gears
cvs diff: Diffing extras/graphics/samples/maze
cvs diff: Diffing extras/graphics/samples/pent
cvs diff: Diffing extras/lazy_evaluation
cvs diff: Diffing extras/lex
cvs diff: Diffing extras/lex/samples
cvs diff: Diffing extras/lex/tests
cvs diff: Diffing extras/logged_output
cvs diff: Diffing extras/moose
cvs diff: Diffing extras/moose/samples
cvs diff: Diffing extras/moose/tests
cvs diff: Diffing extras/morphine
cvs diff: Diffing extras/morphine/non-regression-tests
cvs diff: Diffing extras/morphine/scripts
cvs diff: Diffing extras/morphine/source
cvs diff: Diffing extras/odbc
cvs diff: Diffing extras/posix
cvs diff: Diffing extras/quickcheck
cvs diff: Diffing extras/quickcheck/tutes
cvs diff: Diffing extras/references
cvs diff: Diffing extras/references/samples
cvs diff: Diffing extras/references/tests
cvs diff: Diffing extras/stream
cvs diff: Diffing extras/trailed_update
cvs diff: Diffing extras/trailed_update/samples
cvs diff: Diffing extras/trailed_update/tests
cvs diff: Diffing extras/xml
cvs diff: Diffing extras/xml/samples
cvs diff: Diffing extras/xml_stylesheets
cvs diff: Diffing java
cvs diff: Diffing java/runtime
cvs diff: Diffing library
cvs diff: Diffing mdbcomp
cvs diff: Diffing profiler
cvs diff: Diffing robdd
cvs diff: Diffing runtime
cvs diff: Diffing runtime/GETOPT
cvs diff: Diffing runtime/machdeps
cvs diff: Diffing samples
cvs diff: Diffing samples/c_interface
cvs diff: Diffing samples/c_interface/c_calls_mercury
cvs diff: Diffing samples/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/c_interface/mercury_calls_c
cvs diff: Diffing samples/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/diff
cvs diff: Diffing samples/muz
cvs diff: Diffing samples/rot13
cvs diff: Diffing samples/solutions
cvs diff: Diffing samples/tests
cvs diff: Diffing samples/tests/c_interface
cvs diff: Diffing samples/tests/c_interface/c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/tests/c_interface/mercury_calls_c
cvs diff: Diffing samples/tests/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/tests/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/tests/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/tests/diff
cvs diff: Diffing samples/tests/muz
cvs diff: Diffing samples/tests/rot13
cvs diff: Diffing samples/tests/solutions
cvs diff: Diffing samples/tests/toplevel
cvs diff: Diffing scripts
cvs diff: Diffing slice
cvs diff: Diffing tests
cvs diff: Diffing tests/benchmarks
cvs diff: Diffing tests/debugger
cvs diff: Diffing tests/debugger/declarative
cvs diff: Diffing tests/dppd
cvs diff: Diffing tests/general
cvs diff: Diffing tests/general/accumulator
cvs diff: Diffing tests/general/string_format
cvs diff: Diffing tests/general/structure_reuse
cvs diff: Diffing tests/grade_subdirs
cvs diff: Diffing tests/hard_coded
cvs diff: Diffing tests/hard_coded/exceptions
cvs diff: Diffing tests/hard_coded/purity
cvs diff: Diffing tests/hard_coded/sub-modules
cvs diff: Diffing tests/hard_coded/typeclasses
cvs diff: Diffing tests/invalid
cvs diff: Diffing tests/invalid/purity
cvs diff: Diffing tests/misc_tests
cvs diff: Diffing tests/mmc_make
cvs diff: Diffing tests/mmc_make/lib
cvs diff: Diffing tests/recompilation
cvs diff: Diffing tests/tabling
cvs diff: Diffing tests/term
cvs diff: Diffing tests/valid
cvs diff: Diffing tests/warnings
cvs diff: Diffing tools
cvs diff: Diffing trace
cvs diff: Diffing util
cvs diff: Diffing vim
cvs diff: Diffing vim/after
cvs diff: Diffing vim/ftplugin
cvs diff: Diffing vim/syntax
--------------------------------------------------------------------------
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