2025-09-02 05:11:10 +09:00
|
|
|
|
# Phase 12.5: 実装例集
|
|
|
|
|
|
|
|
|
|
|
|
## 1. MIRMetadataの具体例
|
|
|
|
|
|
|
|
|
|
|
|
### StringBox.lengthのヒント付与
|
|
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
|
// Before(ヒントなし)
|
|
|
|
|
|
BoxCall {
|
|
|
|
|
|
target: ValueId(0),
|
|
|
|
|
|
method: "length",
|
|
|
|
|
|
args: vec![],
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// After(ヒント付き)
|
|
|
|
|
|
BoxCall {
|
|
|
|
|
|
target: ValueId(0),
|
|
|
|
|
|
method: "length",
|
|
|
|
|
|
args: vec![],
|
|
|
|
|
|
metadata: MIRMetadata {
|
|
|
|
|
|
pure: true, // 同じ文字列→同じ長さ
|
|
|
|
|
|
readonly: true, // 文字列を変更しない
|
|
|
|
|
|
nothrow: true, // 例外を投げない
|
|
|
|
|
|
noalias: true, // 結果は新しい整数
|
|
|
|
|
|
..Default::default()
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### ループの最適化ヒント
|
|
|
|
|
|
|
|
|
|
|
|
```nyash
|
|
|
|
|
|
// Nyashコード
|
|
|
|
|
|
for i in 0..1000 {
|
|
|
|
|
|
array.push(i * 2)
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
|
// MIRでのヒント
|
|
|
|
|
|
Branch {
|
|
|
|
|
|
cond: ValueId(5), // i < 1000
|
|
|
|
|
|
then_block: BlockId(2),
|
|
|
|
|
|
else_block: BlockId(3),
|
|
|
|
|
|
metadata: MIRMetadata {
|
|
|
|
|
|
likely: Some(true), // ループ継続が高確率
|
|
|
|
|
|
loop_count: Some(1000), // ループ回数ヒント
|
|
|
|
|
|
..Default::default()
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 2. Cエミッタでの変換例
|
|
|
|
|
|
|
|
|
|
|
|
### 純粋関数の最適化
|
|
|
|
|
|
|
|
|
|
|
|
```c
|
|
|
|
|
|
// MIR: BoxCall(StringBox, "length") with {pure: true}
|
|
|
|
|
|
// ↓
|
|
|
|
|
|
// C出力:
|
|
|
|
|
|
static inline int64_t __attribute__((pure))
|
|
|
|
|
|
ny_string_length(NyashHandle h) {
|
|
|
|
|
|
NyashString* s = ny_handle_to_string(h);
|
|
|
|
|
|
return s->length;
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 分岐予測の最適化
|
|
|
|
|
|
|
|
|
|
|
|
```c
|
|
|
|
|
|
// MIR: Branch with {likely: Some(false)}
|
|
|
|
|
|
// ↓
|
|
|
|
|
|
// C出力:
|
|
|
|
|
|
if (__builtin_expect(!!(error_condition), 0)) {
|
|
|
|
|
|
// エラー処理(めったに実行されない)
|
|
|
|
|
|
ny_handle_error();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 通常処理(ほぼ常に実行)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 3. 最適化パスの実装例
|
|
|
|
|
|
|
|
|
|
|
|
### 定数畳み込み(ConstFoldingPass)
|
|
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
|
impl OptPass for ConstFoldingPass {
|
|
|
|
|
|
fn run(&self, mir: &mut MIR) -> bool {
|
|
|
|
|
|
let mut changed = false;
|
|
|
|
|
|
|
|
|
|
|
|
for block in &mut mir.blocks {
|
|
|
|
|
|
for inst in &mut block.instructions {
|
|
|
|
|
|
match inst {
|
|
|
|
|
|
// Const(3) + Const(5) → Const(8)
|
|
|
|
|
|
BinOp { op: Add, left, right, result } => {
|
|
|
|
|
|
if let (Some(a), Some(b)) = (
|
|
|
|
|
|
self.get_const_value(*left),
|
|
|
|
|
|
self.get_const_value(*right)
|
|
|
|
|
|
) {
|
|
|
|
|
|
*inst = Const {
|
|
|
|
|
|
value: Value::Integer(a + b),
|
|
|
|
|
|
result: *result
|
|
|
|
|
|
};
|
|
|
|
|
|
changed = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
_ => {}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
changed
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### デッドコード除去(DeadCodeElimPass)
|
|
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
|
impl OptPass for DeadCodeElimPass {
|
|
|
|
|
|
fn run(&self, mir: &mut MIR) -> bool {
|
|
|
|
|
|
// 1. 使用されている値を収集
|
|
|
|
|
|
let used = self.collect_used_values(mir);
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 未使用の命令を削除
|
|
|
|
|
|
let mut changed = false;
|
|
|
|
|
|
for block in &mut mir.blocks {
|
|
|
|
|
|
block.instructions.retain(|inst| {
|
|
|
|
|
|
if let Some(result) = inst.get_result() {
|
|
|
|
|
|
if !used.contains(&result) && !inst.has_side_effects() {
|
|
|
|
|
|
changed = true;
|
|
|
|
|
|
return false; // 削除
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
true
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
changed
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 4. バックエンド別の出力例
|
|
|
|
|
|
|
|
|
|
|
|
### zig cc向け(Ubuntu/macOS)
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# MIRからCへ変換
|
2025-11-06 15:41:52 +09:00
|
|
|
|
nyash --emit-c program.hako -o program.c
|
2025-09-02 05:11:10 +09:00
|
|
|
|
|
|
|
|
|
|
# 最適化コンパイル
|
|
|
|
|
|
zig cc -O3 -flto -march=native \
|
|
|
|
|
|
-fno-plt \
|
|
|
|
|
|
-fomit-frame-pointer \
|
|
|
|
|
|
program.c nyrt.c \
|
|
|
|
|
|
-o program
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### MSVC向け(Windows)
|
|
|
|
|
|
|
|
|
|
|
|
```batch
|
|
|
|
|
|
REM リンク時最適化を有効化
|
|
|
|
|
|
cl /O2 /GL /MD program.c nyrt.c /Fe:program.exe ^
|
|
|
|
|
|
/link /LTCG /OPT:REF /OPT:ICF
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### プロファイルガイド最適化(PGO)
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# Step 1: プロファイル収集
|
|
|
|
|
|
zig cc -O3 -fprofile-generate program.c -o program_prof
|
|
|
|
|
|
./program_prof < typical_input.txt
|
|
|
|
|
|
|
|
|
|
|
|
# Step 2: プロファイルを使用して再コンパイル
|
|
|
|
|
|
zig cc -O3 -fprofile-use program.c -o program_opt
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 5. 性能測定の例
|
|
|
|
|
|
|
|
|
|
|
|
```nyash
|
2025-11-06 15:41:52 +09:00
|
|
|
|
// benchmark.hako
|
2025-09-02 05:11:10 +09:00
|
|
|
|
static box Benchmark {
|
|
|
|
|
|
main() {
|
|
|
|
|
|
local start, end, result
|
|
|
|
|
|
|
|
|
|
|
|
// ウォームアップ
|
|
|
|
|
|
me.fibonacci(20)
|
|
|
|
|
|
|
|
|
|
|
|
// 測定開始
|
|
|
|
|
|
start = Time.now()
|
|
|
|
|
|
result = me.fibonacci(40)
|
|
|
|
|
|
end = Time.now()
|
|
|
|
|
|
|
|
|
|
|
|
print("Fibonacci(40) = " + result)
|
|
|
|
|
|
print("Time: " + (end - start) + "ms")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@[pure, nothrow] // 最適化ヒント
|
|
|
|
|
|
fibonacci(n) {
|
|
|
|
|
|
if n <= 1 {
|
|
|
|
|
|
return n
|
|
|
|
|
|
}
|
|
|
|
|
|
return me.fibonacci(n - 1) + me.fibonacci(n - 2)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 6. 最適化レベルごとの比較
|
|
|
|
|
|
|
|
|
|
|
|
| レベル | MIR最適化 | Cコンパイラ | 想定性能 | 用途 |
|
|
|
|
|
|
|--------|-----------|-------------|----------|------|
|
|
|
|
|
|
| 0 | なし | -O0 | 10% | デバッグ |
|
|
|
|
|
|
| 1 | 基本 | -O2 | 50% | 開発 |
|
|
|
|
|
|
| 2 | 全て | -O3 -flto | 70% | リリース |
|
|
|
|
|
|
| 3 | 全て+PGO | -O3 -flto -fprofile-use | 85% | 高性能 |
|
|
|
|
|
|
| 4 | 全て | LLVM -O3 | 90%+ | 特殊用途 |
|
|
|
|
|
|
|
|
|
|
|
|
*性能は理論上の最大性能を100%とした場合の目安
|