youngmit
youngmit

Reputation: 848

Cross-module inlining of derived type accessor functions

In C++ it is common to put small functions that are likely to be inlined into a header file to make inlining possible without resorting to link-time optimization or other sorcery. Most commonly, for accessor methods on classes (think operator[] on std::vector). I'm having a heck of a time getting some sort of similar behavior in modern Fortran.

Say I have a module that defines a derived type with some private data, with a simple accessor like this:

module FooMod
type :: FooType
    integer,allocatable,private :: d(:)

    contains
        procedure,pass :: init
        procedure,pass :: get
        procedure,pass :: clear
endtype

contains
    subroutine init(this,n)
        class(FooType),intent(inout) :: this
        integer,intent(in) :: n
        integer :: i

        allocate(this%d(n))
        do i=1,n
            this%d(i)=i
        enddo
    endsubroutine

    function get(this,i) result(val)
        class(FooType),intent(in) :: this
        integer,intent(in) :: i
        integer :: val

        val = this%d(i)
    endfunction

    subroutine clear(this)
        class(FooType),intent(inout) :: this

        deallocate(this%d)
    endsubroutine
endmodule

Now I write a program to use the accessor:

program testtype
use FooMod

type(FooType) :: foo
integer :: val

call foo%init(10)

val = foo%get(2)

write(*,*)val

endprogram

Compiling with gfortran 5.4.0 with -O3:

gfortran -c -O3 foo.f90
gfortran -O3 -S testfoo.f90 foo.o

produces output like this:

call    __foomod_MOD_get
leaq    16(%rsp), %rdi
movl    %eax, 12(%rsp)
movq    $.LC2, 24(%rsp)
movl    $11, 32(%rsp)
movl    $128, 16(%rsp)
movl    $6, 20(%rsp)
call    _gfortran_st_write

So there is still a call happening with no inlining. I get that since the definition of the get() routine is in a different translation unit, inlining it is maybe a little difficult compared to the textual inclusion of C++ headers, but I thought that was part of the purpose of the .mod files that get generated by the compiler.

Is there any way to get little functions like this to inline across modules? If there isn't, this seems like a serious deficiency in the language/implementation in the context of good modern programming practice of data encapsulation.

I tried the -flto flag to see if that would help, but that just spits GIMPLE as ascii text fields to the "assembly" output, so it's hard to tell what it's doing.

Thanks!

Some clarifications: I'm aware of inline in C++, its true meaning and that it's somewhat of a misnomer, and pretty familiar with the concept of inlining; how it works, what conditions need to be satisfied, why it's hard without headers, and where LTO fits into the picture. My main frustration is that since Fortran has formal modules, for which compiler is allowed to generate implementation-specific .mod files, why is it so difficult? Why do we need to explicitly resort to the big guns of language-agnostic, link-time (difficult) inlining to do something as simple as inlining type-bound accessor functions. Can't the compiler store GIMPLE code, or even the function text in the .mod file and do compile-time inlining? Maybe there is some subtlety that I'm missing.

Upvotes: 2

Views: 484

Answers (1)

Rafik Zurob
Rafik Zurob

Reputation: 361

In C/C++, you typically #include a header containing the accessor function definitions. So after preprocessing, the definitions are in the same C/C++ translation unit as the call site and the function can be inlined, even by the compiler's frontend.

In Fortran, PROGRAM, MODULE, external SUBROUTINE, external FUNCTION, and BLOCK DATA all define separate compilation units. Even if they appear in the same source file, the compiler can treat them as if they appeared in separate files. Some compilers do, and therefore can't inline without Link Time Optimization (LTO). Others try to inline if the definitoins appear in the same source file as the call sites. I know of only one compiler that embeds the definitions of module procedures in their .mod files so that they can inline anywhere the module is used.

TL;DR You have to enable LTO if you want these functions inlined in Fortran.

Upvotes: 3

Related Questions