[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