中間表現(Intermediate Representation: IR)とは
中間表現(IR)とは、
コンピュータがデータをプラットフォームを跨いで扱うため、あるいはその他様々な目的で使用される
データ構造の表現です。中間表現を用いることで、データの抽象化が可能となり、異なるフォーマット間の変換処理を効率化できます。これは、コンピューティング分野では一般的な手法となっています。
中間表現の形態
中間表現はテキストデータやバイナリデータなど、様々な
データ構造を取りえます。例えば、
Java[[バイトコード]]はバイト指向の中間表現の一例です。内部的にはポインタなどで効率的な表現が可能ですが、外部ファイルへの書き出し時には永続化が必要です。
プログラミング言語などの
形式言語を扱うプログラムでは、
ソースコードを
字句解析器でトークンに分割し、
構文解析器で
構文木を構築します。この
構文木を抽象化したものが
抽象[[構文木]]であり、中間表現として利用されます。
抽象[[構文木]]はプラットフォームに依存しない形式でデータを表現し、命令セットを持つデータは中間表現で抽象化した上で、各プラットフォームの命令セットと関連付けられます。
中間言語
中間表現が言語(
形式言語)の形態を持つ場合、特に「中間言語」と呼ばれます。ここでは、主に
プログラミング言語に関連する場合について解説します。
コンパイラや
インタプリタでは、
ソースコードを直接
機械語に変換したり、直接解釈実行するのではなく、中間言語を経由することがあります。中間表現は1段階だけでなく、複数段階にわたることもあります。
中間言語の歴史
1970年代頃までは単一言語・単一ターゲットが主流でしたが、1958年にはUNCOLという概念が提案されました。1980年代には、GNU Compiler Collection(GCC)のように、中間表現を用いることで複数言語やターゲットに対応する
コンパイラが登場しました。GCCでは、Register Transfer Language(RTL)という非依存な内部形式が使われています。
中間言語の発展
2000年頃からは、GPLでないライセンスで利用可能な
コンパイラ基盤のニーズが高まり、「COINS
コンパイラ・インフラストラクチャ」や
LLVMなどが開発されました。
LLVMは、異なる
プログラミング言語の
ソースコードを単一の中間言語に変換し、異なるターゲットコードに変換できる点が特徴です。clang、rustc、Emscriptenなどの「
コンパイラ基盤」として活用されています。
初期のBASIC処理系
初期のBASIC処理系では、
字句解析のみを行い、各ステートメントを直接コードに変換する方式も存在しました。また、高度な中間言語を利用する実装もありました。
仮想マシンとJITコンパイル
いくつかの仮想マシンや
インタプリタは、中間言語を直接実行しますが、実行時コンパイル(JITコンパイル)により、中間言語から実行環境に応じた
機械語を生成する方が高速です。
GPU上で動作する
シェーダープログラムやコンピュートカーネルも、移植性の高い中間表現が利用されています。DirectXでは、DXBC(DirectX Bytecode)やDXILといった中間表現が利用され、OpenGLではSPIR/SPIR-Vが標準化されています。これらの標準化により、オフラインコンパイルが可能になり、フロントエンドの言語選択の自由度が増しました。
CUDAもPTXという中間表現を利用可能です。
その他の事例
C言語などの下位水準言語を、上位水準言語のコンパイル先として利用することがあります。この場合、
C言語はある種の中間言語として機能すると言えます。また、
TypeScriptも
JavaScriptコードを出力するトランス
コンパイラとして同様の役割を果たします。
Unix環境では、多くの場合、
アセンブリ言語が中間言語として利用され、アセンブラが
オブジェクトファイルを生成します。
コンパイラドライバの出力ファイル名がa.outになる慣習は、アセンブラからの出力の名残です。
まとめ
中間表現は、ソフトウェア開発において不可欠な概念であり、異なるプラットフォーム間でのデータのやり取りや、
コンパイラ、
インタプリタなどの様々な場所で活用されています。中間表現の理解は、ソフトウェアの仕組みを深く理解する上で重要な要素となります。
関連項目
LLVMアセンブリ(LLVM IR)
CIL -
.NET環境における中間言語
C--
WebAssembly
Java[[バイトコード]]
PASCAL P-Code