[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