[m-dev.] diff: MLDS function calling convention

Fergus Henderson fjh at cs.mu.OZ.AU
Mon Oct 30 18:08:03 AEDT 2000


Estimated hours taken: 6

Change the MLDS calling convention so that for model_det Mercury functions
with output mode results, the function results get mapped to MLDS function
return values rather than to by-ref parameters.  The rationale for this is
to make interoperability simpler (especially for the IL & Java back-ends).

compiler/lambda.m:
	Change the rules for compatibility of closures so that for
	MLDS grades function closures are not treated as compatible
	with predicate closures.

compiler/ml_code_util.m:
	Change ml_gen_params so that it takes a pred_or_func parameter, and
	for model_det functions it maps the output-moded function results
	to MLDS return values.

compiler/ml_code_gen.m:
	For model_det functions with output mode results,
	return the function result by value.
	Rename the `output_vars' field of the ml_gen_info as
	`byref_output_vars'.

compiler/ml_call_gen.m:
	Pass down the pred_or_func parameter to ml_gen_params.
	For calls to model_det functions with output mode results,
	return the function result by value.

compiler/hlds_goal.m:
	Add new predicate generic_call_pred_or_func, for use by ml_call_gen.m.

compiler/ml_unify_gen.m:
	Modify the code for generating wrapper functions for closures so
	that it reflects the new calling convention for Mercury functions.

compiler/mlds.m:
compiler/mlds_to_c.m:
compiler/ml_code_gen.m:
	Don't handle model_det functions with output mode results specially
	in `pragma export' anymore, since the internal MLDS form now
	has the same prototype as the exported one.

Workspace: /home/pgrad/fjh/fs/roy/traveller/mercury
Index: compiler/hlds_goal.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_goal.m,v
retrieving revision 1.78
diff -u -d -r1.78 hlds_goal.m
--- compiler/hlds_goal.m	2000/10/13 04:04:31	1.78
+++ compiler/hlds_goal.m	2000/10/26 02:31:52
@@ -225,6 +225,8 @@
 		)
 	.
 
+:- func generic_call_pred_or_func(generic_call) = pred_or_func.
+
 	% Builtin Aditi operations. 
 :- type aditi_builtin
 	--->
@@ -1614,6 +1616,15 @@
 	instmap_delta_init_reachable(InstMapDelta0),
 	instmap_delta_insert(InstMapDelta0, Var, Inst, InstMapDelta),
 	goal_info_init(NonLocals, InstMapDelta, det, GoalInfo).
+
+generic_call_pred_or_func(higher_order(_, PredOrFunc, _)) = PredOrFunc.
+generic_call_pred_or_func(class_method(_, _, _, CallId)) =
+	simple_call_id_pred_or_func(CallId).
+generic_call_pred_or_func(aditi_builtin(_, CallId)) =
+	simple_call_id_pred_or_func(CallId).
+
+:- func simple_call_id_pred_or_func(simple_call_id) = pred_or_func.
+simple_call_id_pred_or_func(PredOrFunc - _) = PredOrFunc.
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
Index: compiler/lambda.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/lambda.m,v
retrieving revision 1.67
diff -u -d -r1.67 lambda.m
--- compiler/lambda.m	2000/10/13 13:55:31	1.67
+++ compiler/lambda.m	2000/10/26 03:29:30
@@ -395,21 +395,32 @@
 			list__member(InitialVar, Vars)
 		),
 
-		proc_info_interface_code_model(Call_ProcInfo, Call_CodeModel),
-		determinism_to_code_model(Detism, CodeModel),
 			% Check that the code models are compatible.
 			% Note that det is not compatible with semidet,
 			% and semidet is not compatible with nondet,
 			% since the calling conventions are different.
-			% But if we're using the LLDS back-end
+			% If we're using the LLDS back-end
 			% (i.e. not --high-level-code),
 			% det is compatible with nondet.
-		( CodeModel = Call_CodeModel
-		; CodeModel = model_non, Call_CodeModel = model_det,
-			module_info_globals(ModuleInfo0, Globals),
-			globals__lookup_bool_option(Globals,
-				highlevel_code, no)
+			% If we're using the MLDS back-end,
+			% then predicates and functions have different
+			% calling conventions.
+		proc_info_interface_code_model(Call_ProcInfo, Call_CodeModel),
+		determinism_to_code_model(Detism, CodeModel),
+		module_info_globals(ModuleInfo0, Globals),
+		globals__lookup_bool_option(Globals, highlevel_code, HighLevelCode),
+		(
+			HighLevelCode = no,
+			( CodeModel = Call_CodeModel
+			; CodeModel = model_non, Call_CodeModel = model_det
+			)
+		;
+			HighLevelCode = yes,
+			pred_info_get_is_pred_or_func(Call_PredInfo, Call_PredOrFunc),
+			PredOrFunc = Call_PredOrFunc,
+			CodeModel = Call_CodeModel
 		),
+			
 			% check that the curried arguments are all input
 		proc_info_argmodes(Call_ProcInfo, Call_ArgModes),
 		list__length(InitialVars, NumInitialVars),
Index: compiler/ml_call_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ml_call_gen.m,v
retrieving revision 1.16
diff -u -d -r1.16 ml_call_gen.m
--- compiler/ml_call_gen.m	2000/10/22 09:17:56	1.16
+++ compiler/ml_call_gen.m	2000/10/28 05:00:38
@@ -135,8 +135,9 @@
 	{ ml_gen_info_get_module_info(MLDSGenInfo, ModuleInfo) },
 	{ ml_gen_info_get_varset(MLDSGenInfo, VarSet) },
 	{ ArgNames = ml_gen_var_names(VarSet, ArgVars) },
+	{ PredOrFunc = generic_call_pred_or_func(GenericCall) },
 	{ Params0 = ml_gen_params(ModuleInfo, ArgNames,
-		BoxedArgTypes, ArgModes, CodeModel) },
+		BoxedArgTypes, ArgModes, PredOrFunc, CodeModel) },
 
 	%
 	% insert the `closure_arg' parameter
