[m-dev.] for review: GCC back-end: integrate with mmc

Fergus Henderson fjh at cs.mu.OZ.AU
Sun Jan 14 05:29:26 AEDT 2001


Estimated hours taken: 12

Allow the GCC back-end and the Mercury compiler to be linked with the
Mercury compiler (rather than the GCC back-end) defining main().
This makes it a lot easier to integrate the GCC back-end interface
with the rest of the Mercury implementation.

Also add support to configure for determining the location of the GCC
source code and whether or not to enable the GCC back-end interface.

mercury/configure.in:
	Add option `--enable-gcc-back-end'.  Check for the gcc source
	code, and if it is found, enable this option by default.

mercury/Mmake.common.in:
	Add ENABLE_GCC_BACK_END and GCC_SRC_DIR variables.

mercury/compiler/Mmakefile:
	Link in the GCC back-end if ENABLE_GCC_BACK_END is set.
	Add code to preprocess `#if ENABLE_GCC_BACK_END ... #else
	... #endif' in maybe_mlds_to_gcc.pp.

mercury/compiler/maybe_mlds_to_gcc.pp:
	New file.  This is just a wrapper that calls mlds_to_gcc.m
	if the GCC back-end interface is enabled, or reports
	an error message, if it is not.

mercury/compiler/mercury_compile.m:
	If `--target asm' is enabled, call maybe_mlds_to_gcc;
	then invoke the assembler, and if there is any foreign code,
	also invoke the C compiler.

mercury/compiler/mlds_to_gcc.m:
	Add code to handle the case when main() is defined in Mercury
	rather than in GCC.  For that case, we save the MLDS in a
	global variable, invoke the GCC back-end, and then when it
	calls us back we pick up the MLDS from the global variable and
	do as we did before (i.e. convert the MLDS to GCC trees, etc.)

gcc/mercury/mercury-gcc.c:
	If we're being invoked with main() defined in Mercury,
	then change yyparse() so that it calls back to
	MC_continue_frontend() rather than mercury_main().

gcc/toplev.c:
	Rename main() as toplev_main().

gcc/main.c:
	New file.  Defines main() which calls toplev_main().

gcc/Makefile.in:
	Move toplev.o from $(BACKEND) to $(OBJS), and add main.o to $(BACKEND).
	This ensures that main() gets linked in with cc1, cc1plus, etc.,
	but does not get put in libbackend.a.

gcc/mercury/Make-lang.in:
	Add new target `mercury_back_end_libs', which is a text file
	that contains the list of libraries that we need to link with
	to resolve symbols in the GCC back-end.
	Also use $(BACKEND) rather than hand-coding things.

Workspace: /home/hg/fjh/gcc-cvs/gcc
Index: mercury/compiler/maybe_mlds_to_gcc.pp
===================================================================
RCS file: maybe_mlds_to_gcc.pp
diff -N maybe_mlds_to_gcc.pp
--- /dev/null	Thu Mar 30 14:06:13 2000
+++ maybe_mlds_to_gcc.pp	Sun Jan 14 05:07:24 2001
@@ -0,0 +1,53 @@
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2001 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.
+%-----------------------------------------------------------------------------%
+
+% maybe_mlds_to_gcc - Convert MLDS to the GCC back-end representation,
+% if the GCC back-end interface has been enabled.
+% Main author: fjh.
+
+% This is just a wrapper around mlds_to_gcc.m to enable that
+% file to be included iff we were configured with the
+% gcc back-end interface enabled.
+
+%-----------------------------------------------------------------------------%
+
+:- module maybe_mlds_to_gcc.
+:- interface.
+
+:- import_module mlds, bool.
+:- use_module io.
+
+	% Either invoke mlds_to_gcc__compile_to_asm, or report an error
+	% message, depending on whether the gcc back-end interface has
+	% been enabled.  In the former case,
+	% the bool returned is `yes' iff the module contained C code.
+:- pred maybe_mlds_to_gcc__compile_to_asm(mlds__mlds, bool,
+		io__state, io__state).
+:- mode maybe_mlds_to_gcc__compile_to_asm(in, out, di, uo) is det.
+
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+#if ENABLE_GCC_BACK_END
+
+:- use_module mlds_to_gcc.
+
+maybe_mlds_to_gcc__compile_to_asm(MLDS, ContainsCCode) -->
+	mlds_to_gcc__compile_to_asm(MLDS, ContainsCCode).
+
+#else
+
+:- import_module passes_aux.
+
+maybe_mlds_to_gcc__compile_to_asm(_MLDS, no) -->
+	report_error(
+"Sorry, `--target asm' not supported: this installation of the Mercury\n" ++
+"compiler was built without support for the GCC back-end interface.").
+
+#endif
+
+%-----------------------------------------------------------------------------%
Index: mercury/compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.186
diff -u -d -r1.186 mercury_compile.m
--- mercury/compiler/mercury_compile.m	2000/12/13 12:12:53	1.186
+++ mercury/compiler/mercury_compile.m	2001/01/13 18:13:48
@@ -63,6 +63,7 @@
 :- import_module ml_optimize.			% MLDS -> MLDS
 :- import_module mlds_to_c.			% MLDS -> C
 :- import_module mlds_to_ilasm.			% MLDS -> IL assembler
