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を返します。
