[m-rev.] for review: --warn-non-tail-recursion
Fergus Henderson
fjh at cs.mu.OZ.AU
Tue Feb 12 00:58:58 AEDT 2002
Estimated hours taken: 2
Branches: main
Implement a new option `--warn-non-tail-recursion'.
compiler/ml_tailcall.m:
Add a pass to warn about directly recursive calls that are not
tail calls.
compiler/options.m:
doc/user_guide.texi:
Add a new option to enable the new pass.
compiler/mercury_compile.m:
Add code to invoke the new pass.
compiler/handle_options.m:
If --warn-non-tail-recursion is set, then report an error
if either --high-level-code or --optimize-tailcalls is not,
or if --error-check-only is set.
Workspace: /home/ceres/fjh/mercury
Index: compiler/handle_options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/handle_options.m,v
retrieving revision 1.128
diff -u -d -r1.128 handle_options.m
--- compiler/handle_options.m 11 Feb 2002 11:29:20 -0000 1.128
+++ compiler/handle_options.m 11 Feb 2002 13:41:14 -0000
@@ -809,6 +809,15 @@
% we are expecting some to be missing.
option_implies(use_opt_files, warn_missing_opt_files, bool(no)),
+ % --warn-non-tail-recursion requires both --high-level-code
+ % and --optimize-tailcalls. It also doesn't work if you use
+ % --errorcheck-only.
+ option_requires(warn_non_tail_recursion, highlevel_code, bool(yes),
+ "--warn-non-tail-recursion requires --high-level-code"),
+ option_requires(warn_non_tail_recursion, optimize_tailcalls, bool(yes),
+ "--warn-non-tail-recursion requires --optimize-tailcalls"),
+ option_requires(warn_non_tail_recursion, errorcheck_only, bool(no),
+ "--warn-non-tail-recursion is incompatible with --errorcheck-only"),
% The backend foreign languages depend on the target.
(
@@ -913,6 +922,23 @@
globals__io_lookup_bool_option(SourceOption, SourceOptionValue),
( { SourceOptionValue = no } ->
globals__io_set_option(ImpliedOption, ImpliedOptionValue)
+ ;
+ []
+ ).
+
+% option_requires(SourceBoolOption, RequiredOption, RequiredOptionValue,
+% ErrorMsg):
+% If the SourceBoolOption is set to yes, and RequiredOption is not set
+% to RequiredOptionValue, then report a usage error.
+:- pred option_requires(option::in, option::in, option_data::in,
+ string::in, io__state::di, io__state::uo) is det.
+
+option_requires(SourceOption, RequiredOption, RequiredOptionValue,
+ ErrorMessage) -->
+ globals__io_lookup_bool_option(SourceOption, SourceOptionValue),
+ globals__io_lookup_option(RequiredOption, OptionValue),
+ ( { SourceOptionValue = yes, OptionValue \= RequiredOptionValue } ->
+ usage_error(ErrorMessage)
;
[]
).
Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.231
diff -u -d -r1.231 mercury_compile.m
--- compiler/mercury_compile.m 11 Feb 2002 09:00:18 -0000 1.231
+++ compiler/mercury_compile.m 11 Feb 2002 13:33:38 -0000
@@ -61,7 +61,8 @@
:- import_module mark_static_terms. % HLDS -> HLDS
:- import_module mlds. % MLDS data structure
:- import_module ml_code_gen, rtti_to_mlds. % HLDS/RTTI -> MLDS
-:- import_module ml_elim_nested, ml_tailcall. % MLDS -> MLDS
+:- import_module ml_elim_nested. % MLDS -> MLDS
+:- import_module ml_tailcall. % MLDS -> MLDS
:- import_module ml_optimize. % MLDS -> MLDS
:- import_module mlds_to_c. % MLDS -> C
:- import_module mlds_to_java. % MLDS -> Java
@@ -3262,6 +3263,19 @@
),
maybe_report_stats(Stats),
mercury_compile__maybe_dump_mlds(MLDS20, "20", "tailcalls"),
+
+ % Warning about non-tail calls needs to come after detection
+ % of tail calls
+ globals__io_lookup_bool_option(warn_non_tail_recursion, WarnTailCalls),
+ ( { OptimizeTailCalls = yes, WarnTailCalls = yes } ->
+ maybe_write_string(Verbose,
+ "% Warning about non-tail recursive calls...\n"),
+ ml_warn_tailcalls(MLDS20),
+ maybe_write_string(Verbose, "% done.\n")
+ ;
+ []
+ ),
+ maybe_report_stats(Stats),
% run the ml_optimize pass before ml_elim_nested,
% so that we eliminate as many local variables as possible
Index: compiler/ml_tailcall.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ml_tailcall.m,v
retrieving revision 1.14
diff -u -d -r1.14 ml_tailcall.m
--- compiler/ml_tailcall.m 6 Feb 2002 18:44:19 -0000 1.14
+++ compiler/ml_tailcall.m 11 Feb 2002 13:30:16 -0000
@@ -11,6 +11,10 @@
% that marks function calls as tail calls whenever
% it is safe to do so, based on the assumptions described below.
+% This module also contains a pass over the MLDS that detects functions
+% which are directly recursive, but not tail-recursive,
+% and warns about them.
+
% A function call can safely be marked as a tail call if
% (1) it occurs in a position which would fall through into the
% end of the function body or to a `return' statement,
@@ -60,10 +64,17 @@
:- pred ml_mark_tailcalls(mlds, mlds, io__state, io__state).
:- mode ml_mark_tailcalls(in, out, di, uo) is det.
+ % Traverse the MLDS, warning about all directly recursive calls
+ % that are not marked as tail calls.
+ %
+:- pred ml_warn_tailcalls(mlds, io__state, io__state).
+:- mode ml_warn_tailcalls(in, di, uo) is det.
+
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
+:- import_module prog_data, hlds_out, error_util, ml_util.
:- import_module list, std_util.
ml_mark_tailcalls(MLDS0, MLDS) -->
@@ -543,6 +554,86 @@
Locals = params(Params),
list__member(Param, Params),
Param = mlds__argument(Name, _, _)
+ ).
+
+%-----------------------------------------------------------------------------%
+
+ml_warn_tailcalls(MLDS) -->
+ { solutions(nontailcall_in_mlds(MLDS), Warnings) },
+ list__foldl(report_nontailcall_warning, Warnings).
+
+:- type tailcall_warning ---> tailcall_warning(
+ mlds__pred_label,
+ % XXX perhaps we should also include the proc_id here
+ mlds__context
+ ).
+
+:- pred nontailcall_in_mlds(mlds::in, tailcall_warning::out) is nondet.
+nontailcall_in_mlds(MLDS, Warning) :-
+ MLDS = mlds(ModuleName, _ForeignCode, _Imports, Defns),
+ MLDS_ModuleName = mercury_module_name_to_mlds(ModuleName),
+ nontailcall_in_defns(MLDS_ModuleName, Defns, Warning).
+
+:- pred nontailcall_in_defns(mlds_module_name::in, mlds__defns::in,
+ tailcall_warning::out) is nondet.
+nontailcall_in_defns(ModuleName, Defns, Warning) :-
+ list__member(Defn, Defns),
+ nontailcall_in_defn(ModuleName, Defn, Warning).
+
+:- pred nontailcall_in_defn(mlds_module_name::in, mlds__defn::in,
+ tailcall_warning::out) is nondet.
+nontailcall_in_defn(ModuleName, Defn, Warning) :-
+ Defn = mlds__defn(Name, _Context, _Flags, DefnBody),
+ (
+ DefnBody = mlds__function(_PredProcId, _Params, FuncBody,
+ _Attributes),
+ FuncBody = defined_here(Body),
+ nontailcall_in_statement(ModuleName, Name, Body, Warning)
+ ;
+ DefnBody = mlds__class(ClassDefn),
+ ClassDefn = class_defn(_Kind, _Imports, _BaseClasses,
+ _Implements, CtorDefns, MemberDefns),
+ ( nontailcall_in_defns(ModuleName, CtorDefns, Warning)
+ ; nontailcall_in_defns(ModuleName, MemberDefns, Warning)
+ )
+ ).
+
+:- pred nontailcall_in_statement(mlds_module_name::in, mlds__entity_name::in,
+ mlds__statement::in, tailcall_warning::out) is nondet.
+
+nontailcall_in_statement(CallerModule, CallerFuncName, Statement, Warning) :-
+ % nondeterministically find a non-tail call
+ statement_contains_statement(Statement, SubStatement),
+ SubStatement = mlds__statement(SubStmt, Context),
+ SubStmt = call(_CallSig, Func, _This, _Args, _RetVals, IsTailCall),
+ IsTailCall = call,
+ % check if this call is a directly recursive call
+ Func = const(code_addr_const(CodeAddr)),
+ ( CodeAddr = proc(QualProcLabel, _Sig), MaybeSeqNum = no
+ ; CodeAddr = internal(QualProcLabel, SeqNum, _Sig),
+ MaybeSeqNum = yes(SeqNum)
+ ),
+ QualProcLabel = qual(CallerModule, PredLabel - ProcId),
+ CallerFuncName = function(PredLabel, ProcId, MaybeSeqNum, _PredId),
+ % if so, construct an appropriate warning
+ Warning = tailcall_warning(PredLabel, Context). % XXX include ProcId?
+
+:- pred report_nontailcall_warning(tailcall_warning::in,
+ io__state::di, io__state::uo) is det.
+
+report_nontailcall_warning(tailcall_warning(PredLabel, Context)) -->
+ (
+ { PredLabel = pred(PredOrFunc, _MaybeModule, Name, Arity,
+ _CodeModel, _NonOutputFunc) },
+ { hlds_out__simple_call_id_to_string(PredOrFunc -
+ unqualified(Name) / Arity, CallId) },
+ report_warning(mlds__get_prog_context(Context), 0, [
+ words("In "), fixed(CallId), nl,
+ words(" warning: recursive call is not tail recursive.")
+ ])
+ ;
+ { PredLabel = special_pred(_, _, _, _) }
+ % don't warn about these
).
%-----------------------------------------------------------------------------%
Index: compiler/options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/options.m,v
retrieving revision 1.354
diff -u -d -r1.354 options.m
--- compiler/options.m 11 Feb 2002 10:14:59 -0000 1.354
+++ compiler/options.m 11 Feb 2002 13:12:44 -0000
@@ -71,6 +71,7 @@
; warn_missing_module_name
; warn_wrong_module_name
; warn_smart_recompilation
+ ; warn_non_tail_recursion
% Verbosity options
; verbose
; very_verbose
@@ -566,7 +567,8 @@
warn_duplicate_calls - bool(no),
warn_missing_module_name - bool(yes),
warn_wrong_module_name - bool(yes),
- warn_smart_recompilation - bool(yes)
+ warn_smart_recompilation - bool(yes),
+ warn_non_tail_recursion - bool(no)
]).
option_defaults_2(verbosity_option, [
% Verbosity Options
@@ -1036,6 +1038,7 @@
long_option("warn-missing-module-name", warn_missing_module_name).
long_option("warn-wrong-module-name", warn_wrong_module_name).
long_option("warn-smart-recompilation", warn_smart_recompilation).
+long_option("warn-non-tail-recursion", warn_non_tail_recursion).
% verbosity options
long_option("verbose", verbose).
@@ -1929,7 +1932,10 @@
"\tDisable warnings for modules whose `:- module'",
"\tdeclaration does not match the module's file name.",
"--no-warn-smart-recompilation",
- "\tDisable warnings from the smart recompilation system."
+ "\tDisable warnings from the smart recompilation system.",
+ "--warn-non-tail-recursion",
+ "\tWarn about any directly recursive calls that are not tail calls.",
+ "\tThis requires --high-level-code."
]).
:- pred options_help_verbosity(io__state::di, io__state::uo) is det.
Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.291
diff -u -d -r1.291 user_guide.texi
--- doc/user_guide.texi 11 Feb 2002 10:15:00 -0000 1.291
+++ doc/user_guide.texi 11 Feb 2002 13:50:45 -0000
@@ -3549,9 +3549,15 @@
@sp 1
@item --no-warn-smart-recompilation
+ at findex --warn-smart-recompilation
@findex --no-warn-smart-recompilation
Disable warnings from the smart recompilation system.
+ at sp 1
+ at item --warn-non-tail-recursion
+ at findex --warn-non-tail-recursion
+Warn about any directly recursive calls that are not tail recursive.
+This option also requires @samp{--high-level-code}.
@end table
@node Verbosity options
--
Fergus Henderson <fjh at cs.mu.oz.au> | "I have always known that the pursuit
The University of Melbourne | of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp.
--------------------------------------------------------------------------
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