+:- import_module maybe_mlds_to_gcc.		% MLDS -> GCC back-end
 
 
 	% miscellaneous compiler modules
@@ -484,6 +485,42 @@
 				mercury_compile__il_assemble(ModuleName,
 					HasMain)
 			)
+		    ; { Target = asm } ->
+		    	% compile directly assembler using the gcc back-end
+			mercury_compile__mlds_backend(HLDS50, MLDS),
+			mercury_compile__maybe_mlds_to_gcc(MLDS,
+				ContainsCCode),
+			( { TargetCodeOnly = yes } ->
+				[]
+			;
+				% Invoke the assembler to produce an
+				% object file
+				module_name_to_file_name(ModuleName, ".s", no,
+					AsmFile),
+				object_extension(Obj),
+				module_name_to_file_name(ModuleName, Obj, yes,
+					O_File),
+				mercury_compile__asm_to_obj(
+					AsmFile, O_File, _AssembleOK),
+				%
+				% If the module contained `pragma c_code',
+				% then we will have compiled that to a
+				% separate C file.  We need to invoke the
+				% C compiler on that.
+				%
+				( { ContainsCCode = yes } ->
+					module_name_to_file_name(ModuleName,
+						".c", no, CCode_C_File),
+					module_name_to_file_name(ModuleName,
+						"__c_code" ++ Obj,
+						yes, CCode_O_File),
+					mercury_compile__single_c_to_obj(
+						CCode_C_File, CCode_O_File,
+						_CompileOK)
+				;
+					[]
+				)
+			)
 		    ; { HighLevelCode = yes } ->
 			mercury_compile__mlds_backend(HLDS50, MLDS),
 			mercury_compile__mlds_to_high_level_c(MLDS),
@@ -2544,6 +2581,19 @@
 	maybe_write_string(Verbose, "% Finished converting MLDS to C.\n"),
 	maybe_report_stats(Stats).
 
+:- pred mercury_compile__maybe_mlds_to_gcc(mlds, bool, io__state, io__state).
+:- mode mercury_compile__maybe_mlds_to_gcc(in, out, di, uo) is det.
+
+mercury_compile__maybe_mlds_to_gcc(MLDS, ContainsCCode) -->
+	globals__io_lookup_bool_option(verbose, Verbose),
+	globals__io_lookup_bool_option(statistics, Stats),
+
+	maybe_write_string(Verbose,
+		"% Passing MLDS to GCC and compiling to assembler...\n"),
+	maybe_mlds_to_gcc__compile_to_asm(MLDS, ContainsCCode),
+	maybe_write_string(Verbose, "% Finished compiling to assembler.\n"),
+	maybe_report_stats(Stats).
+
 :- pred mercury_compile__mlds_to_il_assembler(mlds, io__state, io__state).
 :- mode mercury_compile__mlds_to_il_assembler(in, di, uo) is det.
 
@@ -2866,6 +2916,33 @@
 	invoke_system_command(Command, Succeeded),
 	( { Succeeded = no } ->
 		report_error("problem compiling C file.")
+	;
+		[]
+	).
+
+:- pred mercury_compile__asm_to_obj(string, string, bool,
+					io__state, io__state).
+:- mode mercury_compile__asm_to_obj(in, in, out, di, uo) is det.
+
+mercury_compile__asm_to_obj(AsmFile, ObjFile, Succeeded) -->
+	globals__io_lookup_bool_option(verbose, Verbose),
+	maybe_write_string(Verbose, "% Assembling `"),
+	maybe_write_string(Verbose, AsmFile),
+	maybe_write_string(Verbose, "':\n"),
+	% XXX should we use new asm_* options rather than
+	% reusing cc, cflags, c_flag_to_name_object_file?
+	globals__io_lookup_string_option(cc, CC),
+	globals__io_lookup_string_option(c_flag_to_name_object_file,
+			NameObjectFile),
+	globals__io_lookup_accumulating_option(cflags, C_Flags_List),
+	{ join_string_list(C_Flags_List, "", "", " ", CFLAGS) },
+	% Be careful with the order here.
+	% Also be careful that each option is separated by spaces.
+	{ string__append_list([CC, " ", CFLAGS,
+		" -c ", AsmFile, " ", NameObjectFile, ObjFile], Command) },
+	invoke_system_command(Command, Succeeded),
+	( { Succeeded = no } ->
+		report_error("problem assembling the assembler file.")
 	;
 		[]
 	).
Index: mercury/compiler/mlds_to_gcc.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds_to_gcc.m,v
retrieving revision 1.17
diff -u -d -r1.17 mlds_to_gcc.m
--- mercury/compiler/mlds_to_gcc.m	2001/01/11 13:37:58	1.17
+++ mercury/compiler/mlds_to_gcc.m	2001/01/13 18:21:02
@@ -9,9 +9,12 @@
 
 % Note that this does *not* compile to GNU C -- instead it
 % actually generates GCC's internal "Tree" representation,
+% and then invokes the GCC back-end to compile it to assembler,
 % without going via an external file.
+% Code using the C interface, however, does get compiled to C;
+% this module invokes mlds_to_c.m to do that.
 
-% Currently this supports grade hlc.gc only.
+% Currently this back-end supports grade hlc.gc only.
 %
 % Trailing will probably work too, but since trailing
 % is currently implemented using the C interface,
@@ -67,11 +70,14 @@
 :- module mlds_to_gcc.
 :- interface.
 
-:- import_module mlds.
+:- import_module mlds, bool.
 :- use_module io.
 
-:- pred mlds_to_gcc__compile_to_asm(mlds__mlds, io__state, io__state).
-:- mode mlds_to_gcc__compile_to_asm(in, di, uo) is det.
+	% The bool returned is `yes' iff the module contained C code.
+	% In that case, we will have output a separate C file which needs
+	% to be compiled with the C compiler.
+:- pred mlds_to_gcc__compile_to_asm(mlds__mlds, bool, io__state, io__state).
+:- mode mlds_to_gcc__compile_to_asm(in, out, di, uo) is det.
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
@@ -101,13 +107,204 @@
 
 %-----------------------------------------------------------------------------%
 
-:- type output_type == pred(mlds__type, io__state, io__state).
-:- inst output_type = (pred(in, di, uo) is det).
+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) -->
+	module_name_to_file_name(ModuleName, ".m", no, SourceFileName),
+	module_name_to_file_name(ModuleName, ".s", yes, AsmFileName),
+	% XXX should use new gcc_* options rather than
+	% reusing cflags, c_optimize
+	globals__io_lookup_bool_option(statistics, Statistics),
+	{ Statistics = yes ->
+		QuietOption = ""
+	;
+		QuietOption = "-quiet "
+	},
+	globals__io_lookup_bool_option(c_optimize, C_optimize),
+	{ C_optimize = yes ->
+		OptimizeOpt = "-O2 -fomit-frame-pointer "
+	;
+		OptimizeOpt = ""
+	},
+	globals__io_lookup_bool_option(target_debug, Target_Debug),
+	{ Target_Debug = yes ->
+		Target_DebugOpt = "-g "
+	;
+		Target_DebugOpt = ""
+	},
+	globals__io_lookup_accumulating_option(cflags, C_Flags_List),
+	{ CFLAGS = string__append_list(list__map(func(Flag) = Flag ++ " ",
+		C_Flags_List)) },
+	% Be careful with the order here.
+	% Also be careful that each option is separated by spaces.
+	{ string__append_list(["""<GCC back-end>"" ",
+		QuietOption, OptimizeOpt, Target_DebugOpt, CFLAGS,
+		SourceFileName, " -o ", AsmFileName], CommandLine) },
+	globals__io_lookup_bool_option(verbose, Verbose),
+	maybe_write_string(Verbose, "% Invoking GCC back-end as `"),
+	maybe_write_string(Verbose, CommandLine),
+	maybe_write_string(Verbose, "':\n"),
+	call_gcc_backend(CommandLine, Result),
+	( { 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").
 
-mlds_to_gcc__compile_to_asm(MLDS) -->
+:- 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() */
+").
+
+:- pragma c_code("
+#include ""config.h""
+#include ""system.h""
+#include ""gansidecl.h""
+#include ""toplev.h""
+#include ""tree.h""
+#include ""mercury-gcc.h""
+
+/* 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;
+
+	error_msg = MR_make_argv(all_args, &args, &argv, &argc);
+	if (error_msg) {
+		MR_fatal_error(""error parsing GCC back-end arguments:\n%s\n"",
+			error_msg);
+	}
+	merc_continue_frontend = &MC_continue_frontend;
+	*result = toplev_main(argc, argv);
+	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.
+
+mlds_to_gcc__compile_to_gcc(MLDS, ContainsCCode) -->
 	{ MLDS = mlds(ModuleName, ForeignCode, Imports, Defns0) },
 
 	%
@@ -120,6 +317,7 @@
 		{ ForeignCode = mlds__foreign_code([], [], []) },
 		{ ForeignDefns = [] }
 	->
+		{ ContainsCCode = no },
 		% there's no foreign code, so we don't need to
 		% do anything special
 		{ NeedInitFn = yes }
@@ -129,6 +327,8 @@
 		{ ForeignMLDS = mlds(ModuleName, ForeignCode, Imports,
 			ForeignDefns) },
 		mlds_to_c__output_mlds(ForeignMLDS),
+		% XXX currently the only foreign code we handle is C
+		{ ContainsCCode = yes },
 		{ NeedInitFn = no }
 	),
 
Index: mercury/compiler/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/Mmakefile,v
retrieving revision 1.36
diff -u -d -r1.36 Mmakefile
--- mercury/compiler/Mmakefile	2001/01/13 06:48:40	1.36
+++ mercury/compiler/Mmakefile	2001/01/13 17:41:17
@@ -15,6 +15,20 @@
 
 #-----------------------------------------------------------------------------#
 
+# Specify how to link in the GCC back-end.
+# This uses the file `mercury_gcc_backend_libs', which is generated by
+# the gcc Makefile (from gcc/mercury/Make-lang.in), which contains
+# a list of the object files and libraries that we need to link in.
+GCC_SRC_DIR := $(MERCURY_DIR)/$(GCC_SRC_DIR)
+ifeq ($(ENABLE_GCC_BACK_END),yes)
+GCC_LIBS = $(shell cat $(GCC_SRC_DIR)/gcc/mercury_gcc_backend_libs)
+GCC_EXTRA_LIBS = $(filter -l%,$(GCC_LIBS))
+GCC_MAIN_LIBS = $(patsubst %,$(GCC_SRC_DIR)/gcc/%,$(filter-out -l%,$(GCC_LIBS)))
+GCC_BACKEND_LIBS = $(GCC_MAIN_LIBS) $(GCC_EXTRA_LIBS)
+else
+GCC_BACKEND_LIBS =
+endif
+
 # Specify which compilers to use to compile the compiler.
 # Don't change these without good reason - if you want to
 # do a temporary change, change ../Mmake.params
@@ -43,7 +57,7 @@
 		MERCURY_MKINIT=$(UTIL_DIR)/mkinit $(SCRIPTS_DIR)/c2init
 C2INITFLAGS =	--library
 ML	=	MERCURY_C_LIB_DIR=. $(SCRIPTS_DIR)/ml
-MLFLAGS =	--mercury-libs none
+MLFLAGS =	--shared --mercury-libs none
 MLLIBS  =	../main.o \
 		$(TRACE_DIR)/lib$(TRACE_LIB_NAME).$A \
 		$(BROWSER_DIR)/lib$(BROWSER_LIB_NAME).$A \
@@ -56,7 +70,9 @@
 			*.gc*.prof*)	echo $(BOEHM_GC_DIR)/libgc_prof.$A ;; \
 			*.gc*)		echo $(BOEHM_GC_DIR)/libgc.$A ;; \
 		    esac \
-		` $(MATH_LIB)
+		` \
+		$(GCC_BACKEND_LIBS) \
+		$(MATH_LIB)
 MTAGS	=	$(SCRIPTS_DIR)/mtags
 MTAGSFLAGS =	$(EXTRA_MTAGSFLAGS)
 
@@ -85,7 +101,6 @@
 
 # The c_code in the module gcc.m needs the header files from the GNU C
 # distribution.
-GCC_SRC_DIR=	../../../..
 CFLAGS-gcc =	-DMERCURY_BOOTSTRAP_H \
 		-DIN_GCC -DHAVE_CONFIG_H \
 		-I. \
@@ -93,43 +108,70 @@
 		-I$(GCC_SRC_DIR)/gcc/mercury \
 		-I$(GCC_SRC_DIR)/gcc/config \
 		-I$(GCC_SRC_DIR)/include \
-
+# Likewise for mlds_to_gcc.m
+CFLAGS-mlds_to_gcc = $(CFLAGS-gcc)
 
 #-----------------------------------------------------------------------------#
 
 # Rules for preprocessing `.pp' files.
 # `.pp_date' files are used as timestamps as for interface files.
-
-ifeq ($(INCLUDE_ADITI_OUTPUT),yes)
 
-# Remove the #if line and everything between the #else and #endif lines.
+#
+# Rule to generate foo.m from foo.pp by applying `sed $(PP_SED_EXPR)'
+#
+# Note that we set hash="#" for use in $(PP_SED_EXPR).
+# This seems to be the easiest way to get a "#" character;
+# we can't just use a Make variable since "#" is a comment character
+# in Make and so its hard to create a variable with that value.
+#
 $(dates_subdir)%.pp_date: %.pp
-	-m_file=$(<:.pp=.m); \
+	-hash="#"; \
+	m_file=$(<:.pp=.m); \
 	[ ! -f $$m_file ] || chmod +w $$m_file; \
-	sed	-e '/^#if *INCLUDE_ADITI_OUTPUT/s/.*//' \
-		-e '/^#else/,/^#endif/s/.*//' \
-		$< > $$m_file.tmp; \
-	mercury_update_interface -v $$m_file; \
-	touch $@; \
+	sed $(PP_SED_EXPR) $< > $$m_file.tmp && \
+	mercury_update_interface -v $$m_file && \
+	touch $@ && \
 	chmod -w $$m_file
 
-else
+#
+# Define $(PP_SED_EXPR) appropriately for each preprocessed module.
+#
+PP_SED_EXPR			= $(PP_SED_EXPR-$*)
+PP_SED_EXPR-rl_file 		= $(ADITI_SED_EXPR)
+PP_SED_EXPR-rl_out		= $(ADITI_SED_EXPR)
+PP_SED_EXPR-maybe_mlds_to_gcc	= $(GCC_SED_EXPR)
 
+#
+# For Aditi .pp files, enable/disable code within
+# `#if INCLUDE_ADITI_OUTPUT ... #else .. #endif'
+#
+ifeq ($(INCLUDE_ADITI_OUTPUT),yes)
+# Remove the #if line and everything between the #else and #endif lines.
+ADITI_SED_EXPR = -e "/^$${hash}if *INCLUDE_ADITI_OUTPUT/s/.*//" \
+		 -e "/^$${hash}else/,/^$${hash}endif/s/.*//"
+else
 # Remove everything between the #if line and the #else line,
 # and the #endif line.
-$(dates_subdir)%.pp_date: %.pp
-	-m_file=$(<:.pp=.m); \
-	[ ! -f $$m_file ] || chmod +w $$m_file; \
-	sed	-e '/^#if *INCLUDE_ADITI_OUTPUT/,/^#else/s/.*//' \
-		-e '/^#endif/s/.*//' \
-		$< > $$m_file.tmp; \
-	mercury_update_interface -v $$m_file; \
-	touch $@; \
-	chmod -w $$m_file
+ADITI_SED_EXPR = -e "/^$${hash}if *INCLUDE_ADITI_OUTPUT/,/^$${hash}else/s/.*//" \
+		 -e "/^$${hash}endif/s/.*//"
+endif
 
+#
+# For GCC .pp files, enable/disable code within
+# `#if ENABLE_GCC_BACK_END ... #else .. #endif'
+#
+ifeq ($(ENABLE_GCC_BACK_END),yes)
+# Remove the #if line and everything between the #else and #endif lines.
+GCC_SED_EXPR =	-e "/^$${hash}if *ENABLE_GCC_BACK_END/s/.*//" \
+		-e "/^$${hash}else/,/^$${hash}endif/s/.*//"
+else
+# Remove everything between the #if line and the #else line,
+# and the #endif line.
+GCC_SED_EXPR =	-e "/^$${hash}if *ENABLE_GCC_BACK_END/,/^$${hash}else/s/.*//" \
+		-e "/^$${hash}endif/s/.*//"
 endif
 
-PREPROCESSED_MODULES = rl_file rl_out
+PREPROCESSED_MODULES = rl_file rl_out maybe_mlds_to_gcc
 PREPROCESSED_FILES = $(PREPROCESSED_MODULES:%=%.pp)
 PREPROCESSED_M_FILES = $(PREPROCESSED_MODULES:%=%.m)
 PP_DATE_FILES = $(PREPROCESSED_MODULES:%=$(dates_subdir)%.pp_date)
Index: mercury/configure.in
===================================================================
RCS file: /home/mercury1/repository/mercury/configure.in,v
retrieving revision 1.240
diff -u -d -r1.240 configure.in
--- mercury/configure.in	2001/01/13 07:18:09	1.240
+++ mercury/configure.in	2001/01/13 17:18:38
@@ -120,6 +120,70 @@
 	rm -f conftest*
 fi
 #-----------------------------------------------------------------------------#
+#
+# Find the GCC source code
+# and determine whether or not to enable the GCC back-end interface.
+#
+AC_ARG_ENABLE(gcc-back-end,
+[  --enable-gcc-back-end   enable the Mercury compiler's GCC back-end interface],
+enable_gcc_back_end="$enableval",enable_gcc_back_end=default)
+AC_MSG_CHECKING(for GCC source directory)
+gcc_src_dir=not_found
+case $enable_gcc_back_end in
+	yes|no|default)
+		# Search for the gcc source code;
+		# first try in a subdirectory of this directory,
+		# then one parallel to this directory,
+		# and finally try one level up.
+		for dir in gcc ../gcc ..; do
+			if test -f $dir/gcc/tree.c; then
+				gcc_src_dir="$dir"
+				break
+			fi
+		done
+		;;
+	*)
+		# The user has specifies the gcc source directory via
+		# `--enable-gcc-back-end=<directory>'.  Check that
+		# they specified it correctly.
+		gcc_src_dir="$enable_gcc_back_end"
+		if test -f "$gcc_src_dir"/gcc/tree.c; then
+			enable_gcc_back_end=yes
+		else
+			AC_MSG_ERROR(--enable-gcc-back-end=$gcc_src_dir specified,)
+			AC_MSG_ERROR(but GCC source code not found in $gcc_src_dir)
+			exit 1
+		fi		
+		;;
+esac
+AC_MSG_RESULT($gcc_src_dir)
+AC_MSG_CHECKING(whether to enable the GCC back-end interface)
+case $enable_gcc_back_end in
+	yes|default)
+		if test "$gcc_src_dir" = not_found; then
+			case $enable_gcc_back_end in
+				yes)
+					AC_MSG_ERROR(--enable-gcc-back-end specified,)
+					AC_MSG_ERROR(but gcc source code not found)
+					exit 1
+					;;
+				default)
+					enable_gcc_back_end=no
+					;;
+			esac
+		else
+			enable_gcc_back_end=yes
+		fi
+		;;
+	no)
+		;;
+esac
+AC_MSG_RESULT($enable_gcc_back_end)
+ENABLE_GCC_BACK_END=$enable_gcc_back_end
+GCC_SRC_DIR=$gcc_src_dir
+AC_SUBST(ENABLE_GCC_BACK_END)
+AC_SUBST(GCC_SRC_DIR)
+#-----------------------------------------------------------------------------#
 MERCURY_MSG("looking for GNU Make...")
 AC_PROGRAMS_CHECK(GNU_MAKE,gmake make)
 if test "$GNU_MAKE" != ""; then
