llvm-optimization について
LLVM の性能調整や最適化パスの開発に取り組む開発者向けのリファレンススキルです。スカラー、ループ、手続き間の手法に加え、デバッグと正当性検証を扱います。
主な機能
- 01スカラー・ループ最適化手法
- 02カスタムパスの開発
- 03最適化パイプラインの案内
- 04パスのデバッグと最適化リマーク
- 05LTO と Alive2 による検証
活用シーン
- 01LLVM 最適化タスクのパス選定
- 02カスタム LLVM IR 変換の開発
- 03最適化の実行状況とリマークの確認
- 04Alive2 による変換の正当性確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ gmh5225/ awesome-llvm-security --skill llvm-optimizationインストール後、Claude Code で/llvm-optimizationを入力して読み込まれたか確認します。
詳細
LLVM 最適化スキル
このスキルでは、LLVM の最適化基盤、パスの開発、パフォーマンス調整の手法を扱います。
最適化パイプラインの概要
パイプラインの段階
Source → Frontend → LLVM IR → Optimization Passes → CodeGen → Machine Code
↓
[Transform Passes]
[Analysis Passes]
最適化レベル
# No optimization
clang -O0 source.c
# Basic optimization (most optimizations enabled)
clang -O1 source.c
# Full optimization (aggressive inlining, vectorization)
clang -O2 source.c
# Maximum optimization (may increase code size)
clang -O3 source.c
# Size optimization
clang -Os source.c # Optimize for size
clang -Oz source.c # Aggressive size optimization
主要な最適化パス
スカラー最適化
- 定数伝播:既知の定数値で変数を置き換えます
- デッドコード除去(DCE):到達不能なコードや使用されていないコードを削除します
- 共通部分式除去(CSE):重複する計算を回避します
- 命令の結合:複数の命令をより単純な形式に統合します
- 集成体のスカラー置換(SROA):集成体の割り当てを分割します
ループ最適化
- ループ不変コード移動(LICM):不変な計算をループの外に移動します
- ループアンローリング:ループ本体を複製してオーバーヘッドを削減します
- ループベクトル化:スカラーループをベクトル演算に変換します
- ループ融合/分割:ループを統合または分割します
- 帰納変数の簡略化:ループカウンターを最適化します
プロシージャ間最適化
- インライン化:呼び出し箇所を関数本体に置き換えます
- 不要な引数の除去:使用されていない関数パラメーターを削除します
- プロシージャ間定数伝播:関数間で定数を伝播させます
- リンク時最適化(LTO):プログラム全体を最適化します
カスタム最適化パスの作成
新しいパスマネージャー(LLVM 13+)
#include "llvm/IR/PassManager.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
struct MyOptimizationPass : public llvm::PassInfoMixin<MyOptimizationPass> {
llvm::PreservedAnalyses run(llvm::Function &F,
llvm::FunctionAnalysisManager &FAM) {
bool Changed = false;
for (auto &BB : F) {
for (auto &I : BB) {
// Implement optimization logic
if (optimizeInstruction(I)) {
Changed = true;
}
}
}
if (Changed)
return llvm::PreservedAnalyses::none();
return llvm::PreservedAnalyses::all();
}
private:
bool optimizeInstruction(llvm::Instruction &I) {
// Example: Replace add x, 0 with x
if (auto *BinOp = llvm::dyn_cast<llvm::BinaryOperator>(&I)) {
if (BinOp->getOpcode() == llvm::Instruction::Add) {
if (auto *C = llvm::dyn_cast<llvm::ConstantInt>(BinOp->getOperand(1))) {
if (C->isZero()) {
I.replaceAllUsesWith(BinOp->getOperand(0));
return true;
}
}
}
}
return false;
}
};
// Plugin registration
extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo
llvmGetPassPluginInfo() {
return {LLVM_PLUGIN_API_VERSION, "MyOptPass", LLVM_VERSION_STRING,
[](llvm::PassBuilder &PB) {
PB.registerPipelineParsingCallback(
[](llvm::StringRef Name, llvm::FunctionPassManager &FPM,
llvm::ArrayRef<llvm::PassBuilder::PipelineElement>) {
if (Name == "my-opt") {
FPM.addPass(MyOptimizationPass());
return true;
}
return false;
});
}};
}
解析の依存関係
struct MyAnalysis : public llvm::AnalysisInfoMixin<MyAnalysis> {
using Result = MyAnalysisResult;
Result run(llvm::Function &F, llvm::FunctionAnalysisManager &FAM) {
// Compute analysis result
return Result();
}
static llvm::AnalysisKey Key;
};
// Using analysis in a pass
llvm::PreservedAnalyses run(llvm::Function &F,
llvm::FunctionAnalysisManager &FAM) {
auto &DT = FAM.getResult<llvm::DominatorTreeAnalysis>(F);
auto &LI = FAM.getResult<llvm::LoopAnalysis>(F);
auto &AA = FAM.getResult<llvm::AAManager>(F);
// Use analysis results...
}
命令パターン
強度削減
// Replace expensive operations with cheaper ones
// x * 2 → x << 1
// x / 4 → x >> 2
// x % 8 → x & 7
bool reduceStrength(llvm::BinaryOperator *BO) {
if (BO->getOpcode() == llvm::Instruction::Mul) {
if (auto *C = llvm::dyn_cast<llvm::ConstantInt>(BO->getOperand(1))) {
if (C->getValue().isPowerOf2()) {
unsigned Shift = C->getValue().exactLogBase2();
auto *Shl = llvm::BinaryOperator::CreateShl(
BO->getOperand(0),
llvm::ConstantInt::get(C->getType(), Shift));
BO->replaceAllUsesWith(Shl);
return true;
}
}
}
return false;
}
代数的簡略化
// x + 0 → x
// x * 1 → x
// x * 0 → 0
// x - x → 0
// x | x → x
// x & 0 → 0
ドミネーターツリーの使用
最適化の機会を見つける
void optimizeWithDominators(llvm::Function &F,
llvm::DominatorTree &DT) {
// Use dominance for safe code motion
for (auto &BB : F) {
for (auto &I : BB) {
if (auto *Load = llvm::dyn_cast<llvm::LoadInst>(&I)) {
// Check if we can hoist this load
if (canHoist(Load, DT)) {
hoistInstruction(Load, DT);
}
}
}
}
}
bool canHoist(llvm::Instruction *I, llvm::DominatorTree &DT) {
llvm::BasicBlock *DefBB = I->getParent();
// Check all uses are dominated
for (auto *U : I->users()) {
if (auto *UI = llvm::dyn_cast<llvm::Instruction>(U)) {
if (!DT.dominates(DefBB, UI->getParent())) {
return false;
}
}
}
return true;
}
ループ最適化の手法
ループ解析
void analyzeLoops(llvm::Function &F, llvm::LoopInfo &LI) {
for (auto *L : LI) {
// Get loop trip count
if (auto *TC = L->getTripCount()) {
llvm::errs() << "Trip count: " << *TC << "\n";
}
// Check if loop is simple
if (L->isLoopSimplifyForm()) {
llvm::BasicBlock *Header = L->getHeader();
llvm::BasicBlock *Latch = L->getLoopLatch();
llvm::BasicBlock *Exit = L->getExitBlock();
}
// Get induction variables
llvm::PHINode *IV = L->getCanonicalInductionVariable();
}
}
ループアンローリング
// Manually trigger loop unrolling
#pragma unroll 4
for (int i = 0; i < N; i++) {
// Loop body will be unrolled 4x
}
// LLVM unroll metadata
!llvm.loop.unroll.count = !{i32 4}
ベクトル化
自動ベクトル化のヒント
// Enable vectorization
#pragma clang loop vectorize(enable)
for (int i = 0; i < N; i++) {
a[i] = b[i] + c[i];
}
// Specify vector width
#pragma clang loop vectorize_width(8)
for (int i = 0; i < N; i++) {
a[i] = b[i] * c[i];
}
SLP ベクトル化
スーパーワードレベル並列性 — 直線コードをベクトル化します:
// Before SLP
a[0] = b[0] + c[0];
a[1] = b[1] + c[1];
a[2] = b[2] + c[2];
a[3] = b[3] + c[3];
// After SLP (conceptual)
<4 x float> tmp = load <4 x float> b
<4 x float> tmp2 = load <4 x float> c
<4 x float> result = fadd tmp, tmp2
store result to a
最適化のデバッグ
パスの実行を確認する
# Print passes being run
opt -debug-pass-manager input.ll -O2
# Print IR after each pass
opt -print-after-all input.ll -O2
# Print specific pass output
opt -print-after=instcombine input.ll -O2
# Statistics
opt -stats input.ll -O2
最適化に関する注記
# Enable all optimization remarks
clang -Rpass=.* source.c
# Specific remarks
clang -Rpass=loop-vectorize source.c
clang -Rpass-missed=inline source.c
clang -Rpass-analysis=loop-vectorize source.c
リンク時最適化(LTO)
LTO の有効化
# Full LTO
clang -flto source1.c source2.c -o program
# Thin LTO (faster, parallel)
clang -flto=thin source1.c source2.c -o program
LTO の利点
- プログラム全体のデッドコード除去
- プロシージャ間定数伝播
- モジュール間インライン化
- より優れた非仮想化
正しさの検証
Alive2
LLVM の最適化を自動検証します:
# Verify transformation correctness
alive-tv before.ll after.ll
# Check specific optimization
opt -instcombine input.ll | alive-tv input.ll -
リソース
特定のコミットや最適化関連プロジェクトについては、README.md の Optimization セクションを参照してください。
詳細情報の取得
詳細で最新のリソースリンク、ツール一覧、プロジェクトの参照情報が必要な場合は、以下から最新データを取得してください:
https://raw.githubusercontent.com/gmh5225/awesome-llvm-security/refs/heads/main/README.md
この README には、以下の厳選リストがまとめられています:
- LLVM の最適化コミットとパッチ(Optimization セクション)
- Alive2 と検証ツール
- 最適化の講義とチュートリアル(CSCD70)
コメント
Markdown 対応