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.