Compare commits

...

58 Commits

Author SHA1 Message Date
07fd22def1 [backend-fma]添加浮点乘加融合优化,提供开关简单控制是否启用 2025-08-17 00:07:04 +08:00
Lixuanwang
7be5d25372 [backend]更改了commit顺序 2025-08-16 00:11:21 +08:00
Lixuanwang
fdba73d5e1 Merge branch 'midend' into backend 2025-08-15 21:23:48 +08:00
Lixuanwang
8cabb1f195 Merge branch 'backend' of gitee.com:lixuanwang/mysysy into backend 2025-08-15 21:23:02 +08:00
rain2133
fa33bf5134 [midend-Loop-IVE]修复循环的死IV消除逻辑 2025-08-15 01:19:45 +08:00
rain2133
a3435e7c26 [midend-Loop-IVE]循环归纳变量消除逻辑重构,修改运行顺序 2025-08-14 17:27:53 +08:00
rain2133
7547d34598 [midend-IVE]参考libdivide库,实现了魔数的正确求解,如果后续出错直接用API或者不要除法强度削弱了 2025-08-14 05:12:54 +08:00
rain2133
06a368db39 [midend]修复创建新归纳变量的错误逻辑,避免生成悬空phi节点的现象 2025-08-13 20:00:43 +08:00
rain2133
48865fa805 [midend-IVE]增加无用归纳变量消除遍 2025-08-13 17:42:34 +08:00
rain2133
8b5123460b [midend-Loop-InductionVarStrengthReduction]支持了对部分除法运算取模运算的归纳变量的强度削弱策略。(mulh+魔数,负数2的幂次除法符号修正,2的幂次取模运算and优化)。增加了了Printer对移位指令的打印支持 2025-08-13 17:41:41 +08:00
rain2133
cd27f5fda9 [midend]增加部分逻辑位移指令 2025-08-13 15:28:37 +08:00
rain2133
60cb8d6e49 [midend]重命名Sra指令的kind标识 2025-08-13 14:55:46 +08:00
rain2133
ea944f6ba0 [midend-Loop-InductionVarStrengthReduction]增加循环规约变量强度削弱优化 2025-08-13 01:13:01 +08:00
rain2133
0c8a156485 [midend-LoopCharacteristics]强化归纳变量的识别 2025-08-12 22:33:16 +08:00
rain2133
debda205cc [testdata]将官方提供的RV错误样例输入替换成了ARM中正确的输入 2025-08-12 16:24:24 +08:00
rain2133
baef82677b [midend-LICM]将能够外提的循环不变量进行Kanh拓扑排序保证外提后的计算顺序正确。 2025-08-12 16:18:00 +08:00
rain2133
f634273852 [midend-LICM]优化了特征分析中对循环不变量的识别,实现了LICM遍,格式化副作用分析代码 2025-08-12 15:53:57 +08:00
rain2133
70f6a25ebc [midend-LoopAnalysis]修复循环规范遍bug,修正部分打印格式, 2025-08-12 12:34:07 +08:00
rain2133
8cb807c8b9 [midend-LoopAnalysis]修复phi指令缺失的getIncomingValues方法调用 2025-08-11 21:20:38 +08:00
rain2133
1fab6a43f9 Merge branch 'midend' into midend-LoopAnalysis 2025-08-11 21:20:34 +08:00
rain2133
1e3791a801 [midend-LoopNormalization]消除不必要的循环特征分析结果使用。优化phi指令处理逻辑 2025-08-11 20:51:55 +08:00
rain2133
a1cca3c95a [midend-llvmirprint]修改i1类型不存在引入的临时寄存器保存比较结果重命名的逻辑,减少冲突的可能性 2025-08-11 19:10:11 +08:00
rain2133
1361156b0d [midend-CFGOpt]修复上一次提交的漏洞 2025-08-11 18:46:07 +08:00
rain2133
46179e3866 [midend-CFGOpt]修复部分指令删除逻辑错误 2025-08-11 18:40:58 +08:00
rain2133
038552f58b [midend-SCCP]修复了函数参数没有正确初始化为Bottom的问题,现在f/64样例可以-O1通过 2025-08-11 16:47:03 +08:00
rain2133
4d0e2d73ea [midend-LATG]将调试信息改为DEBUG生效 2025-08-10 17:32:45 +08:00
rain2133
ad19a6715f [midend]删除了错误的sra指令生成逻辑 2025-08-10 16:57:40 +08:00
rain2133
d1ba140657 [midend-llvnirprint]修改浮点为字面值打印,修复assign的类型推断 2025-08-10 16:12:09 +08:00
rain2133
2c5e4cead1 [midend-llvmirprint]修复部分打印逻辑,修复生成IR时的基本块错误的前后驱关系链接 2025-08-10 15:19:24 +08:00
rain2133
6b92020bc4 [midend-llvmirprint]修复全局数组打印格式问题 2025-08-09 22:41:32 +08:00
rain2133
c867bda9b4 [midend]解决部分变量重命名问题 2025-08-09 22:30:09 +08:00
rain2133
6b9ad0566d [midend-llvmirprint]修复进度(162/199),修复若干打印问题,修复若干ir生成逻辑问题 2025-08-09 21:28:44 +08:00
rain2133
6a7355ed28 [midend-Loop]初步构建循环规范遍 2025-08-09 17:53:41 +08:00
rain2133
be9ac89584 [midend-LoopAnalysis]将前置分析结果指针保存到循环特征分析类中消除冗余的分析指针传递 2025-08-09 16:42:31 +08:00
rain2133
ac3358d7e3 [midend-LoopAnalysis]移除基本循环特征分析中的向量化并行化内容,增加循环向量化并行化特征分析遍,TODO:构建循环优化遍验证分析遍正确性 2025-08-09 13:53:00 +08:00
lixuanwang
a958435836 Merge commit '167c2ac2aece809765dd8ed2b869fc16f84005f2' into backend 2025-08-08 22:58:17 +08:00
rain2133
bd23f6154d [midend-SideEffect]将副作用分析遍重构为Module级别,更新其他优化遍用法,注册到PassMananger中,修改CMakeLists。 2025-08-08 16:25:41 +08:00
rain2133
126c38a1d9 [midend-CallGraph]增加调用图分析遍 2025-08-08 16:24:13 +08:00
rain2133
c4c91412d1 [midend]修改一点逻辑和注释,删除无用文件 2025-08-08 15:31:35 +08:00
rain2133
f17e44f8d4 [midend-Alias]针对sysy语言设计了保守和激进的别名优化策略,设计了通过接口设置选项,后续需要验证。保留了一些激进策略接口置空待后续增加。 2025-08-08 15:08:49 +08:00
rain2133
a406e44df3 [midend-Alias]应用别名分析结果,sccp现在能简单传播数组元素了 2025-08-08 02:12:32 +08:00
rain2133
b1a46b7d58 [midend-LoopAnalysis]为项目添加别名分析遍,副作用分析遍,循环分析遍,循环特征分析遍 2025-08-08 00:56:50 +08:00
rain2133
bd02f5f1eb [midend-LoopAnalysis]为phi指令添加新的方法供外部遍历(目前不是顺序遍历) 2025-08-08 00:55:01 +08:00
Lixuanwang
c507b98199 [midend-llvmprint]更新脚本,支持-eir执行IR测试 2025-08-07 23:45:26 +08:00
rain2133
ba21bb3203 [midend]修复内存泄漏和Heap-buffer-overflow问题(getexternalfunction中及其隐秘的错误),修复全局常量标量访问的错误 2025-08-07 02:53:36 +08:00
rain2133
8aa5ba692f [midend]初步修复内存泄漏问题(仍然剩余11处) 2025-08-07 01:34:00 +08:00
ladev789
d732800149 [midend-llvmprint]更新脚本,禁用内存泄漏检查 2025-08-07 00:36:43 +08:00
rain2133
f083e38615 [midend-Loop]循环分析构建,增加很多统计方法和循环信息方法 2025-08-06 22:29:39 +08:00
rain2133
37f2a01783 [midend-llvmirprint]修复了gep指令对不含维度信息的数组指针的处理逻辑,修复若干打印bug,在-s ir/ird -o <llvmir.ll file>的参数下最终会打印ir到file中,优化过程中的打印逻辑待更改。 2025-08-06 15:28:54 +08:00
rain2133
5d343f42a5 [midend-llvmirprint]检查并修复了初始值的打印逻辑 2025-08-06 02:02:05 +08:00
rain2133
a4406e0112 [midend]增加了指令重命名逻辑。 2025-08-06 01:31:23 +08:00
rain2133
08fcda939b [midend-llvmirprint]实现了大部分函数的print方法,TODO:需要完善func和module的print方法以及重命名的逻辑 2025-08-06 01:02:11 +08:00
rain2133
33ca8ecf34 [document]修改编译器文档中端设计部分 2025-08-05 21:37:48 +08:00
d439ef7e8e [document]初步添加编译器文档 2025-08-05 20:53:44 +08:00
rain2133
5f63554ca3 [midend]修正合并基本块链会将entry块纳入考虑范围的问题。上次commit同时修改了alloca创建的逻辑保证了alloca的声明全部在entry块中 2025-08-04 18:56:57 +08:00
rain2133
ef9d7c4d03 [midend-LoopAnalysis]增加维护循环层级的逻辑,修改父子循环关系求解的逻辑。 2025-08-03 15:22:18 +08:00
rain2133
1c7c85dd2f Merge commit 'f879a0f521e3033d3f928a5976ac095af6905942' into midend-LoopAnalysis 2025-08-03 14:30:32 +08:00
rain2133
aa7f2bb0f5 [midend]loop分析构建 2025-08-02 17:42:43 +08:00
52 changed files with 11743 additions and 1220 deletions

View File

@@ -228,10 +228,193 @@ Branch 和 Return 指令: 这些是终结符指令,不产生一个可用于其
在提供的代码中SSAPValue 的 constantVal 是 int 类型。这使得浮点数常量传播变得复杂。对于浮点数相关的指令kFAdd, kFMul, kFCmp, kFNeg, kFNot, kItoF, kFtoI 等),如果不能将浮点值准确地存储在 int 中,或者不能可靠地执行浮点运算,那么通常会保守地将结果设置为 Bottom。一个更完善的 SCCP 实现会使用 std::variant<int, float> 或独立的浮点常量存储来处理浮点数。
## LoopSR循环归纳变量强度削弱 关于魔数计算的说明
魔数除法的核心思想是:将除法转换为乘法和移位
数学原理x / d ≈ (x * m) >> (32 + s)
m 是魔数 (magic number)
s 是额外的移位量 (shift)
>> 是算术右移
2^(32+s) / d ≤ m < 2^(32+s) / d + 2^s / d
cd /home/downright/Compiler_Opt/mysysy && python3 -c "
# 真正的迭代原因:精度要求
def explain_precision_requirement():
d = 10
print('魔数算法需要找到精确的边界值:')
print('目标2^p > d * (2^31 - r)其中r是余数')
print()
# 模拟我们算法的迭代过程
p = 31
two_p = 2**p
r = two_p % d # 余数
m = two_p // d # 商
print(f'初始状态 (p={p}):')
print(f' 2^{p} = {two_p:,}')
print(f' 2^{p} / {d} = {m:,} 余 {r}')
print(f' 需要检查: 2^{p} > {d} * (2^31 - {r}) = {d * (2**31 - r):,}')
print(f' 条件满足: {two_p > d * (2**31 - r)}')
print()
# 继续迭代直到条件满足
iteration = 0
while r != 0 and m < 2**31:
iteration += 1
p += 1
two_p *= 2
m *= 2
r *= 2
if r >= d:
m += 1
r -= d
print(f'迭代 {iteration} (p={p}):')
print(f' m = {m:,}, r = {r}')
print(f' m < 2^31? {m < 2**31} (2^31 = {2**31:,})')
if m >= 2**31:
print(f' ✗ 魔数 {m:,} 超出32位范围!')
break
elif r == 0:
print(f' ✓ 余数为0找到精确解')
break
if iteration > 10: # 防止无限循环
print(' ... (限制迭代次数)')
break
explain_precision_requirement()
"
问题在于精度要求。理论魔数需要非常精确,不能简单地用 2^32 / d。让我展示真正的迭代原因
cd /home/downright/Compiler_Opt/mysysy && python3 -c "
# 真正的迭代原因:精度要求
def explain_precision_requirement():
d = 10
print('魔数算法需要找到精确的边界值:')
print('目标2^p > d * (2^31 - r)其中r是余数')
print()
# 模拟我们算法的迭代过程
p = 31
two_p = 2**p
r = two_p % d # 余数
m = two_p // d # 商
print(f'初始状态 (p={p}):')
print(f' 2^{p} = {two_p:,}')
print(f' 2^{p} / {d} = {m:,} 余 {r}')
print(f' 需要检查: 2^{p} > {d} * (2^31 - {r}) = {d * (2**31 - r):,}')
print(f' 条件满足: {two_p > d * (2**31 - r)}')
print()
# 继续迭代直到条件满足
iteration = 0
while r != 0 and m < 2**31:
iteration += 1
p += 1
two_p *= 2
m *= 2
r *= 2
if r >= d:
m += 1
r -= d
print(f'迭代 {iteration} (p={p}):')
print(f' m = {m:,}, r = {r}')
print(f' m < 2^31? {m < 2**31} (2^31 = {2**31:,})')
if m >= 2**31:
print(f' ✗ 魔数 {m:,} 超出32位范围!')
break
elif r == 0:
print(f' ✓ 余数为0找到精确解')
break
if iteration > 10: # 防止无限循环
print(' ... (限制迭代次数)')
break
explain_precision_requirement()
"
cd /home/downright/Compiler_Opt/mysysy && python3 -c "
# 检查初始状态是否会溢出
def check_initial_overflow():
int32_max = 2**31 - 1
print('检查不同除数的初始魔数是否会溢出:')
print(f'32位有符号整数最大值: {int32_max:,}')
print()
# 检查各种除数
divisors = [2, 3, 5, 7, 9, 10, 11, 13, 17, 25, 100, 1000]
for d in divisors:
# 初始魔数 = 2^31 / d
initial_magic = (2**31) // d
overflow = initial_magic > int32_max
status = \"溢出\" if overflow else \"安全\"
print(f'd={d:4d}: 初始魔数 = 2^31/{d} = {initial_magic:10,} [{status}]')
print()
print('结论: 初始状态下魔数不会溢出,溢出发生在迭代过程中')
check_initial_overflow()
"
总结
迭代的必要性:
不是为了避免初始溢出(初始状态安全)
是为了找到最精确的魔数,减少舍入误差
每次迭代提高一倍精度,但魔数也翻倍
溢出发生时机:
初始状态2^31 / d 总是在32位范围内
迭代过程2^32 / d, 2^33 / d, ... 逐渐超出32位范围
回退值的正确性:
回退值是基于数学理论和实践验证的标准值
来自LLVM、GCC等成熟编译器的实现
通过测试验证,对各种输入都能产生正确结果
算法设计哲学:
先尝试最优解:通过迭代寻找最精确的魔数
检测边界条件当超出32位范围时及时发现
智能回退:使用已验证的标准值保证正确性
保持通用性:对于没有预设值的除数仍然可以工作
## 死归纳变量消除
整体架构和工作流程
当前的归纳变量消除优化分为三个清晰的阶段:
识别阶段:找出所有潜在的死归纳变量
安全性分析阶段:验证每个变量消除的安全性
消除执行阶段:实际删除安全的死归纳变量
逃逸点检测 (已修复的关键安全机制)
数组索引检测GEP指令被正确识别为逃逸点
循环退出条件:用于比较和条件分支的归纳变量不会被消除
控制流指令condBr、br、return等被特殊处理为逃逸点
内存操作store/load指令经过别名分析检查
# 后续优化可能涉及的改动
## 1将所有的alloca集中到entryblock中
## 1将所有的alloca集中到entryblock中(已实现)
好处优化友好性方便mem2reg提升
目前没有实现这个机制,如果想要实现首先解决同一函数不同域的同名变量命名区分

272
doc/CompilerDesign.md Normal file
View File

@@ -0,0 +1,272 @@
# 编译器核心技术与优化详解
本文档深入剖析 mysysy 编译器的内部实现,重点阐述其在前端、中端和后端所采用的核心编译技术及优化算法,并结合具体实现函数进行说明。
## 1. 编译器整体架构
本编译器采用经典的三段式架构将编译过程清晰地划分为前端、中端和后端三个主要部分。每个部分处理不同的抽象层级并通过定义良好的接口AST, IR进行通信实现了高度的模块化。
```mermaid
graph TD
A[源代码 .sy] --> B{前端 Frontend};
B --> C[抽象语法树 AST];
C --> D{中端 Midend};
D --> E[SSA-based IR];
E -- 优化 --> F[优化后的 IR];
F --> G{后端 Backend};
G --> H[目标机代码 MachineInstr];
H --> I[RISC-V 64 汇编代码 .s];
subgraph 前端
B
end
subgraph 中端
D
end
subgraph 后端
G
end
```
- **前端 (Frontend)**:负责词法、语法、语义分析,将 SysY 源代码解析为抽象语法树 (AST)。
- **中端 (Midend)**:基于 AST 生成与具体机器无关的中间表示 (IR),并在此基础上进行深入的分析和优化。
- **后端 (Backend)**:将优化后的 IR 翻译成目标平台RISC-V 64的汇编代码。
---
## 2. 前端技术 (Frontend)
前端的核心任务是进行语法和语义的分析与验证,其工作流程如下:
```mermaid
graph TD
subgraph "前端处理流程"
Source["源文件 (.sy)"] --> Lexer["词法分析器 (SysYLexer)"];
Lexer --> TokenStream["Token 流"];
TokenStream --> Parser["语法分析器 (SysYParser)"];
Parser --> ParseTree["解析树"];
ParseTree --> Visitor["AST构建 (SysYVisitor)"];
Visitor --> AST[抽象语法树];
end
```
- **词法与语法分析**:
- **技术**: 采用 **ANTLR (ANother Tool for Language Recognition)** 框架。通过在 `frontend/SysY.g4` 文件中定义的上下文无关文法ANTLR 能够自动生成高效的 LL(*) 词法分析器 (`SysYLexer.cpp`) 和语法分析器 (`SysYParser.cpp`)。
- **实现**: 词法分析器将字符流转换为记号 (Token) 流,语法分析器则根据文法规则将记号流组织成一棵解析树 (Parse Tree)。这棵树精确地反映了源代码的语法结构。
- **AST 构建**:
- **技术**: 应用 **访问者 (Visitor) 设计模式** 遍历 ANTLR 生成的解析树。该模式将数据结构解析树与作用于其上的操作AST构建逻辑解耦。
- **实现**: `frontend/SysYVisitor.cpp` 中定义了具体的遍历逻辑。在遍历过程中,会构建一个比解析树更抽象、更面向编译需求的**抽象语法树 (Abstract Syntax Tree, AST)**。AST 忽略了纯粹的语法细节(如括号、分号),只保留了核心的语义结构,是前端传递给中端的接口。
---
## 3. 中端技术与优化 (Midend)
中端是编译器的核心,所有与目标机器无关的分析和优化都在此阶段完成。
### 3.1. 中间表示 (IR) 及设计要点
- **技术**: 设计了一种三地址码Three-Address Code风格的中间表示其形式和设计哲学深受 **LLVM IR** 的启发。IR 的核心特征是采用了**静态单赋值 (Static Single Assignment, SSA)** 形式。
- **实现**: `midend/IR.cpp` 定义了 IR 的核心数据结构,如 `Instruction`, `BasicBlock`, `Function``Module``midend/SysYIRGenerator.cpp` 负责将前端的 AST 转换为这种 IR。在 SSA 形式下,每个变量只被赋值一次,使得变量的定义-使用关系Def-Use Chain变得异常清晰极大地简化了后续的优化算法。通过继承并重写 SysYBaseVisitor 类,遍历 AST 节点生成自定义 IR并在 IR 生成阶段实现了简单的常量传播和公共子表达式消除CSE
- **设计要点**
- **`alloca` 指令集中管理**
所有 `alloca` 指令统一放置在入口基本块,并与实际计算指令分离。这有助于后续指令调度器专注于优化计算密集型指令的执行顺序,避免内存分配指令的干扰。
- **消除 `fallthrough` 现象**
通过确保所有基本块均以终结指令结尾,消除基本块间的 `fallthrough`简化了控制流图CFG的构建和分析。这一做法提升了编译器整体质量使中端各类 Pass 的编写和维护更加规范和高效。
### 3.2. 核心优化详解
编译器的分析和优化被组织成一系列独立的“遍”Pass。每个 Pass 都是一个独立的算法模块,对 IR 进行特定的分析或变换。这种设计具有高度的模块化和可扩展性。
#### 3.2.1. SSA 构建与解构
- **Mem2Reg (`Mem2Reg.cpp`)**:
- **目标**: 将对栈内存 (`alloca`) 的 `load`/`store` 操作,提升为对虚拟寄存器的直接操作,并构建 SSA 形式。
- **技术**: 该过程是实现 SSA 的关键。它依赖于**支配树 (Dominator Tree)** 分析,通过寻找变量定义块的**支配边界 (Dominance Frontier)** 来确定在何处插入 **Φ (Phi) 函数**
- **实现**: `Mem2RegContext::run` 驱动此过程。首先调用 `isPromotableAlloca` 识别所有仅被 `load`/`store` 使用的标量 `alloca`。然后,`insertPhis` 根据支配边界信息在必要的控制流汇合点插入 `phi` 指令。最后,`renameVariables` 递归地遍历支配树,用一个模拟的值栈来将 `load` 替换为栈顶的 SSA 值,将 `store` 视为对栈的一次 `push` 操作从而完成重命名。值得一提的是由于我们在IR生成阶段就将所有alloca指令统一放置在入口块极大地简化了Mem2Reg遍的实现和支配树分析的计算。
- **Reg2Mem (`Reg2Mem.cpp`)**:
- **目标**: 执行 `Mem2Reg` 的逆操作,将程序从 SSA 形式转换回基于内存的表示。这通常是为不支持 SSA 的后端做准备的**SSA解构 (SSA Destruction)** 步骤。
- **技术**: 为每个 SSA 值(指令结果、函数参数)在函数入口创建一个 `alloca` 栈槽。然后,在每个 SSA 值的定义点之后插入一个 `store` 将其存入对应的栈槽;在每个使用点之前插入一个 `load` 从栈槽中取出值。
- **实现**: `Reg2MemContext::run` 驱动此过程。`allocateMemoryForSSAValues` 为所有需要转换的 SSA 值创建 `alloca` 指令。`rewritePhis` 特殊处理 `phi` 指令,在每个前驱块的末尾插入 `store``insertLoadsAndStores` 则处理所有非 `phi` 指令的定义和使用,插入相应的 `store``load`。虽然
#### 3.2.2. 常量与死代码优化
- **SCCP (`SCCP.cpp`)**:
- **目标**: 稀疏条件常量传播。在编译期计算常量表达式,并利用分支条件为常数的信息来消除死代码,比简单的常量传播更强大。
- **技术**: 这是一种基于数据流分析的格理论Lattice Theory的优化。它为每个变量维护一个值状态可能为 `Top` (未定义), `Constant` (某个常量值), 或 `Bottom` (非常量)。同时,它跟踪基本块的可达性,如果一个分支的条件被推断为常量,则其不可达的后继分支在分析中会被直接忽略。
- **实现**: `SCCPContext::run` 驱动整个分析过程。它维护一个指令工作列表和一个边工作列表。`ProcessInstruction``ProcessEdge` 函数交替执行,不断地从 IR 中传播常量和可达性信息,直到达到不动点为止。最后,`PropagateConstants``SimplifyControlFlow` 将推断出的常量替换到代码中,并移除死块。
- **DCE (`DCE.cpp`)**:
- **目标**: 简单死代码消除。移除那些计算结果对程序输出没有贡献的指令。
- **技术**: 采用**标记-清除 (Mark and Sweep)** 算法。从具有副作用的指令(如 `store`, `call`, `return`)开始,反向追溯其操作数,标记所有相关的指令为“活跃”。
- **实现**: `DCEContext::run` 实现了此算法。第一次遍历时,通过 `isAlive` 函数识别出具有副作用的“根”指令,然后调用 `addAlive` 递归地将所有依赖的指令加入 `alive_insts` 集合。第二次遍历时,所有未被标记为活跃的指令都将被删除。
- **未来规划**: 后续开发更多分析遍会为DCE收集更多的IR信息能够迭代出更健壮的DEC遍。
#### 3.2.3. 控制流图 (CFG) 优化
- **实现**: `SysYIRCFGOpt.cpp` 中定义了一系列用于清理和简化控制流图的 Pass。
- **`SysYDelInstAfterBrPass`**: 删除分支指令后的死代码。
- **`SysYDelNoPreBLockPass`**: 通过从入口块开始的图遍历BFS识别并删除所有不可达的基本块。
- **`SysYDelEmptyBlockPass`**: 识别并删除仅包含一条无条件跳转指令的空块,将其前驱直接重定向到其后继。
- **`SysYBlockMergePass`**: 如果一个块 A 只有一个后继 B且 B 只有一个前驱 A则将 A 和 B 合并为一个块。
- **`SysYCondBr2BrPass`**: 如果一个条件分支的条件是常量,则将其转换为一个无条件分支。
- **`SysYAddReturnPass`**: 确保所有没有终结指令的函数出口路径都有一个 `return` 指令,以保证 CFG 的完整性。
#### 3.2.4. 其他优化
- **LargeArrayToGlobal (`LargeArrayToGlobal.cpp`)**:
- **目标**: 防止因大型局部数组导致的栈溢出,并可能改善数据局部性。
- **技术**: 遍历函数中的 `alloca` 指令,如果通过 `calculateTypeSize` 计算出其分配的内存大小超过一个阈值(如 1024 字节),则将其转换为一个全局变量。
- **实现**: `convertAllocaToGlobal` 函数负责创建一个新的 `GlobalValue`,并调用 `replaceAllUsesWith` 将原 `alloca` 的所有使用者重定向到新的全局变量,最后删除原 `alloca` 指令。
#### 3.3. 核心分析遍
为了为优化遍收集信息,最大程度发掘程序优化潜力,我们目前设计并实现了以下关键的分析遍:
- **支配树分析 (Dominator Tree Analysis)**:
- **技术**: 通过计算每个基本块的支配节点,构建出一棵支配树结构。我们在计算支配节点时采用了**逆后序遍历RPO, Reverse Post Order**以保证数据流分析的收敛速度和正确性。在计算直接支配者Idom, Immediate Dominator采用了经典的**Lengauer-TarjanLT算法**,该算法以高效的并查集和路径压缩技术著称,能够在线性时间内准确计算出每个基本块的直接支配者关系。
- **实现**: `Dom.cpp` 实现了支配树分析。该分析为每个基本块分配其直接支配者,并递归构建整棵支配树。支配树是许多高级优化(尤其是 SSA 形式下的优化的基础。例如Mem2Reg 需要依赖支配树来正确插入 Phi 指令,并在变量重命名阶段高效遍历控制流图。此外,循环相关优化(如循环不变量外提)也依赖于支配树信息来识别循环头和循环体的关系。
- **活跃性分析 (Liveness Analysis)**:
- **技术**: 活跃性分析用于确定在程序的某一特定点上,哪些变量的值在未来会被用到。我们采用**经典的不动点迭代算法**,在数据流分析框架下,逆序遍历基本块,迭代计算每个基本块的 `live-in``live-out` 集合,直到收敛为止。这种方法简单且易于实现,能够满足大多数编译优化的需求。
- **未来规划**: 若后续对分析效率有更高要求,可考虑引入如**工作列表算法**或者**转化为基于SSA的图可达性分析**等更高效的算法,以进一步提升大型函数或复杂控制流下的分析性能。
- **实现**: `Liveness.cpp` 提供了活跃性分析。该分析采用经典的数据流分析框架,迭代计算每个基本块的 `live-in``live-out` 集合。活跃性信息是死代码消除DCE、寄存器分配等优化的必要前置步骤。通过准确的活跃性分析可以识别出无用的变量和指令从而为后续优化遍提供坚实的数据基础。
### 3.4. 未来的规划
基于现有的成果,我们规划将中端能力进一步扩展,近期我们重点将放在循环相关的分析和函数内联的实现,以期大幅提升最终程序的性能。
- **循环优化**:
我们正在开发一个健壮的分析遍来准确识别程序中的循环结构,并通过对已识别的循环进行规范化的转换遍,为后续的向量化、并行化工作做铺垫。并通过循环不变量提升、循环归纳变量分析与强度削减等优化提升循环相关代码的执行效率。
- **函数内联**:
函数内联能够将简单函数可能需要收集更多信息内联到call指令相应位置减少栈空间相关变动并且为其他遍发掘优化空间。
- **`LLVM IR`格式化**:
我们将为所有的IR设计并实现通用的打印器方法使得IR能够显式化为可编译运行的LLVM IR通过编排脚本和调用llvm相关工具链我们能够绕过后端编译运行中间代码为验证中端正确性提供系统化的方法同时减轻后端开发bug溯源的压力。
---
## 4. 后端技术与优化 (Backend)
后端负责将经过优化的、与机器无关的 IR 转换为针对 RISC-V 64 位架构的汇编代码。
### 4.1. 栈帧布局 (Stack Frame Layout)
在函数调用发生时,后端需要在栈上创建一个**栈帧 (Stack Frame)** 来存储局部变量、传递参数和保存寄存器。本编译器采用的栈帧布局遵循 RISC-V 调用约定,结构如下:
```
高地址 +-----------------------------+
| ... |
| 函数参数 (8+) | <-- 调用者传入的、放不进寄存器的参数
+-----------------------------+
| 返回地址 (ra) | <-- sp 在函数入口指向的位置
+-----------------------------+
| 旧的帧指针 (s0/fp) |
+-----------------------------+ <-- s0/fp 在函数序言后指向的位置
| 被调用者保存的寄存器 |
| (Callee-Saved Regs) |
+-----------------------------+
| 局部变量 (Alloca) |
+-----------------------------+
| 寄存器溢出区域 |
| (Spill Slots) |
+-----------------------------+
| 为调用其他函数预留的 |
| 出参空间 (Out-Args) |
低地址 +-----------------------------+ <-- sp 在函数序言后指向的位置
```
- **实现**: `PrologueEpilogueInsertion.h``EliminateFrameIndices.h` 中的 Pass 负责生成函数序言prologue和尾声epilogue代码来构建和销毁上述栈帧。`EliminateFrameIndices` 会将所有对抽象栈槽(如局部变量、溢出槽)的访问,替换为对帧指针 `s0` 或栈指针 `sp` 的、带有具体偏移量的访问。
### 4.2. 指令选择 (Instruction Selection)
- **目标**: 将抽象的 IR 指令高效地翻译成具体的目标机指令序列。
- **技术**: 采用 **基于 DAG (Directed Acyclic Graph) 的模式匹配** 算法。
- **实现**: `RISCv64ISel.cpp` 中的 `RISCv64ISel::select()` 驱动此过程。`selectBasicBlock()` 为每个基本块调用 `build_dag()` 来构建一个操作的 DAG然后通过 `select_recursive()` 对 DAG 进行自底向上的遍历和匹配。在 `selectNode()` 函数中,通过一个大的 `switch` 语句,为不同类型的 DAG 节点(如 `BINARY`, `LOAD`, `STORE`)匹配最优的指令序列。例如,一个 IR 的加法指令,如果其中一个操作数是小常数,会被直接匹配为一条 `ADDIW` 指令,而不是 `LI``ADDW` 两条指令。
### 4.3. 寄存器分配 (Register Allocation)
- **目标**: 将无限的虚拟寄存器映射到有限的物理寄存器上,并优雅地处理寄存器不足(溢出)的情况。
- **技术**: 实现了经典的**基于图着色 (Graph Coloring) 的全局寄存器分配算法**,这是一种强大但复杂的全局优化方法。
- **实现**: `RISCv64RegAlloc.cpp` 中的 `RISCv64RegAlloc::run()` 是主入口。它在一个循环中执行分配,直到没有寄存器需要溢出为止。其内部流程极其精密,如下图所示:
```mermaid
graph TD
subgraph "寄存器分配主循环 (RISCv64RegAlloc::run)"
direction LR
Start((Start)) --> Liveness[1. 活跃性分析 LivenessAnalysis]
Liveness --> Build[2. 构建冲突图 Build]
Build --> Worklist[3. 创建工作表 MakeWorklist]
Worklist --> Loop{Main Loop}
Loop -- simplifyWorklist 非空 --> Simplify[4a. 简化 Simplify]
Simplify --> Loop
Loop -- worklistMoves 非空 --> Coalesce[4b. 合并 Coalesce]
Coalesce --> Loop
Loop -- freezeWorklist 非空 --> Freeze[4c. 冻结 Freeze]
Freeze --> Loop
Loop -- spillWorklist 非空 --> Spill[4d. 选择溢出 SelectSpill]
Spill --> Loop
Loop -- 所有工作表为空 --> Assign[5. 分配颜色 AssignColors]
Assign --> CheckSpill{有溢出?}
CheckSpill -- Yes --> Rewrite[6. 重写代码 RewriteProgram]
Rewrite --> Liveness
CheckSpill -- No --> Finish((Finish))
end
```
1. **`analyzeLiveness()`**: 对机器指令进行数据流分析,计算出每个虚拟寄存器的活跃范围。
2. **`build()`**: 根据活跃性信息构建**冲突图 (Interference Graph)**。如果两个虚拟寄存器同时活跃,则它们冲突,在图中连接一条边。
3. **`makeWorklist()`**: 将图节点(虚拟寄存器)根据其度数放入不同的工作列表,为着色做准备。
4. **核心着色阶段 (The Loop)**:
- **`simplify()`**: 贪心地移除图中度数小于物理寄存器数量的节点,并将其压入栈中。这些节点保证可以被成功着色。
- **`coalesce()`**: 尝试将传送指令 (`MV`) 的源和目标节点合并,以消除这条指令。合并的条件基于 **Briggs****George** 启发式,以避免使图变得不可着色。
- **`freeze()`**: 当一个与传送指令相关的节点无法合并也无法简化时,放弃对该传送指令的合并希望,将其“冻结”为一个普通节点。
- **`selectSpill()`**: 当所有节点都无法进行上述操作时(即图中只剩下高度数的节点),必须选择一个节点进行**溢出 (Spill)**,即决定将其存放在内存中。
5. **`assignColors()`**: 在所有节点都被处理后,从栈中依次弹出节点,并根据其已着色邻居的颜色,为它选择一个可用的物理寄存器。
6. **`rewriteProgram()`**: 如果 `assignColors()` 阶段发现有节点被标记为溢出,此函数会被调用。它会修改机器指令,为溢出的虚拟寄存器插入从内存加载(`lw`/`ld`)和存入内存(`sw`/`sd`)的代码。然后,整个分配过程从步骤 1 重新开始。
### 4.4. 后端特定优化
在寄存器分配前后后端还会进行一系列针对目标机RISC-V特性的优化。
#### 4.4.1. 指令调度 (Instruction Scheduling)
- **寄存器分配前调度 (`PreRA_Scheduler.cpp`)**:
- **目标**: 在寄存器分配前,通过重排指令来提升性能。主要目标是**隐藏加载延迟 (Load Latency)**,即尽早发出 `load` 指令,使其结果能在需要时及时准备好,避免流水线停顿。同时,由于此时使用的是无限的虚拟寄存器,调度器有较大的自由度,但也可能因为过度重排而延长虚拟寄存器的生命周期,从而增加寄存器压力。
- **实现**: `scheduleBlock()` 函数会识别出基本块内的调度边界(如 `call` 或终结指令),然后在每个独立的区域内调用 `scheduleRegion()`。当前的实现是一种简化的列表调度,它会优先尝试将加载指令 (`LW`, `LD` 等) 在不违反数据依赖的前提下,尽可能地向前移动。
- **寄存器分配后调度 (`PostRA_Scheduler.cpp`)**:
- **目标**: 在寄存器分配完成之后,对指令序列进行最后一轮微调。此阶段调度的主要目标与分配前不同,它旨在解决由寄存器分配过程本身引入的性能问题,例如:
- **缓解溢出代价**: 将因溢出Spill而产生的 `load` 指令(从栈加载)尽可能地提前,远离其使用点;将 `store` 指令(存入栈)尽可能地推后,远离其定义点。
- **消除伪依赖**: 寄存器分配器可能会为两个原本不相关的虚拟寄存器分配同一个物理寄存器从而引入了虚假的写后读WAR或写后写WAW依赖。Post-RA 调度可以尝试解开这些伪依赖,为指令重排提供更多自由度。
- **实现**: `scheduleBlock()` 函数实现了此调度器。它采用了一种非常保守的**局部交换 (Local Swapping)** 策略。它迭代地检查相邻的两条指令,在 `canSwapInstructions()` 函数确认交换不会违反任何数据依赖RAW, WAR, WAW或内存依赖后才执行交换。这种方法虽然不如全局列表调度强大但在严格的 Post-RA 约束下是一种安全有效的优化手段。
#### 4.4.2. 强度削减 (Strength Reduction)
- **除法强度削减 (`DivStrengthReduction.cpp`)**:
- **目标**: 将机器指令中昂贵的 `DIV``DIVW` 指令(当除数为编译期常量时)替换为一系列更快、计算成本更低的指令组合。
- **技术**: 基于数论中的**乘法逆元 (Multiplicative Inverse)** 思想。对于一个整数除法 `x / d`,可以找到一个“魔数” `m` 和一个移位数 `s`,使得该除法可以被近似替换为 `(x * m) >> s`。这个过程需要处理复杂的符号、取整和溢出问题。
- **实现**: `runOnMachineFunction()` 实现了此优化。它会遍历机器指令,寻找以常量为除数的 `DIV`/`DIVW` 指令。`computeMagic()` 函数负责计算出对应的魔数和移位数。然后,根据除数是 2 的幂、1、-1 还是其他普通数字,生成不同的指令序列,包括 `MULH` (取高位乘积), `SRAI` (算术右移), `ADD`, `SUB` 等,来精确地模拟定点数除法的效果。
#### 4.4.3. 窥孔优化 (Peephole Optimization)
- **目标**: 在生成最终汇编代码之前,对相邻的机器指令序列进行局部优化,以消除冗余操作和利用目标机特性。
- **技术**: 窥孔优化是一种简单而高效的局部优化技术。它通过一个固定大小的“窥孔”(通常是 2-3 条指令)来扫描指令序列,寻找可以被更优指令序列替换的模式。
- **实现**: `PeepholeOptimizer::runOnMachineFunction()` 实现了此 Pass。它包含了一系列模式匹配和替换规则主要包括
- **冗余移动消除**: `mv x, y` 后跟着一条使用 `x` 的指令 `op z, x, ...`,如果 `x` 之后不再活跃,则将 `op` 的操作数直接替换为 `y`,并移除 `mv` 指令。
- **冗余加载消除**: `sw r1, mem; lw r2, mem` -> `sw r1, mem; mv r2, r1`。如果 `r1``r2` 是同一个寄存器,则直接移除 `lw`
- **地址计算优化**: `addi t1, base, imm1; lw t2, imm2(t1)` -> `lw t2, (imm1+imm2)(base)`。将两条指令合并为一条,减少了指令数量和中间寄存器的使用。
- **指令合并**: `addi t1, t0, imm1; addi t2, t1, imm2` -> `addi t2, t0, (imm1+imm2)`。合并连续的立即数加法。
### 4.5. 局限性与未来工作
根据项目中的 `TODO` 列表和源代码分析,当前实现存在一些可改进之处:
- **寄存器分配**:
- **`CALL` 指令处理**: 当前对 `CALL` 指令的 `use`/`def` 分析不完整,没有将所有调用者保存的寄存器标记为 `def`,这可能导致跨函数调用的值被错误破坏。
- **溢出处理**: 当前所有溢出的虚拟寄存器都被简单地映射到同一个物理寄存器 `t6` 上,这会引入大量不必要的 `load`/`store`,并可能导致 `t6` 成为性能瓶颈。
- **IR 设计**:
- 随着 SSA 的引入IR 中某些冗余信息(如基本块的 `args` 参数)可以被移除,以简化设计。
- **优化**:
- 当前的优化主要集中在标量上。可以引入更多面向循环的优化(如循环不变代码外提 LICM、归纳变量分析 IndVar和过程间优化来进一步提升性能。

View File

@@ -2,66 +2,67 @@
# runit-single.sh - 用于编译和测试单个或少量 SysY 程序的脚本
# 模仿 runit.sh 的功能,但以具体文件路径作为输入。
# 此脚本应该位于 mysysy/script/
export ASAN_OPTIONS=detect_leaks=0
# --- 配置区 ---
# 请根据你的环境修改这些路径
# 假设此脚本位于你的项目根目录或一个脚本目录中
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
# 默认寻找项目根目录下的 build 和 lib
BUILD_BIN_DIR="${SCRIPT_DIR}/../build/bin"
LIB_DIR="${SCRIPT_DIR}/../lib"
# 临时文件会存储在脚本所在目录的 tmp 子目录中
TMP_DIR="${SCRIPT_DIR}/tmp"
# 定义编译器和模拟器
SYSYC="${BUILD_BIN_DIR}/sysyc"
LLC_CMD="llc-19" # 新增
GCC_RISCV64="riscv64-linux-gnu-gcc"
QEMU_RISCV64="qemu-riscv64"
# --- 初始化变量 ---
EXECUTE_MODE=false
IR_EXECUTE_MODE=false # 新增
CLEAN_MODE=false
OPTIMIZE_FLAG="" # 用于存储 -O1 标志
SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒)
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
EXEC_TIMEOUT=5 # qemu 自动化执行超时 (秒)
MAX_OUTPUT_LINES=50 # 对比失败时显示的最大行数
SY_FILES=() # 存储用户提供的 .sy 文件列表
OPTIMIZE_FLAG=""
SYSYC_TIMEOUT=30
LLC_TIMEOUT=10 # 新增
GCC_TIMEOUT=10
EXEC_TIMEOUT=30
MAX_OUTPUT_LINES=20
SY_FILES=()
PASSED_CASES=0
FAILED_CASES_LIST=""
INTERRUPTED=false # 新增
# =================================================================
# --- 函数定义 ---
# =================================================================
show_help() {
echo "用法: $0 [文件1.sy] [文件2.sy] ... [选项]"
echo "编译并测试指定的 .sy 文件。"
echo ""
echo "如果找到对应的 .in/.out 文件,则进行自动化测试。否则,进入交互模式。"
echo "编译并测试指定的 .sy 文件。必须提供 -e 或 -eir 之一。"
echo ""
echo "选项:"
echo " -e, --executable 编译为可执行文件并运行测试 (必须)。"
echo " -e 通过汇编运行测试 (sysyc -> gcc -> qemu)。"
echo " -eir 通过IR运行测试 (sysyc -> llc -> gcc -> qemu)。"
echo " -c, --clean 清理 tmp 临时目录下的所有文件。"
echo " -O1 启用 sysyc 的 -O1 优化。"
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 10)。"
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 30)。"
echo " -lct N 设置 llc-19 编译超时为 N 秒 (默认: 10)。"
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
echo " -et N 设置 qemu 自动化执行超时为 N 秒 (默认: 5)。"
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 50)。"
echo " -et N 设置 qemu 自动化执行超时为 N 秒 (默认: 30)。"
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 20)。"
echo " -h, --help 显示此帮助信息并退出。"
echo ""
echo "可在任何时候按 Ctrl+C 来中断测试并显示当前已完成的测例总结。"
}
# --- 新增功能: 显示文件内容并根据行数截断 ---
display_file_content() {
local file_path="$1"
local title="$2"
local max_lines="$3"
if [ ! -f "$file_path" ]; then
return
fi
if [ ! -f "$file_path" ]; then return; fi
echo -e "$title"
local line_count
line_count=$(wc -l < "$file_path")
if [ "$line_count" -gt "$max_lines" ]; then
head -n "$max_lines" "$file_path"
echo -e "\e[33m[... 输出已截断,共 ${line_count} 行 ...]\e[0m"
@@ -70,55 +71,79 @@ display_file_content() {
fi
}
# --- 新增:总结报告函数 ---
print_summary() {
local total_cases=${#SY_FILES[@]}
echo ""
echo "======================================================================"
if [ "$INTERRUPTED" = true ]; then
echo -e "\e[33m测试被中断。正在汇总已完成的结果...\e[0m"
else
echo "所有测试完成"
fi
local failed_count
if [ -n "$FAILED_CASES_LIST" ]; then
failed_count=$(echo -e -n "${FAILED_CASES_LIST}" | wc -l)
else
failed_count=0
fi
local executed_count=$((PASSED_CASES + failed_count))
echo "测试结果: [通过: ${PASSED_CASES}, 失败: ${failed_count}, 已执行: ${executed_count}/${total_cases}]"
if [ -n "$FAILED_CASES_LIST" ]; then
echo ""
echo -e "\e[31m未通过的测例:\e[0m"
printf "%b" "${FAILED_CASES_LIST}"
fi
echo "======================================================================"
if [ "$failed_count" -gt 0 ]; then
exit 1
else
exit 0
fi
}
# --- 新增SIGINT 信号处理函数 ---
handle_sigint() {
INTERRUPTED=true
print_summary
}
# =================================================================
# --- 主逻辑开始 ---
# =================================================================
# --- 新增:设置 trap 来捕获 SIGINT ---
trap handle_sigint SIGINT
# --- 参数解析 ---
# 使用标准的 while 循环来健壮地处理任意顺序的参数
while [[ "$#" -gt 0 ]]; do
case "$1" in
-e|--executable)
EXECUTE_MODE=true
shift # 消耗选项
;;
-c|--clean)
CLEAN_MODE=true
shift # 消耗选项
;;
-O1)
OPTIMIZE_FLAG="-O1"
shift # 消耗选项
;;
-sct)
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift 2; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi
;;
-gct)
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift 2; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi
;;
-et)
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift 2; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi
;;
-ml|--max-lines)
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi
;;
-h|--help)
show_help
exit 0
;;
-*) # 未知选项
echo "未知选项: $1"
show_help
exit 1
;;
*) # 其他参数被视为文件路径
-e|--executable) EXECUTE_MODE=true; shift ;;
-eir) IR_EXECUTE_MODE=true; shift ;; # 新增
-c|--clean) CLEAN_MODE=true; shift ;;
-O1) OPTIMIZE_FLAG="-O1"; shift ;;
-lct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then LLC_TIMEOUT="$2"; shift 2; else echo "错误: -lct 需要一个正整数参数。" >&2; exit 1; fi ;; # 新增
-sct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift 2; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi ;;
-gct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift 2; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi ;;
-et) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift 2; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi ;;
-ml|--max-lines) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi ;;
-h|--help) show_help; exit 0 ;;
-*) echo "未知选项: $1"; show_help; exit 1 ;;
*)
if [[ -f "$1" && "$1" == *.sy ]]; then
SY_FILES+=("$1")
else
echo "警告: 无效文件或不是 .sy 文件,已忽略: $1"
fi
shift # 消耗文件参数
shift
;;
esac
done
if ${CLEAN_MODE}; then
echo "检测到 -c/--clean 选项,正在清空 ${TMP_DIR}..."
if [ -d "${TMP_DIR}" ]; then
@@ -127,19 +152,22 @@ if ${CLEAN_MODE}; then
else
echo "临时目录 ${TMP_DIR} 不存在,无需清理。"
fi
if [ ${#SY_FILES[@]} -eq 0 ] && ! ${EXECUTE_MODE}; then
if [ ${#SY_FILES[@]} -eq 0 ] && ! ${EXECUTE_MODE} && ! ${IR_EXECUTE_MODE}; then
exit 0
fi
fi
# --- 主逻辑开始 ---
if ! ${EXECUTE_MODE}; then
echo "错误: 请提供 -e 或 --executable 选项来运行测试。"
if ! ${EXECUTE_MODE} && ! ${IR_EXECUTE_MODE}; then
echo "错误: 请提供 -e 或 -eir 选项来运行测试。"
show_help
exit 1
fi
if ${EXECUTE_MODE} && ${IR_EXECUTE_MODE}; then
echo -e "\e[31m错误: -e 和 -eir 选项不能同时使用。\e[0m" >&2
exit 1
fi
if [ ${#SY_FILES[@]} -eq 0 ]; then
echo "错误: 未提供任何 .sy 文件作为输入。"
show_help
@@ -151,18 +179,17 @@ TOTAL_CASES=${#SY_FILES[@]}
echo "SysY 单例测试运行器启动..."
if [ -n "$OPTIMIZE_FLAG" ]; then echo "优化等级: ${OPTIMIZE_FLAG}"; fi
echo "超时设置: sysyc=${SYSYC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
echo "超时设置: sysyc=${SYSYC_TIMEOUT}s, llc=${LLC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
echo ""
for sy_file in "${SY_FILES[@]}"; do
is_passed=1
compilation_ok=1
base_name=$(basename "${sy_file}" .sy)
source_dir=$(dirname "${sy_file}")
ir_file="${TMP_DIR}/${base_name}_sysyc_riscv64.ll"
ir_file="${TMP_DIR}/${base_name}.ll"
assembly_file="${TMP_DIR}/${base_name}.s"
assembly_debug_file="${TMP_DIR}/${base_name}_d.s"
executable_file="${TMP_DIR}/${base_name}"
input_file="${source_dir}/${base_name}.in"
output_reference_file="${source_dir}/${base_name}.out"
@@ -171,47 +198,39 @@ for sy_file in "${SY_FILES[@]}"; do
echo "======================================================================"
echo "正在处理: ${sy_file}"
# --- 本次修改点: 拷贝源文件到 tmp 目录 ---
echo " 拷贝源文件到 ${TMP_DIR}..."
cp "${sy_file}" "${TMP_DIR}/$(basename "${sy_file}")"
if [ -f "${input_file}" ]; then
cp "${input_file}" "${TMP_DIR}/$(basename "${input_file}")"
fi
if [ -f "${output_reference_file}" ]; then
cp "${output_reference_file}" "${TMP_DIR}/$(basename "${output_reference_file}")"
fi
# 步骤 1: sysyc 编译
echo " 使用 sysyc 编译 (超时 ${SYSYC_TIMEOUT}s)..."
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" ${OPTIMIZE_FLAG} -o "${assembly_file}"
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" ${OPTIMIZE_FLAG} > "${ir_file}"
# timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s asmd "${sy_file}" > "${assembly_debug_file}" 2>&1
SYSYC_STATUS=$?
if [ $SYSYC_STATUS -eq 124 ]; then
echo -e "\e[31m错误: SysY 编译 ${sy_file} IR超时\e[0m"
is_passed=0
elif [ $SYSYC_STATUS -ne 0 ]; then
echo -e "\e[31m错误: SysY 编译 ${sy_file} IR失败退出码: ${SYSYC_STATUS}\e[0m"
is_passed=0
fi
if [ $? -ne 0 ]; then
echo -e "\e[31m错误: SysY 编译失败或超时。\e[0m"
is_passed=0
fi
# --- 编译阶段 ---
if ${IR_EXECUTE_MODE}; then
# 路径1: sysyc -> llc -> gcc
echo " [1/3] 使用 sysyc 编译为 IR (超时 ${SYSYC_TIMEOUT}s)..."
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" ${OPTIMIZE_FLAG} -o "${ir_file}"
if [ $? -ne 0 ]; then echo -e "\e[31m错误: SysY (IR) 编译失败或超时。\e[0m"; compilation_ok=0; fi
# 步骤 2: GCC 编译
if [ "$is_passed" -eq 1 ]; then
echo " 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
if [ $? -ne 0 ]; then
echo -e "\e[31m错误: GCC 编译失败或超时。\e[0m"
is_passed=0
if [ "$compilation_ok" -eq 1 ]; then
echo " [2/3] 使用 llc 编译为汇编 (超时 ${LLC_TIMEOUT}s)..."
timeout -s KILL ${LLC_TIMEOUT} "${LLC_CMD}" -march=riscv64 -mcpu=generic-rv64 -mattr=+m,+a,+f,+d,+c -filetype=asm "${ir_file}" -o "${assembly_file}"
if [ $? -ne 0 ]; then echo -e "\e[31m错误: llc 编译失败或超时。\e[0m"; compilation_ok=0; fi
fi
if [ "$compilation_ok" -eq 1 ]; then
echo " [3/3] 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
if [ $? -ne 0 ]; then echo -e "\e[31m错误: GCC 编译失败或超时。\e[0m"; compilation_ok=0; fi
fi
else # EXECUTE_MODE
# 路径2: sysyc -> gcc
echo " [1/2] 使用 sysyc 编译为汇编 (超时 ${SYSYC_TIMEOUT}s)..."
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" ${OPTIMIZE_FLAG} -o "${assembly_file}"
if [ $? -ne 0 ]; then echo -e "\e[31m错误: SysY (汇编) 编译失败或超时。\e[0m"; compilation_ok=0; fi
if [ "$compilation_ok" -eq 1 ]; then
echo " [2/2] 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
if [ $? -ne 0 ]; then echo -e "\e[31m错误: GCC 编译失败或超时。\e[0m"; compilation_ok=0; fi
fi
fi
# 步骤 3: 执行与测试
if [ "$is_passed" -eq 1 ]; then
# 检查是自动化测试还是交互模式
# --- 执行与测试阶段 (公共逻辑) ---
if [ "$compilation_ok" -eq 1 ]; then
if [ -f "${input_file}" ] || [ -f "${output_reference_file}" ]; then
# --- 自动化测试模式 ---
echo " 检测到 .in/.out 文件,进入自动化测试模式..."
@@ -234,24 +253,26 @@ for sy_file in "${SY_FILES[@]}"; do
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
EXPECTED_STDOUT_FILE="${TMP_DIR}/${base_name}.expected_stdout"
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
if [ "$ACTUAL_RETURN_CODE" -ne "$EXPECTED_RETURN_CODE" ]; then echo -e "\e[31m 返回码测试失败: 期望 ${EXPECTED_RETURN_CODE}, 实际 ${ACTUAL_RETURN_CODE}\e[0m"; is_passed=0; fi
ret_ok=1
if [ "$ACTUAL_RETURN_CODE" -ne "$EXPECTED_RETURN_CODE" ]; then echo -e "\e[31m 返回码测试失败: 期望 ${EXPECTED_RETURN_CODE}, 实际 ${ACTUAL_RETURN_CODE}\e[0m"; ret_ok=0; fi
out_ok=1
if ! diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
echo -e "\e[31m 标准输出测试失败。\e[0m"
is_passed=0
echo -e "\e[31m 标准输出测试失败。\e[0m"; out_ok=0
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
echo -e " \e[36m----------------\e[0m"
fi
if [ "$ret_ok" -eq 1 ] && [ "$out_ok" -eq 1 ]; then echo -e "\e[32m 返回码与标准输出测试成功。\e[0m"; else is_passed=0; fi
else
if diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
echo -e "\e[32m 标准输出测试成功。\e[0m"
else
echo -e "\e[31m 标准输出测试失败。\e[0m"
is_passed=0
echo -e "\e[31m 标准输出测试失败。\e[0m"; is_passed=0
display_file_content "${output_reference_file}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
echo -e " \e[36m----------------\e[0m"
fi
fi
else
@@ -260,20 +281,16 @@ for sy_file in "${SY_FILES[@]}"; do
fi
else
# --- 交互模式 ---
echo -e "\e[33m"
echo " **********************************************************"
echo " ** 未找到 .in 或 .out 文件,进入交互模式。 **"
echo " ** 程序即将运行,你可以直接在终端中输入。 **"
echo " ** 按下 Ctrl+D (EOF) 或以其他方式结束程序以继续。 **"
echo " **********************************************************"
echo -e "\e[0m"
echo -e "\e[33m\n 未找到 .in 或 .out 文件,进入交互模式...\e[0m"
"${QEMU_RISCV64}" "${executable_file}"
INTERACTIVE_RET_CODE=$?
echo -e "\e[33m\n 交互模式执行完毕,程序返回码: ${INTERACTIVE_RET_CODE}\e[0m"
echo " 注意: 交互模式的结果未经验证。"
echo -e "\e[33m\n 交互模式执行完毕,程序返回码: ${INTERACTIVE_RET_CODE} (此结果未经验证)\e[0m"
fi
else
is_passed=0
fi
# --- 状态总结 ---
if [ "$is_passed" -eq 1 ]; then
echo -e "\e[32m状态: 通过\e[0m"
((PASSED_CASES++))
@@ -284,20 +301,4 @@ for sy_file in "${SY_FILES[@]}"; do
done
# --- 打印最终总结 ---
echo "======================================================================"
echo "所有测试完成"
echo "测试通过率: [${PASSED_CASES}/${TOTAL_CASES}]"
if [ -n "$FAILED_CASES_LIST" ]; then
echo ""
echo -e "\e[31m未通过的测例:\e[0m"
echo -e "${FAILED_CASES_LIST}"
fi
echo "======================================================================"
if [ "$PASSED_CASES" -eq "$TOTAL_CASES" ]; then
exit 0
else
exit 1
fi
print_summary

View File

@@ -1,31 +1,41 @@
#!/bin/bash
# runit.sh - 用于编译和测试 SysY 程序的脚本
# 此脚本应该位于 mysysy/test_script/
# 此脚本应该位于 mysysy/script/
export ASAN_OPTIONS=detect_leaks=0
# 定义相对于脚本位置的目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
TESTDATA_DIR="${SCRIPT_DIR}/../testdata"
BUILD_BIN_DIR="${SCRIPT_DIR}/../build/bin"
LIB_DIR="${SCRIPT_DIR}/../lib"
# TMP_DIR="${SCRIPT_DIR}/tmp"
TMP_DIR="${SCRIPT_DIR}/tmp"
# 定义编译器和模拟器
SYSYC="${BUILD_BIN_DIR}/sysyc"
LLC_CMD="llc-19"
GCC_RISCV64="riscv64-linux-gnu-gcc"
QEMU_RISCV64="qemu-riscv64"
# --- 状态变量 ---
EXECUTE_MODE=false
OPTIMIZE_FLAG="" # 用于存储 -O1 标志
SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒)
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
EXEC_TIMEOUT=5 # qemu 执行超时 (秒)
MAX_OUTPUT_LINES=50 # 对比失败时显示的最大行数
TEST_SETS=() # 用于存储要运行的测试集
IR_EXECUTE_MODE=false
OPTIMIZE_FLAG=""
SYSYC_TIMEOUT=30
LLC_TIMEOUT=10
GCC_TIMEOUT=10
EXEC_TIMEOUT=30
MAX_OUTPUT_LINES=20
TEST_SETS=()
TOTAL_CASES=0
PASSED_CASES=0
FAILED_CASES_LIST="" # 用于存储未通过的测例列表
FAILED_CASES_LIST=""
INTERRUPTED=false # 新增:用于标记是否被中断
# =================================================================
# --- 函数定义 ---
# =================================================================
# 显示帮助信息的函数
show_help() {
@@ -33,31 +43,32 @@ show_help() {
echo "此脚本用于按文件名前缀数字升序编译和测试 .sy 文件。"
echo ""
echo "选项:"
echo " -e, --executable 编译为可执行文件并运行测试。"
echo " -e, --executable 编译为汇编并运行测试 (sysyc -> gcc -> qemu)。"
echo " -eir 通过IR编译为可执行文件并运行测试 (sysyc -> llc -> gcc -> qemu)。"
echo " -c, --clean 清理 'tmp' 目录下的所有生成文件。"
echo " -O1 启用 sysyc 的 -O1 优化。"
echo " -set [f|h|p|all]... 指定要运行的测试集 (functional, h_functional, performance)。可多选,默认为 all。"
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 10)。"
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 30)。"
echo " -lct N 设置 llc-19 编译超时为 N 秒 (默认: 10)。"
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
echo " -et N 设置 qemu 执行超时为 N 秒 (默认: 5)。"
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 50)。"
echo " -et N 设置 qemu 执行超时为 N 秒 (默认: 30)。"
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 20)。"
echo " -h, --help 显示此帮助信息并退出。"
echo ""
echo "注意: 默认行为 (无 -e 或 -eir) 是将 .sy 文件同时编译为 .s (汇编) 和 .ll (IR),不执行。"
echo " 可在任何时候按 Ctrl+C 来中断测试并显示当前已完成的测例总结。"
}
# 显示文件内容并根据行数截断的函数
display_file_content() {
local file_path="$1"
local title="$2"
local max_lines="$3"
if [ ! -f "$file_path" ]; then
return
fi
if [ ! -f "$file_path" ]; then return; fi
echo -e "$title"
local line_count
line_count=$(wc -l < "$file_path")
if [ "$line_count" -gt "$max_lines" ]; then
head -n "$max_lines" "$file_path"
echo -e "\e[33m[... 输出已截断,共 ${line_count} 行 ...]\e[0m"
@@ -72,63 +83,90 @@ clean_tmp() {
rm -rf "${TMP_DIR}"/*
}
# 如果临时目录不存在,则创建它
# --- 新增:总结报告函数 ---
print_summary() {
echo "" # 确保从新的一行开始
echo "========================================"
if [ "$INTERRUPTED" = true ]; then
echo -e "\e[33m测试被中断。正在汇总已完成的结果...\e[0m"
else
echo "测试完成"
fi
local failed_count
if [ -n "$FAILED_CASES_LIST" ]; then
# `wc -l` 计算由换行符分隔的列表项数
failed_count=$(echo -e -n "${FAILED_CASES_LIST}" | wc -l)
else
failed_count=0
fi
local executed_count=$((PASSED_CASES + failed_count))
echo "测试结果: [通过: ${PASSED_CASES}, 失败: ${failed_count}, 已执行: ${executed_count}/${TOTAL_CASES}]"
if [ -n "$FAILED_CASES_LIST" ]; then
echo ""
echo -e "\e[31m未通过的测例:\e[0m"
# 使用 printf 保证原样输出
printf "%b" "${FAILED_CASES_LIST}"
fi
echo "========================================"
if [ "$failed_count" -gt 0 ]; then
exit 1
else
exit 0
fi
}
# --- 新增SIGINT 信号处理函数 ---
handle_sigint() {
INTERRUPTED=true
print_summary
}
# =================================================================
# --- 主逻辑开始 ---
# =================================================================
# --- 新增:设置 trap 来捕获 SIGINT ---
trap handle_sigint SIGINT
mkdir -p "${TMP_DIR}"
# 解析命令行参数
while [[ "$#" -gt 0 ]]; do
case "$1" in
-e|--executable)
EXECUTE_MODE=true
shift
;;
-c|--clean)
clean_tmp
exit 0
;;
-O1)
OPTIMIZE_FLAG="-O1"
shift
;;
-e|--executable) EXECUTE_MODE=true; shift ;;
-eir) IR_EXECUTE_MODE=true; shift ;;
-c|--clean) clean_tmp; exit 0 ;;
-O1) OPTIMIZE_FLAG="-O1"; shift ;;
-set)
shift # 移过 '-set'
while [[ "$#" -gt 0 && ! "$1" =~ ^- ]]; do
TEST_SETS+=("$1")
shift
done
;;
-sct)
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift 2; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi
;;
-gct)
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift 2; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi
;;
-et)
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift 2; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi
;;
-ml|--max-lines)
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi
;;
-h|--help)
show_help
exit 0
;;
*)
echo "未知选项: $1"
show_help
exit 1
shift
while [[ "$#" -gt 0 && ! "$1" =~ ^- ]]; do TEST_SETS+=("$1"); shift; done
;;
-sct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift 2; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi ;;
-lct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then LLC_TIMEOUT="$2"; shift 2; else echo "错误: -lct 需要一个正整数参数。" >&2; exit 1; fi ;;
-gct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift 2; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi ;;
-et) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift 2; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi ;;
-ml|--max-lines) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi ;;
-h|--help) show_help; exit 0 ;;
*) echo "未知选项: $1"; show_help; exit 1 ;;
esac
done
# --- 本次修改点: 根据 -set 参数构建查找路径 ---
if ${EXECUTE_MODE} && ${IR_EXECUTE_MODE}; then
echo -e "\e[31m错误: -e 和 -eir 选项不能同时使用。\e[0m" >&2
exit 1
fi
declare -A SET_MAP
SET_MAP[f]="functional"
SET_MAP[h]="h_functional"
SET_MAP[p]="performance"
SEARCH_PATHS=()
if [ ${#TEST_SETS[@]} -eq 0 ] || [[ " ${TEST_SETS[@]} " =~ " all " ]]; then
SEARCH_PATHS+=("${TESTDATA_DIR}")
else
@@ -150,9 +188,21 @@ echo "SysY 测试运行器启动..."
if [ -n "$OPTIMIZE_FLAG" ]; then echo "优化等级: ${OPTIMIZE_FLAG}"; fi
echo "输入目录: ${SEARCH_PATHS[@]}"
echo "临时目录: ${TMP_DIR}"
echo "执行模式: ${EXECUTE_MODE}"
if ${EXECUTE_MODE}; then
echo "超时设置: sysyc=${SYSYC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
RUN_MODE_INFO=""
if ${IR_EXECUTE_MODE}; then
RUN_MODE_INFO="IR执行模式 (-eir)"
TIMEOUT_INFO="超时设置: sysyc=${SYSYC_TIMEOUT}s, llc=${LLC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
elif ${EXECUTE_MODE}; then
RUN_MODE_INFO="直接执行模式 (-e)"
TIMEOUT_INFO="超时设置: sysyc=${SYSYC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
else
RUN_MODE_INFO="编译模式 (默认)"
TIMEOUT_INFO="超时设置: sysyc=${SYSYC_TIMEOUT}s"
fi
echo "运行模式: ${RUN_MODE_INFO}"
echo "${TIMEOUT_INFO}"
if ${EXECUTE_MODE} || ${IR_EXECUTE_MODE}; then
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
fi
echo ""
@@ -165,132 +215,228 @@ fi
TOTAL_CASES=$(echo "$sy_files" | wc -w)
while IFS= read -r sy_file; do
is_passed=1 # 1 表示通过, 0 表示失败
is_passed=0 # 0 表示失败, 1 表示通过
relative_path_no_ext=$(realpath --relative-to="${TESTDATA_DIR}" "${sy_file%.*}")
output_base_name=$(echo "${relative_path_no_ext}" | tr '/' '_')
assembly_file="${TMP_DIR}/${output_base_name}_sysyc_riscv64.s"
executable_file="${TMP_DIR}/${output_base_name}_sysyc_riscv64"
assembly_file_S="${TMP_DIR}/${output_base_name}_sysyc_S.s"
executable_file_S="${TMP_DIR}/${output_base_name}_sysyc_S"
output_actual_file_S="${TMP_DIR}/${output_base_name}_sysyc_S.actual_out"
ir_file="${TMP_DIR}/${output_base_name}_sysyc_ir.ll"
assembly_file_from_ir="${TMP_DIR}/${output_base_name}_from_ir.s"
executable_file_from_ir="${TMP_DIR}/${output_base_name}_from_ir"
output_actual_file_from_ir="${TMP_DIR}/${output_base_name}_from_ir.actual_out"
input_file="${sy_file%.*}.in"
output_reference_file="${sy_file%.*}.out"
output_actual_file="${TMP_DIR}/${output_base_name}_sysyc_riscv64.actual_out"
echo "正在处理: $(basename "$sy_file") (路径: ${relative_path_no_ext}.sy)"
echo " 使用 sysyc 编译 (超时 ${SYSYC_TIMEOUT}s)..."
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file}" ${OPTIMIZE_FLAG}
SYSYC_STATUS=$?
if [ $SYSYC_STATUS -eq 124 ]; then
echo -e "\e[31m错误: SysY 编译 ${sy_file} 超时\e[0m"
is_passed=0
elif [ $SYSYC_STATUS -ne 0 ]; then
echo -e "\e[31m错误: SysY 编译 ${sy_file} 失败,退出码: ${SYSYC_STATUS}\e[0m"
is_passed=0
fi
if ${EXECUTE_MODE} && [ "$is_passed" -eq 1 ]; then
echo " 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
GCC_STATUS=$?
if [ $GCC_STATUS -eq 124 ]; then
echo -e "\e[31m错误: GCC 编译 ${assembly_file} 超时\e[0m"
is_passed=0
elif [ $GCC_STATUS -ne 0 ]; then
echo -e "\e[31m错误: GCC 编译 ${assembly_file} 失败,退出码: ${GCC_STATUS}\e[0m"
is_passed=0
# --- 模式 1: IR 执行模式 (-eir) ---
if ${IR_EXECUTE_MODE}; then
step_failed=0
test_logic_passed=0
echo " [1/4] 使用 sysyc 编译为 IR (超时 ${SYSYC_TIMEOUT}s)..."
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" -o "${ir_file}" ${OPTIMIZE_FLAG}
SYSYC_STATUS=$?
if [ $SYSYC_STATUS -ne 0 ]; then
[ $SYSYC_STATUS -eq 124 ] && echo -e "\e[31m错误: SysY (IR) 编译超时\e[0m" || echo -e "\e[31m错误: SysY (IR) 编译失败,退出码: ${SYSYC_STATUS}\e[0m"
step_failed=1
fi
elif ! ${EXECUTE_MODE}; then
echo " 跳过执行模式。仅生成汇编文件。"
if [ "$is_passed" -eq 1 ]; then
((PASSED_CASES++))
else
FAILED_CASES_LIST+="${relative_path_no_ext}.sy\n"
fi
echo ""
continue
fi
if [ "$is_passed" -eq 1 ]; then
echo " 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
exec_cmd="${QEMU_RISCV64} \"${executable_file}\""
if [ -f "${input_file}" ]; then
exec_cmd+=" < \"${input_file}\""
fi
exec_cmd+=" > \"${output_actual_file}\""
eval "timeout -s KILL ${EXEC_TIMEOUT} ${exec_cmd}"
ACTUAL_RETURN_CODE=$?
if [ "$ACTUAL_RETURN_CODE" -eq 124 ]; then
echo -e "\e[31m 执行超时: ${sy_file} 运行超过 ${EXEC_TIMEOUT} 秒\e[0m"
is_passed=0
else
if [ -f "${output_reference_file}" ]; then
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
if [[ "$LAST_LINE_TRIMMED" =~ ^[-+]?[0-9]+$ ]]; then
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
EXPECTED_STDOUT_FILE="${TMP_DIR}/${output_base_name}_sysyc_riscv64.expected_stdout"
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
if [ "$ACTUAL_RETURN_CODE" -eq "$EXPECTED_RETURN_CODE" ]; then
echo -e "\e[32m 返回码测试成功: (${ACTUAL_RETURN_CODE}) 与期望值 (${EXPECTED_RETURN_CODE}) 匹配\e[0m"
else
echo -e "\e[31m 返回码测试失败: 期望: ${EXPECTED_RETURN_CODE}, 实际: ${ACTUAL_RETURN_CODE}\e[0m"
is_passed=0
fi
if ! diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
echo -e "\e[31m 标准输出测试失败\e[0m"
is_passed=0
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
display_file_content "${output_actual_file}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
echo -e " \e[36m------------------------------\e[0m"
fi
else
if [ $ACTUAL_RETURN_CODE -ne 0 ]; then
echo -e "\e[33m警告: 程序以非零状态 ${ACTUAL_RETURN_CODE} 退出 (纯输出比较模式)。\e[0m"
fi
if diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
else
echo -e "\e[31m 失败: 输出不匹配\e[0m"
is_passed=0
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
display_file_content "${output_actual_file}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
echo -e " \e[36m------------------------------\e[0m"
fi
fi
else
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
if [ "$step_failed" -eq 0 ]; then
echo " [2/4] 使用 llc-19 编译为汇编 (超时 ${LLC_TIMEOUT}s)..."
timeout -s KILL ${LLC_TIMEOUT} "${LLC_CMD}" -march=riscv64 -mcpu=generic-rv64 -mattr=+m,+a,+f,+d,+c -filetype=asm "${ir_file}" -o "${assembly_file_from_ir}"
LLC_STATUS=$?
if [ $LLC_STATUS -ne 0 ]; then
[ $LLC_STATUS -eq 124 ] && echo -e "\e[31m错误: llc-19 编译超时\e[0m" || echo -e "\e[31m错误: llc-19 编译失败,退出码: ${LLC_STATUS}\e[0m"
step_failed=1
fi
fi
if [ "$step_failed" -eq 0 ]; then
echo " [3/4] 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file_from_ir}" -o "${executable_file_from_ir}" -L"${LIB_DIR}" -lsysy_riscv -static
GCC_STATUS=$?
if [ $GCC_STATUS -ne 0 ]; then
[ $GCC_STATUS -eq 124 ] && echo -e "\e[31m错误: GCC 编译超时\e[0m" || echo -e "\e[31m错误: GCC 编译失败,退出码: ${GCC_STATUS}\e[0m"
step_failed=1
fi
fi
if [ "$step_failed" -eq 0 ]; then
echo " [4/4] 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
exec_cmd="${QEMU_RISCV64} \"${executable_file_from_ir}\""
[ -f "${input_file}" ] && exec_cmd+=" < \"${input_file}\""
exec_cmd+=" > \"${output_actual_file_from_ir}\""
eval "timeout -s KILL ${EXEC_TIMEOUT} ${exec_cmd}"
ACTUAL_RETURN_CODE=$?
if [ "$ACTUAL_RETURN_CODE" -eq 124 ]; then
echo -e "\e[31m 执行超时: 运行超过 ${EXEC_TIMEOUT} 秒\e[0m"
else
if [ -f "${output_reference_file}" ]; then
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
test_logic_passed=1
if [[ "$LAST_LINE_TRIMMED" =~ ^[-+]?[0-9]+$ ]]; then
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
EXPECTED_STDOUT_FILE="${TMP_DIR}/${output_base_name}_from_ir.expected_stdout"
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
if [ "$ACTUAL_RETURN_CODE" -eq "$EXPECTED_RETURN_CODE" ]; then
echo -e "\e[32m 返回码测试成功: (${ACTUAL_RETURN_CODE}) 与期望值 (${EXPECTED_RETURN_CODE}) 匹配\e[0m"
else
echo -e "\e[31m 返回码测试失败: 期望: ${EXPECTED_RETURN_CODE}, 实际: ${ACTUAL_RETURN_CODE}\e[0m"
test_logic_passed=0
fi
if diff -q <(tr -d '[:space:]' < "${output_actual_file_from_ir}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
[ "$test_logic_passed" -eq 1 ] && echo -e "\e[32m 标准输出测试成功\e[0m"
else
echo -e "\e[31m 标准输出测试失败\e[0m"
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
display_file_content "${output_actual_file_from_ir}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
test_logic_passed=0
fi
else
if [ $ACTUAL_RETURN_CODE -ne 0 ]; then echo -e "\e[33m警告: 程序以非零状态 ${ACTUAL_RETURN_CODE} 退出 (纯输出比较模式)。\e[0m"; fi
if diff -q <(tr -d '[:space:]' < "${output_actual_file_from_ir}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
else
echo -e "\e[31m 失败: 输出不匹配\e[0m"
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
display_file_content "${output_actual_file_from_ir}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
test_logic_passed=0
fi
fi
else
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
test_logic_passed=1
fi
fi
fi
[ "$step_failed" -eq 0 ] && [ "$test_logic_passed" -eq 1 ] && is_passed=1
# --- 模式 2: 直接执行模式 (-e) ---
elif ${EXECUTE_MODE}; then
step_failed=0
test_logic_passed=0
echo " [1/3] 使用 sysyc 编译为汇编 (超时 ${SYSYC_TIMEOUT}s)..."
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file_S}" ${OPTIMIZE_FLAG}
SYSYC_STATUS=$?
if [ $SYSYC_STATUS -ne 0 ]; then
[ $SYSYC_STATUS -eq 124 ] && echo -e "\e[31m错误: SysY (汇编) 编译超时\e[0m" || echo -e "\e[31m错误: SysY (汇编) 编译失败,退出码: ${SYSYC_STATUS}\e[0m"
step_failed=1
fi
if [ "$step_failed" -eq 0 ]; then
echo " [2/3] 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file_S}" -o "${executable_file_S}" -L"${LIB_DIR}" -lsysy_riscv -static
GCC_STATUS=$?
if [ $GCC_STATUS -ne 0 ]; then
[ $GCC_STATUS -eq 124 ] && echo -e "\e[31m错误: GCC 编译超时\e[0m" || echo -e "\e[31m错误: GCC 编译失败,退出码: ${GCC_STATUS}\e[0m"
step_failed=1
fi
fi
if [ "$step_failed" -eq 0 ]; then
echo " [3/3] 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
exec_cmd="${QEMU_RISCV64} \"${executable_file_S}\""
[ -f "${input_file}" ] && exec_cmd+=" < \"${input_file}\""
exec_cmd+=" > \"${output_actual_file_S}\""
eval "timeout -s KILL ${EXEC_TIMEOUT} ${exec_cmd}"
ACTUAL_RETURN_CODE=$?
if [ "$ACTUAL_RETURN_CODE" -eq 124 ]; then
echo -e "\e[31m 执行超时: 运行超过 ${EXEC_TIMEOUT} 秒\e[0m"
else
if [ -f "${output_reference_file}" ]; then
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
test_logic_passed=1
if [[ "$LAST_LINE_TRIMMED" =~ ^[-+]?[0-9]+$ ]]; then
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
EXPECTED_STDOUT_FILE="${TMP_DIR}/${output_base_name}_sysyc_S.expected_stdout"
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
if [ "$ACTUAL_RETURN_CODE" -eq "$EXPECTED_RETURN_CODE" ]; then
echo -e "\e[32m 返回码测试成功: (${ACTUAL_RETURN_CODE}) 与期望值 (${EXPECTED_RETURN_CODE}) 匹配\e[0m"
else
echo -e "\e[31m 返回码测试失败: 期望: ${EXPECTED_RETURN_CODE}, 实际: ${ACTUAL_RETURN_CODE}\e[0m"
test_logic_passed=0
fi
if diff -q <(tr -d '[:space:]' < "${output_actual_file_S}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
[ "$test_logic_passed" -eq 1 ] && echo -e "\e[32m 标准输出测试成功\e[0m"
else
echo -e "\e[31m 标准输出测试失败\e[0m"
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
display_file_content "${output_actual_file_S}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
test_logic_passed=0
fi
else
if [ $ACTUAL_RETURN_CODE -ne 0 ]; then echo -e "\e[33m警告: 程序以非零状态 ${ACTUAL_RETURN_CODE} 退出 (纯输出比较模式)。\e[0m"; fi
if diff -q <(tr -d '[:space:]' < "${output_actual_file_S}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
else
echo -e "\e[31m 失败: 输出不匹配\e[0m"
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
display_file_content "${output_actual_file_S}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
test_logic_passed=0
fi
fi
else
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
test_logic_passed=1
fi
fi
fi
[ "$step_failed" -eq 0 ] && [ "$test_logic_passed" -eq 1 ] && is_passed=1
# --- 模式 3: 默认编译模式 ---
else
s_compile_ok=0
ir_compile_ok=0
echo " [1/2] 使用 sysyc 编译为汇编 (超时 ${SYSYC_TIMEOUT}s)..."
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file_S}" ${OPTIMIZE_FLAG}
SYSYC_S_STATUS=$?
if [ $SYSYC_S_STATUS -eq 0 ]; then
s_compile_ok=1
echo -e " \e[32m-> ${assembly_file_S} [成功]\e[0m"
else
[ $SYSYC_S_STATUS -eq 124 ] && echo -e " \e[31m-> [编译超时]\e[0m" || echo -e " \e[31m-> [编译失败, 退出码: ${SYSYC_S_STATUS}]\e[0m"
fi
echo " [2/2] 使用 sysyc 编译为 IR (超时 ${SYSYC_TIMEOUT}s)..."
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" -o "${ir_file}" ${OPTIMIZE_FLAG}
SYSYC_IR_STATUS=$?
if [ $SYSYC_IR_STATUS -eq 0 ]; then
ir_compile_ok=1
echo -e " \e[32m-> ${ir_file} [成功]\e[0m"
else
[ $SYSYC_IR_STATUS -eq 124 ] && echo -e " \e[31m-> [编译超时]\e[0m" || echo -e " \e[31m-> [编译失败, 退出码: ${SYSYC_IR_STATUS}]\e[0m"
fi
if [ "$s_compile_ok" -eq 1 ] && [ "$ir_compile_ok" -eq 1 ]; then
is_passed=1
fi
fi
# --- 统计结果 ---
if [ "$is_passed" -eq 1 ]; then
((PASSED_CASES++))
else
# 确保 FAILED_CASES_LIST 的每一项都以换行符结尾
FAILED_CASES_LIST+="${relative_path_no_ext}.sy\n"
fi
echo ""
done <<< "$sy_files"
echo "========================================"
echo "测试完成"
echo "测试通过率: [${PASSED_CASES}/${TOTAL_CASES}]"
if [ -n "$FAILED_CASES_LIST" ]; then
echo ""
echo -e "\e[31m未通过的测例:\e[0m"
echo -e "${FAILED_CASES_LIST}"
fi
echo "========================================"
if [ "$PASSED_CASES" -eq "$TOTAL_CASES" ]; then
exit 0
else
exit 1
fi
# --- 修改:调用总结函数 ---
print_summary

View File

@@ -4,6 +4,7 @@
namespace sysy {
char PeepholeOptimizer::ID = 0;
bool PeepholeOptimizer::fusedMulAddEnabled = true; // 默认启用浮点乘加融合优化
bool PeepholeOptimizer::runOnFunction(Function *F, AnalysisManager& AM) {
// This pass works on MachineFunction level, not IR level
@@ -634,6 +635,99 @@ void PeepholeOptimizer::runOnMachineFunction(MachineFunction *mfunc) {
}
}
}
// 8. 浮点乘加融合优化
// 8.1 fmul.s t1, t2, t3; fadd.s t4, t1, t5 -> fmadd.s t4, t2, t3, t5
else if (isFusedMulAddEnabled() &&
mi1->getOpcode() == RVOpcodes::FMUL_S &&
mi2->getOpcode() == RVOpcodes::FADD_S) {
if (mi1->getOperands().size() == 3 && mi2->getOperands().size() == 3) {
auto *fmul_dst = static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *fmul_src1 = static_cast<RegOperand *>(mi1->getOperands()[1].get());
auto *fmul_src2 = static_cast<RegOperand *>(mi1->getOperands()[2].get());
auto *fadd_dst = static_cast<RegOperand *>(mi2->getOperands()[0].get());
auto *fadd_src1 = static_cast<RegOperand *>(mi2->getOperands()[1].get());
auto *fadd_src2 = static_cast<RegOperand *>(mi2->getOperands()[2].get());
// 检查fmul的目标是否是fadd的第一个源操作数
if (areRegsEqual(fmul_dst, fadd_src1)) {
// 检查中间寄存器是否在后续还会被使用
bool canOptimize = true;
for (size_t j = i + 2; j < instrs.size(); ++j) {
auto *later_instr = instrs[j].get();
// 如果中间寄存器被重新定义,则可以优化
if (isRegRedefinedAt(later_instr, fmul_dst, areRegsEqual)) {
break;
}
// 如果中间寄存器被使用,则不能优化
if (isRegUsedLater(instrs, fmul_dst, j)) {
canOptimize = false;
break;
}
}
if (canOptimize) {
// 创建新的FMADD_S指令: fmadd.s t4, t2, t3, t5
auto newInstr = std::make_unique<MachineInstr>(RVOpcodes::FMADD_S);
newInstr->addOperand(std::make_unique<RegOperand>(*fadd_dst));
newInstr->addOperand(std::make_unique<RegOperand>(*fmul_src1));
newInstr->addOperand(std::make_unique<RegOperand>(*fmul_src2));
newInstr->addOperand(std::make_unique<RegOperand>(*fadd_src2));
instrs[i + 1] = std::move(newInstr);
instrs.erase(instrs.begin() + i);
changed = true;
}
}
}
}
// 8.2 fmul.s t1, t2, t3; fadd.s t4, t5, t1 -> fmadd.s t4, t2, t3, t5
else if (isFusedMulAddEnabled() &&
mi1->getOpcode() == RVOpcodes::FMUL_S &&
mi2->getOpcode() == RVOpcodes::FADD_S) {
if (mi1->getOperands().size() == 3 && mi2->getOperands().size() == 3) {
auto *fmul_dst = static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *fmul_src1 = static_cast<RegOperand *>(mi1->getOperands()[1].get());
auto *fmul_src2 = static_cast<RegOperand *>(mi1->getOperands()[2].get());
auto *fadd_dst = static_cast<RegOperand *>(mi2->getOperands()[0].get());
auto *fadd_src1 = static_cast<RegOperand *>(mi2->getOperands()[1].get());
auto *fadd_src2 = static_cast<RegOperand *>(mi2->getOperands()[2].get());
// 检查fmul的目标是否是fadd的第二个源操作数
if (areRegsEqual(fmul_dst, fadd_src2)) {
// 检查中间寄存器是否在后续还会被使用
bool canOptimize = true;
for (size_t j = i + 2; j < instrs.size(); ++j) {
auto *later_instr = instrs[j].get();
// 如果中间寄存器被重新定义,则可以优化
if (isRegRedefinedAt(later_instr, fmul_dst, areRegsEqual)) {
break;
}
// 如果中间寄存器被使用,则不能优化
if (isRegUsedLater(instrs, fmul_dst, j)) {
canOptimize = false;
break;
}
}
if (canOptimize) {
// 创建新的FMADD_S指令: fmadd.s t4, t2, t3, t5
auto newInstr = std::make_unique<MachineInstr>(RVOpcodes::FMADD_S);
newInstr->addOperand(std::make_unique<RegOperand>(*fadd_dst));
newInstr->addOperand(std::make_unique<RegOperand>(*fmul_src1));
newInstr->addOperand(std::make_unique<RegOperand>(*fmul_src2));
newInstr->addOperand(std::make_unique<RegOperand>(*fadd_src1));
instrs[i + 1] = std::move(newInstr);
instrs.erase(instrs.begin() + i);
changed = true;
}
}
}
}
// 根据是否发生变化调整遍历索引
if (!changed) {

View File

@@ -79,6 +79,7 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
case RVOpcodes::FSUB_S: *OS << "fsub.s "; break;
case RVOpcodes::FMUL_S: *OS << "fmul.s "; break;
case RVOpcodes::FDIV_S: *OS << "fdiv.s "; break;
case RVOpcodes::FMADD_S: *OS << "fmadd.s "; break;
case RVOpcodes::FNEG_S: *OS << "fneg.s "; break;
case RVOpcodes::FEQ_S: *OS << "feq.s "; break;
case RVOpcodes::FLT_S: *OS << "flt.s "; break;

View File

@@ -188,13 +188,11 @@ std::string RISCv64CodeGen::module_gen() {
ss << ".text\n";
for (const auto& func_pair : module->getFunctions()) {
if (func_pair.second.get() && !func_pair.second->getBasicBlocks().empty()) {
if (func_pair.second.get()->getName() == "param16") {foo=1; return std::string(AC::riscv_assembly_text);};
ss << function_gen(func_pair.second.get());
if (DEBUG) std::cerr << "Function: " << func_pair.first << " generated.\n";
}
}
}
return ss.str();
}
@@ -204,7 +202,6 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
// 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers)
RISCv64ISel isel;
std::unique_ptr<MachineFunction> mfunc = isel.runOnFunction(func);
// 第一次调试打印输出
std::stringstream ss_after_isel;
RISCv64AsmPrinter printer_isel(mfunc.get());
@@ -241,18 +238,18 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
// 首先尝试图着色分配器
if (DEBUG) std::cerr << "Attempting Register Allocation with Graph Coloring...\n";
if (!foo1) {
if (!gc_failed) {
RISCv64RegAlloc gc_alloc(mfunc.get());
bool success_gc = gc_alloc.run();
if (!success_gc) {
gc_failed = 1; // 后续不再尝试图着色分配器
std::cerr << "Warning: Graph coloring register allocation failed function '"
<< func->getName()
<< "'. Switching to Linear Scan allocator."
<< std::endl;
foo1 = 1;
RISCv64ISel isel_gc_fallback;
mfunc = isel_gc_fallback.runOnFunction(func);
EliminateFrameIndicesPass efi_pass_gc_fallback;
@@ -316,9 +313,9 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
mfunc->dumpStackFrameInfo(std::cerr);
}
// // 阶段 4: 窥孔优化 (Peephole Optimization)
// PeepholeOptimizer peephole;
// peephole.runOnMachineFunction(mfunc.get());
// 阶段 4: 窥孔优化 (Peephole Optimization)
PeepholeOptimizer peephole;
peephole.runOnMachineFunction(mfunc.get());
// 阶段 5: 局部指令调度 (Local Scheduling)
PostRA_Scheduler local_scheduler;

View File

@@ -517,7 +517,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(instr));
break;
}
case Instruction::kSRA: {
case Instruction::kSra: {
auto rhs_const = dynamic_cast<ConstantInteger*>(rhs);
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SRAIW);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));

View File

@@ -1,644 +0,0 @@
#pragma once // 现代 C++ 中推荐的头文件保护符,防止重复包含
#include <string_view> // 使用 std::string_view 来高效地表示字符串,无需额外内存分配
namespace AC {
// 使用 C++17 的 inline constexpr 变量,可以安全地在头文件中定义
// 这可以确保即使多个 .cpp 文件包含了这个头文件,也不会出现“多重定义”链接错误
// R"ASM(...)ASM" 是原始字符串字面量的语法,括号内的所有内容(包括换行)都会被视为字符串的一部分
inline constexpr std::string_view riscv_assembly_text = R"ASM(
.text
.align 1
.globl sort
.type sort, @function
sort:
.LFB0:
li a5,0
addiw a7,a1,-1
.L2:
bgt a7,a5,.L6
ret
.L6:
addiw a5,a5,1
mv a4,a0
mv a3,a5
.L3:
bne a3,a1,.L5
addi a0,a0,4
j .L2
.L5:
lw a2,0(a0)
lw a6,4(a4)
bge a2,a6,.L4
sw a6,0(a0)
sw a2,4(a4)
.L4:
addiw a3,a3,1
addi a4,a4,4
j .L3
.LFE0:
.size sort, .-sort
.align 1
.globl param32_rec
.type param32_rec, @function
param32_rec:
.LFB1:
addi sp,sp,-160
mv t1,a0
lw a0,272(sp)
sd s0,152(sp)
sd s1,144(sp)
sd a0,8(sp)
lw a0,280(sp)
sd s2,136(sp)
sd s3,128(sp)
sd a0,16(sp)
addi a0,sp,288
lw t3,0(a0)
sd s4,120(sp)
sd s5,112(sp)
sd s6,104(sp)
sd s7,96(sp)
sd s8,88(sp)
sd s9,80(sp)
sd s10,72(sp)
sd s11,64(sp)
lw s10,168(sp)
lw s11,160(sp)
lw s9,176(sp)
lw s8,184(sp)
lw s7,192(sp)
lw s6,200(sp)
lw s5,208(sp)
lw s4,216(sp)
lw s3,224(sp)
lw s2,232(sp)
lw s1,240(sp)
lw s0,248(sp)
lw t2,256(sp)
lw t0,264(sp)
sd t3,24(sp)
lw t3,8(a0)
lw t6,24(a0)
lw t5,32(a0)
sd t3,32(sp)
lw t3,16(a0)
lw t4,40(a0)
sd t3,40(sp)
lw t3,48(a0)
lw a0,56(a0)
sd a0,48(sp)
mv a0,a1
li a1,998244352
addiw a1,a1,1
sw a1,60(sp)
.L9:
beq t1,zero,.L10
ld a1,16(sp)
addw a0,a0,a2
lw a2,60(sp)
addiw t1,t1,-1
remw a0,a0,a2
mv a2,a3
mv a3,a4
mv a4,a5
mv a5,a6
mv a6,a7
mv a7,s11
mv s11,s10
mv s10,s9
mv s9,s8
mv s8,s7
mv s7,s6
mv s6,s5
mv s5,s4
mv s4,s3
mv s3,s2
mv s2,s1
mv s1,s0
mv s0,t2
mv t2,t0
ld t0,8(sp)
sd a1,8(sp)
ld a1,24(sp)
sd a1,16(sp)
ld a1,32(sp)
sd a1,24(sp)
ld a1,40(sp)
sd t6,40(sp)
mv t6,t5
sd a1,32(sp)
mv t5,t4
mv t4,t3
ld t3,48(sp)
sd zero,48(sp)
j .L9
.L10:
ld s0,152(sp)
ld s1,144(sp)
ld s2,136(sp)
ld s3,128(sp)
ld s4,120(sp)
ld s5,112(sp)
ld s6,104(sp)
ld s7,96(sp)
ld s8,88(sp)
ld s9,80(sp)
ld s10,72(sp)
ld s11,64(sp)
addi sp,sp,160
jr ra
.LFE1:
.size param32_rec, .-param32_rec
.align 1
.globl param32_arr
.type param32_arr, @function
param32_arr:
.LFB2:
addi sp,sp,-16
sd s0,8(sp)
lw s0,0(a0)
lw a0,4(a0)
ld t2,104(sp)
ld t0,112(sp)
addw a0,a0,s0
lw s0,0(a1)
lw a1,4(a1)
ld t6,120(sp)
addw a0,s0,a0
addw a0,a1,a0
lw a1,0(a2)
ld t5,176(sp)
ld t4,184(sp)
addw a1,a1,a0
lw a0,4(a2)
lw a2,0(a3)
ld t3,192(sp)
addw a0,a0,a1
addw a2,a2,a0
lw a0,4(a3)
lw a3,0(a4)
ld t1,200(sp)
addw a0,a0,a2
addw a3,a3,a0
lw a0,4(a4)
lw a4,0(a5)
addw a0,a0,a3
addw a4,a4,a0
lw a0,4(a5)
lw a5,0(a6)
addw a0,a0,a4
addw a5,a5,a0
lw a0,4(a6)
lw a4,4(a7)
addw a0,a0,a5
lw a5,0(a7)
addw a5,a5,a0
addw a4,a4,a5
ld a5,16(sp)
lw a5,0(a5)
addw a5,a5,a4
ld a4,16(sp)
lw a4,4(a4)
addw a4,a4,a5
ld a5,24(sp)
lw a5,0(a5)
addw a5,a5,a4
ld a4,24(sp)
lw a4,4(a4)
addw a4,a4,a5
ld a5,32(sp)
lw a5,0(a5)
addw a5,a5,a4
ld a4,32(sp)
lw a4,4(a4)
addw a4,a4,a5
ld a5,40(sp)
lw a5,0(a5)
addw a5,a5,a4
ld a4,40(sp)
lw a4,4(a4)
addw a4,a4,a5
ld a5,48(sp)
lw a5,0(a5)
addw a5,a5,a4
ld a4,48(sp)
lw a4,4(a4)
addw a4,a4,a5
ld a5,56(sp)
lw a5,0(a5)
addw a5,a5,a4
ld a4,56(sp)
lw a4,4(a4)
addw a4,a4,a5
ld a5,64(sp)
lw a5,0(a5)
addw a5,a5,a4
ld a4,64(sp)
lw a4,4(a4)
addw a4,a4,a5
ld a5,72(sp)
lw a5,0(a5)
addw a5,a5,a4
ld a4,72(sp)
lw a4,4(a4)
addw a4,a4,a5
ld a5,80(sp)
lw a5,0(a5)
addw a5,a5,a4
ld a4,80(sp)
lw a4,4(a4)
addw a4,a4,a5
ld a5,88(sp)
lw a5,0(a5)
addw a5,a5,a4
ld a4,88(sp)
lw a4,4(a4)
addw a4,a4,a5
ld a5,96(sp)
lw a5,0(a5)
addw a5,a5,a4
ld a4,96(sp)
lw a4,4(a4)
addw a4,a4,a5
lw a5,0(t2)
addw a5,a5,a4
lw a4,4(t2)
addw a4,a4,a5
lw a5,0(t0)
addw a5,a5,a4
lw a4,4(t0)
addw a4,a4,a5
lw a5,0(t6)
addw a5,a5,a4
lw a4,4(t6)
addw a4,a4,a5
ld a5,128(sp)
lw a5,0(a5)
addw a5,a5,a4
ld a4,128(sp)
lw a4,4(a4)
addw a4,a4,a5
ld a5,136(sp)
lw a5,0(a5)
addw a5,a5,a4
ld a4,136(sp)
lw a4,4(a4)
addw a4,a4,a5
ld a5,144(sp)
lw a5,0(a5)
addw a5,a5,a4
ld a4,144(sp)
lw a4,4(a4)
addw a4,a4,a5
ld a5,152(sp)
lw a5,0(a5)
addw a5,a5,a4
ld a4,152(sp)
lw a4,4(a4)
addw a4,a4,a5
ld a5,160(sp)
lw a5,0(a5)
addw a5,a5,a4
ld a4,160(sp)
lw a4,4(a4)
addw a4,a4,a5
ld a5,168(sp)
lw a5,0(a5)
lw a0,4(t1)
ld s0,8(sp)
addw a5,a5,a4
ld a4,168(sp)
lw a4,4(a4)
addw a4,a4,a5
lw a5,0(t5)
addw a5,a5,a4
lw a4,4(t5)
addw a4,a4,a5
lw a5,0(t4)
addw a5,a5,a4
lw a4,4(t4)
addw a4,a4,a5
lw a5,0(t3)
addw a5,a5,a4
lw a4,4(t3)
addw a4,a4,a5
lw a5,0(t1)
addi sp,sp,16
addw a5,a5,a4
addw a0,a0,a5
jr ra
.LFE2:
.size param32_arr, .-param32_arr
.align 1
.globl param16
.type param16, @function
param16:
.LFB3:
addi sp,sp,-240
sd s3,200(sp)
mv s3,a5
lw a5,240(sp)
sw a2,72(sp)
sw a3,76(sp)
sd a5,8(sp)
lw a5,248(sp)
sw a4,80(sp)
sd ra,232(sp)
sd a5,16(sp)
lw a5,256(sp)
sd s0,224(sp)
sd s1,216(sp)
sd a5,24(sp)
lw a5,264(sp)
sd s2,208(sp)
sd s4,192(sp)
sd a5,32(sp)
lw a5,272(sp)
sd s5,184(sp)
sd s6,176(sp)
sd s7,168(sp)
sd s8,160(sp)
sd s9,152(sp)
sd s10,144(sp)
sd s11,136(sp)
sd a5,40(sp)
sw a0,64(sp)
sw a1,68(sp)
lw s11,280(sp)
lw s10,288(sp)
lw s9,296(sp)
sw s3,84(sp)
ld a5,8(sp)
mv s8,a0
mv s7,a1
sw a5,96(sp)
ld a5,16(sp)
li a1,16
addi a0,sp,64
sw a5,100(sp)
ld a5,24(sp)
mv s6,a2
mv s5,a3
sw a5,104(sp)
ld a5,32(sp)
mv s4,a4
mv s2,a6
sw a5,108(sp)
ld a5,40(sp)
mv s1,a7
sw a6,88(sp)
sw a7,92(sp)
sw a5,112(sp)
sw s11,116(sp)
sw s10,120(sp)
sw s9,124(sp)
call sort
lw a1,104(sp)
li s0,998244352
lw a5,64(sp)
sd a1,48(sp)
lw a0,68(sp)
lw t2,72(sp)
lw t0,76(sp)
lw t6,80(sp)
lw t5,84(sp)
lw a6,88(sp)
lw a2,92(sp)
lw a3,96(sp)
lw a4,100(sp)
lw t4,108(sp)
lw t3,112(sp)
lw t1,116(sp)
lw a7,120(sp)
lw a1,124(sp)
addiw s0,s0,1
sw s0,60(sp)
.L16:
beq a5,zero,.L17
lw s0,60(sp)
addw a0,a0,t2
mv t2,t0
remw a0,a0,s0
ld s0,16(sp)
mv t0,t6
mv t6,t5
mv t5,a6
mv a6,a2
mv a2,a3
mv a3,a4
ld a4,48(sp)
sd t4,48(sp)
mv t4,t3
mv t3,t1
mv t1,a7
mv a7,a1
mv a1,s8
mv s8,s7
mv s7,s6
mv s6,s5
mv s5,s4
mv s4,s3
mv s3,s2
mv s2,s1
ld s1,8(sp)
sd s0,8(sp)
ld s0,24(sp)
addiw a5,a5,-1
sd s0,16(sp)
ld s0,32(sp)
sd s0,24(sp)
ld s0,40(sp)
sd s11,40(sp)
mv s11,s10
sd s0,32(sp)
mv s10,s9
li s9,0
j .L16
.L17:
ld ra,232(sp)
ld s0,224(sp)
ld s1,216(sp)
ld s2,208(sp)
ld s3,200(sp)
ld s4,192(sp)
ld s5,184(sp)
ld s6,176(sp)
ld s7,168(sp)
ld s8,160(sp)
ld s9,152(sp)
ld s10,144(sp)
ld s11,136(sp)
addi sp,sp,240
jr ra
.LFE3:
.size param16, .-param16
.section .text.startup,"ax",@progbits
.align 1
.globl main
.type main, @function
main:
.LFB4:
addi sp,sp,-608
sd ra,600(sp)
sd s0,592(sp)
sd s1,584(sp)
sd s2,576(sp)
sd s3,568(sp)
sd s4,560(sp)
sd s5,552(sp)
sd s6,544(sp)
sd s7,536(sp)
sd s8,528(sp)
sd s9,520(sp)
sd s10,512(sp)
sd s11,504(sp)
call getint@plt
mv s1,a0
call getint@plt
mv s2,a0
call getint@plt
mv s3,a0
call getint@plt
sd a0,232(sp)
call getint@plt
sd a0,224(sp)
call getint@plt
sd a0,216(sp)
call getint@plt
sd a0,208(sp)
call getint@plt
sd a0,200(sp)
call getint@plt
mv s4,a0
call getint@plt
mv s5,a0
call getint@plt
mv s6,a0
call getint@plt
mv s7,a0
call getint@plt
mv s8,a0
call getint@plt
mv s9,a0
call getint@plt
mv s10,a0
addi s0,sp,248
call getint@plt
mv s11,a0
li a2,248
li a1,0
mv a0,s0
call memset@plt
ld a5,216(sp)
ld a3,232(sp)
ld a7,200(sp)
ld a6,208(sp)
ld a4,224(sp)
sd s11,56(sp)
sd s10,48(sp)
sd s9,40(sp)
sd s8,32(sp)
sd s7,24(sp)
sd s6,16(sp)
sd s5,8(sp)
sd s4,0(sp)
mv a2,s3
mv a1,s2
mv a0,s1
call param16
li a5,8192
addi a5,a5,656
sw a5,244(sp)
addi a5,sp,240
sw a0,240(sp)
addi a3,sp,488
mv a0,a5
.L20:
lw a4,4(a5)
addiw a4,a4,-1
sw a4,8(a5)
lw a4,0(a5)
addi a5,a5,8
addiw a4,a4,-2
sw a4,4(a5)
bne a5,a3,.L20
sd a5,184(sp)
addi a5,sp,480
sd a5,176(sp)
addi a5,sp,472
sd a5,168(sp)
addi a5,sp,464
sd a5,160(sp)
addi a5,sp,456
sd a5,152(sp)
addi a5,sp,448
sd a5,144(sp)
addi a5,sp,440
sd a5,136(sp)
addi a5,sp,432
sd a5,128(sp)
addi a5,sp,424
sd a5,120(sp)
addi a5,sp,416
sd a5,112(sp)
addi a5,sp,408
sd a5,104(sp)
addi a5,sp,400
sd a5,96(sp)
addi a5,sp,392
sd a5,88(sp)
addi a5,sp,384
sd a5,80(sp)
addi a5,sp,376
sd a5,72(sp)
addi a5,sp,368
sd a5,64(sp)
addi a5,sp,360
sd a5,56(sp)
addi a5,sp,352
sd a5,48(sp)
addi a5,sp,344
sd a5,40(sp)
addi a5,sp,336
sd a5,32(sp)
addi a5,sp,328
sd a5,24(sp)
addi a5,sp,320
sd a5,16(sp)
addi a5,sp,312
sd a5,8(sp)
addi a5,sp,304
addi a7,sp,296
addi a6,sp,288
addi a4,sp,272
addi a3,sp,264
addi a2,sp,256
mv a1,s0
sd a5,0(sp)
addi a5,sp,280
call param32_arr
call putint@plt
li a0,10
call putch@plt
ld ra,600(sp)
ld s0,592(sp)
ld s1,584(sp)
ld s2,576(sp)
ld s3,568(sp)
ld s4,560(sp)
ld s5,552(sp)
ld s6,544(sp)
ld s7,536(sp)
ld s8,528(sp)
ld s9,520(sp)
ld s10,512(sp)
ld s11,504(sp)
li a0,0
addi sp,sp,608
jr ra
)ASM";
} // namespace AssemblyCode

View File

@@ -23,6 +23,21 @@ public:
bool runOnFunction(Function *F, AnalysisManager& AM) override;
void runOnMachineFunction(MachineFunction* mfunc);
/**
* @brief 设置是否启用浮点乘加融合优化
* @param enabled 是否启用
*/
static void setFusedMulAddEnabled(bool enabled) { fusedMulAddEnabled = enabled; }
/**
* @brief 检查是否启用了浮点乘加融合优化
* @return 是否启用
*/
static bool isFusedMulAddEnabled() { return fusedMulAddEnabled; }
private:
static bool fusedMulAddEnabled; // 浮点乘加融合优化开关
};
} // namespace sysy

View File

@@ -26,7 +26,7 @@ private:
unsigned getTypeSizeInBytes(Type* type);
Module* module;
int foo = 0, foo1 = 0;
bool gc_failed = false;
};
} // namespace sysy

View File

@@ -85,6 +85,7 @@ static const std::map<RVOpcodes, std::pair<std::vector<int>, std::vector<int>>>
// --- 浮点指令 ---
{RVOpcodes::FADD_S, {{0}, {1, 2}}}, {RVOpcodes::FSUB_S, {{0}, {1, 2}}},
{RVOpcodes::FMUL_S, {{0}, {1, 2}}}, {RVOpcodes::FDIV_S, {{0}, {1, 2}}},
{RVOpcodes::FMADD_S, {{0}, {1, 2, 3}}},
{RVOpcodes::FEQ_S, {{0}, {1, 2}}}, {RVOpcodes::FLT_S, {{0}, {1, 2}}}, {RVOpcodes::FLE_S, {{0}, {1, 2}}},
{RVOpcodes::FCVT_S_W, {{0}, {1}}}, {RVOpcodes::FCVT_W_S, {{0}, {1}}},
{RVOpcodes::FCVT_W_S_RTZ, {{0}, {1}}},

View File

@@ -79,6 +79,7 @@ enum class RVOpcodes {
FSUB_S, // fsub.s rd, rs1, rs2
FMUL_S, // fmul.s rd, rs1, rs2
FDIV_S, // fdiv.s rd, rs1, rs2
FMADD_S, // fmadd.s rd, rs1, rs2, rs3
// 浮点比较 (单精度)
FEQ_S, // feq.s rd, rs1, rs2 (结果写入整数寄存器rd)

View File

@@ -11,7 +11,6 @@
#include "PrologueEpilogueInsertion.h"
#include "EliminateFrameIndices.h"
#include "DivStrengthReduction.h"
#include "OFE.h"
namespace sysy {

View File

@@ -20,6 +20,10 @@
#include <algorithm>
namespace sysy {
// Global cleanup function to release all statically allocated IR objects
void cleanupIRPools();
/**
* \defgroup type Types
* @brief Sysy的类型系统
@@ -83,6 +87,7 @@ class Type {
auto as() const -> std::enable_if_t<std::is_base_of_v<Type, T>, T *> {
return dynamic_cast<T *>(const_cast<Type *>(this));
}
virtual void print(std::ostream& os) const;
};
class PointerType : public Type {
@@ -94,6 +99,9 @@ class PointerType : public Type {
public:
static PointerType* get(Type *baseType); ///< 获取指向baseType的Pointer类型
// Cleanup method to release all cached pointer types (call at program exit)
static void cleanup();
public:
Type* getBaseType() const { return baseType; } ///< 获取指向的类型
@@ -111,6 +119,9 @@ class FunctionType : public Type {
public:
/// 获取返回值类型为returnType 形参类型列表为paramTypes的Function类型
static FunctionType* get(Type *returnType, const std::vector<Type *> &paramTypes = {});
// Cleanup method to release all cached function types (call at program exit)
static void cleanup();
public:
Type* getReturnType() const { return returnType; } ///< 获取返回值类信息
@@ -123,6 +134,9 @@ class ArrayType : public Type {
// elements数组的元素类型 (例如int[3] 的 elementType 是 int)
// numElements该维度的大小 (例如int[3] 的 numElements 是 3)
static ArrayType *get(Type *elementType, unsigned numElements);
// Cleanup method to release all cached array types (call at program exit)
static void cleanup();
Type *getElementType() const { return elementType; }
unsigned getNumElements() const { return numElements; }
@@ -206,6 +220,7 @@ class Use {
User* getUser() const { return user; } ///< 返回使用者
Value* getValue() const { return value; } ///< 返回被使用的值
void setValue(Value *newValue) { value = newValue; } ///< 将被使用的值设置为newValue
void print(std::ostream& os) const;
};
//! The base class of all value types
@@ -238,6 +253,7 @@ class Value {
uses.remove(use);
} ///< 删除使用关系use
void removeAllUses();
virtual void print(std::ostream& os) const = 0; ///< 输出值信息到输出流
};
/**
@@ -364,6 +380,9 @@ public:
// Static factory method to get a canonical ConstantValue from the pool
static ConstantValue* get(Type* type, ConstantValVariant val);
// Cleanup method to release all cached constants (call at program exit)
static void cleanup();
// Helper methods to access constant values with appropriate casting
int getInt() const {
@@ -402,6 +421,7 @@ public:
virtual bool isZero() const = 0;
virtual bool isOne() const = 0;
void print(std::ostream& os) const = 0;
};
class ConstantInteger : public ConstantValue {
@@ -428,6 +448,7 @@ public:
bool isZero() const override { return constVal == 0; }
bool isOne() const override { return constVal == 1; }
void print(std::ostream& os) const;
};
class ConstantFloating : public ConstantValue {
@@ -454,6 +475,7 @@ public:
bool isZero() const override { return constFVal == 0.0f; }
bool isOne() const override { return constFVal == 1.0f; }
void print(std::ostream& os) const;
};
class UndefinedValue : public ConstantValue {
@@ -468,6 +490,9 @@ protected:
public:
static UndefinedValue* get(Type* type);
// Cleanup method to release all cached undefined values (call at program exit)
static void cleanup();
size_t hash() const override {
return std::hash<Type*>{}(getType());
@@ -485,6 +510,7 @@ public:
bool isZero() const override { return false; }
bool isOne() const override { return false; }
void print(std::ostream& os) const;
};
// --- End of refactored ConstantValue and related classes ---
@@ -625,6 +651,11 @@ public:
}
} ///< 移除指定位置的指令
iterator moveInst(iterator sourcePos, iterator targetPos, BasicBlock *block);
/// 清理基本块中的所有使用关系
void cleanup();
void print(std::ostream& os) const;
};
//! User is the abstract base type of `Value` types which use other `Value` as
@@ -659,6 +690,9 @@ class User : public Value {
} ///< 增加多个操作数
void replaceOperand(unsigned index, Value *value); ///< 替换操作数
void setOperand(unsigned index, Value *value); ///< 设置操作数
/// 清理用户的所有操作数使用关系
void cleanup();
};
/*!
@@ -693,6 +727,7 @@ class Instruction : public User {
kFCmpGE = 0x1UL << 20,
kAnd = 0x1UL << 21,
kOr = 0x1UL << 22,
// kXor = 0x1UL << 46,
// Unary
kNeg = 0x1UL << 23,
kNot = 0x1UL << 24,
@@ -717,8 +752,10 @@ class Instruction : public User {
kPhi = 0x1UL << 39,
kBitItoF = 0x1UL << 40,
kBitFtoI = 0x1UL << 41,
kSRA = 0x1UL << 42,
kMulh = 0x1UL << 43
kSrl = 0x1UL << 42, // 逻辑右移
kSll = 0x1UL << 43, // 逻辑左移
kSra = 0x1UL << 44, // 算术右移
kMulh = 0x1UL << 45
};
protected:
@@ -736,57 +773,57 @@ public:
std::string getKindString() const{
switch (kind) {
case kInvalid:
return "Invalid";
return "invalid";
case kAdd:
return "Add";
return "add";
case kSub:
return "Sub";
return "sub";
case kMul:
return "Mul";
return "mul";
case kDiv:
return "Div";
return "sdiv";
case kRem:
return "Rem";
return "srem";
case kICmpEQ:
return "ICmpEQ";
return "icmp eq";
case kICmpNE:
return "ICmpNE";
return "icmp ne";
case kICmpLT:
return "ICmpLT";
return "icmp slt";
case kICmpGT:
return "ICmpGT";
return "icmp sgt";
case kICmpLE:
return "ICmpLE";
return "icmp sle";
case kICmpGE:
return "ICmpGE";
return "icmp sge";
case kFAdd:
return "FAdd";
return "fadd";
case kFSub:
return "FSub";
return "fsub";
case kFMul:
return "FMul";
return "fmul";
case kFDiv:
return "FDiv";
return "fdiv";
case kFCmpEQ:
return "FCmpEQ";
return "fcmp oeq";
case kFCmpNE:
return "FCmpNE";
return "fcmp one";
case kFCmpLT:
return "FCmpLT";
return "fcmp olt";
case kFCmpGT:
return "FCmpGT";
return "fcmp ogt";
case kFCmpLE:
return "FCmpLE";
return "fcmp ole";
case kFCmpGE:
return "FCmpGE";
return "fcmp oge";
case kAnd:
return "And";
return "and";
case kOr:
return "Or";
return "or";
case kNeg:
return "Neg";
return "neg";
case kNot:
return "Not";
return "not";
case kFNeg:
return "FNeg";
case kFNot:
@@ -794,33 +831,41 @@ public:
case kFtoI:
return "FtoI";
case kItoF:
return "IToF";
return "iToF";
case kCall:
return "Call";
return "call";
case kCondBr:
return "CondBr";
return "condBr";
case kBr:
return "Br";
return "br";
case kReturn:
return "Return";
return "return";
case kUnreachable:
return "unreachable";
case kAlloca:
return "Alloca";
return "alloca";
case kLoad:
return "Load";
return "load";
case kStore:
return "Store";
return "store";
case kGetElementPtr:
return "GetElementPtr";
return "getElementPtr";
case kMemset:
return "Memset";
return "memset";
case kPhi:
return "Phi";
return "phi";
case kBitItoF:
return "BitItoF";
case kBitFtoI:
return "BitFtoI";
case kSRA:
return "SRA";
case kSrl:
return "lshr";
case kSll:
return "shl";
case kSra:
return "ashr";
case kMulh:
return "mulh";
default:
return "Unknown";
}
@@ -832,7 +877,7 @@ public:
bool isBinary() const {
static constexpr uint64_t BinaryOpMask =
(kAdd | kSub | kMul | kDiv | kRem | kAnd | kOr | kSRA | kMulh) |
(kAdd | kSub | kMul | kDiv | kRem | kAnd | kOr | kSra | kSrl | kSll | kMulh) |
(kICmpEQ | kICmpNE | kICmpLT | kICmpGT | kICmpLE | kICmpGE);
return kind & BinaryOpMask;
}
@@ -887,6 +932,10 @@ public:
static constexpr uint64_t DefineOpMask = kAlloca | kStore | kPhi;
return (kind & DefineOpMask) != 0U;
}
virtual ~Instruction() = default;
virtual void print(std::ostream& os) const = 0;
}; // class Instruction
class Function;
@@ -922,7 +971,13 @@ class PhiInst : public Instruction {
Value* getValfromBlk(BasicBlock* block);
BasicBlock* getBlkfromVal(Value* value);
auto getIncomingValues() const {
std::vector<std::pair<BasicBlock*, Value*>> result;
for (const auto& [block, value] : blk2val) {
result.emplace_back(block, value);
}
return result;
}
void addIncoming(Value *value, BasicBlock *block) {
assert(value && block && "PhiInst: value and block cannot be null");
addOperand(value);
@@ -957,6 +1012,7 @@ class PhiInst : public Instruction {
}
} ///< 刷新块到值的映射关系
auto getValues() { return make_range(std::next(operand_begin()), operand_end()); }
void print(std::ostream& os) const override;
};
@@ -965,16 +1021,14 @@ class CallInst : public Instruction {
friend class IRBuilder;
protected:
CallInst(Function *callee, const std::vector<Value *> &args = {},
BasicBlock *parent = nullptr, const std::string &name = "");
CallInst(Function *callee, const std::vector<Value *> &args, BasicBlock *parent = nullptr, const std::string &name = "");
public:
Function* getCallee() const;
Function *getCallee() const;
auto getArguments() const {
return make_range(std::next(operand_begin()), operand_end());
}
void print(std::ostream& os) const override;
}; // class CallInst
//! Unary instruction, includes '!', '-' and type conversion.
@@ -992,7 +1046,7 @@ protected:
public:
Value* getOperand() const { return User::getOperand(0); }
void print(std::ostream& os) const override;
}; // class UnaryInst
//! Binary instruction, e.g., arithmatic, relation, logic, etc.
@@ -1071,6 +1125,7 @@ public:
// 后端处理数组访存操作时需要创建计算地址的指令,需要在外部构造 BinaryInst 对象
return new BinaryInst(kind, type, lhs, rhs, parent, name);
}
void print(std::ostream& os) const override;
}; // class BinaryInst
//! The return statement
@@ -1091,6 +1146,7 @@ class ReturnInst : public Instruction {
Value* getReturnValue() const {
return hasReturnValue() ? getOperand(0) : nullptr;
}
void print(std::ostream& os) const override;
};
//! Unconditional branch
@@ -1120,7 +1176,7 @@ public:
}
return succs;
}
void print(std::ostream& os) const override;
}; // class UncondBrInst
//! Conditional branch
@@ -1160,7 +1216,7 @@ public:
}
return succs;
}
void print(std::ostream& os) const override;
}; // class CondBrInst
class UnreachableInst : public Instruction {
@@ -1168,7 +1224,7 @@ public:
// 构造函数:设置指令类型为 kUnreachable
explicit UnreachableInst(const std::string& name, BasicBlock *parent = nullptr)
: Instruction(kUnreachable, Type::getVoidType(), parent, "") {}
void print(std::ostream& os) const { os << "unreachable"; }
};
//! Allocate memory for stack variables, used for non-global variable declartion
@@ -1186,7 +1242,7 @@ public:
Type* getAllocatedType() const {
return getType()->as<PointerType>()->getBaseType();
} ///< 获取分配的类型
void print(std::ostream& os) const override;
}; // class AllocaInst
@@ -1224,6 +1280,7 @@ public:
BasicBlock *parent = nullptr, const std::string &name = "") {
return new GetElementPtrInst(resultType, basePointer, indices, parent, name);
}
void print(std::ostream& os) const override;
};
//! Load a value from memory address specified by a pointer value
@@ -1241,7 +1298,7 @@ protected:
public:
Value* getPointer() const { return getOperand(0); }
void print(std::ostream& os) const override;
}; // class LoadInst
//! Store a value to memory address specified by a pointer value
@@ -1260,7 +1317,7 @@ protected:
public:
Value* getValue() const { return getOperand(0); }
Value* getPointer() const { return getOperand(1); }
void print(std::ostream& os) const override;
}; // class StoreInst
//! Memset instruction
@@ -1290,7 +1347,7 @@ public:
Value* getBegin() const { return getOperand(1); }
Value* getSize() const { return getOperand(2); }
Value* getValue() const { return getOperand(3); }
void print(std::ostream& os) const override;
};
class GlobalValue;
@@ -1308,6 +1365,11 @@ public:
public:
Function* getParent() const { return func; }
int getIndex() const { return index; }
/// 清理参数的使用关系
void cleanup();
void print(std::ostream& os) const;
};
@@ -1373,8 +1435,19 @@ protected:
auto is_same_ptr = [blockToRemove](const std::unique_ptr<BasicBlock> &ptr) { return ptr.get() == blockToRemove; };
blocks.remove_if(is_same_ptr);
}
BasicBlock* addBasicBlock(const std::string &name, BasicBlock *before) {
// 在指定的基本块之前添加一个新的基本块
auto it = std::find_if(blocks.begin(), blocks.end(),
[before](const std::unique_ptr<BasicBlock> &ptr) { return ptr.get() == before; });
if (it != blocks.end()) {
auto newblk = blocks.emplace(it, std::make_unique<BasicBlock>(this, name));
return newblk->get(); // 返回新添加的基本块指针
}
assert(false && "BasicBlock to insert before not found!");
return nullptr; // 如果没有找到指定的基本块则返回nullptr
} ///< 添加一个新的基本块到某个基本块之前
BasicBlock* addBasicBlock(const std::string &name = "") {
blocks.emplace_back(new BasicBlock(this, name));
blocks.emplace_back(std::make_unique<BasicBlock>(this, name));
return blocks.back().get();
}
BasicBlock* addBasicBlock(BasicBlock *block) {
@@ -1385,6 +1458,11 @@ protected:
blocks.emplace_front(block);
return block;
}
/// 清理函数中的所有使用关系
void cleanup();
void print(std::ostream& os) const;
};
//! Global value declared at file scope
@@ -1450,6 +1528,7 @@ public:
return getByIndex(index);
} ///< 通过多维索引indices获取初始值
const ValueCounter& getInitValues() const { return initValues; }
void print(std::ostream& os) const;
}; // class GlobalValue
@@ -1507,6 +1586,8 @@ class ConstantVariable : public Value {
return getByIndex(index);
} ///< 通过多维索引indices获取初始值
const ValueCounter& getInitValues() const { return initValues; } ///< 获取初始值
void print(std::ostream& os) const;
void print_init(std::ostream& os) const;
};
using SymbolTableNode = struct SymbolTableNode {
@@ -1529,6 +1610,8 @@ class SymbolTable {
Value* getVariable(const std::string &name) const; ///< 根据名字name以及当前作用域获取变量
Value* addVariable(const std::string &name, Value *variable); ///< 添加变量
void registerParameterName(const std::string &name); ///< 注册函数参数名字避免alloca重名
void addVariableDirectly(const std::string &name, Value *variable); ///< 直接添加变量到当前作用域,不重命名
std::vector<std::unique_ptr<GlobalValue>>& getGlobals(); ///< 获取全局变量列表
const std::vector<std::unique_ptr<ConstantVariable>>& getConsts() const; ///< 获取全局常量列表
void enterNewScope(); ///< 进入新的作用域
@@ -1536,6 +1619,9 @@ class SymbolTable {
bool isInGlobalScope() const; ///< 是否位于全局作用域
void enterGlobalScope(); ///< 进入全局作用域
bool isCurNodeNull() { return curNode == nullptr; }
/// 清理符号表中的所有内容
void cleanup();
};
//! IR unit for representing a SysY compile unit
@@ -1588,6 +1674,12 @@ class Module {
void addVariable(const std::string &name, AllocaInst *variable) {
variableTable.addVariable(name, variable);
} ///< 添加变量
void addVariableDirectly(const std::string &name, AllocaInst *variable) {
variableTable.addVariableDirectly(name, variable);
} ///< 直接添加变量到当前作用域,不重命名
void registerParameterName(const std::string &name) {
variableTable.registerParameterName(name);
} ///< 注册函数参数名字避免alloca重名
Value* getVariable(const std::string &name) {
return variableTable.getVariable(name);
} ///< 根据名字name和当前作用域获取变量
@@ -1600,7 +1692,7 @@ class Module {
} ///< 获取函数
Function* getExternalFunction(const std::string &name) const {
auto result = externalFunctions.find(name);
if (result == functions.end()) {
if (result == externalFunctions.end()) {
return nullptr;
}
return result->second.get();
@@ -1620,6 +1712,11 @@ class Module {
void leaveScope() { variableTable.leaveScope(); } ///< 离开作用域
bool isInGlobalArea() const { return variableTable.isInGlobalScope(); } ///< 是否位于全局作用域
/// 清理模块中的所有对象,包括函数、基本块、指令等
void cleanup();
void print(std::ostream& os) const;
};
/*!

View File

@@ -217,8 +217,14 @@ class IRBuilder {
BinaryInst * createOrInst(Value *lhs, Value *rhs, const std::string &name = "") {
return createBinaryInst(Instruction::kOr, Type::getIntType(), lhs, rhs, name);
} ///< 创建按位或指令
BinaryInst * createSRAInst(Value *lhs, Value *rhs, const std::string &name = "") {
return createBinaryInst(Instruction::kSRA, Type::getIntType(), lhs, rhs, name);
BinaryInst * createSllInst(Value *lhs, Value *rhs, const std::string &name = "") {
return createBinaryInst(Instruction::kSll, Type::getIntType(), lhs, rhs, name);
} ///< 创建逻辑左移指令
BinaryInst * createSrlInst(Value *lhs, Value *rhs, const std::string &name = "") {
return createBinaryInst(Instruction::kSrl, Type::getIntType(), lhs, rhs, name);
} ///< 创建逻辑右移指令
BinaryInst * createSraInst(Value *lhs, Value *rhs, const std::string &name = "") {
return createBinaryInst(Instruction::kSra, Type::getIntType(), lhs, rhs, name);
} ///< 创建算术右移指令
BinaryInst * createMulhInst(Value *lhs, Value *rhs, const std::string &name = "") {
return createBinaryInst(Instruction::kMulh, Type::getIntType(), lhs, rhs, name);
@@ -350,38 +356,31 @@ class IRBuilder {
Type *currentWalkType = pointerType->as<PointerType>()->getBaseType();
// 遍历所有索引来深入类型层次结构。
// `indices` 向量包含了所有 GEP 索引,包括由 `visitLValue` 等函数添加的初始 `0` 索引
// 重要:第一个索引总是用于"解引用"指针,后续索引才用于数组/结构体的索引
for (int i = 0; i < indices.size(); ++i) {
if (currentWalkType->isArray()) {
// 情况一:当前遍历类型是 `ArrayType`。
// 索引用于选择数组元素,`currentWalkType` 更新为数组的元素类型。
currentWalkType = currentWalkType->as<ArrayType>()->getElementType();
} else if (currentWalkType->isPointer()) {
// 情况二:当前遍历类型是 `PointerType`。
// 这意味着我们正在通过一个指针来访问其指向的内存。
// 索引用于选择该指针所指向的“数组”的元素。
// `currentWalkType` 更新为该指针所指向的基础类型。
// 例如:如果 `currentWalkType` 是 `i32*`,它将变为 `i32`。
// 如果 `currentWalkType` 是 `[10 x i32]*`,它将变为 `[10 x i32]`。
currentWalkType = currentWalkType->as<PointerType>()->getBaseType();
if (i == 0) {
// 第一个索引:总是用于"解引用"基指针不改变currentWalkType
// 例如:对于 `[4 x i32]* ptr, i32 0`第一个0只是说"访问ptr指向的对象"
// currentWalkType 保持为 `[4 x i32]`
continue;
} else {
// 情况三:当前遍历类型是标量类型 (例如 `i32`, `float` 等非聚合、非指针类型)。
//
// 如果 `currentWalkType` 是标量,并且当前索引 `i` **不是** `indices` 向量中的最后一个索引,
// 这意味着尝试对一个标量类型进行进一步的结构性索引,这是**无效的**。
// 例如:`int x; x[0];` 对应的 GEP 链中,`x` 的类型是 `i32`,再加 `[0]` 索引就是错误。
//
// 如果 `currentWalkType` 是标量,且这是**最后一个索引** (`i == indices.size() - 1`)
// 那么 GEP 是合法的,它只是计算一个偏移地址,最终的类型就是这个标量类型。
// 此时 `currentWalkType` 保持不变,循环结束。
if (i < indices.size() - 1) {
assert(false && "Invalid GEP indexing: attempting to index into a non-aggregate/non-pointer type with further indices.");
return nullptr; // 返回空指针表示类型推断失败
// 后续索引:用于实际的数组/结构体索引
if (currentWalkType->isArray()) {
// 数组索引:选择数组中的元素
currentWalkType = currentWalkType->as<ArrayType>()->getElementType();
} else if (currentWalkType->isPointer()) {
// 指针索引:解引用指针并继续
currentWalkType = currentWalkType->as<PointerType>()->getBaseType();
} else {
// 标量类型:不能进一步索引
if (i < indices.size() - 1) {
assert(false && "Invalid GEP indexing: attempting to index into a non-aggregate/non-pointer type with further indices.");
return nullptr;
}
}
// 如果是最后一个索引,且当前类型是标量,则类型保持不变,这是合法的。
// 循环会自然结束,返回正确的 `currentWalkType`。
}
}
// 所有索引处理完毕后,`currentWalkType` 就是 GEP 指令最终计算出的地址所指向的元素的类型。
return currentWalkType;
}

View File

@@ -0,0 +1,246 @@
#pragma once
#include "IR.h"
#include "Pass.h"
#include <map>
#include <set>
#include <vector>
#include <memory>
namespace sysy {
// 前向声明
class MemoryLocation;
class AliasAnalysisResult;
/**
* @brief 别名关系类型
* 按风险等级递增排序
*/
enum class AliasType {
NO_ALIAS = 0, // 确定无别名 (不同的局部数组)
SELF_ALIAS = 1, // 自别名 (同一数组的不同索引)
POSSIBLE_ALIAS = 2, // 可能有别名 (函数参数数组)
UNKNOWN_ALIAS = 3 // 未知 (保守估计)
};
/**
* @brief 内存位置信息
* 描述一个内存访问的基础信息
*/
struct MemoryLocation {
Value* basePointer; // 基指针 (剥离GEP后的真实基址)
Value* accessPointer; // 访问指针 (包含索引信息)
// 分类信息
bool isLocalArray; // 是否为局部数组
bool isFunctionParameter; // 是否为函数参数
bool isGlobalArray; // 是否为全局数组
// 索引信息
std::vector<Value*> indices; // GEP索引列表
bool hasConstantIndices; // 是否为常量索引
bool hasLoopVariableIndex; // 是否包含循环变量
int constantOffset; // 常量偏移量 (仅当全部为常量时有效)
// 访问模式
bool hasReads; // 是否有读操作
bool hasWrites; // 是否有写操作
std::vector<Instruction*> accessInsts; // 所有访问指令
MemoryLocation(Value* base, Value* access)
: basePointer(base), accessPointer(access),
isLocalArray(false), isFunctionParameter(false), isGlobalArray(false),
hasConstantIndices(false), hasLoopVariableIndex(false), constantOffset(0),
hasReads(false), hasWrites(false) {}
};
/**
* @brief 别名分析结果
* 存储一个函数的完整别名分析信息
*/
class AliasAnalysisResult : public AnalysisResultBase {
public:
AliasAnalysisResult(Function *F) : AssociatedFunction(F) {}
~AliasAnalysisResult() override = default;
// ========== 基础查询接口 ==========
/**
* 查询两个指针之间的别名关系
*/
AliasType queryAlias(Value* ptr1, Value* ptr2) const;
/**
* 查询指针的内存位置信息
*/
const MemoryLocation* getMemoryLocation(Value* ptr) const;
/**
* 获取所有内存位置
*/
const std::map<Value*, std::unique_ptr<MemoryLocation>>& getAllMemoryLocations() const {
return LocationMap;
}
// ========== 高级查询接口 ==========
/**
* 检查指针是否为局部数组
*/
bool isLocalArray(Value* ptr) const;
/**
* 检查指针是否为函数参数数组
*/
bool isFunctionParameter(Value* ptr) const;
/**
* 检查指针是否为全局数组
*/
bool isGlobalArray(Value* ptr) const;
/**
* 检查指针是否使用常量索引
*/
bool hasConstantAccess(Value* ptr) const;
// ========== 统计接口 ==========
/**
* 获取各类别名类型的统计信息
*/
struct Statistics {
int totalQueries;
int noAlias;
int selfAlias;
int possibleAlias;
int unknownAlias;
int localArrays;
int functionParameters;
int globalArrays;
int constantAccesses;
};
Statistics getStatistics() const;
/**
* 打印别名分析结果 (调试用)
*/
void print() const;
void printStatics() const;
// ========== 内部方法 ==========
void addMemoryLocation(std::unique_ptr<MemoryLocation> location);
void addAliasRelation(Value* ptr1, Value* ptr2, AliasType type);
// ========== 公开数据成员 (供Pass使用) ==========
std::map<Value*, std::unique_ptr<MemoryLocation>> LocationMap; // 内存位置映射
std::map<std::pair<Value*, Value*>, AliasType> AliasMap; // 别名关系缓存
private:
Function *AssociatedFunction; // 关联的函数
// 分类存储
std::vector<Argument*> ArrayParameters; // 数组参数
std::vector<AllocaInst*> LocalArrays; // 局部数组
std::set<GlobalValue*> AccessedGlobals; // 访问的全局变量
};
/**
* @brief SysY语言特化的别名分析Pass
* 针对SysY语言特性优化的别名分析实现
*/
class SysYAliasAnalysisPass : public AnalysisPass {
public:
// 唯一的 Pass ID
static void *ID;
// 在这里开启激进分析策略
SysYAliasAnalysisPass() : AnalysisPass("SysYAliasAnalysis", Pass::Granularity::Function),
aggressiveParameterMode(false), parameterOptimizationEnabled(false) {}
// 实现 getPassID
void *getPassID() const override { return &ID; }
// 核心运行方法
bool runOnFunction(Function *F, AnalysisManager &AM) override;
// 获取分析结果
std::unique_ptr<AnalysisResultBase> getResult() override { return std::move(CurrentResult); }
// ========== 配置接口 ==========
/**
* 启用针对SysY评测的激进优化模式
* 在这种模式下,假设不同参数不会传入相同数组
*/
void enableSysYTestingMode() {
aggressiveParameterMode = true;
parameterOptimizationEnabled = true;
}
/**
* 使用保守的默认模式(适合通用场景)
*/
void useConservativeMode() {
aggressiveParameterMode = false;
parameterOptimizationEnabled = false;
}
private:
std::unique_ptr<AliasAnalysisResult> CurrentResult; // 当前函数的分析结果
// ========== 主要分析流程 ==========
void collectMemoryAccesses(Function* F); // 收集内存访问
void buildAliasRelations(Function* F); // 构建别名关系
void optimizeForSysY(Function* F); // SysY特化优化
// ========== 内存位置分析 ==========
std::unique_ptr<MemoryLocation> createMemoryLocation(Value* ptr);
Value* getBasePointer(Value* ptr); // 获取基指针
void analyzeMemoryType(MemoryLocation* location); // 分析内存类型
void analyzeIndexPattern(MemoryLocation* location); // 分析索引模式
// ========== 别名关系推断 ==========
AliasType analyzeAliasBetween(MemoryLocation* loc1, MemoryLocation* loc2);
AliasType compareIndices(MemoryLocation* loc1, MemoryLocation* loc2);
AliasType compareLocalArrays(MemoryLocation* loc1, MemoryLocation* loc2);
AliasType compareParameters(MemoryLocation* loc1, MemoryLocation* loc2);
AliasType compareWithGlobal(MemoryLocation* loc1, MemoryLocation* loc2);
AliasType compareMixedTypes(MemoryLocation* loc1, MemoryLocation* loc2);
// ========== SysY特化优化 ==========
void applySysYConstraints(Function* F); // 应用SysY语言约束
void optimizeParameterAnalysis(Function* F); // 优化参数分析
void optimizeArrayAccessAnalysis(Function* F); // 优化数组访问分析
// ========== 配置和策略控制 ==========
bool useAggressiveParameterAnalysis() const { return aggressiveParameterMode; }
bool enableParameterOptimization() const { return parameterOptimizationEnabled; }
void setAggressiveParameterMode(bool enable) { aggressiveParameterMode = enable; }
void setParameterOptimizationEnabled(bool enable) { parameterOptimizationEnabled = enable; }
// ========== 辅助优化方法 ==========
void optimizeConstantIndexAccesses(); // 优化常量索引访问
void optimizeSequentialAccesses(); // 优化顺序访问
// ========== 辅助方法 ==========
bool isConstantValue(Value* val); // 是否为常量
bool hasLoopVariableInIndices(const std::vector<Value*>& indices, Function* F);
int calculateConstantOffset(const std::vector<Value*>& indices);
void printStatistics() const; // 打印统计信息
private:
// ========== 配置选项 ==========
bool aggressiveParameterMode = false; // 激进的参数别名分析模式
bool parameterOptimizationEnabled = false; // 启用参数优化
};
} // namespace sysy

View File

@@ -0,0 +1,242 @@
#pragma once
#include "IR.h"
#include "Pass.h"
#include <map>
#include <set>
#include <vector>
#include <memory>
#include <algorithm>
#include <unordered_set>
namespace sysy {
// 前向声明
class CallGraphAnalysisResult;
/**
* @brief 调用图节点信息
* 存储单个函数在调用图中的信息
*/
struct CallGraphNode {
Function* function; // 关联的函数
std::set<Function*> callers; // 调用此函数的函数集合
std::set<Function*> callees; // 此函数调用的函数集合
// 递归信息
bool isRecursive; // 是否参与递归调用
bool isSelfRecursive; // 是否自递归
int recursiveDepth; // 递归深度(-1表示无限递归)
// 调用统计
size_t totalCallers; // 调用者总数
size_t totalCallees; // 被调用函数总数
size_t callSiteCount; // 调用点总数
CallGraphNode(Function* f) : function(f), isRecursive(false),
isSelfRecursive(false), recursiveDepth(0), totalCallers(0),
totalCallees(0), callSiteCount(0) {}
};
/**
* @brief 调用图分析结果类
* 包含整个模块的调用图信息和查询接口
*/
class CallGraphAnalysisResult : public AnalysisResultBase {
public:
CallGraphAnalysisResult(Module* M) : AssociatedModule(M) {}
~CallGraphAnalysisResult() override = default;
// ========== 基础查询接口 ==========
/**
* 获取函数的调用图节点
*/
const CallGraphNode* getNode(Function* F) const {
auto it = nodes.find(F);
return (it != nodes.end()) ? it->second.get() : nullptr;
}
/**
* 获取函数的调用图节点非const版本
*/
CallGraphNode* getMutableNode(Function* F) {
auto it = nodes.find(F);
return (it != nodes.end()) ? it->second.get() : nullptr;
}
/**
* 获取所有函数节点
*/
const std::map<Function*, std::unique_ptr<CallGraphNode>>& getAllNodes() const {
return nodes;
}
/**
* 检查函数是否存在于调用图中
*/
bool hasFunction(Function* F) const {
return nodes.find(F) != nodes.end();
}
// ========== 调用关系查询 ==========
/**
* 检查是否存在从caller到callee的调用
*/
bool hasCallEdge(Function* caller, Function* callee) const {
auto node = getNode(caller);
return node && node->callees.count(callee) > 0;
}
/**
* 获取函数的所有调用者
*/
std::vector<Function*> getCallers(Function* F) const {
auto node = getNode(F);
if (!node) return {};
return std::vector<Function*>(node->callers.begin(), node->callers.end());
}
/**
* 获取函数的所有被调用函数
*/
std::vector<Function*> getCallees(Function* F) const {
auto node = getNode(F);
if (!node) return {};
return std::vector<Function*>(node->callees.begin(), node->callees.end());
}
// ========== 递归分析查询 ==========
/**
* 检查函数是否参与递归调用
*/
bool isRecursive(Function* F) const {
auto node = getNode(F);
return node && node->isRecursive;
}
/**
* 检查函数是否自递归
*/
bool isSelfRecursive(Function* F) const {
auto node = getNode(F);
return node && node->isSelfRecursive;
}
/**
* 获取递归深度
*/
int getRecursiveDepth(Function* F) const {
auto node = getNode(F);
return node ? node->recursiveDepth : 0;
}
// ========== 拓扑排序和SCC ==========
/**
* 获取函数的拓扑排序结果
* 保证被调用函数在调用函数之前
*/
const std::vector<Function*>& getTopologicalOrder() const {
return topologicalOrder;
}
/**
* 获取强连通分量列表
* 每个SCC表示一个递归函数群
*/
const std::vector<std::vector<Function*>>& getStronglyConnectedComponents() const {
return sccs;
}
/**
* 获取函数所在的SCC索引
*/
int getSCCIndex(Function* F) const {
auto it = functionToSCC.find(F);
return (it != functionToSCC.end()) ? it->second : -1;
}
// ========== 统计信息 ==========
struct Statistics {
size_t totalFunctions;
size_t totalCallEdges;
size_t recursiveFunctions;
size_t selfRecursiveFunctions;
size_t stronglyConnectedComponents;
size_t maxSCCSize;
double avgCallersPerFunction;
double avgCalleesPerFunction;
};
Statistics getStatistics() const;
/**
* 打印调用图分析结果
*/
void print() const;
// ========== 内部构建接口 ==========
void addNode(Function* F);
void addCallEdge(Function* caller, Function* callee);
void computeTopologicalOrder();
void computeStronglyConnectedComponents();
void analyzeRecursion();
private:
Module* AssociatedModule; // 关联的模块
std::map<Function*, std::unique_ptr<CallGraphNode>> nodes; // 调用图节点
std::vector<Function*> topologicalOrder; // 拓扑排序结果
std::vector<std::vector<Function*>> sccs; // 强连通分量
std::map<Function*, int> functionToSCC; // 函数到SCC的映射
// 内部辅助方法
void dfsTopological(Function* F, std::unordered_set<Function*>& visited,
std::vector<Function*>& result);
void tarjanSCC();
void tarjanDFS(Function* F, int& index, std::vector<int>& indices,
std::vector<int>& lowlinks, std::vector<Function*>& stack,
std::unordered_set<Function*>& onStack);
};
/**
* @brief SysY调用图分析Pass
* Module级别的分析Pass构建整个模块的函数调用图
*/
class CallGraphAnalysisPass : public AnalysisPass {
public:
// 唯一的 Pass ID
static void* ID;
CallGraphAnalysisPass() : AnalysisPass("CallGraphAnalysis", Pass::Granularity::Module) {}
// 实现 getPassID
void* getPassID() const override { return &ID; }
// 核心运行方法
bool runOnModule(Module* M, AnalysisManager& AM) override;
// 获取分析结果
std::unique_ptr<AnalysisResultBase> getResult() override { return std::move(CurrentResult); }
private:
std::unique_ptr<CallGraphAnalysisResult> CurrentResult; // 当前模块的分析结果
// ========== 主要分析流程 ==========
void buildCallGraph(Module* M); // 构建调用图
void scanFunctionCalls(Function* F); // 扫描函数的调用
void processCallInstruction(CallInst* call, Function* caller); // 处理调用指令
// ========== 辅助方法 ==========
bool isLibraryFunction(Function* F) const; // 判断是否为标准库函数
bool isIntrinsicFunction(Function* F) const; // 判断是否为内置函数
void printStatistics() const; // 打印统计信息
};
} // namespace sysy

View File

@@ -0,0 +1,618 @@
#pragma once
#include "Dom.h"
#include "IR.h"
#include "Pass.h"
#include <algorithm>
#include <functional>
#include <map>
#include <memory>
#include <optional>
#include <queue>
#include <set>
#include <vector>
namespace sysy {
// 前向声明
class LoopAnalysisResult;
class AliasAnalysisResult;
class SideEffectAnalysisResult;
/**
* @brief 表示一个识别出的循环。
*/
class Loop {
private:
static int NextLoopID; // 静态变量用于分配唯一ID
int LoopID;
public:
// 构造函数:指定循环头
Loop(BasicBlock *header) : Header(header), LoopID(NextLoopID++) {}
// 获取循环头
BasicBlock *getHeader() const { return Header; }
// 获取循环的名称 基于ID
std::string getName() const { return "loop_" + std::to_string(LoopID); }
// 获取循环体包含的所有基本块
const std::set<BasicBlock *> &getBlocks() const { return LoopBlocks; }
// 获取循环的出口基本块(即从循环内部跳转到循环外部的基本块)
const std::set<BasicBlock *> &getExitBlocks() const { return ExitBlocks; }
// 获取循环前置块(如果存在),可以为 nullptr
BasicBlock *getPreHeader() const { return PreHeader; }
// 获取直接包含此循环的父循环(如果存在),可以为 nullptr
Loop *getParentLoop() const { return ParentLoop; }
// 获取直接嵌套在此循环内的子循环
const std::vector<Loop *> &getNestedLoops() const { return NestedLoops; }
// 获取循环的层级 (0 表示最外层循环1 表示嵌套一层,以此类推)
int getLoopLevel() const { return Level; }
// 检查一个基本块是否属于当前循环
bool contains(BasicBlock *BB) const { return LoopBlocks.count(BB); }
// 判断当前循环是否是最内层循环 (没有嵌套子循环)
bool isInnermost() const { return NestedLoops.empty(); }
// 获取循环的深度(从最外层开始计算)
int getLoopDepth() const { return Level + 1; }
// 获取循环体的大小(基本块数量)
size_t getLoopSize() const { return LoopBlocks.size(); }
// 检查循环是否有唯一的外部前驱(即是否有前置块)
bool hasUniquePreHeader() const { return PreHeader != nullptr; }
// 检查循环是否是最外层循环(没有父循环)
bool isOutermost() const { return getParentLoop() == nullptr; }
// 获取循环的所有出口(从循环内到循环外的基本块)
std::vector<BasicBlock*> getExitingBlocks() const {
std::vector<BasicBlock*> exitingBlocks;
for (BasicBlock* bb : LoopBlocks) {
for (BasicBlock* succ : bb->getSuccessors()) {
if (!contains(succ)) {
exitingBlocks.push_back(bb);
break; // 每个基本块只添加一次
}
}
}
return exitingBlocks;
}
// 判断循环是否是简单循环(只有一个回边)
bool isSimpleLoop() const {
int backEdgeCount = 0;
for (BasicBlock* pred : Header->getPredecessors()) {
if (contains(pred)) {
backEdgeCount++;
}
}
return backEdgeCount == 1;
}
/**
* 获取所有出口目标块 (循环外接收循环出口边的块)
* 使用场景: 循环后置处理、phi节点分析
*/
std::vector<BasicBlock*> getExitTargetBlocks() const {
std::set<BasicBlock*> exitTargetSet;
for (BasicBlock* bb : LoopBlocks) {
for (BasicBlock* succ : bb->getSuccessors()) {
if (!contains(succ)) {
exitTargetSet.insert(succ);
}
}
}
return std::vector<BasicBlock*>(exitTargetSet.begin(), exitTargetSet.end());
}
/**
* 计算循环的"深度"相对于指定的祖先循环
* 使用场景: 相对深度计算、嵌套分析
*/
int getRelativeDepth(Loop* ancestor) const {
if (this == ancestor) return 0;
int depth = 0;
Loop* current = this->ParentLoop;
while (current && current != ancestor) {
depth++;
current = current->ParentLoop;
}
return current == ancestor ? depth : -1; // -1表示不是祖先关系
}
/**
* 检查循环是否包含函数调用
* 使用场景: 内联决策、副作用分析
*/
bool containsFunctionCalls() const {
for (BasicBlock* bb : LoopBlocks) {
for (auto& inst : bb->getInstructions()) {
if (dynamic_cast<CallInst*>(inst.get())) {
return true;
}
}
}
return false;
}
/**
* 检查循环是否可能有副作用(基于副作用分析结果)
* 使用场景: 循环优化决策、并行化分析
*/
bool mayHaveSideEffects(SideEffectAnalysisResult* sideEffectAnalysis) const;
/**
* 检查循环是否访问全局内存(基于别名分析结果)
* 使用场景: 并行化分析、缓存优化
*/
bool accessesGlobalMemory(AliasAnalysisResult* aliasAnalysis) const;
/**
* 检查循环是否有可能的内存别名冲突
* 使用场景: 向量化分析、并行化决策
*/
bool hasMemoryAliasConflicts(AliasAnalysisResult* aliasAnalysis) const;
/**
* 估算循环的"热度" (基于嵌套深度和大小)
* 使用场景: 优化优先级、资源分配
*/
double getLoopHotness() const {
// 简单的热度估算: 深度权重 + 大小惩罚
double hotness = std::pow(2.0, Level); // 深度越深越热
hotness /= std::sqrt(LoopBlocks.size()); // 大小越大相对热度降低
return hotness;
}
// --- 供 LoopAnalysisPass 内部调用的方法,用于构建 Loop 对象 ---
void addBlock(BasicBlock *BB) { LoopBlocks.insert(BB); }
void addExitBlock(BasicBlock *BB) { ExitBlocks.insert(BB); }
void setPreHeader(BasicBlock *BB) { PreHeader = BB; }
void setParentLoop(Loop *loop) { ParentLoop = loop; }
void addNestedLoop(Loop *loop) { NestedLoops.push_back(loop); }
void setLoopLevel(int level) { Level = level; }
void clearNestedLoops() { NestedLoops.clear(); }
private:
BasicBlock *Header; // 循环头基本块
std::set<BasicBlock *> LoopBlocks; // 循环体包含的基本块集合
std::set<BasicBlock *> ExitBlocks; // 循环出口基本块集合
BasicBlock *PreHeader = nullptr; // 循环前置块 (Optional)
Loop *ParentLoop = nullptr; // 父循环 (用于嵌套)
std::vector<Loop *> NestedLoops; // 嵌套的子循环
int Level = -1; // 循环的层级,-1表示未计算
};
/**
* @brief 循环分析结果类。
* 包含一个函数中所有识别出的循环,并提供高效的查询缓存机制。
*/
class LoopAnalysisResult : public AnalysisResultBase {
public:
LoopAnalysisResult(Function *F) : AssociatedFunction(F) {}
~LoopAnalysisResult() override = default;
// ========== 缓存统计结构 ==========
struct CacheStats {
size_t innermostLoopsCached;
size_t outermostLoopsCached;
size_t loopsByDepthCached;
size_t containingLoopsCached;
size_t allNestedLoopsCached;
size_t totalCachedQueries;
};
private:
// ========== 高频查询缓存 ==========
mutable std::optional<std::vector<Loop*>> cachedInnermostLoops;
mutable std::optional<std::vector<Loop*>> cachedOutermostLoops;
mutable std::optional<int> cachedMaxDepth;
mutable std::optional<size_t> cachedLoopCount;
mutable std::map<int, std::vector<Loop*>> cachedLoopsByDepth;
// ========== 中频查询缓存 ==========
mutable std::map<BasicBlock*, Loop*> cachedInnermostContainingLoop;
mutable std::map<Loop*, std::set<Loop*>> cachedAllNestedLoops; // 递归嵌套
mutable std::map<BasicBlock*, std::vector<Loop*>> cachedAllContainingLoops;
// ========== 缓存状态管理 ==========
mutable bool cacheValid = true;
// 内部辅助方法
void invalidateCache() const {
cachedInnermostLoops.reset();
cachedOutermostLoops.reset();
cachedMaxDepth.reset();
cachedLoopCount.reset();
cachedLoopsByDepth.clear();
cachedInnermostContainingLoop.clear();
cachedAllNestedLoops.clear();
cachedAllContainingLoops.clear();
cacheValid = false;
}
void ensureCacheValid() const {
if (!cacheValid) {
// 重新计算基础缓存
computeBasicCache();
cacheValid = true;
}
}
void computeBasicCache() const {
// 计算最内层循环
if (!cachedInnermostLoops) {
cachedInnermostLoops = std::vector<Loop*>();
for (const auto& loop : AllLoops) {
if (loop->isInnermost()) {
cachedInnermostLoops->push_back(loop.get());
}
}
}
// 计算最外层循环
if (!cachedOutermostLoops) {
cachedOutermostLoops = std::vector<Loop*>();
for (const auto& loop : AllLoops) {
if (loop->isOutermost()) {
cachedOutermostLoops->push_back(loop.get());
}
}
}
// 计算最大深度
if (!cachedMaxDepth) {
int maxDepth = 0;
for (const auto& loop : AllLoops) {
maxDepth = std::max(maxDepth, loop->getLoopDepth());
}
cachedMaxDepth = maxDepth;
}
// 计算循环总数
if (!cachedLoopCount) {
cachedLoopCount = AllLoops.size();
}
}
public:
// ========== 基础接口 ==========
// 添加一个识别出的循环到结果中
void addLoop(std::unique_ptr<Loop> loop) {
invalidateCache(); // 添加新循环时失效缓存
AllLoops.push_back(std::move(loop));
LoopMap[AllLoops.back()->getHeader()] = AllLoops.back().get();
}
// 获取所有识别出的循环unique_ptr 管理内存)
const std::vector<std::unique_ptr<Loop>> &getAllLoops() const { return AllLoops; }
// ========== 高频查询接口 ==========
/**
* 获取所有最内层循环 - 循环优化的主要目标
* 使用场景: 循环展开、向量化、循环不变量外提
*/
const std::vector<Loop*>& getInnermostLoops() const {
ensureCacheValid();
if (!cachedInnermostLoops) {
cachedInnermostLoops = std::vector<Loop*>();
for (const auto& loop : AllLoops) {
if (loop->isInnermost()) {
cachedInnermostLoops->push_back(loop.get());
}
}
}
return *cachedInnermostLoops;
}
/**
* 获取所有最外层循环
* 使用场景: 循环树遍历、整体优化策略
*/
const std::vector<Loop*>& getOutermostLoops() const {
ensureCacheValid();
if (!cachedOutermostLoops) {
cachedOutermostLoops = std::vector<Loop*>();
for (const auto& loop : AllLoops) {
if (loop->isOutermost()) {
cachedOutermostLoops->push_back(loop.get());
}
}
}
return *cachedOutermostLoops;
}
/**
* 获取指定深度的所有循环
* 使用场景: 分层优化、循环展开决策、并行化分析
*/
const std::vector<Loop*>& getLoopsAtDepth(int depth) const {
ensureCacheValid();
if (cachedLoopsByDepth.find(depth) == cachedLoopsByDepth.end()) {
std::vector<Loop*> result;
for (const auto& loop : AllLoops) {
if (loop->getLoopDepth() == depth) {
result.push_back(loop.get());
}
}
cachedLoopsByDepth[depth] = std::move(result);
}
return cachedLoopsByDepth[depth];
}
/**
* 获取最大循环嵌套深度
* 使用场景: 优化预算分配、编译时间控制
*/
int getMaxLoopDepth() const {
ensureCacheValid();
if (!cachedMaxDepth) {
int maxDepth = 0;
for (const auto& loop : AllLoops) {
maxDepth = std::max(maxDepth, loop->getLoopDepth());
}
cachedMaxDepth = maxDepth;
}
return *cachedMaxDepth;
}
/**
* 获取循环总数
* 使用场景: 统计信息、优化决策
*/
size_t getLoopCount() const {
ensureCacheValid();
if (!cachedLoopCount) {
cachedLoopCount = AllLoops.size();
}
return *cachedLoopCount;
}
// 获取指定深度的循环数量
size_t getLoopCountAtDepth(int depth) const {
return getLoopsAtDepth(depth).size();
}
// 检查函数是否包含循环
bool hasLoops() const { return !AllLoops.empty(); }
// ========== 中频查询接口 ==========
/**
* 获取包含指定基本块的最内层循环
* 使用场景: 活跃性分析、寄存器分配、指令调度
*/
Loop* getInnermostContainingLoop(BasicBlock* BB) const {
ensureCacheValid();
if (cachedInnermostContainingLoop.find(BB) == cachedInnermostContainingLoop.end()) {
Loop* result = nullptr;
int maxDepth = -1;
for (const auto& loop : AllLoops) {
if (loop->contains(BB) && loop->getLoopDepth() > maxDepth) {
result = loop.get();
maxDepth = loop->getLoopDepth();
}
}
cachedInnermostContainingLoop[BB] = result;
}
return cachedInnermostContainingLoop[BB];
}
/**
* 获取包含指定基本块的所有循环 (从外到内排序)
* 使用场景: 循环间优化、依赖分析
*/
const std::vector<Loop*>& getAllContainingLoops(BasicBlock* BB) const {
ensureCacheValid();
if (cachedAllContainingLoops.find(BB) == cachedAllContainingLoops.end()) {
std::vector<Loop*> result;
for (const auto& loop : AllLoops) {
if (loop->contains(BB)) {
result.push_back(loop.get());
}
}
// 按深度排序 (外层到内层)
std::sort(result.begin(), result.end(),
[](Loop* a, Loop* b) { return a->getLoopDepth() < b->getLoopDepth(); });
cachedAllContainingLoops[BB] = std::move(result);
}
return cachedAllContainingLoops[BB];
}
/**
* 获取指定循环的所有嵌套子循环 (递归)
* 使用场景: 循环树分析、嵌套优化
*/
const std::set<Loop*>& getAllNestedLoops(Loop* loop) const {
ensureCacheValid();
if (cachedAllNestedLoops.find(loop) == cachedAllNestedLoops.end()) {
std::set<Loop*> result;
std::function<void(Loop*)> collectNested = [&](Loop* current) {
for (Loop* nested : current->getNestedLoops()) {
result.insert(nested);
collectNested(nested); // 递归收集
}
};
collectNested(loop);
cachedAllNestedLoops[loop] = std::move(result);
}
return cachedAllNestedLoops[loop];
}
// ========== 利用别名和副作用分析的查询接口 ==========
/**
* 获取所有纯循环(无副作用的循环)
* 并行化、循环优化
*/
std::vector<Loop*> getPureLoops(SideEffectAnalysisResult* sideEffectAnalysis) const {
std::vector<Loop*> result;
if (!sideEffectAnalysis) return result;
for (const auto& loop : AllLoops) {
if (!loop->mayHaveSideEffects(sideEffectAnalysis)) {
result.push_back(loop.get());
}
}
return result;
}
/**
* 获取所有只访问局部内存的循环
* 缓存优化、局部性分析
*/
std::vector<Loop*> getLocalMemoryLoops(AliasAnalysisResult* aliasAnalysis) const {
std::vector<Loop*> result;
if (!aliasAnalysis) return result;
for (const auto& loop : AllLoops) {
if (!loop->accessesGlobalMemory(aliasAnalysis)) {
result.push_back(loop.get());
}
}
return result;
}
/**
* 获取所有无内存别名冲突的循环
* 向量化、并行化
*/
std::vector<Loop*> getNoAliasConflictLoops(AliasAnalysisResult* aliasAnalysis) const {
std::vector<Loop*> result;
if (!aliasAnalysis) return result;
for (const auto& loop : AllLoops) {
if (!loop->hasMemoryAliasConflicts(aliasAnalysis)) {
result.push_back(loop.get());
}
}
return result;
}
// ========== 低频查询接口(不缓存) ==========
/**
* 检查两个循环是否有嵌套关系
* 循环间依赖分析
*/
bool isNestedLoop(Loop* inner, Loop* outer) const {
if (inner == outer) return false;
Loop* current = inner->getParentLoop();
while (current) {
if (current == outer) return true;
current = current->getParentLoop();
}
return false;
}
/**
* 获取两个循环的最近公共祖先循环
* 循环融合分析、优化范围确定
*/
Loop* getLowestCommonAncestor(Loop* loop1, Loop* loop2) const {
if (!loop1 || !loop2) return nullptr;
if (loop1 == loop2) return loop1;
// 收集loop1的所有祖先
std::set<Loop*> ancestors1;
Loop* current = loop1;
while (current) {
ancestors1.insert(current);
current = current->getParentLoop();
}
// 查找loop2祖先链中第一个在ancestors1中的循环
current = loop2;
while (current) {
if (ancestors1.count(current)) {
return current;
}
current = current->getParentLoop();
}
return nullptr; // 没有公共祖先
}
// 通过循环头获取 Loop 对象
Loop *getLoopForHeader(BasicBlock *header) const {
auto it = LoopMap.find(header);
return (it != LoopMap.end()) ? it->second : nullptr;
}
// 通过某个基本块获取包含它的最内层循环 (向后兼容接口)
Loop *getLoopContainingBlock(BasicBlock *BB) const {
return getInnermostContainingLoop(BB);
}
// ========== 缓存管理接口 ==========
/**
* 手动失效缓存 (可删除)
*/
void invalidateQueryCache() const {
invalidateCache();
}
/**
* 获取缓存统计信息
*/
CacheStats getCacheStats() const {
CacheStats stats = {};
stats.innermostLoopsCached = cachedInnermostLoops.has_value() ? 1 : 0;
stats.outermostLoopsCached = cachedOutermostLoops.has_value() ? 1 : 0;
stats.loopsByDepthCached = cachedLoopsByDepth.size();
stats.containingLoopsCached = cachedInnermostContainingLoop.size();
stats.allNestedLoopsCached = cachedAllNestedLoops.size();
stats.totalCachedQueries = stats.innermostLoopsCached + stats.outermostLoopsCached +
stats.loopsByDepthCached + stats.containingLoopsCached +
stats.allNestedLoopsCached;
return stats;
}
// 打印分析结果
void print() const;
void printBBSet(const std::string &prefix, const std::set<BasicBlock *> &s) const;
void printLoopVector(const std::string &prefix, const std::vector<Loop *> &loops) const;
private:
Function *AssociatedFunction; // 结果关联的函数
std::vector<std::unique_ptr<Loop>> AllLoops; // 所有识别出的循环
std::map<BasicBlock *, Loop *> LoopMap; // 循环头到 Loop* 的映射,方便查找
};
/**
* @brief 循环分析遍。
* 识别函数中的所有循环,并生成 LoopAnalysisResult。
*/
class LoopAnalysisPass : public AnalysisPass {
public:
// 唯一的 Pass ID需要在 .cpp 文件中定义
static void *ID;
LoopAnalysisPass() : AnalysisPass("LoopAnalysis", Pass::Granularity::Function) {}
// 实现 getPassID
void *getPassID() const override { return &ID; }
// 核心运行方法:在每个函数上执行循环分析
bool runOnFunction(Function *F, AnalysisManager &AM) override;
// 获取分析结果
std::unique_ptr<AnalysisResultBase> getResult() override { return std::move(CurrentResult); }
private:
std::unique_ptr<LoopAnalysisResult> CurrentResult; // 当前函数的分析结果
};
} // namespace sysy

View File

@@ -0,0 +1,356 @@
#pragma once
#include "Dom.h" // 支配树分析依赖
#include "Loop.h" // 循环分析依赖
#include "Liveness.h" // 活跃性分析依赖
#include "AliasAnalysis.h" // 别名分析依赖
#include "SideEffectAnalysis.h" // 副作用分析依赖
#include "CallGraphAnalysis.h" // 调用图分析依赖
#include "IR.h" // IR定义
#include "Pass.h" // Pass框架
#include <algorithm>
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <vector>
namespace sysy {
// 前向声明
class LoopCharacteristicsResult;
enum IVKind {
kBasic, // 基本归纳变量
kLinear, // 线性归纳变量
kCmplx // 复杂派生归纳变量
} ; // 归纳变量类型
struct InductionVarInfo {
Value* div; // 派生归纳变量的指令
Value* base = nullptr; // 其根phi或BIV或DIV
std::pair<Value*, Value*> Multibase = {nullptr, nullptr}; // 多个BIV
Instruction::Kind Instkind; // 操作类型
int factor = 1; // 系数如i*2+3的2
int offset = 0; // 常量偏移
bool valid; // 是否线性可归约
IVKind ivkind; // 归纳变量类型
static std::unique_ptr<InductionVarInfo> createBasicBIV(Value* v, Instruction::Kind kind, Value* base = nullptr, int factor = 1, int offset = 0) {
return std::make_unique<InductionVarInfo>(
InductionVarInfo{v, base, {nullptr, nullptr}, kind, factor, offset, true, IVKind::kBasic}
);
}
static std::unique_ptr<InductionVarInfo> createSingleDIV(Value* v, Instruction::Kind kind, Value* base = nullptr, int factor = 1, int offset = 0) {
return std::make_unique<InductionVarInfo>(
InductionVarInfo{v, base, {nullptr, nullptr}, kind, factor, offset, true, IVKind::kLinear}
);
}
static std::unique_ptr<InductionVarInfo> createDoubleDIV(Value* v, Instruction::Kind kind, Value* base1 = nullptr, Value* base2 = nullptr, int factor = 1, int offset = 0) {
return std::make_unique<InductionVarInfo>(
InductionVarInfo{v, nullptr, {base1, base2}, kind, factor, offset, false, IVKind::kCmplx}
);
}
};
/**
* @brief 循环特征信息结构 - 基础循环分析阶段
* 存储循环的基本特征信息,为后续精确分析提供基础
*/
struct LoopCharacteristics {
Loop* loop; // 关联的循环对象
// ========== 基础循环形式分析 ==========
bool isCountingLoop; // 是否为计数循环 (for i=0; i<n; i++)
bool isSimpleForLoop; // 是否为简单for循环
bool hasComplexControlFlow; // 是否有复杂控制流 (break, continue)
bool isInnermost; // 是否为最内层循环
// ========== 归纳变量分析 ==========
// ========== 基础循环不变量分析 ==========
std::unordered_set<Value*> loopInvariants; // 循环不变量
std::unordered_set<Instruction*> invariantInsts; // 可提升的不变指令
std::vector<std::unique_ptr<InductionVarInfo>> InductionVars; // 归纳变量
// ========== 基础边界分析 ==========
std::optional<int> staticTripCount; // 静态循环次数(如果可确定)
bool hasKnownBounds; // 是否有已知边界
// ========== 基础纯度和副作用分析 ==========
bool isPure; // 是否为纯循环(无副作用)
bool accessesOnlyLocalMemory; // 是否只访问局部内存
bool hasNoMemoryAliasConflicts; // 是否无内存别名冲突
// ========== 基础内存访问模式分析 ==========
struct MemoryAccessPattern {
std::vector<Instruction*> loadInsts; // load指令列表
std::vector<Instruction*> storeInsts; // store指令列表
bool isArrayParameter; // 是否为数组参数访问
bool isGlobalArray; // 是否为全局数组访问
bool hasConstantIndices; // 是否使用常量索引
};
std::map<Value*, MemoryAccessPattern> memoryPatterns; // 内存访问模式
// ========== 基础性能特征 ==========
size_t instructionCount; // 循环体指令数
size_t memoryOperationCount; // 内存操作数
size_t arithmeticOperationCount; // 算术操作数
double computeToMemoryRatio; // 计算与内存操作比率
// ========== 基础优化提示 ==========
bool benefitsFromUnrolling; // 是否适合循环展开
int suggestedUnrollFactor; // 建议的展开因子
// 构造函数 - 简化的基础分析初始化
LoopCharacteristics(Loop* l) : loop(l),
isCountingLoop(false), isSimpleForLoop(false), hasComplexControlFlow(false),
isInnermost(false), hasKnownBounds(false), isPure(false),
accessesOnlyLocalMemory(false), hasNoMemoryAliasConflicts(false),
benefitsFromUnrolling(false), suggestedUnrollFactor(1),
instructionCount(0), memoryOperationCount(0),
arithmeticOperationCount(0), computeToMemoryRatio(0.0) {}
};
/**
* @brief 循环特征分析结果类
* 包含函数中所有循环的特征信息,并提供查询接口
*/
class LoopCharacteristicsResult : public AnalysisResultBase {
public:
LoopCharacteristicsResult(Function *F) : AssociatedFunction(F) {}
~LoopCharacteristicsResult() override = default;
// ========== 基础接口 ==========
/**
* 添加循环特征信息
*/
void addLoopCharacteristics(std::unique_ptr<LoopCharacteristics> characteristics) {
auto* loop = characteristics->loop;
CharacteristicsMap[loop] = std::move(characteristics);
}
/**
* 获取指定循环的特征信息
*/
const LoopCharacteristics* getCharacteristics(Loop* loop) const {
auto it = CharacteristicsMap.find(loop);
return (it != CharacteristicsMap.end()) ? it->second.get() : nullptr;
}
/**
* 获取所有循环特征信息
*/
const std::map<Loop*, std::unique_ptr<LoopCharacteristics>>& getAllCharacteristics() const {
return CharacteristicsMap;
}
// ========== 核心查询接口 ==========
/**
* 获取所有计数循环
*/
std::vector<Loop*> getCountingLoops() const {
std::vector<Loop*> result;
for (const auto& [loop, chars] : CharacteristicsMap) {
if (chars->isCountingLoop) {
result.push_back(loop);
}
}
return result;
}
/**
* 获取所有纯循环(无副作用)
*/
std::vector<Loop*> getPureLoops() const {
std::vector<Loop*> result;
for (const auto& [loop, chars] : CharacteristicsMap) {
if (chars->isPure) {
result.push_back(loop);
}
}
return result;
}
/**
* 获取所有只访问局部内存的循环
*/
std::vector<Loop*> getLocalMemoryOnlyLoops() const {
std::vector<Loop*> result;
for (const auto& [loop, chars] : CharacteristicsMap) {
if (chars->accessesOnlyLocalMemory) {
result.push_back(loop);
}
}
return result;
}
/**
* 获取所有无内存别名冲突的循环
*/
std::vector<Loop*> getNoAliasConflictLoops() const {
std::vector<Loop*> result;
for (const auto& [loop, chars] : CharacteristicsMap) {
if (chars->hasNoMemoryAliasConflicts) {
result.push_back(loop);
}
}
return result;
}
/**
* 获取所有适合展开的循环
*/
std::vector<Loop*> getUnrollingCandidates() const {
std::vector<Loop*> result;
for (const auto& [loop, chars] : CharacteristicsMap) {
if (chars->benefitsFromUnrolling) {
result.push_back(loop);
}
}
return result;
}
/**
* 根据热度排序循环 (用于优化优先级)
*/
std::vector<Loop*> getLoopsByHotness() const {
std::vector<Loop*> result;
for (const auto& [loop, chars] : CharacteristicsMap) {
result.push_back(loop);
}
// 按循环热度排序 (嵌套深度 + 循环次数 + 指令数)
std::sort(result.begin(), result.end(), [](Loop* a, Loop* b) {
double hotnessA = a->getLoopHotness();
double hotnessB = b->getLoopHotness();
return hotnessA > hotnessB; // 降序排列
});
return result;
}
// ========== 基础统计接口 ==========
/**
* 获取基础优化统计信息
*/
struct BasicOptimizationStats {
size_t totalLoops;
size_t countingLoops;
size_t unrollingCandidates;
size_t pureLoops;
size_t localMemoryOnlyLoops;
size_t noAliasConflictLoops;
double avgInstructionCount;
double avgComputeMemoryRatio;
};
BasicOptimizationStats getOptimizationStats() const {
BasicOptimizationStats stats = {};
stats.totalLoops = CharacteristicsMap.size();
size_t totalInstructions = 0;
double totalComputeMemoryRatio = 0.0;
for (const auto& [loop, chars] : CharacteristicsMap) {
if (chars->isCountingLoop) stats.countingLoops++;
if (chars->benefitsFromUnrolling) stats.unrollingCandidates++;
if (chars->isPure) stats.pureLoops++;
if (chars->accessesOnlyLocalMemory) stats.localMemoryOnlyLoops++;
if (chars->hasNoMemoryAliasConflicts) stats.noAliasConflictLoops++;
totalInstructions += chars->instructionCount;
totalComputeMemoryRatio += chars->computeToMemoryRatio;
}
if (stats.totalLoops > 0) {
stats.avgInstructionCount = static_cast<double>(totalInstructions) / stats.totalLoops;
stats.avgComputeMemoryRatio = totalComputeMemoryRatio / stats.totalLoops;
}
return stats;
}
// 打印分析结果
void print() const;
private:
Function *AssociatedFunction; // 关联的函数
std::map<Loop*, std::unique_ptr<LoopCharacteristics>> CharacteristicsMap; // 循环特征映射
};
/**
* @brief 基础循环特征分析遍
* 在循环规范化前执行,进行基础的循环特征分析,为后续精确分析提供基础
*/
class LoopCharacteristicsPass : public AnalysisPass {
public:
// 唯一的 Pass ID
static void *ID;
LoopCharacteristicsPass() : AnalysisPass("LoopCharacteristics", Pass::Granularity::Function) {}
// 实现 getPassID
void *getPassID() const override { return &ID; }
// 核心运行方法
bool runOnFunction(Function *F, AnalysisManager &AM) override;
// 获取分析结果
std::unique_ptr<AnalysisResultBase> getResult() override { return std::move(CurrentResult); }
private:
std::unique_ptr<LoopCharacteristicsResult> CurrentResult;
// ========== 缓存的分析结果 ==========
LoopAnalysisResult* loopAnalysis; // 循环结构分析结果
AliasAnalysisResult* aliasAnalysis; // 别名分析结果
SideEffectAnalysisResult* sideEffectAnalysis; // 副作用分析结果
// ========== 核心分析方法 ==========
void analyzeLoop(Loop* loop, LoopCharacteristics* characteristics);
// 基础循环形式分析
void analyzeLoopForm(Loop* loop, LoopCharacteristics* characteristics);
// 基础性能指标计算
void computePerformanceMetrics(Loop* loop, LoopCharacteristics* characteristics);
// 基础纯度和副作用分析
void analyzePurityAndSideEffects(Loop* loop, LoopCharacteristics* characteristics);
// 基础归纳变量识别
void identifyBasicInductionVariables(Loop* loop, LoopCharacteristics* characteristics);
// 循环不变量识别
void identifyBasicLoopInvariants(Loop* loop, LoopCharacteristics* characteristics);
// 基础边界分析
void analyzeBasicLoopBounds(Loop* loop, LoopCharacteristics* characteristics);
// 基础内存访问模式分析
void analyzeBasicMemoryAccessPatterns(Loop* loop, LoopCharacteristics* characteristics);
// 基础优化评估
void evaluateBasicOptimizationOpportunities(Loop* loop, LoopCharacteristics* characteristics);
// ========== 辅助方法 ==========
bool isClassicLoopInvariant(Value* val, Loop* loop, const std::unordered_set<Value*>& invariants);
void findDerivedInductionVars(Value* root,
Value* base, // 只传单一BIV base
Loop* loop,
std::vector<std::unique_ptr<InductionVarInfo>>& ivs,
std::set<Value*>& visited
);
bool isBasicInductionVariable(Value* val, Loop* loop);
bool hasSimpleMemoryPattern(Loop* loop); // 简单的内存模式检查
};
} // namespace sysy

View File

@@ -0,0 +1,250 @@
#pragma once
#include "Pass.h"
#include "Loop.h"
#include "LoopCharacteristics.h"
#include "AliasAnalysis.h"
#include "SideEffectAnalysis.h"
#include <vector>
#include <map>
#include <memory>
#include <set>
#include <string>
namespace sysy {
/**
* @brief 依赖类型枚举 - 只考虑真正影响并行性的依赖
*
* 依赖类型分析说明:
* - TRUE_DEPENDENCE (RAW): 真依赖,必须保持原始执行顺序,是最关键的依赖
* - ANTI_DEPENDENCE (WAR): 反依赖,影响指令重排序,可通过寄存器重命名等技术缓解
* - OUTPUT_DEPENDENCE (WAW): 输出依赖,相对较少但需要考虑,可通过变量私有化解决
*
*/
enum class DependenceType {
TRUE_DEPENDENCE, // 真依赖 (RAW) - 读后写流依赖,最重要的依赖类型
ANTI_DEPENDENCE, // 反依赖 (WAR) - 写后读反向依赖,影响指令重排序
OUTPUT_DEPENDENCE // 输出依赖 (WAW) - 写后写,相对较少但需要考虑
};
/**
* @brief 依赖向量 - 表示两个内存访问之间的迭代距离
* 例如a[i] 和 a[i+1] 之间的依赖向量是 [1]
* a[i][j] 和 a[i+1][j-2] 之间的依赖向量是 [1,-2]
*/
struct DependenceVector {
std::vector<int> distances; // 每个循环层次的依赖距离
bool isConstant; // 是否为常量距离
bool isKnown; // 是否已知距离
DependenceVector(size_t loopDepth) : distances(loopDepth, 0), isConstant(false), isKnown(false) {}
// 检查是否为循环无关依赖
bool isLoopIndependent() const {
for (int dist : distances) {
if (dist != 0) return false;
}
return true;
}
// 获取词典序方向向量
std::vector<int> getDirectionVector() const;
// 检查是否可以通过向量化处理
bool isVectorizationSafe() const;
};
/**
* @brief 精确依赖关系 - 包含依赖向量的详细依赖信息
*/
struct PreciseDependence {
Instruction* source;
Instruction* sink;
DependenceType type;
DependenceVector dependenceVector;
Value* memoryLocation;
// 并行化相关
bool allowsParallelization; // 是否允许并行化
bool requiresSynchronization; // 是否需要同步
bool isReductionDependence; // 是否为归约依赖
PreciseDependence(size_t loopDepth) : dependenceVector(loopDepth),
allowsParallelization(true), requiresSynchronization(false), isReductionDependence(false) {}
};
/**
* @brief 向量化分析信息 - 暂时搁置,保留接口
*/
struct VectorizationAnalysis {
bool isVectorizable; // 固定为false暂不支持
int suggestedVectorWidth; // 固定为1
std::vector<std::string> preventingFactors; // 阻止向量化的因素
VectorizationAnalysis() : isVectorizable(false), suggestedVectorWidth(1) {
preventingFactors.push_back("Vectorization temporarily disabled");
}
};
/**
* @brief 并行化分析信息
*/
struct ParallelizationAnalysis {
bool isParallelizable; // 是否可并行化
int suggestedThreadCount; // 建议的线程数
std::vector<std::string> preventingFactors; // 阻止并行化的因素
// 并行化模式
enum ParallelizationType {
NONE, // 不可并行化
EMBARRASSINGLY_PARALLEL, // 完全并行
REDUCTION_PARALLEL, // 归约并行
PIPELINE_PARALLEL, // 流水线并行
CONDITIONAL_PARALLEL // 条件并行
} parallelType;
// 负载均衡
bool hasLoadBalance; // 是否有良好的负载均衡
bool isDynamicLoadBalanced; // 是否需要动态负载均衡
double workComplexity; // 工作复杂度估计
// 同步需求
bool requiresReduction; // 是否需要归约操作
bool requiresBarrier; // 是否需要屏障同步
std::set<Value*> sharedVariables; // 共享变量
std::set<Value*> reductionVariables; // 归约变量
std::set<Value*> privatizableVariables; // 可私有化变量
// 内存访问模式
bool hasMemoryConflicts; // 是否有内存冲突
bool hasReadOnlyAccess; // 是否只有只读访问
bool hasIndependentAccess; // 是否有独立的内存访问
// 并行化收益评估
double parallelizationBenefit; // 并行化收益估计 (0-1)
size_t communicationCost; // 通信开销估计
size_t synchronizationCost; // 同步开销估计
ParallelizationAnalysis() : isParallelizable(false), suggestedThreadCount(1), parallelType(NONE),
hasLoadBalance(true), isDynamicLoadBalanced(false), workComplexity(0.0), requiresReduction(false),
requiresBarrier(false), hasMemoryConflicts(false), hasReadOnlyAccess(false), hasIndependentAccess(false),
parallelizationBenefit(0.0), communicationCost(0), synchronizationCost(0) {}
};
/**
* @brief 循环向量化/并行化分析结果
*/
class LoopVectorizationResult : public AnalysisResultBase {
private:
Function* AssociatedFunction;
std::map<Loop*, VectorizationAnalysis> VectorizationMap;
std::map<Loop*, ParallelizationAnalysis> ParallelizationMap;
std::map<Loop*, std::vector<PreciseDependence>> DependenceMap;
public:
LoopVectorizationResult(Function* F) : AssociatedFunction(F) {}
~LoopVectorizationResult() override = default;
// 基础接口
void addVectorizationAnalysis(Loop* loop, VectorizationAnalysis analysis) {
VectorizationMap[loop] = std::move(analysis);
}
void addParallelizationAnalysis(Loop* loop, ParallelizationAnalysis analysis) {
ParallelizationMap[loop] = std::move(analysis);
}
void addDependenceAnalysis(Loop* loop, std::vector<PreciseDependence> dependences) {
DependenceMap[loop] = std::move(dependences);
}
// 查询接口
const VectorizationAnalysis* getVectorizationAnalysis(Loop* loop) const {
auto it = VectorizationMap.find(loop);
return it != VectorizationMap.end() ? &it->second : nullptr;
}
const ParallelizationAnalysis* getParallelizationAnalysis(Loop* loop) const {
auto it = ParallelizationMap.find(loop);
return it != ParallelizationMap.end() ? &it->second : nullptr;
}
const std::vector<PreciseDependence>* getPreciseDependences(Loop* loop) const {
auto it = DependenceMap.find(loop);
return it != DependenceMap.end() ? &it->second : nullptr;
}
// 统计接口
size_t getVectorizableLoopCount() const;
size_t getParallelizableLoopCount() const;
// 优化建议
std::vector<Loop*> getVectorizationCandidates() const;
std::vector<Loop*> getParallelizationCandidates() const;
// 打印分析结果
void print() const;
};
/**
* @brief 循环向量化/并行化分析遍
* 在循环规范化后执行,进行精确的依赖向量分析和向量化/并行化可行性评估
* 专注于并行化分析,向量化功能暂时搁置
*/
class LoopVectorizationPass : public AnalysisPass {
public:
// 唯一的 Pass ID
static void *ID;
LoopVectorizationPass() : AnalysisPass("LoopVectorization", Pass::Granularity::Function) {}
// 实现 getPassID
void *getPassID() const override { return &ID; }
// 核心运行方法
bool runOnFunction(Function *F, AnalysisManager &AM) override;
// 获取分析结果
std::unique_ptr<AnalysisResultBase> getResult() override { return std::move(CurrentResult); }
private:
std::unique_ptr<LoopVectorizationResult> CurrentResult;
// ========== 主要分析方法 ==========
void analyzeLoop(Loop* loop, LoopCharacteristics* characteristics,
AliasAnalysisResult* aliasAnalysis, SideEffectAnalysisResult* sideEffectAnalysis);
// ========== 依赖向量分析 ==========
std::vector<PreciseDependence> computeDependenceVectors(Loop* loop, AliasAnalysisResult* aliasAnalysis);
DependenceVector computeAccessDependence(Instruction* inst1, Instruction* inst2, Loop* loop);
bool areAccessesAffinelyRelated(Value* ptr1, Value* ptr2, Loop* loop);
// ========== 向量化分析 (暂时搁置) ==========
VectorizationAnalysis analyzeVectorizability(Loop* loop, const std::vector<PreciseDependence>& dependences,
LoopCharacteristics* characteristics);
// ========== 并行化分析 ==========
ParallelizationAnalysis analyzeParallelizability(Loop* loop, const std::vector<PreciseDependence>& dependences,
LoopCharacteristics* characteristics);
bool checkParallelizationLegality(Loop* loop, const std::vector<PreciseDependence>& dependences);
int estimateOptimalThreadCount(Loop* loop, LoopCharacteristics* characteristics);
ParallelizationAnalysis::ParallelizationType determineParallelizationType(Loop* loop,
const std::vector<PreciseDependence>& dependences);
// ========== 并行化专用分析方法 ==========
void analyzeReductionPatterns(Loop* loop, ParallelizationAnalysis* analysis);
void analyzeMemoryAccessPatterns(Loop* loop, ParallelizationAnalysis* analysis, AliasAnalysisResult* aliasAnalysis);
void estimateParallelizationBenefit(Loop* loop, ParallelizationAnalysis* analysis, LoopCharacteristics* characteristics);
void identifyPrivatizableVariables(Loop* loop, ParallelizationAnalysis* analysis);
void analyzeSynchronizationNeeds(Loop* loop, ParallelizationAnalysis* analysis, const std::vector<PreciseDependence>& dependences);
// ========== 辅助方法 ==========
std::vector<int> extractInductionCoefficients(Value* ptr, Loop* loop);
bool isConstantStride(Value* ptr, Loop* loop, int& stride);
bool isIndependentMemoryAccess(Value* ptr1, Value* ptr2, Loop* loop);
double estimateWorkComplexity(Loop* loop);
bool hasReductionPattern(Value* var, Loop* loop);
};
} // namespace sysy

View File

@@ -0,0 +1,137 @@
#pragma once
#include "Pass.h"
#include "IR.h"
#include "AliasAnalysis.h"
#include "CallGraphAnalysis.h"
#include <unordered_set>
#include <unordered_map>
namespace sysy {
// 副作用类型枚举
enum class SideEffectType {
NO_SIDE_EFFECT, // 无副作用
MEMORY_WRITE, // 内存写入store、memset
FUNCTION_CALL, // 函数调用(可能有任意副作用)
IO_OPERATION, // I/O操作printf、scanf等
UNKNOWN // 未知副作用
};
// 副作用信息结构
struct SideEffectInfo {
SideEffectType type = SideEffectType::NO_SIDE_EFFECT;
bool mayModifyGlobal = false; // 可能修改全局变量
bool mayModifyMemory = false; // 可能修改内存
bool mayCallFunction = false; // 可能调用函数
bool isPure = true; // 是否为纯函数(无副作用且结果只依赖参数)
// 合并两个副作用信息
SideEffectInfo merge(const SideEffectInfo& other) const {
SideEffectInfo result;
result.type = (type == SideEffectType::NO_SIDE_EFFECT) ? other.type : type;
result.mayModifyGlobal = mayModifyGlobal || other.mayModifyGlobal;
result.mayModifyMemory = mayModifyMemory || other.mayModifyMemory;
result.mayCallFunction = mayCallFunction || other.mayCallFunction;
result.isPure = isPure && other.isPure;
return result;
}
};
// 副作用分析结果类
class SideEffectAnalysisResult : public AnalysisResultBase {
private:
// 指令级别的副作用信息
std::unordered_map<Instruction*, SideEffectInfo> instructionSideEffects;
// 函数级别的副作用信息
std::unordered_map<Function*, SideEffectInfo> functionSideEffects;
// 已知的SysY标准库函数副作用信息
std::unordered_map<std::string, SideEffectInfo> knownFunctions;
public:
SideEffectAnalysisResult();
virtual ~SideEffectAnalysisResult() noexcept override = default;
// 获取指令的副作用信息
const SideEffectInfo& getInstructionSideEffect(Instruction* inst) const;
// 获取函数的副作用信息
const SideEffectInfo& getFunctionSideEffect(Function* func) const;
// 设置指令的副作用信息
void setInstructionSideEffect(Instruction* inst, const SideEffectInfo& info);
// 设置函数的副作用信息
void setFunctionSideEffect(Function* func, const SideEffectInfo& info);
// 检查指令是否有副作用
bool hasSideEffect(Instruction* inst) const;
// 检查指令是否可能修改内存
bool mayModifyMemory(Instruction* inst) const;
// 检查指令是否可能修改全局状态
bool mayModifyGlobal(Instruction* inst) const;
// 检查函数是否为纯函数
bool isPureFunction(Function* func) const;
// 获取已知函数的副作用信息
const SideEffectInfo* getKnownFunctionSideEffect(const std::string& funcName) const;
// 初始化已知函数的副作用信息
void initializeKnownFunctions();
private:
};
// 副作用分析遍类 - Module级别分析
class SysYSideEffectAnalysisPass : public AnalysisPass {
public:
// 静态成员作为该遍的唯一ID
static void* ID;
SysYSideEffectAnalysisPass() : AnalysisPass("SysYSideEffectAnalysis", Granularity::Module) {}
// 在模块上运行分析
bool runOnModule(Module* M, AnalysisManager& AM) override;
// 获取分析结果
std::unique_ptr<AnalysisResultBase> getResult() override;
// Pass 基类中的纯虚函数,必须实现
void* getPassID() const override { return &ID; }
private:
// 分析结果
std::unique_ptr<SideEffectAnalysisResult> result;
// 调用图分析结果
CallGraphAnalysisResult* callGraphAnalysis = nullptr;
// 分析单个函数的副作用Module级别的内部方法
SideEffectInfo analyzeFunction(Function* func, AnalysisManager& AM);
// 分析单个指令的副作用
SideEffectInfo analyzeInstruction(Instruction* inst, Function* currentFunc, AnalysisManager& AM);
// 分析函数调用指令的副作用(利用调用图)
SideEffectInfo analyzeCallInstruction(CallInst* call, Function* currentFunc, AnalysisManager& AM);
// 分析存储指令的副作用
SideEffectInfo analyzeStoreInstruction(StoreInst* store, Function* currentFunc, AnalysisManager& AM);
// 分析内存设置指令的副作用
SideEffectInfo analyzeMemsetInstruction(MemsetInst* memset, Function* currentFunc, AnalysisManager& AM);
// 使用不动点算法分析递归函数群
void analyzeStronglyConnectedComponent(const std::vector<Function*>& scc, AnalysisManager& AM);
// 检查函数间副作用传播的收敛性
bool hasConverged(const std::unordered_map<Function*, SideEffectInfo>& oldEffects,
const std::unordered_map<Function*, SideEffectInfo>& newEffects) const;
};
} // namespace sysy

View File

@@ -4,6 +4,8 @@
#include "IR.h"
#include "SysYIROptUtils.h"
#include "Dom.h"
#include "AliasAnalysis.h"
#include "SideEffectAnalysis.h"
#include <unordered_set>
#include <queue>
@@ -25,8 +27,12 @@ public:
private:
// 存储活跃指令的集合
std::unordered_set<Instruction*> alive_insts;
// 别名分析结果
AliasAnalysisResult* aliasAnalysis = nullptr;
// 副作用分析结果
SideEffectAnalysisResult* sideEffectAnalysis = nullptr;
// 判断指令是否是天然活跃的(即总是保留的)
// 判断指令是否是"天然活跃"的(即总是保留的)
// inst: 要检查的指令
// 返回值: 如果指令是天然活跃的则为true否则为false
bool isAlive(Instruction* inst);
@@ -34,6 +40,9 @@ private:
// 递归地将活跃指令及其依赖加入到 alive_insts 集合中
// inst: 要标记为活跃的指令
void addAlive(Instruction* inst);
// 检查Store指令是否可能有副作用通过别名分析
bool mayHaveSideEffect(StoreInst* store);
};
// DCE 优化遍类,继承自 OptimizationPass

View File

@@ -0,0 +1,252 @@
#pragma once
#include "Pass.h"
#include "IR.h"
#include "LoopCharacteristics.h"
#include "Loop.h"
#include "Dom.h"
#include "SideEffectAnalysis.h"
#include "AliasAnalysis.h"
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <memory>
namespace sysy {
// 前向声明
class LoopCharacteristicsResult;
class LoopAnalysisResult;
/**
* @brief 死归纳变量信息
* 记录一个可以被消除的归纳变量
*/
struct DeadInductionVariable {
PhiInst* phiInst; // phi 指令
std::vector<Instruction*> relatedInsts; // 相关的递增/递减指令
Loop* containingLoop; // 所在循环
bool canEliminate; // 是否可以安全消除
DeadInductionVariable(PhiInst* phi, Loop* loop)
: phiInst(phi), containingLoop(loop), canEliminate(false) {}
};
/**
* @brief 归纳变量消除上下文类
* 封装归纳变量消除优化的核心逻辑和状态
*/
class InductionVariableEliminationContext {
public:
InductionVariableEliminationContext() {}
/**
* 运行归纳变量消除优化
* @param F 目标函数
* @param AM 分析管理器
* @return 是否修改了IR
*/
bool run(Function* F, AnalysisManager& AM);
private:
// 分析结果缓存
LoopAnalysisResult* loopAnalysis = nullptr;
LoopCharacteristicsResult* loopCharacteristics = nullptr;
DominatorTree* dominatorTree = nullptr;
SideEffectAnalysisResult* sideEffectAnalysis = nullptr;
AliasAnalysisResult* aliasAnalysis = nullptr;
// 死归纳变量存储
std::vector<std::unique_ptr<DeadInductionVariable>> deadIVs;
std::unordered_map<Loop*, std::vector<DeadInductionVariable*>> loopToDeadIVs;
// ========== 核心分析和优化阶段 ==========
/**
* 阶段1识别死归纳变量
* 找出没有被有效使用的归纳变量
*/
void identifyDeadInductionVariables(Function* F);
/**
* 阶段2分析消除的安全性
* 确保消除操作不会破坏程序语义
*/
void analyzeSafetyForElimination();
/**
* 阶段3执行归纳变量消除
* 删除死归纳变量及其相关指令
*/
bool performInductionVariableElimination();
// ========== 辅助方法 ==========
/**
* 检查归纳变量是否为死归纳变量
* @param iv 归纳变量信息
* @param loop 所在循环
* @return 如果是死归纳变量返回相关信息否则返回nullptr
*/
std::unique_ptr<DeadInductionVariable>
isDeadInductionVariable(const InductionVarInfo* iv, Loop* loop);
/**
* 递归分析phi指令及其使用链是否都是死代码
* @param phiInst phi指令
* @param loop 所在循环
* @return phi指令是否可以安全删除
*/
bool isPhiInstructionDeadRecursively(PhiInst* phiInst, Loop* loop);
/**
* 递归分析指令的使用链是否都是死代码
* @param inst 要分析的指令
* @param loop 所在循环
* @param visited 已访问的指令集合(避免无限递归)
* @param currentPath 当前递归路径(检测循环依赖)
* @return 指令的使用链是否都是死代码
*/
bool isInstructionUseChainDeadRecursively(Instruction* inst, Loop* loop,
std::set<Instruction*>& visited,
std::set<Instruction*>& currentPath);
/**
* 检查循环是否有副作用
* @param loop 要检查的循环
* @return 循环是否有副作用
*/
bool loopHasSideEffects(Loop* loop);
/**
* 检查指令是否被用于循环退出条件
* @param inst 要检查的指令
* @param loop 所在循环
* @return 是否被用于循环退出条件
*/
bool isUsedInLoopExitCondition(Instruction* inst, Loop* loop);
/**
* 检查指令的结果是否未被有效使用
* @param inst 要检查的指令
* @param loop 所在循环
* @return 指令结果是否未被有效使用
*/
bool isInstructionResultUnused(Instruction* inst, Loop* loop);
/**
* 检查store指令是否存储到死地址利用别名分析
* @param store store指令
* @param loop 所在循环
* @return 是否存储到死地址
*/
bool isStoreToDeadLocation(StoreInst* store, Loop* loop);
/**
* 检查指令是否为死代码或只在循环内部使用
* @param inst 要检查的指令
* @param loop 所在循环
* @return 是否为死代码或只在循环内部使用
*/
bool isInstructionDeadOrInternalOnly(Instruction* inst, Loop* loop);
/**
* 检查指令是否有效地为死代码(带递归深度限制)
* @param inst 要检查的指令
* @param loop 所在循环
* @param maxDepth 最大递归深度
* @return 指令是否有效地为死代码
*/
bool isInstructionEffectivelyDead(Instruction* inst, Loop* loop, int maxDepth);
/**
* 检查store指令是否有后续的load操作
* @param store store指令
* @param loop 所在循环
* @return 是否有后续的load操作
*/
bool hasSubsequentLoad(StoreInst* store, Loop* loop);
/**
* 检查指令是否在循环外有使用
* @param inst 要检查的指令
* @param loop 所在循环
* @return 是否在循环外有使用
*/
bool hasUsageOutsideLoop(Instruction* inst, Loop* loop);
/**
* 检查store指令是否在循环外有后续的load操作
* @param store store指令
* @param loop 所在循环
* @return 是否在循环外有后续的load操作
*/
bool hasSubsequentLoadOutsideLoop(StoreInst* store, Loop* loop);
/**
* 递归检查基本块子树中是否有对指定位置的load操作
* @param bb 基本块
* @param ptr 指针
* @param visited 已访问的基本块集合
* @return 是否有load操作
*/
bool hasLoadInSubtree(BasicBlock* bb, Value* ptr, std::set<BasicBlock*>& visited);
/**
* 收集与归纳变量相关的所有指令
* @param phiInst phi指令
* @param loop 所在循环
* @return 相关指令列表
*/
std::vector<Instruction*> collectRelatedInstructions(PhiInst* phiInst, Loop* loop);
/**
* 检查消除归纳变量的安全性
* @param deadIV 死归纳变量
* @return 是否可以安全消除
*/
bool isSafeToEliminate(const DeadInductionVariable* deadIV);
/**
* 消除单个死归纳变量
* @param deadIV 死归纳变量
* @return 是否成功消除
*/
bool eliminateDeadInductionVariable(DeadInductionVariable* deadIV);
/**
* 打印调试信息
*/
void printDebugInfo();
};
/**
* @brief 归纳变量消除优化遍
* 消除循环中无用的归纳变量,减少寄存器压力
*/
class InductionVariableElimination : public OptimizationPass {
public:
// 唯一的 Pass ID
static void *ID;
InductionVariableElimination()
: OptimizationPass("InductionVariableElimination", Granularity::Function) {}
/**
* 在函数上运行归纳变量消除优化
* @param F 目标函数
* @param AM 分析管理器
* @return 是否修改了IR
*/
bool runOnFunction(Function* F, AnalysisManager& AM) override;
/**
* 声明分析依赖和失效信息
*/
void getAnalysisUsage(std::set<void*>& analysisDependencies,
std::set<void*>& analysisInvalidations) const override;
void* getPassID() const override { return &ID; }
};
} // namespace sysy

View File

@@ -0,0 +1,40 @@
#pragma once
#include "Pass.h"
#include "Loop.h"
#include "LoopCharacteristics.h"
#include "Dom.h"
#include <unordered_set>
#include <vector>
namespace sysy{
class LICMContext {
public:
LICMContext(Function* func, Loop* loop, IRBuilder* builder, const LoopCharacteristics* chars)
: func(func), loop(loop), builder(builder), chars(chars) {}
// 运行LICM主流程返回IR是否被修改
bool run();
private:
Function* func;
Loop* loop;
IRBuilder* builder;
const LoopCharacteristics* chars; // 特征分析结果
// 外提所有可提升指令
bool hoistInstructions();
};
class LICM : public OptimizationPass{
private:
IRBuilder *builder; ///< IR构建器用于插入指令
public:
static void *ID;
LICM(IRBuilder *builder = nullptr) : OptimizationPass("LICM", Granularity::Function) , builder(builder) {}
bool runOnFunction(Function *F, AnalysisManager &AM) override;
void getAnalysisUsage(std::set<void *> &, std::set<void *> &) const override;
void *getPassID() const override { return &ID; }
};
} // namespace sysy

View File

@@ -0,0 +1,155 @@
#pragma once
#include "Loop.h" // 循环分析依赖
#include "Dom.h" // 支配树分析依赖
#include "IR.h" // IR定义
#include "IRBuilder.h" // IR构建器
#include "Pass.h" // Pass框架
#include <memory>
#include <set>
#include <vector>
namespace sysy {
/**
* @brief 循环规范化转换Pass
*
* 该Pass在循环不变量提升等优化前运行主要负责
* 1. 为没有前置块(preheader)的循环创建前置块
* 2. 确保循环结构符合后续优化的要求
* 3. 规范化循环的控制流结构
*
* 前置块的作用:
* - 为循环不变量提升提供插入位置
* - 简化循环分析和优化
* - 确保循环有唯一的入口点
*/
class LoopNormalizationPass : public OptimizationPass {
public:
// 唯一的 Pass ID
static void *ID;
LoopNormalizationPass(IRBuilder* builder) : OptimizationPass("LoopNormalization", Pass::Granularity::Function), builder(builder) {}
// 实现 getPassID
void *getPassID() const override { return &ID; }
// 核心运行方法
bool runOnFunction(Function *F, AnalysisManager &AM) override;
// 声明分析依赖和失效信息
void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const override;
private:
// ========== IR构建器 ==========
IRBuilder* builder; // IR构建器
// ========== 缓存的分析结果 ==========
LoopAnalysisResult* loopAnalysis; // 循环结构分析结果
DominatorTree* domTree; // 支配树分析结果
// ========== 规范化统计 ==========
struct NormalizationStats {
size_t totalLoops; // 总循环数
size_t loopsNeedingPreheader; // 需要前置块的循环数
size_t preheadersCreated; // 创建的前置块数
size_t loopsNormalized; // 规范化的循环数
size_t redundantPhisRemoved; // 删除的冗余PHI节点数
NormalizationStats() : totalLoops(0), loopsNeedingPreheader(0),
preheadersCreated(0), loopsNormalized(0),
redundantPhisRemoved(0) {}
} stats;
// ========== 核心规范化方法 ==========
/**
* 规范化单个循环
* @param loop 要规范化的循环
* @return 是否进行了修改
*/
bool normalizeLoop(Loop* loop);
/**
* 为循环创建前置块
* @param loop 需要前置块的循环
* @return 创建的前置块如果失败则返回nullptr
*/
BasicBlock* createPreheaderForLoop(Loop* loop);
/**
* 检查循环是否需要前置块(基于结构性需求)
* @param loop 要检查的循环
* @return true如果需要前置块
*/
bool needsPreheader(Loop* loop);
/**
* 检查循环是否已有合适的前置块
* @param loop 要检查的循环
* @return 现有的前置块如果没有则返回nullptr
*/
BasicBlock* getExistingPreheader(Loop* loop);
/**
* 更新支配树关系(在创建新块后)
* @param newBlock 新创建的基本块
* @param loop 相关的循环
*/
void updateDominatorRelations(BasicBlock* newBlock, Loop* loop);
/**
* 重定向循环外的前驱块到新的前置块
* @param loop 目标循环
* @param preheader 新创建的前置块
* @param header 循环头部
*/
void redirectExternalPredecessors(Loop* loop, BasicBlock* preheader, BasicBlock* header, const std::vector<BasicBlock*>& externalPreds);
/**
* 为前置块生成合适的名称
* @param loop 相关的循环
* @return 生成的前置块名称
*/
std::string generatePreheaderName(Loop* loop);
/**
* 验证规范化结果的正确性
* @param loop 规范化后的循环
* @return true如果规范化正确
*/
bool validateNormalization(Loop* loop);
// ========== 辅助方法 ==========
/**
* 获取循环的外部前驱块(不在循环内的前驱)
* @param loop 目标循环
* @return 外部前驱块列表
*/
std::vector<BasicBlock*> getExternalPredecessors(Loop* loop);
/**
* 检查基本块是否适合作为前置块
* @param block 候选基本块
* @param loop 目标循环
* @return true如果适合作为前置块
*/
bool isSuitableAsPreheader(BasicBlock* block, Loop* loop);
/**
* 更新PHI节点以适应新的前置块
* @param header 循环头部
* @param preheader 新的前置块
* @param oldPreds 原来的外部前驱
*/
void updatePhiNodesForPreheader(BasicBlock* header, BasicBlock* preheader,
const std::vector<BasicBlock*>& oldPreds);
/**
* 打印规范化统计信息
*/
void printStats(Function* F);
};
} // namespace sysy

View File

@@ -0,0 +1,240 @@
#pragma once
#include "Pass.h"
#include "IR.h"
#include "LoopCharacteristics.h"
#include "Loop.h"
#include "Dom.h"
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <memory>
namespace sysy {
// 前向声明
class LoopCharacteristicsResult;
class LoopAnalysisResult;
/**
* @brief 强度削弱候选项信息
* 记录一个可以进行强度削弱的表达式信息
*/
struct StrengthReductionCandidate {
enum OpType {
MULTIPLY, // 乘法: iv * const
DIVIDE, // 除法: iv / 2^n (转换为右移)
DIVIDE_CONST, // 除法: iv / const (使用mulh指令优化)
REMAINDER // 取模: iv % 2^n (转换为位与)
};
enum DivisionStrategy {
SIMPLE_SHIFT, // 简单右移(仅适用于无符号或非负数)
SIGNED_CORRECTION, // 有符号除法修正: (x + (x >> 31) & mask) >> k
MULH_OPTIMIZATION // 使用mulh指令优化任意常数除法
};
Instruction* originalInst; // 原始指令 (如 i*4, i/8, i%16)
Value* inductionVar; // 归纳变量 (如 i)
OpType operationType; // 操作类型
DivisionStrategy divStrategy; // 除法策略(仅用于除法)
int multiplier; // 乘数/除数/模数 (如 4, 8, 16)
int shiftAmount; // 位移量 (对于2的幂)
int offset; // 偏移量 (如常数项)
BasicBlock* containingBlock; // 所在基本块
Loop* containingLoop; // 所在循环
bool hasNegativeValues; // 归纳变量是否可能为负数
// 强度削弱后的新变量
PhiInst* newPhi = nullptr; // 新的 phi 指令
Value* newInductionVar = nullptr; // 新的归纳变量
StrengthReductionCandidate(Instruction* inst, Value* iv, OpType opType, int value, int off,
BasicBlock* bb, Loop* loop)
: originalInst(inst), inductionVar(iv), operationType(opType),
divStrategy(SIMPLE_SHIFT), multiplier(value), offset(off),
containingBlock(bb), containingLoop(loop), hasNegativeValues(false) {
// 计算位移量(用于除法和取模的强度削弱)
if (opType == DIVIDE || opType == REMAINDER) {
shiftAmount = 0;
int temp = value;
while (temp > 1) {
temp >>= 1;
shiftAmount++;
}
} else {
shiftAmount = 0;
}
}
};
/**
* @brief 强度削弱上下文类
* 封装强度削弱优化的核心逻辑和状态
*/
class StrengthReductionContext {
public:
StrengthReductionContext(IRBuilder* builder) : builder(builder) {}
/**
* 运行强度削弱优化
* @param F 目标函数
* @param AM 分析管理器
* @return 是否修改了IR
*/
bool run(Function* F, AnalysisManager& AM);
private:
IRBuilder* builder;
// 分析结果缓存
LoopAnalysisResult* loopAnalysis = nullptr;
LoopCharacteristicsResult* loopCharacteristics = nullptr;
DominatorTree* dominatorTree = nullptr;
// 候选项存储
std::vector<std::unique_ptr<StrengthReductionCandidate>> candidates;
std::unordered_map<Loop*, std::vector<StrengthReductionCandidate*>> loopToCandidates;
// ========== 核心分析和优化阶段 ==========
/**
* 阶段1识别强度削弱候选项
* 扫描所有循环中的乘法指令,找出可以优化的模式
*/
void identifyStrengthReductionCandidates(Function* F);
/**
* 阶段2分析候选项的优化潜力
* 评估每个候选项的收益,过滤掉不值得优化的情况
*/
void analyzeOptimizationPotential();
/**
* 阶段3执行强度削弱变换
* 对选中的候选项执行实际的强度削弱优化
*/
bool performStrengthReduction();
// ========== 辅助分析函数 ==========
/**
* 分析归纳变量是否可能取负值
* @param ivInfo 归纳变量信息
* @param loop 所属循环
* @return 如果可能为负数返回true
*/
bool analyzeInductionVariableRange(const InductionVarInfo* ivInfo, Loop* loop) const;
/**
* 计算用于除法优化的魔数和移位量
* @param divisor 除数
* @return {魔数, 移位量}
*/
std::pair<int, int> computeMulhMagicNumbers(int divisor) const;
/**
* 生成除法替换代码
* @param candidate 优化候选项
* @param builder IR构建器
* @return 替换值
*/
Value* generateDivisionReplacement(StrengthReductionCandidate* candidate, IRBuilder* builder) const;
/**
* 生成任意常数除法替换代码
* @param candidate 优化候选项
* @param builder IR构建器
* @return 替换值
*/
Value* generateConstantDivisionReplacement(StrengthReductionCandidate* candidate, IRBuilder* builder) const;
/**
* 检查指令是否为强度削弱候选项
* @param inst 要检查的指令
* @param loop 所在循环
* @return 如果是候选项返回候选项信息否则返回nullptr
*/
std::unique_ptr<StrengthReductionCandidate>
isStrengthReductionCandidate(Instruction* inst, Loop* loop);
/**
* 检查值是否为循环的归纳变量
* @param val 要检查的值
* @param loop 循环
* @param characteristics 循环特征信息
* @return 如果是归纳变量返回归纳变量信息否则返回nullptr
*/
const InductionVarInfo*
getInductionVarInfo(Value* val, Loop* loop, const LoopCharacteristics* characteristics);
/**
* 为候选项创建新的归纳变量
* @param candidate 候选项
* @return 是否成功创建
*/
bool createNewInductionVariable(StrengthReductionCandidate* candidate);
/**
* 替换原始指令的所有使用
* @param candidate 候选项
* @return 是否成功替换
*/
bool replaceOriginalInstruction(StrengthReductionCandidate* candidate);
/**
* 估算优化收益
* 计算强度削弱后的性能提升
* @param candidate 候选项
* @return 估算的收益分数
*/
double estimateOptimizationBenefit(const StrengthReductionCandidate* candidate);
/**
* 检查优化的合法性
* @param candidate 候选项
* @return 是否可以安全地进行优化
*/
bool isOptimizationLegal(const StrengthReductionCandidate* candidate);
/**
* 打印调试信息
*/
void printDebugInfo();
};
/**
* @brief 循环强度削弱优化遍
* 将循环中的乘法运算转换为更高效的加法运算
*/
class LoopStrengthReduction : public OptimizationPass {
public:
// 唯一的 Pass ID
static void *ID;
LoopStrengthReduction(IRBuilder* builder)
: OptimizationPass("LoopStrengthReduction", Granularity::Function),
builder(builder) {}
/**
* 在函数上运行强度削弱优化
* @param F 目标函数
* @param AM 分析管理器
* @return 是否修改了IR
*/
bool runOnFunction(Function* F, AnalysisManager& AM) override;
/**
* 声明分析依赖和失效信息
*/
void getAnalysisUsage(std::set<void*>& analysisDependencies,
std::set<void*>& analysisInvalidations) const override;
void* getPassID() const override { return &ID; }
private:
IRBuilder* builder;
};
} // namespace sysy

View File

@@ -3,6 +3,8 @@
#include "IR.h"
#include "Pass.h"
#include "SysYIROptUtils.h"
#include "AliasAnalysis.h"
#include "SideEffectAnalysis.h"
#include <cassert>
#include <iostream>
#include <map>
@@ -63,6 +65,8 @@ struct SSAPValue {
class SCCPContext {
private:
IRBuilder *builder; // IR 构建器,用于插入指令和创建常量
AliasAnalysisResult *aliasAnalysis; // 别名分析结果
SideEffectAnalysisResult *sideEffectAnalysis; // 副作用分析结果
// 工作列表
// 存储需要重新评估的指令
@@ -92,6 +96,14 @@ private:
SSAPValue ComputeConstant(BinaryInst *binaryinst, SSAPValue lhsVal, SSAPValue rhsVal);
// 辅助函数:对一元操作进行常量折叠
SSAPValue ComputeConstant(UnaryInst *unaryInst, SSAPValue operandVal);
// 辅助函数:检查是否为已知的纯函数
bool isKnownPureFunction(const std::string &funcName) const;
// 辅助函数:计算纯函数的常量结果
SSAPValue computePureFunctionResult(CallInst *call, const std::vector<SSAPValue> &argValues);
// 辅助函数:查找存储到指定位置的常量值
SSAPValue findStoredConstantValue(Value *ptr, BasicBlock *currentBB);
// 辅助函数动态检查数组访问是否为常量索引考虑SCCP状态
bool hasRuntimeConstantAccess(Value *ptr);
// 主要优化阶段
// 阶段1: 常量传播与折叠
@@ -117,7 +129,13 @@ private:
void RemovePhiIncoming(BasicBlock *phiParentBB, BasicBlock *removedPred);
public:
SCCPContext(IRBuilder *builder) : builder(builder) {}
SCCPContext(IRBuilder *builder) : builder(builder), aliasAnalysis(nullptr), sideEffectAnalysis(nullptr) {}
// 设置别名分析结果
void setAliasAnalysis(AliasAnalysisResult *aa) { aliasAnalysis = aa; }
// 设置副作用分析结果
void setSideEffectAnalysis(SideEffectAnalysisResult *sea) { sideEffectAnalysis = sea; }
// 运行 SCCP 优化
void run(Function *func, AnalysisManager &AM);

View File

@@ -151,17 +151,21 @@ public:
}
AnalysisPass *analysisPass = static_cast<AnalysisPass *>(basePass.get());
if(DEBUG){
std::cout << "Running Analysis Pass: " << analysisPass->getName() << "\n";
}
// 根据分析遍的粒度处理
switch (analysisPass->getGranularity()) {
case Pass::Granularity::Module: {
// 检查是否已存在有效结果
auto it = moduleCachedResults.find(analysisID);
if (it != moduleCachedResults.end()) {
if(DEBUG) {
std::cout << "Using cached result for Analysis Pass: " << analysisPass->getName() << "\n";
}
return static_cast<T *>(it->second.get()); // 返回缓存结果
}
// 只有在实际运行时才打印调试信息
if(DEBUG){
std::cout << "Running Analysis Pass: " << analysisPass->getName() << "\n";
}
// 运行模块级分析遍
if (!pModuleRef) {
std::cerr << "Error: Module reference not set for AnalysisManager to run Module Pass.\n";
@@ -183,8 +187,16 @@ public:
// 检查是否已存在有效结果
auto it = functionCachedResults.find({F, analysisID});
if (it != functionCachedResults.end()) {
if(DEBUG) {
std::cout << "Using cached result for Analysis Pass: " << analysisPass->getName() << " (Function: " << F->getName() << ")\n";
}
return static_cast<T *>(it->second.get()); // 返回缓存结果
}
// 只有在实际运行时才打印调试信息
if(DEBUG){
std::cout << "Running Analysis Pass: " << analysisPass->getName() << "\n";
std::cout << "Function: " << F->getName() << "\n";
}
// 运行函数级分析遍
analysisPass->runOnFunction(F, *this);
// 获取结果并缓存
@@ -202,8 +214,16 @@ public:
// 检查是否已存在有效结果
auto it = basicBlockCachedResults.find({BB, analysisID});
if (it != basicBlockCachedResults.end()) {
if(DEBUG) {
std::cout << "Using cached result for Analysis Pass: " << analysisPass->getName() << " (BasicBlock: " << BB->getName() << ")\n";
}
return static_cast<T *>(it->second.get()); // 返回缓存结果
}
// 只有在实际运行时才打印调试信息
if(DEBUG){
std::cout << "Running Analysis Pass: " << analysisPass->getName() << "\n";
std::cout << "BasicBlock: " << BB->getName() << "\n";
}
// 运行基本块级分析遍
analysisPass->runOnBasicBlock(BB, *this);
// 获取结果并缓存

View File

@@ -6,11 +6,21 @@ add_library(midend_lib STATIC
Pass/Pass.cpp
Pass/Analysis/Dom.cpp
Pass/Analysis/Liveness.cpp
Pass/Analysis/Loop.cpp
Pass/Analysis/LoopCharacteristics.cpp
Pass/Analysis/LoopVectorization.cpp
Pass/Analysis/AliasAnalysis.cpp
Pass/Analysis/SideEffectAnalysis.cpp
Pass/Analysis/CallGraphAnalysis.cpp
Pass/Optimize/DCE.cpp
Pass/Optimize/Mem2Reg.cpp
Pass/Optimize/Reg2Mem.cpp
Pass/Optimize/SysYIRCFGOpt.cpp
Pass/Optimize/SCCP.cpp
Pass/Optimize/LoopNormalization.cpp
Pass/Optimize/LICM.cpp
Pass/Optimize/LoopStrengthReduction.cpp
Pass/Optimize/InductionVariableElimination.cpp
Pass/Optimize/BuildCFG.cpp
Pass/Optimize/LargeArrayToGlobal.cpp
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,559 @@
#include "AliasAnalysis.h"
#include "SysYIRPrinter.h"
#include <iostream>
extern int DEBUG;
namespace sysy {
// 静态成员初始化
void *SysYAliasAnalysisPass::ID = (void *)&SysYAliasAnalysisPass::ID;
// ========== AliasAnalysisResult 实现 ==========
void AliasAnalysisResult::print() const {
std::cout << "---- Alias Analysis Results for Function: " << AssociatedFunction->getName() << " ----\n";
// 打印内存位置信息
std::cout << " Memory Locations (" << LocationMap.size() << "):\n";
for (const auto& pair : LocationMap) {
const auto& loc = pair.second;
std::cout << " - Base: " << loc->basePointer->getName();
std::cout << " (Type: ";
if (loc->isLocalArray) std::cout << "Local";
else if (loc->isFunctionParameter) std::cout << "Parameter";
else if (loc->isGlobalArray) std::cout << "Global";
else std::cout << "Unknown";
std::cout << ")\n";
}
// 打印别名关系
std::cout << " Alias Relations (" << AliasMap.size() << "):\n";
for (const auto& pair : AliasMap) {
std::cout << " - (" << pair.first.first->getName() << ", " << pair.first.second->getName() << "): ";
switch (pair.second) {
case AliasType::NO_ALIAS: std::cout << "No Alias"; break;
case AliasType::SELF_ALIAS: std::cout << "Self Alias"; break;
case AliasType::POSSIBLE_ALIAS: std::cout << "Possible Alias"; break;
case AliasType::UNKNOWN_ALIAS: std::cout << "Unknown Alias"; break;
}
std::cout << "\n";
}
std::cout << "-----------------------------------------------------------\n";
}
AliasType AliasAnalysisResult::queryAlias(Value* ptr1, Value* ptr2) const {
auto key = std::make_pair(ptr1, ptr2);
auto it = AliasMap.find(key);
if (it != AliasMap.end()) {
return it->second;
}
// 尝试反向查找
key = std::make_pair(ptr2, ptr1);
it = AliasMap.find(key);
if (it != AliasMap.end()) {
return it->second;
}
return AliasType::UNKNOWN_ALIAS; // 保守估计
}
const MemoryLocation* AliasAnalysisResult::getMemoryLocation(Value* ptr) const {
auto it = LocationMap.find(ptr);
return (it != LocationMap.end()) ? it->second.get() : nullptr;
}
bool AliasAnalysisResult::isLocalArray(Value* ptr) const {
const MemoryLocation* loc = getMemoryLocation(ptr);
return loc && loc->isLocalArray;
}
bool AliasAnalysisResult::isFunctionParameter(Value* ptr) const {
const MemoryLocation* loc = getMemoryLocation(ptr);
return loc && loc->isFunctionParameter;
}
bool AliasAnalysisResult::isGlobalArray(Value* ptr) const {
const MemoryLocation* loc = getMemoryLocation(ptr);
return loc && loc->isGlobalArray;
}
bool AliasAnalysisResult::hasConstantAccess(Value* ptr) const {
const MemoryLocation* loc = getMemoryLocation(ptr);
return loc && loc->hasConstantIndices;
}
AliasAnalysisResult::Statistics AliasAnalysisResult::getStatistics() const {
Statistics stats = {0};
stats.totalQueries = AliasMap.size();
for (auto& pair : AliasMap) {
switch (pair.second) {
case AliasType::NO_ALIAS: stats.noAlias++; break;
case AliasType::SELF_ALIAS: stats.selfAlias++; break;
case AliasType::POSSIBLE_ALIAS: stats.possibleAlias++; break;
case AliasType::UNKNOWN_ALIAS: stats.unknownAlias++; break;
}
}
for (auto& loc : LocationMap) {
if (loc.second->isLocalArray) stats.localArrays++;
if (loc.second->isFunctionParameter) stats.functionParameters++;
if (loc.second->isGlobalArray) stats.globalArrays++;
if (loc.second->hasConstantIndices) stats.constantAccesses++;
}
return stats;
}
void AliasAnalysisResult::printStatics() const {
std::cout << "=== Alias Analysis Results ===" << std::endl;
auto stats = getStatistics();
std::cout << "Total queries: " << stats.totalQueries << std::endl;
std::cout << "No alias: " << stats.noAlias << std::endl;
std::cout << "Self alias: " << stats.selfAlias << std::endl;
std::cout << "Possible alias: " << stats.possibleAlias << std::endl;
std::cout << "Unknown alias: " << stats.unknownAlias << std::endl;
std::cout << "Local arrays: " << stats.localArrays << std::endl;
std::cout << "Function parameters: " << stats.functionParameters << std::endl;
std::cout << "Global arrays: " << stats.globalArrays << std::endl;
std::cout << "Constant accesses: " << stats.constantAccesses << std::endl;
}
void AliasAnalysisResult::addMemoryLocation(std::unique_ptr<MemoryLocation> location) {
Value* ptr = location->accessPointer;
LocationMap[ptr] = std::move(location);
}
void AliasAnalysisResult::addAliasRelation(Value* ptr1, Value* ptr2, AliasType type) {
auto key = std::make_pair(ptr1, ptr2);
AliasMap[key] = type;
}
// ========== SysYAliasAnalysisPass 实现 ==========
bool SysYAliasAnalysisPass::runOnFunction(Function *F, AnalysisManager &AM) {
if (DEBUG) {
std::cout << "Running SysY Alias Analysis on function: " << F->getName() << std::endl;
}
// 创建分析结果
CurrentResult = std::make_unique<AliasAnalysisResult>(F);
// 执行主要分析步骤
collectMemoryAccesses(F);
buildAliasRelations(F);
optimizeForSysY(F);
if (DEBUG) {
CurrentResult->print();
CurrentResult->printStatics();
}
return false; // 分析遍不修改IR
}
void SysYAliasAnalysisPass::collectMemoryAccesses(Function* F) {
// 收集函数中所有内存访问指令
for (auto& bb : F->getBasicBlocks()) {
for (auto& inst : bb->getInstructions()) {
Value* ptr = nullptr;
if (auto* loadInst = dynamic_cast<LoadInst*>(inst.get())) {
ptr = loadInst->getPointer();
} else if (auto* storeInst = dynamic_cast<StoreInst*>(inst.get())) {
ptr = storeInst->getPointer();
}
if (ptr) {
// 创建内存位置信息
auto location = createMemoryLocation(ptr);
location->accessInsts.push_back(inst.get());
// 更新读写标记
if (dynamic_cast<LoadInst*>(inst.get())) {
location->hasReads = true;
} else {
location->hasWrites = true;
}
CurrentResult->addMemoryLocation(std::move(location));
}
}
}
}
void SysYAliasAnalysisPass::buildAliasRelations(Function *F) {
// 构建所有内存访问之间的别名关系
auto& locationMap = CurrentResult->LocationMap;
std::vector<Value*> allPointers;
for (auto& pair : locationMap) {
allPointers.push_back(pair.first);
}
// 两两比较所有指针
for (size_t i = 0; i < allPointers.size(); ++i) {
for (size_t j = i + 1; j < allPointers.size(); ++j) {
Value* ptr1 = allPointers[i];
Value* ptr2 = allPointers[j];
MemoryLocation* loc1 = locationMap[ptr1].get();
MemoryLocation* loc2 = locationMap[ptr2].get();
AliasType aliasType = analyzeAliasBetween(loc1, loc2);
CurrentResult->addAliasRelation(ptr1, ptr2, aliasType);
}
}
}
void SysYAliasAnalysisPass::optimizeForSysY(Function* F) {
// SysY特化优化
applySysYConstraints(F);
optimizeParameterAnalysis(F);
optimizeArrayAccessAnalysis(F);
}
std::unique_ptr<MemoryLocation> SysYAliasAnalysisPass::createMemoryLocation(Value* ptr) {
Value* basePtr = getBasePointer(ptr);
auto location = std::make_unique<MemoryLocation>(basePtr, ptr);
// 分析内存类型和索引模式
analyzeMemoryType(location.get());
analyzeIndexPattern(location.get());
return location;
}
Value* SysYAliasAnalysisPass::getBasePointer(Value* ptr) {
// 递归剥离GEP指令找到真正的基指针
if (auto* gepInst = dynamic_cast<GetElementPtrInst*>(ptr)) {
return getBasePointer(gepInst->getBasePointer());
}
return ptr;
}
void SysYAliasAnalysisPass::analyzeMemoryType(MemoryLocation* location) {
Value* base = location->basePointer;
// 检查内存类型
if (dynamic_cast<AllocaInst*>(base)) {
location->isLocalArray = true;
} else if (dynamic_cast<Argument*>(base)) {
location->isFunctionParameter = true;
} else if (dynamic_cast<GlobalValue*>(base)) {
location->isGlobalArray = true;
}
}
void SysYAliasAnalysisPass::analyzeIndexPattern(MemoryLocation* location) {
// 分析GEP指令的索引模式
if (auto* gepInst = dynamic_cast<GetElementPtrInst*>(location->accessPointer)) {
// 初始化为true如果发现非常量索引则设为false
location->hasConstantIndices = true;
// 收集所有索引
for (unsigned i = 0; i < gepInst->getNumIndices(); ++i) {
Value* index = gepInst->getIndex(i);
location->indices.push_back(index);
// 检查是否为常量索引
if (!isConstantValue(index)) {
location->hasConstantIndices = false;
}
}
// 检查是否包含循环变量
Function* containingFunc = nullptr;
if (auto* inst = dynamic_cast<Instruction*>(location->basePointer)) {
containingFunc = inst->getParent()->getParent();
} else if (auto* arg = dynamic_cast<Argument*>(location->basePointer)) {
containingFunc = arg->getParent();
}
if (containingFunc) {
location->hasLoopVariableIndex = hasLoopVariableInIndices(location->indices, containingFunc);
}
// 计算常量偏移
if (location->hasConstantIndices) {
location->constantOffset = calculateConstantOffset(location->indices);
}
}
}
AliasType SysYAliasAnalysisPass::analyzeAliasBetween(MemoryLocation* loc1, MemoryLocation* loc2) {
// 分析两个内存位置之间的别名关系
// 1. 相同基指针的情况需要进一步分析索引
if (loc1->basePointer == loc2->basePointer) {
// 如果是同一个访问指针,那就是完全相同的内存位置
if (loc1->accessPointer == loc2->accessPointer) {
return AliasType::SELF_ALIAS;
}
// 相同基指针但不同访问指针,需要比较索引
return compareIndices(loc1, loc2);
}
// 2. 不同类型的内存位置
if ((loc1->isLocalArray && loc2->isLocalArray)) {
return compareLocalArrays(loc1, loc2);
}
if ((loc1->isFunctionParameter && loc2->isFunctionParameter)) {
return compareParameters(loc1, loc2);
}
if ((loc1->isGlobalArray || loc2->isGlobalArray)) {
return compareWithGlobal(loc1, loc2);
}
return compareMixedTypes(loc1, loc2);
}
AliasType SysYAliasAnalysisPass::compareIndices(MemoryLocation* loc1, MemoryLocation* loc2) {
// 比较相同基指针下的不同索引访问
// 如果都有常量索引,可以精确比较
if (loc1->hasConstantIndices && loc2->hasConstantIndices) {
// 比较索引数量
if (loc1->indices.size() != loc2->indices.size()) {
return AliasType::NO_ALIAS;
}
// 逐个比较索引值
for (size_t i = 0; i < loc1->indices.size(); ++i) {
Value* idx1 = loc1->indices[i];
Value* idx2 = loc2->indices[i];
// 都是常量,比较值
auto* const1 = dynamic_cast<ConstantInteger*>(idx1);
auto* const2 = dynamic_cast<ConstantInteger*>(idx2);
if (const1 && const2) {
int val1 = std::get<int>(const1->getVal());
int val2 = std::get<int>(const2->getVal());
if (val1 != val2) {
return AliasType::NO_ALIAS; // 不同常量索引,确定无别名
}
} else {
// 不是常量,无法确定
return AliasType::POSSIBLE_ALIAS;
}
}
// 所有索引都相同
return AliasType::SELF_ALIAS;
}
// 如果有非常量索引,保守估计
return AliasType::POSSIBLE_ALIAS;
}
AliasType SysYAliasAnalysisPass::compareLocalArrays(MemoryLocation* loc1, MemoryLocation* loc2) {
// 不同局部数组不别名
return AliasType::NO_ALIAS;
}
AliasType SysYAliasAnalysisPass::compareParameters(MemoryLocation* loc1, MemoryLocation* loc2) {
// SysY特化可配置的数组参数别名策略
//
// SysY中数组参数的语法形式
// void func(int a[], int b[]) - 一维数组参数
// void func(int a[][10], int b[]) - 多维数组参数
//
// 默认保守策略:不同数组参数可能别名(因为可能传入相同数组)
// func(arr, arr); // 传入同一个数组给两个参数
//
// 激进策略:假设不同数组参数不会传入相同数组(适用于评测环境)
// 在SysY评测中这种情况很少出现
if (useAggressiveParameterAnalysis()) {
// 激进策略:不同数组参数假设不别名
return AliasType::NO_ALIAS;
} else {
// 保守策略:不同数组参数可能别名
return AliasType::POSSIBLE_ALIAS;
}
}
AliasType SysYAliasAnalysisPass::compareWithGlobal(MemoryLocation* loc1, MemoryLocation* loc2) {
// 涉及全局数组的访问分析
// 这里处理所有涉及全局数组的情况
// SysY特化局部数组与全局数组不别名
if ((loc1->isLocalArray && loc2->isGlobalArray) ||
(loc1->isGlobalArray && loc2->isLocalArray)) {
// 局部数组在栈上,全局数组在全局区,确定不别名
return AliasType::NO_ALIAS;
}
// SysY特化数组参数与全局数组可能别名保守处理
if ((loc1->isFunctionParameter && loc2->isGlobalArray) ||
(loc1->isGlobalArray && loc2->isFunctionParameter)) {
// 数组参数可能指向全局数组,需要保守处理
return AliasType::POSSIBLE_ALIAS;
}
// 其他涉及全局数组的情况,采用保守策略
return AliasType::POSSIBLE_ALIAS;
}
AliasType SysYAliasAnalysisPass::compareMixedTypes(MemoryLocation* loc1, MemoryLocation* loc2) {
// 混合类型访问的别名分析
// 处理不同内存类型之间的别名关系
// SysY特化局部数组与数组参数通常不别名
// 典型场景:
// void func(int p[]) { // p 是数组参数
// int local[10]; // local 是局部数组
// p[0] = local[0]; // 混合类型访问
// }
// 或多维数组:
// void func(int p[][10]) { // p 是多维数组参数
// int local[10]; // local 是局部数组
// p[i][0] = local[0]; // 混合类型访问
// }
// 局部数组与数组参数在SysY中通常不别名
if ((loc1->isLocalArray && loc2->isFunctionParameter) ||
(loc1->isFunctionParameter && loc2->isLocalArray)) {
// 因为局部数组是栈上分配,而数组参数是传入的外部数组
return AliasType::NO_ALIAS;
}
// 对于其他混合情况,保守估计
return AliasType::UNKNOWN_ALIAS;
}
void SysYAliasAnalysisPass::applySysYConstraints(Function* F) {
// SysY语言特定的约束和优化
// 1. SysY没有指针运算简化了别名分析
// 2. 数组传参时保持数组语义
// 3. 没有动态内存分配,所有数组要么是局部的要么是参数/全局
}
void SysYAliasAnalysisPass::optimizeParameterAnalysis(Function* F) {
// 数组参数别名分析优化
// 为SysY评测环境提供可配置的优化策略
if (!enableParameterOptimization()) {
return; // 保持默认的保守策略
}
// 可选的参数优化:假设不同数组参数不会传入相同数组
// 典型的SysY函数调用
// int arr1[10], arr2[20];
// func(arr1, arr2); // 传入不同数组
// 而不是:
// func(arr1, arr1); // 传入相同数组给两个参数
// 这在SysY评测中通常是安全的假设
auto& locationMap = CurrentResult->LocationMap;
for (auto it1 = locationMap.begin(); it1 != locationMap.end(); ++it1) {
for (auto it2 = std::next(it1); it2 != locationMap.end(); ++it2) {
MemoryLocation* loc1 = it1->second.get();
MemoryLocation* loc2 = it2->second.get();
// 如果两个都是数组参数且基指针不同设为NO_ALIAS
if (loc1->isFunctionParameter && loc2->isFunctionParameter &&
loc1->basePointer != loc2->basePointer) {
CurrentResult->addAliasRelation(it1->first, it2->first, AliasType::NO_ALIAS);
}
}
}
}
void SysYAliasAnalysisPass::optimizeArrayAccessAnalysis(Function* F) {
// 数组访问别名分析优化
// 基于SysY语言的特点进行简单优化
// 优化1同一数组的不同常量索引访问确定无别名
optimizeConstantIndexAccesses();
// 优化2识别简单的顺序访问模式
optimizeSequentialAccesses();
}
bool SysYAliasAnalysisPass::isConstantValue(Value* val) {
return dynamic_cast<ConstantInteger*>(val) != nullptr; // 简化,只检查整数常量
}
bool SysYAliasAnalysisPass::hasLoopVariableInIndices(const std::vector<Value*>& indices, Function* F) {
// 保守策略:所有非常量索引都视为可能的循环变量
// 这样可以避免复杂的循环分析依赖,保持分析的独立性
for (Value* index : indices) {
if (!isConstantValue(index)) {
return true; // 保守估计,确保正确性
}
}
return false;
}
int SysYAliasAnalysisPass::calculateConstantOffset(const std::vector<Value*>& indices) {
int offset = 0;
for (Value* index : indices) {
if (auto* constInt = dynamic_cast<ConstantInteger*>(index)) {
// ConstantInteger的getVal()返回variant需要提取int值
auto val = constInt->getVal();
if (std::holds_alternative<int>(val)) {
offset += std::get<int>(val);
}
}
}
return offset;
}
void SysYAliasAnalysisPass::printStatistics() const {
if (CurrentResult) {
CurrentResult->print();
}
}
void SysYAliasAnalysisPass::optimizeConstantIndexAccesses() {
// 优化常量索引访问的别名关系
// 对于相同基指针的访问,如果索引都是常量且不同,则确定无别名
auto& locationMap = CurrentResult->LocationMap;
std::vector<Value*> allPointers;
for (auto& pair : locationMap) {
allPointers.push_back(pair.first);
}
for (size_t i = 0; i < allPointers.size(); ++i) {
for (size_t j = i + 1; j < allPointers.size(); ++j) {
Value* ptr1 = allPointers[i];
Value* ptr2 = allPointers[j];
MemoryLocation* loc1 = locationMap[ptr1].get();
MemoryLocation* loc2 = locationMap[ptr2].get();
// 相同基指针且都有常量索引
if (loc1->basePointer == loc2->basePointer &&
loc1->hasConstantIndices && loc2->hasConstantIndices) {
// 比较常量偏移
if (loc1->constantOffset != loc2->constantOffset) {
// 不同的常量偏移,确定无别名
CurrentResult->addAliasRelation(ptr1, ptr2, AliasType::NO_ALIAS);
}
}
}
}
}
void SysYAliasAnalysisPass::optimizeSequentialAccesses() {
// 识别和优化顺序访问模式
// 这是一个简化的实现,主要用于识别数组的顺序遍历
// 在SysY中大多数数组访问都是通过循环进行的
// 对于非常量索引的访问,我们采用保守策略,不进行过多优化
// 这样可以保持分析的简单性和正确性
// 未来如果需要更精确的分析,可以在这里添加更复杂的逻辑
}
} // namespace sysy

View File

@@ -0,0 +1,417 @@
#include "CallGraphAnalysis.h"
#include "SysYIRPrinter.h"
#include <iostream>
#include <stack>
#include <unordered_set>
extern int DEBUG;
namespace sysy {
// 静态成员初始化
void* CallGraphAnalysisPass::ID = (void*)&CallGraphAnalysisPass::ID;
// ========== CallGraphAnalysisResult 实现 ==========
CallGraphAnalysisResult::Statistics CallGraphAnalysisResult::getStatistics() const {
Statistics stats = {};
stats.totalFunctions = nodes.size();
size_t totalCallEdges = 0;
size_t recursiveFunctions = 0;
size_t selfRecursiveFunctions = 0;
size_t totalCallers = 0;
size_t totalCallees = 0;
for (const auto& pair : nodes) {
const auto& node = pair.second;
totalCallEdges += node->callees.size();
totalCallers += node->callers.size();
totalCallees += node->callees.size();
if (node->isRecursive) recursiveFunctions++;
if (node->isSelfRecursive) selfRecursiveFunctions++;
}
stats.totalCallEdges = totalCallEdges;
stats.recursiveFunctions = recursiveFunctions;
stats.selfRecursiveFunctions = selfRecursiveFunctions;
stats.stronglyConnectedComponents = sccs.size();
// 计算最大SCC大小
size_t maxSCCSize = 0;
for (const auto& scc : sccs) {
maxSCCSize = std::max(maxSCCSize, scc.size());
}
stats.maxSCCSize = maxSCCSize;
// 计算平均值
if (stats.totalFunctions > 0) {
stats.avgCallersPerFunction = static_cast<double>(totalCallers) / stats.totalFunctions;
stats.avgCalleesPerFunction = static_cast<double>(totalCallees) / stats.totalFunctions;
}
return stats;
}
void CallGraphAnalysisResult::print() const {
std::cout << "---- Call Graph Analysis Results for Module ----\n";
// 打印基本统计信息
auto stats = getStatistics();
std::cout << " Statistics:\n";
std::cout << " Total Functions: " << stats.totalFunctions << "\n";
std::cout << " Total Call Edges: " << stats.totalCallEdges << "\n";
std::cout << " Recursive Functions: " << stats.recursiveFunctions << "\n";
std::cout << " Self-Recursive Functions: " << stats.selfRecursiveFunctions << "\n";
std::cout << " Strongly Connected Components: " << stats.stronglyConnectedComponents << "\n";
std::cout << " Max SCC Size: " << stats.maxSCCSize << "\n";
std::cout << " Avg Callers per Function: " << stats.avgCallersPerFunction << "\n";
std::cout << " Avg Callees per Function: " << stats.avgCalleesPerFunction << "\n";
// 打印拓扑排序结果
std::cout << " Topological Order (" << topologicalOrder.size() << "):\n";
for (size_t i = 0; i < topologicalOrder.size(); ++i) {
std::cout << " " << i << ": " << topologicalOrder[i]->getName() << "\n";
}
// 打印强连通分量
if (!sccs.empty()) {
std::cout << " Strongly Connected Components:\n";
for (size_t i = 0; i < sccs.size(); ++i) {
std::cout << " SCC " << i << " (size " << sccs[i].size() << "): ";
for (size_t j = 0; j < sccs[i].size(); ++j) {
if (j > 0) std::cout << ", ";
std::cout << sccs[i][j]->getName();
}
std::cout << "\n";
}
}
// 打印每个函数的详细信息
std::cout << " Function Details:\n";
for (const auto& pair : nodes) {
const auto& node = pair.second;
std::cout << " Function: " << node->function->getName();
if (node->isRecursive) {
std::cout << " (Recursive";
if (node->isSelfRecursive) std::cout << ", Self";
if (node->recursiveDepth >= 0) std::cout << ", Depth=" << node->recursiveDepth;
std::cout << ")";
}
std::cout << "\n";
if (!node->callers.empty()) {
std::cout << " Callers (" << node->callers.size() << "): ";
bool first = true;
for (Function* caller : node->callers) {
if (!first) std::cout << ", ";
std::cout << caller->getName();
first = false;
}
std::cout << "\n";
}
if (!node->callees.empty()) {
std::cout << " Callees (" << node->callees.size() << "): ";
bool first = true;
for (Function* callee : node->callees) {
if (!first) std::cout << ", ";
std::cout << callee->getName();
first = false;
}
std::cout << "\n";
}
}
std::cout << "--------------------------------------------------\n";
}
void CallGraphAnalysisResult::addNode(Function* F) {
if (nodes.find(F) == nodes.end()) {
nodes[F] = std::make_unique<CallGraphNode>(F);
}
}
void CallGraphAnalysisResult::addCallEdge(Function* caller, Function* callee) {
// 确保两个函数都有对应的节点
addNode(caller);
addNode(callee);
// 添加调用边
nodes[caller]->callees.insert(callee);
nodes[callee]->callers.insert(caller);
// 更新统计信息
nodes[caller]->totalCallees = nodes[caller]->callees.size();
nodes[callee]->totalCallers = nodes[callee]->callers.size();
// 检查自递归
if (caller == callee) {
nodes[caller]->isSelfRecursive = true;
nodes[caller]->isRecursive = true;
}
}
void CallGraphAnalysisResult::computeTopologicalOrder() {
topologicalOrder.clear();
std::unordered_set<Function*> visited;
// 对每个未访问的函数进行DFS
for (const auto& pair : nodes) {
Function* F = pair.first;
if (visited.find(F) == visited.end()) {
dfsTopological(F, visited, topologicalOrder);
}
}
// 反转结果(因为我们在后序遍历中添加)
std::reverse(topologicalOrder.begin(), topologicalOrder.end());
}
void CallGraphAnalysisResult::dfsTopological(Function* F, std::unordered_set<Function*>& visited,
std::vector<Function*>& result) {
visited.insert(F);
auto node = getNode(F);
if (node) {
// 先访问所有被调用的函数
for (Function* callee : node->callees) {
if (visited.find(callee) == visited.end()) {
dfsTopological(callee, visited, result);
}
}
}
// 后序遍历:访问完所有子节点后添加当前节点
result.push_back(F);
}
void CallGraphAnalysisResult::computeStronglyConnectedComponents() {
tarjanSCC();
// 为每个函数设置其所属的SCC
functionToSCC.clear();
for (size_t i = 0; i < sccs.size(); ++i) {
for (Function* F : sccs[i]) {
functionToSCC[F] = static_cast<int>(i);
}
}
}
void CallGraphAnalysisResult::tarjanSCC() {
sccs.clear();
std::vector<int> indices(nodes.size(), -1);
std::vector<int> lowlinks(nodes.size(), -1);
std::vector<Function*> stack;
std::unordered_set<Function*> onStack;
int index = 0;
// 为函数分配索引
std::map<Function*, int> functionIndex;
int idx = 0;
for (const auto& pair : nodes) {
functionIndex[pair.first] = idx++;
}
// 对每个未访问的函数运行Tarjan算法
for (const auto& pair : nodes) {
Function* F = pair.first;
int fIdx = functionIndex[F];
if (indices[fIdx] == -1) {
tarjanDFS(F, index, indices, lowlinks, stack, onStack);
}
}
}
void CallGraphAnalysisResult::tarjanDFS(Function* F, int& index, std::vector<int>& indices,
std::vector<int>& lowlinks, std::vector<Function*>& stack,
std::unordered_set<Function*>& onStack) {
// 这里需要函数到索引的映射,简化实现
// 在实际实现中应该维护一个全局的函数索引映射
static std::map<Function*, int> functionIndex;
static int nextIndex = 0;
if (functionIndex.find(F) == functionIndex.end()) {
functionIndex[F] = nextIndex++;
}
int fIdx = functionIndex[F];
// 确保向量足够大
if (fIdx >= static_cast<int>(indices.size())) {
indices.resize(fIdx + 1, -1);
lowlinks.resize(fIdx + 1, -1);
}
indices[fIdx] = index;
lowlinks[fIdx] = index;
index++;
stack.push_back(F);
onStack.insert(F);
auto node = getNode(F);
if (node) {
for (Function* callee : node->callees) {
int calleeIdx = functionIndex[callee];
// 确保向量足够大
if (calleeIdx >= static_cast<int>(indices.size())) {
indices.resize(calleeIdx + 1, -1);
lowlinks.resize(calleeIdx + 1, -1);
}
if (indices[calleeIdx] == -1) {
// 递归访问
tarjanDFS(callee, index, indices, lowlinks, stack, onStack);
lowlinks[fIdx] = std::min(lowlinks[fIdx], lowlinks[calleeIdx]);
} else if (onStack.find(callee) != onStack.end()) {
// 后向边
lowlinks[fIdx] = std::min(lowlinks[fIdx], indices[calleeIdx]);
}
}
}
// 如果F是SCC的根
if (lowlinks[fIdx] == indices[fIdx]) {
std::vector<Function*> scc;
Function* w;
do {
w = stack.back();
stack.pop_back();
onStack.erase(w);
scc.push_back(w);
} while (w != F);
sccs.push_back(std::move(scc));
}
}
void CallGraphAnalysisResult::analyzeRecursion() {
// 基于SCC分析递归
for (const auto& scc : sccs) {
if (scc.size() > 1) {
// 多函数的SCC标记为相互递归
for (Function* F : scc) {
auto* node = getMutableNode(F);
if (node) {
node->isRecursive = true;
node->recursiveDepth = -1; // 相互递归,深度未定义
}
}
} else if (scc.size() == 1) {
// 单函数SCC检查是否自递归
Function* F = scc[0];
auto* node = getMutableNode(F);
if (node && node->callees.count(F) > 0) {
node->isSelfRecursive = true;
node->isRecursive = true;
node->recursiveDepth = -1; // 简化:不计算递归深度
}
}
}
}
// ========== CallGraphAnalysisPass 实现 ==========
bool CallGraphAnalysisPass::runOnModule(Module* M, AnalysisManager& AM) {
if (DEBUG) {
std::cout << "Running Call Graph Analysis on module\n";
}
// 创建分析结果
CurrentResult = std::make_unique<CallGraphAnalysisResult>(M);
// 执行主要分析步骤
buildCallGraph(M);
CurrentResult->computeTopologicalOrder();
CurrentResult->computeStronglyConnectedComponents();
CurrentResult->analyzeRecursion();
if (DEBUG) {
CurrentResult->print();
}
return false; // 分析遍不修改IR
}
void CallGraphAnalysisPass::buildCallGraph(Module* M) {
// 1. 为所有函数创建节点(包括声明但未定义的函数)
for (auto& pair : M->getFunctions()) {
Function* F = pair.second.get();
if (!isLibraryFunction(F) && !isIntrinsicFunction(F)) {
CurrentResult->addNode(F);
}
}
// 2. 扫描所有函数的调用关系
for (auto& pair : M->getFunctions()) {
Function* F = pair.second.get();
if (!isLibraryFunction(F) && !isIntrinsicFunction(F)) {
scanFunctionCalls(F);
}
}
}
void CallGraphAnalysisPass::scanFunctionCalls(Function* F) {
// 遍历函数中的所有基本块和指令
for (auto& BB : F->getBasicBlocks_NoRange()) {
for (auto& I : BB->getInstructions()) {
if (CallInst* call = dynamic_cast<CallInst*>(I.get())) {
processCallInstruction(call, F);
}
}
}
}
void CallGraphAnalysisPass::processCallInstruction(CallInst* call, Function* caller) {
Function* callee = call->getCallee();
if (!callee) {
// 间接调用,无法静态确定目标函数
return;
}
if (isLibraryFunction(callee) || isIntrinsicFunction(callee)) {
// 跳过标准库函数和内置函数
return;
}
// 添加调用边
CurrentResult->addCallEdge(caller, callee);
// 更新调用点统计
auto* node = CurrentResult->getMutableNode(caller);
if (node) {
node->callSiteCount++;
}
}
bool CallGraphAnalysisPass::isLibraryFunction(Function* F) const {
std::string name = F->getName();
// SysY标准库函数
return name == "getint" || name == "getch" || name == "getfloat" ||
name == "getarray" || name == "getfarray" ||
name == "putint" || name == "putch" || name == "putfloat" ||
name == "putarray" || name == "putfarray" ||
name == "_sysy_starttime" || name == "_sysy_stoptime";
}
bool CallGraphAnalysisPass::isIntrinsicFunction(Function* F) const {
std::string name = F->getName();
// 编译器内置函数(后续可以增加某些内置函数)
return name.substr(0, 5) == "llvm." || name.substr(0, 5) == "sysy.";
}
void CallGraphAnalysisPass::printStatistics() const {
if (CurrentResult) {
CurrentResult->print();
}
}
} // namespace sysy

View File

@@ -0,0 +1,415 @@
#include "Dom.h" // 确保包含 DominatorTreeAnalysisPass 的定义
#include "Loop.h" //
#include "AliasAnalysis.h" // 添加别名分析依赖
#include "SideEffectAnalysis.h" // 添加副作用分析依赖
#include <iostream>
#include <queue> // 用于 BFS 遍历设置循环层级
// 调试模式开关
#ifndef DEBUG
#define DEBUG 0
#endif
namespace sysy {
// 定义 Pass 的唯一 ID
void *LoopAnalysisPass::ID = (void *)&LoopAnalysisPass::ID;
// 定义 Loop 类的静态变量
int Loop::NextLoopID = 0;
// **实现 LoopAnalysisResult::print() 方法**
void LoopAnalysisResult::printBBSet(const std::string &prefix, const std::set<BasicBlock *> &s) const{
if (!DEBUG) return;
std::cout << prefix << "{";
bool first = true;
for (const auto &bb : s) {
if (!first) std::cout << ", ";
std::cout << bb->getName();
first = false;
}
std::cout << "}";
}
// **辅助函数:打印 Loop 指针向量**
void LoopAnalysisResult::printLoopVector(const std::string &prefix, const std::vector<Loop *> &loops) const {
if (!DEBUG) return;
std::cout << prefix << "[";
bool first = true;
for (const auto &loop : loops) {
if (!first) std::cout << ", ";
std::cout << loop->getName(); // 假设 Loop::getName() 存在
first = false;
}
std::cout << "]";
}
void LoopAnalysisResult::print() const {
if (!DEBUG) return; // 只有在 DEBUG 模式下才打印
std::cout << "\n--- Loop Analysis Results for Function: " << AssociatedFunction->getName() << " ---" << std::endl;
if (AllLoops.empty()) {
std::cout << " No loops found." << std::endl;
return;
}
std::cout << "Total Loops Found: " << AllLoops.size() << std::endl;
// 1. 按层级分组循环
std::map<int, std::vector<Loop*>> loopsByLevel;
int maxLevel = 0;
for (const auto& loop_ptr : AllLoops) {
if (loop_ptr->getLoopLevel() != -1) { // 确保层级已计算
loopsByLevel[loop_ptr->getLoopLevel()].push_back(loop_ptr.get());
if (loop_ptr->getLoopLevel() > maxLevel) {
maxLevel = loop_ptr->getLoopLevel();
}
}
}
// 2. 打印循环层次结构
std::cout << "\n--- Loop Hierarchy ---" << std::endl;
for (int level = 0; level <= maxLevel; ++level) {
if (loopsByLevel.count(level)) {
std::cout << "Level " << level << " Loops:" << std::endl;
for (Loop* loop : loopsByLevel[level]) {
std::string indent(level * 2, ' '); // 根据层级缩进
std::cout << indent << "- Loop Header: " << loop->getName() << std::endl;
std::cout << indent << " Blocks: ";
printBBSet("", loop->getBlocks());
std::cout << std::endl;
std::cout << indent << " Exit Blocks: ";
printBBSet("", loop->getExitBlocks());
std::cout << std::endl;
std::cout << indent << " Pre-Header: " << (loop->getPreHeader() ? loop->getPreHeader()->getName() : "None") << std::endl;
std::cout << indent << " Parent Loop: " << (loop->getParentLoop() ? loop->getParentLoop()->getName() : "None (Outermost)") << std::endl;
std::cout << indent << " Nested Loops: ";
printLoopVector("", loop->getNestedLoops());
std::cout << std::endl;
}
}
}
// 3. 打印最外层/最内层循环摘要
std::cout << "\n--- Loop Summary ---" << std::endl;
std::cout << "Outermost Loops: ";
printLoopVector("", getOutermostLoops());
std::cout << std::endl;
std::cout << "Innermost Loops: ";
printLoopVector("", getInnermostLoops());
std::cout << std::endl;
std::cout << "-----------------------------------------------" << std::endl;
}
bool LoopAnalysisPass::runOnFunction(Function *F, AnalysisManager &AM) {
if (F->getBasicBlocks().empty()) {
CurrentResult = std::make_unique<LoopAnalysisResult>(F);
return false; // 空函数,没有循环
}
if (DEBUG)
std::cout << "Running LoopAnalysisPass on function: " << F->getName() << std::endl;
// 获取支配树分析结果
// 这是循环分析的关键依赖
DominatorTree *DT = AM.getAnalysisResult<DominatorTree, DominatorTreeAnalysisPass>(F);
if (!DT) {
// 无法获取支配树,无法进行循环分析
std::cerr << "Error: DominatorTreeAnalysisResult not available for function " << F->getName() << std::endl;
CurrentResult = std::make_unique<LoopAnalysisResult>(F);
return false;
}
// 获取别名分析结果 - 用于循环内存访问分析
AliasAnalysisResult *aliasAnalysis = AM.getAnalysisResult<AliasAnalysisResult, SysYAliasAnalysisPass>(F);
if (DEBUG && aliasAnalysis) {
std::cout << "Loop Analysis: Using alias analysis results for enhanced memory pattern detection" << std::endl;
}
// 获取副作用分析结果 - 用于循环纯度分析
SideEffectAnalysisResult *sideEffectAnalysis = AM.getAnalysisResult<SideEffectAnalysisResult, SysYSideEffectAnalysisPass>();
if (DEBUG && sideEffectAnalysis) {
std::cout << "Loop Analysis: Using side effect analysis results for loop purity detection" << std::endl;
}
CurrentResult = std::make_unique<LoopAnalysisResult>(F);
bool changed = false; // 循环分析本身不修改IR所以通常返回false
// 步骤 1: 识别回边和对应的自然循环
// 回边 (N -> D) 定义D 支配 N
std::vector<std::pair<BasicBlock *, BasicBlock *>> backEdges;
for (auto &BB : F->getBasicBlocks()) {
auto Block = BB.get();
for (BasicBlock *Succ : Block->getSuccessors()) {
if (DT->getDominators(Block) && DT->getDominators(Block)->count(Succ)) {
// Succ 支配 Block所以 (Block -> Succ) 是一条回边
backEdges.push_back({Block, Succ});
if (DEBUG)
std::cout << "Found back edge: " << Block->getName() << " -> " << Succ->getName() << std::endl;
}
}
}
if (DEBUG)
std::cout << "Total back edges found: " << backEdges.size() << std::endl;
// 步骤 2: 为每条回边构建自然循环
std::map<BasicBlock*, std::unique_ptr<Loop>> loopMap; // 按循环头分组
for (auto &edge : backEdges) {
BasicBlock *N = edge.first; // 回边的尾部
BasicBlock *D = edge.second; // 回边的头部 (循环头)
// 检查是否已经为此循环头创建了循环
if (loopMap.find(D) == loopMap.end()) {
// 创建新的 Loop 对象
loopMap[D] = std::make_unique<Loop>(D);
}
Loop* currentLoop = loopMap[D].get();
// 收集此回边对应的循环体块:从 N 逆向遍历到 D
std::set<BasicBlock *> loopBlocks; // 临时存储循环块
std::queue<BasicBlock *> q;
// 循环头总是循环体的一部分
loopBlocks.insert(D);
// 如果回边的尾部不是循环头本身,则将其加入队列进行遍历
if (N != D) {
q.push(N);
loopBlocks.insert(N);
}
while (!q.empty()) {
BasicBlock *current = q.front();
q.pop();
for (BasicBlock *pred : current->getPredecessors()) {
// 如果前驱还没有被访问过,则将其加入循环体并继续遍历
if (loopBlocks.find(pred) == loopBlocks.end()) {
loopBlocks.insert(pred);
q.push(pred);
}
}
}
// 将收集到的块添加到 Loop 对象中(合并所有回边的结果)
for (BasicBlock *loopBB : loopBlocks) {
currentLoop->addBlock(loopBB);
}
}
// 处理每个合并后的循环
for (auto &[header, currentLoop] : loopMap) {
const auto &loopBlocks = currentLoop->getBlocks();
// 步骤 3: 识别循环出口块 (Exit Blocks)
for (BasicBlock *loopBB : loopBlocks) {
for (BasicBlock *succ : loopBB->getSuccessors()) {
if (loopBlocks.find(succ) == loopBlocks.end()) {
// 如果后继不在循环体内,则 loopBB 是一个出口块
currentLoop->addExitBlock(loopBB);
}
}
}
// 步骤 4: 识别循环前置块 (Pre-Header)
BasicBlock *candidatePreHeader = nullptr;
int externalPredecessorCount = 0;
for (BasicBlock *predOfHeader : header->getPredecessors()) {
// 使用 currentLoop->contains() 来检查前驱是否在循环体内
if (!currentLoop->contains(predOfHeader)) {
// 如果前驱不在循环体内,则是一个外部前驱
externalPredecessorCount++;
candidatePreHeader = predOfHeader;
}
}
if (externalPredecessorCount == 1) {
currentLoop->setPreHeader(candidatePreHeader);
}
CurrentResult->addLoop(std::move(currentLoop));
}
// 步骤 5: 处理嵌套循环 (确定父子关系和层级)
const auto &allLoops = CurrentResult->getAllLoops();
// 1. 首先,清除所有循环已设置的父子关系和嵌套子循环列表,确保重新计算
for (const auto &loop_ptr : allLoops) {
loop_ptr->setParentLoop(nullptr); // 清除父指针
loop_ptr->clearNestedLoops(); // 清除子循环列表
loop_ptr->setLoopLevel(-1); // 重置循环层级
}
// 2. 遍历所有循环,为每个循环找到其直接父循环并建立关系
for (const auto &innerLoop_ptr : allLoops) {
Loop *innerLoop = innerLoop_ptr.get();
Loop *immediateParent = nullptr; // 用于存储当前 innerLoop 的最近父循环
for (const auto &outerLoop_ptr : allLoops) {
Loop *outerLoop = outerLoop_ptr.get();
// 一个循环不能是它自己的父循环
if (outerLoop == innerLoop) {
continue;
}
// 检查 outerLoop 是否包含 innerLoop 的所有条件:
// Condition 1: outerLoop 的头支配 innerLoop 的头
if (!(DT->getDominators(innerLoop->getHeader()) &&
DT->getDominators(innerLoop->getHeader())->count(outerLoop->getHeader()))) {
continue; // outerLoop 不支配 innerLoop 的头,因此不是一个外层循环
}
// Condition 2: innerLoop 的所有基本块都在 outerLoop 的基本块集合中
bool allInnerBlocksInOuter = true;
for (BasicBlock *innerBB : innerLoop->getBlocks()) {
if (!outerLoop->contains(innerBB)) { //
allInnerBlocksInOuter = false;
break;
}
}
if (!allInnerBlocksInOuter) {
continue; // outerLoop 不包含 innerLoop 的所有块
}
// 到此为止outerLoop 已经被确认为 innerLoop 的一个“候选父循环”(即它包含了 innerLoop
if (immediateParent == nullptr) {
// 这是找到的第一个候选父循环
immediateParent = outerLoop;
} else {
// 已经有了一个 immediateParent需要判断哪个是更“紧密”的父循环
// 更紧密的父循环是那个包含另一个候选父循环的。
// 如果当前的 immediateParent 包含了 outerLoop 的头,那么 outerLoop 是更深的循环(更接近 innerLoop
if (immediateParent->contains(outerLoop->getHeader())) { //
immediateParent = outerLoop; // outerLoop 是更紧密的父循环
}
// 否则outerLoop 包含了 immediateParent 的头),说明 immediateParent 更紧密,保持不变
// 或者它们互不包含(不应该发生,因为它们都包含了 innerLoop也保持 immediateParent
}
}
// 设置 innerLoop 的直接父循环,并添加到父循环的嵌套列表中
if (immediateParent) {
innerLoop->setParentLoop(immediateParent);
immediateParent->addNestedLoop(innerLoop);
}
}
// 3. 计算循环层级 (Level)
std::queue<Loop *> q_level;
// 查找所有最外层循环没有父循环的设置其层级为0并加入队列
for (const auto &loop_ptr : allLoops) {
if (loop_ptr->isOutermost()) {
loop_ptr->setLoopLevel(0);
q_level.push(loop_ptr.get());
}
}
// 使用 BFS 遍历循环树,计算所有嵌套循环的层级
while (!q_level.empty()) {
Loop *current = q_level.front();
q_level.pop();
for (Loop *nestedLoop : current->getNestedLoops()) {
nestedLoop->setLoopLevel(current->getLoopLevel() + 1);
q_level.push(nestedLoop);
}
}
if (DEBUG) {
std::cout << "Loop Analysis completed for function: " << F->getName() << std::endl;
std::cout << "Total loops found: " << CurrentResult->getLoopCount() << std::endl;
std::cout << "Max loop depth: " << CurrentResult->getMaxLoopDepth() << std::endl;
std::cout << "Innermost loops: " << CurrentResult->getInnermostLoops().size() << std::endl;
std::cout << "Outermost loops: " << CurrentResult->getOutermostLoops().size() << std::endl;
// 打印各深度的循环分布
for (int depth = 1; depth <= CurrentResult->getMaxLoopDepth(); ++depth) {
int count = CurrentResult->getLoopCountAtDepth(depth);
if (count > 0) {
std::cout << "Loops at depth " << depth << ": " << count << std::endl;
}
}
// 输出缓存统计
auto cacheStats = CurrentResult->getCacheStats();
std::cout << "Cache statistics - Total cached queries: " << cacheStats.totalCachedQueries << std::endl;
}
return changed;
}
// ========== Loop 类的新增方法实现 ==========
bool Loop::mayHaveSideEffects(SideEffectAnalysisResult* sideEffectAnalysis) const {
if (!sideEffectAnalysis) return true; // 保守假设
for (BasicBlock* bb : LoopBlocks) {
for (auto& inst : bb->getInstructions()) {
if (sideEffectAnalysis->hasSideEffect(inst.get())) {
return true;
}
}
}
return false;
}
bool Loop::accessesGlobalMemory(AliasAnalysisResult* aliasAnalysis) const {
if (!aliasAnalysis) return true; // 保守假设
for (BasicBlock* bb : LoopBlocks) {
for (auto& inst : bb->getInstructions()) {
if (auto* loadInst = dynamic_cast<LoadInst*>(inst.get())) {
if (!aliasAnalysis->isLocalArray(loadInst->getPointer())) {
return true;
}
} else if (auto* storeInst = dynamic_cast<StoreInst*>(inst.get())) {
if (!aliasAnalysis->isLocalArray(storeInst->getPointer())) {
return true;
}
}
}
}
return false;
}
bool Loop::hasMemoryAliasConflicts(AliasAnalysisResult* aliasAnalysis) const {
if (!aliasAnalysis) return true; // 保守假设
std::vector<Value*> memoryAccesses;
// 收集所有内存访问
for (BasicBlock* bb : LoopBlocks) {
for (auto& inst : bb->getInstructions()) {
if (auto* loadInst = dynamic_cast<LoadInst*>(inst.get())) {
memoryAccesses.push_back(loadInst->getPointer());
} else if (auto* storeInst = dynamic_cast<StoreInst*>(inst.get())) {
memoryAccesses.push_back(storeInst->getPointer());
}
}
}
// 检查两两之间是否有别名
for (size_t i = 0; i < memoryAccesses.size(); ++i) {
for (size_t j = i + 1; j < memoryAccesses.size(); ++j) {
auto aliasType = aliasAnalysis->queryAlias(memoryAccesses[i], memoryAccesses[j]);
if (aliasType == AliasType::SELF_ALIAS || aliasType == AliasType::POSSIBLE_ALIAS) {
return true;
}
}
}
return false;
}
} // namespace sysy

View File

@@ -0,0 +1,813 @@
#include "LoopCharacteristics.h"
#include "Dom.h"
#include "Loop.h"
#include "Liveness.h"
#include "AliasAnalysis.h"
#include "SideEffectAnalysis.h"
#include <iostream>
#include <cmath>
// 使用全局调试开关
extern int DEBUG;
namespace sysy {
// 定义 Pass 的唯一 ID
void *LoopCharacteristicsPass::ID = (void *)&LoopCharacteristicsPass::ID;
void LoopCharacteristicsResult::print() const {
if (!DEBUG) return;
std::cout << "\n--- Loop Characteristics Analysis Results for Function: "
<< AssociatedFunction->getName() << " ---" << std::endl;
if (CharacteristicsMap.empty()) {
std::cout << " No loop characteristics found." << std::endl;
return;
}
// 打印统计信息
auto stats = getOptimizationStats();
std::cout << "\n=== Basic Loop Characteristics Statistics ===" << std::endl;
std::cout << "Total Loops: " << stats.totalLoops << std::endl;
std::cout << "Counting Loops: " << stats.countingLoops << std::endl;
std::cout << "Unrolling Candidates: " << stats.unrollingCandidates << std::endl;
std::cout << "Pure Loops: " << stats.pureLoops << std::endl;
std::cout << "Local Memory Only Loops: " << stats.localMemoryOnlyLoops << std::endl;
std::cout << "No Alias Conflict Loops: " << stats.noAliasConflictLoops << std::endl;
std::cout << "Avg Instructions per Loop: " << stats.avgInstructionCount << std::endl;
std::cout << "Avg Compute/Memory Ratio: " << stats.avgComputeMemoryRatio << std::endl;
// 按热度排序并打印循环特征
auto loopsByHotness = getLoopsByHotness();
std::cout << "\n=== Loop Characteristics (by hotness) ===" << std::endl;
for (auto* loop : loopsByHotness) {
auto* chars = getCharacteristics(loop);
if (!chars) continue;
std::cout << "\n--- Loop: " << loop->getName() << " (Hotness: "
<< loop->getLoopHotness() << ") ---" << std::endl;
std::cout << " Level: " << loop->getLoopLevel() << std::endl;
std::cout << " Blocks: " << loop->getLoopSize() << std::endl;
std::cout << " Instructions: " << chars->instructionCount << std::endl;
std::cout << " Memory Operations: " << chars->memoryOperationCount << std::endl;
std::cout << " Compute/Memory Ratio: " << chars->computeToMemoryRatio << std::endl;
// 循环形式
std::cout << " Form: ";
if (chars->isCountingLoop) std::cout << "Counting ";
if (chars->isSimpleForLoop) std::cout << "SimpleFor ";
if (chars->isInnermost) std::cout << "Innermost ";
if (chars->hasComplexControlFlow) std::cout << "Complex ";
if (chars->isPure) std::cout << "Pure ";
if (chars->accessesOnlyLocalMemory) std::cout << "LocalMemOnly ";
if (chars->hasNoMemoryAliasConflicts) std::cout << "NoAliasConflicts ";
std::cout << std::endl;
// 边界信息
if (chars->staticTripCount.has_value()) {
std::cout << " Static Trip Count: " << *chars->staticTripCount << std::endl;
}
if (chars->hasKnownBounds) {
std::cout << " Has Known Bounds: Yes" << std::endl;
}
// 优化机会
std::cout << " Optimization Opportunities: ";
if (chars->benefitsFromUnrolling)
std::cout << "Unroll(factor=" << chars->suggestedUnrollFactor << ") ";
std::cout << std::endl;
// 归纳变量
if (!chars->InductionVars.empty()) {
std::cout << " Induction Vars: " << chars->InductionVars.size() << std::endl;
}
// 循环不变量
if (!chars->loopInvariants.empty()) {
std::cout << " Loop Invariants: " << chars->loopInvariants.size() << std::endl;
}
if (!chars->invariantInsts.empty()) {
std::cout << " Hoistable Instructions: " << chars->invariantInsts.size() << std::endl;
}
}
std::cout << "-----------------------------------------------" << std::endl;
}
bool LoopCharacteristicsPass::runOnFunction(Function *F, AnalysisManager &AM) {
if (F->getBasicBlocks().empty()) {
CurrentResult = std::make_unique<LoopCharacteristicsResult>(F);
return false; // 空函数
}
if (DEBUG)
std::cout << "Running LoopCharacteristicsPass on function: " << F->getName() << std::endl;
// 获取并缓存所有需要的分析结果
loopAnalysis = AM.getAnalysisResult<LoopAnalysisResult, LoopAnalysisPass>(F);
if (!loopAnalysis) {
std::cerr << "Error: LoopAnalysisResult not available for function " << F->getName() << std::endl;
CurrentResult = std::make_unique<LoopCharacteristicsResult>(F);
return false;
}
// 如果没有循环,直接返回
if (!loopAnalysis->hasLoops()) {
CurrentResult = std::make_unique<LoopCharacteristicsResult>(F);
return false;
}
// 获取别名分析和副作用分析结果并缓存
aliasAnalysis = AM.getAnalysisResult<AliasAnalysisResult, SysYAliasAnalysisPass>(F);
sideEffectAnalysis = AM.getAnalysisResult<SideEffectAnalysisResult, SysYSideEffectAnalysisPass>();
if (DEBUG) {
if (aliasAnalysis) std::cout << "LoopCharacteristics: Using alias analysis results" << std::endl;
if (sideEffectAnalysis) std::cout << "LoopCharacteristics: Using side effect analysis results" << std::endl;
}
CurrentResult = std::make_unique<LoopCharacteristicsResult>(F);
// 分析每个循环的特征 - 现在不需要传递分析结果参数
for (const auto& loop_ptr : loopAnalysis->getAllLoops()) {
Loop* loop = loop_ptr.get();
auto characteristics = std::make_unique<LoopCharacteristics>(loop);
// 执行各种特征分析,使用缓存的分析结果
analyzeLoop(loop, characteristics.get());
// 添加到结果中
CurrentResult->addLoopCharacteristics(std::move(characteristics));
}
if (DEBUG) {
std::cout << "LoopCharacteristicsPass completed for function: " << F->getName() << std::endl;
auto stats = CurrentResult->getOptimizationStats();
std::cout << "Analyzed " << stats.totalLoops << " loops, found "
<< stats.countingLoops << " counting loops, "
<< stats.unrollingCandidates << " unroll candidates" << std::endl;
}
return false; // 特征分析不修改IR
}
void LoopCharacteristicsPass::analyzeLoop(Loop* loop, LoopCharacteristics* characteristics) {
if (DEBUG)
std::cout << " Analyzing basic characteristics of loop: " << loop->getName() << std::endl;
// 按顺序执行基础分析 - 现在使用缓存的分析结果
computePerformanceMetrics(loop, characteristics);
analyzeLoopForm(loop, characteristics);
analyzePurityAndSideEffects(loop, characteristics);
identifyBasicInductionVariables(loop, characteristics);
identifyBasicLoopInvariants(loop, characteristics);
analyzeBasicLoopBounds(loop, characteristics);
analyzeBasicMemoryAccessPatterns(loop, characteristics);
evaluateBasicOptimizationOpportunities(loop, characteristics);
}
void LoopCharacteristicsPass::computePerformanceMetrics(Loop* loop, LoopCharacteristics* characteristics) {
size_t totalInsts = 0;
size_t memoryOps = 0;
size_t arithmeticOps = 0;
// 遍历循环中的所有指令
for (BasicBlock* bb : loop->getBlocks()) {
for (auto& inst : bb->getInstructions()) {
totalInsts++;
// 分类指令类型
if (dynamic_cast<LoadInst*>(inst.get()) || dynamic_cast<StoreInst*>(inst.get())) {
memoryOps++;
} else if (dynamic_cast<BinaryInst*>(inst.get())) {
// 检查是否为算术运算
auto* binInst = dynamic_cast<BinaryInst*>(inst.get());
// 简化:假设所有二元运算都是算术运算
arithmeticOps++;
}
}
}
characteristics->instructionCount = totalInsts;
characteristics->memoryOperationCount = memoryOps;
characteristics->arithmeticOperationCount = arithmeticOps;
// 计算计算与内存操作比率
if (memoryOps > 0) {
characteristics->computeToMemoryRatio = static_cast<double>(arithmeticOps) / memoryOps;
} else {
characteristics->computeToMemoryRatio = arithmeticOps; // 纯计算循环
}
}
void LoopCharacteristicsPass::analyzeLoopForm(Loop* loop, LoopCharacteristics* characteristics) {
// 基本形式判断
characteristics->isInnermost = loop->isInnermost();
// 检查是否为简单循环 (只有一个回边)
bool isSimple = loop->isSimpleLoop();
characteristics->isSimpleForLoop = isSimple;
// 检查复杂控制流 (多个出口表示可能有break/continue)
auto exitingBlocks = loop->getExitingBlocks();
characteristics->hasComplexControlFlow = exitingBlocks.size() > 1;
// 初步判断是否为计数循环 (需要更复杂的分析)
// 简化版本:如果是简单循环且是最内层,很可能是计数循环
characteristics->isCountingLoop = isSimple && loop->isInnermost() && exitingBlocks.size() == 1;
}
void LoopCharacteristicsPass::analyzePurityAndSideEffects(Loop* loop, LoopCharacteristics* characteristics) {
if (!sideEffectAnalysis) {
// 没有副作用分析结果,保守处理
characteristics->isPure = false;
return;
}
// 检查循环是否有副作用
characteristics->isPure = !loop->mayHaveSideEffects(sideEffectAnalysis);
if (DEBUG && characteristics->isPure) {
std::cout << " Loop " << loop->getName() << " is identified as PURE (no side effects)" << std::endl;
}
}
void LoopCharacteristicsPass::analyzeBasicMemoryAccessPatterns(Loop* loop, LoopCharacteristics* characteristics) {
if (!aliasAnalysis) {
// 没有别名分析结果,保守处理
characteristics->accessesOnlyLocalMemory = false;
characteristics->hasNoMemoryAliasConflicts = false;
return;
}
// 检查是否只访问局部内存
characteristics->accessesOnlyLocalMemory = !loop->accessesGlobalMemory(aliasAnalysis);
// 检查是否有内存别名冲突
characteristics->hasNoMemoryAliasConflicts = !loop->hasMemoryAliasConflicts(aliasAnalysis);
if (DEBUG) {
if (characteristics->accessesOnlyLocalMemory) {
std::cout << " Loop " << loop->getName() << " accesses ONLY LOCAL MEMORY" << std::endl;
}
if (characteristics->hasNoMemoryAliasConflicts) {
std::cout << " Loop " << loop->getName() << " has NO MEMORY ALIAS CONFLICTS" << std::endl;
}
}
// 分析基础的内存访问模式
for (BasicBlock* bb : loop->getBlocks()) {
for (auto& inst : bb->getInstructions()) {
if (auto* loadInst = dynamic_cast<LoadInst*>(inst.get())) {
Value* ptr = loadInst->getPointer();
auto& pattern = characteristics->memoryPatterns[ptr];
pattern.loadInsts.push_back(loadInst);
pattern.isArrayParameter = aliasAnalysis->isFunctionParameter(ptr);
pattern.isGlobalArray = aliasAnalysis->isGlobalArray(ptr);
pattern.hasConstantIndices = aliasAnalysis->hasConstantAccess(ptr);
} else if (auto* storeInst = dynamic_cast<StoreInst*>(inst.get())) {
Value* ptr = storeInst->getPointer();
auto& pattern = characteristics->memoryPatterns[ptr];
pattern.storeInsts.push_back(storeInst);
pattern.isArrayParameter = aliasAnalysis->isFunctionParameter(ptr);
pattern.isGlobalArray = aliasAnalysis->isGlobalArray(ptr);
pattern.hasConstantIndices = aliasAnalysis->hasConstantAccess(ptr);
}
}
}
}
bool LoopCharacteristicsPass::isBasicInductionVariable(Value* val, Loop* loop) {
// 简化的基础归纳变量检测
auto* phiInst = dynamic_cast<PhiInst*>(val);
if (!phiInst) return false;
// 检查phi指令是否在循环头
if (phiInst->getParent() != loop->getHeader()) return false;
// 检查是否有来自循环内的更新
for (auto& [incomingBB, incomingVal] : phiInst->getIncomingValues()) {
if (loop->contains(incomingBB)) {
return true; // 简化:有来自循环内的值就认为是基础归纳变量
}
}
return false;
}
void LoopCharacteristicsPass::identifyBasicInductionVariables(
Loop* loop, LoopCharacteristics* characteristics) {
BasicBlock* header = loop->getHeader();
std::vector<std::unique_ptr<InductionVarInfo>> ivs;
if (DEBUG) {
std::cout << " === Identifying Induction Variables for Loop: " << loop->getName() << " ===" << std::endl;
std::cout << " Loop header: " << header->getName() << std::endl;
std::cout << " Loop blocks: ";
for (auto* bb : loop->getBlocks()) {
std::cout << bb->getName() << " ";
}
std::cout << std::endl;
}
// 1. 识别所有BIV
for (auto& inst : header->getInstructions()) {
auto* phi = dynamic_cast<PhiInst*>(inst.get());
if (!phi) continue;
if (isBasicInductionVariable(phi, loop)) {
ivs.push_back(InductionVarInfo::createBasicBIV(phi, Instruction::Kind::kPhi, phi));
if (DEBUG) {
std::cout << " [BIV] Found basic induction variable: " << phi->getName() << std::endl;
std::cout << " Incoming values: ";
for (auto& [incomingBB, incomingVal] : phi->getIncomingValues()) {
std::cout << "{" << incomingBB->getName() << ": " << incomingVal->getName() << "} ";
}
std::cout << std::endl;
}
}
}
if (DEBUG) {
std::cout << " Found " << ivs.size() << " basic induction variables" << std::endl;
}
// 2. 递归识别所有派生DIV
std::set<Value*> visited;
size_t initialSize = ivs.size();
// 保存初始的BIV列表避免在遍历过程中修改向量导致迭代器失效
std::vector<InductionVarInfo*> bivList;
for (size_t i = 0; i < initialSize; ++i) {
if (ivs[i] && ivs[i]->ivkind == IVKind::kBasic) {
bivList.push_back(ivs[i].get());
}
}
for (auto* biv : bivList) {
if (DEBUG) {
if (biv && biv->div) {
std::cout << " Searching for derived IVs from BIV: " << biv->div->getName() << std::endl;
} else {
std::cout << " ERROR: Invalid BIV pointer or div field is null" << std::endl;
continue;
}
}
findDerivedInductionVars(biv->div, biv->base, loop, ivs, visited);
}
if (DEBUG) {
size_t derivedCount = ivs.size() - initialSize;
std::cout << " Found " << derivedCount << " derived induction variables" << std::endl;
// 打印所有归纳变量的详细信息
std::cout << " === Final Induction Variables Summary ===" << std::endl;
for (size_t i = 0; i < ivs.size(); ++i) {
const auto& iv = ivs[i];
std::cout << " [" << i << "] " << iv->div->getName()
<< " (kind: " << (iv->ivkind == IVKind::kBasic ? "Basic" :
iv->ivkind == IVKind::kLinear ? "Linear" : "Complex") << ")" << std::endl;
std::cout << " Operation: " << static_cast<int>(iv->Instkind) << std::endl;
if (iv->base) {
std::cout << " Base: " << iv->base->getName() << std::endl;
}
if (iv->Multibase.first || iv->Multibase.second) {
std::cout << " Multi-base: ";
if (iv->Multibase.first) std::cout << iv->Multibase.first->getName() << " ";
if (iv->Multibase.second) std::cout << iv->Multibase.second->getName() << " ";
std::cout << std::endl;
}
std::cout << " Factor: " << iv->factor << ", Offset: " << iv->offset << std::endl;
std::cout << " Valid: " << (iv->valid ? "Yes" : "No") << std::endl;
}
std::cout << " =============================================" << std::endl;
}
characteristics->InductionVars = std::move(ivs);
}
struct LinearExpr {
// 表达为: a * base1 + b * base2 + offset
Value* base1 = nullptr;
Value* base2 = nullptr;
int factor1 = 0;
int factor2 = 0;
int offset = 0;
bool valid = false;
bool isSimple = false; // 仅一个BIV时true
};
static LinearExpr analyzeLinearExpr(Value* val, Loop* loop, std::vector<std::unique_ptr<InductionVarInfo>>& ivs) {
// 递归归约val为线性表达式
// 只支持单/双BIV线性组合
// 见下方详细实现
// ----------
if (DEBUG >= 2) { // 更详细的调试级别
if (auto* inst = dynamic_cast<Instruction*>(val)) {
std::cout << " Analyzing linear expression for: " << val->getName()
<< " (kind: " << static_cast<int>(inst->getKind()) << ")" << std::endl;
} else {
std::cout << " Analyzing linear expression for value: " << val->getName() << std::endl;
}
}
// 基本变量:常数
if (auto* cint = dynamic_cast<ConstantInteger*>(val)) {
if (DEBUG >= 2) {
std::cout << " -> Constant: " << cint->getInt() << std::endl;
}
return {nullptr, nullptr, 0, 0, cint->getInt(), true, false};
}
// 基本变量BIV或派生IV
for (auto& iv : ivs) {
if (iv->div == val) {
if (iv->ivkind == IVKind::kBasic ||
iv->ivkind == IVKind::kLinear) {
if (DEBUG >= 2) {
std::cout << " -> Found " << (iv->ivkind == IVKind::kBasic ? "Basic" : "Linear")
<< " IV with base: " << (iv->base ? iv->base->getName() : "null")
<< ", factor: " << iv->factor << ", offset: " << iv->offset << std::endl;
}
return {iv->base, nullptr, iv->factor, 0, iv->offset, true, true};
}
// 复杂归纳变量
if (iv->ivkind == IVKind::kCmplx) {
if (DEBUG >= 2) {
std::cout << " -> Found Complex IV with multi-base" << std::endl;
}
return {iv->Multibase.first, iv->Multibase.second, 1, 1, 0, true, false};
}
}
}
// 一元负号
if (auto* inst = dynamic_cast<Instruction*>(val)) {
auto kind = inst->getKind();
if (kind == Instruction::Kind::kNeg) {
if (DEBUG >= 2) {
std::cout << " -> Analyzing negation" << std::endl;
}
auto expr = analyzeLinearExpr(inst->getOperand(0), loop, ivs);
if (!expr.valid) return expr;
expr.factor1 = -expr.factor1;
expr.factor2 = -expr.factor2;
expr.offset = -expr.offset;
expr.isSimple = (expr.base2 == nullptr);
if (DEBUG >= 2) {
std::cout << " -> Negation result: valid=" << expr.valid << ", simple=" << expr.isSimple << std::endl;
}
return expr;
}
// 二元加减乘
if (kind == Instruction::Kind::kAdd || kind == Instruction::Kind::kSub) {
if (DEBUG >= 2) {
std::cout << " -> Analyzing " << (kind == Instruction::Kind::kAdd ? "addition" : "subtraction") << std::endl;
}
auto expr0 = analyzeLinearExpr(inst->getOperand(0), loop, ivs);
auto expr1 = analyzeLinearExpr(inst->getOperand(1), loop, ivs);
if (!expr0.valid || !expr1.valid) {
if (DEBUG >= 2) {
std::cout << " -> Failed: operand not linear (expr0.valid=" << expr0.valid << ", expr1.valid=" << expr1.valid << ")" << std::endl;
}
return {nullptr, nullptr, 0, 0, 0, false, false};
}
// 合并若BIV相同或有一个是常数
// 单BIV+常数
if (expr0.base1 && !expr1.base1 && !expr1.base2) {
int sign = (kind == Instruction::Kind::kAdd ? 1 : -1);
if (DEBUG >= 2) {
std::cout << " -> Single BIV + constant pattern" << std::endl;
}
return {expr0.base1, nullptr, expr0.factor1, 0, expr0.offset + sign * expr1.offset, true, expr0.isSimple};
}
if (!expr0.base1 && !expr0.base2 && expr1.base1) {
int sign = (kind == Instruction::Kind::kAdd ? 1 : -1);
int f = sign * expr1.factor1;
int off = expr0.offset + sign * expr1.offset;
if (DEBUG >= 2) {
std::cout << " -> Constant + single BIV pattern" << std::endl;
}
return {expr1.base1, nullptr, f, 0, off, true, expr1.isSimple};
}
// 双BIV线性组合
if (expr0.base1 && expr1.base1 && expr0.base1 != expr1.base1 && !expr0.base2 && !expr1.base2) {
int sign = (kind == Instruction::Kind::kAdd ? 1 : -1);
Value* base1 = expr0.base1;
Value* base2 = expr1.base1;
int f1 = expr0.factor1;
int f2 = sign * expr1.factor1;
int off = expr0.offset + sign * expr1.offset;
if (DEBUG >= 2) {
std::cout << " -> Double BIV linear combination" << std::endl;
}
return {base1, base2, f1, f2, off, true, false};
}
// 同BIV合并
if (expr0.base1 && expr1.base1 && expr0.base1 == expr1.base1 && !expr0.base2 && !expr1.base2) {
int sign = (kind == Instruction::Kind::kAdd ? 1 : -1);
int f = expr0.factor1 + sign * expr1.factor1;
int off = expr0.offset + sign * expr1.offset;
if (DEBUG >= 2) {
std::cout << " -> Same BIV combination" << std::endl;
}
return {expr0.base1, nullptr, f, 0, off, true, true};
}
}
// 乘法BIV*const 或 const*BIV
if (kind == Instruction::Kind::kMul) {
if (DEBUG >= 2) {
std::cout << " -> Analyzing multiplication" << std::endl;
}
auto expr0 = analyzeLinearExpr(inst->getOperand(0), loop, ivs);
auto expr1 = analyzeLinearExpr(inst->getOperand(1), loop, ivs);
// 只允许一侧为常数
if (expr0.base1 && !expr1.base1 && !expr1.base2 && expr1.offset) {
if (DEBUG >= 2) {
std::cout << " -> BIV * constant pattern" << std::endl;
}
return {expr0.base1, nullptr, expr0.factor1 * expr1.offset, 0, expr0.offset * expr1.offset, true, true};
}
if (!expr0.base1 && !expr0.base2 && expr0.offset && expr1.base1) {
if (DEBUG >= 2) {
std::cout << " -> Constant * BIV pattern" << std::endl;
}
return {expr1.base1, nullptr, expr1.factor1 * expr0.offset, 0, expr1.offset * expr0.offset, true, true};
}
// 双BIV乘法不支持
if (DEBUG >= 2) {
std::cout << " -> Multiplication pattern not supported" << std::endl;
}
}
// 除法BIV/const仅当const是2的幂时
if (kind == Instruction::Kind::kDiv) {
if (DEBUG >= 2) {
std::cout << " -> Analyzing division" << std::endl;
}
auto expr0 = analyzeLinearExpr(inst->getOperand(0), loop, ivs);
auto expr1 = analyzeLinearExpr(inst->getOperand(1), loop, ivs);
// 只支持 BIV / 2^n 形式
if (expr0.base1 && !expr1.base1 && !expr1.base2 && expr1.offset > 0) {
// 检查是否为2的幂
int divisor = expr1.offset;
if ((divisor & (divisor - 1)) == 0) { // 2的幂检查
if (DEBUG >= 2) {
std::cout << " -> BIV / power_of_2 pattern (divisor=" << divisor << ")" << std::endl;
}
// 对于除法,我们记录为特殊的归纳变量模式
// factor表示除数用于后续强度削弱
return {expr0.base1, nullptr, -divisor, 0, expr0.offset / divisor, true, true};
}
}
if (DEBUG >= 2) {
std::cout << " -> Division pattern not supported (not power of 2)" << std::endl;
}
}
// 取模BIV % const仅当const是2的幂时
if (kind == Instruction::Kind::kRem) {
if (DEBUG >= 2) {
std::cout << " -> Analyzing remainder" << std::endl;
}
auto expr0 = analyzeLinearExpr(inst->getOperand(0), loop, ivs);
auto expr1 = analyzeLinearExpr(inst->getOperand(1), loop, ivs);
// 只支持 BIV % 2^n 形式
if (expr0.base1 && !expr1.base1 && !expr1.base2 && expr1.offset > 0) {
// 检查是否为2的幂
int modulus = expr1.offset;
if ((modulus & (modulus - 1)) == 0) { // 2的幂检查
if (DEBUG >= 2) {
std::cout << " -> BIV % power_of_2 pattern (modulus=" << modulus << ")" << std::endl;
}
// 对于取模,我们记录为特殊的归纳变量模式
// 使用负的模数来区分取模和除法
return {expr0.base1, nullptr, -10000 - modulus, 0, 0, true, true}; // 特殊标记
}
}
if (DEBUG >= 2) {
std::cout << " -> Remainder pattern not supported (not power of 2)" << std::endl;
}
}
}
// 其它情况
if (DEBUG >= 2) {
std::cout << " -> Other case: not linear" << std::endl;
}
return {nullptr, nullptr, 0, 0, 0, false, false};
}
void LoopCharacteristicsPass::identifyBasicLoopInvariants(Loop* loop, LoopCharacteristics* characteristics) {
// 经典推进法:反复遍历,直到收敛 TODO优化
bool changed;
std::unordered_set<Value*> invariants = characteristics->loopInvariants; // 可能为空
do {
changed = false;
for (BasicBlock* bb : loop->getBlocks()) {
for (auto& inst : bb->getInstructions()) {
Instruction* I = inst.get();
// 跳过phi和terminator
if (dynamic_cast<PhiInst*>(I)) continue;
if (I->isTerminator()) continue;
if (invariants.count(I)) continue;
if (isClassicLoopInvariant(I, loop, invariants)) {
invariants.insert(I);
characteristics->invariantInsts.insert(I);
if (DEBUG)
std::cout << " Found loop invariant: " << I->getName() << std::endl;
changed = true;
}
}
}
} while (changed);
characteristics->loopInvariants = std::move(invariants);
}
void LoopCharacteristicsPass::analyzeBasicLoopBounds(Loop* loop, LoopCharacteristics* characteristics) {
// 简化的基础边界分析
// 检查是否有静态可确定的循环次数(简化版本)
if (characteristics->isCountingLoop && !characteristics->InductionVars.empty()) {
// 简化:如果是计数循环且有基本归纳变量,尝试确定循环次数
if (characteristics->instructionCount < 10) {
characteristics->staticTripCount = 100; // 简化估计
characteristics->hasKnownBounds = true;
if (DEBUG) {
std::cout << " Estimated static trip count: " << *characteristics->staticTripCount << std::endl;
}
}
}
}
void LoopCharacteristicsPass::evaluateBasicOptimizationOpportunities(Loop* loop, LoopCharacteristics* characteristics) {
// 评估基础循环展开机会
characteristics->benefitsFromUnrolling =
characteristics->isInnermost &&
characteristics->instructionCount > 3 &&
characteristics->instructionCount < 50 &&
!characteristics->hasComplexControlFlow;
if (characteristics->benefitsFromUnrolling) {
// 基于循环体大小估算展开因子
if (characteristics->instructionCount <= 5) characteristics->suggestedUnrollFactor = 8;
else if (characteristics->instructionCount <= 10) characteristics->suggestedUnrollFactor = 4;
else if (characteristics->instructionCount <= 20) characteristics->suggestedUnrollFactor = 2;
else characteristics->suggestedUnrollFactor = 1;
}
if (DEBUG) {
if (characteristics->benefitsFromUnrolling) {
std::cout << " Loop " << loop->getName() << " benefits from UNROLLING (factor="
<< characteristics->suggestedUnrollFactor << ")" << std::endl;
}
}
}
// ========== 辅助方法实现 ==========
// 递归识别DIV支持线性与复杂归纳变量
void LoopCharacteristicsPass::findDerivedInductionVars(
Value* root,
Value* base, // 只传单一BIV base
Loop* loop,
std::vector<std::unique_ptr<InductionVarInfo>>& ivs,
std::set<Value*>& visited)
{
if (visited.count(root)) return;
visited.insert(root);
if (DEBUG) {
std::cout << " Analyzing uses of: " << root->getName() << std::endl;
}
for (auto use : root->getUses()) {
auto user = use->getUser();
Instruction* inst = dynamic_cast<Instruction*>(user);
if (!inst) continue;
if (!loop->contains(inst->getParent())) {
if (DEBUG) {
std::cout << " Skipping user outside loop: " << inst->getName() << std::endl;
}
continue;
}
if (DEBUG) {
std::cout << " Checking instruction: " << inst->getName()
<< " (kind: " << static_cast<int>(inst->getKind()) << ")" << std::endl;
}
// 线性归约分析
auto expr = analyzeLinearExpr(inst, loop, ivs);
if (!expr.valid) {
if (DEBUG) {
std::cout << " Linear expression analysis failed for: " << inst->getName() << std::endl;
}
// 复杂非线性归纳变量作为kCmplx记录假如你想追踪
// 这里假设expr.base1、base2都有效才记录double
if (expr.base1 && expr.base2) {
if (DEBUG) {
std::cout << " [DIV-COMPLEX] Creating complex derived IV: " << inst->getName()
<< " with bases: " << expr.base1->getName() << ", " << expr.base2->getName() << std::endl;
}
ivs.push_back(InductionVarInfo::createDoubleDIV(inst, inst->getKind(), expr.base1, expr.base2, 0, expr.offset));
}
continue;
}
// 单BIV线性
if (expr.base1 && !expr.base2) {
// 检查这个指令是否已经是一个已知的IV特别是BIV避免重复创建
bool alreadyExists = false;
for (const auto& existingIV : ivs) {
if (existingIV->div == inst) {
alreadyExists = true;
if (DEBUG) {
std::cout << " [DIV-SKIP] Instruction " << inst->getName()
<< " already exists as IV, skipping creation" << std::endl;
}
break;
}
}
if (!alreadyExists) {
if (DEBUG) {
std::cout << " [DIV-LINEAR] Creating single-base derived IV: " << inst->getName()
<< " with base: " << expr.base1->getName()
<< ", factor: " << expr.factor1
<< ", offset: " << expr.offset << std::endl;
}
ivs.push_back(InductionVarInfo::createSingleDIV(inst, inst->getKind(), expr.base1, expr.factor1, expr.offset));
findDerivedInductionVars(inst, expr.base1, loop, ivs, visited);
}
}
// 双BIV线性
else if (expr.base1 && expr.base2) {
if (DEBUG) {
std::cout << " [DIV-COMPLEX] Creating double-base derived IV: " << inst->getName()
<< " with bases: " << expr.base1->getName() << ", " << expr.base2->getName()
<< ", offset: " << expr.offset << std::endl;
}
ivs.push_back(InductionVarInfo::createDoubleDIV(inst, inst->getKind(), expr.base1, expr.base2, 0, expr.offset));
// 双BIV情形一般不再递归下游
}
}
if (DEBUG) {
std::cout << " Finished analyzing uses of: " << root->getName() << std::endl;
}
}
// 递归/推进式判定
bool LoopCharacteristicsPass::isClassicLoopInvariant(Value* val, Loop* loop, const std::unordered_set<Value*>& invariants) {
// 1. 常量
if (auto* constval = dynamic_cast<ConstantValue*>(val)) return true;
// 2. 参数函数参数通常不在任何BasicBlock内直接判定为不变量
if (auto* arg = dynamic_cast<Argument*>(val)) return true;
// 3. 指令且定义在循环外
if (auto* inst = dynamic_cast<Instruction*>(val)) {
if (!loop->contains(inst->getParent()))
return true;
// 4. 跳转 phi指令 副作用 不外提
if (inst->isTerminator() || inst->isPhi() || sideEffectAnalysis->hasSideEffect(inst))
return false;
// 5. 所有操作数都是不变量
for (size_t i = 0; i < inst->getNumOperands(); ++i) {
Value* op = inst->getOperand(i);
if (!isClassicLoopInvariant(op, loop, invariants) && !invariants.count(op))
return false;
}
return true;
}
// 其它情况
return false;
}
bool LoopCharacteristicsPass::hasSimpleMemoryPattern(Loop* loop) {
// 检查是否有简单的内存访问模式
return true; // 暂时简化处理
}
} // namespace sysy

View File

@@ -0,0 +1,803 @@
#include "LoopVectorization.h"
#include "Dom.h"
#include "Loop.h"
#include "Liveness.h"
#include "AliasAnalysis.h"
#include "SideEffectAnalysis.h"
#include <iostream>
#include <algorithm>
#include <cmath>
#include <set>
extern int DEBUG;
namespace sysy {
// 定义 Pass 的唯一 ID
void *LoopVectorizationPass::ID = (void *)&LoopVectorizationPass::ID;
std::vector<int> DependenceVector::getDirectionVector() const {
std::vector<int> direction;
direction.reserve(distances.size());
for (int dist : distances) {
if (dist > 0) direction.push_back(1); // 前向依赖
else if (dist < 0) direction.push_back(-1); // 后向依赖
else direction.push_back(0); // 无依赖
}
return direction;
}
bool DependenceVector::isVectorizationSafe() const {
if (!isKnown) return false; // 未知依赖,不安全
// 对于向量化,我们主要关心最内层循环的依赖
if (distances.empty()) return true;
int innermostDistance = distances.back(); // 最内层循环的距离
// 前向依赖 (距离 > 0) 通常是安全的,可以通过调整向量化顺序处理
// 后向依赖 (距离 < 0) 通常不安全,会阻止向量化
// 距离 = 0 表示同一迭代内的依赖,通常安全
return innermostDistance >= 0;
}
size_t LoopVectorizationResult::getVectorizableLoopCount() const {
size_t count = 0;
for (const auto& [loop, analysis] : VectorizationMap) {
if (analysis.isVectorizable) count++;
}
return count;
}
size_t LoopVectorizationResult::getParallelizableLoopCount() const {
size_t count = 0;
for (const auto& [loop, analysis] : ParallelizationMap) {
if (analysis.isParallelizable) count++;
}
return count;
}
std::vector<Loop*> LoopVectorizationResult::getVectorizationCandidates() const {
std::vector<Loop*> candidates;
for (const auto& [loop, analysis] : VectorizationMap) {
if (analysis.isVectorizable) {
candidates.push_back(loop);
}
}
// 按建议的向量宽度排序,优先处理收益更大的循环
std::sort(candidates.begin(), candidates.end(),
[this](Loop* a, Loop* b) {
const auto& analysisA = VectorizationMap.at(a);
const auto& analysisB = VectorizationMap.at(b);
return analysisA.suggestedVectorWidth > analysisB.suggestedVectorWidth;
});
return candidates;
}
std::vector<Loop*> LoopVectorizationResult::getParallelizationCandidates() const {
std::vector<Loop*> candidates;
for (const auto& [loop, analysis] : ParallelizationMap) {
if (analysis.isParallelizable) {
candidates.push_back(loop);
}
}
// 按建议的线程数排序
std::sort(candidates.begin(), candidates.end(),
[this](Loop* a, Loop* b) {
const auto& analysisA = ParallelizationMap.at(a);
const auto& analysisB = ParallelizationMap.at(b);
return analysisA.suggestedThreadCount > analysisB.suggestedThreadCount;
});
return candidates;
}
void LoopVectorizationResult::print() const {
if (!DEBUG) return;
std::cout << "\n--- Loop Vectorization/Parallelization Analysis Results for Function: "
<< AssociatedFunction->getName() << " ---" << std::endl;
if (VectorizationMap.empty() && ParallelizationMap.empty()) {
std::cout << " No vectorization/parallelization analysis results." << std::endl;
return;
}
// 统计信息
std::cout << "\n=== Summary ===" << std::endl;
std::cout << "Total Loops Analyzed: " << VectorizationMap.size() << std::endl;
std::cout << "Vectorizable Loops: " << getVectorizableLoopCount() << std::endl;
std::cout << "Parallelizable Loops: " << getParallelizableLoopCount() << std::endl;
// 详细分析结果
for (const auto& [loop, vecAnalysis] : VectorizationMap) {
std::cout << "\n--- Loop: " << loop->getName() << " ---" << std::endl;
// 向量化分析 (暂时搁置)
std::cout << " Vectorization: " << (vecAnalysis.isVectorizable ? "YES" : "NO") << std::endl;
if (!vecAnalysis.preventingFactors.empty()) {
std::cout << " Preventing Factors: ";
for (const auto& factor : vecAnalysis.preventingFactors) {
std::cout << factor << " ";
}
std::cout << std::endl;
}
// 并行化分析
auto parallelIt = ParallelizationMap.find(loop);
if (parallelIt != ParallelizationMap.end()) {
const auto& parAnalysis = parallelIt->second;
std::cout << " Parallelization: " << (parAnalysis.isParallelizable ? "YES" : "NO") << std::endl;
if (parAnalysis.isParallelizable) {
std::cout << " Suggested Thread Count: " << parAnalysis.suggestedThreadCount << std::endl;
if (parAnalysis.requiresReduction) {
std::cout << " Requires Reduction: Yes" << std::endl;
}
if (parAnalysis.requiresBarrier) {
std::cout << " Requires Barrier: Yes" << std::endl;
}
} else if (!parAnalysis.preventingFactors.empty()) {
std::cout << " Preventing Factors: ";
for (const auto& factor : parAnalysis.preventingFactors) {
std::cout << factor << " ";
}
std::cout << std::endl;
}
}
// 依赖关系
auto depIt = DependenceMap.find(loop);
if (depIt != DependenceMap.end()) {
const auto& dependences = depIt->second;
std::cout << " Dependences: " << dependences.size() << " found" << std::endl;
for (const auto& dep : dependences) {
if (dep.dependenceVector.isKnown) {
std::cout << " " << dep.source->getName() << " -> " << dep.sink->getName();
std::cout << " [";
for (size_t i = 0; i < dep.dependenceVector.distances.size(); ++i) {
if (i > 0) std::cout << ",";
std::cout << dep.dependenceVector.distances[i];
}
std::cout << "]" << std::endl;
}
}
}
}
std::cout << "-----------------------------------------------" << std::endl;
}
bool LoopVectorizationPass::runOnFunction(Function *F, AnalysisManager &AM) {
if (F->getBasicBlocks().empty()) {
CurrentResult = std::make_unique<LoopVectorizationResult>(F);
return false;
}
if (DEBUG) {
std::cout << "Running LoopVectorizationPass on function: " << F->getName() << std::endl;
}
// 获取循环分析结果
auto* loopAnalysisResult = AM.getAnalysisResult<LoopAnalysisResult, LoopAnalysisPass>(F);
if (!loopAnalysisResult || !loopAnalysisResult->hasLoops()) {
CurrentResult = std::make_unique<LoopVectorizationResult>(F);
return false;
}
// 获取循环特征分析结果
auto* loopCharacteristics = AM.getAnalysisResult<LoopCharacteristicsResult, LoopCharacteristicsPass>(F);
if (!loopCharacteristics) {
if (DEBUG) {
std::cout << "Warning: LoopCharacteristics analysis not available" << std::endl;
}
}
// 获取别名分析结果
auto* aliasAnalysis = AM.getAnalysisResult<AliasAnalysisResult, SysYAliasAnalysisPass>(F);
// 获取副作用分析结果
auto* sideEffectAnalysis = AM.getAnalysisResult<SideEffectAnalysisResult, SysYSideEffectAnalysisPass>();
CurrentResult = std::make_unique<LoopVectorizationResult>(F);
// 分析每个循环的向量化/并行化可行性
for (const auto& loop_ptr : loopAnalysisResult->getAllLoops()) {
Loop* loop = loop_ptr.get();
// 获取该循环的特征信息
LoopCharacteristics* characteristics = nullptr;
if (loopCharacteristics) {
characteristics = const_cast<LoopCharacteristics*>(loopCharacteristics->getCharacteristics(loop));
}
analyzeLoop(loop, characteristics, aliasAnalysis, sideEffectAnalysis);
}
if (DEBUG) {
std::cout << "LoopVectorizationPass completed. Found "
<< CurrentResult->getVectorizableLoopCount() << " vectorizable loops, "
<< CurrentResult->getParallelizableLoopCount() << " parallelizable loops" << std::endl;
}
return false; // 分析遍不修改IR
}
void LoopVectorizationPass::analyzeLoop(Loop* loop, LoopCharacteristics* characteristics,
AliasAnalysisResult* aliasAnalysis, SideEffectAnalysisResult* sideEffectAnalysis) {
if (DEBUG) {
std::cout << " Analyzing advanced features for loop: " << loop->getName() << std::endl;
}
// 1. 计算精确依赖向量
auto dependences = computeDependenceVectors(loop, aliasAnalysis);
CurrentResult->addDependenceAnalysis(loop, dependences);
// 2. 分析向量化可行性 (暂时搁置,总是返回不可向量化)
auto vecAnalysis = analyzeVectorizability(loop, dependences, characteristics);
CurrentResult->addVectorizationAnalysis(loop, vecAnalysis);
// 3. 分析并行化可行性
auto parAnalysis = analyzeParallelizability(loop, dependences, characteristics);
CurrentResult->addParallelizationAnalysis(loop, parAnalysis);
}
// ========== 依赖向量分析实现 ==========
std::vector<PreciseDependence> LoopVectorizationPass::computeDependenceVectors(Loop* loop,
AliasAnalysisResult* aliasAnalysis) {
std::vector<PreciseDependence> dependences;
std::vector<Instruction*> memoryInsts;
// 收集所有内存操作指令
for (BasicBlock* bb : loop->getBlocks()) {
for (auto& inst : bb->getInstructions()) {
if (dynamic_cast<LoadInst*>(inst.get()) || dynamic_cast<StoreInst*>(inst.get())) {
memoryInsts.push_back(inst.get());
}
}
}
// 分析每对内存操作之间的依赖关系
for (size_t i = 0; i < memoryInsts.size(); ++i) {
for (size_t j = i + 1; j < memoryInsts.size(); ++j) {
Instruction* inst1 = memoryInsts[i];
Instruction* inst2 = memoryInsts[j];
Value* ptr1 = nullptr;
Value* ptr2 = nullptr;
if (auto* load = dynamic_cast<LoadInst*>(inst1)) {
ptr1 = load->getPointer();
} else if (auto* store = dynamic_cast<StoreInst*>(inst1)) {
ptr1 = store->getPointer();
}
if (auto* load = dynamic_cast<LoadInst*>(inst2)) {
ptr2 = load->getPointer();
} else if (auto* store = dynamic_cast<StoreInst*>(inst2)) {
ptr2 = store->getPointer();
}
if (!ptr1 || !ptr2) continue;
// 检查是否可能存在别名关系
bool mayAlias = false;
if (aliasAnalysis) {
mayAlias = aliasAnalysis->queryAlias(ptr1, ptr2) != AliasType::NO_ALIAS;
} else {
mayAlias = (ptr1 != ptr2); // 保守估计
}
if (mayAlias) {
// 创建依赖关系
PreciseDependence dep(loop->getLoopDepth());
dep.source = inst1;
dep.sink = inst2;
dep.memoryLocation = ptr1;
// 确定依赖类型
bool isStore1 = dynamic_cast<StoreInst*>(inst1) != nullptr;
bool isStore2 = dynamic_cast<StoreInst*>(inst2) != nullptr;
if (isStore1 && !isStore2) {
dep.type = DependenceType::TRUE_DEPENDENCE; // Write -> Read (RAW)
} else if (!isStore1 && isStore2) {
dep.type = DependenceType::ANTI_DEPENDENCE; // Read -> Write (WAR)
} else if (isStore1 && isStore2) {
dep.type = DependenceType::OUTPUT_DEPENDENCE; // Write -> Write (WAW)
} else {
continue; // Read -> Read (RAR) - 跳过,不是真正的依赖
}
// 计算依赖向量
dep.dependenceVector = computeAccessDependence(inst1, inst2, loop);
// 判断是否允许并行化
dep.allowsParallelization = dep.dependenceVector.isLoopIndependent() ||
(dep.dependenceVector.isKnown &&
std::all_of(dep.dependenceVector.distances.begin(),
dep.dependenceVector.distances.end(),
[](int d) { return d >= 0; }));
dependences.push_back(dep);
if (DEBUG && dep.dependenceVector.isKnown) {
std::cout << " Found dependence: " << inst1->getName()
<< " -> " << inst2->getName() << " [";
for (size_t k = 0; k < dep.dependenceVector.distances.size(); ++k) {
if (k > 0) std::cout << ",";
std::cout << dep.dependenceVector.distances[k];
}
std::cout << "]" << std::endl;
}
}
}
}
return dependences;
}
DependenceVector LoopVectorizationPass::computeAccessDependence(Instruction* inst1, Instruction* inst2, Loop* loop) {
DependenceVector depVec(loop->getLoopDepth());
Value* ptr1 = nullptr;
Value* ptr2 = nullptr;
if (auto* load = dynamic_cast<LoadInst*>(inst1)) {
ptr1 = load->getPointer();
} else if (auto* store = dynamic_cast<StoreInst*>(inst1)) {
ptr1 = store->getPointer();
}
if (auto* load = dynamic_cast<LoadInst*>(inst2)) {
ptr2 = load->getPointer();
} else if (auto* store = dynamic_cast<StoreInst*>(inst2)) {
ptr2 = store->getPointer();
}
if (!ptr1 || !ptr2) return depVec;
// 尝试分析仿射关系
if (areAccessesAffinelyRelated(ptr1, ptr2, loop)) {
auto coeff1 = extractInductionCoefficients(ptr1, loop);
auto coeff2 = extractInductionCoefficients(ptr2, loop);
if (coeff1.size() == coeff2.size()) {
depVec.isKnown = true;
depVec.isConstant = true;
for (size_t i = 0; i < coeff1.size(); ++i) {
depVec.distances[i] = coeff2[i] - coeff1[i];
}
}
}
return depVec;
}
bool LoopVectorizationPass::areAccessesAffinelyRelated(Value* ptr1, Value* ptr2, Loop* loop) {
// 简化实现:检查是否都是基于归纳变量的数组访问
// 真正的实现需要复杂的仿射关系分析
// 检查是否为 GEP 指令
auto* gep1 = dynamic_cast<GetElementPtrInst*>(ptr1);
auto* gep2 = dynamic_cast<GetElementPtrInst*>(ptr2);
if (!gep1 || !gep2) return false;
// 检查是否访问同一个数组基址
if (gep1->getBasePointer() != gep2->getBasePointer()) return false;
// 简化:假设都是仿射的
return true;
}
// ========== 向量化分析实现 (暂时搁置) ==========
VectorizationAnalysis LoopVectorizationPass::analyzeVectorizability(Loop* loop,
const std::vector<PreciseDependence>& dependences,
LoopCharacteristics* characteristics) {
VectorizationAnalysis analysis; // 构造函数已设置为不可向量化
if (DEBUG) {
std::cout << " Vectorization analysis: DISABLED (temporarily)" << std::endl;
}
// 向量化功能暂时搁置,总是返回不可向量化
// 这里可以添加一些基本的诊断信息用于日志
if (!loop->isInnermost()) {
analysis.preventingFactors.push_back("Not innermost loop");
}
if (loop->getBlocks().size() > 1) {
analysis.preventingFactors.push_back("Complex control flow");
}
if (!dependences.empty()) {
analysis.preventingFactors.push_back("Has dependences (not analyzed in detail)");
}
return analysis;
}
// ========== 并行化分析实现 ==========
ParallelizationAnalysis LoopVectorizationPass::analyzeParallelizability(Loop* loop,
const std::vector<PreciseDependence>& dependences,
LoopCharacteristics* characteristics) {
ParallelizationAnalysis analysis;
if (DEBUG) {
std::cout << " Analyzing parallelizability for loop: " << loop->getName() << std::endl;
std::cout << " Found " << dependences.size() << " dependences" << std::endl;
}
// 按依赖类型分类分析
bool hasTrueDependences = false;
bool hasAntiDependences = false;
bool hasOutputDependences = false;
for (const auto& dep : dependences) {
switch (dep.type) {
case DependenceType::TRUE_DEPENDENCE:
hasTrueDependences = true;
// 真依赖通常是最难处理的,需要检查是否为归约模式
if (dep.isReductionDependence) {
analysis.requiresReduction = true;
analysis.reductionVariables.insert(dep.memoryLocation);
} else {
analysis.preventingFactors.push_back("Non-reduction true dependence");
}
break;
case DependenceType::ANTI_DEPENDENCE:
hasAntiDependences = true;
// 反依赖可以通过变量私有化解决
analysis.privatizableVariables.insert(dep.memoryLocation);
break;
case DependenceType::OUTPUT_DEPENDENCE:
hasOutputDependences = true;
// 输出依赖可以通过变量私有化或原子操作解决
analysis.sharedVariables.insert(dep.memoryLocation);
break;
}
}
// 确定并行化类型
analysis.parallelType = determineParallelizationType(loop, dependences);
// 基于依赖类型评估可并行性
if (!hasTrueDependences && !hasOutputDependences) {
// 只有反依赖或无依赖,完全可并行
analysis.parallelType = ParallelizationAnalysis::EMBARRASSINGLY_PARALLEL;
analysis.isParallelizable = true;
} else if (analysis.requiresReduction) {
// 有归约模式,可以并行但需要特殊处理
analysis.parallelType = ParallelizationAnalysis::REDUCTION_PARALLEL;
analysis.isParallelizable = true;
} else if (hasTrueDependences) {
// 有非归约的真依赖,通常不能并行化
analysis.isParallelizable = false;
analysis.preventingFactors.push_back("Non-reduction loop-carried true dependences");
}
if (analysis.isParallelizable) {
// 进一步分析并行化收益和成本
estimateParallelizationBenefit(loop, &analysis, characteristics);
analyzeSynchronizationNeeds(loop, &analysis, dependences);
analysis.suggestedThreadCount = estimateOptimalThreadCount(loop, characteristics);
}
if (DEBUG) {
std::cout << " Parallelizable: " << (analysis.isParallelizable ? "YES" : "NO") << std::endl;
if (analysis.isParallelizable) {
std::cout << " Type: " << (int)analysis.parallelType << ", Threads: " << analysis.suggestedThreadCount << std::endl;
}
}
return analysis;
}
bool LoopVectorizationPass::checkParallelizationLegality(Loop* loop, const std::vector<PreciseDependence>& dependences) {
// 检查所有依赖是否允许并行化
for (const auto& dep : dependences) {
if (!dep.allowsParallelization) {
return false;
}
}
// 检查是否有无法并行化的操作
for (BasicBlock* bb : loop->getBlocks()) {
for (auto& inst : bb->getInstructions()) {
// 检查原子操作、同步操作等
if (auto* call = dynamic_cast<CallInst*>(inst.get())) {
// 简化:假设函数调用需要特殊处理
// 在实际实现中,需要分析函数的副作用
return false;
}
}
}
return true;
}
int LoopVectorizationPass::estimateOptimalThreadCount(Loop* loop, LoopCharacteristics* characteristics) {
// 基于循环特征估计最优线程数
if (!characteristics) return 2;
// 基于循环体大小和计算密度
int baseThreads = 2;
if (characteristics->instructionCount > 50) baseThreads = 4;
if (characteristics->instructionCount > 200) baseThreads = 8;
// 基于计算与内存比率调整
if (characteristics->computeToMemoryRatio > 2.0) {
baseThreads *= 2; // 计算密集型,可以使用更多线程
}
return std::min(baseThreads, 16); // 限制最大线程数
}
// ========== 辅助方法实现 ==========
bool LoopVectorizationPass::isConstantStride(Value* ptr, Loop* loop, int& stride) {
// 简化实现:检查是否为常量步长访问
stride = 1; // 默认步长
auto* gep = dynamic_cast<GetElementPtrInst*>(ptr);
if (!gep) return false;
// 检查最后一个索引是否为归纳变量 + 常量
if (gep->getNumIndices() > 0) {
Value* lastIndex = gep->getIndex(gep->getNumIndices() - 1);
// 简化:假设是 i 或 i+c 的形式
if (auto* binInst = dynamic_cast<BinaryInst*>(lastIndex)) {
if (binInst->getKind() == Instruction::kAdd) {
// 检查是否为 i + constant
if (auto* constInt = dynamic_cast<ConstantInteger*>(binInst->getRhs())) {
stride = constInt->getInt();
return true;
}
}
}
// 默认为步长1的连续访问
stride = 1;
return true;
}
return false;
}
std::vector<int> LoopVectorizationPass::extractInductionCoefficients(Value* ptr, Loop* loop) {
// 简化实现:返回默认的仿射系数
std::vector<int> coefficients;
// 假设是简单的 a[i] 形式,系数为 [0, 1]
coefficients.push_back(0); // 常数项
coefficients.push_back(1); // 归纳变量系数
return coefficients;
}
// ========== 缺失的方法实现 ==========
ParallelizationAnalysis::ParallelizationType LoopVectorizationPass::determineParallelizationType(
Loop* loop, const std::vector<PreciseDependence>& dependences) {
// 检查是否有任何依赖
if (dependences.empty()) {
return ParallelizationAnalysis::EMBARRASSINGLY_PARALLEL;
}
// 检查是否只有归约模式
bool hasReduction = false;
bool hasOtherDependences = false;
for (const auto& dep : dependences) {
if (dep.isReductionDependence) {
hasReduction = true;
} else if (dep.type == DependenceType::TRUE_DEPENDENCE) {
hasOtherDependences = true;
}
}
if (hasReduction && !hasOtherDependences) {
return ParallelizationAnalysis::REDUCTION_PARALLEL;
} else if (!hasOtherDependences) {
return ParallelizationAnalysis::EMBARRASSINGLY_PARALLEL;
}
return ParallelizationAnalysis::NONE;
}
void LoopVectorizationPass::analyzeReductionPatterns(Loop* loop, ParallelizationAnalysis* analysis) {
// 简化实现:查找常见的归约模式
for (BasicBlock* bb : loop->getBlocks()) {
for (auto& inst : bb->getInstructions()) {
if (auto* binInst = dynamic_cast<BinaryInst*>(inst.get())) {
if (binInst->getKind() == Instruction::kAdd || binInst->getKind() == Instruction::kMul) {
// 检查是否为累加/累乘模式
Value* lhs = binInst->getLhs();
if (hasReductionPattern(lhs, loop)) {
analysis->requiresReduction = true;
analysis->reductionVariables.insert(lhs);
}
}
}
}
}
}
void LoopVectorizationPass::analyzeMemoryAccessPatterns(Loop* loop, ParallelizationAnalysis* analysis,
AliasAnalysisResult* aliasAnalysis) {
std::vector<Value*> memoryAccesses;
// 收集所有内存访问
for (BasicBlock* bb : loop->getBlocks()) {
for (auto& inst : bb->getInstructions()) {
if (auto* load = dynamic_cast<LoadInst*>(inst.get())) {
memoryAccesses.push_back(load->getPointer());
} else if (auto* store = dynamic_cast<StoreInst*>(inst.get())) {
memoryAccesses.push_back(store->getPointer());
}
}
}
// 分析内存访问独立性
bool hasIndependentAccess = true;
for (size_t i = 0; i < memoryAccesses.size(); ++i) {
for (size_t j = i + 1; j < memoryAccesses.size(); ++j) {
if (!isIndependentMemoryAccess(memoryAccesses[i], memoryAccesses[j], loop)) {
hasIndependentAccess = false;
analysis->hasMemoryConflicts = true;
}
}
}
analysis->hasIndependentAccess = hasIndependentAccess;
}
void LoopVectorizationPass::estimateParallelizationBenefit(Loop* loop, ParallelizationAnalysis* analysis,
LoopCharacteristics* characteristics) {
if (!analysis->isParallelizable) {
analysis->parallelizationBenefit = 0.0;
return;
}
// 基于计算复杂度和并行度计算收益
double workComplexity = estimateWorkComplexity(loop);
double parallelFraction = 1.0; // 假设完全可并行
// 根据依赖调整并行度
if (analysis->requiresReduction) {
parallelFraction *= 0.8; // 归约降低并行效率
}
if (analysis->hasMemoryConflicts) {
parallelFraction *= 0.6; // 内存冲突降低效率
}
// Amdahl定律估算
double serialFraction = 1.0 - parallelFraction;
int threadCount = analysis->suggestedThreadCount;
double speedup = 1.0 / (serialFraction + parallelFraction / threadCount);
analysis->parallelizationBenefit = std::min((speedup - 1.0) / threadCount, 1.0);
// 估算同步和通信开销
analysis->synchronizationCost = analysis->requiresBarrier ? 100 : 0;
analysis->communicationCost = analysis->sharedVariables.size() * 50;
}
void LoopVectorizationPass::identifyPrivatizableVariables(Loop* loop, ParallelizationAnalysis* analysis) {
// 简化实现:标识循环内定义的变量为可私有化
for (BasicBlock* bb : loop->getBlocks()) {
for (auto& inst : bb->getInstructions()) {
if (!inst->getType()->isVoid()) {
// 如果变量只在循环内使用,可能可以私有化
bool onlyUsedInLoop = true;
for (auto& use : inst->getUses()) {
if (auto* userInst = dynamic_cast<Instruction*>(use->getUser())) {
if (!loop->contains(userInst->getParent())) {
onlyUsedInLoop = false;
break;
}
}
}
if (onlyUsedInLoop) {
analysis->privatizableVariables.insert(inst.get());
}
}
}
}
}
void LoopVectorizationPass::analyzeSynchronizationNeeds(Loop* loop, ParallelizationAnalysis* analysis,
const std::vector<PreciseDependence>& dependences) {
// 根据依赖类型确定同步需求
for (const auto& dep : dependences) {
if (dep.type == DependenceType::OUTPUT_DEPENDENCE) {
analysis->requiresBarrier = true;
analysis->sharedVariables.insert(dep.memoryLocation);
}
}
// 如果有归约,需要特殊的归约同步
if (analysis->requiresReduction) {
analysis->requiresBarrier = true;
}
}
bool LoopVectorizationPass::isIndependentMemoryAccess(Value* ptr1, Value* ptr2, Loop* loop) {
// 简化实现:基本的独立性检查
if (ptr1 == ptr2) return false;
// 如果是不同的基址,认为是独立的
auto* gep1 = dynamic_cast<GetElementPtrInst*>(ptr1);
auto* gep2 = dynamic_cast<GetElementPtrInst*>(ptr2);
if (gep1 && gep2) {
if (gep1->getBasePointer() != gep2->getBasePointer()) {
return true; // 不同的基址
}
// 相同基址,需要更精细的分析(这里简化为不独立)
return false;
}
return true; // 默认认为独立
}
double LoopVectorizationPass::estimateWorkComplexity(Loop* loop) {
double complexity = 0.0;
for (BasicBlock* bb : loop->getBlocks()) {
for (auto& inst : bb->getInstructions()) {
// 基于指令类型分配复杂度权重
if (auto* binInst = dynamic_cast<BinaryInst*>(inst.get())) {
switch (binInst->getKind()) {
case Instruction::kAdd:
case Instruction::kSub:
complexity += 1.0;
break;
case Instruction::kMul:
complexity += 3.0;
break;
case Instruction::kDiv:
complexity += 10.0;
break;
default:
complexity += 2.0;
}
} else if (dynamic_cast<LoadInst*>(inst.get()) || dynamic_cast<StoreInst*>(inst.get())) {
complexity += 2.0; // 内存访问
} else {
complexity += 1.0; // 其他指令
}
}
}
return complexity;
}
bool LoopVectorizationPass::hasReductionPattern(Value* var, Loop* loop) {
// 简化实现:检查是否为简单的累加/累乘模式
for (auto& use : var->getUses()) {
if (auto* binInst = dynamic_cast<BinaryInst*>(use->getUser())) {
if (binInst->getKind() == Instruction::kAdd || binInst->getKind() == Instruction::kMul) {
// 检查是否为 var = var op something 的模式
if (binInst->getLhs() == var || binInst->getRhs() == var) {
return true;
}
}
}
}
return false;
}
} // namespace sysy

View File

@@ -0,0 +1,402 @@
#include "SideEffectAnalysis.h"
#include "AliasAnalysis.h"
#include "CallGraphAnalysis.h"
#include "SysYIRPrinter.h"
#include <iostream>
namespace sysy {
// 副作用分析遍的静态 ID
void *SysYSideEffectAnalysisPass::ID = (void *)&SysYSideEffectAnalysisPass::ID;
// ======================================================================
// SideEffectAnalysisResult 类的实现
// ======================================================================
SideEffectAnalysisResult::SideEffectAnalysisResult() { initializeKnownFunctions(); }
const SideEffectInfo &SideEffectAnalysisResult::getInstructionSideEffect(Instruction *inst) const {
auto it = instructionSideEffects.find(inst);
if (it != instructionSideEffects.end()) {
return it->second;
}
// 返回默认的无副作用信息
static SideEffectInfo noEffect;
return noEffect;
}
const SideEffectInfo &SideEffectAnalysisResult::getFunctionSideEffect(Function *func) const {
auto it = functionSideEffects.find(func);
if (it != functionSideEffects.end()) {
return it->second;
}
// 返回默认的无副作用信息
static SideEffectInfo noEffect;
return noEffect;
}
void SideEffectAnalysisResult::setInstructionSideEffect(Instruction *inst, const SideEffectInfo &info) {
instructionSideEffects[inst] = info;
}
void SideEffectAnalysisResult::setFunctionSideEffect(Function *func, const SideEffectInfo &info) {
functionSideEffects[func] = info;
}
bool SideEffectAnalysisResult::hasSideEffect(Instruction *inst) const {
const auto &info = getInstructionSideEffect(inst);
return info.type != SideEffectType::NO_SIDE_EFFECT;
}
bool SideEffectAnalysisResult::mayModifyMemory(Instruction *inst) const {
const auto &info = getInstructionSideEffect(inst);
return info.mayModifyMemory;
}
bool SideEffectAnalysisResult::mayModifyGlobal(Instruction *inst) const {
const auto &info = getInstructionSideEffect(inst);
return info.mayModifyGlobal;
}
bool SideEffectAnalysisResult::isPureFunction(Function *func) const {
const auto &info = getFunctionSideEffect(func);
return info.isPure;
}
void SideEffectAnalysisResult::initializeKnownFunctions() {
// SysY标准库函数的副作用信息
// I/O函数 - 有副作用
SideEffectInfo ioEffect;
ioEffect.type = SideEffectType::IO_OPERATION;
ioEffect.mayModifyGlobal = true;
ioEffect.mayModifyMemory = true;
ioEffect.mayCallFunction = true;
ioEffect.isPure = false;
// knownFunctions["printf"] = ioEffect;
// knownFunctions["scanf"] = ioEffect;
knownFunctions["getint"] = ioEffect;
knownFunctions["getch"] = ioEffect;
knownFunctions["getfloat"] = ioEffect;
knownFunctions["getarray"] = ioEffect;
knownFunctions["getfarray"] = ioEffect;
knownFunctions["putint"] = ioEffect;
knownFunctions["putch"] = ioEffect;
knownFunctions["putfloat"] = ioEffect;
knownFunctions["putarray"] = ioEffect;
knownFunctions["putfarray"] = ioEffect;
// 时间函数 - 有副作用
SideEffectInfo timeEffect;
timeEffect.type = SideEffectType::FUNCTION_CALL;
timeEffect.mayModifyGlobal = true;
timeEffect.mayModifyMemory = false;
timeEffect.mayCallFunction = true;
timeEffect.isPure = false;
knownFunctions["_sysy_starttime"] = timeEffect;
knownFunctions["_sysy_stoptime"] = timeEffect;
}
const SideEffectInfo *SideEffectAnalysisResult::getKnownFunctionSideEffect(const std::string &funcName) const {
auto it = knownFunctions.find(funcName);
return (it != knownFunctions.end()) ? &it->second : nullptr;
}
// ======================================================================
// SysYSideEffectAnalysisPass 类的实现
// ======================================================================
bool SysYSideEffectAnalysisPass::runOnModule(Module *M, AnalysisManager &AM) {
if (DEBUG) {
std::cout << "Running SideEffect analysis on module" << std::endl;
}
// 创建分析结果构造函数中已经调用了initializeKnownFunctions
result = std::make_unique<SideEffectAnalysisResult>();
// 获取调用图分析结果
callGraphAnalysis = AM.getAnalysisResult<CallGraphAnalysisResult, CallGraphAnalysisPass>();
if (!callGraphAnalysis) {
std::cerr << "Warning: CallGraphAnalysis not available, falling back to conservative analysis" << std::endl;
}
// 按拓扑序分析函数,确保被调用函数先于调用者分析
if (callGraphAnalysis) {
// 使用调用图的拓扑排序结果
const auto &topOrder = callGraphAnalysis->getTopologicalOrder();
// 处理强连通分量(递归函数群)
const auto &sccs = callGraphAnalysis->getStronglyConnectedComponents();
for (const auto &scc : sccs) {
if (scc.size() > 1) {
// 多个函数的强连通分量,使用不动点算法
analyzeStronglyConnectedComponent(scc, AM);
} else {
// 单个函数,检查是否自递归
Function *func = scc[0];
if (callGraphAnalysis->isSelfRecursive(func)) {
// 自递归函数也需要不动点算法
analyzeStronglyConnectedComponent(scc, AM);
} else {
// 非递归函数,直接分析
SideEffectInfo funcEffect = analyzeFunction(func, AM);
result->setFunctionSideEffect(func, funcEffect);
}
}
}
} else {
// 没有调用图,保守地分析每个函数
for (auto &pair : M->getFunctions()) {
Function *func = pair.second.get();
SideEffectInfo funcEffect = analyzeFunction(func, AM);
result->setFunctionSideEffect(func, funcEffect);
}
}
if (DEBUG) {
std::cout << "---- Side Effect Analysis Results for Module ----\n";
for (auto &pair : M->getFunctions()) {
Function *func = pair.second.get();
const auto &funcInfo = result->getFunctionSideEffect(func);
std::cout << "Function " << func->getName() << ": ";
switch (funcInfo.type) {
case SideEffectType::NO_SIDE_EFFECT:
std::cout << "No Side Effect";
break;
case SideEffectType::MEMORY_WRITE:
std::cout << "Memory Write";
break;
case SideEffectType::FUNCTION_CALL:
std::cout << "Function Call";
break;
case SideEffectType::IO_OPERATION:
std::cout << "I/O Operation";
break;
case SideEffectType::UNKNOWN:
std::cout << "Unknown";
break;
}
std::cout << " (Pure: " << (funcInfo.isPure ? "Yes" : "No")
<< ", Modifies Global: " << (funcInfo.mayModifyGlobal ? "Yes" : "No") << ")\n";
}
std::cout << "--------------------------------------------------\n";
}
return false; // Analysis passes return false since they don't modify the IR
}
std::unique_ptr<AnalysisResultBase> SysYSideEffectAnalysisPass::getResult() { return std::move(result); }
SideEffectInfo SysYSideEffectAnalysisPass::analyzeFunction(Function *func, AnalysisManager &AM) {
SideEffectInfo functionSideEffect;
// 为每个指令分析副作用
for (auto &BB : func->getBasicBlocks()) {
for (auto &I : BB->getInstructions_Range()) {
Instruction *inst = I.get();
SideEffectInfo instEffect = analyzeInstruction(inst, func, AM);
// 记录指令的副作用信息
result->setInstructionSideEffect(inst, instEffect);
// 合并到函数级别的副作用信息中
functionSideEffect = functionSideEffect.merge(instEffect);
}
}
return functionSideEffect;
}
void SysYSideEffectAnalysisPass::analyzeStronglyConnectedComponent(const std::vector<Function *> &scc,
AnalysisManager &AM) {
// 使用不动点算法处理递归函数群
std::unordered_map<Function *, SideEffectInfo> currentEffects;
std::unordered_map<Function *, SideEffectInfo> previousEffects;
// 初始化:所有函数都假设为纯函数
for (Function *func : scc) {
SideEffectInfo initialEffect;
initialEffect.isPure = true;
currentEffects[func] = initialEffect;
result->setFunctionSideEffect(func, initialEffect);
}
bool converged = false;
int iterations = 0;
const int maxIterations = 10; // 防止无限循环
while (!converged && iterations < maxIterations) {
previousEffects = currentEffects;
// 重新分析每个函数
for (Function *func : scc) {
SideEffectInfo newEffect = analyzeFunction(func, AM);
currentEffects[func] = newEffect;
result->setFunctionSideEffect(func, newEffect);
}
// 检查是否收敛
converged = hasConverged(previousEffects, currentEffects);
iterations++;
}
if (iterations >= maxIterations) {
std::cerr << "Warning: SideEffect analysis did not converge for SCC after " << maxIterations << " iterations"
<< std::endl;
}
}
bool SysYSideEffectAnalysisPass::hasConverged(const std::unordered_map<Function *, SideEffectInfo> &oldEffects,
const std::unordered_map<Function *, SideEffectInfo> &newEffects) const {
for (const auto &pair : oldEffects) {
Function *func = pair.first;
const SideEffectInfo &oldEffect = pair.second;
auto it = newEffects.find(func);
if (it == newEffects.end()) {
return false; // 函数不存在于新结果中
}
const SideEffectInfo &newEffect = it->second;
// 比较关键属性是否相同
if (oldEffect.type != newEffect.type || oldEffect.mayModifyGlobal != newEffect.mayModifyGlobal ||
oldEffect.mayModifyMemory != newEffect.mayModifyMemory ||
oldEffect.mayCallFunction != newEffect.mayCallFunction || oldEffect.isPure != newEffect.isPure) {
return false;
}
}
return true;
}
SideEffectInfo SysYSideEffectAnalysisPass::analyzeInstruction(Instruction *inst, Function *currentFunc,
AnalysisManager &AM) {
SideEffectInfo info;
// 根据指令类型进行分析
if (inst->isCall()) {
return analyzeCallInstruction(static_cast<CallInst *>(inst), currentFunc, AM);
} else if (inst->isStore()) {
return analyzeStoreInstruction(static_cast<StoreInst *>(inst), currentFunc, AM);
} else if (inst->isMemset()) {
return analyzeMemsetInstruction(static_cast<MemsetInst *>(inst), currentFunc, AM);
} else if (inst->isBranch() || inst->isReturn()) {
// 控制流指令无副作用,但必须保留
info.type = SideEffectType::NO_SIDE_EFFECT;
info.isPure = true;
} else {
// 其他指令(算术、逻辑、比较等)通常无副作用
info.type = SideEffectType::NO_SIDE_EFFECT;
info.isPure = true;
}
return info;
}
SideEffectInfo SysYSideEffectAnalysisPass::analyzeCallInstruction(CallInst *call, Function *currentFunc,
AnalysisManager &AM) {
SideEffectInfo info;
// 获取被调用的函数
Function *calledFunc = call->getCallee();
if (!calledFunc) {
// 间接调用,保守处理
info.type = SideEffectType::UNKNOWN;
info.mayModifyGlobal = true;
info.mayModifyMemory = true;
info.mayCallFunction = true;
info.isPure = false;
return info;
}
std::string funcName = calledFunc->getName();
// 检查是否为已知的标准库函数
const SideEffectInfo *knownInfo = result->getKnownFunctionSideEffect(funcName);
if (knownInfo) {
return *knownInfo;
}
// 利用调用图分析结果进行精确分析
if (callGraphAnalysis) {
// 检查被调用函数是否已分析过
const SideEffectInfo &funcEffect = result->getFunctionSideEffect(calledFunc);
if (funcEffect.type != SideEffectType::NO_SIDE_EFFECT || !funcEffect.isPure) {
return funcEffect;
}
// 检查递归调用
if (callGraphAnalysis->isRecursive(calledFunc)) {
// 递归函数保守处理(在不动点算法中会精确分析)
info.type = SideEffectType::FUNCTION_CALL;
info.mayModifyGlobal = true;
info.mayModifyMemory = true;
info.mayCallFunction = true;
info.isPure = false;
return info;
}
}
// 对于未分析的用户函数,保守处理
info.type = SideEffectType::FUNCTION_CALL;
info.mayModifyGlobal = true;
info.mayModifyMemory = true;
info.mayCallFunction = true;
info.isPure = false;
return info;
}
SideEffectInfo SysYSideEffectAnalysisPass::analyzeStoreInstruction(StoreInst *store, Function *currentFunc,
AnalysisManager &AM) {
SideEffectInfo info;
info.type = SideEffectType::MEMORY_WRITE;
info.mayModifyMemory = true;
info.isPure = false;
// 获取函数的别名分析结果
AliasAnalysisResult *aliasAnalysis = AM.getAnalysisResult<AliasAnalysisResult, SysYAliasAnalysisPass>(currentFunc);
if (aliasAnalysis) {
Value *storePtr = store->getPointer();
// 如果存储到全局变量或可能别名的位置,则可能修改全局状态
if (!aliasAnalysis->isLocalArray(storePtr)) {
info.mayModifyGlobal = true;
}
} else {
// 没有别名分析结果,保守处理
info.mayModifyGlobal = true;
}
return info;
}
SideEffectInfo SysYSideEffectAnalysisPass::analyzeMemsetInstruction(MemsetInst *memset, Function *currentFunc,
AnalysisManager &AM) {
SideEffectInfo info;
info.type = SideEffectType::MEMORY_WRITE;
info.mayModifyMemory = true;
info.isPure = false;
// 获取函数的别名分析结果
AliasAnalysisResult *aliasAnalysis = AM.getAnalysisResult<AliasAnalysisResult, SysYAliasAnalysisPass>(currentFunc);
if (aliasAnalysis) {
Value *memsetPtr = memset->getPointer();
// 如果memset操作全局变量或可能别名的位置则可能修改全局状态
if (!aliasAnalysis->isLocalArray(memsetPtr)) {
info.mayModifyGlobal = true;
}
} else {
// 没有别名分析结果,保守处理
info.mayModifyGlobal = true;
}
return info;
}
} // namespace sysy

View File

@@ -1,9 +1,9 @@
#include "DCE.h" // 包含DCE遍的头文件
#include "IR.h" // 包含IR相关的定义
#include "SysYIROptUtils.h" // 包含SysY IR优化工具类的定义
#include <cassert> // 用于断言
#include <iostream> // 用于调试输出
#include <set> // 包含set虽然DCEContext内部用unordered_set但这里保留
#include "DCE.h"
#include "SysYIROptUtils.h"
#include "SideEffectAnalysis.h"
#include <cassert>
#include <iostream>
#include <set>
namespace sysy {
@@ -17,10 +17,26 @@ void *DCE::ID = (void *)&DCE::ID;
// DCEContext 的 run 方法实现
void DCEContext::run(Function *func, AnalysisManager *AM, bool &changed) {
// 获取别名分析结果
if (AM) {
aliasAnalysis = AM->getAnalysisResult<AliasAnalysisResult, SysYAliasAnalysisPass>(func);
// 获取副作用分析结果Module级别
sideEffectAnalysis = AM->getAnalysisResult<SideEffectAnalysisResult, SysYSideEffectAnalysisPass>();
if (DEBUG) {
if (aliasAnalysis) {
std::cout << "DCE: Using alias analysis results" << std::endl;
}
if (sideEffectAnalysis) {
std::cout << "DCE: Using side effect analysis results" << std::endl;
}
}
}
// 清空活跃指令集合,确保每次运行都是新的状态
alive_insts.clear();
// 第一次遍历:扫描所有指令,识别天然活跃的指令并将其及其依赖标记为活跃
// 第一次遍历:扫描所有指令,识别"天然活跃"的指令并将其及其依赖标记为活跃
// 使用 func->getBasicBlocks() 获取基本块列表,保留用户风格
auto basicBlocks = func->getBasicBlocks();
for (auto &basicBlock : basicBlocks) {
@@ -51,7 +67,7 @@ void DCEContext::run(Function *func, AnalysisManager *AM, bool &changed) {
// 如果指令不在活跃集合中,则删除它。
// 分支和返回指令由 isAlive 处理,并会被保留。
if (alive_insts.count(currentInst) == 0) {
instIter = SysYIROptUtils::usedelete(instIter); // 删除后返回下一个迭代器
instIter = SysYIROptUtils::usedelete(instIter); // 删除后返回下一个迭代器
changed = true; // 标记 IR 已被修改
} else {
++instIter; // 指令活跃,移动到下一个
@@ -60,20 +76,58 @@ void DCEContext::run(Function *func, AnalysisManager *AM, bool &changed) {
}
}
// 判断指令是否是天然活跃的实现
// 判断指令是否是"天然活跃"的实现
// 只有具有副作用的指令(如存储、函数调用、原子操作)
// 和控制流指令(如分支、返回)是天然活跃的。
bool DCEContext::isAlive(Instruction *inst) {
// TODO: 后续程序并发考虑原子操作
// 其结果不被其他指令使用的指令(例如 StoreInst, BranchInst, ReturnInst
// dynamic_cast<ir::CallInst>(inst) 检查是否是函数调用指令,
// 函数调用通常有副作用。
// 终止指令 (BranchInst, ReturnInst) 必须是活跃的,因为它控制了程序的执行流程。
// 保留用户提供的 isAlive 逻辑
bool isBranchOrReturn = inst->isBranch() || inst->isReturn();
bool isCall = inst->isCall();
bool isStoreOrMemset = inst->isStore() || inst->isMemset();
return isBranchOrReturn || isCall || isStoreOrMemset;
// 终止指令 (BranchInst, ReturnInst) 必须是活跃的,因为它控制了程序的执行流程
if (inst->isBranch() || inst->isReturn()) {
return true;
}
// 使用副作用分析来判断指令是否有副作用
if (sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(inst)) {
return true;
}
// 特殊处理Store指令使用别名分析进行更精确的判断
if (inst->isStore()) {
auto* storeInst = static_cast<StoreInst*>(inst);
return mayHaveSideEffect(storeInst);
}
// 特殊处理Memset指令总是保留因为它修改内存
if (inst->isMemset()) {
return true;
}
// 函数调用指令:总是保留(可能有未知副作用)
if (inst->isCall()) {
return true;
}
// 其他指令算术、逻辑、Load等无副作用可以删除
return false;
}
// 检查Store指令是否可能有副作用通过别名分析
bool DCEContext::mayHaveSideEffect(StoreInst* store) {
if (!aliasAnalysis) {
// 没有别名分析结果时保守地认为所有store都有副作用
return true;
}
Value* storePtr = store->getPointer();
// 如果是对本地数组的存储且访问模式是常量,可能可以安全删除
if (aliasAnalysis->isLocalArray(storePtr)) {
// 检查是否有其他指令可能读取这个位置
// 这里需要更复杂的活性分析,暂时保守处理
return true; // 保守地保留所有本地数组的存储
}
// 对全局变量、函数参数等的存储总是有副作用
return true;
}
// 递归地将活跃指令及其依赖加入到 alive_insts 集合中
@@ -102,7 +156,6 @@ void DCEContext::addAlive(Instruction *inst) {
// DCE 遍的 runOnFunction 方法实现
bool DCE::runOnFunction(Function *func, AnalysisManager &AM) {
DCEContext ctx;
bool changed = false;
ctx.run(func, &AM, changed); // 运行 DCE 优化
@@ -120,7 +173,11 @@ bool DCE::runOnFunction(Function *func, AnalysisManager &AM) {
// 声明DCE遍的分析依赖和失效信息
void DCE::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
// DCE依赖特定的分析结果,它通过遍历和副作用判断来工作。
// DCE依赖别名分析来更精确地判断Store指令的副作用
analysisDependencies.insert(&SysYAliasAnalysisPass::ID);
// DCE依赖副作用分析来判断指令是否有副作用
analysisDependencies.insert(&SysYSideEffectAnalysisPass::ID);
// DCE会删除指令这会影响许多分析结果。
// 至少,它会影响活跃性分析、支配树、控制流图(如果删除导致基本块为空并被合并)。

View File

@@ -0,0 +1,916 @@
#include "InductionVariableElimination.h"
#include "LoopCharacteristics.h"
#include "Loop.h"
#include "Dom.h"
#include "SideEffectAnalysis.h"
#include "AliasAnalysis.h"
#include "SysYIROptUtils.h"
#include <iostream>
#include <algorithm>
// 使用全局调试开关
extern int DEBUG;
namespace sysy {
// 定义 Pass 的唯一 ID
void *InductionVariableElimination::ID = (void *)&InductionVariableElimination::ID;
bool InductionVariableElimination::runOnFunction(Function* F, AnalysisManager& AM) {
if (F->getBasicBlocks().empty()) {
return false; // 空函数
}
if (DEBUG) {
std::cout << "Running InductionVariableElimination on function: " << F->getName() << std::endl;
}
// 创建优化上下文并运行
InductionVariableEliminationContext context;
bool modified = context.run(F, AM);
if (DEBUG) {
std::cout << "InductionVariableElimination " << (modified ? "modified" : "did not modify")
<< " function: " << F->getName() << std::endl;
}
return modified;
}
void InductionVariableElimination::getAnalysisUsage(std::set<void*>& analysisDependencies,
std::set<void*>& analysisInvalidations) const {
// 依赖的分析
analysisDependencies.insert(&LoopAnalysisPass::ID);
analysisDependencies.insert(&LoopCharacteristicsPass::ID);
analysisDependencies.insert(&DominatorTreeAnalysisPass::ID);
analysisDependencies.insert(&SysYSideEffectAnalysisPass::ID);
analysisDependencies.insert(&SysYAliasAnalysisPass::ID);
// 会使失效的分析归纳变量消除会修改IR结构
analysisInvalidations.insert(&LoopCharacteristicsPass::ID);
// 注意:支配树分析通常不会因为归纳变量消除而失效,因为我们不改变控制流
}
// ========== InductionVariableEliminationContext 实现 ==========
bool InductionVariableEliminationContext::run(Function* F, AnalysisManager& AM) {
if (DEBUG) {
std::cout << " Starting induction variable elimination analysis..." << std::endl;
}
// 获取必要的分析结果
loopAnalysis = AM.getAnalysisResult<LoopAnalysisResult, LoopAnalysisPass>(F);
if (!loopAnalysis || !loopAnalysis->hasLoops()) {
if (DEBUG) {
std::cout << " No loops found, skipping induction variable elimination" << std::endl;
}
return false;
}
loopCharacteristics = AM.getAnalysisResult<LoopCharacteristicsResult, LoopCharacteristicsPass>(F);
if (!loopCharacteristics) {
if (DEBUG) {
std::cout << " LoopCharacteristics analysis not available" << std::endl;
}
return false;
}
dominatorTree = AM.getAnalysisResult<DominatorTree, DominatorTreeAnalysisPass>(F);
if (!dominatorTree) {
if (DEBUG) {
std::cout << " DominatorTree analysis not available" << std::endl;
}
return false;
}
sideEffectAnalysis = AM.getAnalysisResult<SideEffectAnalysisResult, SysYSideEffectAnalysisPass>();
if (!sideEffectAnalysis) {
if (DEBUG) {
std::cout << " SideEffectAnalysis not available, using conservative approach" << std::endl;
}
// 可以继续执行,但会使用更保守的策略
} else {
if (DEBUG) {
std::cout << " Using SideEffectAnalysis for safety checks" << std::endl;
}
}
aliasAnalysis = AM.getAnalysisResult<AliasAnalysisResult, SysYAliasAnalysisPass>(F);
if (!aliasAnalysis) {
if (DEBUG) {
std::cout << " AliasAnalysis not available, using conservative approach" << std::endl;
}
// 可以继续执行,但会使用更保守的策略
} else {
if (DEBUG) {
std::cout << " Using AliasAnalysis for memory safety checks" << std::endl;
}
}
// 执行三个阶段的优化
// 阶段1识别死归纳变量
identifyDeadInductionVariables(F);
if (deadIVs.empty()) {
if (DEBUG) {
std::cout << " No dead induction variables found" << std::endl;
}
return false;
}
if (DEBUG) {
std::cout << " Found " << deadIVs.size() << " potentially dead induction variables" << std::endl;
}
// 阶段2分析安全性
analyzeSafetyForElimination();
// 阶段3执行消除
bool modified = performInductionVariableElimination();
if (DEBUG) {
printDebugInfo();
}
return modified;
}
void InductionVariableEliminationContext::identifyDeadInductionVariables(Function* F) {
if (DEBUG) {
std::cout << " === Phase 1: Identifying Dead Induction Variables ===" << std::endl;
}
// 遍历所有循环
for (const auto& loop_ptr : loopAnalysis->getAllLoops()) {
Loop* loop = loop_ptr.get();
if (DEBUG) {
std::cout << " Analyzing loop: " << loop->getName() << std::endl;
}
// 获取循环特征
const LoopCharacteristics* characteristics = loopCharacteristics->getCharacteristics(loop);
if (!characteristics) {
if (DEBUG) {
std::cout << " No characteristics available for loop" << std::endl;
}
continue;
}
if (characteristics->InductionVars.empty()) {
if (DEBUG) {
std::cout << " No induction variables found in loop" << std::endl;
}
continue;
}
// 检查每个归纳变量是否为死归纳变量
for (const auto& iv : characteristics->InductionVars) {
auto deadIV = isDeadInductionVariable(iv.get(), loop);
if (deadIV) {
if (DEBUG) {
std::cout << " Found potential dead IV: %" << deadIV->phiInst->getName() << std::endl;
}
// 添加到候选项列表
loopToDeadIVs[loop].push_back(deadIV.get());
deadIVs.push_back(std::move(deadIV));
}
}
}
if (DEBUG) {
std::cout << " === End Phase 1: Found " << deadIVs.size() << " candidates ===" << std::endl;
}
}
std::unique_ptr<DeadInductionVariable>
InductionVariableEliminationContext::isDeadInductionVariable(const InductionVarInfo* iv, Loop* loop) {
// 获取 phi 指令
auto* phiInst = dynamic_cast<PhiInst*>(iv->div);
if (!phiInst) {
return nullptr; // 不是 phi 指令
}
// 新的逻辑递归分析整个use-def链判断是否有真实的使用
if (!isPhiInstructionDeadRecursively(phiInst, loop)) {
return nullptr; // 有真实的使用,不能删除
}
// 创建死归纳变量信息
auto deadIV = std::make_unique<DeadInductionVariable>(phiInst, loop);
deadIV->relatedInsts = collectRelatedInstructions(phiInst, loop);
return deadIV;
}
// 递归分析phi指令及其使用链是否都是死代码
bool InductionVariableEliminationContext::isPhiInstructionDeadRecursively(PhiInst* phiInst, Loop* loop) {
if (DEBUG) {
std::cout << " 递归分析归纳变量 " << phiInst->getName() << " 的完整使用链" << std::endl;
}
// 使用访问集合避免无限递归
std::set<Instruction*> visitedInstructions;
std::set<Instruction*> currentPath; // 用于检测循环依赖
// 核心逻辑:递归分析使用链,寻找任何"逃逸点"
return isInstructionUseChainDeadRecursively(phiInst, loop, visitedInstructions, currentPath);
}
// 递归分析指令的使用链是否都是死代码
bool InductionVariableEliminationContext::isInstructionUseChainDeadRecursively(
Instruction* inst, Loop* loop,
std::set<Instruction*>& visited,
std::set<Instruction*>& currentPath) {
if (DEBUG && visited.size() < 10) { // 限制debug输出
std::cout << " 分析指令 " << inst->getName() << " (" << inst->getKindString() << ")" << std::endl;
}
// 避免无限递归
if (currentPath.count(inst) > 0) {
// 发现循环依赖,这在归纳变量中是正常的,继续分析其他路径
if (DEBUG && visited.size() < 10) {
std::cout << " 发现循环依赖,继续分析其他路径" << std::endl;
}
return true; // 循环依赖本身不是逃逸点
}
if (visited.count(inst) > 0) {
// 已经分析过这个指令
return true; // 假设之前的分析是正确的
}
visited.insert(inst);
currentPath.insert(inst);
// 1. 检查是否有副作用(逃逸点)
if (sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(inst)) {
if (DEBUG && visited.size() < 10) {
std::cout << " 指令有副作用,是逃逸点" << std::endl;
}
currentPath.erase(inst);
return false; // 有副作用的指令是逃逸点
}
// 1.5. 特殊检查:控制流指令永远不是死代码
auto instKind = inst->getKind();
if (instKind == Instruction::Kind::kCondBr ||
instKind == Instruction::Kind::kBr ||
instKind == Instruction::Kind::kReturn) {
if (DEBUG && visited.size() < 10) {
std::cout << " 控制流指令,是逃逸点" << std::endl;
}
currentPath.erase(inst);
return false; // 控制流指令是逃逸点
}
// 2. 检查指令的所有使用
bool allUsesAreDead = true;
for (auto use : inst->getUses()) {
auto user = use->getUser();
auto* userInst = dynamic_cast<Instruction*>(user);
if (!userInst) {
// 被非指令使用(如函数返回值),是逃逸点
if (DEBUG && visited.size() < 10) {
std::cout << " 被非指令使用,是逃逸点" << std::endl;
}
allUsesAreDead = false;
break;
}
// 检查使用是否在循环外(逃逸点)
if (!loop->contains(userInst->getParent())) {
if (DEBUG && visited.size() < 10) {
std::cout << " 在循环外被 " << userInst->getName() << " 使用,是逃逸点" << std::endl;
}
allUsesAreDead = false;
break;
}
// 特殊检查:如果使用者是循环的退出条件,需要进一步分析
// 对于用于退出条件的归纳变量,需要更谨慎的处理
if (isUsedInLoopExitCondition(userInst, loop)) {
// 修复逻辑:用于循环退出条件的归纳变量通常不应该被消除
// 除非整个循环都可以被证明是完全无用的(这需要更复杂的分析)
if (DEBUG && visited.size() < 10) {
std::cout << " 被用于循环退出条件,是逃逸点(避免破坏循环语义)" << std::endl;
}
allUsesAreDead = false;
break;
}
// 递归分析使用者的使用链
if (!isInstructionUseChainDeadRecursively(userInst, loop, visited, currentPath)) {
allUsesAreDead = false;
break; // 找到逃逸点,不需要继续分析
}
}
currentPath.erase(inst);
if (allUsesAreDead && DEBUG && visited.size() < 10) {
std::cout << " 指令 " << inst->getName() << " 的所有使用都是死代码" << std::endl;
}
return allUsesAreDead;
}
// 检查循环是否有副作用
bool InductionVariableEliminationContext::loopHasSideEffects(Loop* loop) {
// 遍历循环中的所有指令,检查是否有副作用
for (BasicBlock* bb : loop->getBlocks()) {
for (auto& inst : bb->getInstructions()) {
Instruction* instPtr = inst.get();
// 使用副作用分析(如果可用)
if (sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(instPtr)) {
if (DEBUG) {
std::cout << " 循环中发现有副作用的指令: " << instPtr->getName() << std::endl;
}
return true;
}
// 如果没有副作用分析,使用保守的判断
if (!sideEffectAnalysis) {
auto kind = instPtr->getKind();
// 这些指令通常有副作用
if (kind == Instruction::Kind::kCall ||
kind == Instruction::Kind::kStore ||
kind == Instruction::Kind::kReturn) {
if (DEBUG) {
std::cout << " 循环中发现潜在有副作用的指令: " << instPtr->getName() << std::endl;
}
return true;
}
}
}
}
// 重要修复:检查是否为嵌套循环的外层循环
// 如果当前循环包含其他循环,那么它有潜在的副作用
for (const auto& loop_ptr : loopAnalysis->getAllLoops()) {
Loop* otherLoop = loop_ptr.get();
if(loopAnalysis->getLowestCommonAncestor(otherLoop, loop) == loop) {
if (DEBUG) {
std::cout << " 循环 " << loop->getName() << " 是其他循环的外层循环,视为有副作用" << std::endl;
}
return true; // 外层循环被视为有副作用
}
// if (otherLoop != loop && loop->contains(otherLoop->getHeader())) {
// if (DEBUG) {
// std::cout << " 循环 " << loop->getName() << " 包含子循环 " << otherLoop->getName() << ",视为有副作用" << std::endl;
// }
// return true; // 包含子循环的外层循环被视为有副作用
// }
}
if (DEBUG) {
std::cout << " 循环 " << loop->getName() << " 无副作用" << std::endl;
}
return false; // 循环无副作用
}
// 检查指令是否被用于循环退出条件
bool InductionVariableEliminationContext::isUsedInLoopExitCondition(Instruction* inst, Loop* loop) {
// 检查指令是否被循环的退出条件使用
for (BasicBlock* exitingBB : loop->getExitingBlocks()) {
auto terminatorIt = exitingBB->terminator();
if (terminatorIt != exitingBB->end()) {
Instruction* terminator = terminatorIt->get();
if (terminator) {
// 检查终结指令的操作数
for (size_t i = 0; i < terminator->getNumOperands(); ++i) {
if (terminator->getOperand(i) == inst) {
if (DEBUG) {
std::cout << " 指令 " << inst->getName() << " 用于循环退出条件" << std::endl;
}
return true;
}
}
// 对于条件分支,还需要检查条件指令的操作数
if (terminator->getKind() == Instruction::Kind::kCondBr) {
auto* condBr = dynamic_cast<CondBrInst*>(terminator);
if (condBr) {
Value* condition = condBr->getCondition();
if (condition == inst) {
if (DEBUG) {
std::cout << " 指令 " << inst->getName() << " 是循环条件" << std::endl;
}
return true;
}
// 递归检查条件指令的操作数(比如比较指令)
auto* condInst = dynamic_cast<Instruction*>(condition);
if (condInst) {
for (size_t i = 0; i < condInst->getNumOperands(); ++i) {
if (condInst->getOperand(i) == inst) {
if (DEBUG) {
std::cout << " 指令 " << inst->getName() << " 用于循环条件的操作数" << std::endl;
}
return true;
}
}
}
}
}
}
}
}
return false;
}
// 检查指令的结果是否未被有效使用
bool InductionVariableEliminationContext::isInstructionResultUnused(Instruction* inst, Loop* loop) {
// 检查指令的所有使用
if (inst->getUses().empty()) {
return true; // 没有使用,肯定是未使用
}
for (auto use : inst->getUses()) {
auto user = use->getUser();
auto* userInst = dynamic_cast<Instruction*>(user);
if (!userInst) {
return false; // 被非指令使用,认为是有效使用
}
// 如果在循环外被使用,认为是有效使用
if (!loop->contains(userInst->getParent())) {
return false;
}
// 递归检查使用这个结果的指令是否也是死代码
// 为了避免无限递归,限制递归深度
if (!isInstructionEffectivelyDead(userInst, loop, 3)) {
return false; // 存在有效使用
}
}
return true; // 所有使用都是无效的
}
// 检查store指令是否存储到死地址利用别名分析
bool InductionVariableEliminationContext::isStoreToDeadLocation(StoreInst* store, Loop* loop) {
if (!aliasAnalysis) {
return false; // 没有别名分析保守返回false
}
Value* storePtr = store->getPointer();
// 检查是否存储到局部临时变量且该变量在循环外不被读取
const MemoryLocation* memLoc = aliasAnalysis->getMemoryLocation(storePtr);
if (!memLoc) {
return false; // 无法确定内存位置
}
// 如果是局部数组且只在循环内被访问
if (memLoc->isLocalArray) {
// 检查该内存位置是否在循环外被读取
for (auto* accessInst : memLoc->accessInsts) {
if (accessInst->getKind() == Instruction::Kind::kLoad) {
if (!loop->contains(accessInst->getParent())) {
return false; // 在循环外被读取,不是死存储
}
}
}
if (DEBUG) {
std::cout << " 存储到局部数组且仅在循环内访问" << std::endl;
}
return true; // 存储到仅循环内访问的局部数组
}
return false;
}
// 检查指令是否有效死代码(带递归深度限制)
bool InductionVariableEliminationContext::isInstructionEffectivelyDead(Instruction* inst, Loop* loop, int maxDepth) {
if (maxDepth <= 0) {
return false; // 达到递归深度限制保守返回false
}
// 利用副作用分析
if (sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(inst)) {
return false; // 有副作用的指令不是死代码
}
// 检查特殊指令类型
switch (inst->getKind()) {
case Instruction::Kind::kStore:
// Store指令可能是死存储
return isStoreToDeadLocation(dynamic_cast<StoreInst*>(inst), loop);
case Instruction::Kind::kCall:
// 函数调用通常有副作用
if (sideEffectAnalysis) {
return !sideEffectAnalysis->hasSideEffect(inst);
}
return false; // 保守地认为函数调用有效果
case Instruction::Kind::kReturn:
case Instruction::Kind::kBr:
case Instruction::Kind::kCondBr:
// 控制流指令不是死代码
return false;
default:
// 其他指令检查其使用是否有效
break;
}
// 检查指令的使用
if (inst->getUses().empty()) {
return true; // 没有使用的纯指令是死代码
}
// 递归检查所有使用
for (auto use : inst->getUses()) {
auto user = use->getUser();
auto* userInst = dynamic_cast<Instruction*>(user);
if (!userInst) {
return false; // 被非指令使用
}
if (!loop->contains(userInst->getParent())) {
return false; // 在循环外被使用
}
// 递归检查使用者
if (!isInstructionEffectivelyDead(userInst, loop, maxDepth - 1)) {
return false; // 存在有效使用
}
}
return true; // 所有使用都是死代码
}
// 原有的函数保持兼容,但现在使用增强的死代码分析
bool InductionVariableEliminationContext::isInstructionDeadOrInternalOnly(Instruction* inst, Loop* loop) {
return isInstructionEffectivelyDead(inst, loop, 5);
}
// 检查store指令是否有后续的load操作
bool InductionVariableEliminationContext::hasSubsequentLoad(StoreInst* store, Loop* loop) {
if (!aliasAnalysis) {
// 没有别名分析,保守地假设有后续读取
return true;
}
Value* storePtr = store->getPointer();
const MemoryLocation* storeLoc = aliasAnalysis->getMemoryLocation(storePtr);
if (!storeLoc) {
// 无法确定内存位置,保守处理
return true;
}
// 在循环中和循环后查找对同一位置的load操作
std::vector<BasicBlock*> blocksToCheck;
// 添加循环内的所有基本块
for (auto* bb : loop->getBlocks()) {
blocksToCheck.push_back(bb);
}
// 添加循环的退出块
auto exitBlocks = loop->getExitBlocks();
for (auto* exitBB : exitBlocks) {
blocksToCheck.push_back(exitBB);
}
// 搜索load操作
for (auto* bb : blocksToCheck) {
for (auto& inst : bb->getInstructions()) {
if (inst->getKind() == Instruction::Kind::kLoad) {
LoadInst* loadInst = static_cast<LoadInst*>(inst.get());
Value* loadPtr = loadInst->getPointer();
const MemoryLocation* loadLoc = aliasAnalysis->getMemoryLocation(loadPtr);
if (loadLoc && aliasAnalysis->queryAlias(storePtr, loadPtr) != AliasType::NO_ALIAS) {
// 找到可能读取同一位置的load操作
if (DEBUG) {
std::cout << " 找到后续load操作: " << loadInst->getName() << std::endl;
}
return true;
}
}
}
}
// 检查是否通过函数调用间接访问
for (auto* bb : blocksToCheck) {
for (auto& inst : bb->getInstructions()) {
if (inst->getKind() == Instruction::Kind::kCall) {
CallInst* callInst = static_cast<CallInst*>(inst.get());
if (callInst && sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(callInst)) {
// 函数调用可能间接读取内存
if (DEBUG) {
std::cout << " 函数调用可能读取内存: " << callInst->getName() << std::endl;
}
return true;
}
}
}
}
if (DEBUG) {
std::cout << " 未找到后续load操作" << std::endl;
}
return false; // 没有找到后续读取
}
// 检查指令是否在循环外有使用
bool InductionVariableEliminationContext::hasUsageOutsideLoop(Instruction* inst, Loop* loop) {
for (auto use : inst->getUses()) {
auto user = use->getUser();
auto* userInst = dynamic_cast<Instruction*>(user);
if (!userInst) {
// 被非指令使用,可能在循环外
return true;
}
if (!loop->contains(userInst->getParent())) {
// 在循环外被使用
if (DEBUG) {
std::cout << " 指令 " << inst->getName() << " 在循环外被 "
<< userInst->getName() << " 使用" << std::endl;
}
return true;
}
}
return false; // 没有循环外使用
}
// 检查store指令是否在循环外有后续的load操作
bool InductionVariableEliminationContext::hasSubsequentLoadOutsideLoop(StoreInst* store, Loop* loop) {
if (!aliasAnalysis) {
// 没有别名分析,保守地假设有后续读取
return true;
}
Value* storePtr = store->getPointer();
// 检查循环的退出块及其后继
auto exitBlocks = loop->getExitBlocks();
std::set<BasicBlock*> visitedBlocks;
for (auto* exitBB : exitBlocks) {
if (hasLoadInSubtree(exitBB, storePtr, visitedBlocks)) {
if (DEBUG) {
std::cout << " 找到循环外的后续load操作" << std::endl;
}
return true;
}
}
return false; // 没有找到循环外的后续读取
}
// 递归检查基本块子树中是否有对指定位置的load操作
bool InductionVariableEliminationContext::hasLoadInSubtree(BasicBlock* bb, Value* ptr, std::set<BasicBlock*>& visited) {
if (visited.count(bb) > 0) {
return false; // 已经访问过,避免无限循环
}
visited.insert(bb);
// 检查当前基本块中的指令
for (auto& inst : bb->getInstructions()) {
if (inst->getKind() == Instruction::Kind::kLoad) {
LoadInst* loadInst = static_cast<LoadInst*>(inst.get());
if (aliasAnalysis && aliasAnalysis->queryAlias(ptr, loadInst->getPointer()) != AliasType::NO_ALIAS) {
return true; // 找到了对相同或别名位置的load
}
} else if (inst->getKind() == Instruction::Kind::kCall) {
// 函数调用可能间接读取内存
CallInst* callInst = static_cast<CallInst*>(inst.get());
if (sideEffectAnalysis && sideEffectAnalysis->hasSideEffect(callInst)) {
return true; // 保守地认为函数调用可能读取内存
}
}
}
// 递归检查后继基本块(限制深度以避免过度搜索)
static int searchDepth = 0;
if (searchDepth < 10) { // 限制搜索深度
searchDepth++;
for (auto* succ : bb->getSuccessors()) {
if (hasLoadInSubtree(succ, ptr, visited)) {
searchDepth--;
return true;
}
}
searchDepth--;
}
return false;
}
std::vector<Instruction*> InductionVariableEliminationContext::collectRelatedInstructions(
PhiInst* phiInst, Loop* loop) {
std::vector<Instruction*> relatedInsts;
// 收集所有与该归纳变量相关的指令
for (auto use : phiInst->getUses()) {
auto user = use->getUser();
auto* userInst = dynamic_cast<Instruction*>(user);
if (userInst && loop->contains(userInst->getParent())) {
relatedInsts.push_back(userInst);
}
}
return relatedInsts;
}
void InductionVariableEliminationContext::analyzeSafetyForElimination() {
if (DEBUG) {
std::cout << " === Phase 2: Analyzing Safety for Elimination ===" << std::endl;
}
// 为每个死归纳变量检查消除的安全性
for (auto& deadIV : deadIVs) {
bool isSafe = isSafeToEliminate(deadIV.get());
deadIV->canEliminate = isSafe;
if (DEBUG) {
std::cout << " Dead IV " << deadIV->phiInst->getName()
<< ": " << (isSafe ? "SAFE" : "UNSAFE") << " to eliminate" << std::endl;
}
}
if (DEBUG) {
size_t safeCount = 0;
for (const auto& deadIV : deadIVs) {
if (deadIV->canEliminate) safeCount++;
}
std::cout << " === End Phase 2: " << safeCount << " of " << deadIVs.size()
<< " variables are safe to eliminate ===" << std::endl;
}
}
bool InductionVariableEliminationContext::isSafeToEliminate(const DeadInductionVariable* deadIV) {
// 1. 确保归纳变量在循环头
if (deadIV->phiInst->getParent() != deadIV->containingLoop->getHeader()) {
if (DEBUG) {
std::cout << " Unsafe: phi not in loop header" << std::endl;
}
return false;
}
// 2. 确保相关指令都在循环内
for (auto* inst : deadIV->relatedInsts) {
if (!deadIV->containingLoop->contains(inst->getParent())) {
if (DEBUG) {
std::cout << " Unsafe: related instruction outside loop" << std::endl;
}
return false;
}
}
// 3. 确保没有副作用
for (auto* inst : deadIV->relatedInsts) {
if (sideEffectAnalysis) {
// 使用副作用分析进行精确检查
if (sideEffectAnalysis->hasSideEffect(inst)) {
if (DEBUG) {
std::cout << " Unsafe: related instruction " << inst->getName()
<< " has side effects" << std::endl;
}
return false;
}
} else {
// 没有副作用分析时使用保守策略:只允许基本算术运算
auto kind = inst->getKind();
if (kind != Instruction::Kind::kAdd &&
kind != Instruction::Kind::kSub &&
kind != Instruction::Kind::kMul) {
if (DEBUG) {
std::cout << " Unsafe: related instruction may have side effects (conservative)" << std::endl;
}
return false;
}
}
}
// 4. 确保不影响循环的退出条件
for (BasicBlock* exitingBB : deadIV->containingLoop->getExitingBlocks()) {
auto terminatorIt = exitingBB->terminator();
if (terminatorIt != exitingBB->end()) {
Instruction* terminator = terminatorIt->get();
if (terminator) {
for (size_t i = 0; i < terminator->getNumOperands(); ++i) {
if (terminator->getOperand(i) == deadIV->phiInst) {
if (DEBUG) {
std::cout << " Unsafe: phi used in loop exit condition" << std::endl;
}
return false;
}
}
}
}
}
return true;
}
bool InductionVariableEliminationContext::performInductionVariableElimination() {
if (DEBUG) {
std::cout << " === Phase 3: Performing Induction Variable Elimination ===" << std::endl;
}
bool modified = false;
for (auto& deadIV : deadIVs) {
if (!deadIV->canEliminate) {
continue;
}
if (DEBUG) {
std::cout << " Eliminating dead IV: " << deadIV->phiInst->getName() << std::endl;
}
if (eliminateDeadInductionVariable(deadIV.get())) {
if (DEBUG) {
std::cout << " Successfully eliminated: " << deadIV->phiInst->getName() << std::endl;
}
modified = true;
} else {
if (DEBUG) {
std::cout << " Failed to eliminate: " << deadIV->phiInst->getName() << std::endl;
}
}
}
if (DEBUG) {
std::cout << " === End Phase 3: " << (modified ? "Eliminations performed" : "No eliminations") << " ===" << std::endl;
}
return modified;
}
bool InductionVariableEliminationContext::eliminateDeadInductionVariable(DeadInductionVariable* deadIV) {
// 1. 删除所有相关指令
for (auto* inst : deadIV->relatedInsts) {
auto* bb = inst->getParent();
auto it = bb->findInstIterator(inst);
if (it != bb->end()) {
SysYIROptUtils::usedelete(it);
// bb->getInstructions().erase(it);
if (DEBUG) {
std::cout << " Removed related instruction: " << inst->getName() << std::endl;
}
}
}
// 2. 删除 phi 指令
auto* bb = deadIV->phiInst->getParent();
auto it = bb->findInstIterator(deadIV->phiInst);
if (it != bb->end()) {
SysYIROptUtils::usedelete(it);
// bb->getInstructions().erase(it);
if (DEBUG) {
std::cout << " Removed phi instruction: " << deadIV->phiInst->getName() << std::endl;
}
return true;
}
return false;
}
void InductionVariableEliminationContext::printDebugInfo() {
if (!DEBUG) return;
std::cout << "\n=== Induction Variable Elimination Summary ===" << std::endl;
std::cout << "Total dead IVs found: " << deadIVs.size() << std::endl;
size_t eliminatedCount = 0;
for (auto& [loop, loopDeadIVs] : loopToDeadIVs) {
size_t loopEliminatedCount = 0;
for (auto* deadIV : loopDeadIVs) {
if (deadIV->canEliminate) {
loopEliminatedCount++;
eliminatedCount++;
}
}
if (loopEliminatedCount > 0) {
std::cout << "Loop " << loop->getName() << ": " << loopEliminatedCount
<< " of " << loopDeadIVs.size() << " IVs eliminated" << std::endl;
}
}
std::cout << "Total eliminated: " << eliminatedCount << " of " << deadIVs.size() << std::endl;
std::cout << "=============================================" << std::endl;
}
} // namespace sysy

View File

@@ -0,0 +1,112 @@
#include "LICM.h"
#include "IR.h"
extern int DEBUG;
namespace sysy {
void *LICM::ID = (void *)&LICM::ID;
bool LICMContext::run() { return hoistInstructions(); }
bool LICMContext::hoistInstructions() {
bool changed = false;
BasicBlock *preheader = loop->getPreHeader();
if (!preheader || !chars)
return false;
// 1. 先收集所有可外提指令
std::unordered_set<Instruction *> workSet(chars->invariantInsts.begin(), chars->invariantInsts.end());
// 2. 计算每个指令被依赖的次数(入度)
std::unordered_map<Instruction *, int> indegree;
for (auto *inst : workSet) {
indegree[inst] = 0;
}
for (auto *inst : workSet) {
for (size_t i = 0; i < inst->getNumOperands(); ++i) {
if (auto *dep = dynamic_cast<Instruction *>(inst->getOperand(i))) {
if (workSet.count(dep)) {
indegree[inst]++;
}
}
}
}
// 3. Kahn拓扑排序
std::vector<Instruction *> sorted;
std::queue<Instruction *> q;
for (auto &[inst, deg] : indegree) {
if (deg == 0)
q.push(inst);
}
while (!q.empty()) {
auto *inst = q.front();
q.pop();
sorted.push_back(inst);
for (size_t i = 0; i < inst->getNumOperands(); ++i) {
if (auto *dep = dynamic_cast<Instruction *>(inst->getOperand(i))) {
if (workSet.count(dep)) {
indegree[dep]--;
if (indegree[dep] == 0)
q.push(dep);
}
}
}
}
// 检查是否全部排序,若未全部排序,说明有环(理论上不会)
if (sorted.size() != workSet.size()) {
if (DEBUG)
std::cerr << "LICM: Topological sort failed, possible dependency cycle." << std::endl;
return false;
}
// 4. 按拓扑序外提
for (auto *inst : sorted) {
if (!inst)
continue;
BasicBlock *parent = inst->getParent();
if (parent && loop->contains(parent)) {
auto sourcePos = parent->findInstIterator(inst);
auto targetPos = preheader->terminator();
parent->moveInst(sourcePos, targetPos, preheader);
changed = true;
}
}
return changed;
}
// ---- LICM Pass Implementation ----
bool LICM::runOnFunction(Function *F, AnalysisManager &AM) {
auto *loopAnalysis = AM.getAnalysisResult<LoopAnalysisResult, LoopAnalysisPass>(F);
auto *loopCharsResult = AM.getAnalysisResult<LoopCharacteristicsResult, LoopCharacteristicsPass>(F);
if (!loopAnalysis || !loopCharsResult)
return false;
bool changed = false;
// 对每个函数内的所有循环做处理
for (const auto &loop_ptr : loopAnalysis->getAllLoops()) {
Loop *loop = loop_ptr.get();
if (DEBUG) {
std::cout << "LICM: Processing loop in function " << F->getName() << ": " << loop->getName() << std::endl;
}
const LoopCharacteristics *chars = loopCharsResult->getCharacteristics(loop);
if (!chars || !loop->getPreHeader())
continue; // 没有分析结果或没有前置块则跳过
LICMContext ctx(F, loop, builder, chars);
changed |= ctx.run();
}
return changed;
}
void LICM::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
analysisDependencies.insert(&LoopAnalysisPass::ID);
analysisDependencies.insert(&LoopCharacteristicsPass::ID);
analysisInvalidations.insert(&LoopCharacteristicsPass::ID);
analysisInvalidations.insert(&LivenessAnalysisPass::ID);
}
} // namespace sysy

View File

@@ -52,14 +52,16 @@ bool LargeArrayToGlobalPass::runOnModule(Module *M, AnalysisManager &AM) {
// Calculate the size of the allocated type
unsigned size = calculateTypeSize(allocatedType);
// Debug: print size information
std::cout << "LargeArrayToGlobalPass: Found alloca with size " << size
if(DEBUG){
// Debug: print size information
std::cout << "LargeArrayToGlobalPass: Found alloca with size " << size
<< " for type " << typeToString(allocatedType) << std::endl;
}
// Convert arrays of 1KB (1024 bytes) or larger to global variables
if (size >= 1024) {
std::cout << "LargeArrayToGlobalPass: Converting array of size " << size << " to global" << std::endl;
if(DEBUG)
std::cout << "LargeArrayToGlobalPass: Converting array of size " << size << " to global" << std::endl;
allocasToConvert.emplace_back(alloca, F);
}
}

View File

@@ -0,0 +1,528 @@
#include "LoopNormalization.h"
#include "Dom.h"
#include "Loop.h"
#include "SysYIROptUtils.h"
#include <iostream>
#include <algorithm>
#include <sstream>
// 使用全局调试开关
extern int DEBUG;
namespace sysy {
// 定义 Pass 的唯一 ID
void *LoopNormalizationPass::ID = (void *)&LoopNormalizationPass::ID;
bool LoopNormalizationPass::runOnFunction(Function *F, AnalysisManager &AM) {
if (F->getBasicBlocks().empty()) {
return false; // 空函数
}
if (DEBUG)
std::cout << "Running LoopNormalizationPass on function: " << F->getName() << std::endl;
// 获取并缓存所有需要的分析结果
loopAnalysis = AM.getAnalysisResult<LoopAnalysisResult, LoopAnalysisPass>(F);
if (!loopAnalysis || !loopAnalysis->hasLoops()) {
if (DEBUG)
std::cout << "No loops found in function " << F->getName() << ", skipping normalization" << std::endl;
return false; // 没有循环需要规范化
}
domTree = AM.getAnalysisResult<DominatorTree, DominatorTreeAnalysisPass>(F);
if (!domTree) {
std::cerr << "Error: DominatorTree not available for function " << F->getName() << std::endl;
return false;
}
// 重置统计信息
stats = NormalizationStats();
bool modified = false;
const auto& allLoops = loopAnalysis->getAllLoops();
stats.totalLoops = allLoops.size();
if (DEBUG) {
std::cout << "Found " << stats.totalLoops << " loops to analyze for normalization" << std::endl;
}
// 按循环深度从外到内处理,确保外层循环先规范化
std::vector<Loop*> sortedLoops;
for (const auto& loop_ptr : allLoops) {
sortedLoops.push_back(loop_ptr.get());
}
std::sort(sortedLoops.begin(), sortedLoops.end(), [](Loop* a, Loop* b) {
return a->getLoopDepth() < b->getLoopDepth(); // 按深度升序排列
});
// 逐个规范化循环
for (Loop* loop : sortedLoops) {
if (needsPreheader(loop)) {
stats.loopsNeedingPreheader++;
if (DEBUG) {
std::cout << " Loop " << loop->getName() << " needs preheader (depth="
<< loop->getLoopDepth() << ")" << std::endl;
}
if (normalizeLoop(loop)) {
modified = true;
stats.loopsNormalized++;
// 验证规范化结果
if (!validateNormalization(loop)) {
std::cerr << "Warning: Loop normalization validation failed for loop "
<< loop->getName() << std::endl;
}
}
} else {
if (DEBUG) {
auto* preheader = getExistingPreheader(loop);
if (preheader) {
std::cout << " Loop " << loop->getName() << " already has preheader: "
<< preheader->getName() << std::endl;
}
}
}
}
if (DEBUG && modified) {
printStats(F);
}
return modified;
}
bool LoopNormalizationPass::normalizeLoop(Loop* loop) {
if (DEBUG)
std::cout << " Normalizing loop: " << loop->getName() << std::endl;
// 创建前置块
BasicBlock* preheader = createPreheaderForLoop(loop);
if (!preheader) {
if (DEBUG)
std::cout << " Failed to create preheader for loop " << loop->getName() << std::endl;
return false;
}
stats.preheadersCreated++;
if (DEBUG) {
std::cout << " Successfully created preheader " << preheader->getName()
<< " for loop " << loop->getName() << std::endl;
}
return true;
}
BasicBlock* LoopNormalizationPass::createPreheaderForLoop(Loop* loop) {
BasicBlock* header = loop->getHeader();
if (!header) {
if (DEBUG)
std::cerr << " Error: Loop has no header block" << std::endl;
return nullptr;
}
// 获取循环外的前驱块
std::vector<BasicBlock*> externalPreds = getExternalPredecessors(loop);
if (externalPreds.empty()) {
if (DEBUG)
std::cout << " Loop " << loop->getName() << " has no external predecessors" << std::endl;
return nullptr;
}
if (DEBUG) {
std::cout << " Found " << externalPreds.size() << " external predecessors for loop "
<< loop->getName() << std::endl;
for (auto* pred : externalPreds) {
std::cout << " External pred: " << pred->getName() << std::endl;
}
}
// 生成前置块名称
std::string preheaderName = generatePreheaderName(loop);
// 创建新的前置块
Function* parentFunction = header->getParent();
BasicBlock* preheader = parentFunction->addBasicBlock(preheaderName, header);
if (!preheader) {
if (DEBUG)
std::cerr << " Error: Failed to create basic block " << preheaderName << std::endl;
return nullptr;
}
// 在前置块中创建跳转指令到循环头部
builder->setPosition(preheader, preheader->end());
UncondBrInst* br = builder->createUncondBrInst(header);
// 更新preheader的CFG关系
preheader->addSuccessor(header);
header->addPredecessor(preheader);
if(DEBUG) {
std::cout << " Created preheader " << preheader->getName()
<< " with unconditional branch to " << header->getName() << std::endl;
}
// 重定向外部前驱到新的前置块
redirectExternalPredecessors(loop, preheader, header, externalPreds);
// 更新PHI节点
updatePhiNodesForPreheader(header, preheader, externalPreds);
// 更新支配树关系
updateDominatorRelations(preheader, loop);
// 重要:更新循环对象的前置块信息
// 这样后续的优化遍可以通过 loop->getPreHeader() 获取到新创建的前置块
loop->setPreHeader(preheader);
if (DEBUG) {
std::cout << " Updated loop object: preheader set to " << preheader->getName() << std::endl;
}
return preheader;
}
bool LoopNormalizationPass::needsPreheader(Loop* loop) {
// 检查是否已有合适的前置块
if (getExistingPreheader(loop) != nullptr) {
return false;
}
// 检查是否有外部前驱(如果没有外部前驱,不需要前置块)
std::vector<BasicBlock*> externalPreds = getExternalPredecessors(loop);
if (externalPreds.empty()) {
return false;
}
// 基于结构性需求判断:
// 1. 如果有多个外部前驱,必须创建前置块来合并它们
// 2. 如果单个外部前驱不适合作为前置块,需要创建新的前置块
return (externalPreds.size() > 1) || !isSuitableAsPreheader(externalPreds[0], loop);
}
BasicBlock* LoopNormalizationPass::getExistingPreheader(Loop* loop) {
BasicBlock* header = loop->getHeader();
if (!header) return nullptr;
std::vector<BasicBlock*> externalPreds = getExternalPredecessors(loop);
// 如果只有一个外部前驱,且适合作为前置块,则返回它
if (externalPreds.size() == 1 && isSuitableAsPreheader(externalPreds[0], loop)) {
return externalPreds[0];
}
return nullptr;
}
void LoopNormalizationPass::updateDominatorRelations(BasicBlock* newBlock, Loop* loop) {
// 由于在getAnalysisUsage中声明了DominatorTree会失效
// PassManager会在本遍运行后自动将支配树结果标记为失效
// 后续需要支配树的Pass会触发重新计算所以这里无需手动更新
if (DEBUG) {
BasicBlock* header = loop->getHeader();
std::cout << " DominatorTree marked for invalidation - new preheader "
<< newBlock->getName() << " will dominate " << header->getName()
<< " after recomputation by PassManager" << std::endl;
}
}
void LoopNormalizationPass::redirectExternalPredecessors(Loop* loop, BasicBlock* preheader, BasicBlock* header,
const std::vector<BasicBlock*>& externalPreds) {
// std::vector<BasicBlock*> externalPreds = getExternalPredecessors(loop);
if (DEBUG) {
std::cout << " Redirecting " << externalPreds.size() << " external predecessors" << std::endl;
}
for (BasicBlock* pred : externalPreds) {
// 获取前驱块的终止指令
auto termIt = pred->terminator();
if (termIt == pred->end()) continue;
Instruction* terminator = termIt->get();
if (!terminator) continue;
// 更新跳转目标
if (auto* br = dynamic_cast<UncondBrInst*>(terminator)) {
// 无条件跳转
if (br->getBlock() == header) {
if(DEBUG){
std::cout << " Updating unconditional branch from " << br->getBlock()->getName()
<< " to " << preheader->getName() << std::endl;
}
// 需要更新操作数
br->setOperand(0, preheader);
// 更新CFG关系
header->removePredecessor(pred);
preheader->addPredecessor(pred);
pred->removeSuccessor(header);
pred->addSuccessor(preheader);
}
} else if (auto* condBr = dynamic_cast<CondBrInst*>(terminator)) {
// 条件跳转
bool updated = false;
if (condBr->getThenBlock() == header) {
condBr->setOperand(1, preheader); // 第1个操作数是then分支
updated = true;
}
if (condBr->getElseBlock() == header) {
condBr->setOperand(2, preheader); // 第2个操作数是else分支
updated = true;
}
if (updated) {
// 更新CFG关系
header->removePredecessor(pred);
preheader->addPredecessor(pred);
pred->removeSuccessor(header);
pred->addSuccessor(preheader);
if (DEBUG) {
std::cout << " Updated conditional branch from " << pred->getName()
<< " to " << preheader->getName() << std::endl;
}
}
}
}
}
std::string LoopNormalizationPass::generatePreheaderName(Loop* loop) {
std::ostringstream oss;
oss << loop->getName() << "_preheader";
return oss.str();
}
bool LoopNormalizationPass::validateNormalization(Loop* loop) {
BasicBlock* header = loop->getHeader();
if (!header) return false;
// 检查循环是否现在有唯一的外部前驱
std::vector<BasicBlock*> externalPreds = getExternalPredecessors(loop);
if (externalPreds.size() != 1) {
if (DEBUG)
std::cout << " Validation failed: Loop " << loop->getName()
<< " has " << externalPreds.size() << " external predecessors (expected 1)" << std::endl;
return false;
}
// 检查外部前驱是否适合作为前置块
BasicBlock* preheader = externalPreds[0];
if (!isSuitableAsPreheader(preheader, loop)) {
if (DEBUG)
std::cout << " Validation failed: External predecessor " << preheader->getName()
<< " is not suitable as preheader" << std::endl;
return false;
}
// 额外验证检查CFG连接性
if (!preheader->hasSuccessor(header)) {
if (DEBUG)
std::cout << " Validation failed: Preheader " << preheader->getName()
<< " is not connected to header " << header->getName() << std::endl;
return false;
}
if (!header->hasPredecessor(preheader)) {
if (DEBUG)
std::cout << " Validation failed: Header " << header->getName()
<< " does not have preheader " << preheader->getName() << " as predecessor" << std::endl;
return false;
}
if (DEBUG)
std::cout << " Validation passed for loop " << loop->getName() << std::endl;
return true;
}
std::vector<BasicBlock*> LoopNormalizationPass::getExternalPredecessors(Loop* loop) {
std::vector<BasicBlock*> externalPreds;
BasicBlock* header = loop->getHeader();
if (!header) return externalPreds;
for (BasicBlock* pred : header->getPredecessors()) {
if (!loop->contains(pred)) {
externalPreds.push_back(pred);
}
}
return externalPreds;
}
bool LoopNormalizationPass::isSuitableAsPreheader(BasicBlock* block, Loop* loop) {
if (!block) return false;
// 检查该块是否只有一个后继,且后继是循环头部
auto successors = block->getSuccessors();
if (successors.size() != 1) {
return false;
}
if (successors[0] != loop->getHeader()) {
return false;
}
// 检查该块是否不包含复杂的控制流
// 理想的前置块应该只包含简单的跳转指令
size_t instCount = 0;
for (const auto& inst : block->getInstructions()) {
instCount++;
// 如果指令过多,可能不适合作为前置块
if (instCount > 10) { // 阈值可调整
return false;
}
}
return true;
}
void LoopNormalizationPass::updatePhiNodesForPreheader(BasicBlock* header, BasicBlock* preheader,
const std::vector<BasicBlock*>& oldPreds) {
if (DEBUG) {
std::cout << " Updating PHI nodes in header " << header->getName()
<< " for new preheader " << preheader->getName() << std::endl;
}
std::vector<PhiInst*> phisToRemove; // 需要删除的PHI节点
for (auto& inst : header->getInstructions()) {
if (auto* phi = dynamic_cast<PhiInst*>(inst.get())) {
if (DEBUG) {
std::cout << " Processing PHI node: " << phi->getName() << std::endl;
}
// 收集来自外部前驱的值 - 需要保持原始的映射关系
std::map<BasicBlock*, Value*> externalValues;
for (BasicBlock* oldPred : oldPreds) {
Value* value = phi->getValfromBlk(oldPred);
if (value) {
externalValues[oldPred] = value;
}
}
// 处理PHI节点的更新
if (externalValues.size() > 1) {
// 多个外部前驱在前置块中创建新的PHI节点
builder->setPosition(preheader, preheader->getInstructions().begin());
std::vector<Value*> values;
std::vector<BasicBlock*> blocks;
for (auto& [block, value] : externalValues) {
values.push_back(value);
blocks.push_back(block);
}
PhiInst* newPhi = builder->createPhiInst(phi->getType(), values, blocks);
// 移除所有外部前驱的条目
for (BasicBlock* oldPred : oldPreds) {
phi->removeIncomingBlock(oldPred);
}
// 添加来自新前置块的条目
phi->addIncoming(newPhi, preheader);
} else if (externalValues.size() == 1) {
// 单个外部前驱:直接重新映射
Value* value = externalValues.begin()->second;
// 移除旧的外部前驱条目
for (BasicBlock* oldPred : oldPreds) {
phi->removeIncomingBlock(oldPred);
}
// 添加来自新前置块的条目
phi->addIncoming(value, preheader);
// 检查PHI节点是否只剩下一个条目只来自前置块
if (phi->getNumIncomingValues() == 1) {
if (DEBUG) {
std::cout << " PHI node " << phi->getName()
<< " now has only one incoming value, scheduling for removal" << std::endl;
}
// 用单一值替换所有使用
Value* singleValue = phi->getIncomingValue(0u);
phi->replaceAllUsesWith(singleValue);
phisToRemove.push_back(phi);
}
} else {
// 没有外部值的PHI节点检查是否需要更新
// 这种PHI节点只有循环内的边通常不需要修改
// 但我们仍然需要检查是否只有一个条目
if (phi->getNumIncomingValues() == 1) {
if (DEBUG) {
std::cout << " PHI node " << phi->getName()
<< " has only one incoming value (no external), scheduling for removal" << std::endl;
}
// 用单一值替换所有使用
Value* singleValue = phi->getIncomingValue(0u);
phi->replaceAllUsesWith(singleValue);
phisToRemove.push_back(phi);
}
}
if (DEBUG && std::find(phisToRemove.begin(), phisToRemove.end(), phi) == phisToRemove.end()) {
std::cout << " Updated PHI node with " << externalValues.size()
<< " external values, total incoming: " << phi->getNumIncomingValues() << std::endl;
}
}
}
// 删除标记为移除的PHI节点
for (PhiInst* phi : phisToRemove) {
if (DEBUG) {
std::cout << " Removing redundant PHI node: " << phi->getName() << std::endl;
}
SysYIROptUtils::usedelete(phi);
}
// 更新统计信息
stats.redundantPhisRemoved += phisToRemove.size();
if (DEBUG && !phisToRemove.empty()) {
std::cout << " Removed " << phisToRemove.size() << " redundant PHI nodes" << std::endl;
}
}
void LoopNormalizationPass::printStats(Function* F) {
std::cout << "\n--- Loop Normalization Statistics for Function: " << F->getName() << " ---" << std::endl;
std::cout << "Total loops analyzed: " << stats.totalLoops << std::endl;
std::cout << "Loops needing preheader: " << stats.loopsNeedingPreheader << std::endl;
std::cout << "Preheaders created: " << stats.preheadersCreated << std::endl;
std::cout << "Loops successfully normalized: " << stats.loopsNormalized << std::endl;
std::cout << "Redundant PHI nodes removed: " << stats.redundantPhisRemoved << std::endl;
if (stats.totalLoops > 0) {
double normalizationRate = (double)stats.loopsNormalized / stats.totalLoops * 100.0;
std::cout << "Normalization rate: " << normalizationRate << "%" << std::endl;
}
std::cout << "---------------------------------------------------------------" << std::endl;
}
void LoopNormalizationPass::getAnalysisUsage(std::set<void *> &analysisDependencies,
std::set<void *> &analysisInvalidations) const {
// LoopNormalization依赖的分析
analysisDependencies.insert(&LoopAnalysisPass::ID); // 循环结构分析
analysisDependencies.insert(&DominatorTreeAnalysisPass::ID); // 支配树分析
// LoopNormalization会修改CFG结构因此会使以下分析失效
analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID); // 支配树需要重新计算
// 注意:我们不让循环结构分析失效,原因如下:
// 1. 循环规范化只添加前置块,不改变循环的核心结构(头部、体、回边)
// 2. 我们会手动更新Loop对象的前置块信息通过loop->setPreHeader()
// 3. 让循环分析失效并重新计算的成本较高且不必要
// 4. 后续优化遍可以正确获取到更新后的前置块信息
//
// 如果未来有更复杂的循环结构修改,可能需要考虑让循环分析失效:
// analysisInvalidations.insert(&LoopAnalysisPass::ID);
}
} // namespace sysy

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,8 @@
#include "Mem2Reg.h" // 包含 Mem2Reg 遍的头文件
#include "Dom.h" // 包含支配树分析的头文件
#include "Liveness.h"
#include "AliasAnalysis.h" // 包含别名分析
#include "SideEffectAnalysis.h" // 包含副作用分析
#include "IR.h" // 包含 IR 相关的定义
#include "SysYIROptUtils.h"
#include <cassert> // 用于断言
@@ -420,8 +422,9 @@ void Mem2Reg::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<
// 因此,它会使许多分析结果失效。
analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID); // 支配树可能受影响
analysisInvalidations.insert(&LivenessAnalysisPass::ID); // 活跃性分析肯定失效
analysisInvalidations.insert(&SysYAliasAnalysisPass::ID); // 别名分析必须失效因为Mem2Reg改变了内存访问模式
analysisInvalidations.insert(&SysYSideEffectAnalysisPass::ID); // 副作用分析也可能失效
// analysisInvalidations.insert(&LoopInfoAnalysisPass::ID); // 循环信息可能失效
// analysisInvalidations.insert(&SideEffectInfoAnalysisPass::ID); // 副作用分析可能失效
// 其他所有依赖于数据流或 IR 结构的分析都可能失效。
}

View File

@@ -1,10 +1,12 @@
#include "SCCP.h"
#include "Dom.h"
#include "Liveness.h"
#include "SideEffectAnalysis.h"
#include <algorithm>
#include <cassert>
#include <cmath> // For std::fmod, std::fabs
#include <limits> // For std::numeric_limits
#include <set> // For std::set in isKnownPureFunction
namespace sysy {
@@ -263,6 +265,192 @@ SSAPValue SCCPContext::ComputeConstant(UnaryInst *unaryInst, SSAPValue operandVa
return SSAPValue(LatticeVal::Bottom);
}
// 辅助函数:检查是否为已知的纯函数
bool SCCPContext::isKnownPureFunction(const std::string &funcName) const {
// SysY中一些已知的纯函数不修改全局状态结果只依赖参数
static const std::set<std::string> knownPureFunctions = {
// 数学函数(如果有的话)
// "abs", "fabs", "sqrt", "sin", "cos"
// SysY标准中基本没有纯函数大多数都有I/O副作用
};
return knownPureFunctions.find(funcName) != knownPureFunctions.end();
}
// 辅助函数:计算纯函数的常量结果
SSAPValue SCCPContext::computePureFunctionResult(CallInst *call, const std::vector<SSAPValue> &argValues) {
Function *calledFunc = call->getCallee();
if (!calledFunc) {
return SSAPValue(LatticeVal::Bottom);
}
std::string funcName = calledFunc->getName();
// 目前SysY中没有标准的纯函数这里预留扩展空间
// 未来可以添加数学函数的常量折叠
/*
if (funcName == "abs" && argValues.size() == 1) {
if (argValues[0].constant_type == ValueType::Integer) {
int val = std::get<int>(argValues[0].constantVal);
return SSAPValue(std::abs(val));
}
}
*/
return SSAPValue(LatticeVal::Bottom);
}
// 辅助函数:查找存储到指定位置的常量值
SSAPValue SCCPContext::findStoredConstantValue(Value *ptr, BasicBlock *currentBB) {
if (!aliasAnalysis) {
if (DEBUG) {
std::cout << "SCCP: No alias analysis available" << std::endl;
}
return SSAPValue(LatticeVal::Bottom);
}
if (DEBUG) {
std::cout << "SCCP: Searching for stored constant value for ptr" << std::endl;
}
// 从当前块的指令列表末尾向前查找最近的Store
std::vector<Instruction*> instructions;
for (auto it = currentBB->begin(); it != currentBB->end(); ++it) {
instructions.push_back(it->get());
}
for (int i = instructions.size() - 1; i >= 0; --i) {
Instruction *prevInst = instructions[i];
if (prevInst->isStore()) {
StoreInst *storeInst = static_cast<StoreInst *>(prevInst);
Value *storePtr = storeInst->getPointer();
if (DEBUG) {
std::cout << "SCCP: Checking store instruction" << std::endl;
}
// 使用别名分析检查Store是否针对相同的内存位置
auto aliasResult = aliasAnalysis->queryAlias(ptr, storePtr);
if (DEBUG) {
std::cout << "SCCP: Alias result: " << (int)aliasResult << std::endl;
}
if (aliasResult == AliasType::SELF_ALIAS) {
// 找到了对相同位置的Store获取存储的值
Value *storedValue = storeInst->getValue();
if (DEBUG) {
std::cout << "SCCP: Found matching store, checking value type" << std::endl;
}
// 检查存储的值是否为常量
if (auto constInt = dynamic_cast<ConstantInteger *>(storedValue)) {
int val = std::get<int>(constInt->getVal());
if (DEBUG) {
std::cout << "SCCP: Found constant integer value: " << val << std::endl;
}
return SSAPValue(val);
} else if (auto constFloat = dynamic_cast<ConstantFloating *>(storedValue)) {
float val = std::get<float>(constFloat->getVal());
if (DEBUG) {
std::cout << "SCCP: Found constant float value: " << val << std::endl;
}
return SSAPValue(val);
} else {
// 存储的值不是常量检查其SCCP状态
SSAPValue storedState = GetValueState(storedValue);
if (storedState.state == LatticeVal::Constant) {
if (DEBUG) {
std::cout << "SCCP: Found SCCP constant value" << std::endl;
}
return storedState;
} else {
if (DEBUG) {
std::cout << "SCCP: Stored value is not constant" << std::endl;
}
}
}
// 找到了最近的Store但不是常量停止查找
if (DEBUG) {
std::cout << "SCCP: Found non-constant store, stopping search" << std::endl;
}
break;
}
}
}
if (DEBUG) {
std::cout << "SCCP: No constant value found" << std::endl;
}
return SSAPValue(LatticeVal::Bottom);
}
// 辅助函数动态检查数组访问是否为常量索引考虑SCCP状态
bool SCCPContext::hasRuntimeConstantAccess(Value *ptr) {
if (auto gep = dynamic_cast<GetElementPtrInst *>(ptr)) {
if (DEBUG) {
std::cout << "SCCP: Checking runtime constant access for GEP instruction" << std::endl;
}
// 检查所有索引是否为常量或SCCP传播的常量
bool allConstantIndices = true;
for (auto indexUse : gep->getIndices()) {
Value* index = indexUse->getValue();
// 首先检查是否为编译时常量
if (auto constInt = dynamic_cast<ConstantInteger *>(index)) {
if (DEBUG) {
std::cout << "SCCP: Index is compile-time constant integer: " << std::get<int>(constInt->getVal()) << std::endl;
}
continue;
}
if (auto constFloat = dynamic_cast<ConstantFloating *>(index)) {
if (DEBUG) {
std::cout << "SCCP: Index is compile-time constant float: " << std::get<float>(constFloat->getVal()) << std::endl;
}
continue;
}
// 检查是否为SCCP传播的常量
SSAPValue indexState = GetValueState(index);
if (indexState.state == LatticeVal::Constant) {
if (DEBUG) {
std::cout << "SCCP: Index is SCCP constant: ";
if (indexState.constant_type == ValueType::Integer) {
std::cout << std::get<int>(indexState.constantVal);
} else {
std::cout << std::get<float>(indexState.constantVal);
}
std::cout << std::endl;
}
continue;
}
// 如果任何一个索引不是常量返回false
if (DEBUG) {
std::cout << "SCCP: Index is not constant, access is not constant" << std::endl;
}
allConstantIndices = false;
break;
}
if (DEBUG) {
std::cout << "SCCP: hasRuntimeConstantAccess result: " << (allConstantIndices ? "true" : "false") << std::endl;
}
return allConstantIndices;
}
// 对于非GEP指令回退到别名分析的静态结果
if (aliasAnalysis) {
return aliasAnalysis->hasConstantAccess(ptr);
}
return false;
}
// 辅助函数:处理单条指令
void SCCPContext::ProcessInstruction(Instruction *inst) {
SSAPValue oldState = GetValueState(inst);
@@ -280,6 +468,22 @@ void SCCPContext::ProcessInstruction(Instruction *inst) {
return; // 不处理不可达块中的指令的实际值
}
if(DEBUG) {
std::cout << "Processing instruction: " << inst->getName() << " in block " << inst->getParent()->getName() << std::endl;
std::cout << "Old state: ";
if (oldState.state == LatticeVal::Top) {
std::cout << "Top";
} else if (oldState.state == LatticeVal::Constant) {
if (oldState.constant_type == ValueType::Integer) {
std::cout << "Const<int>(" << std::get<int>(oldState.constantVal) << ")";
} else {
std::cout << "Const<float>(" << std::get<float>(oldState.constantVal) << ")";
}
} else {
std::cout << "Bottom";
}
}
switch (inst->getKind()) {
case Instruction::kAdd:
case Instruction::kSub:
@@ -380,27 +584,237 @@ void SCCPContext::ProcessInstruction(Instruction *inst) {
break;
}
case Instruction::kLoad: {
// 对于 Load 指令,除非我们有特殊的别名分析,否则假定为 Bottom
// 或者如果它加载的是一个已知常量地址的全局常量
// 使用别名分析和副作用分析改进Load指令的处理
Value *ptr = inst->getOperand(0);
// 首先检查是否是全局常量
if (auto globalVal = dynamic_cast<GlobalValue *>(ptr)) {
// 如果 GlobalValue 有初始化器,并且它是常量,我们可以传播
// 这需要额外的逻辑来检查 globalVal 的初始化器
// 暂时保守地设置为 Bottom
// TODO: 检查全局变量的初始化器进行常量传播
newState = SSAPValue(LatticeVal::Bottom);
} else if (aliasAnalysis && sideEffectAnalysis) {
// 使用别名分析和副作用分析进行更精确的Load分析
if (aliasAnalysis->isLocalArray(ptr) && (aliasAnalysis->hasConstantAccess(ptr) || hasRuntimeConstantAccess(ptr))) {
// 对于局部数组的常量索引访问检查是否有影响该位置的Store
bool mayBeModified = false;
if (DEBUG) {
std::cout << "SCCP: Analyzing local array with constant access for modification" << std::endl;
}
// 遍历指令所在块之前的所有指令查找可能修改该内存位置的Store
BasicBlock *currentBB = inst->getParent();
auto instPos = currentBB->findInstIterator(inst);
SSAPValue foundConstantValue = SSAPValue(LatticeVal::Bottom);
bool hasFoundDefinitiveStore = false;
for (auto it = currentBB->begin(); it != instPos; ++it) {
Instruction *prevInst = it->get();
if (prevInst->isStore()) {
StoreInst *storeInst = static_cast<StoreInst *>(prevInst);
Value *storePtr = storeInst->getPointer();
// 使用别名分析判断Store是否可能影响当前Load
auto aliasResult = aliasAnalysis->queryAlias(ptr, storePtr);
if (DEBUG) {
std::cout << "SCCP: Checking store with alias result: " << (int)aliasResult << std::endl;
}
if (aliasResult == AliasType::SELF_ALIAS) {
// 找到对相同位置的精确Store
Value *storedValue = storeInst->getValue();
if (DEBUG) {
std::cout << "SCCP: Found exact store to same location, checking value" << std::endl;
}
// 检查存储的值是否为常量
if (auto constInt = dynamic_cast<ConstantInteger *>(storedValue)) {
int val = std::get<int>(constInt->getVal());
if (DEBUG) {
std::cout << "SCCP: Store contains constant integer: " << val << std::endl;
}
foundConstantValue = SSAPValue(val);
hasFoundDefinitiveStore = true;
// 继续遍历查找是否有更后面的Store覆盖这个值
} else if (auto constFloat = dynamic_cast<ConstantFloating *>(storedValue)) {
float val = std::get<float>(constFloat->getVal());
if (DEBUG) {
std::cout << "SCCP: Store contains constant float: " << val << std::endl;
}
foundConstantValue = SSAPValue(val);
hasFoundDefinitiveStore = true;
} else {
// 存储的值不是编译时常量检查其SCCP状态
SSAPValue storedState = GetValueState(storedValue);
if (storedState.state == LatticeVal::Constant) {
if (DEBUG) {
std::cout << "SCCP: Store contains SCCP constant" << std::endl;
}
foundConstantValue = storedState;
hasFoundDefinitiveStore = true;
} else {
if (DEBUG) {
std::cout << "SCCP: Store contains non-constant value" << std::endl;
}
// 非常量Store覆盖了之前的常量无法传播
foundConstantValue = SSAPValue(LatticeVal::Bottom);
hasFoundDefinitiveStore = true;
}
}
} else if (aliasResult != AliasType::NO_ALIAS) {
// 可能有别名,但不确定
if (DEBUG) {
std::cout << "SCCP: Found store with uncertain alias, stopping propagation" << std::endl;
}
mayBeModified = true;
break;
}
} else if (prevInst->isCall()) {
// 检查函数调用是否可能修改该内存位置
if (sideEffectAnalysis->mayModifyMemory(prevInst)) {
// 进一步检查是否可能影响局部数组
if (!aliasAnalysis->isLocalArray(ptr) ||
sideEffectAnalysis->mayModifyGlobal(prevInst)) {
mayBeModified = true;
break;
}
}
} else if (prevInst->isMemset()) {
// Memset指令可能影响内存但只有在它在相关Store之前时才阻止常量传播
MemsetInst *memsetInst = static_cast<MemsetInst *>(prevInst);
Value *memsetPtr = memsetInst->getOperand(0);
auto aliasResult = aliasAnalysis->queryAlias(ptr, memsetPtr);
if (aliasResult != AliasType::NO_ALIAS) {
// Memset可能影响这个位置但我们继续查找是否有Store覆盖了memset
// 不立即设置mayBeModified = true让后续的Store有机会覆盖
if (DEBUG) {
std::cout << "SCCP: Found memset that may affect location, but continuing to check for overwriting stores" << std::endl;
}
}
}
}
if (DEBUG) {
std::cout << "SCCP: mayBeModified = " << (mayBeModified ? "true" : "false") << std::endl;
std::cout << "SCCP: hasFoundDefinitiveStore = " << (hasFoundDefinitiveStore ? "true" : "false") << std::endl;
}
if (!mayBeModified) {
if (hasFoundDefinitiveStore && foundConstantValue.state == LatticeVal::Constant) {
// 直接使用找到的常量值
if (DEBUG) {
std::cout << "SCCP: Using found constant value from store analysis: ";
if (foundConstantValue.constant_type == ValueType::Integer) {
std::cout << std::get<int>(foundConstantValue.constantVal);
} else {
std::cout << std::get<float>(foundConstantValue.constantVal);
}
std::cout << std::endl;
}
newState = foundConstantValue;
} else {
// 如果没有发现修改该位置的指令尝试用旧方法找到对应的Store值
SSAPValue constantValue = findStoredConstantValue(ptr, inst->getParent());
if (constantValue.state == LatticeVal::Constant) {
if (DEBUG) {
std::cout << "SCCP: Found constant value for array load using fallback method: ";
if (constantValue.constant_type == ValueType::Integer) {
std::cout << std::get<int>(constantValue.constantVal);
} else {
std::cout << std::get<float>(constantValue.constantVal);
}
std::cout << std::endl;
}
newState = constantValue;
} else {
newState = SSAPValue(LatticeVal::Bottom);
}
}
} else {
newState = SSAPValue(LatticeVal::Bottom);
}
} else {
// 非局部数组或非常量访问,保守处理
newState = SSAPValue(LatticeVal::Bottom);
}
} else {
// 没有分析信息时保守处理
newState = SSAPValue(LatticeVal::Bottom);
}
if (DEBUG && aliasAnalysis && sideEffectAnalysis) {
std::cout << "SCCP: Load instruction analysis - "
<< (aliasAnalysis->isLocalArray(ptr) ? "local array" : "other")
<< ", static constant access: "
<< (aliasAnalysis->hasConstantAccess(ptr) ? "yes" : "no")
<< ", runtime constant access: "
<< (hasRuntimeConstantAccess(ptr) ? "yes" : "no") << std::endl;
}
break;
}
case Instruction::kStore:
// Store 指令不产生值,其 SSAPValue 不重要
newState = SSAPValue(); // 保持 Top
break;
case Instruction::kCall:
// 大多数 Call 指令都假定为 Bottom除非是纯函数且所有参数都是常量
newState = SSAPValue(LatticeVal::Bottom);
case Instruction::kCall: {
// 使用副作用分析改进Call指令处理
CallInst *callInst = static_cast<CallInst *>(inst);
if (sideEffectAnalysis) {
const auto &sideEffect = sideEffectAnalysis->getInstructionSideEffect(callInst);
// 检查是否为纯函数且所有参数都是常量
if (sideEffect.isPure && sideEffect.type == SideEffectType::NO_SIDE_EFFECT) {
// 对于纯函数,检查所有参数是否都是常量
bool allArgsConstant = true;
std::vector<SSAPValue> argValues;
for (unsigned i = 0; i < callInst->getNumOperands() - 1; ++i) { // 减1排除函数本身
SSAPValue argVal = GetValueState(callInst->getOperand(i));
argValues.push_back(argVal);
if (argVal.state != LatticeVal::Constant) {
allArgsConstant = false;
break;
}
}
if (allArgsConstant) {
// 对于参数全为常量的纯函数,可以尝试常量折叠
// 但由于实际执行函数比较复杂,这里先标记为可优化
// TODO: 实现具体的纯函数常量折叠
Function *calledFunc = callInst->getCallee();
if (calledFunc && isKnownPureFunction(calledFunc->getName())) {
// 对已知的纯函数进行常量计算
newState = computePureFunctionResult(callInst, argValues);
} else {
newState = SSAPValue(LatticeVal::Bottom);
}
} else {
// 参数不全是常量,但函数无副作用
newState = SSAPValue(LatticeVal::Bottom);
}
if (DEBUG) {
std::cout << "SCCP: Pure function call with "
<< (allArgsConstant ? "constant" : "non-constant") << " arguments" << std::endl;
}
} else {
// 有副作用的函数调用,保守处理
newState = SSAPValue(LatticeVal::Bottom);
if (DEBUG) {
std::cout << "SCCP: Function call with side effects" << std::endl;
}
}
} else {
// 没有副作用分析时保守处理所有Call
newState = SSAPValue(LatticeVal::Bottom);
}
break;
}
case Instruction::kGetElementPtr: {
// GEP 指令计算地址,通常其结果值(地址指向的内容)是 Bottom
// 除非所有索引和基指针都是常量,指向一个确定常量值的内存位置
@@ -417,19 +831,71 @@ void SCCPContext::ProcessInstruction(Instruction *inst) {
}
case Instruction::kPhi: {
PhiInst *phi = static_cast<PhiInst *>(inst);
if(DEBUG) {
std::cout << "Processing Phi node: " << phi->getName() << std::endl;
}
// 标准SCCP的phi节点处理
// 只考虑可执行前驱,但要保证单调性
SSAPValue currentPhiState = GetValueState(phi);
SSAPValue phiResult = SSAPValue(); // 初始为 Top
bool hasAnyExecutablePred = false;
for (unsigned i = 0; i < phi->getNumIncomingValues(); ++i) {
Value *incomingVal = phi->getIncomingValue(i);
BasicBlock *incomingBlock = phi->getIncomingBlock(i);
if (executableBlocks.count(incomingBlock)) { // 仅考虑可执行前驱
phiResult = Meet(phiResult, GetValueState(incomingVal));
if (phiResult.state == LatticeVal::Bottom)
break; // 如果已经 Bottom则提前退出
if (executableBlocks.count(incomingBlock)) {
hasAnyExecutablePred = true;
Value *incomingVal = phi->getIncomingValue(i);
SSAPValue incomingState = GetValueState(incomingVal);
if(DEBUG) {
std::cout << " Incoming from block " << incomingBlock->getName()
<< " with value " << incomingVal->getName() << " state: ";
if (incomingState.state == LatticeVal::Top)
std::cout << "Top";
else if (incomingState.state == LatticeVal::Constant) {
if (incomingState.constant_type == ValueType::Integer)
std::cout << "Const<int>(" << std::get<int>(incomingState.constantVal) << ")";
else
std::cout << "Const<float>(" << std::get<float>(incomingState.constantVal) << ")";
} else
std::cout << "Bottom";
std::cout << std::endl;
}
phiResult = Meet(phiResult, incomingState);
if (phiResult.state == LatticeVal::Bottom) {
break; // 提前退出优化
}
}
// 不可执行前驱暂时被忽略
// 这是标准SCCP的做法依赖于单调性保证正确性
}
if (!hasAnyExecutablePred) {
// 没有可执行前驱保持Top状态
newState = SSAPValue();
} else {
// 关键修复:使用严格的单调性
// 确保phi的值只能从Top -> Constant -> Bottom单向变化
if (currentPhiState.state == LatticeVal::Top) {
// 从Top状态可以变为任何计算结果
newState = phiResult;
} else if (currentPhiState.state == LatticeVal::Constant) {
// 从Constant状态只能保持相同常量或变为Bottom
if (phiResult.state == LatticeVal::Constant &&
currentPhiState.constantVal == phiResult.constantVal &&
currentPhiState.constant_type == phiResult.constant_type) {
// 保持相同的常量
newState = currentPhiState;
} else {
// 不同的值必须变为Bottom
newState = SSAPValue(LatticeVal::Bottom);
}
} else {
// 已经是Bottom保持Bottom
newState = currentPhiState;
}
}
newState = phiResult;
break;
}
case Instruction::kAlloca: // 对应 kAlloca
@@ -486,6 +952,22 @@ void SCCPContext::ProcessInstruction(Instruction *inst) {
}
}
}
if (DEBUG) {
std::cout << "New state: ";
if (newState.state == LatticeVal::Top) {
std::cout << "Top";
} else if (newState.state == LatticeVal::Constant) {
if (newState.constant_type == ValueType::Integer) {
std::cout << "Const<int>(" << std::get<int>(newState.constantVal) << ")";
} else {
std::cout << "Const<float>(" << std::get<float>(newState.constantVal) << ")";
}
} else {
std::cout << "Bottom";
}
std::cout << std::endl;
}
}
// 辅助函数:处理单条控制流边
@@ -493,14 +975,22 @@ void SCCPContext::ProcessEdge(const std::pair<BasicBlock *, BasicBlock *> &edge)
BasicBlock *fromBB = edge.first;
BasicBlock *toBB = edge.second;
// 检查目标块是否已经可执行
bool wasAlreadyExecutable = executableBlocks.count(toBB) > 0;
// 标记目标块为可执行(如果还不是的话)
MarkBlockExecutable(toBB);
// 对于目标块中的所有 Phi 指令,重新评估其值,因为可能有新的前驱被激活
for (auto &inst_ptr : toBB->getInstructions()) {
if (dynamic_cast<PhiInst *>(inst_ptr.get())) {
instWorkList.push(inst_ptr.get());
// 如果目标块之前就已经可执行那么需要重新处理其中的phi节点
// 因为现在有新的前驱变为可执行phi节点的值可能需要更新
if (wasAlreadyExecutable) {
for (auto &inst_ptr : toBB->getInstructions()) {
if (dynamic_cast<PhiInst *>(inst_ptr.get())) {
instWorkList.push(inst_ptr.get());
}
}
}
// 如果目标块是新变为可执行的MarkBlockExecutable已经添加了所有指令
}
// 阶段1: 常量传播与折叠
@@ -515,18 +1005,29 @@ bool SCCPContext::PropagateConstants(Function *func) {
}
}
// 初始化函数参数为Bottom因为它们在编译时是未知的
for (auto arg : func->getArguments()) {
valueState[arg] = SSAPValue(LatticeVal::Bottom);
if (DEBUG) {
std::cout << "Initializing function argument " << arg->getName() << " to Bottom" << std::endl;
}
}
// 标记入口块为可执行
if (!func->getBasicBlocks().empty()) {
MarkBlockExecutable(func->getEntryBlock());
}
// 主循环:处理工作列表直到不动点
// 主循环:标准的SCCP工作列表算法
// 交替处理边工作列表和指令工作列表直到不动点
while (!instWorkList.empty() || !edgeWorkList.empty()) {
// 处理所有待处理的CFG边
while (!edgeWorkList.empty()) {
ProcessEdge(edgeWorkList.front());
edgeWorkList.pop();
}
// 处理所有待处理的指令
while (!instWorkList.empty()) {
Instruction *inst = instWorkList.front();
instWorkList.pop();
@@ -866,12 +1367,34 @@ bool SCCP::runOnFunction(Function *F, AnalysisManager &AM) {
if (DEBUG) {
std::cout << "Running SCCP on function: " << F->getName() << std::endl;
}
SCCPContext context(builder);
// 获取别名分析结果
if (auto *aliasResult = AM.getAnalysisResult<AliasAnalysisResult, SysYAliasAnalysisPass>(F)) {
context.setAliasAnalysis(aliasResult);
if (DEBUG) {
std::cout << "SCCP: Using alias analysis results" << std::endl;
}
}
// 获取副作用分析结果Module级别
if (auto *sideEffectResult = AM.getAnalysisResult<SideEffectAnalysisResult, SysYSideEffectAnalysisPass>()) {
context.setSideEffectAnalysis(sideEffectResult);
if (DEBUG) {
std::cout << "SCCP: Using side effect analysis results" << std::endl;
}
}
context.run(F, AM);
return true;
}
void SCCP::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
// 声明依赖别名分析和副作用分析
analysisDependencies.insert(&SysYAliasAnalysisPass::ID);
analysisDependencies.insert(&SysYSideEffectAnalysisPass::ID);
// analysisInvalidations.insert(nullptr); // 表示使所有默认分析失效
analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID); // 支配树可能受影响
analysisInvalidations.insert(&LivenessAnalysisPass::ID); // 活跃性分析很可能失效

View File

@@ -42,7 +42,7 @@ bool SysYCFGOptUtils::SysYDelInstAfterBr(Function *func) {
++Branchiter;
while (Branchiter != instructions.end()) {
changed = true;
Branchiter = instructions.erase(Branchiter);
Branchiter = SysYIROptUtils::usedelete(Branchiter); // 删除指令
}
if (Branch) { // 更新前驱后继关系
@@ -77,6 +77,11 @@ bool SysYCFGOptUtils::SysYBlockMerge(Function *func) {
bool changed = false;
for (auto blockiter = func->getBasicBlocks().begin(); blockiter != func->getBasicBlocks().end();) {
// 检查当前块是是不是entry块
if( blockiter->get() == func->getEntryBlock() ) {
blockiter++;
continue; // 跳过入口块
}
if (blockiter->get()->getNumSuccessors() == 1) {
// 如果当前块只有一个后继块
// 且后继块只有一个前驱块
@@ -86,7 +91,7 @@ bool SysYCFGOptUtils::SysYBlockMerge(Function *func) {
BasicBlock *block = blockiter->get();
BasicBlock *nextBlock = blockiter->get()->getSuccessors()[0];
// auto nextarguments = nextBlock->getArguments();
// 删除br指令
// 删除block的br指令
if (block->getNumInstructions() != 0) {
auto thelastinstinst = block->terminator();
if (thelastinstinst->get()->isUnconditional()) {
@@ -98,14 +103,21 @@ bool SysYCFGOptUtils::SysYBlockMerge(Function *func) {
if (brinst->getThenBlock() == brinst->getElseBlock()) {
thelastinstinst = SysYIROptUtils::usedelete(thelastinstinst);
}
else{
assert(false && "SysYBlockMerge: unexpected conditional branch with different then and else blocks");
}
}
}
// 将后继块的指令移动到当前块
// 并将后继块的父指针改为当前块
for (auto institer = nextBlock->begin(); institer != nextBlock->end();) {
institer->get()->setParent(block);
block->getInstructions().emplace_back(institer->release());
institer = nextBlock->getInstructions().erase(institer);
// institer->get()->setParent(block);
// block->getInstructions().emplace_back(institer->release());
// 用usedelete删除会导致use关系被删除我只希望移动指令到当前块
// institer = SysYIROptUtils::usedelete(institer);
// institer = nextBlock->getInstructions().erase(institer);
institer = nextBlock->moveInst(institer, block->getInstructions().end(), block);
}
// 更新前驱后继关系,类似树节点操作
block->removeSuccessor(nextBlock);
@@ -288,13 +300,12 @@ bool SysYCFGOptUtils::SysYDelEmptyBlock(Function *func, IRBuilder *pBuilder) {
continue;
}
std::function<Value *(Value *, BasicBlock *)> getUltimateSourceValue = [&](Value *val,
BasicBlock *currentDefBlock) -> Value * {
// 如果值不是指令,例如常量或函数参数,则它本身就是最终来源
if (auto instr = dynamic_cast<Instruction *>(val)) { // Assuming Value* has a method to check if it's an instruction
std::function<Value *(Value *, BasicBlock *)> getUltimateSourceValue = [&](Value *val, BasicBlock *currentDefBlock) -> Value * {
if(!dynamic_cast<Instruction *>(val)) {
// 如果 val 不是指令,直接返回它
return val;
}
Instruction *inst = dynamic_cast<Instruction *>(val);
// 如果定义指令不在任何空块中,它就是最终来源
if (!emptyBlockRedirectMap.count(currentDefBlock)) {

View File

@@ -1,5 +1,10 @@
#include "Dom.h"
#include "Liveness.h"
#include "Loop.h"
#include "LoopCharacteristics.h"
#include "AliasAnalysis.h"
#include "CallGraphAnalysis.h"
#include "SideEffectAnalysis.h"
#include "SysYIRCFGOpt.h"
#include "SysYIRPrinter.h"
#include "DCE.h"
@@ -8,6 +13,10 @@
#include "SCCP.h"
#include "BuildCFG.h"
#include "LargeArrayToGlobal.h"
#include "LoopNormalization.h"
#include "LICM.h"
#include "LoopStrengthReduction.h"
#include "InductionVariableElimination.h"
#include "Pass.h"
#include <iostream>
#include <queue>
@@ -39,6 +48,13 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
// 注册分析遍
registerAnalysisPass<DominatorTreeAnalysisPass>();
registerAnalysisPass<LivenessAnalysisPass>();
registerAnalysisPass<sysy::DominatorTreeAnalysisPass>();
registerAnalysisPass<sysy::LivenessAnalysisPass>();
registerAnalysisPass<SysYAliasAnalysisPass>(); // 别名分析 (优先级高)
registerAnalysisPass<CallGraphAnalysisPass>(); // 调用图分析 (Module级别独立分析)
registerAnalysisPass<SysYSideEffectAnalysisPass>(); // 副作用分析 (依赖别名分析和调用图)
registerAnalysisPass<LoopAnalysisPass>();
registerAnalysisPass<LoopCharacteristicsPass>(); // 循环特征分析依赖别名分析
// 注册优化遍
registerOptimizationPass<BuildCFG>();
@@ -54,6 +70,10 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
registerOptimizationPass<DCE>();
registerOptimizationPass<Mem2Reg>(builderIR);
registerOptimizationPass<LoopNormalizationPass>(builderIR);
registerOptimizationPass<LICM>(builderIR);
registerOptimizationPass<LoopStrengthReduction>(builderIR);
registerOptimizationPass<InductionVariableElimination>();
registerOptimizationPass<Reg2Mem>(builderIR);
registerOptimizationPass<SCCP>(builderIR);
@@ -119,9 +139,21 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
}
this->clearPasses();
this->addPass(&Reg2Mem::ID);
this->addPass(&LoopNormalizationPass::ID);
this->addPass(&InductionVariableElimination::ID);
this->addPass(&LICM::ID);
this->addPass(&LoopStrengthReduction::ID);
this->run();
if(DEBUG) {
std::cout << "=== IR After Loop Normalization, LICM, and Strength Reduction Optimizations ===\n";
printPasses();
}
// this->clearPasses();
// this->addPass(&Reg2Mem::ID);
// this->run();
if(DEBUG) {
std::cout << "=== IR After Reg2Mem Optimizations ===\n";
printPasses();

View File

@@ -391,26 +391,7 @@ void SysYIRGenerator::compute() {
case BinaryOp::ADD: resultValue = builder.createAddInst(lhs, rhs); break;
case BinaryOp::SUB: resultValue = builder.createSubInst(lhs, rhs); break;
case BinaryOp::MUL: resultValue = builder.createMulInst(lhs, rhs); break;
case BinaryOp::DIV: {
ConstantInteger *rhsConst = dynamic_cast<ConstantInteger *>(rhs);
if (rhsConst) {
int divisor = rhsConst->getInt();
if (divisor > 0 && (divisor & (divisor - 1)) == 0) {
int shift = 0;
int temp = divisor;
while (temp > 1) {
temp >>= 1;
shift++;
}
resultValue = builder.createSRAInst(lhs, ConstantInteger::get(shift));
} else {
resultValue = builder.createDivInst(lhs, rhs);
}
} else {
resultValue = builder.createDivInst(lhs, rhs);
}
break;
}
case BinaryOp::DIV: resultValue = builder.createDivInst(lhs, rhs); break;
case BinaryOp::MOD: resultValue = builder.createRemInst(lhs, rhs); break;
}
} else if (commonType == Type::getFloatType()) {
@@ -1212,15 +1193,25 @@ std::any SysYIRGenerator::visitFuncDef(SysYParser::FuncDefContext *ctx){
for(int i = 0; i < paramActualTypes.size(); ++i) {
Argument* arg = new Argument(paramActualTypes[i], function, i, paramNames[i]);
function->insertArgument(arg);
}
// 先将所有参数名字注册到符号表中确保alloca不会使用相同的名字
for (int i = 0; i < paramNames.size(); ++i) {
// 预先注册参数名字这样addVariable就会使用不同的后缀
module->registerParameterName(paramNames[i]);
}
auto funcArgs = function->getArguments();
std::vector<AllocaInst *> allocas;
for (int i = 0; i < paramActualTypes.size(); ++i) {
AllocaInst *alloca = builder.createAllocaInst(Type::getPointerType(paramActualTypes[i]), paramNames[i]);
// 使用函数特定的前缀来确保参数alloca名字唯一
std::string allocaName = name + "_param_" + paramNames[i];
AllocaInst *alloca = builder.createAllocaInst(Type::getPointerType(paramActualTypes[i]), allocaName);
// 直接设置唯一名字不依赖addVariable的命名逻辑
alloca->setName(allocaName);
allocas.push_back(alloca);
module->addVariable(paramNames[i], alloca);
// 直接添加到符号表,使用原参数名作为查找键
module->addVariableDirectly(paramNames[i], alloca);
}
for(int i = 0; i < paramActualTypes.size(); ++i) {
@@ -1289,6 +1280,45 @@ std::any SysYIRGenerator::visitAssignStmt(SysYParser::AssignStmtContext *ctx) {
if (dynamic_cast<AllocaInst*>(variable) || dynamic_cast<GlobalValue*>(variable)) {
LValue = variable;
}
// 标量变量的类型推断
Type* LType = builder.getIndexedType(variable->getType(), indices);
Value* RValue = computeExp(ctx->exp(), LType); // 右值计算
Type* RType = RValue->getType();
// TODO:computeExp处理了类型转换可以考虑删除判断逻辑
if (LType != RType) {
ConstantValue *constValue = dynamic_cast<ConstantValue *>(RValue);
if (constValue != nullptr) {
if (LType == Type::getFloatType()) {
if(dynamic_cast<ConstantInteger *>(constValue)) {
// 如果是整型常量,转换为浮点型
RValue = ConstantFloating::get(static_cast<float>(constValue->getInt()));
} else if (dynamic_cast<ConstantFloating *>(constValue)) {
// 如果是浮点型常量,直接使用
RValue = ConstantFloating::get(static_cast<float>(constValue->getFloat()));
}
} else { // 假设如果不是浮点型,就是整型
if(dynamic_cast<ConstantFloating *>(constValue)) {
// 如果是浮点型常量,转换为整型
RValue = ConstantInteger::get(static_cast<int>(constValue->getFloat()));
} else if (dynamic_cast<ConstantInteger *>(constValue)) {
// 如果是整型常量,直接使用
RValue = ConstantInteger::get(static_cast<int>(constValue->getInt()));
}
}
} else {
if (LType == Type::getFloatType() && RType != Type::getFloatType()) {
RValue = builder.createItoFInst(RValue);
} else if (LType != Type::getFloatType() && RType == Type::getFloatType()) {
RValue = builder.createFtoIInst(RValue);
}
// 如果两者都是同一类型,就不需要转换
}
}
builder.createStoreInst(RValue, LValue);
}
else {
// 对于数组或多维数组的左值处理
@@ -1326,51 +1356,47 @@ std::any SysYIRGenerator::visitAssignStmt(SysYParser::AssignStmtContext *ctx) {
}
// 左值为地址
LValue = getGEPAddressInst(gepBasePointer, gepIndices);
}
// 数组变量的类型推断使用gepIndices和gepBasePointer的类型
Type* LType = builder.getIndexedType(gepBasePointer->getType(), gepIndices);
Value* RValue = computeExp(ctx->exp(), LType); // 右值计算
Type* RType = RValue->getType();
// Value* RValue = std::any_cast<Value *>(visitExp(ctx->exp())); // 右值
// 先推断 LValue 的类型
// 如果 LValue 是指向数组的指针,则需要根据 indices 获取正确的类型
// 如果 LValue 是标量,则直接使用其类型
// 注意LValue 的类型可能是指向数组的指针 (e.g., int(*)[3]) 或者指向标量的指针 (e.g., int*) 也能推断
Type* LType = builder.getIndexedType(variable->getType(), indices);
Value* RValue = computeExp(ctx->exp(), LType); // 右值计算
Type* RType = RValue->getType();
// TODO:computeExp处理了类型转换可以考虑删除判断逻辑
if (LType != RType) {
ConstantValue *constValue = dynamic_cast<ConstantValue *>(RValue);
if (constValue != nullptr) {
if (LType == Type::getFloatType()) {
if(dynamic_cast<ConstantInteger *>(constValue)) {
// 如果是整型常量,转换为浮点型
RValue = ConstantFloating::get(static_cast<float>(constValue->getInt()));
} else if (dynamic_cast<ConstantFloating *>(constValue)) {
// 如果是浮点型常量,直接使用
RValue = ConstantFloating::get(static_cast<float>(constValue->getFloat()));
// TODO:computeExp处理了类型转换可以考虑删除判断逻辑
if (LType != RType) {
ConstantValue *constValue = dynamic_cast<ConstantValue *>(RValue);
if (constValue != nullptr) {
if (LType == Type::getFloatType()) {
if(dynamic_cast<ConstantInteger *>(constValue)) {
// 如果是整型常量,转换为浮点型
RValue = ConstantFloating::get(static_cast<float>(constValue->getInt()));
} else if (dynamic_cast<ConstantFloating *>(constValue)) {
// 如果是浮点型常量,直接使用
RValue = ConstantFloating::get(static_cast<float>(constValue->getFloat()));
}
} else { // 假设如果不是浮点型,就是整型
if(dynamic_cast<ConstantFloating *>(constValue)) {
// 如果是浮点型常量,转换为整型
RValue = ConstantInteger::get(static_cast<int>(constValue->getFloat()));
} else if (dynamic_cast<ConstantInteger *>(constValue)) {
// 如果是整型常量,直接使用
RValue = ConstantInteger::get(static_cast<int>(constValue->getInt()));
}
}
} else { // 假设如果不是浮点型,就是整型
if(dynamic_cast<ConstantFloating *>(constValue)) {
// 如果是浮点型常量,转换为整型
RValue = ConstantInteger::get(static_cast<int>(constValue->getFloat()));
} else if (dynamic_cast<ConstantInteger *>(constValue)) {
// 如果是整型常量,直接使用
RValue = ConstantInteger::get(static_cast<int>(constValue->getInt()));
} else {
if (LType == Type::getFloatType() && RType != Type::getFloatType()) {
RValue = builder.createItoFInst(RValue);
} else if (LType != Type::getFloatType() && RType == Type::getFloatType()) {
RValue = builder.createFtoIInst(RValue);
}
}
} else {
if (LType == Type::getFloatType()) {
RValue = builder.createItoFInst(RValue);
} else { // 假设如果不是浮点型,就是整型
RValue = builder.createFtoIInst(RValue);
// 如果两者都是同一类型,就不需要转换
}
}
builder.createStoreInst(RValue, LValue);
}
builder.createStoreInst(RValue, LValue);
invalidateExpressionsOnStore(LValue);
return std::any();
}
@@ -1537,7 +1563,7 @@ std::any SysYIRGenerator::visitWhileStmt(SysYParser::WhileStmtContext *ctx) {
}
builder.createUncondBrInst(headBlock);
BasicBlock::conectBlocks(builder.getBasicBlock(), exitBlock);
BasicBlock::conectBlocks(builder.getBasicBlock(), headBlock);
builder.popBreakBlock();
builder.popContinueBlock();
@@ -1654,11 +1680,19 @@ std::any SysYIRGenerator::visitLValue(SysYParser::LValueContext *ctx) {
break;
}
}
if (allIndicesConstant) {
// 如果是常量变量且所有索引都是常量,并且不是数组名单独出现的情况
if (allIndicesConstant && !dims.empty()) {
// 如果是常量变量且所有索引都是常量,直接通过 getByIndices 获取编译时值
// 这个方法会根据索引深度返回最终的标量值或指向子数组的指针 (作为 ConstantValue/Variable)
return constVar->getByIndices(dims);
}
// 如果dims为空检查是否是常量标量
if (dims.empty() && declaredNumDims == 0) {
// 常量标量,直接返回其值
// 默认传入空索引列表,表示访问标量本身
return constVar->getByIndices(dims);
}
// 如果dims为空但不是标量数组名单独出现需要走GEP路径来实现数组到指针的退化
}
// 3. 处理可变变量 (AllocaInst/GlobalValue) 或带非常量索引的常量变量
@@ -1668,7 +1702,8 @@ std::any SysYIRGenerator::visitLValue(SysYParser::LValueContext *ctx) {
if (dims.empty() && declaredNumDims == 0) {
if (dynamic_cast<AllocaInst*>(variable) || dynamic_cast<GlobalValue*>(variable)) {
targetAddress = variable;
} else {
}
else {
assert(false && "Unhandled scalar variable type in LValue access.");
return static_cast<Value*>(nullptr);
}
@@ -1683,16 +1718,39 @@ std::any SysYIRGenerator::visitLValue(SysYParser::LValueContext *ctx) {
} else {
gepBasePointer = alloc;
gepIndices.push_back(ConstantInteger::get(0));
gepIndices.insert(gepIndices.end(), dims.begin(), dims.end());
if (dims.empty() && declaredNumDims > 0) {
// 数组名单独出现没有索引在SysY中多维数组名应该退化为指向第一行的指针
// 对于二维数组 T[M][N],退化为 T(*)[N]需要GEP: getelementptr T[M][N], T[M][N]* ptr, i32 0, i32 0
// 第一个i32 0: 选择数组本身第二个i32 0: 选择第0行
// 结果类型: T[N]*
gepIndices.push_back(ConstantInteger::get(0));
} else {
// 正常的数组元素访问
gepIndices.insert(gepIndices.end(), dims.begin(), dims.end());
}
}
} else if (GlobalValue *glob = dynamic_cast<GlobalValue *>(variable)) {
gepBasePointer = glob;
gepIndices.push_back(ConstantInteger::get(0));
gepIndices.insert(gepIndices.end(), dims.begin(), dims.end());
if (dims.empty() && declaredNumDims > 0) {
// 全局数组名单独出现(没有索引):应该退化为指向第一行的指针
// 需要添加一个额外的i32 0索引
gepIndices.push_back(ConstantInteger::get(0));
} else {
// 正常的数组元素访问
gepIndices.insert(gepIndices.end(), dims.begin(), dims.end());
}
} else if (ConstantVariable *constV = dynamic_cast<ConstantVariable *>(variable)) {
gepBasePointer = constV;
gepIndices.push_back(ConstantInteger::get(0));
gepIndices.insert(gepIndices.end(), dims.begin(), dims.end());
if (dims.empty() && declaredNumDims > 0) {
// 常量数组名单独出现(没有索引):应该退化为指向第一行的指针
// 需要添加一个额外的i32 0索引
gepIndices.push_back(ConstantInteger::get(0));
} else {
// 正常的数组元素访问
gepIndices.insert(gepIndices.end(), dims.begin(), dims.end());
}
} else {
assert(false && "LValue variable type not supported for GEP base pointer.");
return static_cast<Value *>(nullptr);
@@ -1774,10 +1832,10 @@ std::any SysYIRGenerator::visitCall(SysYParser::CallContext *ctx) {
// 获取形参列表。`getArguments()` 返回的是 `Argument*` 的集合,
// 每个 `Argument` 代表一个函数形参,其 `getType()` 就是指向形参的类型的指针类型。
auto formalParams = function->getArguments();
const auto& formalParams = function->getArguments();
// 检查实参和形参数量是否匹配。
if (args.size() != formalParams.size()) {
if (args.size() != function->getNumArguments()) {
std::cerr << "Error: Function call argument count mismatch for function '" << funcName << "'." << std::endl;
assert(false && "Function call argument count mismatch!");
}
@@ -1809,15 +1867,27 @@ std::any SysYIRGenerator::visitCall(SysYParser::CallContext *ctx) {
} else if (formalParamExpectedValueType->isFloat() && actualArgType->isInt()) {
args[i] = builder.createItoFInst(args[i]);
}
// 2. 指针类型转换 (例如数组退化:`[N x T]*` 到 `T*`,或兼容指针类型之间) TODO不清楚有没有这种样例
// 2. 指针类型转换 (例如数组退化:`[N x T]*` 到 `T*`,或兼容指针类型之间)
// 这种情况常见于数组参数,实参可能是一个更具体的数组指针类型,
// 而形参是其退化后的基础指针类型。LLVM 的 `bitcast` 指令可以用于
// 在相同大小的指针类型之间进行转换,这对于数组退化至关重要。
// else if (formalParamType->isPointer() && actualArgType->isPointer()) {
// 检查指针基类型是否兼容,或者是否是数组退化导致的类型不同。
// 使用 bitcast
// args[i] = builder.createBitCastInst(args[i], formalParamType);
// }
// 而形参是其退化后的基础指针类型。
else if (formalParamExpectedValueType->isPointer() && actualArgType->isPointer()) {
// 检查是否是数组指针到元素指针的decay
// 例如:[N x T]* -> T*
auto formalPtrType = formalParamExpectedValueType->as<PointerType>();
auto actualPtrType = actualArgType->as<PointerType>();
if (formalPtrType && actualPtrType && actualPtrType->getBaseType()->isArray()) {
auto actualArrayType = actualPtrType->getBaseType()->as<ArrayType>();
if (actualArrayType &&
formalPtrType->getBaseType() == actualArrayType->getElementType()) {
// 这是数组decay的情况添加GEP来获取数组的第一个元素
std::vector<Value*> indices;
indices.push_back(ConstantInteger::get(0)); // 第一个索引:解引用指针
indices.push_back(ConstantInteger::get(0)); // 第二个索引:获取数组第一个元素
args[i] = getGEPAddressInst(args[i], indices);
}
}
}
// 3. 其他未预期的类型不匹配
// 如果代码执行到这里,说明存在编译器前端未处理的类型不兼容或错误。
else {
@@ -2201,15 +2271,23 @@ void Utils::createExternalFunction(
const std::vector<std::string> &paramNames,
const std::vector<std::vector<Value *>> &paramDims, Type *returnType,
const std::string &funcName, Module *pModule, IRBuilder *pBuilder) {
auto funcType = Type::getFunctionType(returnType, paramTypes);
// 根据paramDims调整参数类型数组参数需要转换为指针类型
std::vector<Type *> adjustedParamTypes = paramTypes;
for (int i = 0; i < paramTypes.size() && i < paramDims.size(); ++i) {
if (!paramDims[i].empty()) {
// 如果参数有维度信息,说明是数组参数,转换为指针类型
adjustedParamTypes[i] = Type::getPointerType(paramTypes[i]);
}
}
auto funcType = Type::getFunctionType(returnType, adjustedParamTypes);
auto function = pModule->createExternalFunction(funcName, funcType);
auto entry = function->getEntryBlock();
pBuilder->setPosition(entry, entry->end());
for (int i = 0; i < paramTypes.size(); ++i) {
auto arg = new Argument(paramTypes[i], function, i, paramNames[i]);
auto arg = new Argument(adjustedParamTypes[i], function, i, paramNames[i]);
auto alloca = pBuilder->createAllocaInst(
Type::getPointerType(paramTypes[i]), paramNames[i]);
Type::getPointerType(adjustedParamTypes[i]), paramNames[i]);
function->insertArgument(arg);
auto store = pBuilder->createStoreInst(arg, alloca);
pModule->addVariable(paramNames[i], alloca);

View File

@@ -240,7 +240,9 @@ void SysYPrinter::printInst(Instruction *pInst) {
case Kind::kMul:
case Kind::kDiv:
case Kind::kRem:
case Kind::kSRA:
case Kind::kSrl:
case Kind::kSll:
case Kind::kSra:
case Kind::kMulh:
case Kind::kFAdd:
case Kind::kFSub:
@@ -274,7 +276,9 @@ void SysYPrinter::printInst(Instruction *pInst) {
case Kind::kMul: std::cout << "mul"; break;
case Kind::kDiv: std::cout << "sdiv"; break;
case Kind::kRem: std::cout << "srem"; break;
case Kind::kSRA: std::cout << "ashr"; break;
case Kind::kSrl: std::cout << "lshr"; break;
case Kind::kSll: std::cout << "shl"; break;
case Kind::kSra: std::cout << "ashr"; break;
case Kind::kMulh: std::cout << "mulh"; break;
case Kind::kFAdd: std::cout << "fadd"; break;
case Kind::kFSub: std::cout << "fsub"; break;

View File

@@ -35,7 +35,7 @@ void usage(int code) {
"Supported options:\n"
" -h \tprint help message and exit\n"
" -f \tpretty-format the input file\n"
" -s {ast,ir,asm,llvmir,asmd,ird}\tstop after generating AST/IR/Assembly\n"
" -s {ast,ir,asm,asmd,ird}\tstop after generating AST/IR/Assembly\n"
" -S \tcompile to assembly (.s file)\n"
" -o <file>\tplace the output into <file>\n"
" -O<level>\tenable optimization at <level> (e.g., -O0, -O1)\n";
@@ -110,6 +110,7 @@ int main(int argc, char **argv) {
// 如果指定停止在 AST 阶段,则打印并退出
if (argStopAfter == "ast") {
cout << moduleAST->toStringTree(true) << '\n';
sysy::cleanupIRPools(); // 清理内存池
return EXIT_SUCCESS;
}
@@ -132,7 +133,7 @@ int main(int argc, char **argv) {
if (DEBUG) {
cout << "=== Init IR ===\n";
SysYPrinter(moduleIR).printIR(); // 临时打印器用于调试
moduleIR->print(cout); // 使用新实现的print方法直接打印IR
}
// 创建 Pass 管理器并运行优化管道
@@ -144,10 +145,26 @@ int main(int argc, char **argv) {
// a) 如果指定停止在 IR 阶段,则打印最终 IR 并退出
if (argStopAfter == "ir" || argStopAfter == "ird") {
// 打印最终 IR
cout << "=== Final IR ===\n";
SysYPrinter printer(moduleIR); // 在这里创建打印器,因为可能之前调试时用过临时打印器
printer.printIR();
if (DEBUG) cerr << "=== Final IR ===\n";
if (!argOutputFilename.empty()) {
// 输出到指定文件
ofstream fout(argOutputFilename);
if (not fout.is_open()) {
cerr << "Failed to open output file: " << argOutputFilename << endl;
moduleIR->cleanup(); // 清理模块
sysy::cleanupIRPools(); // 清理内存池
return EXIT_FAILURE;
}
moduleIR->print(fout);
fout.close();
} else {
// 输出到标准输出
moduleIR->print(cout);
}
moduleIR->cleanup(); // 清理模块
sysy::cleanupIRPools(); // 清理内存池
return EXIT_SUCCESS;
}
// b) 如果未停止在 IR 阶段,则继续生成汇编 (后端)
@@ -166,6 +183,8 @@ int main(int argc, char **argv) {
ofstream fout(argOutputFilename);
if (not fout.is_open()) {
cerr << "Failed to open output file: " << argOutputFilename << endl;
moduleIR->cleanup(); // 清理模块
sysy::cleanupIRPools(); // 清理内存池
return EXIT_FAILURE;
}
fout << asmCode << endl;
@@ -173,6 +192,8 @@ int main(int argc, char **argv) {
} else {
cout << asmCode << endl;
}
moduleIR->cleanup(); // 清理模块
sysy::cleanupIRPools(); // 清理内存池
return EXIT_SUCCESS;
}
@@ -181,5 +202,7 @@ int main(int argc, char **argv) {
cout << "Compilation completed. No output specified (neither -s nor -S). Exiting.\n";
// return EXIT_SUCCESS; // 或者这里调用一个链接器生成可执行文件
moduleIR->cleanup(); // 清理模块
sysy::cleanupIRPools(); // 清理内存池
return EXIT_SUCCESS;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long