@@ -201,7 +202,7 @@
 	ml_gen_var_list(ArgVars, ArgLvals),
 	ml_variable_types(ArgVars, ActualArgTypes),
 	ml_gen_arg_list(ArgNames, ArgLvals, ActualArgTypes, BoxedArgTypes,
-		ArgModes, CodeModel, Context,
+		ArgModes, PredOrFunc, CodeModel, Context,
 		InputRvals, OutputLvals, OutputTypes,
 		ConvArgDecls, ConvOutputStatements),
 	{ ClosureRval = unop(unbox(ClosureArgType), lval(ClosureLval)) },
@@ -303,6 +304,7 @@
 	{ ml_gen_info_get_module_info(MLDSGenInfo, ModuleInfo) },
 	{ module_info_pred_proc_info(ModuleInfo, PredId, ProcId,
 		PredInfo, ProcInfo) },
+	{ pred_info_get_is_pred_or_func(PredInfo, PredOrFunc) },
 	{ pred_info_arg_types(PredInfo, PredArgTypes) },
 	{ proc_info_argmodes(ProcInfo, ArgModes) },
 
@@ -312,7 +314,7 @@
 	% to pass as the function call's arguments and return values
 	%
 	ml_gen_arg_list(ArgNames, ArgLvals, ActualArgTypes, PredArgTypes,
-		ArgModes, CodeModel, Context,
+		ArgModes, PredOrFunc, CodeModel, Context,
 		InputRvals, OutputLvals, OutputTypes,
 		ConvArgDecls, ConvOutputStatements),
 
@@ -536,14 +538,16 @@
 % Generate rvals and lvals for the arguments of a procedure call
 %
 :- pred ml_gen_arg_list(list(var_name), list(mlds__lval), list(prog_type),
-		list(prog_type), list(mode), code_model, prog_context,
-		list(mlds__rval), list(mlds__lval), list(mlds__type),
-		mlds__defns, mlds__statements, ml_gen_info, ml_gen_info).
-:- mode ml_gen_arg_list(in, in, in, in, in, in, in, out, out, out, out, out,
+		list(prog_type), list(mode), pred_or_func, code_model,
+		prog_context, list(mlds__rval), list(mlds__lval),
+		list(mlds__type), mlds__defns, mlds__statements,
+		ml_gen_info, ml_gen_info).
+:- mode ml_gen_arg_list(in, in, in, in, in, in, in, in, out, out, out, out, out,
 		in, out) is det.
 
