[m-dev.] diff: MLDS back-end: implement `pragma c_code'

Fergus Henderson fjh at cs.mu.OZ.AU
Mon Dec 6 18:24:35 AEDT 1999


Estimated hours taken: 8

compiler/ml_code_gen.m:
compiler/mlds_to_c.m:
	Implement `pragma c_code' (except for the model_non case)
	and `pragma c_header_code' for the MLDS back-end.
	Note that model_non `pragma c_code' is still not yet
	implemented, and neither is `pragma export'.

compiler/ml_code_gen.m:
	Implement code generation for par_conj goals --
	for now, we just generate sequential code for them.

Workspace: /mnt/hg/home/hg/fjh/mercury
Index: compiler/ml_code_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ml_code_gen.m,v
retrieving revision 1.22
diff -u -d -r1.22 ml_code_gen.m
--- ml_code_gen.m	1999/12/03 20:22:45	1.22
+++ ml_code_gen.m	1999/12/06 07:17:37
@@ -611,6 +611,7 @@
 
 :- import_module ml_base_type_info.
 :- import_module llds. % XXX needed for `code_model'.
+:- import_module export, llds_out. % XXX needed for pragma C code
 :- import_module code_util. % XXX needed for `code_util__compiler_generated'.
 			    % and `code_util__cons_id_to_tag'.
 :- import_module goal_util.
@@ -640,12 +641,13 @@
 :- mode ml_gen_foreign_code(in, out, di, uo) is det.
 
 ml_gen_foreign_code(ModuleInfo, MLDS_ForeignCode) -->
+	{ module_info_get_c_header(ModuleInfo, C_Header_Info) },
+	{ module_info_get_c_body_code(ModuleInfo, C_Body_Info) },
+	{ ConvBody = (func(S - C) = user_c_code(S, C)) },
+	{ User_C_Code = list__map(ConvBody, C_Body_Info) },
 	%
 	% XXX not yet implemented -- this is just a stub
 	%
-	{ module_info_get_c_header(ModuleInfo, C_Header_Info) },
-	{ module_info_get_c_body_code(ModuleInfo, _C_Body_Info) },
-	{ User_C_Code = [] },
 	{ C_Exports = [] },
 	{ MLDS_ForeignCode = mlds__foreign_code(C_Header_Info, User_C_Code,
 			C_Exports) }.
@@ -1296,9 +1298,13 @@
 		MLDS_Decls, MLDS_Statements) -->
 	ml_gen_disj(Goals, CodeModel, Context, MLDS_Decls, MLDS_Statements).
 
-ml_gen_goal_expr(par_conj(_Goals, _SM), _, _, _, _) -->
-	% XXX not yet implemented
-	{ sorry("parallel conjunction") }.
+ml_gen_goal_expr(par_conj(Goals, _SM), CodeModel, Context,
+		MLDS_Decls, MLDS_Statements) -->
+	%
+	% XXX currently we treat parallel conjunction the same as
+	%     sequential conjunction -- parallelism is not yet implemented
+	%
+	ml_gen_conj(Goals, CodeModel, Context, MLDS_Decls, MLDS_Statements).
 
 ml_gen_goal_expr(generic_call(GenericCall, Vars, Modes, Detism), CodeModel,
 		Context, MLDS_Decls, MLDS_Statements) -->
@@ -1330,14 +1336,351 @@
 	ml_gen_unification(Unification, CodeModel, Context,
 		MLDS_Decls, MLDS_Statements).
 
