コンパイラ理論 では、デッドコード除去(DCE、デッドコード削除、デッドコードストリッピング、またはデッドコードストリップ)は、デッドコード(プログラムの結果に影響を与えないコード)を削除するコンパイラの最適化です。このようなコードを削除すると、いくつかの利点があります。プログラムのサイズが縮小します(一部の状況では重要な考慮事項です)。転送するバイト数などのリソース使用量が削減されます[ 1 ]。実行中のプログラムが無関係な操作の実行を回避できるため、実行時間が短縮されます。また、プログラム構造を簡素化することで、さらなる最適化が可能になります。デッドコードには、決して実行されないコード(到達不能コード)と、デッド変数(書き込まれるが二度と読み込まれない)にのみ影響するコード、つまりプログラムに無関係なコードが含まれます。
C言語で書かれた以下の例を考えてみましょう。
int foo ( void ) {int a = 24 ;int b = 25 ; // デッド変数への代入整数c ;c = a * 4 ;cを返す;b = 24 ; // 到達不能なコード0を返す;}制御フローを単純に分析すると、 の後には決して到達しないため、7 行目と 8 行目は削除対象としてマークされますreturn c;。プロシージャの制御フローがより複雑で、例えば return ステートメントの後にラベルがあり、gotoプロシージャの別の場所に がある場合、 への代入まで実行可能なパスが存在する可能性がありますb。
さらに、値の使用状況を簡単に分析すると、の値はbに書き込まれるだけで、から読み取られることはないことがわかります。bは内部でローカル変数として宣言されているfooため、その値は外部では使用できませんfoo。したがって、変数は無効bであり、オプティマイザはその記憶領域を解放し、初期化を省略できます。
また、関数内で計算が行われる場合でも、その値は関数のスコープ外からアクセス可能な場所に格納されません。さらに、関数は静的な値(96)を返すため、その値に単純化することができます(この単純化は定数畳み込みと呼ばれます)。その結果、次のようになります。
int foo ( void ) {96を返す;}ほとんどの高度なコンパイラには、デッドコード除去を有効にするオプションがあり、そのレベルは様々です。低いレベルでは、実行できない命令のみを削除する場合があります。高いレベルでは、未使用変数用のメモリ領域を確保しない場合もあります。さらに高いレベルでは、役に立たない命令や関数を特定して削除する場合もあります。
デッドコード除去の一般的な用途は、プリプロセッサによるオプションのコードインクルードの代替手段として使用されることです。次のコードを考えてみましょう。
// 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: 非推奨のアーカイブサービス (リンク) (注: これは、事前にアセンブルまたはコンパイルされたソフトウェアに対する、バイトレベルのきめ細かな動的デッドコード除去の最初の既知の実装です。)