[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