[m-rev.] for review: --warn-non-tail-recursion
Peter Ross
peter.ross at miscrit.be
Tue Feb 12 19:30:10 AEDT 2002
On Tue, Feb 12, 2002 at 12:58:58AM +1100, Fergus Henderson wrote:
> 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/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
> + ).
Well as I see it the advantage of including the proc_id is that it would
allow one to report which mode is non tail recursive. I think this
would be useful information as not all modes of a procedure will be tail
recursive. So I suggest that you do it.
> +
> +:- 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
> ).
>
> %-----------------------------------------------------------------------------%
Apart from the comment about the proc_id, this looks fine and I know
there have been times I would have found it useful.
--------------------------------------------------------------------------
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