Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
531 changes: 440 additions & 91 deletions benchmarks/bench_asm_peephole.py

Large diffs are not rendered by default.

418 changes: 418 additions & 0 deletions benchmarks/compare_peephole.py

Large diffs are not rendered by default.

483 changes: 483 additions & 0 deletions docs/topics/13-窥孔优化器-设计文档.md

Large diffs are not rendered by default.

84 changes: 74 additions & 10 deletions docs/topics/13-窥孔优化器.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
# 课题13:窥孔优化器

> **难度**:低 | **类型**:项目实战 | **源文件**:`scratchv/backend/asm_peephole.py` | **行数**:~400
> **状态**:✅ 已完成
> **难度**:低 | **类型**:项目实战 | **源文件**:`scratchv/backend/asm_peephole.py`
> **状态**:✅ 课题收尾完成(2026-09-05,**94 项相关测试通过**,8 条默认规则)

**文档导航**:

| 文档 | 读者 | 链接 |
|------|------|------|
| **完成目录** | 总入口(课题 13 + 全部路径) | [`topic13/README.md`](../../topic13/README.md) |
| 本页 | 新手入门、动手练习 | 当前文件 |
| 设计文档 | 负责人、审查者 | [13-窥孔优化器-设计文档.md](13-窥孔优化器-设计文档.md) |
| 开发文档(AI) | Agent / 维护者 | [archive/topic13_asm_peephole_guide.md](archive/topic13_asm_peephole_guide.md) |
| 前后对比报告 | 效果数据 | [`benchmark_reports/peephole_compare.html`](../../benchmark_reports/peephole_compare.html) |

---