-ml_gen_goal_expr(pragma_c_code(_, _, _, _, _ArgNames, _, _PragmaCode),
-		_, _, [], []) -->
-	{ sorry("C interface") }.
+ml_gen_goal_expr(pragma_c_code(Attributes,
+                PredId, ProcId, ArgVars, ArgDatas, OrigArgTypes, PragmaImpl),
+		CodeModel, OuterContext, MLDS_Decls, MLDS_Statements) -->
+        (
+                { PragmaImpl = ordinary(C_Code, _MaybeContext) },
+                ml_gen_ordinary_pragma_c_code(CodeModel, Attributes,
+                        PredId, ProcId, ArgVars, ArgDatas, OrigArgTypes,
+                        C_Code, OuterContext, MLDS_Decls, MLDS_Statements)
+        ;
+                { PragmaImpl = nondet( _, _, _, _, _, _, _, _, _) },
+		{ sorry("nondet pragma c_code") }
+		/*
+                { PragmaImpl = nondet(
+                        Fields, FieldsContext, First, FirstContext,
+                        Later, LaterContext, Treat, Shared, SharedContext) },
+                ml_gen_nondet_pragma_c_code(CodeModel, Attributes,
+                        PredId, ProcId, ArgVars, ArgDatas, OrigArgTypes,
+                        Fields, FieldsContext, First, FirstContext,
+                        Later, LaterContext, Treat, Shared, SharedContext,
+                        MLDS_Decls, MLDS_Statements)
+		*/
+        ).
 
 ml_gen_goal_expr(bi_implication(_, _), _, _, _, _) -->
 	% these should have been expanded out by now
 	{ error("ml_gen_goal_expr: unexpected bi_implication") }.