-ml_gen_arg_list(VarNames, VarLvals, CallerTypes, CalleeTypes, Modes, CodeModel,
-		Context, InputRvals, OutputLvals, OutputTypes,
+ml_gen_arg_list(VarNames, VarLvals, CallerTypes, CalleeTypes, Modes,
+		PredOrFunc, CodeModel, Context,
+		InputRvals, OutputLvals, OutputTypes,
 		ConvDecls, ConvOutputStatements) -->
 	(
 		{ VarNames = [] },
@@ -565,11 +569,13 @@
 		{ Modes = [Mode | Modes1] }
 	->
 		ml_gen_arg_list(VarNames1, VarLvals1,
-			CallerTypes1, CalleeTypes1, Modes1, CodeModel, Context,
+			CallerTypes1, CalleeTypes1, Modes1,
+			PredOrFunc, CodeModel, Context,
 			InputRvals1, OutputLvals1, OutputTypes1,
 			ConvDecls1, ConvOutputStatements1),
 		=(MLDSGenInfo),
 		{ ml_gen_info_get_module_info(MLDSGenInfo, ModuleInfo) },
+		{ mode_to_arg_mode(ModuleInfo, Mode, CalleeType, ArgMode) },
 		(
 			{ type_util__is_dummy_argument_type(CalleeType) }
 		->
@@ -581,7 +587,7 @@
 			{ OutputTypes = OutputTypes1 },
 			{ ConvDecls = ConvDecls1 },
 			{ ConvOutputStatements = ConvOutputStatements1 }
-		; { mode_to_arg_mode(ModuleInfo, Mode, CalleeType, top_in) } ->
+		; { ArgMode = top_in } ->
 			%
 			% it's an input argument
 			%
@@ -618,11 +624,24 @@
 			ml_gen_info_get_globals(Globals),
 			{ CopyOut = get_copy_out_option(Globals, CodeModel) },
 			(
-				%
-				% if the target language allows multiple
-				% return values, then use them
-				%
-				{ CopyOut = yes }
+				(
+					%
+					% if the target language allows
+					% multiple return values, then use them
+					%
+					{ CopyOut = yes }
+				;
+					%
+					% if this is the result argument 
+					% of a model_det function, and it has
+					% an output mode, then return it as a
+					% value
+					%
+					{ VarNames1 = [] },
+					{ CodeModel = model_det },
+					{ PredOrFunc = function },
+					{ ArgMode = top_out }
+				)
 			->
 				{ InputRvals = InputRvals1 },
 				{ OutputLvals = [ArgLval | OutputLvals1] },
Index: compiler/ml_code_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ml_code_gen.m,v
retrieving revision 1.62
diff -u -d -r1.62 ml_code_gen.m
--- compiler/ml_code_gen.m	2000/10/22 15:57:36	1.62
+++ compiler/ml_code_gen.m	2000/10/28 21:48:44
@@ -778,28 +778,22 @@
 		MLDS_Name, MLDS_ModuleName),
 	MLDS_FuncParams = ml_gen_proc_params(ModuleInfo, PredId, ProcId),
 	MLDS_Context = mlds__make_context(ProgContext),
-
-	(
-		is_output_det_function(ModuleInfo, PredId, ProcId)
-	->
-		IsOutDetFunc = yes
-	;
-		IsOutDetFunc = no
-	),
-
 	ML_Defn = ml_pragma_export(C_Name, qual(MLDS_ModuleName, MLDS_Name),
-			MLDS_FuncParams, MLDS_Context, IsOutDetFunc).
+			MLDS_FuncParams, MLDS_Context).
 
 
 	%
-	% Test to see if the procedure is of the following form
-	%   :- func <name>(...) = V::out is det.
-	% as these need to handled specially.
+	% Test to see if the procedure is 
+	% a model_det function whose function result has an output mode
+	% (whose type is not a dummy argument type like io__state),
+	% and if so, bind RetVar to the procedure's return value.
+	% These procedures need to handled specially: for such functions,
+	% we map the Mercury function result to an MLDS return value.
 	%
-:- pred is_output_det_function(module_info, pred_id, proc_id).
-:- mode is_output_det_function(in, in, in) is semidet.
+:- pred is_output_det_function(module_info, pred_id, proc_id, prog_var).
+:- mode is_output_det_function(in, in, in, out) is semidet.
 
-is_output_det_function(ModuleInfo, PredId, ProcId) :-
+is_output_det_function(ModuleInfo, PredId, ProcId, RetArgVar) :-
 	module_info_pred_proc_info(ModuleInfo, PredId, ProcId, PredInfo,
 			ProcInfo),
 	
@@ -808,9 +802,11 @@
 
 	proc_info_argmodes(ProcInfo, Modes),
 	pred_info_arg_types(PredInfo, ArgTypes),
+	proc_info_headvars(ProcInfo, ArgVars),
 	modes_to_arg_modes(ModuleInfo, Modes, ArgTypes, ArgModes),
 	pred_args_to_func_args(ArgModes, _InputArgModes, RetArgMode),
 	pred_args_to_func_args(ArgTypes, _InputArgTypes, RetArgType),
+	pred_args_to_func_args(ArgVars, _InputArgVars, RetArgVar),
 
 	RetArgMode = top_out,
 	\+ type_util__is_dummy_argument_type(RetArgType).
@@ -984,13 +980,29 @@
 	MLDSGenInfo0 = ml_gen_info_init(ModuleInfo, PredId, ProcId),
 	MLDS_Params = ml_gen_proc_params(ModuleInfo, PredId, ProcId),
 
+	% Set up the initial success continuation, if any.
+	% Also figure out which output variables are returned by
+	% value (rather than being passed by reference) and remove
+	% them from the byref_output_vars field in the ml_gen_info.
 	( CodeModel = model_non ->
-		% set up the initial success continuation
-		ml_set_up_initial_succ_cont(ModuleInfo, NondetCopiedOutputVars,
-			MLDSGenInfo0, MLDSGenInfo2)
+		ml_set_up_initial_succ_cont(ModuleInfo, CopiedOutputVars,
+			MLDSGenInfo0, MLDSGenInfo1)
 	;
-		NondetCopiedOutputVars = [],
-		MLDSGenInfo2 = MLDSGenInfo0
+		(
+			is_output_det_function(ModuleInfo, PredId, ProcId,
+				ResultVar)
+		->
+			CopiedOutputVars = [ResultVar],
+			ml_gen_info_get_byref_output_vars(MLDSGenInfo0,
+				ByRefOutputVars0),
+			list__delete_all(ByRefOutputVars0,
+				ResultVar, ByRefOutputVars),
+			ml_gen_info_set_byref_output_vars(ByRefOutputVars,	
+				MLDSGenInfo0, MLDSGenInfo1)
+		;
+			CopiedOutputVars = [],
+			MLDSGenInfo1 = MLDSGenInfo0
+		)
 	),
 
 	% This would generate all the local variables at the top of the
@@ -999,23 +1011,29 @@
 	% 		VarTypes, HeadVars, ModuleInfo),
 	% But instead we now generate them locally for each goal.
 	% We just declare the `succeeded' var here,
-	% plus, if --nondet-copy-out is enabled,
-	% locals for the output arguments.
+	% plus locals for any output arguments that are returned by value
+	% (e.g. if --nondet-copy-out is enabled, or for det function return
+	% values).
 	MLDS_Context = mlds__make_context(Context),
-	( NondetCopiedOutputVars = [] ->
+	( CopiedOutputVars = [] ->
 		% optimize common case
 		OutputVarLocals = []
 	;
 		proc_info_varset(ProcInfo, VarSet),
 		proc_info_vartypes(ProcInfo, VarTypes),
-		OutputVarLocals = ml_gen_local_var_decls(VarSet, VarTypes,
-			MLDS_Context, ModuleInfo, NondetCopiedOutputVars)
+		% note that for headvars we must use the types from
+		% the procedure interface, not from the procedure body
+		HeadVarTypes = map__from_corresponding_lists(HeadVars,
+			ArgTypes),
+		OutputVarLocals = ml_gen_local_var_decls(VarSet,
+			map__overlay(VarTypes, HeadVarTypes),
+			MLDS_Context, ModuleInfo, CopiedOutputVars)
 	),
 	MLDS_LocalVars = [ml_gen_succeeded_var_decl(MLDS_Context) |
 			OutputVarLocals],
-	ml_gen_proc_body(CodeModel, HeadVars, ArgTypes, Goal,
+	ml_gen_proc_body(CodeModel, HeadVars, ArgTypes, CopiedOutputVars, Goal,
 			MLDS_Decls0, MLDS_Statements,
-			MLDSGenInfo2, MLDSGenInfo),
+			MLDSGenInfo1, MLDSGenInfo),
 	ml_gen_info_get_extra_defns(MLDSGenInfo, ExtraDefns),
 	MLDS_Decls = list__append(MLDS_LocalVars, MLDS_Decls0),
 	MLDS_Statement = ml_gen_block(MLDS_Decls, MLDS_Statements, Context),
@@ -1035,9 +1053,9 @@
 		% for the output variables and then pass them to the
 		% continuation, rather than passing them by reference.
 		=(MLDSGenInfo0),
-		{ ml_gen_info_get_output_vars(MLDSGenInfo0,
+		{ ml_gen_info_get_byref_output_vars(MLDSGenInfo0,
 			NondetCopiedOutputVars) },
-		ml_gen_info_set_output_vars([])
+		ml_gen_info_set_byref_output_vars([])
 	;
 		{ NondetCopiedOutputVars = [] }
 	),
@@ -1092,11 +1110,11 @@
 	% Generate the code for a procedure body.
 	%
 :- pred ml_gen_proc_body(code_model, list(prog_var), list(prog_type),
-		hlds_goal, mlds__defns, mlds__statements,
+		list(prog_var), hlds_goal, mlds__defns, mlds__statements,
 		ml_gen_info, ml_gen_info).
-:- mode ml_gen_proc_body(in, in, in, in, out, out, in, out) is det.
+:- mode ml_gen_proc_body(in, in, in, in, in, out, out, in, out) is det.
 
-ml_gen_proc_body(CodeModel, HeadVars, ArgTypes, Goal,
+ml_gen_proc_body(CodeModel, HeadVars, ArgTypes, CopiedOutputVars, Goal,
 		MLDS_Decls, MLDS_Statements) -->
 	{ Goal = _ - GoalInfo },
 	{ goal_info_get_context(GoalInfo, Context) },
@@ -1111,8 +1129,12 @@
 	% or unification/compare procedures for equivalence types --
 	% the parameters types may not match the types of the head variables.
 	% In such cases, we need to box/unbox/cast them to the right type.
+	% We also grab the original (uncast) lvals for the copied output
+	% variables (if any) here, since for the return statement that
+	% we append below, we want the original vars, not their cast versions.
 	%
-	ml_gen_convert_headvars(HeadVars, ArgTypes, Context,
+	ml_gen_var_list(CopiedOutputVars, CopiedOutputVarOriginalLvals),
+	ml_gen_convert_headvars(HeadVars, ArgTypes, CopiedOutputVars, Context,
 		ConvDecls, ConvInputStatements, ConvOutputStatements),
 	(
 		{ ConvDecls = [] },
@@ -1144,16 +1166,8 @@
 	%
 	% Finally append an appropriate `return' statement, if needed.
 	%
-	( { CodeModel = model_semi } ->
-		ml_gen_test_success(Succeeded),
-		{ ReturnStmt = return([Succeeded]) },
-		{ ReturnStatement = mlds__statement(ReturnStmt,
-			mlds__make_context(Context)) },
-		{ MLDS_Statements = list__append(MLDS_Statements1,
-			[ReturnStatement]) }
-	;
-		{ MLDS_Statements = MLDS_Statements1 }
-	).
+	ml_append_return_statement(CodeModel, CopiedOutputVarOriginalLvals,
+		Context, MLDS_Statements1, MLDS_Statements).
 
 %
 % In certain cases -- for example existentially typed procedures,
@@ -1162,13 +1176,14 @@
 % In such cases, we need to box/unbox/cast them to the right type.
 % This procedure handles that.
 %
-:- pred ml_gen_convert_headvars(list(prog_var), list(prog_type), prog_context,
+:- pred ml_gen_convert_headvars(list(prog_var), list(prog_type),
+		list(prog_var), prog_context,
 		mlds__defns, mlds__statements, mlds__statements,
 		ml_gen_info, ml_gen_info).
-:- mode ml_gen_convert_headvars(in, in, in, out, out, out, in, out) is det.
+:- mode ml_gen_convert_headvars(in, in, in, in, out, out, out, in, out) is det.
 
-ml_gen_convert_headvars([], [], _, [], [], []) --> [].
-ml_gen_convert_headvars([Var|Vars], [HeadType|HeadTypes],
+ml_gen_convert_headvars([], [], _, _, [], [], []) --> [].
+ml_gen_convert_headvars([Var|Vars], [HeadType|HeadTypes], CopiedOutputVars,
 		Context, Decls, InputStatements, OutputStatements) -->
 	ml_variable_type(Var, BodyType),
 	(
@@ -1181,8 +1196,8 @@
 		{ map__is_empty(Subst) }
 	->
 		% just recursively process the remaining arguments
-		ml_gen_convert_headvars(Vars, HeadTypes, Context,
-				Decls, InputStatements, OutputStatements)
+		ml_gen_convert_headvars(Vars, HeadTypes, CopiedOutputVars,
+			Context, Decls, InputStatements, OutputStatements)
 	;
 		%
 		% generate the lval for the head variable
@@ -1210,15 +1225,20 @@
 		%
 		% Recursively process the remaining arguments
 		%
-		ml_gen_convert_headvars(Vars, HeadTypes, Context,
-				Decls1, InputStatements1, OutputStatements1),
+		ml_gen_convert_headvars(Vars, HeadTypes, CopiedOutputVars,
+			Context, Decls1, InputStatements1, OutputStatements1),
 
 		%
 		% Add the code to convert this input or output.
 		%
 		=(MLDSGenInfo2),
-		{ ml_gen_info_get_output_vars(MLDSGenInfo2, OutputVars) },
-		{ list__member(Var, OutputVars) ->
+		{ ml_gen_info_get_byref_output_vars(MLDSGenInfo2,
+			ByRefOutputVars) },
+		{
+			( list__member(Var, ByRefOutputVars)
+			; list__member(Var, CopiedOutputVars)
+			)
+		->
 			InputStatements = InputStatements1,
 			OutputStatements = list__append(OutputStatements1,
 				ConvOutputStatements)
@@ -1229,9 +1249,9 @@
 		},
 		{ list__append(ConvDecls, Decls1, Decls) }
 	).
-ml_gen_convert_headvars([], [_|_], _, _, _, _) -->
+ml_gen_convert_headvars([], [_|_], _, _, _, _, _) -->
 	{ error("ml_gen_convert_headvars: length mismatch") }.
-ml_gen_convert_headvars([_|_], [], _, _, _, _) -->
+ml_gen_convert_headvars([_|_], [], _, _, _, _, _) -->
 	{ error("ml_gen_convert_headvars: length mismatch") }.
 
 %-----------------------------------------------------------------------------%
@@ -1591,8 +1611,9 @@
 	( { NondetCopyOut = yes } ->
 		{ goal_info_get_context(GoalInfo, Context) },
 		{ goal_info_get_nonlocals(GoalInfo, NonLocals) },
-		{ ml_gen_info_get_output_vars(MLDSGenInfo0, OutputVars) },
-		{ VarsToCopy = set__intersect(set__list_to_set(OutputVars),
+		{ ml_gen_info_get_byref_output_vars(MLDSGenInfo0,
+			ByRefOutputVars) },
+		{ VarsToCopy = set__intersect(set__list_to_set(ByRefOutputVars),
 			NonLocals) },
 		ml_gen_make_locals_for_output_args(
 			set__to_sorted_list(VarsToCopy), Context,
Index: compiler/ml_code_util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ml_code_util.m,v
retrieving revision 1.26
diff -u -d -r1.26 ml_code_util.m
--- compiler/ml_code_util.m	2000/10/22 13:57:37	1.26
+++ compiler/ml_code_util.m	2000/10/28 21:49:41
@@ -32,6 +32,14 @@
 	% Generate an MLDS assignment statement.
 :- func ml_gen_assign(mlds__lval, mlds__rval, prog_context) = mlds__statement.
 
+	%
+	% Append an appropriate `return' statement for the given code_model
+	% and returning the given lvals, if needed.
+	%
+:- pred ml_append_return_statement(code_model, list(mlds__lval), prog_context,
+		mlds__statements, mlds__statements, ml_gen_info, ml_gen_info).
+:- mode ml_append_return_statement(in, in, in, in, out, in, out) is det.
+
 	% Generate a block statement, i.e. `{ <Decls>; <Statements>; }'.
 	% But if the block consists only of a single statement with no
 	% declarations, then just return that statement.
@@ -115,7 +123,7 @@
 	% given argument types, modes, and code model.
 	%
 :- func ml_gen_params(module_info, list(string), list(prog_type),
-		list(mode), code_model) = mlds__func_params.
+		list(mode), pred_or_func, code_model) = mlds__func_params.
 
 	% Given a list of variables and their corresponding modes,
 	% return a list containing only those variables which have
@@ -456,11 +464,12 @@
 :- pred ml_gen_info_get_var_types(ml_gen_info, map(prog_var, prog_type)).
 :- mode ml_gen_info_get_var_types(in, out) is det.
 
-:- pred ml_gen_info_get_output_vars(ml_gen_info, list(prog_var)).
-:- mode ml_gen_info_get_output_vars(in, out) is det.
+:- pred ml_gen_info_get_byref_output_vars(ml_gen_info, list(prog_var)).
+:- mode ml_gen_info_get_byref_output_vars(in, out) is det.
 
-:- pred ml_gen_info_set_output_vars(list(prog_var), ml_gen_info, ml_gen_info).
-:- mode ml_gen_info_set_output_vars(in, in, out) is det.
+:- pred ml_gen_info_set_byref_output_vars(list(prog_var),
+		ml_gen_info, ml_gen_info).
+:- mode ml_gen_info_set_byref_output_vars(in, in, out) is det.
 
 :- pred ml_gen_info_get_globals(globals, ml_gen_info, ml_gen_info).
 :- mode ml_gen_info_get_globals(out, in, out) is det.
@@ -639,6 +648,31 @@
 	MLDS_Statement = mlds__statement(MLDS_Stmt,
 		mlds__make_context(Context)).
 
+	%
+	% Append an appropriate `return' statement for the given code_model
+	% and returning the given OutputVarLvals, if needed.
+	%
+ml_append_return_statement(CodeModel, CopiedOutputVarLvals, Context,
+		MLDS_Statements0, MLDS_Statements) -->
+	( { CodeModel = model_semi } ->
+		ml_gen_test_success(Succeeded),
+		{ ReturnStmt = return([Succeeded]) },
+		{ ReturnStatement = mlds__statement(ReturnStmt,
+			mlds__make_context(Context)) },
+		{ MLDS_Statements = list__append(MLDS_Statements0,
+			[ReturnStatement]) }
+	; { CodeModel \= model_non, CopiedOutputVarLvals \= [] } ->
+		{ CopiedOutputVarRvals = list__map(func(Lval) = lval(Lval),
+			CopiedOutputVarLvals) },
+		{ ReturnStmt = return(CopiedOutputVarRvals) },
+		{ ReturnStatement = mlds__statement(ReturnStmt,
+			mlds__make_context(Context)) },
+		{ MLDS_Statements = list__append(MLDS_Statements0,
+			[ReturnStatement]) }
+	;
+		{ MLDS_Statements = MLDS_Statements0 }
+	).
+
 	% Generate a block statement, i.e. `{ <Decls>; <Statements>; }'.
 	% But if the block consists only of a single statement with no
 	% declarations, then just return that statement.
@@ -859,12 +893,13 @@
 		PredInfo, ProcInfo),
 	proc_info_varset(ProcInfo, VarSet),
 	proc_info_headvars(ProcInfo, HeadVars),
+	pred_info_get_is_pred_or_func(PredInfo, PredOrFunc),
 	pred_info_arg_types(PredInfo, HeadTypes),
 	proc_info_argmodes(ProcInfo, HeadModes),
 	proc_info_interface_code_model(ProcInfo, CodeModel),
 	HeadVarNames = ml_gen_var_names(VarSet, HeadVars),
 	FuncParams = ml_gen_params(ModuleInfo, HeadVarNames, HeadTypes,
-		HeadModes, CodeModel).
+		HeadModes, PredOrFunc, CodeModel).
 
 	% As above, but from the rtti_proc_id rather than
 	% from the module_info, pred_id, and proc_id.
@@ -874,41 +909,74 @@
 	HeadVars = RttiProcId^proc_headvars,
 	ArgTypes = RttiProcId^arg_types,
 	ArgModes = RttiProcId^proc_arg_modes,
+	PredOrFunc = RttiProcId^pred_or_func,
 	CodeModel = RttiProcId^proc_interface_code_model,
 	HeadVarNames = ml_gen_var_names(VarSet, HeadVars),
 	FuncParams = ml_gen_params_base(ModuleInfo, HeadVarNames,
-		ArgTypes, ArgModes, CodeModel).
+		ArgTypes, ArgModes, PredOrFunc, CodeModel).
 	
 	% Generate the function prototype for a procedure with the
 	% given argument types, modes, and code model.
 	%
-ml_gen_params(ModuleInfo, HeadVarNames, HeadTypes, HeadModes, CodeModel) =
-		FuncParams :-
+ml_gen_params(ModuleInfo, HeadVarNames, HeadTypes, HeadModes, PredOrFunc,
+		CodeModel) = FuncParams :-
 	modes_to_arg_modes(ModuleInfo, HeadModes, HeadTypes, ArgModes),
 	FuncParams = ml_gen_params_base(ModuleInfo, HeadVarNames,
-		HeadTypes, ArgModes, CodeModel).
+		HeadTypes, ArgModes, PredOrFunc, CodeModel).
 
 :- func ml_gen_params_base(module_info, list(string), list(prog_type),
-		list(arg_mode), code_model) = mlds__func_params.
+		list(arg_mode), pred_or_func, code_model) = mlds__func_params.
 
 ml_gen_params_base(ModuleInfo, HeadVarNames, HeadTypes, HeadModes,
-		CodeModel) = FuncParams :-
+		PredOrFunc, CodeModel) = FuncParams :-
 	module_info_globals(ModuleInfo, Globals),
 	CopyOut = get_copy_out_option(Globals, CodeModel),
 	ml_gen_arg_decls(ModuleInfo, HeadVarNames, HeadTypes, HeadModes,
 		CopyOut, FuncArgs0, RetTypes0),
-	( CodeModel = model_semi ->
+	(
+		CodeModel = model_det,
+		%
+		% for model_det Mercury functions whose result argument has an
+		% output mode, make the result into the MLDS return type
+		%
+		(
+			RetTypes0 = [],
+			PredOrFunc = function,
+			pred_args_to_func_args(HeadModes, _, ResultMode),
+			ResultMode = top_out,
+			pred_args_to_func_args(HeadTypes, _, ResultType),
+			\+ type_util__is_dummy_argument_type(ResultType)
+		->
+			pred_args_to_func_args(FuncArgs0, FuncArgs,
+				_RetArgName - RetTypePtr),
+			( RetTypePtr = mlds__ptr_type(RetType) ->
+				RetTypes = [RetType]
+			;
+				error("output mode function result doesn't have pointer type")
+			)
+		;
+			FuncArgs = FuncArgs0,
+			RetTypes = RetTypes0
+		)
+	;
+		CodeModel = model_semi,
+		%
+		% for model_semi procedures, return a bool
+		%
+		FuncArgs = FuncArgs0,
 		RetTypes = [mlds__native_bool_type | RetTypes0]
-	; CodeModel = model_non, CopyOut = yes ->
-		RetTypes = []
 	;
-		RetTypes = RetTypes0
-	),
-	( CodeModel = model_non ->
+		CodeModel = model_non,
+		%
+		% for model_non procedures, we return values
+		% by passing them to the continuation
+		%
 		( CopyOut = yes ->
-			ContType = mlds__cont_type(RetTypes0)
+			ContType = mlds__cont_type(RetTypes0),
+			RetTypes = []
 		;
-			ContType = mlds__cont_type([])
+			ContType = mlds__cont_type([]),
+			RetTypes = RetTypes0
 		),
 		ContName = data(var("cont")),
 		ContArg = ContName - ContType,
@@ -925,8 +993,6 @@
 			FuncArgs = list__append(FuncArgs0,
 				[ContArg, ContEnvArg])
 		)
-	;
-		FuncArgs = FuncArgs0
 	),
 	FuncParams = mlds__func_params(FuncArgs, RetTypes).
 
@@ -1186,9 +1252,9 @@
 		{ VarName = ml_gen_var_name(VarSet, Var) },
 		ml_qualify_var(VarName, VarLval),
 		%
-		% output variables are passed by reference...
+		% output variables may be passed by reference...
 		%
-		{ ml_gen_info_get_output_vars(MLDSGenInfo, OutputVars) },
+		{ ml_gen_info_get_byref_output_vars(MLDSGenInfo, OutputVars) },
 		( { list__member(Var, OutputVars) } ->
 			ml_gen_type(Type, MLDS_Type),
 			{ Lval = mem_ref(lval(VarLval), MLDS_Type) }
@@ -1602,7 +1668,9 @@
 			proc_id :: proc_id,
 			varset :: prog_varset,
 			var_types :: map(prog_var, prog_type),
-			output_vars :: list(prog_var),	% output arguments
+			byref_output_vars :: list(prog_var),
+				% output arguments that are passed by
+				% reference
 
 			%
 			% these fields get updated as we traverse
@@ -1634,7 +1702,7 @@
 	proc_info_varset(ProcInfo, VarSet),
 	proc_info_vartypes(ProcInfo, VarTypes),
 	proc_info_argmodes(ProcInfo, HeadModes),
-	OutputVars = select_output_vars(ModuleInfo, HeadVars, HeadModes,
+	ByRefOutputVars = select_output_vars(ModuleInfo, HeadVars, HeadModes,
 		VarTypes),
 
 	FuncLabelCounter = 0,
@@ -1653,7 +1721,7 @@
 			ProcId,
 			VarSet,
 			VarTypes,
-			OutputVars,
+			ByRefOutputVars,
 			FuncLabelCounter,
 			CommitLabelCounter,
 			CondVarCounter,
@@ -1675,8 +1743,9 @@
 ml_gen_info_get_proc_id(Info, Info^proc_id).
 ml_gen_info_get_varset(Info, Info^varset).
 ml_gen_info_get_var_types(Info, Info^var_types).
-ml_gen_info_get_output_vars(Info, Info^output_vars).
-ml_gen_info_set_output_vars(OutputVars, Info, Info^output_vars := OutputVars).
+ml_gen_info_get_byref_output_vars(Info, Info^byref_output_vars).
+ml_gen_info_set_byref_output_vars(OutputVars, Info,
+		Info^byref_output_vars := OutputVars).
 
 ml_gen_info_use_gcc_nested_functions(UseNestedFuncs) -->
 	ml_gen_info_get_globals(Globals),
Index: compiler/mlds.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds.m,v
retrieving revision 1.36
diff -u -d -r1.36 mlds.m
--- compiler/mlds.m	2000/10/22 07:27:19	1.36
+++ compiler/mlds.m	2000/10/28 04:43:09
@@ -628,9 +628,7 @@
 		string,			% Exported name
 		mlds__qualified_entity_name, % MLDS name for exported entity
 		mlds__func_params,	% MLDS function parameters
-		mlds__context,
-		bool			% is a det function with the
-					% final args mode top_out.
+		mlds__context
 	).
 
 
Index: compiler/mlds_to_c.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds_to_c.m,v
retrieving revision 1.59
diff -u -d -r1.59 mlds_to_c.m
--- compiler/mlds_to_c.m	2000/10/22 13:57:37	1.59
+++ compiler/mlds_to_c.m	2000/10/28 21:23:47
@@ -472,21 +472,14 @@
 
 mlds_output_pragma_export_defn(ModuleName, Indent, PragmaExport) -->
 	{ PragmaExport = ml_pragma_export(_C_name, MLDS_Name, MLDS_Signature,
-			Context, IsFunc) },
+			Context) },
 	mlds_output_pragma_export_func_name(ModuleName, Indent, PragmaExport),
 	io__write_string("\n"),
 	mlds_indent(Context, Indent),
 	io__write_string("{\n"),
 	mlds_indent(Context, Indent),
