[m-rev.] for review: Make modecheck_conj_list_flatten_and_schedule tail recursive.

Peter Wang novalazy at gmail.com
Thu Oct 15 14:28:25 AEDT 2015


compiler/modecheck_conj.m:
        Make modecheck_conj_list_flatten_and_schedule tail recursive
        by accumulating the list of successfully scheduled goals in
        reverse, then reversing the list at the end.

        Delete comment about two mutually recursive predicates; they were
        combined into modecheck_conj_list_flatten_and_schedule previously.
---
 compiler/modecheck_conj.m | 71 ++++++++++++++++++++++++-----------------------
 1 file changed, 37 insertions(+), 34 deletions(-)

diff --git a/compiler/modecheck_conj.m b/compiler/modecheck_conj.m
index b5d723c..66320aa 100644
--- a/compiler/modecheck_conj.m
+++ b/compiler/modecheck_conj.m
@@ -124,32 +124,35 @@ modecheck_conj_list(ConjType, Goals0, Goals, !ModeInfo) :-
 
 :- type impurity_errors == list(mode_error_info).
 
-    % Flatten conjunctions as we go, as long as they are of the same type.
-    % Call modecheck_conj_list_schedule to do the actual scheduling.
-    %
-    % NOTE: In some rare cases, when the compiler is compled in a in hlc grade
-    % and the conjunction is particularly large, the mutual recursion between
-    % modecheck_conj_list_flatten_and_schedule and modecheck_conj_list_schedule
-    % can exhaust the C stack, causing a core dump. This happens e.g. when
-    % compiling zm_enums.m in a compiler in which polymorphism's reuse of
-    % inserted typeinfo and related variables has been disabled.
+    % Schedule goals, and also flatten conjunctions of the same type as we go.
     %
 :- pred modecheck_conj_list_flatten_and_schedule(conj_type::in,
     list(hlds_goal)::in, list(hlds_goal)::out,
     impurity_errors::in, impurity_errors::out,
     mode_info::in, mode_info::out) is det.
 
-modecheck_conj_list_flatten_and_schedule(_ConjType, [], [],
-        !ImpurityErrors, !ModeInfo).
-modecheck_conj_list_flatten_and_schedule(ConjType, [Goal0 | Goals0], Goals,
+modecheck_conj_list_flatten_and_schedule(ConjType, Goals0, Goals,
         !ImpurityErrors, !ModeInfo) :-
+    modecheck_conj_list_flatten_and_schedule_acc(ConjType, Goals0,
+        [], RevGoals, !ImpurityErrors, !ModeInfo),
+    list.reverse(RevGoals, Goals).
+
+:- pred modecheck_conj_list_flatten_and_schedule_acc(conj_type::in,
+    list(hlds_goal)::in, list(hlds_goal)::in, list(hlds_goal)::out,
+    impurity_errors::in, impurity_errors::out,
+    mode_info::in, mode_info::out) is det.
+
+modecheck_conj_list_flatten_and_schedule_acc(_ConjType, [], !RevGoals,
+        !ImpurityErrors, !ModeInfo).
+modecheck_conj_list_flatten_and_schedule_acc(ConjType, [Goal0 | Goals0],
+        !RevGoals, !ImpurityErrors, !ModeInfo) :-
     ( if
         Goal0 = hlds_goal(conj(plain_conj, ConjGoals), _),
         ConjType = plain_conj
     then
         Goals1 = ConjGoals ++ Goals0,
-        modecheck_conj_list_flatten_and_schedule(ConjType, Goals1, Goals,
-            !ImpurityErrors, !ModeInfo)
+        modecheck_conj_list_flatten_and_schedule_acc(ConjType, Goals1,
+            !RevGoals, !ImpurityErrors, !ModeInfo)
     else
         % We attempt to schedule the first goal in the conjunction.
         % If successful, we try to wake up pending goals (if any), and if not,
@@ -211,6 +214,23 @@ modecheck_conj_list_flatten_and_schedule(ConjType, [Goal0 | Goals0], Goals,
             mode_info_get_delay_info(!.ModeInfo, DelayInfo1)
         ),
 
+        reverse_prepend(ScheduledSolverGoals, !RevGoals),
+        (
+            Errors = [],
+            % We successfully scheduled this goal, so insert it
+            % in the list of successfully scheduled goals.
+            % We flatten out conjunctions if we can. They can arise
+            % when Goal0 was a scope(from_ground_term, _) goal.
+            ( if Goal = hlds_goal(conj(ConjType, SubGoals), _) then
+                reverse_prepend(SubGoals, !RevGoals)
+            else
+                cons(Goal, !RevGoals)
+            )
+        ;
+            Errors = [_ | _]
+            % We delayed this goal -- it will be stored in the delay_info.
+        ),
+
         % Next, we attempt to wake up any pending goals, and then continue
         % scheduling the rest of the goal.
         delay_info_wakeup_goals(WokenGoals, DelayInfo1, DelayInfo),
@@ -230,28 +250,11 @@ modecheck_conj_list_flatten_and_schedule(ConjType, [Goal0 | Goals0], Goals,
             % We should not mode-analyse the remaining goals, since they are
             % unreachable. Instead we optimize them away, so that later passes
             % won't complain about them not having mode information.
-            mode_info_remove_goals_live_vars(Goals1, !ModeInfo),
-            Goals2  = []
+            mode_info_remove_goals_live_vars(Goals1, !ModeInfo)
         else
             % The remaining goals may still need to be flattened.
-            modecheck_conj_list_flatten_and_schedule(ConjType, Goals1, Goals2,
-                !ImpurityErrors, !ModeInfo)
-        ),
-        (
-            Errors = [_ | _],
-            % We delayed this goal -- it will be stored in the delay_info.
-            Goals = ScheduledSolverGoals ++ Goals2
-        ;
-            Errors = [],
-            % We successfully scheduled this goal, so insert it
-            % in the list of successfully scheduled goals.
-            % We flatten out conjunctions if we can. They can arise
-            % when Goal0 was a scope(from_ground_term, _) goal.
-            ( if Goal = hlds_goal(conj(ConjType, SubGoals), _) then
-                Goals = ScheduledSolverGoals ++ SubGoals ++ Goals2
-            else
-                Goals = ScheduledSolverGoals ++ [Goal | Goals2]
-            )
+            modecheck_conj_list_flatten_and_schedule_acc(ConjType, Goals1,
+                !RevGoals, !ImpurityErrors, !ModeInfo)
         )
     ).
 
-- 
2.1.2




More information about the reviews mailing list