In compiler theory, dead-code elimination (DCE, dead-code removal, dead-code stripping, or dead-code strip) is a compiler optimization to remove dead code (code that does not affect the program results). Removing such code has several benefits: it shrinks program size (an important consideration in some contexts); reduces resource usage, such as the number of bytes to be transferred[1]; and allows the running program to avoid executing irrelevant operations, which reduces its running time. It can also enable further optimizations by simplifying program structure. Dead code includes code that can never be executed (unreachable code) and code that only affects dead variables (written to, but never read again), that is, irrelevant to the program.
Consider the following example written in C.
intfoo(void){inta=24;intb=25;// Assignment to dead variableintc;c=a*4;returnc;b=24;// Unreachable codereturn0;}Trivial analysis of the control flow would mark lines 7 and 8 for removal as they are never reached after return c;. If the procedure had a more complex control flow, such as a label after the return statement and a goto elsewhere in the procedure, then a feasible execution path might exist to the assignment to b.
Furthermore, simple analysis of the uses of values would then show that the value of b is only written to and never read from. b is declared as a local variable inside foo, so its value cannot be used outside foo. Thus, the variable b is dead and an optimizer can reclaim its storage space and eliminate its initialization.
Also, even though some calculations are performed in the function, their values are not stored in locations accessible outside the scope of this function. Furthermore, given the function returns a static value (96), it may be simplified to the value it returns (this simplification is called constant folding), resulting in:
intfoo(void){return96;}ほとんどの高度なコンパイラには、デッドコード除去を有効にするオプションがあり、そのレベルは様々です。低いレベルでは、実行できない命令のみを削除する場合があります。高いレベルでは、未使用変数用のメモリ領域を確保しない場合もあります。さらに高いレベルでは、役に立たない命令や関数を特定して削除する場合もあります。
デッドコード除去の一般的な用途は、プリプロセッサによるオプションのコードインクルードの代替手段として使用されることです。次のコードを考えてみましょう。
// DEBUG_MODEをfalseに設定するconstexpr bool DEBUG_MODE = false ;int main ( void ) {int a = 5 ;int b = 6 ;整数c ;c = a * ( b / 2 );if ( DEBUG_MODE ) {printf ( "%d \n " , c );}cを返す;}定数は常にfalseDEBUG_MODEと評価されるため(そのように定義されているため)、if 文内のコードは決して実行されず、デッドコード除去によって最適化されたプログラムから完全に削除されます。この手法はデバッグ時にコードブロックを任意にアクティブ化するためによく用いられます。デッドコード除去機能を備えたオプティマイザを使用すると、同じタスク (例えばthen ...) を実行するためにプリプロセッサを使用する必要がなくなります。#define DEBUG_MODE 0#if DEBUG_MODE
実際には、オプティマイザが見つけるデッドコードの多くは、オプティマイザ内の他の変換によって生成されます。たとえば、演算子強度削減の古典的な手法では、コードに新しい計算を挿入し、古い、よりコストのかかる計算をデッドコードにします。[ 2 ]その後のデッドコード削除により、これらの計算が削除され、効果が完了します(強度削減アルゴリズムを複雑にすることなく)。
歴史的に、デッドコードの削除はデータフロー分析から得られた情報を使用して実行されていました。[ 3 ]静的単一代入形式(SSA)に基づくアルゴリズムは、Ron Cytron らによるSSA形式に関する最初の論文に掲載されています。[ 4 ] Robert Shillingsburg(別名 Shillner)は、このアルゴリズムを改良し、不要な制御フロー操作を削除するための付随アルゴリズムを開発しました。[ 5 ]
上記の例では、コンパイル時に不要なコードを削除しています。しかし、この方法では、オプティマイザによって無条件に不要と判断できるコードのみを削除できます。コンパイル単位(CU)の境界が存在すると、オプティマイザによる不要コードの判定が困難になります。
例えば、多数のオブジェクトファイル()を含むUnix静的ライブラリ( )を考えてみましょう。リンク時に、リンカldは他のコードから参照されるシンボルを調べ、必要なオブジェクトファイルのみを含めるように選択します。つまり、元のコードと、元のオブジェクトファイルのニーズを満たすために取り込まれたオブジェクトファイルの両方から参照されるシンボルを含むオブジェクトファイルのみを含めるようにします。これは、デッドコード削除の非常に粗いバージョンと言えます。*.a*.o
オブジェクトファイルは、互いに参照し合う可能性のある、比較的独立したセクションで構成されています。オブジェクトファイルが、例えば各関数や変数が独自のセクション(-ffunction-sections -fdata-sections)に分割され、リンカにセクションレベルの粒度で相互依存関係を分析するように指示されている場合(--gc-sections)、より完全な形式のリンク時DCEが実現できます。(は、-fdata-sections再配置エントリを増やすことでバイナリのサイズを逆効果に増大させる可能性があります。)[ 6 ]
リンク時DCEの理想的な方法は、リンク時間を別のコンパイル時間、つまりリンク時最適化に変換することです。この構成では、オブジェクトファイルには、コンパイラがマシンコードの代わりに(またはマシンコードに加えて)使用する中間表現が含まれます。このようにして、オプティマイザはプログラム全体にアクセスできるため、CU境界に制約されることがなくなり、最適化に使用できるコードのより多くの特性を検証できるようになります。ただし、プログラムのこのような大きな表現を処理するため、コンパイル時間が長くなるという欠点があります。
実際には、コードセクションが特定の条件下でのみデッドコードまたは到達不能コードを表すことも一般的であり、コンパイル時またはアセンブリ時にはその条件が不明な場合があります。このような条件は、異なる実行時環境(たとえば、異なるバージョンのオペレーティングシステム、または特定のターゲット環境にロードされるドライバやサービスの異なるセットと組み合わせ)によって課される可能性があり、コード内で異なる特殊ケースのセットが必要になる場合がありますが、同時に他のケースでは条件付きデッドコードになります。[ 7 ] [ 8 ]また、ソフトウェア(たとえば、ドライバまたは常駐サービス)は、ユーザーの好みに応じて特定の機能を含めるか除外するように構成でき、特定のシナリオでは未使用のコード部分が役に立たなくなる場合があります。[ 7 ] [ 8 ]モジュール型ソフトウェアは、必要に応じてライブラリを動的にロードするように開発できますが、ほとんどの場合、特定のライブラリから関連するルーチンのみをロードすることは不可能であり、たとえこれがサポートされていたとしても、ルーチンには、特定のシナリオではデッドコードとみなされるコードセクションが含まれている可能性がありますが、コンパイル時に除外することはできません。
需要を動的に検出し、依存関係を特定して解決し、条件付きで不要なコードを削除し、ロード時または実行時に残りのコードを再結合するために使用される技術は、動的デッドコード除去[ 9 ] [ 10 ] [ 11 ]または動的デッド命令除去[ 12 ]と呼ばれます。
ほとんどのプログラミング言語、コンパイラ、オペレーティングシステムは、ライブラリの動的ロードと遅延リンク以外のサポートをほとんど、あるいは全く提供していないため、事前にコンパイルされた言語やアセンブリ言語で書かれた言語と併用して動的デッドコード除去を利用するソフトウェアは非常にまれである。[ 13 ] [ 14 ] [ 15 ]ただし、ジャストインタイムコンパイルを行う言語実装では、デッドコード除去のために動的に最適化される可能性がある。[ 11 ] [ 16 ] [ 17 ]
焦点はやや異なるものの、同様のアプローチは動的なソフトウェア更新やホットパッチにも利用されることがある。
動的デッドコード削除
により、対応するコード抜粋のメモリも節約されます
)。また、ユーザーがマシンを再起動できないようにしたい場合は、API 関数を使用して後でいつでも無効または有効にできます。 […] 同期キャッシュ フラッシュ呼び出しをさらに追加することを検討しています […] 動的デッドコード削除方法により、特定のターゲット構成で必要ない場合は、特定のキャッシュ フラッシュ呼び出しが FreeKEYB のランタイム イメージに含まれるのは、対応するディスク キャッシュもロードされている場合、またはコマンドライン スイッチによって FreeKEYB が対応するサポートをロードするように指示されている場合のみであるため、いかなる種類の肥大化も発生しません。
{{cite web}}: CS1メンテナンス: アーカイブサービスは非推奨になりました (リンク)[…] FreeKEYB は、初期化時に、ロードされるマシンの種類、使用されるキーボードの種類、レイアウト、国、コード ページ、インストールされているマウスとビデオ アダプタの種類、そのシステムにロードされている他のドライバ、オペレーティングシステム、使用されるロードおよび再配置方法、含まれる個々の機能、およびコマンドラインで指定された構成オプションに応じて、ドライバのランタイム イメージを構築します。サポートされているコマンドライン スイッチとオプションの数が多いため […] (約 50 個のスイッチ […] に複数の設定が可能)、無数の依存関係を持つ多数の機能の組み合わせがあり […] 結果として […] 無限の数の […] 異なるターゲット イメージが存在します。 FreeKEYBの動的デッドコード除去技術は、これらの依存関係を解決し、デッドコードとデータを削除します。これは、従来のTSRプログラミングのように、限られた数のモジュールやサブルーチン全体を含めるか除外するか、ディスパッチテーブルを修正するといったことに限定されません。バイトレベルで動作し、より大きなルーチンの途中にある個々の命令を削除できます。特定のケースを処理したり、特定の機能をサポートしたりするために、コード全体に分散されています。特別なツールを使用してコードを分析し、修正テーブルを作成します。条件定義を使用して自動化されたさまざまなケースを宣言します。アセンブリ時だけでなく初期化時にもオプションです。ランタイムイメージに少なくともある程度のデッドコードが残るオーバーヘッドなしで、これらの条件間のすべての依存関係を追跡し、ランタイムイメージを動的に構築および再配置し、これらの小さく、変化し、移動するバイナリ部分間のすべての参照を修正します。小さな.COM/.SYSスタイルのモデルを引き続き使用できます。初期化時に実行されます。FreeKEYBと呼び出し元のアプリケーション間でオブジェクト構造をインポートおよびエクスポートするためのAPI。透過的に実行時に内部的にサイズ変更や移動を行う […] […]
{{cite web}}: CS1メンテナンス: アーカイブサービスは非推奨になりました (リンク)[…]
遅延評価
は基本的に
動的デッドコード除去である
。 […]
{{cite newsgroup}}: CS1 maint: 非推奨のアーカイブサービス (リンク) (注:動的デッドコード削除という用語が初めて公に使用された例である可能性が高いが、概念的なものであり、関数型言語における遅延評価に焦点を当てている。){{cite web}}: CS1メンテナンス: アーカイブサービスは非推奨になりました (リンク)[…] brandneue[s] 機能、
デッドコード排除機能
、宝石ではなく、ベストアンサーメンバステルトと再配置のインストール、つまり、コードの日付を変更する (zB wenn jemand ein) Bestimmtes FreeKEYB-Feature nicht benötigt)。 […]
{{cite newsgroup}}: CS1 maint: 非推奨のアーカイブサービス (リンク) (注: これは、事前にアセンブルまたはコンパイルされたソフトウェアに対する、バイトレベルのきめ細かな動的デッドコード除去の最初の既知の実装です。)