This is the mail archive of the fortran@gcc.gnu.org mailing list for the GNU Fortran project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Function Inlining for FORTRAN


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.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]