[m-dev.] for review: make tailcall loops an MLDS transformation
Tyson Dowd
trd at cs.mu.OZ.AU
Tue Aug 22 13:31:27 AEST 2000
Hi,
Another .NET backend change.
Fergus will probably want to look at this one.
===================================================================
Estimated hours taken: 5
Do the transformation of self-tailcalls into loops as an MLDS->MLDS
transformation (instead of during mlds_to_c.m). Both the IL and C
backends for MLDS use this transformation.
Also, we transform into label/goto instead of for/continue. This is
because IL doesn't have a for/continue construct. It may be worth
revisiting this decision in future and performing benchmarks.
compiler/mercury_compile.m:
Add an optimization phase to the MLDS end of the compiler.
compiler/ml_optimize.m:
New file that performs MLDS->MLDS optimizations such as turning
self-tail calls into loops.
compiler/ml_tailcall.m:
Use ml_util.
compiler/ml_util.m:
New file containing generic MLDS utilities.
Contents are can_optimize_tailcall and statements_contain_statements.
This code was in mlds_to_c but will be used by more than just
this backend.
compiler/mlds_to_c.m:
Delete old tailcall transformation code (it is either moved into
ml_optimize, ml_util or it is no longer needed).
Only handle general tailcalls.
Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.171
diff -u -r1.171 mercury_compile.m
--- compiler/mercury_compile.m 2000/08/11 08:19:12 1.171
+++ compiler/mercury_compile.m 2000/08/21 01:50:42
@@ -64,6 +64,7 @@
:- 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_optimize. % MLDS -> MLDS
:- import_module mlds_to_c. % MLDS -> C
% miscellaneous compiler modules
@@ -2376,7 +2377,13 @@
maybe_report_stats(Stats),
mercury_compile__maybe_dump_mlds(MLDS30, "30", "nested_funcs"),
- { MLDS = MLDS30 },
+ maybe_write_string(Verbose, "% Optimizing MLDS...\n"),
+ ml_optimize__optimize(MLDS30, MLDS40),
+ maybe_write_string(Verbose, "% done.\n"),
+ maybe_report_stats(Stats),
+ mercury_compile__maybe_dump_mlds(MLDS40, "40", "optimize"),
+
+ { MLDS = MLDS40 },
mercury_compile__maybe_dump_mlds(MLDS, "99", "final").
:- pred mercury_compile__mlds_gen_rtti_data(module_info, mlds, mlds).
Index: compiler/ml_optimize.m
===================================================================
RCS file: ml_optimize.m
diff -N ml_optimize.m
--- /dev/null Tue May 16 14:50:59 2000
+++ ml_optimize.m Mon Aug 21 14:42:48 2000
@@ -0,0 +1,288 @@
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2000 The University of Melbourne.
+% This file may only be copied under the terms of the GNU General
+% Public License - see the file COPYING in the Mercury distribution.
+%-----------------------------------------------------------------------------%
+
+% File: ml_optimize.m
+% Main author: trd, fjh
+
+% This module runs various optimizations on the MLDS.
+%
+% Currently the only optimization is turning tailcalls into loops.
+%
+% Note that tailcall detection is done in ml_tailcall.m.
+% It might be nice to move the detection here, and do both the
+% loop transformation (in the case of self-tailcalls) and marking
+% tailcalls at the same time.
+%
+% It would probably be a good idea to make this transformation optional.
+% Previously it depended on emit_c_loops, but this is a bit misleading
+% given the documentation of emit_c_loops.
+
+%-----------------------------------------------------------------------------%
+
+:- module ml_optimize.
+:- interface.
+
+:- import_module mlds, io.
+
+:- pred optimize(mlds, mlds, io__state, io__state).
+:- mode optimize(in, out, di, uo) is det.
+
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module bool, list, require, std_util, string.
+:- import_module builtin_ops, globals.
+:- import_module ml_util, ml_code_util.
+
+:- type opt_info --->
+ opt_info(
+ globals :: globals,
+ module_name :: mlds_module_name,
+ entity_name :: mlds__entity_name,
+ func_params :: mlds__func_params,
+ context :: mlds__context
+ ).
+
+ % The label name we use for the top of the loop introduced by
+ % tailcall optimization.
+:- func tailcall_loop_label_name = string.
+tailcall_loop_label_name = "looptop".
+
+optimize(MLDS0, MLDS) -->
+ globals__io_get_globals(Globals),
+ { MLDS0 = mlds(ModuleName, ForeignCode, Imports, Defns0) },
+ { Defns = optimize_in_defns(Defns0, Globals,
+ mercury_module_name_to_mlds(ModuleName)) },
+ { MLDS = mlds(ModuleName, ForeignCode, Imports, Defns) }.
+
+:- func optimize_in_defns(mlds__defns, globals, mlds_module_name)
+ = mlds__defns.
+optimize_in_defns(Defns, Globals, ModuleName) =
+ list__map(optimize_in_defn(ModuleName, Globals), Defns).
+
+:- func optimize_in_defn(mlds_module_name, globals, mlds__defn) = mlds__defn.
+optimize_in_defn(ModuleName, Globals, Defn0) = Defn :-
+ Defn0 = mlds__defn(Name, Context, Flags, DefnBody0),
+ (
+ DefnBody0 = mlds__function(PredProcId, Params, FuncBody0),
+ OptInfo = opt_info(Globals, ModuleName, Name, Params, Context),
+
+ FuncBody1 = optimize_func(OptInfo, FuncBody0),
+ FuncBody = optimize_in_maybe_statement(OptInfo, FuncBody1),
+
+ DefnBody = mlds__function(PredProcId, Params, FuncBody),
+ Defn = mlds__defn(Name, Context, Flags, DefnBody)
+ ;
+ DefnBody0 = mlds__data(_, _),
+ Defn = Defn0
+ ;
+ DefnBody0 = mlds__class(ClassDefn0),
+ ClassDefn0 = class_defn(Kind, Imports, BaseClasses, Implements,
+ MemberDefns0),
+ MemberDefns = optimize_in_defns(MemberDefns0, Globals,
+ ModuleName),
+ ClassDefn = class_defn(Kind, Imports, BaseClasses, Implements,
+ MemberDefns),
+ DefnBody = mlds__class(ClassDefn),
+ Defn = mlds__defn(Name, Context, Flags, DefnBody)
+ ).
+
+:- func optimize_in_maybe_statement(opt_info,
+ maybe(mlds__statement)) = maybe(mlds__statement).
+
+optimize_in_maybe_statement(_, no) = no.
+optimize_in_maybe_statement(OptInfo, yes(Statement0)) = yes(Statement) :-
+ Statement = optimize_in_statement(OptInfo, Statement0).
+
+:- func optimize_in_statements(opt_info, list(mlds__statement)) =
+ (list(mlds__statement)).
+
+optimize_in_statements(OptInfo, Statements) =
+ list__map(optimize_in_statement(OptInfo), Statements).
+
+:- func optimize_in_statement(opt_info, mlds__statement) =
+ (mlds__statement).
+
+optimize_in_statement(OptInfo, statement(Stmt, Context)) =
+ statement(optimize_in_stmt(OptInfo ^ context := Context, Stmt),
+ Context).
+
+:- func optimize_in_stmt(opt_info, mlds__stmt) = (mlds__stmt).
+
+optimize_in_stmt(OptInfo, Stmt0) = Stmt :-
+ (
+ Stmt0 = call(_, _, _, _, _, _),
+ Stmt = optimize_in_call_stmt(OptInfo, Stmt0)
+ ;
+ Stmt0 = block(Defns, Statements0),
+ Stmt = block(Defns, optimize_in_statements(OptInfo,
+ Statements0))
+ ;
+ Stmt0 = while(Rval, Statement0, Once),
+ Stmt = while(Rval, optimize_in_statement(OptInfo,
+ Statement0), Once)
+ ;
+ Stmt0 = if_then_else(Rval, Then, MaybeElse),
+ Stmt = if_then_else(Rval,
+ optimize_in_statement(OptInfo, Then),
+ maybe_apply(optimize_in_statement(OptInfo), MaybeElse))
+ ;
+ Stmt0 = do_commit(_),
+ Stmt = Stmt0
+ ;
+ Stmt0 = return(_),
+ Stmt = Stmt0
+ ;
+ Stmt0 = try_commit(Ref, TryGoal, HandlerGoal),
+ Stmt = try_commit(Ref,
+ optimize_in_statement(OptInfo, TryGoal),
+ optimize_in_statement(OptInfo, HandlerGoal))
+ ;
+ Stmt0 = label(_Label),
+ Stmt = Stmt0
+ ;
+ Stmt0 = goto(_Label),
+ Stmt = Stmt0
+ ;
+ Stmt0 = computed_goto(_Rval, _Label),
+ Stmt = Stmt0
+ ;
+ Stmt0 = atomic(_Atomic),
+ Stmt = Stmt0
+ ).
+
+:- func optimize_in_call_stmt(opt_info, mlds__stmt) = (mlds__stmt).
+
+optimize_in_call_stmt(OptInfo, Stmt0) = Stmt :-
+ % If we have a self-tailcall, assign to the arguments and
+ % then goto the top of the tailcall loop.
+ (
+ Stmt0 = call(_Signature, _FuncRval, _MaybeObject, CallArgs,
+ _Results, _IsTailCall),
+ can_optimize_tailcall(qual(OptInfo ^ module_name,
+ OptInfo ^ entity_name), Stmt0)
+ ->
+ CommentStatement = statement(
+ atomic(comment("direct tailcall eliminated")),
+ OptInfo ^ context),
+ GotoStatement = statement(goto(tailcall_loop_label_name),
+ OptInfo ^ context),
+ OptInfo ^ func_params = mlds__func_params(FuncArgs, _RetTypes),
+ generate_assign_args(OptInfo, FuncArgs, CallArgs,
+ AssignStatements, AssignDefns),
+ AssignVarsStatement = statement(block(AssignDefns,
+ AssignStatements), OptInfo ^ context),
+
+ CallReplaceStatements = [
+ CommentStatement,
+ AssignVarsStatement,
+ GotoStatement
+ ],
+ Stmt = block([], CallReplaceStatements)
+ ;
+ Stmt = Stmt0
+ ).
+
+%----------------------------------------------------------------------------
+
+ % Generate assigments of new values to a list of arguments.
+
+:- pred generate_assign_args(opt_info, mlds__arguments, list(mlds__rval),
+ list(mlds__statement), list(mlds__defn)).
+:- mode generate_assign_args(in, in, in, out, out) is det.
+
+generate_assign_args(_, [_|_], [], [], []) :-
+ error("generate_assign_args: length mismatch").
+generate_assign_args(_, [], [_|_], [], []) :-
+ error("generate_assign_args: length mismatch").
+generate_assign_args(_, [], [], [], []).
+generate_assign_args(OptInfo,
+ [Name - Type | Rest], [Arg | Args], Statements, TempDefns) :-
+ (
+ Name = data(var(VarName))
+ ->
+ QualVarName = qual(OptInfo ^ module_name, VarName),
+ (
+ %
+ % don't bother assigning a variable to itself
+ %
+ Arg = lval(var(QualVarName))
+ ->
+ generate_assign_args(OptInfo, Rest, Args,
+ Statements, TempDefns)
+ ;
+
+ % The temporaries are needed for the case where
+ % we are e.g. assigning v1, v2 to v2, v1;
+ % they ensure that we don't try to reference the old
+ % value of a parameter after it has already been
+ % clobbered by the new value.
+
+ string__append(VarName, "__tmp_copy", TempName),
+ QualTempName = qual(OptInfo ^ module_name,
+ TempName),
+ Initializer = init_obj(Arg),
+ TempDefn = ml_gen_mlds_var_decl(var(TempName),
+ Type, Initializer, OptInfo ^ context),
+
+ Statement = statement(
+ atomic(assign(
+ var(QualVarName),
+ lval(var(QualTempName)))),
+ OptInfo ^ context),
+ generate_assign_args(OptInfo, Rest, Args, Statements0,
+ TempDefns0),
+ Statements = [Statement | Statements0],
+ TempDefns = [TempDefn | TempDefns0]
+ )
+ ;
+ error("generate_assign_args: function param is not a var")
+ ).
+
+%----------------------------------------------------------------------------
+
+:- func optimize_func(opt_info, maybe(mlds__statement))
+ = maybe(mlds__statement).
+
+optimize_func(OptInfo, MaybeStatement) =
+ maybe_apply(optimize_func_stmt(OptInfo), MaybeStatement).
+
+
+:- func optimize_func_stmt(opt_info,
+ mlds__statement) = (mlds__statement).
+
+optimize_func_stmt(OptInfo, mlds__statement(Stmt0, Context)) =
+ mlds__statement(Stmt, Context) :-
+
+ % Tailcall optimization -- if we do a self tailcall, we
+ % can turn it into a loop.
+ (
+ stmt_contains_statement(Stmt0, Call),
+ Call = mlds__statement(CallStmt, _),
+ can_optimize_tailcall(
+ qual(OptInfo ^ module_name, OptInfo ^ entity_name),
+ CallStmt)
+ ->
+ Comment = atomic(comment("tailcall optimized into a loop")),
+ Label = label(tailcall_loop_label_name),
+ Stmt = block([], [statement(Comment, Context),
+ statement(Label, Context),
+ statement(Stmt0, Context)])
+ ;
+ Stmt = Stmt0
+ ).
+
+
+
+ % Maps T into V, inside a maybe .
+:- func maybe_apply(func(T) = V, maybe(T)) = maybe(V).
+
+maybe_apply(_, no) = no.
+maybe_apply(F, yes(T)) = yes(F(T)).
+
+
+
Index: compiler/ml_tailcall.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ml_tailcall.m,v
retrieving revision 1.2
diff -u -r1.2 ml_tailcall.m
--- compiler/ml_tailcall.m 2000/03/30 05:41:50 1.2
+++ compiler/ml_tailcall.m 2000/08/14 01:37:38
@@ -57,6 +57,7 @@
:- implementation.
:- import_module list, std_util.
+:- import_module ml_util.
ml_mark_tailcalls(MLDS0, MLDS) -->
{ MLDS0 = mlds(ModuleName, ForeignCode, Imports, Defns0) },
Index: compiler/ml_util.m
===================================================================
RCS file: ml_util.m
diff -N ml_util.m
--- /dev/null Tue May 16 14:50:59 2000
+++ ml_util.m Mon Aug 14 11:37:33 2000
@@ -0,0 +1,141 @@
+%-----------------------------------------------------------------------------%
+% Copyright (C) 1999-2000 The University of Melbourne.
+% This file may only be copied under the terms of the GNU General
+% Public License - see the file COPYING in the Mercury distribution.
+%-----------------------------------------------------------------------------%
+
+% File: ml_util.m
+% Main author: fjh, trd
+
+% This module contains utility predicates for manipulating the MLDS.
+
+%-----------------------------------------------------------------------------%
+
+:- module ml_util.
+:- interface.
+
+:- import_module mlds.
+
+%-----------------------------------------------------------------------------%
+%
+% Various utility routines used for MLDS manipulation.
+%
+
+ % return `true' if the statement is a tail call which
+ % can be optimized into a jump back to the start of the
+ % function
+:- pred can_optimize_tailcall(mlds__qualified_entity_name, mlds__stmt).
+:- mode can_optimize_tailcall(in, in) is semidet.
+
+
+ % nondeterministically generates sub-statements from statements.
+:- pred statements_contains_statement(mlds__statements, mlds__statement).
+:- mode statements_contains_statement(in, out) is nondet.
+
+:- pred statement_contains_statement(mlds__statement, mlds__statement).
+:- mode statement_contains_statement(in, out) is multi.
+
+:- pred stmt_contains_statement(mlds__stmt, mlds__statement).
+:- mode stmt_contains_statement(in, out) is nondet.
+
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module bool, list, std_util.
+
+can_optimize_tailcall(Name, Call) :-
+ Call = call(_Signature, FuncRval, MaybeObject, _CallArgs,
+ _Results, IsTailCall),
+ %
+ % check if this call can be optimized as a tail call
+ %
+ IsTailCall = tail_call,
+
+ %
+ % check if the callee adddress is the same as
+ % the caller
+ %
+ FuncRval = const(code_addr_const(CodeAddr)),
+ (
+ CodeAddr = proc(QualifiedProcLabel, _Sig),
+ MaybeSeqNum = no
+ ;
+ CodeAddr = internal(QualifiedProcLabel, SeqNum, _Sig),
+ MaybeSeqNum = yes(SeqNum)
+ ),
+ QualifiedProcLabel = qual(ModuleName, PredLabel - ProcId),
+ % check that the module name matches
+ Name = qual(ModuleName, FuncName),
+ % check that the PredLabel, ProcId, and MaybeSeqNum match
+ FuncName = function(PredLabel, ProcId, MaybeSeqNum, _),
+
+ %
+ % In C++, `this' is a constant, so our usual technique
+ % of assigning the arguments won't work if it is a
+ % member function. Thus we don't do this optimization
+ % if we're optimizing a member function call
+ %
+ MaybeObject = no.
+
+
+
+statements_contains_statement(Statements, SubStatement) :-
+ list__member(Statement, Statements),
+ statement_contains_statement(Statement, SubStatement).
+
+:- pred maybe_statement_contains_statement(maybe(mlds__statement), mlds__statement).
+:- mode maybe_statement_contains_statement(in, out) is nondet.
+
+maybe_statement_contains_statement(no, _Statement) :- fail.
+maybe_statement_contains_statement(yes(Statement), SubStatement) :-
+ statement_contains_statement(Statement, SubStatement).
+
+
+statement_contains_statement(Statement, Statement).
+statement_contains_statement(Statement, SubStatement) :-
+ Statement = mlds__statement(Stmt, _Context),
+ stmt_contains_statement(Stmt, SubStatement).
+
+
+stmt_contains_statement(Stmt, SubStatement) :-
+ (
+ Stmt = block(_Defns, Statements),
+ statements_contains_statement(Statements, SubStatement)
+ ;
+ Stmt = while(_Rval, Statement, _Once),
+ statement_contains_statement(Statement, SubStatement)
+ ;
+ Stmt = if_then_else(_Cond, Then, MaybeElse),
+ ( statement_contains_statement(Then, SubStatement)
+ ; maybe_statement_contains_statement(MaybeElse, SubStatement)
+ )
+ ;
+ Stmt = label(_Label),
+ fail
+ ;
+ Stmt = goto(_),
+ fail
+ ;
+ Stmt = computed_goto(_Rval, _Labels),
+ fail
+ ;
+ Stmt = call(_Sig, _Func, _Obj, _Args, _RetLvals, _TailCall),
+ fail
+ ;
+ Stmt = return(_Rvals),
+ fail
+ ;
+ Stmt = do_commit(_Ref),
+ fail
+ ;
+ Stmt = try_commit(_Ref, Statement, Handler),
+ ( statement_contains_statement(Statement, SubStatement)
+ ; statement_contains_statement(Handler, SubStatement)
+ )
+ ;
+ Stmt = atomic(_AtomicStmt),
+ fail
+ ).
+
+%-----------------------------------------------------------------------------%
Index: compiler/mlds_to_c.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds_to_c.m,v
retrieving revision 1.51
diff -u -r1.51 mlds_to_c.m
--- compiler/mlds_to_c.m 2000/08/11 03:15:35 1.51
+++ compiler/mlds_to_c.m 2000/08/14 05:01:44
@@ -1170,59 +1170,8 @@
{ FuncInfo = func_info(Name, Signature) },
mlds_maybe_output_time_profile_instr(Context, Indent + 1, Name),
- %
- % If the procedure body contains any optimizable tailcalls,
- % we wrap the function body inside a `for(;;)' loop
- % so that we can use `continue;' inside the function body
- % to optimize tail recursive calls.
- %
- globals__io_lookup_bool_option(emit_c_loops, Emit_C_Loops),
- (
- { Emit_C_Loops = yes },
- { statement_contains_statement(Body, Call) },
- { Call = mlds__statement(CallStmt, _) },
- { can_optimize_tailcall(FuncInfo, CallStmt) }
- ->
- mlds_indent(Context, Indent + 1),
- io__write_string("for(;;)\n"),
- mlds_indent(Context, Indent + 2),
- io__write_string("{\n"),
- { Indent2 = Indent + 2 }
- ;
- { Indent2 = Indent }
- ),
-
- mlds_output_statement(Indent2 + 1, FuncInfo, Body),
+ mlds_output_statement(Indent + 1, FuncInfo, Body),
- %
- % Output a `return' statement to terminate the `for(;;)' loop.
- % This should only be necessary for functions with no
- % return values; for functions with return values,
- % the function body should never just fall through,
- % instead it must always return via a `return' statement.
- %
- { Signature = mlds__func_params(_Parameters, RetTypes) },
- ( { RetTypes = [] } ->
- mlds_output_stmt(Indent2 + 1, FuncInfo, return([]),
- Context)
- ;
- globals__io_lookup_bool_option(auto_comments, Comments),
- ( { Comments = yes } ->
- mlds_indent(Context, Indent2 + 1),
- io__write_string("/*NOTREACHED*/\n")
- ;
- []
- )
- ),
-
- ( { Indent2 = Indent + 2 } ->
- % end the `for(;;)'
- mlds_indent(Context, Indent2),
- io__write_string("}\n")
- ;
- []
- ),
-
mlds_indent(Context, Indent),
io__write_string("}\n") % end the function
).
@@ -1902,93 +1851,62 @@
mlds_output_stmt(Indent, CallerFuncInfo, Call, Context) -->
{ Call = call(_Signature, FuncRval, MaybeObject, CallArgs,
Results, IsTailCall) },
+ { CallerFuncInfo = func_info(Name, _Params) },
%
- % Optimize directly-recursive tail calls
+ % Optimize general tail calls.
+ % We can't really do much here except to insert `return'
+ % as an extra hint to the C compiler.
+ % XXX these optimizations should be disable-able
+ %
+ % If Results = [], i.e. the function has `void' return type,
+ % then this would result in code that is not legal ANSI C
+ % (although it _is_ legal in GNU C and in C++),
+ % so for that case, we put the return statement after
+ % the call -- see below. We need to enclose it inside
+ % an extra pair of curly braces in case this `call'
+ % is e.g. inside an if-then-else.
%
- { CallerFuncInfo = func_info(Name, Params) },
- globals__io_lookup_bool_option(emit_c_loops, Emit_C_Loops),
- (
- { Emit_C_Loops = yes },
- { can_optimize_tailcall(CallerFuncInfo, Call) }
- ->
- mlds_indent(Indent),
- io__write_string("{\n"),
- globals__io_lookup_bool_option(auto_comments, Comments),
- ( { Comments = yes } ->
- mlds_indent(Context, Indent + 1),
- io__write_string("/* tail recursive call */\n")
- ;
- []
- ),
- { Name = qual(ModuleName, _) },
- { Params = mlds__func_params(FuncArgs, _RetTypes) },
- mlds_output_assign_args(Indent + 1, ModuleName, Context,
- FuncArgs, CallArgs),
- mlds_indent(Context, Indent + 1),
- ( { Comments = yes } ->
- io__write_string("continue; /* go to start of function */\n")
- ;
- io__write_string("continue;\n")
- ),
- mlds_indent(Context, Indent),
- io__write_string("}\n")
- ;
- %
- % Optimize general tail calls.
- % We can't really do much here except to insert `return'
- % as an extra hint to the C compiler.
- % XXX these optimizations should be disable-able
- %
- % If Results = [], i.e. the function has `void' return type,
- % then this would result in code that is not legal ANSI C
- % (although it _is_ legal in GNU C and in C++),
- % so for that case, we put the return statement after
- % the call -- see below. We need to enclose it inside
- % an extra pair of curly braces in case this `call'
- % is e.g. inside an if-then-else.
- %
- mlds_indent(Indent),
- io__write_string("{\n"),
+ mlds_indent(Indent),
+ io__write_string("{\n"),
- mlds_maybe_output_call_profile_instr(Context,
- Indent + 1, FuncRval, Name),
+ mlds_maybe_output_call_profile_instr(Context,
+ Indent + 1, FuncRval, Name),
- mlds_indent(Context, Indent + 1),
+ mlds_indent(Context, Indent + 1),
- ( { IsTailCall = tail_call, Results \= [] } ->
- io__write_string("return ")
- ;
- []
- ),
- ( { MaybeObject = yes(Object) } ->
- mlds_output_bracketed_rval(Object),
- io__write_string(".") % XXX should this be "->"?
- ;
- []
- ),
- ( { Results = [] } ->
- []
- ; { Results = [Lval] } ->
- mlds_output_lval(Lval),
- io__write_string(" = ")
- ;
- { error("mld_output_stmt: multiple return values") }
- ),
- mlds_output_bracketed_rval(FuncRval),
- io__write_string("("),
- io__write_list(CallArgs, ", ", mlds_output_rval),
- io__write_string(");\n"),
+ ( { IsTailCall = tail_call, Results \= [] } ->
+ io__write_string("return ")
+ ;
+ []
+ ),
+ ( { MaybeObject = yes(Object) } ->
+ mlds_output_bracketed_rval(Object),
+ io__write_string(".") % XXX should this be "->"?
+ ;
+ []
+ ),
+ ( { Results = [] } ->
+ []
+ ; { Results = [Lval] } ->
+ mlds_output_lval(Lval),
+ io__write_string(" = ")
+ ;
+ { error("mld_output_stmt: multiple return values") }
+ ),
+ mlds_output_bracketed_rval(FuncRval),
+ io__write_string("("),
+ io__write_list(CallArgs, ", ", mlds_output_rval),
+ io__write_string(");\n"),
- ( { IsTailCall = tail_call, Results = [] } ->
- mlds_indent(Context, Indent + 1),
- io__write_string("return;\n")
- ;
- mlds_maybe_output_time_profile_instr(Context,
- Indent + 1, Name)
- ),
- mlds_indent(Indent),
- io__write_string("}\n")
- ).
+ ( { IsTailCall = tail_call, Results = [] } ->
+ mlds_indent(Context, Indent + 1),
+ io__write_string("return;\n")
+ ;
+ mlds_maybe_output_time_profile_instr(Context,
+ Indent + 1, Name)
+ ),
+ mlds_indent(Indent),
+ io__write_string("}\n").
mlds_output_stmt(Indent, _FuncInfo, return(Results), _) -->
mlds_indent(Indent),
@@ -2193,47 +2111,6 @@
SymName = qualified(unqualified("mercury"), "private_builtin"),
PredLabel = pred(predicate, _, "unsafe_type_cast", 2).
- % return `true' if the statement is a tail call which
- % can be optimized into a jump back to the start of the
- % function
-:- pred can_optimize_tailcall(func_info, mlds__stmt).
-:- mode can_optimize_tailcall(in, in) is semidet.
-can_optimize_tailcall(CallerFuncInfo, Call) :-
- Call = call(_Signature, FuncRval, MaybeObject, _CallArgs,
- _Results, IsTailCall),
- CallerFuncInfo = func_info(Name, _Params),
- %
- % check if this call can be optimized as a tail call
- %
- IsTailCall = tail_call,
-
- %
- % check if the callee adddress is the same as
- % the caller
- %
- FuncRval = const(code_addr_const(CodeAddr)),
- (
- CodeAddr = proc(QualifiedProcLabel, _Sig),
- MaybeSeqNum = no
- ;
- CodeAddr = internal(QualifiedProcLabel, SeqNum, _Sig),
- MaybeSeqNum = yes(SeqNum)
- ),
- QualifiedProcLabel = qual(ModuleName, PredLabel - ProcId),
- % check that the module name matches
- Name = qual(ModuleName, FuncName),
- % check that the PredLabel, ProcId, and MaybeSeqNum match
- FuncName = function(PredLabel, ProcId, MaybeSeqNum, _),
-
- %
- % In C++, `this' is a constant, so our usual technique
- % of assigning the arguments won't work if it is a
- % member function. Thus we don't do this optimization
- % if we're optimizing a member function call
- %
- MaybeObject = no.
-
-
% Assign the specified list of rvals to the arguments.
% This is used as part of tail recursion optimization (see above).
:- pred mlds_output_assign_args(indent, mlds_module_name, mlds__context,
@@ -2977,73 +2854,6 @@
;
io__write_string(" "),
mlds_indent(N - 1)
- ).
-
-%-----------------------------------------------------------------------------%
-
-:- pred statements_contains_statement(mlds__statements, mlds__statement).
-:- mode statements_contains_statement(in, out) is nondet.
-
-statements_contains_statement(Statements, SubStatement) :-
- list__member(Statement, Statements),
- statement_contains_statement(Statement, SubStatement).
-
-:- pred maybe_statement_contains_statement(maybe(mlds__statement), mlds__statement).
-:- mode maybe_statement_contains_statement(in, out) is nondet.
-
-maybe_statement_contains_statement(no, _Statement) :- fail.
-maybe_statement_contains_statement(yes(Statement), SubStatement) :-
- statement_contains_statement(Statement, SubStatement).
-
-:- pred statement_contains_statement(mlds__statement, mlds__statement).
-:- mode statement_contains_statement(in, out) is multi.
-
-statement_contains_statement(Statement, Statement).
-statement_contains_statement(Statement, SubStatement) :-
- Statement = mlds__statement(Stmt, _Context),
- stmt_contains_statement(Stmt, SubStatement).
-
-:- pred stmt_contains_statement(mlds__stmt, mlds__statement).
-:- mode stmt_contains_statement(in, out) is nondet.
-
-stmt_contains_statement(Stmt, SubStatement) :-
- (
- Stmt = block(_Defns, Statements),
- statements_contains_statement(Statements, SubStatement)
- ;
- Stmt = while(_Rval, Statement, _Once),
- statement_contains_statement(Statement, SubStatement)
- ;
- Stmt = if_then_else(_Cond, Then, MaybeElse),
- ( statement_contains_statement(Then, SubStatement)
- ; maybe_statement_contains_statement(MaybeElse, SubStatement)
- )
- ;
- Stmt = label(_Label),
- fail
- ;
- Stmt = goto(_),
- fail
- ;
- Stmt = computed_goto(_Rval, _Labels),
- fail
- ;
- Stmt = call(_Sig, _Func, _Obj, _Args, _RetLvals, _TailCall),
- fail
- ;
- Stmt = return(_Rvals),
- fail
- ;
- Stmt = do_commit(_Ref),
- fail
- ;
- Stmt = try_commit(_Ref, Statement, Handler),
- ( statement_contains_statement(Statement, SubStatement)
- ; statement_contains_statement(Handler, SubStatement)
- )
- ;
- Stmt = atomic(_AtomicStmt),
- fail
).
%-----------------------------------------------------------------------------%
--
Tyson Dowd #
# Surreal humour isn't everyone's cup of fur.
trd at cs.mu.oz.au #
http://www.cs.mu.oz.au/~trd #
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to: mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions: mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------
More information about the developers
mailing list