-	(
-		{ IsFunc = yes },
-		mlds_output_pragma_export_func_defn_body(ModuleName, MLDS_Name,
-				MLDS_Signature)
-	;
-		{ IsFunc = no },
-		mlds_output_pragma_export_defn_body(ModuleName, MLDS_Name,
-				MLDS_Signature)
-	),
+	mlds_output_pragma_export_defn_body(ModuleName, MLDS_Name,
+				MLDS_Signature),
 	io__write_string("}\n").
 
 :- pred mlds_output_pragma_export_func_name(mlds_module_name, indent,
@@ -494,15 +487,7 @@
 :- mode mlds_output_pragma_export_func_name(in, in, in, di, uo) is det.
 
 mlds_output_pragma_export_func_name(ModuleName, Indent,
-		ml_pragma_export(C_name, _MLDS_Name, Signature0, Context,
-			IsFunc)) -->
-	(
-		{ IsFunc = yes }
-	->
-		{ Signature = det_func_signature(Signature0) }
-	;
-		{ Signature = Signature0 }
-	),
+		ml_pragma_export(C_name, _MLDS_Name, Signature, Context)) -->
 	{ Name = qual(ModuleName, export(C_name)) },
 	mlds_indent(Context, Indent),
 	mlds_output_func_decl_ho(Indent, Name, Context, Signature,
@@ -549,8 +534,7 @@
 	
 
 	%
-	% Output the definition body for a pragma export when it is
-	% *NOT* a det function whose last arg is top_out.
+	% Output the definition body for a pragma export
 	%
 :- pred mlds_output_pragma_export_defn_body(mlds_module_name,
 		mlds__qualified_entity_name, func_params, io__state, io__state).
@@ -578,47 +562,6 @@
 
 
 	%
-	% Output the definition body for a pragma export when it is
-	% det function whose last arg is top_out.
-	%
-:- pred mlds_output_pragma_export_func_defn_body(mlds_module_name,
-		mlds__qualified_entity_name, func_params,
-		io__state, io__state).
-:- mode mlds_output_pragma_export_func_defn_body(in, in, in, di, uo) is det.
-
-mlds_output_pragma_export_func_defn_body(ModuleName, FuncName, Signature) -->
-	{ ExportedSignature = det_func_signature(Signature) },
-	{ ExportedSignature = mlds__func_params(_ExpParameters, ExpRetTypes) },
-	{ Signature = mlds__func_params(Parameters, _RetTypes) },
-
-	( { ExpRetTypes = [ExpRetType0] } ->
-		{ ExpRetType = ExpRetType0 }
-	;
-		{ error("mlds_output_pragma_export_func_defn_body") }
-	),
-
-		% Define a variable to hold the function result.
-	io__write_string("\t"),
-	mlds_output_type_prefix(ExpRetType),
-	io__write_string(" arg"),
-	mlds_output_type_suffix(ExpRetType),
-	io__write_string(";\n"),
-
-		% Call the MLDS function.
-	io__write_string("\t"),
-	mlds_output_fully_qualified_name(FuncName),
-	io__write_string("("),
-	write_func_args(ModuleName, Parameters),
-	io__write_string(");\n"),
-
-		% return the function result.
-	io__write_string("\t"),
-	io__write_string("return ("),
-	mlds_output_pragma_export_type(prefix, ExpRetType),
-	mlds_output_pragma_export_type(suffix, ExpRetType),
-	io__write_string(") arg;\n").
-
-	%
 	% Write out the arguments to the MLDS function.  Note the last
 	% in the list of the arguments is the return value, so it must
 	% be "&arg"
@@ -1985,7 +1928,7 @@
 		io__write_char(' '),
 		mlds_output_rval(Rval)
 	;
-		{ error("mld_output_stmt: multiple return values") }
+		{ error("mlds_output_stmt: multiple return values") }
 	),
 	io__write_string(";\n").
 	