Expand Down Expand Up @@ -49,15 +59,21 @@ PeepholeRule(
)
```

#### 2. 5 条默认规则
#### 2. 默认规则(8 条)

| 规则 | 匹配 | 替换 | 效果 |
|------|------|------|------|
| **addi+addi fusion** | `addi x,a,N; addi x,x,M` | `addi x,a,N+M` | 两条合并为一条 |
| **redundant mv swap** | `mv x,y; mv y,x` | 删除 | 无意义的交换 |
| **addi+addi fusion** | `addi x,a,N; addi x,x,M` | `addi x,a,N+M` | 两条合并(和须 ∈ [-2048,2047]) |
| **li+addi fusion** | `li x,N; addi x,x,M` | `li x,N+M` | 常量折叠 |
| **beq zero-zero to j** | `beq x0,x0,label` | `j label` | 无条件跳转简化 |
| **redundant mv elimination** | `mv a,b; ... mv c,a` | `mv c,b` | 跳过中间寄存器 |
| **redundant mv elimination** | `mv a,b; mv c,a` | `mv c,b` | 跳过中间寄存器(中间寄存器若仍存活则不安全) |
| **addi-zero self** | `addi x,x,0` | 删除 | 加零无操作 |
| **addi-zero to mv** | `addi y,x,0` | `mv y,x` | 加零改成搬运 |
| **nop elimination** | `nop` | 删除 | 空指令 |
| **mv-self** | `mv x,x` | 删除 | 自己搬自己 |

> ⚠️ **已移除的错误规则**:`mv x,y; mv y,x → 删除`
> 这两条**不是**真交换,也不是空操作(结果是两个寄存器都变成原来的 `y`)。删除会改变语义,故默认规则中不再包含。

#### 3. 固定点迭代

Expand All @@ -79,7 +95,8 @@ PeepholeRule(

1. 定义3~5个窥孔优化规则,例如:
- `addi x1, x1, 1; addi x1, x1, 1` → `addi x1, x1, 2`
- `mv x1, x2; mv x2, x1` → 删除两条(如果可交换)
- ~~`mv x1, x2; mv x2, x1` → 删除~~(**错误**:非真交换,禁止删除)
- `mv a, b; mv c, a` → `mv c, b`(中间寄存器不再使用时)
- `li x1, 0; addi x1, x1, 1` → `li x1, 1`
- `beq x0, x0, label` → 无条件跳转`j label`
2. 编写汇编解析器,将每行解析为对象(标签、操作码、操作数列表)。
Expand Down Expand Up @@ -226,6 +243,8 @@ def _match_rule(rule, window):

| 坑 | 说明 |
|----|------|
| **假交换删除** | `mv x,y; mv y,x` **不是**空操作(结果两寄存器都等于原 `y`)。已从默认规则移除 |
| **mv 链活跃性** | `mv a,b; mv c,a → mv c,b` 在中间 `a` 后续仍使用时可能不健全 |
| **寄存器别名** | `x0` 和 `zero` 是同一个寄存器,但字符串比较不相等。需要做规范化 |
| **规则顺序** | 规则的应用顺序影响最终结果——可能规则 A 的替换产物正好被规则 B 匹配 |
| **常量折叠的溢出** | `addi+addi fusion` 中两个立即数相加可能超出 12 位有符号范围(-2048~2047),需要检查 |
Expand All @@ -249,9 +268,54 @@ def _match_rule(rule, window):
- **W4**:实现模式匹配:滑动窗口大小等于规则长度,比较操作码和操作数(支持通配符如任意寄存器)。
- **W5**:实现替换:删除匹配窗口,插入新指令列表,重新扫描。
- **W6**:实现第一条规则:`addi x1,x1,1; addi x1,x1,1` → `addi x1,x1,2`。测试。
- **W7**:实现规则:`mv x1, x2; mv x2, x1` → 删除两条(简单情况)。
- **W7**:分析为何 `mv x,y; mv y,x` **不能**删除;实现 `mv a,b; mv c,a` → `mv c,b`(并写语义测试)。
- **W8**:实现规则:`li x1, 0; addi x1, x1, 1` → `li x1, 1`。
- **W9**:实现规则:`beq x0, x0, label` → `j label`(需要处理标签)。
- **W10**:增加优化报告,打印匹配次数、节省的指令数。
- **W11**:集成到编译器后端(在汇编生成后自动调用),添加`--peephole`开关。
- **W12**:测试10个以上汇编文件,用模拟器验证正确性,撰写文档。
- **W11**:集成到编译器后端(在汇编生成后自动调用),添加`--peephole-asm`开关。
- **W12**:测试10个以上汇编文件,用模拟器/语义检查验证正确性,撰写文档。

---


## Benchmark:开关前后对比

Benchmark 只比较同一份汇编输入在 peephole 关闭/开启时的静态结果,不改变“窥孔优化器”课题定位:

~~~bash
source .venv/bin/activate

# 规则覆盖、负向样例和规模基准
python benchmarks/bench_asm_peephole.py --repeats 5 --output benchmark_reports/peephole_raw.json

# 生成开关对比数据和与现有 benchmark.html 风格一致的报告
python benchmarks/compare_peephole.py --repeats 5 --output-dir benchmark_reports
~~~

输出文件:

- peephole_raw.json:规则覆盖和合成规模的原始数据;
- peephole_compare.json:机器可读的开关对比数据;
- peephole_compare.html:汇总卡片、水平条、规则命中和样例明细。

报告中的指令数使用共享 _asm_parser.parse_asm 统计有效 opcode,排除标签、伪指令和空行;elapsed_ms 仅用于观察趋势,不作为跨机器性能门槛。每个样例带有输入 SHA-256,便于复现和确认开关两侧使用的是同一输入。

---

## 课题总结(收尾)

| 项 | 现状 |
|----|------|
| 默认规则 | **8 条**(假交换删除已移除) |
| 测试 | **94 PASSED**(含 benchmark 数据与报告测试) |
| Benchmark 默认覆盖套件 | 31→22(-29.032%,本地冒烟数据) |
| 报告产物 | JSON + HTML(运行脚本生成) |
| 代表性 codegen 样例 | 6→3(-50%,假交换保留) |

**一句话**:汇编层局部优化已可用;小程序收益有限,冗余多时收益明显;正确性优先于盲目删指令。

```bash
source .venv/bin/activate
python -m pytest tests/test_asm_peephole*.py -q
python benchmarks/compare_peephole.py --repeats 5 --output-dir benchmark_reports
```
Loading
Loading