* Function Inlining for FORTRAN
@ 2005-07-20 14:26 Canqun Yang
2005-07-20 15:24 ` Paul Brook
0 siblings, 1 reply; 12+ messages in thread
From: Canqun Yang @ 2005-07-20 14:26 UTC (permalink / raw)
To: jh, gcc, fortran
Hi, all
Function inlining for FORTRAN programs always fails. If no one engages in it, I will give a try.
Would you please give me some clues?
Canqun Yang
Creative Compiler Research Group.
National University of Defense Technology, China.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Function Inlining for FORTRAN
2005-07-20 14:26 Function Inlining for FORTRAN Canqun Yang
@ 2005-07-20 15:24 ` Paul Brook
2005-07-20 15:58 ` Steven Bosscher
2005-07-22 2:27 ` Function Inlining for FORTRAN Canqun Yang
0 siblings, 2 replies; 12+ messages in thread
From: Paul Brook @ 2005-07-20 15:24 UTC (permalink / raw)
To: fortran, Canqun Yang; +Cc: jh, gcc, Steven Bosscher
On Wednesday 20 July 2005 15:35, Canqun Yang wrote:
> Hi, all
>
> Function inlining for FORTRAN programs always fails.
Not entirely true. Inlining of contained procedures works fine (or it did last
time I checked). This should include inlining of siblings within a module.
> If no one engages in it, I will give a try. Would you please give me
> some clues?
The problem is that each top level program unit (PU)[1] is compiled
separately. Each PU has it's own "external" decls for all function calls,
even if the function happens to be in the same function. Thus each PU is an
isolated self-contained tree structure, and the callgraph doesn't know the
definition and declaration are actually the same thing.
Basically what you need to do is parse the whole file, then start generating
code.
Unfortunately this isn't simple (or it would have been fixed already!).
Unlike C Fortran doesn't have file-level scope. It makes absolutely no
difference whether two procedures are in the same file, or in different
files. You get all the problems that multifile IPA in C experiences within a
single Fortran file.
The biggest problem is type consistency and aliasing. Consider the following
example:
subroutine a(p)
type t
integer :: t1
end type
type(t) :: p
p%t1 = 42
end subroutine
subroutine b
type u
integer :: u1
end type
type (u) :: q
call a(q)
print * q%u1
end subroutine
Here you have two different derived types which are actually the same derived
types. To make unit-at-a-time work (ie. inlining) you need to either
(a) Replace all occurrences of one type with the other
(b) Tell the compiler that the two types alias, and fixup the types with
explicit casts at any interfaces.
Ideally we'd do (a), but I don't think doing that is practical, and might not
even be possible. I think it would require fairly major hacking of the whole
frontend.
Which leaves (b).
Currently the high-level flow is something like:
- Parse and resolve the PU. This is basically everything before
gfc_generate_code.
- Call gfc_generate_code (or gfc_generate_module_code) to generate code for
that PU.
- Throw away the PU.
- Repeat for each function.
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.
- Generate global DECLs for all PU. Something similar to
gfc_create_function_decl. Probably also generate global DECLs for external
routines.
- Generate common blocks. This may simplify the existing code because we have
all definitions before we start generating DECLs.
- Generate code for each PU. This is more-or-less the same as the current code
except function calls may need explicit typecasts to accommodate type
mismatches described above.
- Tweak aliasing information so this type mismatching doesn't generate bad
code.
I believe Steven Bosscher had a go at implementing this, but never got it to
work properly.
Paul
[1] A top level Program Unit is a file-level subroutine, function, program or
module. If a PU has contained procedures these procedures and the parent
procedure constitute a single PU.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Function Inlining for FORTRAN
2005-07-20 15:24 ` Paul Brook
@ 2005-07-20 15:58 ` Steven Bosscher
2005-07-22 14:11 ` Michael Matz
2005-07-22 2:27 ` Function Inlining for FORTRAN Canqun Yang
1 sibling, 1 reply; 12+ messages in thread
From: Steven Bosscher @ 2005-07-20 15:58 UTC (permalink / raw)
To: Paul Brook; +Cc: fortran, Canqun Yang, jh, gcc
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 ();
}
\f
/* 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 *);
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Function Inlining for FORTRAN
2005-07-20 15:24 ` Paul Brook
2005-07-20 15:58 ` Steven Bosscher
@ 2005-07-22 2:27 ` Canqun Yang
2005-07-22 2:37 ` Paul Brook
1 sibling, 1 reply; 12+ messages in thread
From: Canqun Yang @ 2005-07-22 2:27 UTC (permalink / raw)
To: Paul Brook; +Cc: Steven Bosscher, fortran, gcc
Paul Brook <paul@codesourcery.com>:
> On Wednesday 20 July 2005 15:35, Canqun Yang wrote:
> > Hi, all
> >
> > Function inlining for FORTRAN programs always fails.
>
> Not entirely true. Inlining of contained procedures works fine (or it did la
> st
> time I checked). This should include inlining of siblings within a module.
>
> > If no one engages in it, I will give a try. Would you please give me
> > some clues?
>
> The problem is that each top level program unit (PU)[1] is compiled
> separately. Each PU has it's own "external" decls for all function calls,
> even if the function happens to be in the same function. Thus each PU is an
>
> isolated self-contained tree structure, and the callgraph doesn't know the
> definition and declaration are actually the same thing.
>
> Basically what you need to do is parse the whole file, then start generating
>
> code.
>
> Unfortunately this isn't simple (or it would have been fixed already!).
> Unlike C Fortran doesn't have file-level scope. It makes absolutely no
> difference whether two procedures are in the same file, or in different
> files. You get all the problems that multifile IPA in C experiences within
> a
> single Fortran file.
>
> The biggest problem is type consistency and aliasing. Consider the following
>
I have several FORTRAN 77 programs. After inlining the small functions in them by hand, they
made a great performance improvements. So I need a trial implementation of function inlining to
verify the effectiveness of it.
Now, my question is: If we just take the FORTRAN 77 syntax into account (no derived types, no
complex aliasing), may it be simpler to implement function inlining for FORTRAN 77.
>
> Paul
>
Canqun Yang
Creative Compiler Research Group.
National University of Defense Technology, China.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Function Inlining for FORTRAN
2005-07-22 2:27 ` Function Inlining for FORTRAN Canqun Yang
@ 2005-07-22 2:37 ` Paul Brook
0 siblings, 0 replies; 12+ messages in thread
From: Paul Brook @ 2005-07-22 2:37 UTC (permalink / raw)
To: fortran, Canqun Yang; +Cc: Steven Bosscher, gcc
> > The biggest problem is type consistency and aliasing. Consider the
> > following
>
> I have several FORTRAN 77 programs. After inlining the small functions in
> them by hand, they made a great performance improvements. So I need a trial
> implementation of function inlining to verify the effectiveness of it.
>
> Now, my question is: If we just take the FORTRAN 77 syntax into account (no
> derived types, no complex aliasing), may it be simpler to implement
> function inlining for FORTRAN 77.
Maybe, but gfortran is a fortran 95 compiler so this is not an acceptable
solution.
Paul
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Function Inlining for FORTRAN
2005-07-20 15:58 ` Steven Bosscher
@ 2005-07-22 14:11 ` Michael Matz
2005-08-06 1:05 ` IPA branch Canqun Yang
0 siblings, 1 reply; 12+ messages in thread
From: Michael Matz @ 2005-07-22 14:11 UTC (permalink / raw)
To: Steven Bosscher; +Cc: Paul Brook, fortran, Canqun Yang, jh, gcc
Hi,
On Wed, 20 Jul 2005, Steven Bosscher wrote:
> 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.
And I had once written a hack to make whole-program mode work with
gfortran (which in the end worked well enough for the fortran programs in
SPEC2k). Its purpose is the merging of decls, so that a real call graph
can be generated. As I know not much of Fortran the actual inlining
enabled by this might generate wrong code in cases like Paul mentioned.
If so, then at least spec2k does not contain such ;-) The patch is below,
perhaps it's of use for anyone. It's against an old version of the
tree-profiling branch.
Ciao,
Michael.
--
diff -urp -x CVS -x '*.orig' gcc.jh/gcc/fortran/f95-lang.c gcc/gcc/fortran/f95-lang.c
--- gcc.jh/gcc/fortran/f95-lang.c 2005-03-12 21:30:09.000000000 +0100
+++ gcc/gcc/fortran/f95-lang.c 2005-03-14 11:50:08.000000000 +0100
@@ -534,6 +534,22 @@ pushdecl_top_level (tree x)
return t;
}
+tree find_fndecl (tree name);
+tree
+find_fndecl (tree name)
+{
+ struct binding_level *b = current_binding_level;
+ while (b)
+ {
+ tree t;
+ for (t = b->names; t; t = TREE_CHAIN (t))
+ if (TREE_CODE (t) == FUNCTION_DECL
+ && DECL_NAME (t) == name)
+ return t;
+ b = b->level_chain;
+ }
+ return NULL_TREE;
+}
/* Clear the binding stack. */
static void
diff -urp -x CVS -x '*.orig' gcc.jh/gcc/fortran/trans.c gcc/gcc/fortran/trans.c
--- gcc.jh/gcc/fortran/trans.c 2005-03-12 21:30:09.000000000 +0100
+++ gcc/gcc/fortran/trans.c 2005-03-14 11:50:10.000000000 +0100
@@ -658,6 +658,8 @@ gfc_generate_code (gfc_namespace * ns)
/* Main program subroutine. */
if (!ns->proc_name)
{
+ /* Let backend know that this is the main entry point to the program. */
+ main_identifier_node = get_identifier ("MAIN__");
/* 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);
diff -urp -x CVS -x '*.orig' gcc.jh/gcc/fortran/trans-decl.c gcc/gcc/fortran/trans-decl.c
--- gcc.jh/gcc/fortran/trans-decl.c 2005-03-12 21:30:09.000000000 +0100
+++ gcc/gcc/fortran/trans-decl.c 2005-03-14 11:50:09.000000000 +0100
@@ -45,6 +45,7 @@ Software Foundation, 59 Temple Place - S
#define MAX_LABEL_VALUE 99999
+extern tree find_fndecl (tree);
/* Holds the result of the function if no result variable specified. */
@@ -917,54 +918,58 @@ gfc_get_extern_function_decl (gfc_symbol
mangled_name = gfc_sym_mangled_function_id (sym);
}
- type = gfc_get_function_type (sym);
- fndecl = build_decl (FUNCTION_DECL, name, type);
+ fndecl = find_fndecl (name);
+ if (!fndecl || TREE_CODE (fndecl) != FUNCTION_DECL)
+ {
+ type = gfc_get_function_type (sym);
+ fndecl = build_decl (FUNCTION_DECL, name, type);
- SET_DECL_ASSEMBLER_NAME (fndecl, mangled_name);
- /* If the return type is a pointer, avoid alias issues by setting
- DECL_IS_MALLOC to nonzero. This means that the function should be
- treated as if it were a malloc, meaning it returns a pointer that
- is not an alias. */
- if (POINTER_TYPE_P (type))
- DECL_IS_MALLOC (fndecl) = 1;
+ SET_DECL_ASSEMBLER_NAME (fndecl, mangled_name);
+ /* If the return type is a pointer, avoid alias issues by setting
+ DECL_IS_MALLOC to nonzero. This means that the function should be
+ treated as if it were a malloc, meaning it returns a pointer that
+ is not an alias. */
+ if (POINTER_TYPE_P (type))
+ DECL_IS_MALLOC (fndecl) = 1;
- /* Set the context of this decl. */
- if (0 && sym->ns && sym->ns->proc_name)
- {
- /* TODO: Add external decls to the appropriate scope. */
- DECL_CONTEXT (fndecl) = sym->ns->proc_name->backend_decl;
- }
- else
- {
- /* Global declaration, e.g. intrinsic subroutine. */
- DECL_CONTEXT (fndecl) = NULL_TREE;
- }
+ /* Set the context of this decl. */
+ if (0 && sym->ns && sym->ns->proc_name)
+ {
+ /* TODO: Add external decls to the appropriate scope. */
+ DECL_CONTEXT (fndecl) = sym->ns->proc_name->backend_decl;
+ }
+ else
+ {
+ /* Global declaration, e.g. intrinsic subroutine. */
+ DECL_CONTEXT (fndecl) = NULL_TREE;
+ }
- DECL_EXTERNAL (fndecl) = 1;
+ DECL_EXTERNAL (fndecl) = 1;
- /* This specifies if a function is globally addressable, i.e. it is
- the opposite of declaring static in C. */
- TREE_PUBLIC (fndecl) = 1;
+ /* This specifies if a function is globally addressable, i.e. it is
+ the opposite of declaring static in C. */
+ TREE_PUBLIC (fndecl) = 1;
- /* Set attributes for PURE functions. A call to PURE function in the
- Fortran 95 sense is both pure and without side effects in the C
- sense. */
- if (sym->attr.pure || sym->attr.elemental)
- {
- if (sym->attr.function)
- DECL_IS_PURE (fndecl) = 1;
- /* TODO: check if pure SUBROUTINEs don't have INTENT(OUT)
- parameters and don't use alternate returns (is this
- allowed?). In that case, calls to them are meaningless, and
- can be optimized away. See also in build_function_decl(). */
- TREE_SIDE_EFFECTS (fndecl) = 0;
+ /* Set attributes for PURE functions. A call to PURE function in the
+ Fortran 95 sense is both pure and without side effects in the C
+ sense. */
+ if (sym->attr.pure || sym->attr.elemental)
+ {
+ if (sym->attr.function)
+ DECL_IS_PURE (fndecl) = 1;
+ /* TODO: check if pure SUBROUTINEs don't have INTENT(OUT)
+ parameters and don't use alternate returns (is this
+ allowed?). In that case, calls to them are meaningless, and
+ can be optimized away. See also in build_function_decl(). */
+ TREE_SIDE_EFFECTS (fndecl) = 0;
+ }
+
+ if (DECL_CONTEXT (fndecl) == NULL_TREE)
+ pushdecl_top_level (fndecl);
}
sym->backend_decl = fndecl;
- if (DECL_CONTEXT (fndecl) == NULL_TREE)
- pushdecl_top_level (fndecl);
-
return fndecl;
}
@@ -979,6 +984,7 @@ build_function_decl (gfc_symbol * sym)
tree fndecl, type;
symbol_attribute attr;
tree result_decl;
+ tree name;
gfc_formal_arglist *f;
gcc_assert (!sym->backend_decl);
@@ -992,8 +998,24 @@ build_function_decl (gfc_symbol * sym)
gcc_assert (current_function_decl == NULL_TREE
|| DECL_CONTEXT (current_function_decl) == NULL_TREE);
- type = gfc_get_function_type (sym);
- fndecl = build_decl (FUNCTION_DECL, gfc_sym_identifier (sym), type);
+ name = gfc_sym_identifier (sym);
+ fndecl = find_fndecl (name);
+ if (fndecl)
+ {
+ /* type = TREE_TYPE (fndecl); */
+ /* XXX hack to insert the correct type, which is known only
+ with the declaration, not with calls. */
+ type = gfc_get_function_type (sym);
+ TREE_TYPE (fndecl) = type;
+ }
+ else
+ {
+ type = gfc_get_function_type (sym);
+ fndecl = build_decl (FUNCTION_DECL, gfc_sym_identifier (sym), type);
+ /* Layout the function declaration and put it in the binding level
+ of the current function. */
+ pushdecl (fndecl);
+ }
/* Perform name mangling if this is a top level or module procedure. */
if (current_function_decl == NULL_TREE)
@@ -1079,10 +1101,6 @@ build_function_decl (gfc_symbol * sym)
TREE_SIDE_EFFECTS (fndecl) = 0;
}
- /* Layout the function declaration and put it in the binding level
- of the current function. */
- pushdecl (fndecl);
-
sym->backend_decl = fndecl;
}
diff -urp -x CVS -x '*.orig' gcc.jh/gcc/var-tracking.c gcc/gcc/var-tracking.c
--- gcc.jh/gcc/var-tracking.c 2005-03-12 21:30:29.000000000 +0100
+++ gcc/gcc/var-tracking.c 2005-03-14 10:58:52.000000000 +0100
@@ -2514,8 +2514,8 @@ vt_add_function_parameters (void)
{
rtx decl_rtl = DECL_RTL_IF_SET (parm);
rtx incoming = DECL_INCOMING_RTL (parm);
- tree decl;
- HOST_WIDE_INT offset;
+ tree decl = 0;
+ HOST_WIDE_INT offset = 0;
dataflow_set *out;
if (TREE_CODE (parm) != PARM_DECL)
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: IPA branch
2005-07-22 14:11 ` Michael Matz
@ 2005-08-06 1:05 ` Canqun Yang
2005-08-06 6:15 ` Andrew Pinski
0 siblings, 1 reply; 12+ messages in thread
From: Canqun Yang @ 2005-08-06 1:05 UTC (permalink / raw)
To: Jan Hubicka; +Cc: Michael Matz, Steven Bosscher, Paul Brook, fortran, gcc
Hi,
Patch from Michael Matz (http://gcc.gnu.org/ml/fortran/2005-07/msg00331.html) may partly fixes
the multiple decls problems.
I've tested and tuned this patch. It works, small functions can be inlined after DECL_INLINE
flags (build_function_decl in trans-decl.c) have been set for them. The only regression is
FORTRAN 95 testcase function_modulo_1.f90, it produces a wong result.
Canqun Yang
Creative Compiler Research Group.
National University of Defense Technology, China.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: IPA branch
2005-08-06 1:05 ` IPA branch Canqun Yang
@ 2005-08-06 6:15 ` Andrew Pinski
2005-08-06 8:54 ` Steven Bosscher
0 siblings, 1 reply; 12+ messages in thread
From: Andrew Pinski @ 2005-08-06 6:15 UTC (permalink / raw)
To: Canqun Yang
Cc: fortran, Jan Hubicka, Paul Brook, gcc, Steven Bosscher, Michael Matz
On Aug 5, 2005, at 9:24 PM, Canqun Yang wrote:
> Hi,
>
> Patch from Michael Matz
> (http://gcc.gnu.org/ml/fortran/2005-07/msg00331.html) may partly fixes
> the multiple decls problems.
That will only help with the fortran problem, the C++ front-end have
the same
issue. The C front-end have still some issues but most of the problems
with
multiple decls in the C front-end was fixed in 4.0.0.
-- pinski
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: IPA branch
2005-08-06 6:15 ` Andrew Pinski
@ 2005-08-06 8:54 ` Steven Bosscher
2005-08-06 19:20 ` Jan Hubicka
0 siblings, 1 reply; 12+ messages in thread
From: Steven Bosscher @ 2005-08-06 8:54 UTC (permalink / raw)
To: Andrew Pinski
Cc: Canqun Yang, fortran, Jan Hubicka, Paul Brook, gcc, Michael Matz
On Saturday 06 August 2005 08:14, Andrew Pinski wrote:
> On Aug 5, 2005, at 9:24 PM, Canqun Yang wrote:
> > Hi,
> >
> > Patch from Michael Matz
> > (http://gcc.gnu.org/ml/fortran/2005-07/msg00331.html) may partly fixes
> > the multiple decls problems.
>
> That will only help with the fortran problem,
That is the only problem we have to care about, isn't it? The C++
front-end folks can fix their own front end.
Gr.
Steven
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: IPA branch
2005-08-06 8:54 ` Steven Bosscher
@ 2005-08-06 19:20 ` Jan Hubicka
0 siblings, 0 replies; 12+ messages in thread
From: Jan Hubicka @ 2005-08-06 19:20 UTC (permalink / raw)
To: Steven Bosscher
Cc: Andrew Pinski, Canqun Yang, fortran, Jan Hubicka, Paul Brook,
gcc, Michael Matz
> On Saturday 06 August 2005 08:14, Andrew Pinski wrote:
> > On Aug 5, 2005, at 9:24 PM, Canqun Yang wrote:
> > > Hi,
> > >
> > > Patch from Michael Matz
> > > (http://gcc.gnu.org/ml/fortran/2005-07/msg00331.html) may partly fixes
> > > the multiple decls problems.
> >
> > That will only help with the fortran problem,
> That is the only problem we have to care about, isn't it? The C++
> front-end folks can fix their own front end.
There is also problem with the C frontend and K&R style declarations.
Either we can refuse functions K&R declared in one unit and properly
declared in other unit or we create duplicated decls... Both is quite
wrong :(
Honza
>
> Gr.
> Steven
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Function inlining for FORTRAN
2005-07-20 15:52 Function inlining " Joost VandeVondele
@ 2005-07-20 16:03 ` Paul Brook
0 siblings, 0 replies; 12+ messages in thread
From: Paul Brook @ 2005-07-20 16:03 UTC (permalink / raw)
To: Joost VandeVondele; +Cc: gcc, canqun
On Wednesday 20 July 2005 16:52, Joost VandeVondele wrote:
> Hi,
>
> I don't think Paul's example is completely correct, I've created PR22571
> with some more info.
Ah, this makes thing somewhat simpler. For some reason I though my example was
legal.
I think this makes it possible to implement my option (a). Ie. use the same
type for all derived types that are "the same". This basically means where we
create global function DECLs we also want to create global type declarations
for derived types, and the type munging of function arguments becomes a
no-op.
Some trickey may still be needed for modules, but that's a slightly different
issue.
Paul
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Function inlining for FORTRAN
@ 2005-07-20 15:52 Joost VandeVondele
2005-07-20 16:03 ` Paul Brook
0 siblings, 1 reply; 12+ messages in thread
From: Joost VandeVondele @ 2005-07-20 15:52 UTC (permalink / raw)
To: paul; +Cc: gcc, canqun
Hi,
I don't think Paul's example is completely correct, I've created PR22571
with some more info.
Cheers,
Joost
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2005-08-06 19:20 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-07-20 14:26 Function Inlining for FORTRAN Canqun Yang
2005-07-20 15:24 ` Paul Brook
2005-07-20 15:58 ` Steven Bosscher
2005-07-22 14:11 ` Michael Matz
2005-08-06 1:05 ` IPA branch Canqun Yang
2005-08-06 6:15 ` Andrew Pinski
2005-08-06 8:54 ` Steven Bosscher
2005-08-06 19:20 ` Jan Hubicka
2005-07-22 2:27 ` Function Inlining for FORTRAN Canqun Yang
2005-07-22 2:37 ` Paul Brook
2005-07-20 15:52 Function inlining " Joost VandeVondele
2005-07-20 16:03 ` Paul Brook
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).