diff --git a/Mmake.common.in b/Mmake.common.in index 00d23e125..a0de62dff 100644 --- a/Mmake.common.in +++ b/Mmake.common.in @@ -1,5 +1,5 @@ #-----------------------------------------------------------------------------# -# Copyright (C) 1995-2000 The University of Melbourne. +# Copyright (C) 1995-2001 The University of Melbourne. # This file may only be copied under the terms of the GNU General # Public Licence - see the file COPYING in the Mercury distribution. #-----------------------------------------------------------------------------# @@ -154,6 +154,18 @@ MCFLAGS = --no-infer-all --halt-at-warn # 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 diff --git a/compiler/Mmakefile b/compiler/Mmakefile index 7dda91524..59388d513 100644 --- a/compiler/Mmakefile +++ b/compiler/Mmakefile @@ -15,6 +15,20 @@ VPATH=$(LIBRARY_DIR) $(BROWSER_DIR) #-----------------------------------------------------------------------------# +# 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 @@ -56,7 +70,9 @@ MLLIBS = ../main.$O \ *.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 @@ CFLAGS-rl_code=-O1 # 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 @@ CFLAGS-gcc = -DMERCURY_BOOTSTRAP_H \ -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 -PREPROCESSED_MODULES = rl_file rl_out +# +# 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 maybe_mlds_to_gcc PREPROCESSED_FILES = $(PREPROCESSED_MODULES:%=%.pp) PREPROCESSED_M_FILES = $(PREPROCESSED_MODULES:%=%.m) PP_DATE_FILES = $(PREPROCESSED_MODULES:%=$(dates_subdir)%.pp_date) diff --git a/compiler/maybe_mlds_to_gcc.pp b/compiler/maybe_mlds_to_gcc.pp new file mode 100644 index 000000000..bceddd923 --- /dev/null +++ b/compiler/maybe_mlds_to_gcc.pp @@ -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 + +%-----------------------------------------------------------------------------% diff --git a/compiler/mercury_compile.m b/compiler/mercury_compile.m index b722eb40b..2eb89ca9c 100644 --- a/compiler/mercury_compile.m +++ b/compiler/mercury_compile.m @@ -1,5 +1,5 @@ %-----------------------------------------------------------------------------% -% Copyright (C) 1994-2000 The University of Melbourne. +% Copyright (C) 1994-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. %-----------------------------------------------------------------------------% @@ -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(Module) --> 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 @@ mercury_compile__mlds_to_high_level_c(MLDS) --> 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. @@ -2870,6 +2920,33 @@ mercury_compile__single_c_to_obj(C_File, O_File, Succeeded) --> [] ). +:- 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.") + ; + [] + ). + %-----------------------------------------------------------------------------% :- pred mercury_compile__link_module_list(list(string), io__state, io__state). diff --git a/compiler/mlds_to_gcc.m b/compiler/mlds_to_gcc.m index 9ad41c045..5a69b97ec 100644 --- a/compiler/mlds_to_gcc.m +++ b/compiler/mlds_to_gcc.m @@ -9,9 +9,25 @@ % 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. - -% Currently this supports grade hlc.gc only. +% +% Code using the C interface, however, does get compiled to C; this module +% invokes mlds_to_c.m to do that. We split off all the parts of the MLDS +% for `c_code'/`foreign_code' declarations, `c_header_code'/`foreign_decl' +% declarations, `export' declarations, and procedures defined with +% `c_code'/`foreign_proc', and pass them to mlds_to_c.m. That will generate +% a `.c' file for this module; mercury_compile.m will invoke the C +% compiler to compile that to `__c_code.o'. The remainding parts +% of the MLDS, which don't contain any foreign code, we handle normally, +% converting them to GCC trees and passing them to the GCC back-end +% to generate an assembler file. Calls to procedures defined using +% `c_code'/`foreign_proc' will end up calling the functions defined in +% `__c_code.o'. This works because the calling convention that +% is used for the MLDS->C back-end is the same as (i.e. binary compatible +% with) the calling convention that we use here in the MLDS->GCC back-end. +% +% Currently this back-end supports grade hlc.gc only. % % Trailing will probably work too, but since trailing % is currently implemented using the C interface, @@ -23,7 +39,7 @@ % with C; need to promote boolean return type to int % % Fix configuration issues: -% - mmake support +% - mmake support for foreign code % - document installation procedure % - test more % - support in tools/bootcheck and check that it bootchecks @@ -67,11 +83,23 @@ :- 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. + % + % XXX Currently the only foreign language we handle is C. + % To make it work properly we'd need to change the + % `ContainsCCode' boolean that we return to instead be a list + % of the foreign languages used, so that mercury_compile.m + % will know which foreign language files have been generated + % which foreign language compilers it needs to invoke, + % and which object files to link into the executable. + +:- 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 +129,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([""""" ", + 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") + ). -mlds_to_gcc__compile_to_asm(MLDS) --> + % 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() */ +"). + +:- 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 +339,7 @@ mlds_to_gcc__compile_to_asm(MLDS) --> { 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 +349,10 @@ mlds_to_gcc__compile_to_asm(MLDS) --> { ForeignMLDS = mlds(ModuleName, ForeignCode, Imports, ForeignDefns) }, mlds_to_c__output_mlds(ForeignMLDS), + % XXX currently the only foreign code we handle is C; + % see comments above (at the declaration for + % mlds_to_c__compile_to_asm) + { ContainsCCode = yes }, { NeedInitFn = no } ), @@ -1712,13 +1936,12 @@ build_rtti_type(notag_functor_desc, _, GCC_Type) --> % typedef struct { % MR_ConstString MR_notag_functor_name; % MR_PseudoTypeInfo MR_notag_functor_arg_type; - % XXX need to add the following field when I do a cvs update: - % /***MR_ConstString MR_notag_functor_arg_name;***/ + % MR_ConstString MR_notag_functor_arg_name; % } MR_NotagFunctorDesc; build_struct_type("MR_NotagFunctorDesc", ['MR_ConstString' - "MR_notag_functor_name", - 'MR_PseudoTypeInfo' - "MR_notag_functor_arg_type"], - %%% 'MR_ConstString' - "MR_notag_functor_arg_name"], + 'MR_PseudoTypeInfo' - "MR_notag_functor_arg_type", + 'MR_ConstString' - "MR_notag_functor_arg_name"], GCC_Type). build_rtti_type(du_functor_desc(_), _, GCC_Type) --> % typedef struct { @@ -1738,9 +1961,7 @@ build_rtti_type(du_functor_desc(_), _, GCC_Type) --> gcc__build_pointer_type(MR_DuExistInfo, MR_DuExistInfoPtr), gcc__build_pointer_type('MR_ConstString', MR_ConstStringPtr), build_struct_type("MR_DuFunctorDesc", - ['MR_ConstString' - "MR_notag_functor_name", - 'MR_PseudoTypeInfo' - "MR_notag_functor_arg_type", - 'MR_ConstString' - "MR_du_functor_name", + ['MR_ConstString' - "MR_du_functor_name", 'MR_int_least16_t' - "MR_du_functor_orig_arity", 'MR_int_least16_t' - "MR_du_functor_arg_type_contains_var", 'MR_Sectag_Locn' - "MR_du_functor_sectag_locn", diff --git a/compiler/modules.m b/compiler/modules.m index 44d0a7647..2c3bc358c 100644 --- a/compiler/modules.m +++ b/compiler/modules.m @@ -1,5 +1,5 @@ %-----------------------------------------------------------------------------% -% Copyright (C) 1996-2000 The University of Melbourne. +% Copyright (C) 1996-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. %-----------------------------------------------------------------------------% @@ -1793,9 +1793,11 @@ write_dependency_file(Module, AllDepsSet, MaybeTransOptDeps) --> ), globals__io_lookup_bool_option(highlevel_code, HighLevelCode), - ( { HighLevelCode = yes } -> + globals__io_get_target(CompilationTarget), + ( { HighLevelCode = yes, CompilationTarget = c } -> % - % For --high-level-code, we need to make sure that we + % For --high-level-code with --target c, + % we need to make sure that we % generate the header files for imported modules % before compiling the C files, since the generated C % files #include those header files. @@ -2706,7 +2708,8 @@ generate_dv_file(SourceFileName, ModuleName, DepsMap, DepStream) --> io__write_string(DepStream, MakeVarName), io__write_string(DepStream, ".ss = "), - write_compact_dependencies_list(Modules, "", ".s", Basis, DepStream), + write_compact_dependencies_list(Modules, "$(ss_subdir)", ".s", + Basis, DepStream), io__write_string(DepStream, "\n"), io__write_string(DepStream, MakeVarName), @@ -2882,10 +2885,14 @@ generate_dep_file(SourceFileName, ModuleName, DepsMap, DepStream) --> % module_name_to_file_name(SourceModuleName, "", no, ExeFileName), io__write_strings(DepStream, [ - "ifeq ($(RM_C),:)\n", - MakeVarName, ".maybe_cs=$(", MakeVarName, ".cs)\n", + "ifeq ($(TARGET_ASM),yes)\n", + MakeVarName, ".maybe_cs=$(", MakeVarName, ".ss)\n", "else\n", + " ifeq ($(RM_C),:)\n", + MakeVarName, ".maybe_cs=$(", MakeVarName, ".cs)\n", + " else\n", MakeVarName, ".maybe_cs=\n", + " endif\n\n", "endif\n\n" ]), diff --git a/configure.in b/configure.in index 086ec7cd3..ddca07cb2 100644 --- a/configure.in +++ b/configure.in @@ -120,6 +120,70 @@ EOF 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='. 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 diff --git a/runtime/mercury_type_info.h b/runtime/mercury_type_info.h index 885588740..83d138114 100644 --- a/runtime/mercury_type_info.h +++ b/runtime/mercury_type_info.h @@ -22,6 +22,7 @@ ** compiler/type_ctor_info.m ** compiler/rtti.m ** compiler/rtti_out.m +** compiler/mlds_to_gcc.m ** (for updating the compiler-generated RTTI ** structures) ** diff --git a/runtime/mercury_wrapper.c b/runtime/mercury_wrapper.c index 5f8633a8e..8ee357bce 100644 --- a/runtime/mercury_wrapper.c +++ b/runtime/mercury_wrapper.c @@ -3,7 +3,7 @@ INIT mercury_sys_init_wrapper ENDINIT */ /* -** Copyright (C) 1994-2000 The University of Melbourne. +** Copyright (C) 1994-2001 The University of Melbourne. ** This file may only be copied under the terms of the GNU Library General ** Public License - see the file COPYING.LIB in the Mercury distribution. */ @@ -241,7 +241,6 @@ static void process_args(int argc, char **argv); static void process_environment_options(void); static void process_options(int argc, char **argv); static void usage(void); -static void make_argv(const char *, char **, char ***, int *); #ifdef MEASURE_REGISTER_USAGE static void print_register_usage_counts(void); @@ -472,12 +471,15 @@ MR_do_init_modules_debugger(void) /* ** Given a string, parse it into arguments and create an argv vector for it. -** Returns args, argv, and argc. It is the caller's responsibility to +** The return value is NULL if the string parses OK, or an error message +** if it didn't (e.g. if it contained an unterminated quoted string). +** Also returns args, argv, and argc. It is the caller's responsibility to ** MR_GC_free() args and argv when they are no longer needed. */ -static void -make_argv(const char *string, char **args_ptr, char ***argv_ptr, int *argc_ptr) +const char * +MR_make_argv(const char *string, + char **args_ptr, char ***argv_ptr, int *argc_ptr) { char *args; char **argv; @@ -511,10 +513,10 @@ make_argv(const char *string, char **args_ptr, char ***argv_ptr, int *argc_ptr) /* "double quoted" arg - scan until next double quote */ while (*s != '"') { if (s == '\0') { - MR_fatal_error( - "Mercury runtime: unterminated quoted string\n" - "in MERCURY_OPTIONS environment variable\n" - ); + *args_ptr = NULL; + *argv_ptr = NULL; + *argc_ptr = argc; + return "unterminated quoted string"; } if (*s == '\\') s++; @@ -582,7 +584,8 @@ make_argv(const char *string, char **args_ptr, char ***argv_ptr, int *argc_ptr) *args_ptr = args; *argv_ptr = argv; *argc_ptr = argc; -} /* end make_argv() */ + return NULL; /* success */ +} /* end MR_make_argv() */ /* ** process_args() is a function that sets some global variables from the @@ -613,13 +616,14 @@ process_environment_options(void) const char *cmd; char *arg_str, **argv; char *dummy_command_line; + const char *error_msg; int argc; /* ** getopt() expects the options to start in argv[1], ** not argv[0], so we need to insert a dummy program ** name (we use "mercury_runtime") at the start of the - ** options before passing them to make_argv() and then + ** options before passing them to MR_make_argv() and then ** to getopt(). */ cmd = "mercury_runtime "; @@ -628,7 +632,12 @@ process_environment_options(void) strcpy(dummy_command_line, cmd); strcat(dummy_command_line, options); - make_argv(dummy_command_line, &arg_str, &argv, &argc); + error_msg = MR_make_argv(dummy_command_line, + &arg_str, &argv, &argc); + if (error_msg != NULL) { + MR_fatal_error("error parsing the MERCURY_OPTIONS " + "environment variable:\n%s\n", error_msg); + } MR_GC_free(dummy_command_line); process_options(argc, argv); diff --git a/runtime/mercury_wrapper.h b/runtime/mercury_wrapper.h index b0e0e9f7c..538ae28d5 100644 --- a/runtime/mercury_wrapper.h +++ b/runtime/mercury_wrapper.h @@ -1,5 +1,5 @@ /* -** Copyright (C) 1994-2000 The University of Melbourne. +** Copyright (C) 1994-2001 The University of Melbourne. ** This file may only be copied under the terms of the GNU Library General ** Public License - see the file COPYING.LIB in the Mercury distribution. */ @@ -226,4 +226,7 @@ extern void MR_register_type_ctor_stat(MR_TypeStat *type_stat, #endif +/* This is used by compiler/mlds_to_gcc.m. */ +const char *MR_make_argv(const char *, char **, char ***, int *); + #endif /* not MERCURY_WRAPPER_H */ diff --git a/scripts/Mmake.rules b/scripts/Mmake.rules index 565999471..476b1d484 100644 --- a/scripts/Mmake.rules +++ b/scripts/Mmake.rules @@ -168,6 +168,25 @@ $(trans_opts_subdir)%.trans_opt : $(trans_opt_dates_subdir)%.trans_opt_date # duplicated in compiler/modules.m. # +ifeq ($(TARGET_ASM),yes) + +# `--target asm' back-end +$(ss_subdir)%.s : %.m + $(MCG) $(ALL_GRADEFLAGS) --target-code-only $(ALL_MCGFLAGS) \ + $< > $*.err 2>&1 + +$(ss_subdir)%.pic_s : %.m + $(MCG) $(ALL_GRADEFLAGS) --target-code-only $(ALL_MCGFLAGS) \ + --cflags "$(CFLAGS_FOR_PIC)" $< > $*.err 2>&1 + +$(os_subdir)%.$O : $(ss_subdir)%.s + $(AS) $< $(OBJFILE_OPT)$@ + +$(os_subdir)%.pic_o : $(ss_subdir)%.pic_s + $(AS) $< $(OBJFILE_OPT)$@ + +endif + # C back-end $(cs_subdir)%.c : %.m rm -f $(cs_subdir)$*.c @@ -175,7 +194,7 @@ $(cs_subdir)%.c : %.m # Aditi-RL back-end $(rlos_subdir)%.rlo : %.m - rm -f $(rlos_subdir)$*.c + rm -f $(rlos_subdir)$*.rlo $(MCG) $(ALL_GRADEFLAGS) $(ALL_MCGFLAGS) --aditi-only $< > $*.err 2>&1 # .NET back-end diff --git a/scripts/Mmake.vars.in b/scripts/Mmake.vars.in index b4350bab7..8bade1292 100644 --- a/scripts/Mmake.vars.in +++ b/scripts/Mmake.vars.in @@ -47,7 +47,17 @@ DEFAULT_GRADE = $(MERCURY_DEFAULT_GRADE) GRADE = $(DEFAULT_GRADE) GRADESTRING = $(shell $(MCOGS) $(ALL_GRADEFLAGS)) -ALL_GRADEFLAGS = $(GRADEFLAGS) $(EXTRA_GRADEFLAGS) $(TARGET_GRADEFLAGS) +# This may be overridden on the command line +TARGET_ASM = no + +ifeq ($(TARGET_ASM),yes) +ASM_OPT = --target asm +else +ASM_OPT = +endif + +ALL_GRADEFLAGS = $(USUAL_GRADEFLAGS) $(ASM_OPT) +USUAL_GRADEFLAGS = $(GRADEFLAGS) $(EXTRA_GRADEFLAGS) $(TARGET_GRADEFLAGS) GRADEFLAGS = --grade $(GRADE) EXTRA_GRADEFLAGS = @@ -404,6 +414,7 @@ date3s_subdir=$(SUBDIR)date3s/ optdates_subdir=$(SUBDIR)optdates/ trans_opt_dates_subdir=$(SUBDIR)trans_opt_dates/ cs_subdir=$(SUBDIR)cs/ +ss_subdir=$(SUBDIR)cs/ os_subdir=$(SUBDIR)os/ rlos_subdir=$(SUBDIR)rlos/ ils_subdir=$(SUBDIR)ils/ @@ -429,6 +440,7 @@ date3s_subdir= optdates_subdir= trans_opt_dates_subdir= cs_subdir= +ss_subdir= os_subdir= rlos_subdir= ils_subdir= diff --git a/scripts/final_grade_options.sh-subr b/scripts/final_grade_options.sh-subr index fe677dbb8..3b66b9fb7 100644 --- a/scripts/final_grade_options.sh-subr +++ b/scripts/final_grade_options.sh-subr @@ -1,5 +1,5 @@ #---------------------------------------------------------------------------# -# Copyright (C) 1998-2000 The University of Melbourne. +# Copyright (C) 1998-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. #---------------------------------------------------------------------------# @@ -39,9 +39,9 @@ case $stack_trace,$require_tracing,$use_minimal_model in esac # -# IL implies --high-level-code +# --target asm or IL implies --high-level-code # -case $target in il) +case $target in asm|il) highlevel_code=true ;; esac diff --git a/scripts/init_grade_options.sh-subr b/scripts/init_grade_options.sh-subr index 4d70c3931..d731b5d12 100644 --- a/scripts/init_grade_options.sh-subr +++ b/scripts/init_grade_options.sh-subr @@ -1,5 +1,5 @@ #---------------------------------------------------------------------------# -# Copyright (C) 1997-2000 The University of Melbourne. +# Copyright (C) 1997-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. #---------------------------------------------------------------------------# @@ -23,7 +23,7 @@ grade_usage="\ Grade options: -s , --grade - --target {il, c} + --target {il, c, asm} --il --asm-labels --gcc-non-local-gotos diff --git a/scripts/mmake.in b/scripts/mmake.in index 099d92f36..b82e21da5 100644 --- a/scripts/mmake.in +++ b/scripts/mmake.in @@ -1,7 +1,7 @@ #! /bin/sh # @configure_input@ #---------------------------------------------------------------------------# -# Copyright (C) 1995-1999 The University of Melbourne. +# Copyright (C) 1995-1999, 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. #---------------------------------------------------------------------------# @@ -24,6 +24,11 @@ Options: rather than in the current directory. (If the current directory already contains a \`Mercury' subdirectory, then this option is the default.) + --target asm: + Compile directly to assembler, rather than going via C. + --target c: + Compile via C, rather than going directly to assembler. + This is the default. -s, --save-makefile: Save the generated makefile to \`Mmake.makefile'. This is useful for tracking down syntax errors in @@ -79,6 +84,7 @@ else use_subdirs=${MMAKE_USE_SUBDIRS=no} fi warn_undefined_vars=true +target_asm=${MMAKE_TARGET_ASM=default} while [ $# -gt 0 ]; do case "$1" in @@ -94,6 +100,20 @@ while [ $# -gt 0 ]; do use_subdirs=no shift ;; + --target) + case "$2" in + asm) target_asm=yes ;; + c|il) target_asm=no ;; + *) echo "$0: invalid argument to" \ + "\`--target' option" 1>&2 + exit 1 ;; + esac + shift; shift + ;; + --no-use-subdirs) + use_subdirs=no + shift + ;; -s|--save-makefile) save_makefile=true MMAKE="$MMAKE $1" @@ -210,6 +230,12 @@ else esac fi +case $target_asm in + yes) set_target_asm="TARGET_ASM=yes" ;; + no) set_target_asm="TARGET_ASM=no" ;; + default) set_target_asm="" ;; +esac + MMAKE_MAKE_CMD="${MMAKE_MAKE} -f $tmp -r" # Enable checking for undefined variables -- but not when making the @@ -247,7 +273,7 @@ if $verbose; then echo MERCURY_DEFAULT_GRADE=$MERCURY_DEFAULT_GRADE echo export MERCURY_DEFAULT_GRADE echo cat ${MMAKE_VARS} $dvs $ds $mmake $deps ${MMAKE_RULES} ">>" $tmp - echo ${MMAKE_MAKE} ${MMAKE_MAKE_OPTS} -f $tmp -r "$@" + echo ${MMAKE_MAKE} ${MMAKE_MAKE_OPTS} -f $tmp -r ${set_target_asm} "$@" fi export MMAKE export MMAKE_MAKE_CMD @@ -258,6 +284,6 @@ cat ${MMAKE_VARS} $dvs $ds $mmake $deps ${MMAKE_RULES} > $tmp case $# in # Note that we can't use `exec' here, because if we did that, # that `trap' code which removes $tmp would never get executed. - 0) ${MMAKE_MAKE} ${MMAKE_MAKE_OPTS} -f $tmp -r ;; - *) ${MMAKE_MAKE} ${MMAKE_MAKE_OPTS} -f $tmp -r "$@" ;; + 0) ${MMAKE_MAKE} ${MMAKE_MAKE_OPTS} -f $tmp -r ${set_target_asm} ;; + *) ${MMAKE_MAKE} ${MMAKE_MAKE_OPTS} -f $tmp -r ${set_target_asm} "$@" ;; esac diff --git a/scripts/parse_grade_options.sh-subr b/scripts/parse_grade_options.sh-subr index 6a3ae79e8..0e8839178 100644 --- a/scripts/parse_grade_options.sh-subr +++ b/scripts/parse_grade_options.sh-subr @@ -1,5 +1,5 @@ #---------------------------------------------------------------------------# -# Copyright (C) 1997-2000 The University of Melbourne. +# Copyright (C) 1997-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. #---------------------------------------------------------------------------# @@ -22,6 +22,8 @@ --target) shift case "$1" in + asm) + target=asm ;; c|C) target=c ;; il|IL) @@ -33,7 +35,7 @@ esac ;; - --il|--IL) + --il|--IL|--il-only|--IL-only) target=il ;; --high-level-code|-H) @@ -207,7 +209,6 @@ highlevel_data=false ;; hl) - target=c asm_labels=false non_local_gotos=false global_regs=false @@ -216,7 +217,6 @@ highlevel_data=true ;; hlc) - target=c asm_labels=false non_local_gotos=false global_regs=false @@ -225,7 +225,6 @@ highlevel_data=false ;; hl_nest) - target=c asm_labels=false non_local_gotos=false global_regs=false @@ -234,7 +233,6 @@ highlevel_data=true ;; hlc_nest) - target=c asm_labels=false non_local_gotos=false global_regs=false