Index: compiler/ml_unify_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ml_unify_gen.m,v
retrieving revision 1.21
diff -u -d -r1.21 ml_unify_gen.m
--- compiler/ml_unify_gen.m	2000/10/22 13:57:38	1.21
+++ compiler/ml_unify_gen.m	2000/10/28 21:49:07
@@ -555,7 +555,8 @@
 	=(Info),
 	{ ml_gen_info_get_module_info(Info, ModuleInfo) },
 	{ module_info_pred_proc_info(ModuleInfo, PredId, ProcId,
-		_PredInfo, ProcInfo) },
+		PredInfo, ProcInfo) },
+	{ pred_info_get_is_pred_or_func(PredInfo, PredOrFunc) },
 	{ proc_info_headvars(ProcInfo, ProcHeadVars) },
 	{ proc_info_argmodes(ProcInfo, ProcArgModes) },
 	{ proc_info_interface_code_model(ProcInfo, CodeModel) },
@@ -596,7 +597,7 @@
 	{ WrapperHeadVarNames = ml_gen_wrapper_head_var_names(1,
 		list__length(WrapperHeadVars)) },
 	{ WrapperParams0 = ml_gen_params(ModuleInfo, WrapperHeadVarNames,
-		WrapperBoxedArgTypes, WrapperArgModes, CodeModel) },
+		WrapperBoxedArgTypes, WrapperArgModes, PredOrFunc, CodeModel) },
 
 	% then insert the `closure_arg' parameter
 	{ ClosureArg = data(var("closure_arg")) - mlds__generic_type },
@@ -607,8 +608,8 @@
 	% also compute the lvals for the parameters,
 	% and local declarations for any --copy-out output parameters
 	ml_gen_wrapper_arg_lvals(WrapperHeadVarNames, WrapperBoxedArgTypes,
-		WrapperArgModes, CodeModel, Context,
-		WrapperHeadVarDecls, WrapperHeadVarLvals),
+		WrapperArgModes, PredOrFunc, CodeModel, Context,
+		WrapperHeadVarDecls, WrapperHeadVarLvals, WrapperCopyOutLvals),
 
 	%
 	% generate code to declare and initialize the closure pointer.
@@ -687,20 +688,18 @@
 
 	%
 	% For semidet code, add the declaration `bool succeeded;'
