public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
* 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).