+
+:- pred ml_gen_ordinary_pragma_c_code(code_model, pragma_c_code_attributes,
+		pred_id, proc_id, list(prog_var), list(maybe(pair(string, mode))),
+		list(prog_type), string, prog_context,
+		mlds__defns, mlds__statements, ml_gen_info, ml_gen_info).
+:- mode ml_gen_ordinary_pragma_c_code(in, in, in, in, in, in, 
+		in, in, in, out, out, in, out) is det.
+
+	% We generate code of the following form:
+	%
+	% model_det pragma_c_code:
+	%
+	%	{
+	% 		<declaration of one local variable for each arg>
+	%
+	%		<assign input args>
+	%		<obtain global lock>
+	%		<c code>
+	%		<release global lock>
+	%		<assign output args>
+	%	}
+	%		
+	% model_semi pragma_c_code:
+	%
+	%	{
+	% 		<declaration of one local variable for each arg>
+	%		#define SUCCESS_INDICATOR <succeeded>
+	%
+	%		<assign input args>
+	%		<obtain global lock>
+	%		<c code>
+	%		<release global lock>
+	%		if (SUCCESS_INDICATOR) {
+	%			<assign output args>
+	%		}
+	%	}
+	%		
+	% Note that we generate this code directly as
+	% `target_code(lang_C, <string>)' instructions in the MLDS.
+	% It would probably be nicer to encode more of the structure
+	% in the MLDS, so that (a) we could do better MLDS optimization
+	% and (b) so that the generation of C code strings could be
+	% isolated in mlds_to_c.m.  Also we will need to do something
+	% different for targets other than C, e.g. when compiling to
+	% Java.
+	%
+ml_gen_ordinary_pragma_c_code(CodeModel, Attributes,
+		PredId, _ProcId, ArgVars, ArgDatas, OrigArgTypes,
+		C_Code, Context, MLDS_Decls, MLDS_Statements) -->
+	%
+	% Combine all the information about the each arg
+	%
+	{ ml_make_c_arg_list(ArgVars, ArgDatas, OrigArgTypes,
+		ArgList) },
+
+	%
+	% Generate <declaration of one local variable for each arg>
+	%
+	{ ml_gen_pragma_c_decls(ArgList, ArgDeclsList) },
+
+	%
+	% Generate code to set the values of the input variables.
+	%
+	list__map_foldl(ml_gen_pragma_c_input_arg, ArgList, AssignInputsList),
+
+	%
+	% Generate code to assign the values of the output variables.
+	%
+	list__map_foldl(ml_gen_pragma_c_output_arg, ArgList, AssignOutputsList),
+
+	%
+	% Generate code fragments to obtain and release the global lock
+	% (this is used for ensuring thread safety in a concurrent
+	% implementation)
+	% XXX we should only generate these if the `parallel' option
+	% was enabled
+	%
+	=(MLDSGenInfo),
+	{ thread_safe(Attributes, ThreadSafe) },
+	{ ThreadSafe = thread_safe ->
+		ObtainLock = "",
+		ReleaseLock = ""
+	;
+		ml_gen_info_get_module_info(MLDSGenInfo, ModuleInfo),
+		module_info_pred_info(ModuleInfo, PredId, PredInfo),
+		pred_info_name(PredInfo, Name),
+		llds_out__quote_c_string(Name, MangledName),
+		string__append_list(["\tMR_OBTAIN_GLOBAL_LOCK(""",
+			MangledName, """);\n"], ObtainLock),
+		string__append_list(["\tMR_RELEASE_GLOBAL_LOCK(""",
+			MangledName, """);\n"], ReleaseLock)
+	},
+
+	%
+	% Put it all together
+	%
+	{ string__append_list(ArgDeclsList, ArgDecls) },
+	{ string__append_list(AssignInputsList, AssignInputsCode) },
+	{ string__append_list(AssignOutputsList, AssignOutputsCode) },
+	( { CodeModel = model_det } ->
+		{ string__append_list([
+				"{\n",
+				ArgDecls,
+				"\n",
+				AssignInputsCode,
+				ObtainLock,
+				"\t\t{\n",
+				C_Code,
+				"\n\t\t}\n",
+				ReleaseLock,
+				AssignOutputsCode,
+				"}\n"],
+			Combined_C_Code) }
+	; { CodeModel = model_semi } ->
+		ml_success_lval(SucceededLval),
+		{ ml_gen_c_code_for_rval(lval(SucceededLval), SucceededVar) },
+		{ DefineSuccessIndicator = string__format(
+			"#define SUCCESS_INDICATOR = %s\n",
+			[s(SucceededVar)]) },
+		{ MaybeAssignOutputsCode = string__format(
+			"\tif (SUCCESS_INDICATOR) {\n%s\n\t}",
+			[s(AssignOutputsCode)]) },
+		{ UndefSuccessIndicator = "#undef SUCCESS_INDICATOR" },
+		{ string__append_list([
+				"{\n",
+				ArgDecls,
+				DefineSuccessIndicator,
+				"\n",
+				AssignInputsCode,
+				ObtainLock,
+				"\t\t{\n",
+				C_Code,
+				"\n\t\t}\n",
+				ReleaseLock,
+				MaybeAssignOutputsCode,
+				UndefSuccessIndicator,
+				"}\n"],
+			Combined_C_Code) }
+	;
+		{ error("ml_gen_ordinary_pragma_c_code: unexpected code model") }
+	),
+	{ C_Code_Stmt = target_code(lang_C, Combined_C_Code) },
+	{ C_Code_Statement = mlds__statement(atomic(C_Code_Stmt),
+		mlds__make_context(Context)) },
+	{ MLDS_Statements = [C_Code_Statement] },
+	{ MLDS_Decls = [] }.
+
+%---------------------------------------------------------------------------%
+
+%
+% we gather all the information about each pragma_c argument
+% together into this struct
+%
+
+:- type ml_c_arg
+	--->	ml_c_arg(
+			prog_var,
+			maybe(pair(string, mode)),	% name and mode
+			prog_type	% original type before
+					% inlining/specialization
+					% (the actual type may be an instance
+					% of this type, if this type is
+					% polymorphic).
+		).
+
+:- pred ml_make_c_arg_list(list(prog_var)::in,
+		list(maybe(pair(string, mode)))::in, list(prog_type)::in,
+		list(ml_c_arg)::out) is det.
+
+ml_make_c_arg_list(Vars, ArgDatas, Types, ArgList) :-
+	( Vars = [], ArgDatas = [], Types = [] ->
+		ArgList = []
+	; Vars = [V|Vs], ArgDatas = [N|Ns], Types = [T|Ts] ->
+		Arg = ml_c_arg(V, N, T),
+		ml_make_c_arg_list(Vs, Ns, Ts, Args),
+		ArgList = [Arg | Args]
+	;
+		error("ml_code_gen:make_c_arg_list - length mismatch")
+	).
+
+%---------------------------------------------------------------------------%
+
+% ml_gen_pragma_c_decls generates C code to declare the arguments
+% for a `pragma c_code' declaration.
+%
+:- pred ml_gen_pragma_c_decls(list(ml_c_arg)::in, list(string)::out) is det.
+
+ml_gen_pragma_c_decls([], []).
+ml_gen_pragma_c_decls([Arg|Args], [Decl|Decls]) :-
+	ml_gen_pragma_c_decl(Arg, Decl),
+	ml_gen_pragma_c_decls(Args, Decls).
+
+% ml_gen_pragma_c_decl generates C code to declare an argument
+% of a `pragma c_code' declaration.
+%
+:- pred ml_gen_pragma_c_decl(ml_c_arg::in, string::out) is det.
+
+ml_gen_pragma_c_decl(ml_c_arg(_Var, MaybeNameAndMode, Type), DeclString) :-
+	(
+		MaybeNameAndMode = yes(ArgName - _Mode),
+		\+ var_is_singleton(ArgName)
+	->
+		export__type_to_type_string(Type, TypeString),
+		string__format("\t%s %s;\n", [s(TypeString), s(ArgName)],
+			DeclString)
+	;
+		% if the variable doesn't occur in the ArgNames list,
+		% it can't be used, so we just ignore it
+		DeclString = ""
+	).
+
+%-----------------------------------------------------------------------------%
+
+% var_is_singleton determines whether or not a given pragma_c variable
+% is singleton (i.e. starts with an underscore)
+%
+% Singleton vars should be ignored when generating the declarations for
+% pragma_c arguments because:
+%
+%	- they should not appear in the C code
+% 	- they could clash with the system name space
+%
+:- pred var_is_singleton(string) is semidet.
+:- mode var_is_singleton(in) is semidet.
+
+var_is_singleton(Name) :-
+	string__first_char(Name, '_', _).
+
+%-----------------------------------------------------------------------------%
+
+% ml_gen_pragma_c_input_arg generates C code to assign the value of an input
+% arg for a `pragma c_code' declaration.
+%
+:- pred ml_gen_pragma_c_input_arg(ml_c_arg::in, string::out,
+		ml_gen_info::in, ml_gen_info::out) is det.
+
+ml_gen_pragma_c_input_arg(ml_c_arg(Var, MaybeNameAndMode, OrigType),
+		AssignInputString) -->
+	=(MLDSGenInfo),
+	{ ml_gen_info_get_module_info(MLDSGenInfo, ModuleInfo) },
+	(
+		{ MaybeNameAndMode = yes(ArgName - Mode) },
+		{ \+ var_is_singleton(ArgName) },
+		{ mode_to_arg_mode(ModuleInfo, Mode, OrigType, top_in) }
+	->
+		ml_variable_type(Var, VarType),
+		ml_gen_var(Var, VarLval),
+		{ type_util__is_dummy_argument_type(VarType) ->
+			% The variable may not have been declared,
+			% so we need to generate a dummy value for it.
+			% Using `0' here is more efficient than
+			% using private_builtin__dummy_var, which is
+			% what ml_gen_var will have generated for this
+			% variable.
+			Var_ArgName = "0"
+		;
+			ml_gen_box_or_unbox_rval(VarType, OrigType, lval(VarLval),
+				ArgRval),
+			ml_gen_c_code_for_rval(ArgRval, Var_ArgName)
+		},
+		{ string__format("\t%s = %s;\n", [s(ArgName), s(Var_ArgName)],
+			AssignInputString) }
+	;
+		% if the variable doesn't occur in the ArgNames list,
+		% it can't be used, so we just ignore it
+		{ AssignInputString = "" }
+	).
+
+% ml_gen_pragma_c_output_arg generates C code to assign the value of an output
+% arg for a `pragma c_code' declaration.
+%
+:- pred ml_gen_pragma_c_output_arg(ml_c_arg::in, string::out,
+		ml_gen_info::in, ml_gen_info::out) is det.
+
+ml_gen_pragma_c_output_arg(ml_c_arg(Var, MaybeNameAndMode, OrigType),
+		AssignOutputString) -->
+	=(MLDSGenInfo),
+	{ ml_gen_info_get_module_info(MLDSGenInfo, ModuleInfo) },
+	(
+		{ MaybeNameAndMode = yes(ArgName - Mode) },
+		{ \+ var_is_singleton(ArgName) },
+		{ \+ type_util__is_dummy_argument_type(OrigType) },
+		{ mode_to_arg_mode(ModuleInfo, Mode, OrigType, top_out) }
+	->
+		ml_variable_type(Var, VarType),
+		ml_gen_var(Var, VarLval),
+		{ ml_gen_box_or_unbox_rval(OrigType, VarType, lval(VarLval),
+			ArgRval) },
+		{ ml_gen_c_code_for_rval(ArgRval, Var_ArgName) },
+		{ string__format("\t%s = %s;\n", [s(Var_ArgName), s(ArgName)],
+			AssignOutputString) }
+	;
+		% if the variable doesn't occur in the ArgNames list,
+		% it can't be used, so we just ignore it
+		{ AssignOutputString = "" }
+	).
+
+	%
+	% XXX this is a bit of a hack --
+	% for `pragma c_code', we generate the C code for an mlds__rval
+	% directly rather than going via the MLDS
+	%
+:- pred ml_gen_c_code_for_rval(mlds__rval::in, string::out) is det.
+ml_gen_c_code_for_rval(ArgRval, Var_ArgName) :-
+	( ArgRval = lval(var(qual(ModuleName, VarName))) ->
+		SymName = mlds_module_name_to_sym_name(ModuleName),
+		llds_out__sym_name_mangle(SymName, MangledModuleName),
+		llds_out__name_mangle(VarName, MangledVarName),
+		string__append_list([MangledModuleName, "__",
+			MangledVarName], Var_ArgName)
+	; ArgRval = lval(mem_ref(lval(var(qual(ModuleName, VarName))))) ->
+		SymName = mlds_module_name_to_sym_name(ModuleName),
+		llds_out__sym_name_mangle(SymName, MangledModuleName),
+		llds_out__name_mangle(VarName, MangledVarName),
+		string__append_list(["*", MangledModuleName, "__",
+			MangledVarName], Var_ArgName)
+	;
+		sorry("complicated pragma c_code")
+	).
 
 %-----------------------------------------------------------------------------%
 %
Index: compiler/mlds_to_c.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds_to_c.m,v
retrieving revision 1.19
diff -u -d -r1.19 mlds_to_c.m
--- mlds_to_c.m	1999/12/03 20:22:45	1.19
+++ mlds_to_c.m	1999/12/06 06:14:40
@@ -32,6 +32,7 @@
 
 :- implementation.
 
+:- import_module llds. % XXX needed for C interface types
 :- import_module llds_out. % XXX needed for llds_out__name_mangle.
 :- import_module globals, options, passes_aux.
 :- import_module builtin_ops, c_util, modules.
@@ -245,21 +246,43 @@
 		io__state, io__state).
 :- mode mlds_output_c_hdr_decls(in, in, di, uo) is det.
 
-% XXX not yet implemented
-mlds_output_c_hdr_decls(_, _) --> [].
+mlds_output_c_hdr_decls(Indent, ForeignCode) -->
+	% XXX we don't yet handle `pragma export' decls
+	{ ForeignCode = mlds__foreign_code(RevHeaderCode, _RevBodyCode,
+		_ExportDefns) },
+	{ HeaderCode = list__reverse(RevHeaderCode) },
+	io__write_list(HeaderCode, "\n", mlds_output_c_hdr_decl(Indent)).
+
+:- pred mlds_output_c_hdr_decl(indent, c_header_code, io__state, io__state).
+:- mode mlds_output_c_hdr_decl(in, in, di, uo) is det.
+
+mlds_output_c_hdr_decl(_Indent, Code - Context) -->
+	mlds_output_context(mlds__make_context(Context)),
+	io__write_string(Code).
 
 :- pred mlds_output_c_decls(indent, mlds__foreign_code, io__state, io__state).
 :- mode mlds_output_c_decls(in, in, di, uo) is det.
 
-% XXX not yet implemented
+% all of the declarations go in the header file or as c_code
 mlds_output_c_decls(_, _) --> [].
 
 :- pred mlds_output_c_defns(indent, mlds__foreign_code, io__state, io__state).
 :- mode mlds_output_c_defns(in, in, di, uo) is det.
 
-% XXX not yet implemented
-mlds_output_c_defns(_, _) --> [].
+mlds_output_c_defns(Indent, ForeignCode) -->
+	% XXX export decls
+	{ ForeignCode = mlds__foreign_code(_RevHeaderCode, RevBodyCode,
+		_ExportDefns) },
+	{ BodyCode = list__reverse(RevBodyCode) },
+	io__write_list(BodyCode, "\n", mlds_output_c_defn(Indent)).
 
+:- pred mlds_output_c_defn(indent, user_c_code, io__state, io__state).
+:- mode mlds_output_c_defn(in, in, di, uo) is det.
+
+mlds_output_c_defn(_Indent, user_c_code(Code, Context)) -->
+	mlds_output_context(mlds__make_context(Context)),
+	io__write_string(Code).
+
 %-----------------------------------------------------------------------------%
 %
 % Code to output declarations and definitions
@@ -1409,18 +1432,16 @@
 	%
 	% foreign language interfacing
 	%
-mlds_output_atomic_stmt(_Indent, target_code(_TargetLang, _CodeString), _) -->
-	{ error("mlds_to_c.m: sorry, target_code not implemented") }.
-/*
-		target_code(target_lang, string)
-			% Do whatever is specified by the string,
-			% which can be any piece of code in the specified
-			% target language (C, assembler, or whatever)
-			% that does not have any non-local flow of control.
-*/
+mlds_output_atomic_stmt(_Indent, target_code(TargetLang, CodeString), Context) -->
+	( { TargetLang = lang_C } ->
+		mlds_output_context(Context),
+		io__write_string(CodeString)
+	;
+		{ error("mlds_to_c.m: sorry, target_code only works for lang_C") }
+	).
 
-:- pred mlds_output_init_args(list(rval), list(mlds__type), mlds__context,
-		int, mlds__lval, tag, indent, io__state, io__state).
+:- pred mlds_output_init_args(list(mlds__rval), list(mlds__type), mlds__context,
+		int, mlds__lval, mlds__tag, indent, io__state, io__state).
 :- mode mlds_output_init_args(in, in, in, in, in, in, in, di, uo) is det.
 
 mlds_output_init_args([_|_], [], _, _, _, _, _) -->
@@ -1752,7 +1773,7 @@
 
 %-----------------------------------------------------------------------------%
 
-:- pred mlds_output_tag(tag, io__state, io__state).
+:- pred mlds_output_tag(mlds__tag, io__state, io__state).
 :- mode mlds_output_tag(in, di, uo) is det.
 
 mlds_output_tag(Tag) -->

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