diff --git a/doc/Lab5-基本标量优化.md b/doc/Lab5-基本标量优化.md index 4acbbac..129260d 100644 --- a/doc/Lab5-基本标量优化.md +++ b/doc/Lab5-基本标量优化.md @@ -9,7 +9,7 @@ ## 2. Lab5 要求 -需要同学完成的事情并不复杂:先理解当前 IR/CFG 结构,明确“有用代码、无用代码、不可达代码”的区别;然后实现能够运行的基础标量优化,并把这些优化接入 `PassManager`,形成可重复执行的流程;最后通过测试确认优化前后语义一致。 +需要同学完成的事情并不复杂:先理解当前 IR/CFG 结构,然后实现能够运行的基础标量优化,并把这些优化接入 `PassManager`,形成可重复执行的流程;最后通过测试确认优化前后语义一致。 ## 3. 相关文件 @@ -18,6 +18,7 @@ - `include/ir/IR.h` - `src/ir/passes/Mem2Reg.cpp` - `src/ir/passes/ConstFold.cpp` +- `src/ir/passes/ConstProp.cpp` - `src/ir/passes/DCE.cpp` - `src/ir/passes/PassManager.cpp` @@ -36,7 +37,7 @@ #### 4.1.2 Mem2Reg 的关键算法基础 -支配树(Dominator Tree)用于描述“定义能影响到哪里”。若从入口到块 A 的所有路径都经过块 B,则 B 支配 A;变量重命名通常就建立在这层关系上,常见实现可采用 Lengauer-Tarjan 算法。 +支配树(Dominator Tree)用于描述“定义能影响到哪里”。若从入口到块 A 的所有路径都经过块 B,则 B 支配 A;变量重命名通常就建立在这层关系上,常见实现可采用 Lengauer-Tarjan 等算法。 支配边界(Dominance Frontier)描述的是“支配关系结束并发生控制流汇合”的位置。在 Mem2Reg 中,它的核心作用是确定 `phi` 函数插入点。 @@ -60,25 +61,29 @@ use-def(或 def-use)描述的是“值在哪里被定义、又在哪里被 ## 5. 可实现的优化方向与实现提示 -### 5.1 Dead(无用代码删除) +### 5.1 Constant Folding / Constant Propagation -可以采用“标记 + 清扫”思路:先从关键操作出发标记“有用”指令,再沿数据依赖和必要控制依赖扩展标记,最后删除未标记指令。 +常量相关优化通常包括常量折叠(Constant Folding)与常量传播(Constant Propagation)。前者是指当一条指令的操作数已经都是常量时,直接在编译期计算结果并用常量替换原指令;后者是指当某个 SSA 值已知为常量时,将该常量继续传播到其使用点,从而为后续进一步折叠、删除冗余分支和清理死代码创造条件。 +### 5.2 Dead Code Elimination (DCE) + +可以采用“标记 + 清扫”思路:先从会影响程序可观察行为的指令出发,标记为“有用”指令,例如 ret、分支跳转、store 以及可能具有副作用的 call;再沿这些指令的数据依赖反向传播,将其依赖的定义一并标记为有用;最后删除其余未被标记、且本身不具有副作用的指令。 > 本实验不限定具体思路,实现可自由设计。 -### 5.2 Clean +### 5.3 CFG Simplification 在 DCE 之后,通常还需要对 CFG 做一轮结构化清理,例如改写冗余分支、删除或绕过空块、合并线性可拼接的基本块,以及清理不可达块。 -### 5.3 优化顺序建议 +### 5.4 公共子表达式消除(Common Subexpression Elimination) -这里建议只固定一个基本约束:先执行一遍 `Mem2Reg`,把 IR 提升到更适合做标量优化的形式。 +如果同一个表达式在程序中被多次计算,并且其操作数在计算之间没有改变,那么就可以只计算一次并复用结果。这类优化的直接收益,是减少重复计算、压缩指令数量、提升执行效率。实现时,通常会在基本块或更大范围内记录已经出现过的表达式;当再次遇到相同表达式且操作数未变化时,直接复用之前的结果,而不是重新生成同一计算。 -其余优化遍(如 `ConstFold`、`CSE`、`DCE`、`CFGSimplify`)的组织顺序不做硬性规定,可根据你的实现自由设计;必要时也可以采用迭代方式,直到 IR 不再变化。 +### 5.5 优化顺序建议 -### 5.4 公共子表达式消除(Common Subexpression Elimination) +这里建议只固定一个基本约束:先执行一遍 `Mem2Reg`,把 IR 提升到更适合做标量优化的形式。 + +其余优化遍(如 `ConstFold`、`CSE`、`DCE`、`CFGSimplify`)的组织顺序不做硬性规定,可根据你的实现自由设计;可以采用优化遍多次迭代方式,直到 IR 不再变化。 -如果同一个表达式在程序中被多次计算,并且其操作数在计算之间没有改变,那么就可以只计算一次并复用结果。这类优化的直接收益,是减少重复计算、压缩指令数量、提升执行效率。实现时,通常会在基本块或更大范围内记录已经出现过的表达式;当再次遇到相同表达式且操作数未变化时,直接复用之前的结果,而不是重新生成同一计算。 ## 6. 构建与验证 diff --git a/doc/Lab6-并行与循环优化.md b/doc/Lab6-并行与循环优化.md index 1090a60..94161f2 100644 --- a/doc/Lab6-并行与循环优化.md +++ b/doc/Lab6-并行与循环优化.md @@ -6,7 +6,7 @@ Lab6 的重点是在 Lab5 基本标量优化之后,继续围绕循环结构开 ## 2. Lab6 要求 -本实验需要完成的事情包括:在现有 IR 上识别循环结构,至少能够区分循环头、循环体与回边;实现有效的循环优化,并保证变换前后语义一致;将这些优化接入 `PassManager`,使其能够与 Lab5 的优化流程协同工作;最后通过回归测试和性能或代码规模对比,验证优化结果的正确性与收益。若希望进一步提升性能,也可以继续尝试可并行循环识别与并行化改造。 +本实验需要完成的事情包括:在现有 IR 上识别循环结构,能够区分循环头、循环体、前置块、退出块与回边等部分;实现有效的循环优化,并保证变换前后语义一致;将这些优化接入 `PassManager`,使其能够与 Lab5 的优化流程协同工作;最后通过回归测试和性能或代码规模对比,验证优化结果的正确性与收益。若希望进一步提升性能,也可以继续尝试可并行循环识别与并行化改造。 ## 3. 相关文件 diff --git a/src/ir/passes/CMakeLists.txt b/src/ir/passes/CMakeLists.txt index 4d8f509..98867f5 100644 --- a/src/ir/passes/CMakeLists.txt +++ b/src/ir/passes/CMakeLists.txt @@ -2,6 +2,7 @@ add_library(ir_passes STATIC PassManager.cpp Mem2Reg.cpp ConstFold.cpp + ConstProp.cpp CSE.cpp DCE.cpp CFGSimplify.cpp diff --git a/src/ir/passes/ConstProp.cpp b/src/ir/passes/ConstProp.cpp new file mode 100644 index 0000000..1768b71 --- /dev/null +++ b/src/ir/passes/ConstProp.cpp @@ -0,0 +1,5 @@ +// 常量传播(Constant Propagation): +// - 沿 use-def 关系传播已知常量 +// - 将可替换的 SSA 值改写为常量,暴露更多折叠机会 +// - 常与 ConstFold、DCE、CFGSimplify 迭代配合使用 +