-	% and the `return succeeded;' statement.
 	%
 	( { CodeModel = model_semi } ->
 		{ SucceededVarDecl = ml_gen_succeeded_var_decl(MLDS_Context) },
-		{ Decls2 = [SucceededVarDecl | Decls1] },
-		ml_gen_test_success(Succeeded),
-		{ ReturnStmt = return([Succeeded]) },
-		{ ReturnStatement = mlds__statement(ReturnStmt, MLDS_Context) },
-		{ Statements = list__append(Statements1, [ReturnStatement]) }
+		{ Decls2 = [SucceededVarDecl | Decls1] }
 	;
-		{ Decls2 = Decls1 },
-		{ Statements = Statements1 }
+		{ Decls2 = Decls1 }
 	),
 
+	% Add an appropriate `return' statement
+	ml_append_return_statement(CodeModel, WrapperCopyOutLvals, Context,
+		Statements1, Statements),
+
 	%
 	% Insert the local declarations of the wrapper's output arguments,
 	% if any (this is needed for `--nondet-copy-out')
@@ -738,8 +737,8 @@
 		Names = [Name | Names1]
 	).
 
-	% ml_gen_wrapper_arg_lvals(HeadVarNames, Types, ArgModes, CodeModel,
-	%		LocalVarDefns, HeadVarLvals):
+	% ml_gen_wrapper_arg_lvals(HeadVarNames, Types, ArgModes,
+	%		PredOrFunc, CodeModel, LocalVarDefns, HeadVarLvals):
 	%	Generate lvals for the specified head variables
 	%	passed in the specified modes.
 	%	Also generate local definitions for output variables,
@@ -747,16 +746,19 @@
 	%	rather than passed by reference.
 	%
 :- pred ml_gen_wrapper_arg_lvals(list(var_name), list(prog_type), list(mode),
-		code_model, prog_context, list(mlds__defn), list(mlds__lval),
+		pred_or_func, code_model, prog_context,
+		list(mlds__defn), list(mlds__lval), list(mlds__lval),
 		ml_gen_info, ml_gen_info).
-:- mode ml_gen_wrapper_arg_lvals(in, in, in, in, in, out, out, in, out) is det.
+:- mode ml_gen_wrapper_arg_lvals(in, in, in, in, in, in, out, out, out, in, out)
+		is det.
 
-ml_gen_wrapper_arg_lvals(Names, Types, Modes, CodeModel, Context,
-		Defns, Lvals) -->
+ml_gen_wrapper_arg_lvals(Names, Types, Modes, PredOrFunc, CodeModel, Context,
+		Defns, Lvals, CopyOutLvals) -->
 	(
 		{ Names = [], Types = [], Modes = [] }
 	->
 		{ Lvals = [] },
+		{ CopyOutLvals = [] },
 		{ Defns = [] }
 	;
 		{ Names = [Name | Names1] },
@@ -764,12 +766,15 @@
 		{ Modes = [Mode | Modes1] }
 	->
 		ml_gen_wrapper_arg_lvals(Names1, Types1, Modes1,
-			CodeModel, Context, Defns1, Lvals1),
+			PredOrFunc, CodeModel, Context,
+			Defns1, Lvals1, CopyOutLvals1),
 		ml_qualify_var(Name, VarLval),
 		=(Info),
 		{ ml_gen_info_get_module_info(Info, ModuleInfo) },
-		( { mode_to_arg_mode(ModuleInfo, Mode, Type, top_in) } ->
+		{ mode_to_arg_mode(ModuleInfo, Mode, Type, ArgMode) },
+		( { ArgMode = top_in } ->
 			{ Lval = VarLval },
+			{ CopyOutLvals = CopyOutLvals1 },
 			{ Defns = Defns1 }
 		;
 			%
@@ -777,7 +782,21 @@
 			%
 			ml_gen_info_get_globals(Globals),
 			{ CopyOut = get_copy_out_option(Globals, CodeModel) },
-			( { CopyOut = yes } ->
+			(
+				{
+					CopyOut = yes
+				;
+					% for model_det functions,
+					% output mode function results
+					% are mapped to MLDS return values
+					PredOrFunc = function,
+					CodeModel = model_det,
+					ArgMode = top_out,
+					Types1 = [],
+					\+ type_util__is_dummy_argument_type(
+						Type)
+				}
+			->
 				%
 				% output arguments are copied out,
 				% so we need to generate a local declaration
@@ -785,8 +804,11 @@
 				%
 				{ Lval = VarLval },
 				( { type_util__is_dummy_argument_type(Type) } ->
+					{ CopyOutLvals = CopyOutLvals1 },
 					{ Defns = Defns1 }
 				;
+					{ CopyOutLvals = [Lval |
+						CopyOutLvals1] },
 					ml_gen_local_for_output_arg(Name, Type,
 						Context, Defn),
 					{ Defns = [Defn | Defns1] }
@@ -798,6 +820,7 @@
 				%
 				ml_gen_type(Type, MLDS_Type),
 				{ Lval = mem_ref(lval(VarLval), MLDS_Type) },
+				{ CopyOutLvals = CopyOutLvals1 },
 				{ Defns = Defns1 }
 			)
 		),

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
                                    |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
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