[m-rev.] diff: clean up GCC back-end callbacks

Fergus Henderson fjh at cs.mu.OZ.AU
Tue May 8 15:36:05 AEST 2001


Estimated hours taken: 2
Branches: main

Clean up some of the code in the GCC back-end.

compiler/gcc.m:
compiler/mlds_to_gcc.m:
	Move the code for initializing the GCC back-end and calling
	back to the Mercury front-end from mlds_to_gcc.m to gcc.m, at the
	same time generalizing it (the callback procedure is now passed
	as a parameter to gcc__run_backend, rather than being hard-coded).
	This changes means that all of the code for interfacing with
	GCC is now in gcc.m, and mlds_to_gcc.m only talks to GCC via
	that interface.

compiler/Mmakefile:
	There's no longer any need to pass the CFLAGS options needed
	for GCC when compiling mlds_to_gcc.m.

Workspace: /mnt/hg/home/hg/fjh/gcc-cvs/gcc/mercury
Index: compiler/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/Mmakefile,v
retrieving revision 1.41
diff -u -d -r1.41 Mmakefile
--- compiler/Mmakefile	2001/01/29 06:47:17	1.41
+++ compiler/Mmakefile	2001/05/08 05:09:16
@@ -110,8 +110,6 @@
 		-I$(GCC_SRC_DIR)/gcc/config \
 		-I$(GCC_SRC_DIR)/include \
 		-I$(GCC_SRC_DIR)
-# Likewise for mlds_to_gcc.m
-CFLAGS-mlds_to_gcc = $(CFLAGS-gcc)
 
 #-----------------------------------------------------------------------------#
 
Index: compiler/gcc.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/gcc.m,v
retrieving revision 1.22
diff -u -d -r1.22 gcc.m
--- compiler/gcc.m	2001/02/26 01:33:52	1.22
+++ compiler/gcc.m	2001/05/08 05:21:14
@@ -68,6 +68,41 @@
 
 %-----------------------------------------------------------------------------%
 