Index: mercury/Mmake.common.in
===================================================================
RCS file: /home/mercury1/repository/mercury/Mmake.common.in,v
retrieving revision 1.48
diff -u -d -r1.48 Mmake.common.in
--- mercury/Mmake.common.in	2000/09/22 08:23:44	1.48
+++ mercury/Mmake.common.in	2001/01/13 15:12:49
@@ -154,6 +154,18 @@
 # complicating things.
 LIBRARY_INTERMODULE = yes
 
+# Do we want to include the support for compiling directly to assembler
+# using the GCC back-end in the compiler?
+# This requires that you have the source code for gcc in the
+# directory ../gcc.
+ENABLE_GCC_BACK_END = @ENABLE_GCC_BACK_END@
+
+# Specify the directory containing the GCC sources.
+# This should contain subdirectories `gcc', `libiberty', etc.,
+# and the `gcc' subdirectory should contain files `gcc.c',
+# `tree.c', `tree.h', etc.
+GCC_SRC_DIR = @GCC_SRC_DIR@
+
 # Do we want to include the support for Aditi compilation in the compiler?
 # It is not practical to include the code to output Aditi-RL in the alias
 # branch compiler - it currently takes more than an hour to compile
Index: gcc/main.c
===================================================================
RCS file: main.c
diff -N main.c
--- /dev/null	Tue May  5 13:32:27 1998
+++ main.c	Sat Jan 13 10:26:34 2001
@@ -0,0 +1,35 @@
+/* main.c: defines main() for cc1, cc1plus, etc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#include "gansidecl.h"
+#include "toplev.h"
+
+int main PARAMS ((int argc, char **argv));
+
+/* We define main() to call toplev_main(), which is defined in toplev.c.
+   We do this in a separate file in order to allow the language front-end
+   to define a different main(), if it so desires.  */
+
+int
+main (argc, argv)
+  int argc;
+  char **argv;
+{
+  return toplev_main (argc, argv);
+}
Index: gcc/Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.574
diff -u -d -r1.574 Makefile.in
--- Makefile.in	2000/12/22 12:27:35	1.574
+++ Makefile.in	2001/01/13 18:26:36
@@ -738,9 +738,9 @@
  mbchar.o splay-tree.o graph.o sbitmap.o resource.o hash.o predict.o	      \
  lists.o ggc-common.o $(GGC) stringpool.o simplify-rtx.o ssa.o bb-reorder.o   \
  sibcall.o conflict.o timevar.o ifcvt.o dominance.o dependence.o dce.o \
