[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