LLVM
LLVMハンドブック
[編集]はじめに
[編集]LLVMとは
[編集]LLVMは、コンパイラを開発するためのモジュール化されたフレームワークであり、再利用可能なコンパイラおよびツールチェーンコンポーネントのセットです。LLVMは、最適化、コード生成、リンカなど、コンパイルプロセスの多くの段階で使用されます。
LLVMの歴史と開発コミュニティ
[編集]LLVMは2000年代初頭にクリス・ラットナーによって設立されました。その後、Apple、Google、Facebookなどの主要企業がLLVMを採用し、開発を支援しています。LLVMプロジェクトはオープンソースであり、世界中の開発者が貢献しています。
かつてBSD系UNIX(FreeBSDやNetBSDなど)では、GCCやbinutilsがコンパイラツールチェインとして使用されていましたが、2000年代に相次いでLLVM/Clangに移行しました。
LLVMプロジェクトの全体構成
[編集]LLVMプロジェクトは、以下の多くのサブプロジェクトで構成されています。
- LLVMコアライブラリ
- Clangと周辺ツール
- compiler-rt
- Polly
- libFuzzer
- LLDB
- LLD (Linker)
- libc++
- OpenMP
- libclc
- libunwind
- MLIR
- BOLT
- Flang
- WebAssemblyサポート
- LLVM libc
各サブプロジェクトについては、後続の章で概要を説明し、詳細は専用のハンドブックを参照してください。
LLVMメインプロジェクト
[編集]LLVMコアライブラリ
[編集]LLVMコアライブラリは、コンパイラのフロントエンドからバックエンドまで、すべての段階で使用される基本的なライブラリです。
インストールとビルド
[編集]LLVMのインストールとビルドは、以下のコマンドで行います。
git clone --depth=1 -b llvmorg-18.1.6 https://github.com/llvm/llvm-project.git cd llvm-project/ cmake -S . -B build/ -DLLVM_ENABLE_PROJECTS="llvm" -DCMAKE_BUILD_TYPE=Release llvm cmake --build build/
基本的な使い方
[編集]LLVMは、様々なツール(clang
、opt
、llc
など)を提供しています。例えば、C言語のソースコードをコンパイルしてLLVM IRに変換するには、以下のようにします。
clang -S -emit-llvm hello.c -o hello.ll
中間表現(IR)
[編集]LLVM IRは、LLVMコンパイラフレームワークの中心であり、フロントエンドとバックエンドの間でコードを表現するための形式です。
最適化パス
[編集]LLVMは、多くの最適化パスを提供しており、これを使用してコードを最適化できます。最適化パスの例として、デッドコード除去やループ最適化があります。
進んだ使い方とカスタマイズ
[編集]LLVMは、高度にカスタマイズ可能であり、独自の最適化パスやコード生成器を追加することができます。
Clangと周辺ツール
[編集]Clangの概要
[編集]Clangは、C、C++、Objective-C、Objective-C++用のLLVMベースのフロントエンドです。高速でモジュール化されており、他のツールやIDEと容易に統合できます。
インストールとビルド
[編集]Clangのインストールとビルドは、LLVMのビルドと一緒に行われます。
cd llvm-project/ cmake -S . -B build/ -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" llvm cmake --build build/
基本的な使い方
[編集]Clangを使用してC++プログラムをコンパイルするには、以下のようにします。
clang++ hello.cpp -o hello
コンパイルオプションとフラグ
[編集]Clangは、多くのコンパイルオプションを提供しており、最適化レベルの指定や警告の制御が可能です。
clang++ -march=native -Oz -Weverything -std=c++23 -use-ld=lld hello.cpp -o hello
静的解析ツール
[編集]Clangには、静的解析ツールが組み込まれており、コードの品質を向上させるために使用できます。
進んだ使い方とカスタマイズ
[編集]Clangは、プラグインを通じて機能を拡張することができます。また、AST(抽象構文木)を直接操作することも可能です。
compiler-rt
[編集]compiler-rtの概要
[編集]compiler-rtは、LLVMとClangに依存するランタイムライブラリ群です。主にサニタイザやプロファイリングツールとして使用されます。
インストールとビルド
[編集]compiler-rtのインストールとビルドは、LLVMとClangのビルドと一緒に行われます。
cd llvm-project/ cmake -S . -B build/ -DLLVM_ENABLE_PROJECTS="clang;compiler-rt" llvm cmake --build build/
サニタイザ(AddressSanitizer, ThreadSanitizer, UndefinedBehaviorSanitizerなど)
[編集]compiler-rtには、様々なサニタイザが含まれており、メモリエラーやデータ競合などを検出することができます。
clang -fsanitize=address example.c -o example ./example
プロファイリングツール
[編集]compiler-rtには、プロファイリングツールも含まれており、パフォーマンスのボトルネックを特定するのに役立ちます。
進んだ使い方とカスタマイズ
[編集]compiler-rtの機能をカスタマイズすることで、特定のニーズに応じたエラー検出やプロファイリングが可能です。
Polly
[編集]Pollyの概要
[編集]Pollyは、LLVMのループ最適化ツールです。ループの並列化やタイル化を行うことで、プログラムの実行速度を向上させます。
インストールとビルド
[編集]Pollyのインストールとビルドは、LLVMのビルドと一緒に行われます。
cd llvm-project/ cmake -S . -B build/ -DLLVM_ENABLE_PROJECTS="clang;polly" llvm cmake --build build/
基本的な使い方
[編集]Pollyを使用してコードを最適化するには、clang
の-mllvm
および-polly
オプションを使用します。
clang -O3 -mllvm -polly example.c -o example
ループ最適化
[編集]Pollyは、ループの依存関係を解析し、並列化やタイル化を行います。これにより、プログラムの実行速度を大幅に向上させることができます。
進んだ使い方とカスタマイズ
[編集]Pollyの機能をカスタマイズすることで、特定のループ最適化手法を適用することが可能です。
libFuzzer
[編集]libFuzzerの概要
[編集]libFuzzerは、LLVMプロジェクトの一部であり、ライブラリ内のバグを検出するためのファジングツールです。入力をランダムに生成し、テスト対象の関数に与えて異常動作を引き起こすことで、バグを発見します。
インストールとビルド
[編集]libFuzzerのインストールとビルドは、LLVMのビルドと一緒に行われます。
cd llvm-project/ cmake -S . -B build/ -DLLVM_ENABLE_PROJECTS="clang;compiler-rt" llvm cmake --build build/
基本的な使い方
[編集]libFuzzerを使用するには、ファジング対象の関数を定義し、libFuzzerのAPIを使用してファズテストを実行します。
#include <stdint.h> #include <stddef.h> extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { // ファジング対象のコード return 0; }
コンパイルと実行は以下の通りです。
clang++ -fsanitize=fuzzer example.cpp -o example ./example
進んだ使い方とカスタマイズ
[編集]libFuzzerは、カスタムの入力生成器やターゲット関数のインストルメンテーションをサポートしており、特定のニーズに合わせてカスタマイズ可能です。
LLDB
[編集]LLDBの概要
[編集]LLDBは、LLVMプロジェクトのデバッガであり、高速でモジュール化されたデバッグツールです。C、C++、Objective-Cなどの言語をサポートしています。
インストールとビルド
[編集]LLDBのインストールとビルドは、LLVMのビルドと一緒に行われます。
cd llvm-project/ cmake -S . -B build/ -DLLVM_ENABLE_PROJECTS="clang;lldb" llvm cmake --build build/
基本的な使い方
[編集]LLDBを使用してプログラムをデバッグするには、以下のコマンドを使用します。
lldb ./example (lldb) target create "./example" (lldb) run
デバッグテクニック
[編集]LLDBは、ブレークポイント設定、ステップ実行、変数の検査など、多くのデバッグ機能を提供します。
(lldb) breakpoint set --name main (lldb) step (lldb) print variable_name
進んだ使い方とカスタマイズ
[編集]LLDBはスクリプトを使用してカスタマイズ可能であり、Pythonスクリプティングをサポートしています。
LLD (Linker)
[編集]LLDの概要
[編集]LLDは、LLVMプロジェクトのリンカであり、高速かつ柔軟性に富んだリンキングツールです。ELF、COFF、Mach-Oなど、様々なフォーマットをサポートしています。
インストールとビルド
[編集]LLDのインストールとビルドは、LLVMのビルドと一緒に行われます。
cd llvm-project/ cmake -S . -B build/ -DLLVM_ENABLE_PROJECTS="clang;lld" llvm cmake --build build/
基本的な使い方
[編集]LLDを使用してプログラムをリンキングするには、以下のコマンドを使用します。
clang++ -fuse-ld=lld example.o -o example
進んだ使い方とカスタマイズ
[編集]LLDは、多くのリンキングオプションを提供しており、特定のリンキングシナリオに応じてカスタマイズ可能です。
libc++
[編集]libc++の概要
[編集]libc++は、LLVMプロジェクトの一部である標準C++ライブラリです。最新のC++標準に準拠しており、高いパフォーマンスと互換性を提供します。
インストールとビルド
[編集]libc++のインストールとビルドは、LLVMのビルドと一緒に行われます。
cd llvm-project/ cmake -S . -B build/ -DLLVM_ENABLE_PROJECTS="libcxx;libcxxabi" llvm cmake --build build/
基本的な使い方
[編集]libc++を使用するには、コンパイル時に指定します。
clang++ -stdlib=libc++ example.cpp -o example
進んだ使い方とカスタマイズ
[編集]libc++は、高度にカスタマイズ可能であり、独自のアロケータやスレッド管理機能を実装することができます。
OpenMP
[編集]OpenMPの概要
[編集]OpenMPは、マルチプラットフォームの並列プログラミングAPIであり、C、C++、Fortranで使用されます。LLVMは、OpenMPのコンパイラサポートを提供しています。
インストールとビルド
[編集]OpenMPのインストールとビルドは、LLVMのビルドと一緒に行われます。
cd llvm-project/ cmake -S . -B build/ -DLLVM_ENABLE_PROJECTS="clang;openmp" llvm cmake --build build/
基本的な使い方
[編集]OpenMPを使用して並列プログラムを作成するには、以下のディレクティブを使用します。
#include <omp.h> auto main() -> int { #pragma omp parallel { // 並列化されたコード } return 0; }
コンパイルは以下の通りです。
clang++ -fopenmp example.cpp -o example
進んだ使い方とカスタマイズ
[編集]OpenMPの高度な機能には、タスク並列性、データ指向の並列性、およびネストされた並列性が含まれます。
libclc
[編集]libclcの概要
[編集]libclcは、オープンソースのOpenCL実装であり、LLVMバックエンドを使用してOpenCLカーネルをコンパイルします。
インストールとビルド
[編集]libclcのインストールとビルドは、以下の手順で行います。
git clone --depth=1 -b llvmorg-18.1.6 https://github.com/llvm/llvm-project.git cd llvm-project/ cmake -S . -B build/ -DLLVM_ENABLE_PROJECTS="libclc" llvm cmake --build build/
基本的な使い方
[編集]libclcを使用してOpenCLカーネルをコンパイルするには、Clangを使用します。
clang -x cl -cl-std=CL1.2 example.cl -o example.bc
進んだ使い方とカスタマイズ
[編集]libclcは、特定のデバイス向けのカスタムビルトイン関数を追加するなど、カスタマイズが可能です。
libunwind
[編集]libunwindの概要
[編集]libunwindは、スタックトレースを取得し、例外処理のためにコールスタックを巻き戻すためのライブラリです。
インストールとビルド
[編集]libunwindのインストールとビルドは、LLVMのビルドと一緒に行われます。
cd llvm-project/ cmake -S . -B build/ -DLLVM_ENABLE_PROJECTS="libunwind" llvm cmake --build build/
基本的な使い方
[編集]libunwindを使用してスタックトレースを取得するには、以下のコードを使用します。
#include <libunwind.h> auto printStackTrace() -> void { unw_cursor_t cursor; unw_context_t context; unw_getcontext(&context); unw_init_local(&cursor, &context); while (unw_step(&cursor) > 0) { unw_word_t offset, pc; unw_get_reg(&cursor, UNW_REG_IP, &pc); printf("0x%lx\n", pc); } }
進んだ使い方とカスタマイズ
[編集]libunwindは、特定のプラットフォームやアーキテクチャに応じてカスタマイズが可能です。
MLIR
[編集]MLIRの概要
[編集]MLIR(Multi-Level Intermediate Representation)は、LLVMプロジェクトの一部であり、ドメイン固有の中間表現を構築するためのフレームワークです。
インストールとビルド
[編集]MLIRのインストールとビルドは、LLVMのビルドと一緒に行われます。
cd llvm-project/ cmake -S . -B build/ -DLLVM_ENABLE_PROJECTS="mlir" llvm cmake --build build/
基本的な使い方
[編集]MLIRを使用して中間表現を操作するには、以下のコードを使用します。
#include "mlir/IR/MLIRContext.h" #include "mlir/IR/Module.h" auto main() -> int { mlir::MLIRContext context; auto module = mlir::ModuleOp::create(mlir::UnknownLoc::get(&context)); module.dump(); return 0; }
進んだ使い方とカスタマイズ
[編集]MLIRは、カスタムのディアレクトやオペレーションを定義することで、特定のドメインに適した中間表現を構築することが可能です。
BOLT
[編集]BOLTの概要
[編集]BOLT(Binary Optimization and Layout Tool)は、バイナリの最適化ツールであり、実行時プロファイリングデータを使用してバイナリのパフォーマンスを向上させます。
インストールとビルド
[編集]BOLTのインストールとビルドは、以下の手順で行います。
git clone --depth=1 -b llvmorg-18.1.6 https://github.com/facebookincubator/BOLT.git cd BOLT cmake -S . -B build/ .. llvm cmake --build build/
基本的な使い方
[編集]BOLTを使用してバイナリを最適化するには、以下のコマンドを使用します。
perf record -e cycles:u ./example llvm-bolt ./example -o example.bolt --data=perf.data
進んだ使い方とカスタマイズ
[編集]BOLTは、詳細なプロファイリングデータを収集し、特定のコードパスを最適化することで、さらにパフォーマンスを向上させることができます。
Flang
[編集]Flangの概要
[編集]Flangは、LLVMプロジェクトのFortranコンパイラフロントエンドです。FortranコードをLLVM IRに変換し、最適化およびコード生成を行います。
インストールとビルド
[編集]Flangのインストールとビルドは、LLVMのビルドと一緒に行われます。
cd llvm-project/ cmake -S . -B build/ -DLLVM_ENABLE_PROJECTS="flang" llvm cmake --build build/
基本的な使い方
[編集]Flangを使用してFortranプログラムをコンパイルするには、以下のコマンドを使用します。
flang hello.f90 -o hello
進んだ使い方とカスタマイズ
[編集]Flangは、特定の最適化パスやランタイムライブラリのカスタマイズをサポートしています。
WebAssemblyサポート
[編集]WebAssemblyの概要
[編集]WebAssembly(Wasm)は、バイナリ命令フォーマットであり、LLVMはWebAssembly向けのバックエンドを提供しています。
インストールとビルド
[編集]WebAssemblyのインストールとビルドは、LLVMのビルドと一緒に行われます。
cd llvm-project/ cmake -S . -B build/ -DLLVM_ENABLE_PROJECTS="clang;lld" -DLLVM_TARGETS_TO_BUILD="WebAssembly" llvm cmake --build build/
基本的な使い方
[編集]WebAssembly向けにコードをコンパイルするには、以下のコマンドを使用します。
clang --target=wasm32-unknown-unknown-wasm -O3 -o hello.wasm hello.c
進んだ使い方とカスタマイズ
[編集]WebAssemblyのバックエンドは、カスタムセクションや特定の最適化オプションをサポートしています。
LLVM libc
[編集]LLVM libcの概要
[編集]LLVM libcは、LLVMプロジェクトによって提供される標準Cライブラリです。高い移植性とパフォーマンスを目指しています。
インストールとビルド
[編集]LLVM libcのインストールとビルドは、以下の手順で行います。
cd llvm-project/ cmake -S . -B build/ -DLLVM_ENABLE_PROJECTS="libc" llvm cmake --build build/
基本的な使い方
[編集]LLVM libcを使用するには、コンパイル時に指定します。
clang --rtlib=libc hello.c -o hello
進んだ使い方とカスタマイズ
[編集]LLVM libcは、高度にカスタマイズ可能であり、独自の機能や最適化を追加することができます。