- sched-vis.o sched-deps.o sched-rgn.o sched-ebb.o hashtab.o
+ sched-vis.o sched-deps.o sched-rgn.o sched-ebb.o hashtab.o toplev.o
 
-BACKEND = toplev.o libbackend.a
+BACKEND = main.o libbackend.a
 
 # GEN files are listed separately, so they can be built before doing parallel
 #  makes for cc1 or cc1plus.  Otherwise sequent parallel make attempts to load
@@ -1315,6 +1315,7 @@
 	$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(MAYBE_USE_COLLECT2) \
 	  -DTARGET_NAME=\"$(target_alias)\" \
 	  -c $(srcdir)/toplev.c
+main.o : main.c toplev.h
 
 rtl.o : rtl.c $(GCONFIG_H) system.h $(RTL_H) bitmap.h $(GGC_H) toplev.h
 	$(CC) -c $(ALL_CFLAGS) -DGENERATOR_FILE $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
Index: gcc/toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.408
diff -u -d -r1.408 toplev.c
--- toplev.c	2000/12/29 13:09:35	1.408
+++ toplev.c	2001/01/13 18:26:38
@@ -192,7 +192,7 @@
 
 const char *progname;
 
-/* Copy of arguments to main.  */
+/* Copy of arguments to toplev_main.  */
 int save_argc;
 char **save_argv;
 

