LLVMについて、バックエンドの部分はある程度勉強したけど、そういえばPassの作り方をまじめに勉強したことが無かった。
LLVMと言えばPassだろう!ということでPassの作り方について勉強することにした。これはそのうちLLVMの拡張や最適化をしたいときに役に立つはずだ。
今回は少し進んで、LLVMのPassのクラスについて。いくつかのPassを構成するクラスがあり、最適なものを選択する必要があるということ。
LLVMのPassを書く
passのクラスと必要事項
新しいpassをデザインするときにまず考えなければならないのは、そのpassがどのクラスのサブクラスなのかということです。
"Hello World"の例ではFunctionPass
を使用しましたが、なぜこのpassを使ったのか、他にどのようなpassがあるのかについては特に議論しませんでした。
ここではどのようなクラスが利用なのか、最も一般的なものから専門的なものまで紹介します。
Passのスーパークラスを選択する際、可能ならばその要求に適した最も専門的なクラスを選択すべきです。 これにより、LLVM Passインフラストラクチャはpassの実行方法を最適化するために必要な情報を提供し、 結果としてコンパイラが不必要に遅くならないようにします。
ImmutablePass
クラス
もっとも一般的なタイプのpassはImmutablePass
クラスです。
このpass型は実行する必要のない、状態を変更しない、更新する必要のないpassに対して使用します。
これは変換もしくは解析の普通の型ではありませんが、現在のコンパイラのコンフィグレーションについての情報を提供することができます。
このpassクラスは殆ど使用されることはありませんが、コンパイルされている現在のターゲットマシンについての情報や、 いくつかの変換に影響を与える他の静的な情報を提供するために重要です。
ImmutablePass
は他の変換を決して無効化せず、また決して無効化されず、また決して「実行」されることもありません。
ModulePass
クラス
ModulePass
クラスはすべてのスーパークラスのもっとも一般的なものです。ModulePass
から派生したものは、
このpassはプログラム全体を使用することを意味し、単体として、predictable順ではなく関数の本体を参照し、関数を追加または削除します。
ModulePass
サブクラスについて何も知らないため、このpassの実行では最適化は実行できません。
モジュールpassは、任意のモジュールまたはimmutable passを使用しないとき、getAnalysis
インタフェースgetAnalysis<DominatorTree>(llvm::Function *)
を使用する関数レベルのpass(例: dominatorなど)を使用することができ、関数に対して全体的な解析の結果を提供します。
これは解析の行われた関数に対してのみ行われます。例えば、dominatorの場合はDominatorTree
の関数定義に対してのみ問い合わせるべきであり、宣言に対しては問い合わせるべきではありません。
正しいModulePass
サブクラスを実装するためには、ModulePass
から派生してrunOnModule
メソッドを以下のようにして実装する必要があります:
runOnModule
メソッド
virtual bool runOnModule(Module &M) = 0;
runOnModule
メソッドはpass乗で面白い動作をします。
変換処理によりモジュールを変更した場合、true
を返す必要があり、そうでない場合はfalse
を返します。