rfc: multiple decls for functions

Daniel Franke franke.daniel@gmail.com
Fri Dec 19 20:33:00 GMT 2008


Hi all,

I spent some time with the multiple-decl-per function problem gfortran has. As 
trans-* is nothing for the lighthearted, I'd like to get some comments before 
proceeding.

First, what's the actual problem? Consider:

  SUBROUTINE F()
    CALL G()
  END SUBROUTINE
  SUBROUTINE G()
  END SUBROUTINE

When translating, the following backend_decls are created:
  building decl for subroutine: F          (build_function_decl)
  building decl for called subroutine: G   (gfc_get_extern_function_decl)
  building decl for subroutine: G          (build_function_decl)

Now, whatever the optimizer might figure out about (global) G, e.g. G not 
changing its arguments, it does not affect optimization of F as F has another, 
second, decl for G (see also [1]). The same holds if G is declared before F!

FX worked on this problem earlier this year. When he finally got stuck, he 
noted:
	"The best way to fix this is to use the other approach: 
	file-scope resolution" [2].

Thus, I'd propose the following: create a list/table of known functions where 
new decls are added to, using the mangled name as a key. Before adding a decl, 
check the list if the mangled name already exists, if so, use that decl 
instead of creating a new one. Above would then become:

  looking up decl for subroutine F: not found
  building decl for subroutine: F
  adding decl for subroutine F to list
  looking up decl for subroutine G: not found
  building decl for subroutine: G
  adding decl for subroutine G to list
  looking up decl for subroutine G: found

The list could be implemented as hashtable (provided by libiberty).

Noteworthy side-effect: if multiple source-files are compiled simultaniously, 
decls could be shared between the files if the list is not cleared in between. 
Question is: do we want this, or should the list be cleared for each 
compilation unit?

Generally, this seems to be straight forward. However, does this work for any 
combination of functions/subroutines, if external, if contained, if in 
modules, if ... any corner-cases that spring to mind? Maybe [3]?

Also, is there any other approach possible? PaulT pointed out on IRC that one 
might get a working solution if a backend_decl would be added to struct 
gsymbol. I haven't looked into this yet (because I haven't knowingly used 
gsymbol before), but maybe someone could comment on this as well?

Thanks :)

	Daniel


[1] http://gcc.gnu.org/bugzilla/show_bug.cgi?id=23169
[2] http://gcc.gnu.org/ml/fortran/2008-08/msg00173.html
[3]
Would this be legal?
  SUBROUTINE g()
  END SUBROUTINE
  SUBROUTINE f()
    CALL g()
  CONTAINS
    SUBROUTINE g()
    END SUBROUTINE
  END SUBROUTINE

It is accepted by gfortran and the contained g() is called; nm shows

000000da T f_
0000006d t g.1501
00000000 T g_

Where does '.1501' come from? Is it possible to distinguish between global g() 
and contained g() in the approach outlined above?

If F and G as shown above are grouped into a module (MODULE m), nm shows:
0000006d T __m_MOD_f
00000000 t g.1501
0000007a T g_

Should G/contained G not be mangled here (as it is if the contained G is 
removed)?

$> cat callg.f90
  USE m
  CALL G()
END

$> gfortran-svn -g -Wall call2.f90 call.o
/tmp/ccsU0BKE.o: In function `MAIN__':
/home/daniel/pr/call2.f90:2: undefined reference to `__m_MOD_g'
collect2: ld returned 1 exit status



More information about the Fortran mailing list