This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: Function Inlining for FORTRAN
On Wednesday 20 July 2005 17:22, Paul Brook wrote:
> To implement (b) this needs to be changed to:
>
> - Do everything up until gfc_generate{,_module}_code as normal.
> - Save the results somewhere and repeat for each PU.
> - Identify calls for procedures for which we have definitions, and link
> them together somehow. It 's probably worth maintaining some sort of global
> symbol table and building these associations incrementally during
> resolution.
This is what I was working on, but I never finished it. I encountered
some memory corruption issues (procedure names disappearing underneath
me) that I never found time for to investigate.
I've appended the last incarnation of my hack that I could find in my
local mail archive. This was supposed to help implement the first two
points of (b). Actually linking things together is something I never
got to do.
Gr.
Steven
Index: f95-lang.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fortran/f95-lang.c,v
retrieving revision 1.26
diff -u -3 -p -r1.26 f95-lang.c
--- f95-lang.c 25 Nov 2004 11:13:35 -0000 1.26
+++ f95-lang.c 11 Dec 2004 20:34:40 -0000
@@ -45,6 +45,7 @@ Software Foundation, 59 Temple Place - S
#include "cgraph.h"
#include "gfortran.h"
+#include "gfc-toplev.h"
#include "trans.h"
#include "trans-types.h"
#include "trans-const.h"
@@ -262,17 +263,36 @@ gfc_be_parse_file (int set_yydebug ATTRI
int errors;
int warnings;
- gfc_create_decls ();
- gfc_parse_file ();
- gfc_generate_constructors ();
+ /* Set up the module and subprogram queues for the parser. */
+ gfc_initialize_module_and_subprogram_queues ();
- cgraph_finalize_compilation_unit ();
- cgraph_optimize ();
+ /* Parse the whole input file, queueing up things as we see them. */
+ gfc_parse_file ();
/* Tell the frontent about any errors. */
gfc_get_errors (&warnings, &errors);
errorcount += errors;
warningcount += warnings;
+
+ /* If there were no errors and we not asked to skip code generation,
+ generate code for all queued modules and subprograms. */
+ if (errors == 0 && ! gfc_option.flag_no_backend)
+ {
+ gfc_create_decls ();
+ gfc_generate_code ();
+ gfc_generate_constructors ();
+
+ /* We've now generated code for everything, so we can free up
+ all the parsing data structures and queues. */
+ gfc_finalize_module_and_subprogram_queues ();
+
+ /* Hand over control to the middle-end. */
+ cgraph_finalize_compilation_unit ();
+ cgraph_optimize ();
+ }
+ else
+ /* Just free the queues. */
+ gfc_finalize_module_and_subprogram_queues ();
}
/* Initialize everything. */
Index: gfc-toplev.h
===================================================================
RCS file: gfc-toplev.h
diff -N gfc-toplev.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gfc-toplev.h 11 Dec 2004 20:34:40 -0000
@@ -0,0 +1,106 @@
+/* Header for toplevel translation functions.
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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.
+
+GCC 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 GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef GFC_TOPLEV_H
+#define GFC_TOPLEV_H
+
+#include "vec.h"
+#include "gfortran.h"
+
+/* This header defines the interface between the parser and the
+ inter-subprogram name resolution and code generation phases.
+ The "driver" for the compilation process is in f95-lang.c, from where
+ we call the parser which queues up all modules and subprograms, then
+ the ip-resolve pass, and finally the code generator (trans*.[ch]).
+ The interface consists of two queues, one for modules and one for all
+ possible kinds of subprograms, including the main PROGRAM, for which
+ we produce a dummy function subprogram called __MAIN. */
+
+/* The queues are vectors of gfc_namespace pointers. Unfortunately we
+ need a new typedef for that. */
+typedef gfc_namespace * gfc_namespace_p;
+DEF_VEC_MALLOC_P(gfc_namespace_p);
+extern VEC(gfc_namespace_p) *gfc_module_queue;
+extern VEC(gfc_namespace_p) *gfc_subprogram_queue;
+
+
+/* Add module M to the queue of modules to generate code for.
+ Note that the .mod files are generated from the parser, because they
+ might be needed in other subprograms. */
+
+static inline void
+gfc_queue_module (gfc_namespace *m)
+{
+ VEC_safe_push (gfc_namespace_p, gfc_module_queue, m);
+}
+
+
+/* Add subprogram P to the queue of subprograms to generate code for. */
+
+static inline void
+gfc_queue_subprogram (gfc_namespace *p)
+{
+ VEC_safe_push (gfc_namespace_p, gfc_subprogram_queue, p);
+}
+
+
+/* Construct the queues. */
+
+static inline void
+gfc_initialize_module_and_subprogram_queues (void)
+{
+ /* Don't be cheap, use large queues. */
+ gfc_module_queue = VEC_alloc (gfc_namespace_p, 200);
+ gfc_subprogram_queue = VEC_alloc (gfc_namespace_p, 1000);
+}
+
+
+/* Return the queue length of Q. */
+
+static inline int
+gfc_queue_length (VEC(gfc_namespace_p) *q)
+{
+ return VEC_length (gfc_namespace_p, q);
+}
+
+/* Destruct the queues _and_ everything in them. */
+
+static inline void
+gfc_finalize_module_and_subprogram_queues (void)
+{
+ int i;
+
+ for (i = 0; i < gfc_queue_length (gfc_module_queue); i++)
+ {
+ gfc_namespace *ns = VEC_index (gfc_namespace_p, gfc_module_queue, i);
+ gfc_free_namespace (ns);
+ }
+
+ for (i = 0; i < gfc_queue_length (gfc_subprogram_queue); i++)
+ {
+ gfc_namespace *ns = VEC_index (gfc_namespace_p, gfc_subprogram_queue, i);
+ gfc_free_namespace (ns);
+ }
+
+ VEC_free (gfc_namespace_p, gfc_module_queue);
+ VEC_free (gfc_namespace_p, gfc_subprogram_queue);
+}
+
+#endif /* GFC_TOPLEV_H */
Index: gfortran.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fortran/gfortran.h,v
retrieving revision 1.44
diff -u -3 -p -r1.44 gfortran.h
--- gfortran.h 2 Dec 2004 04:10:24 -0000 1.44
+++ gfortran.h 11 Dec 2004 20:34:40 -0000
@@ -1480,6 +1480,7 @@ try gfc_new_file (const char *, gfc_sour
extern gfc_source_form gfc_current_form;
extern char *gfc_source_file;
extern locus gfc_current_locus;
+extern locus gfc_null_locus;
/* misc.c */
void *gfc_getmem (size_t) ATTRIBUTE_MALLOC;
@@ -1815,8 +1816,7 @@ symbol_attribute gfc_variable_attr (gfc_
symbol_attribute gfc_expr_attr (gfc_expr *);
/* trans.c */
-void gfc_generate_code (gfc_namespace *);
-void gfc_generate_module_code (gfc_namespace *);
+void gfc_generate_code (void);
/* bbt.c */
typedef int (*compare_fn) (void *, void *);
@@ -1827,6 +1827,6 @@ void gfc_delete_bbt (void *, void *, com
void gfc_show_namespace (gfc_namespace *);
/* parse.c */
-try gfc_parse_file (void);
+void gfc_parse_file (void);
#endif /* GCC_GFORTRAN_H */
Index: parse.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fortran/parse.c,v
retrieving revision 1.21
diff -u -3 -p -r1.21 parse.c
--- parse.c 8 Nov 2004 14:56:39 -0000 1.21
+++ parse.c 11 Dec 2004 20:34:41 -0000
@@ -28,6 +28,7 @@ Software Foundation, 59 Temple Place - S
#include "gfortran.h"
#include "match.h"
#include "parse.h"
+#include "gfc-toplev.h"
/* Current statement label. Zero means no statement label. Because
new_st can get wiped during statement matching, we have to keep it
@@ -2498,6 +2499,29 @@ add_global_procedure (int sub)
}
+/* Lots of things in the middle-end get upset if a subroutine doesn't
+ have a symbol, so we make one now. Hopefully we've set all the
+ required fields. */
+
+static void
+create_dummy_main_program_symbol (locus prog_locus)
+{
+ symbol_attribute attr;
+ gfc_symbol *main_program = NULL;
+
+ gfc_get_symbol ("MAIN__", gfc_current_ns, &main_program);
+ gfc_clear_attr (&attr);
+ attr.flavor = FL_PROCEDURE;
+ attr.proc = PROC_UNKNOWN;
+ attr.subroutine = 1;
+ attr.access = ACCESS_PUBLIC;
+ main_program->attr = attr;
+ main_program->declared_at = prog_locus;
+ gfc_current_ns->proc_name = main_program;
+ gfc_commit_symbols ();
+}
+
+
/* Add a program to the global symbol table. */
static void
@@ -2521,7 +2545,7 @@ add_global_program (void)
/* Top level parser. */
-try
+void
gfc_parse_file (void)
{
int seen_program, errors_before, errors;
@@ -2542,13 +2566,21 @@ gfc_parse_file (void)
gfc_statement_label = NULL;
if (setjmp (eof_buf))
- return FAILURE; /* Come here on unexpected EOF */
+ return; /* Come here on unexpected EOF */
seen_program = 0;
loop:
gfc_init_2 ();
st = next_statement ();
+
+ /* For entities that need a locus, but we have no good place to store
+ it (e.g. the location of BLOCK DATA tokens). The proper solution is
+ to give everything a meaningful locus. In the mean time, we just
+ give such objects the locus of the first statement we see. */
+ if (gfc_null_locus.lb == NULL)
+ gfc_null_locus = gfc_current_locus;
+
switch (st)
{
case ST_NONE:
@@ -2565,6 +2597,7 @@ loop:
accept_statement (st);
add_global_program ();
parse_progunit (ST_NONE);
+ create_dummy_main_program_symbol (prog_locus);
break;
case ST_SUBROUTINE:
@@ -2601,9 +2634,9 @@ loop:
goto duplicate_main;
seen_program = 1;
prog_locus = gfc_current_locus;
-
push_state (&s, COMP_PROGRAM, gfc_new_block);
parse_progunit (st);
+ create_dummy_main_program_symbol (prog_locus);
break;
}
@@ -2619,22 +2652,15 @@ loop:
if (s.state == COMP_MODULE)
{
gfc_dump_module (s.sym->name, errors_before == errors);
- if (errors == 0 && ! gfc_option.flag_no_backend)
- gfc_generate_module_code (gfc_current_ns);
+ gfc_queue_module (gfc_current_ns);
}
else
- {
- if (errors == 0 && ! gfc_option.flag_no_backend)
- gfc_generate_code (gfc_current_ns);
- }
+ gfc_queue_subprogram (gfc_current_ns);
pop_state ();
gfc_done_2 ();
goto loop;
-done:
- return SUCCESS;
-
duplicate_main:
/* If we see a duplicate main program, shut down. If the second
instance is an implied main program, ie data decls or executable
@@ -2642,5 +2668,7 @@ duplicate_main:
gfc_error ("Two main PROGRAMs at %L and %C", &prog_locus);
reject_statement ();
gfc_done_2 ();
- return SUCCESS;
+
+done:
+ return;
}
Index: scanner.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fortran/scanner.c,v
retrieving revision 1.13
diff -u -3 -p -r1.13 scanner.c
--- scanner.c 8 Nov 2004 14:56:40 -0000 1.13
+++ scanner.c 11 Dec 2004 20:34:41 -0000
@@ -70,6 +70,7 @@ static gfc_linebuf *line_head, *line_tai
locus gfc_current_locus;
char *gfc_source_file;
+locus gfc_null_locus = { NULL, NULL };
/* Main scanner initialization. */
Index: symbol.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fortran/symbol.c,v
retrieving revision 1.16
diff -u -3 -p -r1.16 symbol.c
--- symbol.c 8 Sep 2004 14:33:02 -0000 1.16
+++ symbol.c 11 Dec 2004 20:34:42 -0000
@@ -2253,8 +2253,6 @@ gfc_symbol_init_2 (void)
void
gfc_symbol_done_2 (void)
{
-
- gfc_free_namespace (gfc_current_ns);
gfc_current_ns = NULL;
}
Index: trans-common.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fortran/trans-common.c,v
retrieving revision 1.18
diff -u -3 -p -r1.18 trans-common.c
--- trans-common.c 16 Sep 2004 16:00:43 -0000 1.18
+++ trans-common.c 11 Dec 2004 20:34:42 -0000
@@ -271,7 +271,7 @@ build_equiv_decl (tree union_type, bool
/* The source location has been lost, and doesn't really matter.
We need to set it to something though. */
- gfc_set_decl_location (decl, &gfc_current_locus);
+ gfc_set_decl_location (decl, &gfc_null_locus);
gfc_add_decl_to_function (decl);
Index: trans-decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fortran/trans-decl.c,v
retrieving revision 1.49
diff -u -3 -p -r1.49 trans-decl.c
--- trans-decl.c 25 Nov 2004 11:13:35 -0000 1.49
+++ trans-decl.c 11 Dec 2004 20:34:43 -0000
@@ -1298,17 +1298,12 @@ trans_function_start (gfc_symbol * sym)
rest_of_decl_compilation (fndecl, 1, 0);
}
+ /* Initialize the RTL code for the function. */
+ allocate_struct_function (fndecl);
+
/* Create RTL for function definition. */
make_decl_rtl (fndecl);
- init_function_start (fndecl);
-
- /* Even though we're inside a function body, we still don't want to
- call expand_expr to calculate the size of a variable-sized array.
- We haven't necessarily assigned RTL to all variables yet, so it's
- not safe to try to expand expressions involving them. */
- cfun->x_dont_save_pending_sizes_p = 1;
-
/* function.c requires a push at the start of the function. */
pushlevel (0);
}
@@ -2374,7 +2369,7 @@ gfc_generate_block_data (gfc_namespace *
if (ns->proc_name)
gfc_set_backend_locus (&ns->proc_name->declared_at);
else
- gfc_set_backend_locus (&gfc_current_locus);
+ gfc_set_backend_locus (&gfc_null_locus);
/* Process the DATA statements. */
gfc_trans_common (ns);
Index: trans.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fortran/trans.c,v
retrieving revision 1.19
diff -u -3 -p -r1.19 trans.c
--- trans.c 30 Oct 2004 14:35:23 -0000 1.19
+++ trans.c 11 Dec 2004 20:34:43 -0000
@@ -31,6 +31,7 @@ Software Foundation, 59 Temple Place - S
#include "real.h"
#include <gmp.h>
#include "gfortran.h"
+#include "gfc-toplev.h"
#include "trans.h"
#include "trans-stmt.h"
#include "trans-array.h"
@@ -45,8 +46,14 @@ Software Foundation, 59 Temple Place - S
gfc_get_* get a backend tree representation of a decl or type */
+
+/* The file we are currently compiling. */
static gfc_file *gfc_current_backend_file;
+/* Modules and subprograms (and also the main program) that we have
+ queued up for code generation. */
+VEC(gfc_namespace_p) *gfc_module_queue, *gfc_subprogram_queue;
+
/* Advance along TREE_CHAIN n times. */
@@ -185,35 +192,6 @@ gfc_init_block (stmtblock_t * block)
}
-/* Sometimes we create a scope but it turns out that we don't actually
- need it. This function merges the scope of BLOCK with its parent.
- Only variable decls will be merged, you still need to add the code. */
-
-void
-gfc_merge_block_scope (stmtblock_t * block)
-{
- tree decl;
- tree next;
-
- gcc_assert (block->has_scope);
- block->has_scope = 0;
-
- /* Remember the decls in this scope. */
- decl = getdecls ();
- poplevel (0, 0, 0);
-
- /* Add them to the parent scope. */
- while (decl != NULL_TREE)
- {
- next = TREE_CHAIN (decl);
- TREE_CHAIN (decl) = NULL_TREE;
-
- pushdecl (decl);
- decl = next;
- }
-}
-
-
/* Finish a scope containing a block of statements. */
tree
@@ -645,37 +623,15 @@ gfc_trans_code (gfc_code * code)
/* This function is called after a complete program unit has been parsed
and resolved. */
-void
-gfc_generate_code (gfc_namespace * ns)
+static void
+gfc_generate_subprogram_code (gfc_namespace * ns)
{
- gfc_symbol *main_program = NULL;
- symbol_attribute attr;
-
if (ns->is_block_data)
{
gfc_generate_block_data (ns);
return;
}
- /* Main program subroutine. */
- if (!ns->proc_name)
- {
- /* Lots of things get upset if a subroutine doesn't have a symbol, so we
- make one now. Hopefully we've set all the required fields. */
- gfc_get_symbol ("MAIN__", ns, &main_program);
- gfc_clear_attr (&attr);
- attr.flavor = FL_PROCEDURE;
- attr.proc = PROC_UNKNOWN;
- attr.subroutine = 1;
- attr.access = ACCESS_PUBLIC;
- main_program->attr = attr;
- /* Set the location to the first line of code. */
- if (ns->code)
- main_program->declared_at = ns->code->loc;
- ns->proc_name = main_program;
- gfc_commit_symbols ();
- }
-
gfc_generate_function_code (ns);
}
@@ -683,7 +639,7 @@ gfc_generate_code (gfc_namespace * ns)
/* This function is called after a complete module has been parsed
and resolved. */
-void
+static void
gfc_generate_module_code (gfc_namespace * ns)
{
gfc_namespace *n;
@@ -709,3 +665,24 @@ gfc_generate_module_code (gfc_namespace
}
}
+
+/* Generate code for all queued up entities. */
+
+void
+gfc_generate_code (void)
+{
+ int i;
+
+ for (i = 0; i < gfc_queue_length (gfc_module_queue); i++)
+ {
+ gfc_namespace *ns = VEC_index (gfc_namespace_p, gfc_module_queue, i);
+ gfc_generate_module_code (ns);
+ }
+
+ for (i = 0; i < gfc_queue_length (gfc_subprogram_queue); i++)
+ {
+ gfc_namespace *ns = VEC_index (gfc_namespace_p, gfc_subprogram_queue, i);
+ gfc_generate_subprogram_code (ns);
+ }
+}
+
Index: trans.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fortran/trans.h,v
retrieving revision 1.21
diff -u -3 -p -r1.21 trans.h
--- trans.h 16 Nov 2004 02:02:37 -0000 1.21
+++ trans.h 11 Dec 2004 20:34:43 -0000
@@ -336,8 +336,6 @@ void gfc_start_block (stmtblock_t *);
/* Finish a statement block. Also closes the scope if the block was created
with gfc_start_block. */
tree gfc_finish_block (stmtblock_t *);
-/* Merge the scope of a block with its parent. */
-void gfc_merge_block_scope (stmtblock_t * block);
/* Return the backend label decl. */
tree gfc_get_label_decl (gfc_st_label *);