+	% gcc__run_backend(CommandLine, ReturnValue, FrontEndCallBack, Output):
+	% 
+	% This is the top-level routine that MUST be used to invoke the
+	% GCC back-end.  It makes sure GCC has been initialized, using
+	% the specified CommandLine for GCC's command-line parameters,
+	% and then calls the specified FrontEndCallBack procedure.
+	% The FrontEndCallBack should then call the appropriate
+	% routines defined below (e.g. gcc__{start,end}_function,
+	% gcc__gen_expr_stmt, etc.) to generate code.  When it
+	% is finished, the FrontEndCallBack can return an Output.
+	% gcc__run_backend will then finish generating the assembler
+	% file and clean up.  Finally gcc__run_backend will return
+	% the Output of the FrontEndCallBack procedure back to the
+	% caller of gcc__run_backend.  ReturnValue will be the
+	% return value from the GCC backend, i.e. zero if all is OK,
+	% and non-zero if something went wrong.
+	% 
+	% WARNING: The other functions and predicates defined in this
+	% module MUST NOT be called directly; they can only be called
+	% from the FrontEndCallBack routine passed to gcc__run_backend.
+	% Otherwise the GCC back-end won't get properly initialized.
+	% 
+	% Due to limitations in the GCC back-end, this routine must
+	% not be called more than once; if it is, it will print an
+	% error message and abort execution.
+
+:- type frontend_callback(T) == pred(T, io__state, io__state).
+:- inst frontend_callback == (pred(out, di, uo) is det).
+
+:- pred gcc__run_backend(string::in, int::out, 
+		frontend_callback(T)::in(frontend_callback), T::out,
+		io__state::di, io__state::uo) is det.
+
+%-----------------------------------------------------------------------------%
+
 % The GCC `tree' type.
 :- type gcc__tree.
 :- type gcc__tree_code.
@@ -659,6 +694,215 @@
 
 ").
 
+%-----------------------------------------------------------------------------%
+
+	%
+	% For gcc__run_backend, there's two possible cases, depending on who
+	% defined main():
+	%
+	%	1. GCC main():
+	%		gcc/toplev.c gets control first.
+	%
+	%		In this case, by the time we get to here
+	%		(gcc.m), the GCC back-end has already
+	%		been initialized.  We can go ahead and directly
+	%		call the front-end callback to generate the
+	%		GCC tree and RTL.  When we return back to
+	%		main/2 in mercury_compile, and that returns,
+	% 		the gcc back-end will continue on and will
+	%		generate the asm file. 
+	%
+	%		Note that mercury_compile.m can't invoke the
+	% 		assembler to produce an object file, since
+	% 		the assembler won't get produced until
+	%		after main/2 has exited!  Instead, the gcc
+	%		driver program (`gcc') will invoke the assembler.
+	%		
+	%	2. Mercury main():
+	%		mercury_compile.m gets control first.
+	%
+	%		When we get here (gcc.m), the gcc back-end
+	%		has not been initialized. We need to save
+	%		the front-end callback in a global variable,
+	%		and then invoke the GCC toplev_main() here.
+	%		This will start the GCC back-end, which will
+	%		eventually call MC_continue_frontend().
+	%		MC_continue_frontend() will then call the front-end
+	%		callback that we saved in a global earlier.
+	%		Eventually MC_continue_frontend() will
+	%		return and the gcc back-end will continue.
+	%
+	%		It's OK for mercury_compile.m to invoke the assembler.
+	%
+	%		XXX For programs with nested modules,
+	%		we'll end up calling the gcc back-end
+	%		more than once; this will lead to an abort.
+	%		
+
+gcc__run_backend(CommandLine, ReturnValue, FrontEndCallBack, Output) -->
+	in_gcc(InGCC),
+	( { InGCC = yes } ->
+		FrontEndCallBack(Output),
+		{ ReturnValue = 0 }
+	;
+		set_global_frontend_callback(FrontEndCallBack),
+		call_gcc_backend(CommandLine, ReturnValue),
+		get_global_frontend_callback_output(Output)
+	).
+
+	% Returns `yes' iff we've already entered the gcc back-end.
+:- pred in_gcc(bool::out, io__state::di, io__state::uo) is det.
+:- pragma import(in_gcc(out, di, uo), "MC_in_gcc").
+
+:- pred call_gcc_backend(string::in, int::out,
+		io__state::di, io__state::uo) is det.
+:- pragma import(call_gcc_backend(in, out, di, uo), "MC_call_gcc_backend").
+
+:- pragma c_header_code("
+/* We use an `MC_' prefix for C code in the mercury/compiler directory. */
+
+extern MR_Word MC_frontend_callback;
+extern MR_Word MC_frontend_callback_output;
+extern MR_Word MC_frontend_callback_type;
+
+void MC_in_gcc(MR_Word *result);
+void MC_call_gcc_backend(MR_String all_args, MR_Integer *result);
+void MC_continue_frontend(void);
+
+#include ""mercury_wrapper.h""		/* for MR_make_argv() */
+#include <stdio.h>			/* for fprintf() */
+#include <stdlib.h>			/* for exit() */
+").
+
+:- pragma c_code("
+
+/* We use an `MC_' prefix for C code in the mercury/compiler directory. */
+MR_Word MC_frontend_callback;
+MR_Word MC_frontend_callback_output;
+MR_Word MC_frontend_callback_type;
+
+extern int toplev_main(int argc, char **argv);
+
+void
+MC_in_gcc(MR_Word *result)
+{
+	/* If we've already entered gcc, then gcc will have set progname. */
+	*result = (progname != NULL);
+}
+
+void
+MC_call_gcc_backend(MR_String all_args, MR_Integer *result)
+{
+	char *args;
+	char **argv;
+	int argc;
+	const char *error_msg;
+	static int num_calls = 0;
+
+	/*
+	** The gcc back-end cannot be called more than once.
+	** If you try, it uses up all available memory.
+	** So we need to abort nicely in that case.
+	**
+	** That case will happen if (a) there were nested
+	** sub-modules or (b) the user specified more than
+	** one module on the command line.
+	*/
+	num_calls++;
+	if (num_calls > 1) {
+		fprintf(stderr, ""Sorry, not implemented: ""
+			""calling GCC back-end multiple times.\\n""
+			""This can occur if you are trying to ""
+			""compile more than one module\\n""
+			""at a time with `--target asm'.\\n""
+			""Please use separate sub-modules ""
+			""rather than nested sub-modules,\\n""
+			""i.e. put each sub-module in its own file, ""
+			""and don't specify more\\n""
+			""than one module on the command line ""
+			""(use Mmake instead).\\n""
+			""Or alternatively, just use `--target c'.\\n"");
+		exit(EXIT_FAILURE);
+	}
+
+	error_msg = MR_make_argv(all_args, &args, &argv, &argc);
+	if (error_msg) {
+		fprintf(stderr,
+			""Error parsing GCC back-end arguments:\n%s\n"",
+			error_msg);
+		exit(EXIT_FAILURE);
+	}
+
+	merc_continue_frontend = &MC_continue_frontend;
+	*result = toplev_main(argc, argv);
+
+	/*
+	** Reset GCC's progname after we return from toplev_main(),
+	** so that MC_in_gcc() knows that we're no longer in GCC. 
+	*/
+	progname = NULL;
+
+	MR_GC_free(args);
+	MR_GC_free(argv);
+}
+
+/*
+** This is called from yyparse() in mercury/mercury-gcc.c
+** in the gcc back-end.
+*/
+void
+MC_continue_frontend(void)
+{
+	MC_call_frontend_callback(MC_frontend_callback_type,
+		MC_frontend_callback, &MC_frontend_callback_output);
+}
+").
+
+:- pred call_frontend_callback(frontend_callback(T)::in(frontend_callback),
+		T::out, io__state::di, io__state::uo) is det.
+
+:- pragma export(call_frontend_callback(in(frontend_callback), out, di, uo),
+	"MC_call_frontend_callback").
+
+call_frontend_callback(FrontEndCallBack, Output) -->
+	FrontEndCallBack(Output).
+
+:- pred get_global_frontend_callback(
+		frontend_callback(T)::out(frontend_callback),
+		io__state::di, io__state::uo) is det.
+:- pred set_global_frontend_callback(
+		frontend_callback(T)::in(frontend_callback),
+		io__state::di, io__state::uo) is det.
+:- pred get_global_frontend_callback_output(T::out,
+		io__state::di, io__state::uo) is det.
+:- pred set_global_frontend_callback_output(T::in,
+		io__state::di, io__state::uo) is det.
+
+:- pragma c_code(get_global_frontend_callback(CallBack::out(frontend_callback),
+	_IO0::di, _IO::uo), [will_not_call_mercury],
+"
+	CallBack = MC_frontend_callback;
+").
+:- pragma c_code(set_global_frontend_callback(CallBack::in(frontend_callback),
+	_IO0::di, _IO::uo), [will_not_call_mercury],
+"
+	MC_frontend_callback = CallBack;
+	MC_frontend_callback_type = TypeInfo_for_T;
+
+").
+:- pragma c_code(get_global_frontend_callback_output(Output::out,
+	_IO0::di, _IO::uo), [will_not_call_mercury],
+"
+	Output = MC_frontend_callback_output;
+").
+:- pragma c_code(set_global_frontend_callback_output(Output::in,
+	_IO0::di, _IO::uo),
+	[will_not_call_mercury],
+"
+	MC_frontend_callback_output = Output;
+").
+
+%-----------------------------------------------------------------------------%
 
 :- type gcc__tree ---> gcc__tree(c_pointer).
 :- type gcc__tree_code == int.
Index: compiler/mlds_to_gcc.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds_to_gcc.m,v
retrieving revision 1.36
diff -u -d -r1.36 mlds_to_gcc.m
--- compiler/mlds_to_gcc.m	2001/03/16 07:51:59	1.36
+++ compiler/mlds_to_gcc.m	2001/05/08 05:15:16
@@ -142,63 +142,7 @@
 %-----------------------------------------------------------------------------%
 
 mlds_to_gcc__compile_to_asm(MLDS, ContainsCCode) -->
-	%
-	% There's two possible cases, depending on who defined main().
-	%
-	%	1. GCC main():
-	%		gcc/toplev.c gets control first.
-	%
-	%		In this case, by the time we get to here
-	%		(mlds_to_gcc.m), the GCC back-end has already
-	%		been initialized.  We can go ahead and generate
-	%		the GCC tree and RTL.  When we return back to
-	%		main/2 in mercury_compile, and that returns,
-	% 		the gcc back-end will continue on and will
-	%		generate the asm file. 
-	%
-	%		Note that mercury_compile.m can't invoke the
-	% 		assembler to produce an object file, since
-	% 		the assembler won't get produced until
-	%		after main/2 has exited!  Instead, the gcc
-	%		driver program (`gcc') will invoke the assembler.
-	%		
-	%	2. Mercury main():
-	%		mercury_compile.m gets control first.
-	%
-	%		When we get here (mlds_to_gcc.m), the gcc back-end
-	%		has not been initialized.
-	%		We need to save the MLDS in a global variable,
-	%		and then invoke the GCC toplev_main() here.
-	%		This will start the GCC back-end, which will
-	%		eventually call MC_continue_frontend().
-	%		Eventually MC_continue_frontend() will
-	%		return and the gcc back-end will continue.
-	%
-	%		It's OK for mercury_compile.m to invoke the assembler.
-	%
-	%		XXX For programs with nested modules,
-	%		we'll end up calling the gcc back-end
-	%		more than once; this will probably crash.
-	%		
-	in_gcc(InGCC),
-	( { InGCC = yes } ->
-		mlds_to_gcc__compile_to_gcc(MLDS, ContainsCCode)
-	;
-		set_global_mlds(MLDS),
-		{ MLDS = mlds(ModuleName, _, _, _) },
-		do_call_gcc_backend(ModuleName, Result),
-		( { Result \= 0 } ->
-			io__set_exit_status(1)
-		;
-			[]
-		),
-		get_global_contains_c_code(ContainsCCode)
-	).
-
-:- pred do_call_gcc_backend(mlds__mercury_module_name::in, int::out,
-		io__state::di, io__state::uo) is det.
-
-do_call_gcc_backend(ModuleName, Result) -->
+	{ MLDS = mlds(ModuleName, _, _, _) },
 	globals__io_lookup_bool_option(pic, Pic),
 	{ Pic = yes ->
 		PicExt = ".pic_s",
@@ -241,153 +185,13 @@
 	maybe_write_string(Verbose, "% Invoking GCC back-end as `"),
 	maybe_write_string(Verbose, CommandLine),
 	maybe_write_string(Verbose, "':\n"),
-	call_gcc_backend(CommandLine, Result),
+	gcc__run_backend(CommandLine, Result,
+		mlds_to_gcc__compile_to_gcc(MLDS), ContainsCCode),
 	( { Result \= 0 } ->
 		report_error("GCC back-end failed!\n")
 	;
 		maybe_write_string(Verbose, "% GCC back-end done.\n")
 	).
-
-	% Returns `yes' iff we've already entered the gcc back-end.
-:- pred in_gcc(bool::out, io__state::di, io__state::uo) is det.
-:- pragma import(in_gcc(out, di, uo), "MC_in_gcc").
-
-:- pred call_gcc_backend(string::in, int::out,
-		io__state::di, io__state::uo) is det.
-:- pragma import(call_gcc_backend(in, out, di, uo), "MC_call_gcc_backend").
-
-:- pragma c_header_code("
-/* We use an `MC_' prefix for C code in the mercury/compiler directory. */
-
-extern MR_Word MC_mlds;
-extern MR_Word MC_contains_c_code;
-
-void MC_in_gcc(MR_Word *result);
-void MC_call_gcc_backend(MR_String all_args, MR_Integer *result);
-void MC_continue_frontend(void);
-
-#include ""mercury_wrapper.h""		/* for MR_make_argv() */
-#include <stdio.h>			/* for fprintf() */
-#include <stdlib.h>			/* for exit() */
-").
-
-:- pragma c_code("
-
-#ifndef MC_GUARD_GCC_HEADERS
-#define MC_GUARD_GCC_HEADERS
-
-#include ""gcc/config.h""
-#include ""gcc/system.h""
-#include ""gcc/gansidecl.h""
-#include ""gcc/toplev.h""
-#include ""gcc/tree.h""
-/* XXX we should eliminate the dependency on the C front-end */
-#include ""gcc/c-tree.h""
-
-#include ""gcc/mercury/mercury-gcc.h""
-
-#endif /* MC_GUARD_GCC_HEADERS */
-
-/* We use an `MC_' prefix for C code in the mercury/compiler directory. */
-MR_Word MC_mlds;
-MR_Word MC_contains_c_code;
-
-extern int toplev_main(int argc, char **argv);
-
-void
-MC_in_gcc(MR_Word *result)
-{
-	/* If we've already entered gcc, then gcc will have set progname. */
-	*result = (progname != NULL);
-}
-
-void
-MC_call_gcc_backend(MR_String all_args, MR_Integer *result)
-{
-	char *args;
-	char **argv;
-	int argc;
-	const char *error_msg;
-	static int num_calls = 0;
-
-	/*
-	** The gcc back-end cannot be called more than once.
-	** If you try, it uses up all available memory.
-	** So we need to abort nicely in that case.
-	**
-	** That case will happen if (a) there were nested
-	** sub-modules or (b) the user specified more than
-	** one module on the command line.
-	*/
-	num_calls++;
-	if (num_calls > 1) {
-		fprintf(stderr, ""Sorry, not implemented:\\n""
-			""compiling more than one module at a time ""
-			""with `--target asm'.\\n""
-			""Please use separate sub-modules ""
-			""rather than nested sub-modules,\\n""
-			""i.e. put each sub-module in its own file, ""
-			""and don't specify more\\n""
-			""than one module on the command line ""
-			""(use Mmake instead).\\n""
-			""Or alternatively, just use `--target c'.\\n"");
-		exit(EXIT_FAILURE);
-	}
-
-	error_msg = MR_make_argv(all_args, &args, &argv, &argc);
-	if (error_msg) {
-		fprintf(stderr,
-			""Error parsing GCC back-end arguments:\n%s\n"",
-			error_msg);
-		exit(EXIT_FAILURE);
-	}
-
-	merc_continue_frontend = &MC_continue_frontend;
-	*result = toplev_main(argc, argv);
-
-	/*
-	** Reset GCC's progname after we return from toplev_main(),
-	** so that MC_in_gcc() knows that we're no longer in GCC. 
-	*/
-	progname = NULL;
-
-	MR_GC_free(args);
-	MR_GC_free(argv);
-}
-
-void
-MC_continue_frontend(void)
-{
-	MC_compile_to_gcc(MC_mlds, &MC_contains_c_code);
-}
-").
-
-:- pred get_global_mlds(mlds__mlds::out, io__state::di, io__state::uo) is det.
-:- pred set_global_mlds(mlds__mlds::in, io__state::di, io__state::uo) is det.
-:- pred get_global_contains_c_code(bool::out,
-		io__state::di, io__state::uo) is det.
-:- pred set_global_contains_c_code(bool::in,
-		io__state::di, io__state::uo) is det.
-
-:- pragma c_code(get_global_mlds(MLDS::out, _IO0::di, _IO::uo),
-	[will_not_call_mercury],
-	"MLDS = MC_mlds;").
-:- pragma c_code(set_global_mlds(MLDS::in, _IO0::di, _IO::uo),
-	[will_not_call_mercury],
-	"MC_mlds = MLDS;").
-:- pragma c_code(get_global_contains_c_code(ContainsCCode::out,
-	_IO0::di, _IO::uo), [will_not_call_mercury],
-	"ContainsCCode = MC_contains_c_code;").
-:- pragma c_code(set_global_contains_c_code(ContainsCCode::in,
-	_IO0::di, _IO::uo), [will_not_call_mercury],
-	"MC_contains_c_code = ContainsCCode;").
-
-	%
-	% This is called from yyparse() in mercury/mercury-gcc
-	% in the gcc back-end.
-	%
-:- pragma export(mlds_to_gcc__compile_to_gcc(in, out, di, uo),
-	"MC_compile_to_gcc").
 
 :- pred mlds_to_gcc__compile_to_gcc(mlds__mlds, bool, io__state, io__state).
 :- mode mlds_to_gcc__compile_to_gcc(in, out, di, uo) is det.

-- 
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-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list