LLVM

LLVMとは、コンパイル時、リンク時、実行時などあらゆる時点でプログラムを最適化するよう設計された、任意のプログラミング言語に対応可能なコンパイラ基盤である。当初は、LLVMの名称の由来は、Low Level Virtual Machine  の略であるとしていたが、現在は、何の頭文字でもないとしている。

1. 概要
-----

LLVMは、JavaとJava VMの関係のように、まず仮想機械をターゲットとした中間コードを生成し、その仮想機械向けコードを特定のマシンの機械語に変換する。この時言語やプラットフォームとは独立した最適化を行う。この方法によってLLVMは言語からもアーキテクチャからも独立しており、それぞれに特化した、プログラミング言語固有のモジュールと、マシン向けコード生成部を用意することにより様々な言語アーキテクチャーに対応する。LLVMは積極的にプロシージャ間最適化を行うとともに、静的コンパイラとしてもJITコンパイラとしても使え、開発の様々な段階で使える多数の部品を持っている。JITコンパイラの場合、実行時に不要な静的分岐を最適化する機能があり、これはプログラムが様々な実行時オプションを持っている場合、強力な最適化手法となる。このため、Mac OS X v10.5ではこれを使ってハードウェア機能がない場合にOpenGLパイプラインを実現している。

LLVM自体はC++で書かれており、イリノイ大学でVikram AdveとChris Lattnerにより2000年に開発が開始されたものである。ライセンス条件はイリノイ大学/NCSAオープンソースライセンスであり、これはBSDライセンスによく似たOSI認証ライセンスである。バージョン9.0.0からはライセンスがLLVM例外付きApache License 2.0に変更された。

2. LLVM IR及びビットコード
------------------

LLVMは言語から独立した命令セットと型システムを持つ。命令の多くは3番地コード形式に似ている。各命令はまた静的単一代入形でもあり、変数は一回代入されるとその後は変更されない。このため、変数間の依存関係の解析が単純化される。

型変換は、どういう形式であっても明示的に cast 命令を使って行われる。LLVMの持つ基本型はいくつかの固定長の整数型であり、派生型としてポインタ、配列、ベクトル、構造体、関数の5つがある。具体的な言語で構築される型は、LLVM上ではこれらの型を組み合わせて表現される。例えば、C++におけるクラスは、構造体と関数と関数へのポインタの配列を組み合わせて表現される。

2.1. MLIR
---------

MLIR  は特定用途に向けて LLVM IR を拡張するための方言を作る試みである。MLIRではLLVM IR自体も「llvm」方言となっている。また一部のアーキテクチャ固有のSIMD/Single instruction, multiple threads命令も方言となっており、これには例えばx86アーキテクチャのための「x86vector」方言や「amx」方言、ARMアーキテクチャのための「arm_neon」方言や「arm_sve」方言、NVIDIA GPUアーキテクチャ  のための「nvvm」方言、AMD GPUアーキテクチャのための「rocdl」方言などが存在する。

その他のMLIRの方言には例えばOpenMPのための「omp」方言、OpenACCのための「acc」方言、CUDAやOpenCLなどのための「gpu」方言、VulkanやOpenCLに使われる中間言語Standard Portable Intermediate RepresentationのためのSPIR-V方言が存在する。

また高度なベクトル/行列操作などの機械学習のために使われる様々な方言も存在する。外部定義の方言も存在し、そのうちの一つ、GoogleのTensorFlowプロジェクトによるMHLO方言[1]はTensorFlowだけでなくGoogle JAXやTorch-MLIRなど広く使われるようになった。その後、Googleは他のビッグ・テック企業と共にOpenXLAプロジェクトを立ち上げ、そのOpenXLAはTensorFlowから独立したものとしてStableHLO方言の開発を開始した。

また、PyTorch 2.0のTorchDynamoの標準バックエンド「TorchInductor」で使われてるOpenAI Tritonは2.0でバックエンドをMLIRへと移行し、そこで独自のTriton方言およびTritonGPU方言を使用している。

3. フロントエンド
----------

3.1. dragonegg
--------------

LLVMは、もともと既存のGCCスタック用のものより積極的な最適化を行う高性能のシステムとして開発され、GCCフロントエンドがLLVMと動作するように修正された。現在では、GCC 4.6から派生したフロントエンドを用いてC言語、C++、FORTRAN、Adaをサポートし、Objective-C、Objective-C++、Goがおおむね動くとしている。

3.2. Clang
----------

しかし、LLVMへの興味が広がるにつれ、まったく新しいフロントエンドを多数のプログラミング言語向けに開発しようという動きが出てきた。もっとも注目されているのはC、C++、Objective-C、Objective-C++をサポートする新しいコンパイラClangである。主にAppleのサポートを受け、ClangはGCCシステムのC/C++/Objective-C/Objective-C++コンパイラを統合開発環境と統合できマルチスレッドをサポートした現代的なシステムで置き換えることを目指している。GCCでのObjective-C/Objective-C++の開発は衰退気味で、アップルが施した変更は別個にメンテナンスされている。アップルにとっては、自社でコンパイラを開発することにより、第一のObjective-C/Objective-C++実装であり続けながら、LLVMがすでに達成している統合開発環境への統合やその他の現代的な機能への対応といった問題を解決することができる。

3.3. Flang
----------

Flangは LLVM Project の FORTRAN コンパイラである。旧来の Flang は NVIDIA の nvfortranの派生であったが、f18プロジェクトとして開発された次世代 Flang は C++17 や MLIR などの新しい技術を採用している。

3.4. Torch-MLIR
---------------

Torch-MLIR は機械学習に使われる PyTorch 向けのコンパイラとなっている。元々はnpcompであり、NumPyのコンパイラであった。

3.5. Polygeist
--------------

Polygeistは旧来の LLVM IR の代わりに MLIR を用いた実験的なC/C++コンパイラである。MLIR を用いることによって多面体最適化が可能となっている。C/C++からCUDAへのコンパイルも可能となっている。

4. 標準C++ライブラリ
-------------

GNUはlibstdc++という標準C++ライブラリを開発しているが、LLVMも独自のlibc++という標準C++ライブラリを開発している。

5. 参照
-----

6. 関連項目
-------

Clang
C--
Swift
OpenCL
Julia

7. 外部リンク
--------

[2] — by Chris Lattner and Vikram Adve.
[3] — LLVMの中間表現の解説
[4] — LLVMをGCCに導入することについての議論