2017-07-26 5 views
1

C++では、リンク時間の最適化や他の魔法に頼らずに、インライン化が可能な小さな関数をヘッダーファイルに組み込むことが一般的です。最も一般的には、クラスのアクセサメソッドの場合(operator[]std::vectorと考えてください)。私は、現代のFortranで何らかの類似の動作を得るために時代を過ごしています。派生型アクセサ関数のモジュール間インライン展開

は、私はこのような単純なアクセサで、いくつかのプライベートデータを持つ派生型を定義するモジュールを持っていると言う:

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 

今私はアクセサを使用するプログラムを作成:

program testtype 
use FooMod 

type(FooType) :: foo 
integer :: val 

call foo%init(10) 

val = foo%get(2) 

write(*,*)val 

endprogram 

-O3でのgfortran 5.4.0でコンパイル:

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

は出力を生成します

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 

したがって、インライン化が行われていない状態でコールが発生しています。 get()ルーチンの定義が別の翻訳単位になっているので、インライン展開はC++ヘッダーのテキストによる組み込みに比べて少し難しいかもしれませんが、それは.modファイルの目的の一部であると考えていました。コンパイラ。

このような機能をモジュール間でインライン化する方法はありますか?存在しない場合、これはデータカプセル化の現代的なプログラミング慣行の文脈における言語/実装における重大な欠陥のようである。

私は-fltoフラグを使ってそれが役立つかどうかを試しましたが、GIMPLEを「アセンブリ」出力にASCIIテキストフィールドとして吐き出すので、何をしているのか分かりにくいです。

ありがとうございます!

私はinlineをC++で認識しています。その真の意味、それはやや誤解であり、インライン化の概念にかなり精通しています。どのような条件が満たされる必要があるのか​​、ヘッダーがないと難しいのはなぜ、そしてLTOはどこに画像に収まるのでしょうか。私の主な不満は、Fortranは正式なモジュールを持っているので、コンパイラは実装固有の.modファイルを生成することができますが、それはどうして難しいのですか?なぜ型に束縛されたアクセサー関数をインライン化するのと同じようなことをするために、言語に依存しないリンク時(難しい)インライン展開の大きな銃に明示的に頼る必要があるのですか?コンパイラはGIMPLEコード、または関数テキストを.modファイルに格納してコンパイル時のインライン展開を実行できませんか?たぶん私が紛失している微妙なことがあるかもしれません。

+0

どのコンパイラオプションを使用しましたか? '-flto'は実際には完全に必要ですが、別のファイルで別のgfortran呼び出しでコンパイルされます。 –

+1

'-flto' [here](https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html)に関連するドキュメントを見て、あなたの役に立つかもしれない関連オプション調査(例えば、 '-fno-fat-lto-objects')です。 '-flto'は、コンパイル段階とリンク段階の両方で提供されなければならないことに注意してください。 –

+1

また、[関連する質問](https://stackoverflow.com/a/42386798) –

答えて

2

C/C++では、アクセサー関数定義を含むヘッダーを#includeします。したがって、前処理の後、定義はコールサイトと同じC/C++翻訳単位にあり、関数はコンパイラのフロントエンドによってさえインライン化できます。

Fortranでは、PROGRAM、MODULE、外部SUBROUTINE、外部FUNCTION、およびBLOCK DATAはすべて、別々のコンパイル単位を定義します。たとえそれらが同じソースファイルにあっても、コンパイラはそれらを別々のファイルにあるかのように扱うことができます。コンパイラの中にはリンク時間最適化(LTO)なしでインライン化できないものがあります。他の人は、definitoinsがコールサイトと同じソースファイルに表示される場合、インライン化を試みます。私は、モジュールが使用されているどこにでもインラインで記述できるように、モジュール・プロシージャの定義を.modファイルに埋め込んだ唯一のコンパイラを知っています。

TL; DR Fortranでこれらの関数をインライン化するには、LTOを有効にする必要があります。

+0

どのコンパイラが関数定義を.modファイルに格納しているかを参照していますか? – youngmit

+2

Crayコンパイラには、モジュールプロシージャをインライン化するためのオプション "-O modinline"があります。 (私はLTOなしと信じています) この問題は、Fortranの標準メーリングリストに複数回出現しています。たとえば、[ここ](http://mailman.j3-fortran.org/pipermail/j3/2014-May/007435.html)。 免責事項:私はIBMコンパイラを使用しています。 LTOをモジュール・プロシージャーを他のコンパイル単位にインライン化できるようにする必要があります。 –

関連する問題