ZOMI ちゃんに感謝します:https://space.bilibili.com/517221395
コンパイラの基本概念#
- コンパイラとは何ですか?
- なぜ AI フレームワークはコンパイラを導入する必要があるのですか?
- AI フレームワークと AI コンパイラの関係は何ですか?
コンパイラとインタプリタ#
コンパイラ(Compiler)とインタプリタ(Interpreter)の最大の違いは:インタプリタはプログラム実行時にコードを機械語に変換し、コンパイラはプログラム実行前にコードを機械語に変換します。
JIT と AOT コンパイル方式#
現在、プログラムには主に 2 つの実行方式があります:静的コンパイルと動的解釈。
- 静的コンパイルのコードプログラムは実行前にすべて機械語に翻訳されます。通常、このタイプは AOT(Ahead of time)と呼ばれ、「事前コンパイル」となります;
- 動的解釈のプログラムはコードプログラムを翻訳しながら実行します。通常、このタイプは JIT(Just in time)と呼ばれ、「即時コンパイル」となります。
AOT プログラムの典型的な代表は C/C++ で開発されたアプリケーションで、実行前に機械語にコンパイルする必要があり、その後オペレーティングシステムに具体的に実行されます;
一方、JIT の代表は JavaScript、Python などの動的解釈プログラムが多数あります。
特徴 | JIT (即時コンパイル) | AOT (事前コンパイル) |
---|---|---|
利点 | 1. 現在のハードウェア状況に基づいてリアルタイムで最適な機械命令を生成 2. 現在のプログラムの実行状況に基づいて最適な機械命令列を生成 3. プログラムが動的リンクをサポートする必要がある場合、JIT コンパイル方式のみを使用できます 4. プロセス内のメモリの実際の状況に基づいてコードを調整し、メモリをより十分に利用できるようにします | 1. プログラム実行前にコンパイルすることで、実行時のコンパイル性能消耗とメモリ消耗を回避 2. プログラムの初期段階で最高の性能を達成 3. プログラムの実行効率を大幅に向上させる |
欠点 | 1. コンパイルには実行時のリソースを占有し、プロセス実行時にカクつくことがあります 2. コンパイルは実行時間を占有し、一部のコードのコンパイル最適化を完全にサポートできず、スムーズさと時間のトレードオフが必要です 3. コンパイル準備と頻繁に使用されるメソッドの識別には時間がかかり、初期コンパイルでは最高の性能に達しません | 1. プログラム実行前のコンパイルにより、プログラムのインストール時間が増加します 2. 事前コンパイルされた内容を保存すると、より多くのメモリを占有します 3. 高級言語の一貫性の問題を犠牲にします |
AI フレームワークにおける違い#
現在の主流の AI フレームワークは、フロントエンドの表現層を持ち、AI コンパイラがハードウェアを有効にするため、AI フレームワークと AI コンパイラの関係は非常に密接です。MindSpore、TensorFlow などの AI フレームワークの一部には、デフォルトで独自の AI コンパイラが含まれています。現在、PyTorch2.X バージョンのアップグレード後、Inductor 機能特性がデフォルトで搭載され、複数の異なる AI コンパイラと接続できます。
コンパイル方式 | 説明 | 典型的な代表 |
---|---|---|
AOT (事前コンパイル) | 静的コンパイルのコードプログラムは実行前にすべて機械語に翻訳され、モバイルや組み込み深層学習アプリケーションに適しています。 | 1. 推論エンジン:トレーニング後の AI モデルが事前に固化され、推論デプロイに使用されます。 2. 静的グラフ生成:神経ネットワークモデルは統一された IR 記述として表現され、実行時にコンパイルされた内容が実行されます。 |
JIT (即時コンパイル) | 動的解釈のプログラムは翻訳しながら実行され、リアルタイム最適化が必要なシーンに適しています。 | 1. PyTorch JIT:Python コードをリアルタイムでネイティブ機械コードにコンパイルし、深層学習モデルを最適化および加速します。 2. Jittor:動的コンパイル JIT に基づき、メタオペレーターと統一計算グラフを使用した深層学習フレームワークで、高効率な操作と自動最適化を実現します。 |
Pass と中間表現 IR#
Pass は主にソースプログラム言語の完全なスキャンまたは処理を行います。コンパイラにおいて、Pass はコンパイル対象(IR)の分析、最適化、変換などの機能を完了するために採用される構造化技術を指します。Pass の実行は、コンパイラがコンパイルユニットを分析し最適化するプロセスであり、Pass はこれらのプロセスに必要な分析結果を構築します。
コンパイラ LLVM で提供される Pass は 3 つのカテゴリに分かれています:Analysis pass、Transform pass、Utility pass。
Pass タイプ | 説明 | 機能 | 一般的な例 |
---|---|---|---|
Analysis Pass | 関連する IR ユニットの高レベル情報を計算しますが、変更は行いません。これらの情報は他の Pass で使用されるか、デバッグやプログラムの可視化に使用されます。 | 1. IR ユニットから情報を掘り出し、保存します 2. 他の Pass がアクセスできるクエリインターフェースを提供します 3. 情報の無効化を処理するための invalidate インターフェースを提供します | Basic Alias Analysis、Scalar Evolution Analysis |
Transform Pass | Analysis Pass の分析結果を使用して、IR を変更および最適化します。 | 1. IR 内の命令と制御フローを変更します 2. 関数呼び出しを減らし、より多くの最適化機会を露出する可能性があります | Inline Pass |
Utility Pass | 機能的なユーティリティプログラムで、Analysis Pass または Transform Pass には属しません。 | 1. 特定のタスクを実行します。例えば、basic block の抽出 | extract-blocks Pass |
IR(Intermediate Representation)中間表現は、コンパイラにおいて非常に重要なデータ構造です。コンパイラはフロントエンドの作業を完了した後、まず独自の IR を生成し、その基礎の上でさまざまな最適化アルゴリズムを実行し、最終的にターゲットコードを生成します。
図に示すように、コンパイラの原理では、通常、コンパイラはフロントエンドとバックエンドに分かれています。フロントエンドは入力されたプログラムに対して字句解析、構文解析、意味解析を行い、中間表現 IR を生成します。バックエンドは IR を最適化し、ターゲットコードを生成します。
例えば:LLVM はフロントエンドとバックエンドを分離し、中間層で抽象的な言語を明確に定義します。この言語は IR と呼ばれます。IR を定義した後、フロントエンドのタスクは最終的に IR を生成することになり、最適化器は生成された IR を最適化し、バックエンドのタスクは IR をターゲットプラットフォームの言語に変換することです。LLVM の IR は LLVM アセンブリ言語または LLVM 言語を使用して LLVM IR の型システムを実現し、これは LLVM アセンブリ言語の型システムを指します。
したがって、コンパイラのフロントエンド、最適化器、バックエンドの間で唯一交換されるデータ構造のタイプは IR であり、IR を通じて異なるモジュールのデカップリングを実現します。一部の IR には特別な名前が付けられることもあります。例えば、Open64 の IR は通常 WHIRL IR と呼ばれ、Ark コンパイラの IR は MAPLE IR と呼ばれ、LLVM は通常 LLVM IR と呼ばれます。
IR は通常、2 つの用途があります。1)分析と変換に使用されるもの、2)直接解釈実行に使用されるもの。
コンパイラ内で、IR に基づく分析と処理の作業は、初期段階では比較的高い抽象レベルの意味に基づいて行われ、この時点で必要な IR はソースコードにより近いです。一方、コンパイラの後期段階では、低レベルで、ターゲットコードにより近い意味が使用されます。上述の高から低への抽象レベルに基づき、IR は 3 つのレベルに分類できます:高レベル HIR、中間レベル MIR、低レベル LIR。
IR タイプ | 説明 | 用途 | 特徴 |
---|---|---|---|
HIR (High IR) | ソースプログラム言語に基づくコードの分析と変換。 | IDE、コード翻訳ツール、コード生成ツールなどに使用され、高レベルのコード最適化(例えば、定数折りたたみ、インライン関連)を実行します。 | 1. ソースプログラム言語の意味を正確に表現 2. AST とシンボルテーブルを使用できます |
MIR (Middle IR) | ソースプログラム言語とハードウェアアーキテクチャに依存しないコード分析と最適化。 | コンパイル最適化アルゴリズムに使用され、一般的な最適化(例えば、算術最適化、定数と変数の伝播、死コード削除)を実行します。 | 1. ソースプログラムコードとターゲットプログラムコードに依存しない 2. 通常、三地址コード(TAC)に基づいています |
LIR (Low IR) | 具体的なハードウェアアーキテクチャに依存して最適化とコード生成を行います。 | 具体的なハードウェアアーキテクチャに関連する最適化を実行し、機械命令またはアセンブリコードを生成します。 | 1. 命令は通常、機械命令と一対一で対応します 2. 具体的なハードウェアアーキテクチャの低レベルの特徴を反映しています |
三地址コード TAC の特徴:最大で 3 つのアドレス(すなわち変数)があり、代入記号の左側は書き込み用、右側には最大で 2 つのアドレスと 1 つの演算子があり、データを読み取り計算するために使用されます。
多層 IR は単層 IR と比較して、明らかな利点があります:
- より多くのソースプログラム言語の情報を提供できます
- IR の表現がより柔軟で、最適化が容易です
- 最適化アルゴリズムと最適化 Pass の実行がより効率的になります
LLVM コンパイラでは、抽象レベルに基づいて高から低へと、フロントエンドとバックエンドを分離した三段構造を採用しています。これにより、コンパイラに新しい言語サポートや新しいターゲットプラットフォームサポートを追加する際に非常に便利で、プロジェクトのコストを大幅に削減できます。また、LLVM IR はこのフロントエンドとバックエンドを分離した三段構造の中で、主に 3 層の IR に分かれており、IR はコンパイラ全体で重要な役割を果たしています。開発者がプログラムコードを理解しやすくすることから、ハードウェアマシンが理解しやすくすることまで。
まとめ#
- インタプリタはコンピュータプログラムであり、各高級プログラム文を機械コードに変換します
- コンパイラは高級言語プログラムを機械語に変換し、人間が読めるコードをコンピュータが読めるコードに変換します
- Pass は主にソースプログラム言語の完全なスキャンまたは処理を行います
- 中間表現 IR はコンパイラ内のデータ構造であり、コンパイラ内の各レベルとモジュールをつなぐ役割を果たします
02 伝統的なコンパイラの発展#
コンパイラとプログラミング言語はほぼ同時に発展してきました。その発展過程は数段階に分けられます:
- 第一段階:1950 年代、最初のコンパイラプログラムが登場し、算術式を機械コードに翻訳し、高級言語の発展の基礎を築きました。
- 第二段階:1960 年代、Fortran、COBOL、LISP、ALGOL などの多くの高級言語とそれに対応するコンパイラが登場し、コンパイル技術も次第に成熟し、標準化されました。
- 第三段階:1970 年代、構造化プログラム設計方法とモジュール化プログラミング思想、オブジェクト指向言語とコンパイラ(Pascal、C、Simula など)が登場し、コンパイル技術はエンジニアリングコードの可読性と保守性に注目し始めました。
- 第四段階は 1980 年代、並列コンピュータと分散システムが登場し、並列および分散をサポートする言語とコンパイラ(Ada、Prolog、ML など)が登場し、コンパイル技術はプログラムの並列性と分散能力を考慮し始めました。
- 第五段階:1990 年代、インターネットやモバイルデバイスなどの新興プラットフォームが登場し、クロスプラットフォームと動的特性をサポートする言語とコンパイラ(Java、C#、Python など)が登場し、コンパイル技術はプログラムの安全性と効率に注目し始めました。
- 第六段階:21 世紀の最初の 10 年間、Lua を先頭にした Torch フレームワークが登場し、爆発的に増加する AI アプリケーションと AI アルゴリズム研究を解決するために使用され、その後 TensorFlow、PyTorch、MindSpore、Paddle などの AI フレームワークが登場しました。AI フレームワークと AI 産業の発展に伴い、AKG、MLIR などの AI コンパイラが登場しました。
伝統的なコンパイラの争い#
現在の主流の LLVM や GCC などの古典的なオープンソースコンパイラは、通常 3 つの部分に分かれています:フロントエンド(frontEnd)、最適化器(Optimizer)、バックエンド(backEnd)。
- フロントエンド:主に字句解析と構文解析を担当し、ソースコードを抽象構文木に変換します。つまり、プログラムを基本的な構成要素に分割し、コードの構文、意味、文法をチェックし、中間コードを生成します。
- 最適化器:最適化器はフロントエンドの基礎の上に、得られた中間コードを最適化(冗長コードの削除、部分式の消去など)し、コードをより効率的にします。
- バックエンド:バックエンドは、すでに最適化された中間コードを具体的なハードウェアに基づいてターゲットコードに生成し、コード最適化器とコード生成器を含むように変換します。
タイプ | GCC | Clang/LLVM |
---|---|---|
ライセンス | GNU GPL | Apache 2.0 |
コードモジュール化 | 統合アーキテクチャ | モジュール化 |
サポートプラットフォーム | Unix, Windows, MAC | Unix, MAC |
コード生成 | 効率的で、多くのコンパイラオプションが使用可能 | 効率的で、LLVM バックエンドは SSA 形式を使用 |
言語独立型システム | なし | あり |
ビルドツール | Make Base | CMake |
パーサー | 最初は Bison LR を使用し、現在は再帰下降パーサーに変更 | 手書きの再帰下降パーサー |
リンカー | LD | lld |
デバッガー | GDB | LLDB |
まとめ#
- コンパイル技術はコンピュータ科学の宝石であり、基盤ソフトウェアの核心技術です
- コンパイラは高級言語プログラムコード内の語彙、文、およびさまざまな特定の形式とデータ構造を認識できます
- コンパイルプロセスは、ソースコードプログラムを機械が認識できるバイナリコードに変換することです
- 伝統的なコンパイラは通常 3 つの部分に分かれています:フロントエンド(frontEnd)、最適化器(Optimizer)、バックエンド(backEnd)