[m-rev.] for review: Make some compiler predicates tail recursive with LCMC.
Peter Wang
novalazy at gmail.com
Thu Oct 15 14:26:46 AEDT 2015
Alternatively we can enable --optimize-constructor-last-call for the whole of the
compiler directory. I think we should do that, but this is a smaller change.
The "lcmc" annotations are how I remind myself not to break the tail recursion
property. I can change them or delete them if they are too cryptic.
---
This prevents the compiler exhausting the stack on larger modules.
compiler/module_qual.m:
compiler/purity.m:
compiler/typecheck.m:
Make the LCMC opportunities more obvious to programmers
maintaining the code.
compiler/Mercury.options:
Enable --optimize-constructor-last-call for the preceding
modules.
---
compiler/Mercury.options | 9 ++++++++-
compiler/module_qual.m | 6 +++---
compiler/purity.m | 7 ++++---
compiler/typecheck.m | 8 +++++---
4 files changed, 20 insertions(+), 10 deletions(-)
diff --git a/compiler/Mercury.options b/compiler/Mercury.options
index 25e3411..28fa755 100644
--- a/compiler/Mercury.options
+++ b/compiler/Mercury.options
@@ -18,7 +18,14 @@ MCFLAGS-hlds.quantification = --optimize-unused-args
# Delete the code that computes information needed only in trace goals
# in the common case that the trace goals are not enabled.
-MCFLAGS-check_hlds.typecheck = --unneeded-code
+# typecheck_module_one_iteration should be tail recursive.
+MCFLAGS-check_hlds.typecheck = --unneeded-code --optimize-constructor-last-call
+
+# compute_goals_purity should be tail recursive.
+MCFLAGS-check_hlds.purity = --optimize-constructor-last-call
+
+# module_qualify_items_loop should be tail recursive.
+MCFLAGS-parse_tree.module_qual = --optimize-constructor-last-call
# In these files, some imports are needed only in some grades.
# Until unused_imports.m can avoid generating messages about these,
diff --git a/compiler/module_qual.m b/compiler/module_qual.m
index 5cab3cb..acac78a 100644
--- a/compiler/module_qual.m
+++ b/compiler/module_qual.m
@@ -816,10 +816,10 @@ module_qualify_items_in_src_item_blocks([SrcItemBlock0 | SrcItemBlocks0],
list(error_spec)::in, list(error_spec)::out) is det.
module_qualify_items_loop(_InInt, [], [], !Info, !Specs).
-module_qualify_items_loop(InInt, [Item0 | Items0], [Item | Items],
- !Info, !Specs) :-
+module_qualify_items_loop(InInt, [Item0 | Items0], Itemss, !Info, !Specs) :-
module_qualify_item(InInt, Item0, Item, !Info, !Specs),
- module_qualify_items_loop(InInt, Items0, Items, !Info, !Specs).
+ module_qualify_items_loop(InInt, Items0, Items, !Info, !Specs),
+ Itemss = [Item | Items]. % lcmc
% Call predicates to qualify a single item.
%
diff --git a/compiler/purity.m b/compiler/purity.m
index 75874e1..6ac92e6 100644
--- a/compiler/purity.m
+++ b/compiler/purity.m
@@ -613,12 +613,13 @@ update_purity_ct_in_goal_info(Purity, ContainsTrace, !GoalInfo) :-
purity_info::in, purity_info::out) is det.
compute_goals_purity([], [], !Purity, !ContainsTrace, !Info).
-compute_goals_purity([Goal0 | Goals0], [Goal | Goals], !Purity, !ContainsTrace,
- !Info) :-
+compute_goals_purity([Goal0 | Goals0], Goalss, !Purity, !ContainsTrace, !Info)
+ :-
compute_goal_purity(Goal0, Goal, GoalPurity, GoalContainsTrace, !Info),
!:Purity = worst_purity(GoalPurity, !.Purity),
!:ContainsTrace = worst_contains_trace(GoalContainsTrace, !.ContainsTrace),
- compute_goals_purity(Goals0, Goals, !Purity, !ContainsTrace, !Info).
+ compute_goals_purity(Goals0, Goals, !Purity, !ContainsTrace, !Info),
+ Goalss = [Goal | Goals]. % lcmc
:- pred compute_cases_purity(list(case)::in, list(case)::out,
purity::in, purity::out, contains_trace_goal::in, contains_trace_goal::out,
diff --git a/compiler/typecheck.m b/compiler/typecheck.m
index baffffd..bf1e82a 100644
--- a/compiler/typecheck.m
+++ b/compiler/typecheck.m
@@ -353,7 +353,7 @@ typecheck_report_max_iterations_exceeded(MaxIterations) = Spec :-
typecheck_module_one_iteration(_, _, [], [],
!NewlyInvalidPredIds, !Specs, !Changed).
typecheck_module_one_iteration(ModuleInfo, ValidPredIdSet,
- [PredIdInfo0 | PredIdsInfos0], [PredIdInfo | PredIdsInfos],
+ [PredIdInfo0 | PredIdsInfos0], PredIdInfoss,
!NewlyInvalidPredIds, !Specs, !Changed) :-
PredIdInfo0 = PredId - PredInfo0,
( if
@@ -366,7 +366,8 @@ typecheck_module_one_iteration(ModuleInfo, ValidPredIdSet,
PredIdInfo = PredIdInfo0,
typecheck_module_one_iteration(ModuleInfo, ValidPredIdSet,
PredIdsInfos0, PredIdsInfos, !NewlyInvalidPredIds,
- !Specs, !Changed)
+ !Specs, !Changed),
+ PredIdInfoss = [PredIdInfo | PredIdsInfos] % lcmc
else
% Potential parallelization site.
typecheck_pred_if_needed(ModuleInfo, PredId, PredInfo0, PredInfo,
@@ -399,7 +400,8 @@ typecheck_module_one_iteration(ModuleInfo, ValidPredIdSet,
bool.or(PredChanged, !Changed),
typecheck_module_one_iteration(ModuleInfo, ValidPredIdSet,
PredIdsInfos0, PredIdsInfos, !NewlyInvalidPredIds,
- !Specs, !Changed)
+ !Specs, !Changed),
+ PredIdInfoss = [PredIdInfo | PredIdsInfos] % lcmc
).
:- pred typecheck_pred_if_needed(module_info::in, pred_id::in,
--
2.1.2
More information about the reviews
mailing list