@@ -4502,14 +4502,15 @@
   return 1;
 }
 

-/* Entry point of cc1/c++.  Decode command args, then call compile_file.
-   Exit code is 35 if can't open files, 34 if fatal error,
-   33 if had nonfatal errors, else success.  */
-
-extern int main PARAMS ((int, char **));
+/* Entry point of cc1, cc1plus, jc1, f771, etc.
+   Decode command args, then call compile_file.
+   Exit code is FATAL_EXIT_CODE if can't open files or if there were
+   any errors, or SUCCESS_EXIT_CODE if compilation succeeded.
+   
+   It is not safe to call this function more than once.  */
 
 int
-main (argc, argv)
+toplev_main (argc, argv)
      int argc;
      char **argv;
 {
Index: gcc/mercury/Make-lang.in
===================================================================
RCS file: /home/mercury1/repository/gcc/mercury/Make-lang.in,v
retrieving revision 1.3
diff -u -d -r1.3 Make-lang.in
--- gcc/mercury/Make-lang.in	2001/01/01 13:57:04	1.3
+++ gcc/mercury/Make-lang.in	2001/01/13 16:47:24
@@ -53,6 +53,9 @@
 	$(MERCURY_FRONT_END_SRC_DIR)/runtime/libmer_rt.a \
 	$(MERCURY_FRONT_END_SRC_DIR)/boehm_gc/libgc.a
 
+# GCC object files used for the Mercury front-end.
+MERCURY_GCC_OBJS = mercury/mercury-gcc.o c-convert.o
+
 # Additional C libraries that we need to link in
 # because they are needed by the libraries listed above.
 MERCURY_C_LIBS = -lm
@@ -63,10 +66,6 @@
 MLFLAGS =
 ALL_MLFLAGS = $(MLFLAGS) $(EXTRA_MLFLAGS)
 
-# Libraries from the GNU back-end that we need.
-MERCURY_BACK_END_LIBS = toplev.o libbackend.a \
-	$(LIBIBERTY) $(INTLLIBS) $(LIBS) $(LIBDEPS)
-
 # List any automatically generated files, e.g.
 # MERCURY_GENERATED = $(srcdir)/mercury/parse.c
 MERCURY_GENERATED =
@@ -87,18 +86,24 @@
 
 mercury MERCURY: mercury/cc1mercury$(exeext) mercury/testmercury$(exeext)
 
-mercury/cc1mercury$(exeext): mercury/mercury-gcc.o $(OBJDEPS) $(LIBDEPS) \
-		c-convert.o $(MERCURY_FRONT_END_LIBS) $(MERCURY_BACK_END_LIBS)
-	@echo mercury objs = $(OBJS)
-	$(CC) $(ALL_CFLAGS) $(LDFLAGS) mercury/mercury-gcc.o c-convert.o \
-		$(OBJS) $(MERCURY_BACK_END_LIBS) $(MERCURY_FRONT_END_LIBS) \
-		$(MERCURY_C_LIBS) \
+mercury/cc1mercury$(exeext): $(MERCURY_FRONT_END_LIBS) $(MERCURY_GCC_OBJS) \
+		$(BACKEND) $(LIBDEPS)
+	$(CC) $(ALL_CFLAGS) $(LDFLAGS) \
+		$(MERCURY_GCC_OBJS) $(MERCURY_FRONT_END_LIBS) $(BACKEND) \
+		$(LIBS) $(MERCURY_C_LIBS) \
 		-o $@ 
 	@# The code above uses the C compiler to do the linking.
 	@# Another alternative would be to use the Mercury linker instead:
 	@# $(ML) $(ALL_MLFLAGS) $(ALL_CFLAGS) $(LDFLAGS) \
 	@	mercury/mercury-gcc.o c-convert.o \
 	@	$(OBJS) $(MERCURY_BACK_END_LIBS) -o $@ 
+
+# The mercury_gcc_backend_libs target contains a list of the
+# libraries and object files that need to be linked with the
+# MERCURY_FRONT_END_LIBS.
+mercury_gcc_backend_libs: $(MERCURY_GCC_OBJS) libbackend.a $(LIBDEPS)
+	echo $(MERCURY_GCC_OBJS) libbackend.a $(LIBS) \
+		> mercury_gcc_backend_libs
 
 mercury/testmercury$(exeext): mercury/testmercury.o mercury/test.o 
 	$(CC) $(ALL_CFLAGS) $(LDFLAGS) mercury/testmercury.o mercury/test.o \
Index: gcc/mercury/mercury-gcc.c
===================================================================
RCS file: /home/mercury1/repository/gcc/mercury/mercury-gcc.c,v
retrieving revision 1.20
diff -u -d -r1.20 mercury-gcc.c
--- gcc/mercury/mercury-gcc.c	2001/01/08 03:02:52	1.20
+++ gcc/mercury/mercury-gcc.c	2001/01/13 18:04:26
@@ -70,6 +70,7 @@
 static tree merc_convert PARAMS((tree type, tree expr));
 static void merc_init_builtin_functions PARAMS((void));
 static void merc_handle_fatal_error PARAMS((const char *msg, va_list *args));
+static int merc_call_mercury_compiler PARAMS((void));
 
 /*---------------------------------------------------------------------------*/
 
@@ -77,7 +78,9 @@
 
 extern char **save_argv; /* in toplev.c */
 
-/* Global Variables for the various types and nodes we create.  */ 
+/* Global Variables defined here.  */ 
+
+void (*merc_continue_frontend) PARAMS((void)) = NULL;
 
 /* Declaration nodes for builtin functions:  */
 tree merc_alloc_function_node;		/* GC_malloc() */
@@ -634,7 +637,28 @@
   return filename;
 }
 
