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)