LLVM エイリアス解析インフラストラクチャ¶
はじめに¶
エイリアス解析(別名ポインタ解析)は、2つのポインタがメモリの同じオブジェクトを指す可能性があるかどうかを判断しようとする手法のクラスです。エイリアス解析には多くの異なるアルゴリズムがあり、それらを分類する方法はたくさんあります。フローセンシティブ対フローインセンシティブ、コンテキストセンシティブ対コンテキストインセンシティブ、フィールドセンシティブ対フィールドインセンシティブ、ユニフィケーションベース対サブセットベースなどです。伝統的に、エイリアス解析はクエリに対してMust、May、またはNoエイリアス応答で応答し、2つのポインタが常に同じオブジェクトを指す、同じオブジェクトを指す可能性がある、または同じオブジェクトを指さないことがわかっていることを示します。
LLVM AliasAnalysisクラスは、LLVMシステムにおけるエイリアス解析の実装とクライアントで使用される主要なインターフェースです。このクラスは、エイリアス解析情報のクライアントとそれを提供する実装の間の共通のインターフェースであり、幅広い実装とクライアントをサポートするように設計されています(ただし、現在のすべてのクライアントはフローインセンシティブであると想定されています)。単純なエイリアス解析情報に加えて、このクラスは、それを提供できる実装からMod/Ref情報を公開し、強力な解析と変換が連携して機能することを可能にします。
このドキュメントには、このインターフェースを正常に実装し、使用し、両側をテストするために必要な情報が含まれています。また、結果の意味に関するいくつかの詳細についても説明します。
AliasAnalysis
クラスの概要¶
AliasAnalysisクラスは、さまざまなエイリアス解析実装がサポートする必要があるインターフェースを定義します。このクラスは、AliasResult
とModRefResult
という2つの重要な列挙型をエクスポートします。これらはそれぞれ、エイリアスクエリまたはmod/refクエリの結果を表します。
AliasAnalysis
インターフェースは、いくつかの異なる方法で表されるメモリに関する情報を公開します。特に、メモリオブジェクトは開始アドレスとサイズで表され、関数呼び出しは、呼び出しを実行する実際のcall
またはinvoke
命令で表されます。AliasAnalysis
インターフェースは、任意の命令のmod/ref情報を取得できるヘルパーメソッドも公開します。
すべてのAliasAnalysis
インターフェースでは、複数の値を含むクエリにおいて、定数ではない値はすべて同じ関数内で定義されている必要があります。
ポインタの表現¶
最も重要なことに、AliasAnalysis
クラスは、2つのメモリオブジェクトがエイリアスするかどうか、関数呼び出しがメモリオブジェクトを変更または読み取る可能性があるかどうかなどを問い合わせるために使用されるいくつかのメソッドを提供します。これらのクエリのすべてにおいて、メモリオブジェクトは、その開始アドレス(シンボリックなLLVM Value*
)と静的なサイズのペアとして表されます。
メモリオブジェクトを開始アドレスとサイズで表すことは、正しいエイリアス解析にとって非常に重要です。たとえば、次の(ばかげているが可能な)Cコードを考えてみましょう。
int i;
char C[2];
char A[10];
/* ... */
for (i = 0; i != 10; ++i) {
C[0] = A[i]; /* One byte store */
C[1] = A[9-i]; /* One byte store */
}
この場合、basic-aa
パスは、C[0]
とC[1]
へのストアを区別します。なぜなら、それらは1バイト離れた2つの異なる場所へのアクセスであり、アクセスはそれぞれ1バイトだからです。この場合、ループ不変コード移動(LICM)パスは、ストア移動を使用してループからストアを削除できます。対照的に、次のコードは
int i;
char C[2];
char A[10];
/* ... */
for (i = 0; i != 10; ++i) {
((short*)C)[0] = A[i]; /* Two byte store! */
C[1] = A[9-i]; /* One byte store */
}
この場合、&C[0]
要素へのアクセスは2バイトアクセスであるため、Cへの2つのストアは互いにエイリアスします。サイズ情報がクエリで使用できなかった場合、最初のケースでさえ、アクセスがエイリアスすると保守的に仮定する必要があります。
alias
メソッド¶
alias
メソッドは、2つのメモリオブジェクトが互いにエイリアスするかどうかを判断するために使用される主要なインターフェースです。2つのメモリオブジェクトを入力として受け取り、適切なMustAlias、PartialAlias、MayAlias、またはNoAliasを返します。
すべてのAliasAnalysis
インターフェースと同様に、alias
メソッドでは、2つのポインタ値が同じ関数内で定義されているか、少なくとも1つの値が定数である必要があります。
Must、May、およびNoエイリアス応答¶
NoAlias
応答は、一方のポインタに基づくメモリ参照と、もう一方のポインタに基づくメモリ参照の間に、即時的な依存関係がない場合に使用できます。最も明白な例は、2つのポインタが重複しないメモリ範囲を指している場合です。もう1つは、2つのポインタがメモリを読み取るためだけに使用される場合です。もう1つは、メモリが解放され、一方のポインタによるアクセスともう一方のポインタによるアクセスの間に再割り当てされる場合です。この場合、依存関係がありますが、それは解放と再割り当てによって仲介されます。
noaliasキーワードでは例外があります。「無関係な」依存関係は無視されます。
MayAlias
応答は、2つのポインタが同じオブジェクトを参照する可能性がある場合に使用されます。
2つのメモリオブジェクトが、開始アドレスが同じかどうかに関係なく、何らかの方法でオーバーラップしていることがわかっている場合、PartialAlias
レスポンスが使用されます。
MustAlias
レスポンスは、2つのメモリオブジェクトが常にまったく同じ場所で開始することが保証されている場合にのみ返される可能性があります。MustAlias
レスポンスは、ポインタが等しいことを意味するものではありません。
getModRefInfo
メソッド¶
getModRefInfo
メソッドは、命令の実行がメモリの場所を読み取るか変更するかについての情報を返します。Mod/Ref情報は常に保守的です。命令が場所を読み取るか書き込む可能性がある場合、ModRef
が返されます。
AliasAnalysis
クラスは、関数呼び出し間の依存関係をテストするためのgetModRefInfo
メソッドも提供します。このメソッドは2つの呼び出しサイト(CS1
とCS2
)を受け取り、どちらの呼び出しも他方の読み取りまたは書き込みメモリに書き込まない場合はNoModRef
を返し、CS1
がCS2
によって書き込まれたメモリを読み取る場合はRef
を返し、CS1
がCS2
によって読み取られたり書き込まれたりするメモリに書き込む場合はMod
を返し、CS1
がCS2
によって書き込まれたメモリを読み取ったり書き込んだりする可能性がある場合はModRef
を返します。この関係は可換ではないことに注意してください。
その他の有用なAliasAnalysis
メソッド¶
さまざまなエイリアス分析実装によって収集されることが多いその他の情報のスニペットがいくつかあり、さまざまなクライアントによって有効活用できます。
getModRefInfoMask
メソッド¶
getModRefInfoMask
メソッドは、ポインタがグローバル定数メモリを指しているかどうか(NoModRef
を返す)、またはローカル不変メモリを指しているかどうか(Ref
を返す)に関する知識に基づいて、指定されたポインタのMod/Ref情報の境界を返します。グローバル定数メモリには、関数、定数グローバル変数、ヌルポインタが含まれます。ローカル不変メモリとは、SSA値のライフタイム中は不変であることがわかっているメモリですが、プログラムのライフタイム中とは限りません。たとえば、readonly
noalias
パラメータによって指されるメモリは、対応する関数呼び出しの期間中は不変であることがわかっています。メモリの場所Loc
に対するMod/Ref情報MRI
の場合、MRI &= AA.getModRefInfoMask(Loc);
のようなステートメントでMRI
を改良できます。別の便利なイディオムはisModSet(AA.getModRefInfoMask(Loc))
です。これは、指定された場所が変更される可能性があるかどうかをチェックします。便宜上、pointsToConstantMemory(Loc)
メソッドもあります。これはisNoModRef(AA.getModRefInfoMask(Loc))
と同義です。
doesNotAccessMemory
およびonlyReadsMemory
メソッド¶
これらのメソッドは、関数呼び出しに対して非常に単純なmod/ref情報を提供するために使用されます。doesNotAccessMemory
メソッドは、分析によって関数がメモリを読み書きしないことが証明されている場合、または関数が定数メモリからのみ読み取る場合、関数に対してtrueを返します。このプロパティを持つ関数は副作用がなく、入力引数にのみ依存するため、共通部分式を形成する場合やループから持ち上げることができる場合は削除できます。多くの一般的な関数はこのように動作しますが(例:sin
およびcos
)、そうでないものもあります(例:errno
変数を変更するacos
)。
onlyReadsMemory
メソッドは、分析によって(多くとも)関数が揮発性ではないメモリからのみ読み取ることを証明できる場合、関数に対してtrueを返します。このプロパティを持つ関数は副作用がなく、入力引数と呼び出されたときのメモリの状態のみに依存します。このプロパティにより、メモリの内容を変更するストア命令がない限り、これらの関数の呼び出しを削除して移動することができます。doesNotAccessMemory
メソッドを満たすすべての関数は、onlyReadsMemory
も満たすことに注意してください。
新しいAliasAnalysis
実装の記述¶
LLVM向けの新しいエイリアス分析実装の記述は非常に簡単です。既にいくつかの実装例があり、次の情報が詳細の記入に役立ちます。例として、LLVMに含まれるさまざまなエイリアス分析の実装をご覧ください。
異なるパススタイル¶
エイリアス分析に使用すべきLLVMパスの種類を決定する最初のステップです。他のほとんどの分析と変換の場合と同様に、解決しようとしている問題の種類から答えは非常に明白であるはずです。
プロシージャ間分析が必要な場合は、
Pass
にする必要があります。関数ローカル分析の場合は、
FunctionPass
をサブクラス化します。プログラム全体を調べる必要がない場合は、
ImmutablePass
をサブクラス化します。
サブクラス化するパスに加えて、もちろんAliasAnalysis
インターフェースからも継承し、RegisterAnalysisGroup
テンプレートを使用してAliasAnalysis
の実装として登録する必要があります。
必要な初期化呼び出し¶
AliasAnalysis
のサブクラスは、AliasAnalysis
基本クラスでgetAnalysisUsage
メソッドとInitializeAliasAnalysis
メソッドの2つのメソッドを呼び出す必要があります。特に、getAnalysisUsage
の実装では、パスが持つ依存関係を宣言することに加えて、AliasAnalysis::getAnalysisUsage
メソッドへの明示的な呼び出しを行う必要があります。したがって、次のようなものが必要です。
void getAnalysisUsage(AnalysisUsage &AU) const {
AliasAnalysis::getAnalysisUsage(AU);
// declare your dependencies here.
}
さらに、分析実行メソッド(Pass
の場合はrun
、FunctionPass
の場合はrunOnFunction
、ImmutablePass
の場合はInitializePass
)からInitializeAliasAnalysis
メソッドを呼び出す必要があります。たとえば(Pass
の一部として)
bool run(Module &M) {
InitializeAliasAnalysis(this);
// Perform analysis here...
return false;
}
オーバーライドが必要なメソッド¶
AliasAnalysis
のすべてのサブクラスでgetAdjustedAnalysisPointer
メソッドをオーバーライドする必要があります。このメソッドの実装例を次に示します。
void *getAdjustedAnalysisPointer(const void* ID) override {
if (ID == &AliasAnalysis::ID)
return (AliasAnalysis*)this;
return this;
}
指定できるインターフェース¶
すべてのAliasAnalysis仮想メソッドは、デフォルトで別のエイリアス分析実装へのチェイニングを提供します。これは、保守的に正しい情報を返すことになります(エイリアスとmod/refクエリに対してそれぞれ「May」Aliasと「Mod/Ref」を返します)。実装している分析の機能に応じて、改善できるインターフェースのみをオーバーライドします。
AliasAnalysis
チェイニング動作¶
すべてのエイリアス分析パスは、別のエイリアス分析実装にチェイニングされます(たとえば、ユーザーは「-basic-aa -ds-aa -licm
」を指定して、両方のエイリアス分析の最大の利点を得ることができます)。エイリアス分析クラスは、オーバーライドしないメソッドのほとんどを自動的に処理します。オーバーライドするメソッドの場合、保守的なMayAliasまたはMod/Refの結果を返すコードパスでは、単にスーパークラスが計算するものを返します。例:
AliasResult alias(const Value *V1, unsigned V1Size,
const Value *V2, unsigned V2Size) {
if (...)
return NoAlias;
...
// Couldn't determine a must or no-alias result.
return AliasAnalysis::alias(V1, V1Size, V2, V2Size);
}
分析クエリに加えて、オーバーライドする場合はLLVMの更新通知メソッドをスーパークラスに無条件に渡す必要があります。これにより、変更におけるすべてのエイリアス分析を更新できます。
変換に対する分析結果の更新¶
エイリアス分析情報は、プログラムの静的スナップショットに対して最初に計算されますが、クライアントはこの情報を使用してコードに変換を行います。ほとんどの単純な形式を除くすべてのエイリアス分析では、これらの変換によって行われた変更を反映するように分析結果を更新する必要があります。
AliasAnalysis
インターフェースは、クライアントから分析実装へのプログラムの変更を伝えるために使用される4つのメソッドを公開しています。さまざまなエイリアス分析実装では、これらのメソッドを使用して、プログラムの変更(命令の削除など)に伴い内部データ構造を最新の状態に保つ必要があります。また、エイリアス分析のクライアントは、これらのインターフェースを適切に呼び出す必要があります。
deleteValue
メソッド¶
deleteValue
メソッドは、変換によって命令またはその他の値がプログラムから削除された場合(ポインタを使用しない値を含む)に呼び出されます。通常、エイリアス分析はプログラム内の各値のエントリを持つデータ構造を保持します。このメソッドが呼び出されると、指定された値のエントリがあれば削除する必要があります。
copyValue
メソッド¶
copyValue
メソッドは、新しい値がプログラムに導入された場合に使用されます。以前に存在しなかった値をプログラムに導入する方法はありません(安全なコンパイラ変換では意味がありません)。そのため、これは新しい値を導入する唯一の方法です。このメソッドは、新しい値がコピーされている値とまったく同じプロパティを持っていることを示します。
replaceWithNewValue
メソッド¶
このメソッドは、クライアントの使いやすさを向上させるために提供される単純なヘルパーメソッドです。古い分析情報を新しい値にコピーしてから、古い値を削除することによって実装されます。このメソッドは、エイリアス分析実装によってオーバーライドすることはできません。
addEscapingUse
メソッド¶
addEscapingUse
メソッドは、ポインタ値の使用が、事前に計算された分析情報を無効にする可能性のある方法で変更された場合に使用されます。実装では、このコールバックを使用して、使用が分析時間以降に変更されたポイントに対して保守的な応答を提供するか、内部状態の一部またはすべてを再計算して、正確な応答を引き続き提供できます。
一般に、ポインタ値の新しい使用はすべてエスケープ使用と見なされ、このコールバックを通じて報告する必要があります。ただし、以下の使用は除きます。
ポインタの
bitcast
またはgetelementptr
ポインタを経由した
store
(ただし、ポインタのstore
ではない)ポインタを経由した
load
効率性の問題¶
LLVMの観点から、効率的なエイリアス分析を提供するために必要なのは、エイリアス分析の**クエリ**が迅速に処理されるようにすることだけです。「実行」メソッドではエイリアス分析の結果の実際の計算は一度だけ実行されますが、多くの(おそらく重複した)クエリが実行される可能性があります。そのため、可能な限り(妥当な範囲内で)多くの計算を「実行」メソッドに移動するようにしてください。
制限事項¶
AliasAnalysisインフラストラクチャには、新しいAliasAnalysis
実装の作成を困難にするいくつかの制限があります。
デフォルトのエイリアス分析をオーバーライドする方法はありません。「opt -my-aa -O2
」のようなことを行って、AliasAnalysisを必要とするすべてのパスで-my-aa
を使用させることは非常に役立ちますが、ソースコードを変更して再コンパイルする以外に、現在はそのようなサポートはありません。同様に、分析のチェーンをデフォルトとして設定する方法もありません。
AliasAnalysis
実装を保存することを変換パスが宣言する方法はありません。AliasAnalysis
インターフェースには、パスがAliasAnalysisの一貫性を維持できるようにするためのdeleteValue
とcopyValue
メソッドが含まれていますが、パスがそうすることをgetAnalysisUsage
で宣言する方法はありません。一部のパスはAU.addPreserved<AliasAnalysis>
を使用しようとしますが、実際には効果がありません。
同様に、opt -p
オプションは各パスの間にModulePass
パスを導入するため、FunctionPass
エイリアス分析パスの使用が妨げられます。
AliasAnalysis
APIには、値が削除またはコピーされたときに実装に通知するための関数がありますが、これだけでは不十分です。AliasAnalysis
実装に関連する可能性のあるLLVM IRの変更方法は他にもたくさんあり、表現できません。
AliasAnalysisDebugger
ユーティリティは、AliasAnalysis
実装が、エイリアスクエリに表示される前に関連するValue
が通知されると想定できることを示唆しているようです。しかし、GVN
などの一般的なクライアントはこれをサポートしておらず、AliasAnalysisDebugger
で実行するとエラーが発生することが知られています。
AliasSetTracker
クラス(LICM
で使用される)は、非決定的な数のエイリアスクエリを行います。これにより、事前に決定された数のクエリ後に実行を一時停止するデバッグ手法の信頼性が低下する可能性があります。
多くのエイリアスクエリは、他のエイリアスクエリで言い換えることができます。複数のAliasAnalysis
クエリがチェーン状に連結されている場合、無限ループを避けるために注意を払って、チェーンの先頭からそれらのクエリを開始することが理にかなっていますが、現在、これを行いたい実装は自分自身からしかそのようなクエリを開始できません。
エイリアス分析結果の使用¶
エイリアス分析結果を使用するには、いくつかの異なる方法があります。優先順位の高い順に、これらは以下のとおりです。
MemoryDependenceAnalysis
パスの使用¶
memdep
パスは、エイリアス分析を使用して、メモリを使用する命令に関する高レベルの依存関係情報を提供します。たとえば、どのストアがロードに供給されるかを教えてくれます。キャッシングやその他の技術を使用して効率性を高めており、デッドストアの削除、GVN、memcpy最適化で使用されています。
AliasSetTracker
クラスの使用¶
多くの変換では、ペアワイズエイリアシングに関する情報ではなく、あるスコープでアクティブなエイリアス**セット**に関する情報が必要です。AliasSetTrackerクラスは、AliasAnalysis
インターフェースによって提供されるペアワイズエイリアス分析情報からこれらのエイリアスセットを効率的に構築するために使用されます。
最初に、「add
」メソッドを使用して、関心のあるスコープ内のさまざまな可能性のあるエイリアシング命令に関する情報を追加することにより、AliasSetTrackerを初期化します。すべてのエイリアスセットが完了したら、パスは構築されたエイリアスセットを単純に反復処理し、AliasSetTracker
のbegin()
/end()
メソッドを使用する必要があります。
AliasSetTracker
によって形成されたAliasSet
は、互いに素であることが保証され、セットのmod/ref情報と揮発性を計算し、セット内のすべてのポインタがMustエイリアスであるかどうかを追跡します。AliasSetTrackerは、セットが呼び出し命令のために適切に折り畳まれるようにし、各セットのポインタのリストを提供することもできます。
この例として、ループ不変コード移動パスはAliasSetTracker
を使用して、各ループネストのエイリアスセットを計算します。ループ内のAliasSet
が変更されない場合、そのセットからのすべてのロード命令をループの外に持ち上げることができます。エイリアスセットが保存され、かつ必須エイリアスセットである場合、ストアをループの外に沈めることができ、ループネストの期間中はメモリ位置をレジスタに昇格させることができます。これらの変換はどちらも、ポインタ引数がループ不変の場合にのみ適用されます。
AliasSetTrackerの実装¶
AliasSetTrackerクラスは、可能な限り効率的に実装されています。ポインタが複数のAliasSetにエイリアスされるAliasSetTrackerに挿入された場合、ユニオンファインドアルゴリズムを使用してAliasSetを効率的にマージします。主要なデータ構造は、ポインタをそれらが属するAliasSetにマッピングするハッシュテーブルです。
AliasSetTrackerクラスは、各AliasSetにあるすべてのLLVM Value*
のリストを維持する必要があります。ハッシュテーブルには既に目的の各LLVM Value*
のエントリがあるため、AliasesSetsはこれらのハッシュテーブルノードを介してリンクリストをスレッド化し、不要なメモリ割り当てを回避し、エイリアスセットのマージを非常に効率的にします(リンクリストのマージは定数時間です)。
AliasSetTrackerのクライアントであるだけなら、これらの詳細は理解する必要はありませんが、コードを確認する場合は、この簡単な説明が設計の理由を理解するのに役立つことを願っています。
AliasAnalysis
インターフェースの直接使用¶
これらのユーティリティクラスのどちらもパスに必要なものでない場合は、AliasAnalysis
クラスによって公開されるインターフェースを直接使用してください。可能な限り上位レベルのメソッドを使用してください(例:可能な場合はaliasメソッドを直接使用するのではなく、mod/ref情報を使用する)。これにより、最高の精度と効率が得られます。
既存のエイリアス解析の実装とクライアント¶
LLVMエイリアス解析インフラストラクチャを操作する場合は、利用可能なエイリアス解析のクライアントと実装について知っておく必要があります。特に、エイリアス解析を実装する場合は、さまざまな実装の監視と評価に役立つクライアントを認識しておく必要があります。
利用可能なAliasAnalysis
実装¶
このセクションでは、AliasAnalysis
インターフェースのさまざまな実装をリストしています。これらすべては、他のエイリアス解析実装にチェーンします。
-basic-aa
パス¶
-basic-aa
パスは、多くの重要な事実を「知っている」積極的なローカル解析です。
異なるグローバル変数、スタック割り当て、ヒープ割り当ては、決してエイリアスしません。
グローバル変数、スタック割り当て、ヒープ割り当ては、ヌルポインタと決してエイリアスしません。
構造体の異なるフィールドはエイリアスしません。
静的に異なる添字を持つ配列へのインデックスは、エイリアスできません。
多くの一般的な標準Cライブラリ関数は、メモリにアクセスしないか、読み取り専用です。
明らかに定数グローバル変数を指すポインタは「
pointToConstantMemory
」です。関数呼び出しは、割り当てた関数からエスケープしない場合(自動配列の一般的なケース)、スタック割り当てを修正または参照することはできません。
-globalsmodref-aa
パス¶
このパスは、「アドレスが取得されていない」内部グローバル変数に対して、単純なコンテキスト依存のmod/refおよびエイリアス解析を実装します。グローバル変数のアドレスが取得されていない場合、このパスは、ポインタがグローバル変数とエイリアスしないことを認識します。このパスはまた、メモリにアクセスしない、またはメモリを読み取らないことがわかっている関数の追跡も行います。これにより、特定の最適化(例:GVN)で関数呼び出し命令を完全に削除できます。
このパスの真の威力は、関数呼び出し命令に対してコンテキスト依存のmod/ref情報を提供することです。これにより、最適化器は、関数への呼び出しがグローバル変数の値を破壊または読み取らないことを認識できるため、ロードとストアを削除できます。
注記
このパスの範囲はいくぶん限定的ですが(アドレスが取得されていないグローバル変数のみをサポート)、非常に高速な解析です。
-steens-aa
パス¶
-steens-aa
パスは、よく知られた「Steensgaardアルゴリズム」の変形を、プロシージャ間エイリアス解析のために実装します。Steensgaardアルゴリズムは、統一ベースの、フロー非依存、コンテキスト非依存、フィールド非依存のエイリアス解析であり、非常にスケーラブルでもあります(事実上線形時間)。
LLVM -steens-aa
パスは、データ構造解析フレームワークを使用して、Steensgaardアルゴリズムの「投機的なフィールド**依存**」バージョンを実装します。これにより、標準アルゴリズムよりも大幅に精度が向上し、優れた解析スケーラビリティが維持されます。
注記
-steens-aa
は、オプションの「poolalloc」モジュールで使用できます。LLVMコアの一部ではありません。
-ds-aa
パス¶
-ds-aa
パスは、完全なデータ構造解析アルゴリズムを実装します。データ構造解析は、モジュール式の統一ベース、フロー非依存、コンテキスト**依存**、投機的なフィールド**依存**エイリアス解析であり、非常にスケーラブルです。通常はO(n * log(n))
です。
このアルゴリズムは、さまざまなエイリアス解析クエリに対応でき、コンテキスト依存のmod/ref情報も提供できます。これまで実装されていない唯一の主要な機能は、must-alias情報のサポートです。
注記
-ds-aa
は、オプションの「poolalloc」モジュールで使用できます。LLVMコアの一部ではありません。
-scev-aa
パス¶
-scev-aa
パスは、ScalarEvolutionクエリに変換することでAliasAnalysisクエリを実装します。これにより、他のエイリアス解析よりもgetelementptr
命令とループ誘導変数の理解が深まります。
エイリアス解析駆動型変換¶
LLVMには、上記のいずれかの実装で使用できる、いくつかのエイリアス解析駆動型変換が含まれています。
-adce
パス¶
-adce
パス(積極的なデッドコード除去を実装)は、AliasAnalysis
インターフェースを使用して、副作用がなく使用されていない関数への呼び出しを削除します。
-licm
パス¶
-licm
パスは、ループ不変コード移動に関連するさまざまな変換を実装します。さまざまな変換にAliasAnalysis
インターフェースを使用します。
ループ内でロードされたメモリを変更する命令がない場合、mod/ref情報を使用して、ループからロード命令をホイスティングまたはシンクします。
メモリに書き込まず、ループ不変である関数呼び出しをループからホイスティングするために、mod/ref情報を使用します。
ループ内でロードおよびストアされるメモリオブジェクトをレジスタにプロモーションするために、エイリアス情報を使用します。ロード/ストアされたメモリ位置にmayエイリアスがない場合、これを実行できます。
-argpromotion
パス¶
-argpromotion
パスは、参照渡し引数を値渡しで渡すようにプロモーションします。特に、ポインタ引数からロードされるだけであれば、関数にアドレスではなくロードされた値を渡します。このパスは、エイリアス情報を使用して、引数ポインタからロードされた値が関数のエントリとポインタのロードの間に変更されていないことを確認します。
-gvn
、-memcpyopt
、および-dse
パス¶
これらのパスは、AliasAnalysis情報を使用してロードとストアを推論します。
実装のデバッグと評価のためのクライアント¶
これらのパスは、さまざまなエイリアス解析の実装を評価するのに役立ちます。これらは次のようなコマンドで使用できます。
% opt -ds-aa -aa-eval foo.bc -disable-output -stats
-print-alias-sets
パス¶
-print-alias-sets
パスは、opt
ツールの一部として公開されており、AliasSetTracker クラスによって形成されたエイリアス集合を出力します。これは、AliasSetTracker
クラスを使用している場合に役立ちます。使用方法の例を以下に示します。
% opt -ds-aa -print-alias-sets -disable-output
-aa-eval
パス¶
-aa-eval
パスは、関数内のすべてのポインタのペアを単純に反復処理し、エイリアス解析にそれらのポインタがエイリアス化されるかどうかを問い合わせます。これにより、エイリアス解析の精度を示すことができます。発見されたno/may/mustエイリアスの割合を示す統計情報が出力されます(より正確なアルゴリズムでは、mayエイリアスの数が少なくなります)。
メモリ依存性解析¶
注記
現在、MemoryDependenceAnalysis
から MemorySSA への移行作業中です。代わりにこれを使用してください。
エイリアス解析情報のクライアントになるだけの場合、代わりにメモリ依存性解析インターフェースの使用を検討してください。MemDepは、エイリアス解析の上に構築された遅延キャッシングレイヤーであり、特定の命令が依存する先行するメモリ操作を、ブロック内またはブロック間レベルのいずれかで回答することができます。その遅延性とキャッシングポリシーにより、MemDepを使用することで、エイリアス解析に直接アクセスするよりもパフォーマンスが大幅に向上する可能性があります。