-/* This is the main entry point.
+/* This is the main entry point.  */
+int
+yyparse (void)
+{
+  if (merc_continue_frontend != NULL)
+    {
+      /* We're using the Mercury main().  We've already started
+         the Mercury compiler, and it has already parsed the
+         source code and built the MLDS.  All we need to do now
+         is to generate the GCC tree and expand it to RTL.  */
+      (*merc_continue_frontend) ();
+      return 0;
+    }
+  else
+    {
+      /* We're using the gcc main(), and we haven't run
+         the Mercury compiler yet.  Do so.  */
+      return merc_call_mercury_compiler ();
+    }
+}
+
+/* This is the main entry point, if we're using a gcc main().
    We invoke the Mercury compiler, which will
    	1. parse the source code,
    	2. perform semantic analysis (e.g. type checking),
@@ -651,8 +675,8 @@
    for each function, which in turn will call rest_of_compilation(),
    which invokes the remaining stages of the GCC back-end.  */
 
-int
-yyparse (void)
+static int
+merc_call_mercury_compiler ()
 {
   const char *base_argv[] = {
     "--target", "asm", "--target-code-only"
@@ -700,9 +724,8 @@
   free (argv);
 
   /* XXX We should set errorcount properly, but currently we don't.  */
-  if (result != 0 && errorcount == 0) {
-  	errorcount++;
-  }
+  if (result != 0 && errorcount == 0)
+    errorcount++;
 
   return result;
 }

-- 
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