Compare commits

...

47 Commits

Author SHA1 Message Date
c268191826 [midend-SCCP]修改BaiscBlock的析构逻辑,将CFG修改的职责交给优化遍,注释Mem2Reg的调试信息。 2025-08-01 01:44:33 +08:00
0f1fcc835d [midend-SCCP]删除User的析构函数,usedelete增加逻辑通知inst所使用的value移除对应的use关系(一般在这之前会替换使用inst的uses为其他值),TODO:仍然存在bug需要调试 2025-07-31 22:32:04 +08:00
c5af4f1c49 [midend-SCCP]bug修复,增加不可达指令(理论来说后端不会出现这条指令,只是为了IR完整性添加),添加相关方法,phi指令方法修复;目前能够跑完所有优化,但是User的析构函数重定义导致全局析构不能正确完成,需要修复 2025-07-31 22:03:35 +08:00
9a53e1b917 [midend]适应上一次commit修改已有优化遍中相关指令删除的代码 2025-07-31 21:10:59 +08:00
ef09bc70d4 [midend]修改了removeinst方法,应对不同的使用情况,增加user析构函数使得user对象销毁顺带销毁其use关系销毁,重构usedelete方法封装指令删除和use关系删除 2025-07-31 21:10:20 +08:00
aed4577490 [midend]同上,删除了打印函数对维度信息的错误访问 2025-07-31 19:57:19 +08:00
35b421b60b [midend]修改原因同上一次commit 2025-07-31 19:38:43 +08:00
f3f603a032 [midend]消除冗余维度信息记录,适配IR生成器,TODO:其他优化遍生成指令修改,或者后端的访问 2025-07-31 19:36:39 +08:00
de0f8422e9 [midend-SCCP]没有编译报错但是Segmemtation falut 2025-07-31 17:29:34 +08:00
35691ab7bc [midend-SCCP]为跳转指令增加getSuccessors方法 2025-07-31 17:19:57 +08:00
61768fa180 [midend-SCCP]头文件构架完毕,cpp文件部分报错暂时不commit 2025-07-31 17:00:02 +08:00
520ebd96f0 [midend-SCCP]增加不可达指令,修改跳转指令参数(基本块args已弃用默认为{}) 2025-07-31 16:59:22 +08:00
6868f638d7 [midend-SCCP]增加基本块对的哈希值计算方法,增加删除use关系和指令的函数 2025-07-31 16:57:47 +08:00
206a0af424 [midend-SCCP]暂存1 2025-07-30 16:33:56 +08:00
38bee5d5ac [midend]IRPrinter增加了打印全局常量的功能 2025-07-30 14:46:28 +08:00
98511efd91 [midend]修改constdecl的逻辑区分局部常量和全局常量声明逻辑,提供方法访问全局变量,常量的维度信息,修改GlobalValue,ConstantVariable的继承父类(User->Value)维度信息保存在Type中。 2025-07-30 14:40:10 +08:00
507096a0f6 Merge branch 'midend' of gitee.com:lixuanwang/mysysy into midend 2025-07-30 11:31:46 +08:00
7f2e501cea [backend]修复了指令选择不支持ConstantVariable操作数的bug 2025-07-30 11:31:37 +08:00
31b6711d74 [midend]IR修改常量类getint和getfloat逻辑,如果类型和方法不一致那么应用强制转换返回转换后的值 2025-07-29 23:52:37 +08:00
42dce9820b Merge branch 'midend' into backend 2025-07-29 21:31:04 +08:00
09ae47924e [midend]重构了src目录 2025-07-29 21:30:30 +08:00
f5922d0178 [midend]修改类型转换判断的逻辑 2025-07-29 20:23:25 +08:00
63906d0648 [midend]修复82样例生成IR的错误(未正确初始化全局数组常量和数组常量的Type计算) 2025-07-29 19:35:39 +08:00
6ba05e0d8c [PreRA_Scheduler]添加寄存器分配前的指令调度优化 2025-07-29 17:00:27 +08:00
e4fd16e36a Merge branch 'backend' into midend 2025-07-29 16:37:11 +08:00
32bdc17dc3 [backend]调整了后端pass的顺序 2025-07-29 16:15:01 +08:00
8deb4ed076 [backend]添加了2个新的pass,用于解决大立即数加载问题 2025-07-29 15:48:37 +08:00
37e99e37a3 Merge branch 'midend-mem2reg' into midend 2025-07-29 15:48:34 +08:00
8e69992b29 [midend-mem2reg]增加说明 2025-07-29 15:47:51 +08:00
15fe69187a [midend-mem2reg]目前reg2mem仅将函数参数和phi指令及其对应指令进行reg2mem,旨在消除phi指令。 2025-07-29 15:30:28 +08:00
fff19ca1ea [midend-mem2reg]Reg2Mem建立完成runit测试127/140,reg2mem基本思路:函数参数默认降级到内存,有结果的指令被降级的内存 2025-07-29 14:34:16 +08:00
4a329eeaf2 [midend]修复return指令exp为空的判断条件错误 2025-07-29 12:16:46 +08:00
3dc4b28c92 [midend-mem2reg]dom增加访问支配树子节点求解和访问方法,修复block打印,phi指令命名,TODO:reg2membug待修复 2025-07-29 03:25:56 +08:00
202e6d7cd8 [midend-mem2reg]增加遍打印方法,修复reg2mem构造函数错误 2025-07-29 02:11:10 +08:00
3e4cac089e [midend-reg2mem]增加reg2mem遍,应用未定义值,增加inst迭代器查找方法,通过编译且脚本运行通过率不变 2025-07-29 02:01:48 +08:00
76d7b14b2e [backend]更新了测试脚本,现在的测试更准确 2025-07-29 01:04:43 +08:00
9ba08126fb Merge branch 'peephole' into backend 2025-07-28 23:46:34 +08:00
875100ec01 [backend]为单次运行脚本添加了clean参数 2025-07-28 23:41:36 +08:00
b0cecca081 Merge branch 'backend-rec' into backend 2025-07-28 23:40:58 +08:00
434bcea98e [PostRA_Scheduler]修复了超大测例卡死的bug 2025-07-28 23:17:26 +08:00
da5c2bb41d [PostRA_Scheduler]完成寄存器分配后的指令调度优化 2025-07-28 22:35:29 +08:00
fcc3806342 Merge branch 'backend-bss' into backend 2025-07-28 17:31:47 +08:00
535a935bf1 [midend-mem2reg]暂存文件,思路留存 2025-07-28 14:57:15 +08:00
efe74cba6c [midend-mem2reg]mem2reg遍基本写完,编译不报错,待reg2mem写完统一测试 2025-07-28 14:28:46 +08:00
634a84f29c [peephole]Pass架构重构优化 2025-07-27 11:03:26 +08:00
2dd6a17fca [backend]saving1 2025-07-27 00:34:45 +08:00
78dee0d72a [peephole]添加7项窥孔优化规则初步测试生效成功,有待进一步检查,TODO: 指令调度优化 2025-07-26 21:48:14 +08:00
97 changed files with 5408 additions and 2856 deletions

View File

@ -3,4 +3,244 @@
| 名称 | 优化级别 | 开发进度 |
| ------------ | ------------ | ---------- |
| CFG优化 | 函数级 | 已完成 |
| DCE | 函数级 | 待测试 |
| DCE | 函数级 | 待正确性测试 |
| Mem2Reg | 函数级 | 待正确性测试 |
| Reg2Mem | 函数级 | 待正确性测试 |
# 部分优化遍的说明
## Mem2Reg
Mem2Reg 遍的主要目标是将那些不必要的、只用于局部标量变量的内存分配 (alloca 指令) 消除,并将这些变量的值转换为 SSA 形式。这有助于减少内存访问,提高代码效率,并为后续的优化创造更好的条件。
通过Mem2Reg理解删除指令时对use关系的维护
`Mem2Reg` 优化遍中,当 `load``store` 指令被删除时,其 `use` 关系(即它们作为操作数与其他 `Value` 对象之间的连接)的正确消除是一个关键问题,尤其涉及到 `AllocaInst`
结合您提供的 `Mem2RegContext::renameVariables` 代码和我们之前讨论的 `usedelete` 逻辑,下面是 `use` 关系如何被正确消除的详细过程:
### 问题回顾:`Use` 关系的双向性
在您的 IR 设计中,`Use` 对象扮演着连接 `User`(使用者,如 `LoadInst`)和 `Value`(被使用者,如 `AllocaInst`)的双向角色:
* 一个 `User` 持有对其操作数 `Value``Use` 对象(通过 `User::operands` 列表)。
* 一个 `Value` 持有所有使用它的 `User``Use` 对象(通过 `Value::uses` 列表)。
原始问题是:当一个 `LoadInst``StoreInst` 被删除时,如果不对其作为操作数与 `AllocaInst` 之间的 `Use` 关系进行明确清理,`AllocaInst``uses` 列表中就会留下指向已删除 `LoadInst` / `StoreInst``Use` 对象,导致内部的 `User*` 指针悬空,在后续访问时引发 `segmentation fault`
### `Mem2Reg` 中 `load`/`store` 指令的删除行为
`Mem2RegContext::renameVariables` 函数中,`load``store` 指令被处理时,其行为如下:
1. **处理 `LoadInst`**
当找到一个指向可提升 `AllocaInst``LoadInst` 时,其用途会被 `replaceAllUsesWith(allocaToValueStackMap[alloca].top())` 替换。这意味着任何原本使用 `LoadInst` 本身计算结果的指令,现在都直接使用 SSA 值栈顶部的 `Value`
**重点:** 这一步处理的是 `LoadInst` 作为**被使用的值 (Value)** 时,其 `uses` 列表的清理。即,将 `LoadInst` 的所有使用者重定向到新的 SSA 值,并把这些 `Use` 对象从 `LoadInst``uses` 列表中移除。
2. **处理 `StoreInst`**
当找到一个指向可提升 `AllocaInst``StoreInst` 时,`StoreInst` 存储的值会被压入值栈。`StoreInst` 本身并不产生可被其他指令直接使用的值(其类型是 `void`),所以它没有 `uses` 列表需要替换。
**重点:** `StoreInst` 的主要作用是更新内存状态,在 SSA 形式下,它被移除后需要清理它作为**使用者 (User)** 时的操作数关系。
在这两种情况下,一旦 `load``store` 指令的 SSA 转换完成,它们都会通过 `instIter = SysYIROptUtils::usedelete(instIter)` 被显式删除。
### `SysYIROptUtils::usedelete` 如何正确消除 `Use` 关系
关键在于对 `SysYIROptUtils::usedelete` 函数的修改,使其在删除指令时,同时处理该指令作为 `User``Value` 的两种 `Use` 关系:
1. **清理指令作为 `Value` 时的 `uses` 列表 (由 `replaceAllUsesWith` 完成)**
`usedelete` 函数中,`inst->replaceAllUsesWith(UndefinedValue::get(inst->getType()))` 的调用至关重要。这确保了:
* 如果被删除的 `Instruction`(例如 `LoadInst`)产生了结果值并被其他指令使用,所有这些使用者都会被重定向到 `UndefinedValue`(或者 `Mem2Reg` 中具体的 SSA 值)。
* 这个过程会遍历 `LoadInst``uses` 列表,并将这些 `Use` 对象从 `LoadInst``uses` 列表中移除。这意味着 `LoadInst` 自己不再被任何其他指令使用。
2. **清理指令作为 `User` 时其操作数的 `uses` 列表 (由 `RemoveUserOperandUses` 完成)**
这是您提出的、并已集成到 `usedelete` 中的关键改进点。对于一个被删除的 `Instruction`(它同时也是 `User`),我们需要清理它**自己使用的操作数**所维护的 `use` 关系。
* 例如,`LoadInst %op1` 使用了 `%op1`(一个 `AllocaInst`)。当 `LoadInst` 被删除时,`AllocaInst``uses` 列表中有一个 `Use` 对象指向这个 `LoadInst`
* `RemoveUserOperandUses` 函数会遍历被删除 `User`(即 `LoadInst``StoreInst`)的 `operands` 列表。
* 对于 `operands` 列表中的每个 `std::shared_ptr<Use> use_ptr`,它会获取 `Use` 对象内部指向的 `Value`(例如 `AllocaInst*`),然后调用 `value->removeUse(use_ptr)`
* 这个 `removeUse` 调用会负责将 `use_ptr``AllocaInst``uses` 列表中删除。
### 总结
通过在 `SysYIROptUtils::usedelete` 中同时执行这两个步骤:
* `replaceAllUsesWith`:处理被删除指令**作为结果被使用**时的 `use` 关系。
* `RemoveUserOperandUses`:处理被删除指令**作为使用者User其操作数**的 `use` 关系。
这就确保了当 `Mem2Reg` 遍历并删除 `load``store` 指令时,无论是它们作为 `Value` 的使用者,还是它们作为 `User` 的操作数,所有相关的 `Use` 对象都能被正确地从 `Value``uses` 列表中移除,从而避免了悬空指针和后续的 `segmentation fault`
最后,当所有指向某个 `AllocaInst``load``store` 指令都被移除后,`AllocaInst``uses` 列表将变得干净(只包含 Phi 指令,如果它们在 SSA 转换中需要保留 Alloca 作为操作数),这时在 `Mem2RegContext::cleanup()` 阶段,`SysYIROptUtils::usedelete(alloca)` 就可以安全地删除 `AllocaInst` 本身了。
## Reg2Mem
我们的Reg2Mem 遍的主要目标是作为 Mem2Reg 的一种逆操作,但更具体是解决后端无法识别 PhiInst 指令的问题。主要的速录是将函数参数和 PhiInst 指令的结果从 SSA 形式转换回内存形式,通过插入 alloca、load 和 store 指令来实现。其他非 Phi 的指令结果将保持 SSA 形式。
## SCCP
SCCP稀疏条件常量传播是一种编译器优化技术它结合了常量传播和死代码消除。其核心思想是在程序执行过程中尝试识别并替换那些在编译时就能确定其值的变量常量同时移除那些永远不会被执行到的代码块不可达代码
以下是 SCCP 的实现思路:
1. 核心数据结构与工作列表:
Lattice 值Lattice Value: SCCP 使用三值格Three-Valued Lattice来表示变量的状态
Top (T): 初始状态,表示变量的值未知,但可能是一个常量。
Constant (C): 表示变量的值已经确定为一个具体的常量。
Bottom (⊥): 表示变量的值不确定或不是一个常量(例如,它可能在运行时有多个不同的值,或者从内存中加载)。一旦变量状态变为 Bottom它就不能再变回 Constant 或 Top。
SSAPValue: 封装了 Lattice 值和常量具体值(如果状态是 Constant
*valState (map<Value, SSAPValue>):** 存储程序中每个 Value变量、指令结果等的当前 SCCP Lattice 状态。
*ExecutableBlocks (set<BasicBlock>):** 存储在分析过程中被确定为可执行的基本块。
工作列表 (Worklists):
cfgWorkList (queue<pair<BasicBlock, BasicBlock>>):** 存储待处理的控制流图CFG边。当一个块被标记为可执行时它的后继边会被添加到这个列表。
*ssaWorkList (queue<Instruction>):** 存储待处理的 SSA (Static Single Assignment) 指令。当一个指令的任何操作数的状态发生变化时,该指令就会被添加到这个列表,需要重新评估。
2. 初始化:
所有 Value 的状态都被初始化为 Top。
所有基本块都被初始化为不可执行。
函数的入口基本块被标记为可执行,并且该块中的所有指令被添加到 ssaWorkList。
3. 迭代过程 (Fixed-Point Iteration)
SCCP 的核心是一个迭代过程,它交替处理 CFG 工作列表和 SSA 工作列表,直到达到一个不动点(即没有更多的状态变化)。
处理 cfgWorkList:
从 cfgWorkList 中取出一个边 (prev, next)。
如果 next 块之前是不可执行的,现在通过 prev 块可达,则将其标记为可执行 (markBlockExecutable)。
一旦 next 块变为可执行,其内部的所有指令(特别是 Phi 指令)都需要被重新评估,因此将它们添加到 ssaWorkList。
处理 ssaWorkList:
从 ssaWorkList 中取出一个指令 inst。
重要: 只有当 inst 所在的块是可执行的,才处理该指令。不可执行块中的指令不参与常量传播。
计算新的 Lattice 值 (computeLatticeValue): 根据指令类型和其操作数的当前 Lattice 状态,计算 inst 的新的 Lattice 状态。
常量折叠: 如果所有操作数都是常量,则可以直接执行运算并得到一个新的常量结果。
Bottom 传播: 如果任何操作数是 Bottom或者运算规则导致不确定例如除以零则结果为 Bottom。
Phi 指令的特殊处理: Phi 指令的值取决于其所有可执行的前驱块传入的值。
如果所有可执行前驱都提供了相同的常量 C则 Phi 结果为 C。
如果有任何可执行前驱提供了 Bottom或者不同的可执行前驱提供了不同的常量则 Phi 结果为 Bottom。
如果所有可执行前驱都提供了 Top则 Phi 结果仍为 Top。
更新状态: 如果 inst 的新计算出的 Lattice 值与它当前存储的值不同,则更新 valState[inst]。
传播变化: 如果 inst 的状态发生变化,那么所有使用 inst 作为操作数的指令都可能受到影响,需要重新评估。因此,将 inst 的所有使用者添加到 ssaWorkList。
处理终结符指令 (BranchInst, ReturnInst):
对于条件分支 BranchInst如果其条件操作数变为常量
如果条件为真,则只有真分支的目标块是可达的,将该边添加到 cfgWorkList。
如果条件为假,则只有假分支的目标块是可达的,将该边添加到 cfgWorkList。
如果条件不是常量Top 或 Bottom则两个分支都可能被执行将两边的边都添加到 cfgWorkList。
这会影响 CFG 的可达性分析,可能导致新的块被标记为可执行。
4. 应用优化 (Transformation)
当两个工作列表都为空,达到不动点后,程序代码开始进行实际的修改:
常量替换:
遍历所有指令。如果指令的 valState 为 Constant则用相应的 ConstantValue 替换该指令的所有用途 (replaceAllUsesWith)。
将该指令标记为待删除。
对于指令的操作数,如果其 valState 为 Constant则直接将操作数替换为对应的 ConstantValue常量折叠
删除死指令: 遍历所有标记为待删除的指令,并从其父基本块中删除它们。
删除不可达基本块: 遍历函数中的所有基本块。如果一个基本块没有被标记为可执行 (ExecutableBlocks 中不存在),则将其从函数中删除。但入口块不能删除。
简化分支指令:
遍历所有可执行的基本块的终结符指令。
对于条件分支 BranchInst如果其条件操作数在 valState 中是 Constant
如果条件为真,则将该条件分支替换为一个无条件跳转到真分支目标块的指令。
如果条件为假,则将该条件分支替换为一个无条件跳转到假分支目标块的指令。
更新 CFG移除不可达的分支边和其前驱信息。
computeLatticeValue 的具体逻辑:
这个函数是 SCCP 的核心逻辑,它定义了如何根据指令类型和操作数的当前 Lattice 状态来计算指令结果的 Lattice 状态。
二元运算 (Add, Sub, Mul, Div, Rem, ICmp, And, Or):
如果任何一个操作数是 Bottom结果就是 Bottom。
如果任何一个操作数是 Top结果就是 Top。
如果两个操作数都是 Constant执行实际的常量运算结果是一个新的 Constant。
一元运算 (Neg, Not):
如果操作数是 Bottom结果就是 Bottom。
如果操作数是 Top结果就是 Top。
如果操作数是 Constant执行实际的常量运算结果是一个新的 Constant。
Load 指令: 通常情况下Load 的结果会被标记为 Bottom因为内存内容通常在编译时无法确定。但如果加载的是已知的全局常量可能可以确定。在提供的代码中它通常返回 Bottom。
Store 指令: Store 不产生值,所以其 SSAPValue 保持 Top 或不关心。
Call 指令: 大多数 Call 指令(尤其是对外部或有副作用的函数)的结果都是 Bottom。对于纯函数如果所有参数都是常量理论上可以折叠但这需要额外的分析。
GetElementPtr (GEP) 指令: GEP 计算内存地址。如果所有索引都是常量,地址本身是常量。但 SCCP 关注的是数据值,因此这里通常返回 Bottom除非有特定的指针常量跟踪。
Phi 指令: 如上所述,基于所有可执行前驱的传入值进行聚合。
Alloc 指令: Alloc 分配内存,返回一个指针。其内容通常是 Bottom。
Branch 和 Return 指令: 这些是终结符指令,不产生一个可用于其他指令的值,通常 SSAPValue 保持 Top 或不关心。
类型转换 (ZExt, SExt, Trunc, FtoI, ItoF): 如果操作数是 Constant则执行相应的类型转换结果仍为 Constant。对于浮点数转换由于 SSAPValue 的 constantVal 为 int 类型,所以对浮点数的操作会保守地返回 Bottom。
未处理的指令: 默认情况下,任何未明确处理的指令都被保守地假定为产生 Bottom 值。
浮点数处理的注意事项:
在提供的代码中SSAPValue 的 constantVal 是 int 类型。这使得浮点数常量传播变得复杂。对于浮点数相关的指令kFAdd, kFMul, kFCmp, kFNeg, kFNot, kItoF, kFtoI 等),如果不能将浮点值准确地存储在 int 中,或者不能可靠地执行浮点运算,那么通常会保守地将结果设置为 Bottom。一个更完善的 SCCP 实现会使用 std::variant<int, float> 或独立的浮点常量存储来处理浮点数。
# 后续优化可能涉及的改动
## 1将所有的alloca集中到entryblock中
好处优化友好性方便mem2reg提升
目前没有实现这个机制,如果想要实现首先解决同一函数不同域的同名变量命名区分
需要保证符号表能正确维护域中的局部变量
# 关于中端优化提升编译器性能的TODO
## usedelete_withinstdelte方法
这个方法删除了use关系并移除了指令逻辑是根据Instruction* inst去find对应的迭代器并erase
有些情况下外部持有迭代器和inst,可以省略find过程

View File

@ -14,6 +14,7 @@ TESTDATA_DIR="${SCRIPT_DIR}/testdata" # 用于查找 .in/.out 文件
GCC_NATIVE="gcc" # VM 内部的原生 gcc
# --- 初始化变量 ---
CLEAN_MODE=false
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
EXEC_TIMEOUT=5 # 程序自动化执行超时 (秒)
MAX_OUTPUT_LINES=50 # 对比失败时显示的最大行数
@ -29,6 +30,7 @@ show_help() {
echo "如果找到对应的 .in/.out 文件,则进行自动化测试。否则,进入交互模式。"
echo ""
echo "选项:"
echo " -c, --clean 清理 tmp 临时目录下的所有文件。"
echo " -ct N 设置 gcc 编译超时为 N 秒 (默认: 10)。"
echo " -t N 设置程序自动化执行超时为 N 秒 (默认: 5)。"
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 50)。"
@ -57,10 +59,24 @@ display_file_content() {
fi
}
# --- 新增功能: 清理临时文件的函数 ---
clean_tmp() {
echo "正在清理临时目录: ${TMP_DIR}"
if [ -d "${TMP_DIR}" ]; then
rm -rf "${TMP_DIR}"/* 2>/dev/null
echo "清理完成。"
else
echo "临时目录 ${TMP_DIR} 不存在,无需清理。"
fi
}
# --- 参数解析 ---
# 从参数中分离出 .s 文件和选项
for arg in "$@"; do
case "$arg" in
-c|--clean)
CLEAN_MODE=true
;;
-ct|-t|-ml|--max-lines)
# 选项和其值将在下一个循环中处理
;;
@ -74,6 +90,7 @@ for arg in "$@"; do
args_processed=true # 标记已处理过参数
while [[ "$#" -gt 0 ]]; do
case "$1" in
-c|--clean) ;; # 已在外部处理
-ct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift; else echo "错误: -ct 需要一个正整数参数。" >&2; exit 1; fi ;;
-t) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift; else echo "错误: -t 需要一个正整数参数。" >&2; exit 1; fi ;;
-ml|--max-lines) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi ;;
@ -95,6 +112,14 @@ for arg in "$@"; do
done
# --- 主逻辑开始 ---
if ${CLEAN_MODE}; then
clean_tmp
# 如果只提供了 -c 选项,则退出
if [ ${#S_FILES[@]} -eq 0 ]; then
exit 0
fi
fi
if [ ${#S_FILES[@]} -eq 0 ]; then
echo "错误: 未提供任何 .s 文件作为输入。"
show_help
@ -162,14 +187,17 @@ for s_file in "${S_FILES[@]}"; do
EXPECTED_STDOUT_FILE="${TMP_DIR}/${base_name_from_s_file}.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
if ! diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
# --- 本次修改点: 使用 tr 删除所有空白字符后再比较 ---
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 ! diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${output_reference_file}") >/dev/null 2>&1; then
# --- 本次修改点: 使用 tr 删除所有空白字符后再比较 ---
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

View File

@ -175,7 +175,8 @@ while IFS= read -r s_file; do
is_passed=0
fi
if ! diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
# --- 本次修改点: 使用 tr 删除所有空白字符后再比较 ---
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}"
@ -186,7 +187,9 @@ while IFS= read -r s_file; do
if [ $ACTUAL_RETURN_CODE -ne 0 ]; then
echo -e "\e[33m警告: 程序以非零状态 ${ACTUAL_RETURN_CODE} 退出 (纯输出比较模式)。\e[0m"
fi
if ! diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${output_reference_file}") >/dev/null 2>&1; then
# --- 本次修改点: 使用 tr 删除所有空白字符后再比较 ---
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"

View File

@ -20,6 +20,7 @@ QEMU_RISCV64="qemu-riscv64"
# --- 初始化变量 ---
EXECUTE_MODE=false
CLEAN_MODE=false
SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒)
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
EXEC_TIMEOUT=5 # qemu 自动化执行超时 (秒)
@ -37,6 +38,7 @@ show_help() {
echo ""
echo "选项:"
echo " -e, --executable 编译为可执行文件并运行测试 (必须)。"
echo " -c, --clean 清理 tmp 临时目录下的所有文件。"
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 10)。"
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
echo " -et N 设置 qemu 自动化执行超时为 N 秒 (默认: 5)。"
@ -74,6 +76,10 @@ for arg in "$@"; do
-e|--executable)
EXECUTE_MODE=true
;;
-c|--clean)
CLEAN_MODE=true
shift
;;
-sct|-gct|-et|-ml|--max-lines)
# 选项和其值将在下一个循环中处理
;;
@ -110,6 +116,23 @@ for arg in "$@"; do
esac
done
if ${CLEAN_MODE}; then
echo "检测到 -c/--clean 选项,正在清空 ${TMP_DIR}..."
if [ -d "${TMP_DIR}" ]; then
# 使用 * 而不是 . 来确保只删除内容,不删除目录本身
# 忽略 rm 可能因目录为空而报告的错误
rm -rf "${TMP_DIR}"/* 2>/dev/null
echo "清理完成。"
else
echo "临时目录 ${TMP_DIR} 不存在,无需清理。"
fi
# 如果只提供了 -c 选项而没有其他 .sy 文件,则在清理后退出
if [ ${#SY_FILES[@]} -eq 0 ] && ! ${EXECUTE_MODE}; then
exit 0
fi
fi
# --- 主逻辑开始 ---
if ! ${EXECUTE_MODE}; then
echo "错误: 请提供 -e 或 --executable 选项来运行测试。"
@ -138,6 +161,7 @@ for sy_file in "${SY_FILES[@]}"; do
ir_file="${TMP_DIR}/${base_name}_sysyc_riscv64.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"
@ -162,6 +186,7 @@ for sy_file in "${SY_FILES[@]}"; do
echo -e "\e[31m错误: SysY 编译失败或超时。\e[0m"
is_passed=0
fi
# timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s asmd "${sy_file}" > "${assembly_debug_file}" 2>&1
# 步骤 2: GCC 编译
if [ "$is_passed" -eq 1 ]; then
@ -200,21 +225,22 @@ for sy_file in "${SY_FILES[@]}"; do
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
if ! diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
# --- 本次修改点: 使用 tr 删除所有空白字符后再比较 ---
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 ! diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${output_reference_file}") >/dev/null 2>&1; then
# --- 本次修改点: 使用 tr 删除所有空白字符后再比较 ---
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"
@ -236,7 +262,6 @@ for sy_file in "${SY_FILES[@]}"; do
"${QEMU_RISCV64}" "${executable_file}"
INTERACTIVE_RET_CODE=$?
echo -e "\e[33m\n 交互模式执行完毕,程序返回码: ${INTERACTIVE_RET_CODE}\e[0m"
# 交互模式无法自动判断对错,默认算通过,但会提示
echo " 注意: 交互模式的结果未经验证。"
fi
fi

View File

@ -203,7 +203,9 @@ while IFS= read -r sy_file; do
echo -e "\e[31m 返回码测试失败: 期望: ${EXPECTED_RETURN_CODE}, 实际: ${ACTUAL_RETURN_CODE}\e[0m"
is_passed=0
fi
if ! diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
# --- 本次修改点: 使用 tr 删除所有空白字符后再比较 ---
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}"
@ -214,7 +216,9 @@ while IFS= read -r sy_file; do
if [ $ACTUAL_RETURN_CODE -ne 0 ]; then
echo -e "\e[33m警告: 程序以非零状态 ${ACTUAL_RETURN_CODE} 退出 (纯输出比较模式)。\e[0m"
fi
if ! diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${output_reference_file}") >/dev/null 2>&1; then
# --- 本次修改点: 使用 tr 删除所有空白字符后再比较 ---
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"

View File

@ -1,171 +0,0 @@
#include "AddressCalculationExpansion.h"
#include <iostream>
#include <vector>
#include "IR.h"
#include "IRBuilder.h"
extern int DEBUG;
namespace sysy {
bool AddressCalculationExpansion::run() {
bool changed = false;
for (auto& funcPair : pModule->getFunctions()) {
Function* func = funcPair.second.get();
for (auto& bb_ptr : func->getBasicBlocks()) {
BasicBlock* bb = bb_ptr.get();
for (auto it = bb->getInstructions().begin(); it != bb->getInstructions().end(); ) {
Instruction* inst = it->get();
Value* basePointer = nullptr;
Value* valueToStore = nullptr;
size_t firstIndexOperandIdx = 0;
size_t numBaseOperands = 0;
if (inst->isLoad()) {
numBaseOperands = 1;
basePointer = inst->getOperand(0);
firstIndexOperandIdx = 1;
} else if (inst->isStore()) {
numBaseOperands = 2;
valueToStore = inst->getOperand(0);
basePointer = inst->getOperand(1);
firstIndexOperandIdx = 2;
} else {
++it;
continue;
}
if (inst->getNumOperands() <= numBaseOperands) {
++it;
continue;
}
std::vector<int> dims;
if (AllocaInst* allocaInst = dynamic_cast<AllocaInst*>(basePointer)) {
for (const auto& use_ptr : allocaInst->getDims()) {
Value* dimValue = use_ptr->getValue();
if (ConstantValue* constVal = dynamic_cast<ConstantValue*>(dimValue)) {
dims.push_back(constVal->getInt());
} else {
std::cerr << "Warning: AllocaInst dimension is not a constant integer. Skipping GEP expansion for: ";
SysYPrinter::printValue(allocaInst);
std::cerr << "\n";
dims.clear();
break;
}
}
} else if (GlobalValue* globalValue = dynamic_cast<GlobalValue*>(basePointer)) {
// 遍历 GlobalValue 的所有维度操作数
for (const auto& use_ptr : globalValue->getDims()) {
Value* dimValue = use_ptr->getValue();
// 将维度值转换为常量整数
if (ConstantInteger* constVal = dynamic_cast<ConstantInteger*>(dimValue)) {
dims.push_back(constVal->getInt());
} else {
// 如果维度不是常量整数,则无法处理。
// 根据 IR.h 中 GlobalValue 的构造函数,这种情况不应发生,但作为安全检查是好的。
std::cerr << "Warning: GlobalValue dimension is not a constant integer. Skipping GEP expansion for: ";
SysYPrinter::printValue(globalValue);
std::cerr << "\n";
dims.clear(); // 清空已收集的部分维度信息
break;
}
}
} else {
std::cerr << "Warning: Base pointer is not AllocaInst/GlobalValue or its array dimensions cannot be determined for GEP expansion. Skipping GEP for: ";
SysYPrinter::printValue(basePointer);
std::cerr << " in instruction ";
SysYPrinter::printInst(inst);
std::cerr << "\n";
++it;
continue;
}
if (dims.empty() && (inst->getNumOperands() > numBaseOperands)) {
if (DEBUG) {
std::cerr << "ACE Warning: Could not get valid array dimensions for ";
SysYPrinter::printValue(basePointer);
std::cerr << " in instruction ";
SysYPrinter::printInst(inst);
std::cerr << " (expected dimensions for indices, but got none).\n";
}
++it;
continue;
}
std::vector<Value*> indexOperands;
for (size_t i = firstIndexOperandIdx; i < inst->getNumOperands(); ++i) {
indexOperands.push_back(inst->getOperand(i));
}
if (AllocaInst* allocaInst = dynamic_cast<AllocaInst*>(basePointer)) {
if (allocaInst->getNumDims() != indexOperands.size()) {
if (DEBUG) {
std::cerr << "ACE Warning: Index count (" << indexOperands.size() << ") does not match AllocaInst dimensions (" << allocaInst->getNumDims() << ") for instruction ";
SysYPrinter::printInst(inst);
std::cerr << "\n";
}
++it;
continue;
}
}
Value* totalOffset = ConstantInteger::get(0);
pBuilder->setPosition(bb, it);
for (size_t i = 0; i < indexOperands.size(); ++i) {
Value* index = indexOperands[i];
int stride = calculateStride(dims, i);
Value* strideConst = ConstantInteger::get(stride);
Type* intType = Type::getIntType();
BinaryInst* currentDimOffsetInst = pBuilder->createBinaryInst(Instruction::kMul, intType, index, strideConst);
BinaryInst* newTotalOffsetInst = pBuilder->createBinaryInst(Instruction::kAdd, intType, totalOffset, currentDimOffsetInst);
totalOffset = newTotalOffsetInst;
}
// 计算有效地址effective_address = basePointer + totalOffset
Value* effective_address = pBuilder->createBinaryInst(Instruction::kAdd, basePointer->getType(), basePointer, totalOffset);
// 创建新的 LoadInst 或 StoreInstindices 为空
Instruction* newInst = nullptr;
if (inst->isLoad()) {
newInst = pBuilder->createLoadInst(effective_address, {});
inst->replaceAllUsesWith(newInst);
} else { // StoreInst
newInst = pBuilder->createStoreInst(valueToStore, effective_address, {});
}
Instruction* oldInst = it->get();
++it;
for (size_t i = 0; i < oldInst->getNumOperands(); ++i) {
Value* operandValue = oldInst->getOperand(i);
if (operandValue) {
for (auto use_it = operandValue->getUses().begin(); use_it != operandValue->getUses().end(); ++use_it) {
if ((*use_it)->getUser() == oldInst && (*use_it)->getIndex() == i) {
operandValue->removeUse(*use_it);
break;
}
}
}
}
bb->getInstructions().erase(std::prev(it));
changed = true;
if (DEBUG) {
std::cerr << "ACE: Computed effective address:\n";
SysYPrinter::printInst(dynamic_cast<Instruction*>(effective_address));
std::cerr << "ACE: New Load/Store instruction:\n";
SysYPrinter::printInst(newInst);
std::cerr << "--------------------------------\n";
}
}
}
}
return changed;
}
} // namespace sysy

View File

@ -1,55 +1,24 @@
# 移除 ANTLR 代码生成相关配置
# list(APPEND CMAKE_MODULE_PATH "${ANTLR_RUNTIME}/cmake")
# include(FindANTLR)
# antlr_target(SysYGen SysY.g4
# LEXER PARSER
# OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
# VISITOR
# )
# src/CMakeLists.txt
# add_subdirectory 命令会负责遍历子目录并查找其内部的 CMakeLists.txt 文件
add_subdirectory(frontend)
add_subdirectory(midend)
add_subdirectory(backend/RISCv64)
# 移除 SysYParser 库的构建(如果不需要独立库)
# add_library(SysYParser SHARED ${ANTLR_SysYGen_CXX_OUTPUTS})
# target_include_directories(SysYParser PUBLIC ${ANTLR_RUNTIME}/runtime/src)
# target_link_libraries(SysYParser PUBLIC antlr4_shared)
# 构建 sysyc 可执行文件,使用手动提供的 SysYLexer.cpp、SysYParser.cpp 等文件
# 构建 sysyc 可执行文件,链接各个模块的库
add_executable(sysyc
sysyc.cpp
SysYLexer.cpp # 手动提供的文件
SysYParser.cpp # 手动提供的文件
SysYVisitor.cpp # 手动提供的文件
IR.cpp
SysYIRGenerator.cpp
SysYIRPrinter.cpp
SysYIRCFGOpt.cpp
Pass.cpp
Dom.cpp
Liveness.cpp
DCE.cpp
AddressCalculationExpansion.cpp
# Mem2Reg.cpp
# Reg2Mem.cpp
RISCv64Backend.cpp
RISCv64ISel.cpp
RISCv64RegAlloc.cpp
RISCv64AsmPrinter.cpp
RISCv64Passes.cpp
RISCv64LLIR.cpp
sysyc.cpp
)
# 设置 include 路径,包含 ANTLR 运行时库和项目头文件
# 链接各个模块的库
target_link_libraries(sysyc PRIVATE
frontend_lib
midend_lib
riscv64_backend_lib
antlr4_shared
)
# 设置 include 路径,包含项目顶层 include 目录
target_include_directories(sysyc PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include # 项目头文件目录
${ANTLR_RUNTIME}/runtime/src # ANTLR 运行时库头文件
)
# 保留 ANTLR 运行时库的链接
target_link_libraries(sysyc PRIVATE antlr4_shared)
# 保留其他编译选项
target_compile_options(sysyc PRIVATE -frtti)
# 可选:线程支持(如果需要,取消注释)
# set(THREADS_PREFER_PTHREAD_FLAG ON)
# find_package(Threads REQUIRED)
# target_link_libraries(sysyc PRIVATE Threads::Threads)
${CMAKE_CURRENT_SOURCE_DIR}/include # 项目头文件目录
${ANTLR_RUNTIME}/runtime/src # ANTLR运行时库头文件
)

View File

@ -1,529 +0,0 @@
#include "SysYIRAnalyser.h"
#include <iostream>
namespace sysy {
void ControlFlowAnalysis::init() {
// 初始化分析器
auto &functions = pModule->getFunctions();
for (const auto &function : functions) {
auto func = function.second.get();
auto basicBlocks = func->getBasicBlocks();
for (auto &basicBlock : basicBlocks) {
blockAnalysisInfo[basicBlock.get()] = new BlockAnalysisInfo();
blockAnalysisInfo[basicBlock.get()]->clear();
}
functionAnalysisInfo[func] = new FunctionAnalysisInfo();
functionAnalysisInfo[func]->clear();
}
}
void ControlFlowAnalysis::runControlFlowAnalysis() {
// 运行控制流分析
clear(); // 清空之前的分析结果
init(); // 初始化分析器
computeDomNode();
computeDomTree();
computeDomFrontierAllBlk();
}
void ControlFlowAnalysis::intersectOP4Dom(std::unordered_set<BasicBlock *> &dom, const std::unordered_set<BasicBlock *> &other) {
// 计算交集
for (auto it = dom.begin(); it != dom.end();) {
if (other.find(*it) == other.end()) {
// 如果other中没有这个基本块则从dom中删除
it = dom.erase(it);
} else {
++it;
}
}
}
auto ControlFlowAnalysis::findCommonDominator(BasicBlock *a, BasicBlock *b) -> BasicBlock * {
// 查找两个基本块的共同支配结点
while (a != b) {
BlockAnalysisInfo* infoA = blockAnalysisInfo[a];
BlockAnalysisInfo* infoB = blockAnalysisInfo[b];
// 如果深度不同,则向上移动到直接支配结点
// TODO空间换时间倍增优化优先级较低
while (infoA->getDomDepth() > infoB->getDomDepth()) {
a = const_cast<BasicBlock*>(infoA->getIdom());
infoA = blockAnalysisInfo[a];
}
while (infoB->getDomDepth() > infoA->getDomDepth()) {
b = const_cast<BasicBlock*>(infoB->getIdom());
infoB = blockAnalysisInfo[b];
}
if (a == b) break;
a = const_cast<BasicBlock*>(infoA->getIdom());
b = const_cast<BasicBlock*>(infoB->getIdom());
}
return a;
}
void ControlFlowAnalysis::computeDomNode(){
auto &functions = pModule->getFunctions();
// 分析每个函数内的基本块
for (const auto &function : functions) {
auto func = function.second.get();
auto basicBlocks = func->getBasicBlocks();
std::unordered_set<BasicBlock *> domSetTmp;
// 一开始把domSetTmp置为所有block
auto entry_block = func->getEntryBlock();
entry_block->setName("Entry");
blockAnalysisInfo[entry_block]->addDominants(entry_block);
for (auto &basicBlock : basicBlocks) {
domSetTmp.emplace(basicBlock.get());
}
// 初始化
for (auto &basicBlock : basicBlocks) {
if (basicBlock.get() != entry_block) {
blockAnalysisInfo[basicBlock.get()]->setDominants(domSetTmp);
// 先把所有block的必经结点都设为N
}
}
// 支配节点计算公式
//DOM[B]={B} {⋂P∈pred(B) DOM[P]}
// 其中pred(B)是B的所有前驱结点
// 迭代计算支配结点,直到不再变化
// 这里使用迭代法,直到支配结点不再变化
// TODOLengauer-Tarjan 算法可以更高效地计算支配结点
// 或者按照CFG拓扑序遍历效率更高
bool changed = true;
while (changed) {
changed = false;
// 循环非start结点
for (auto &basicBlock : basicBlocks) {
if (basicBlock.get() != entry_block) {
auto olddom =
blockAnalysisInfo[basicBlock.get()]->getDominants();
std::unordered_set<BasicBlock *> dom =
blockAnalysisInfo[basicBlock->getPredecessors().front()]->getDominants();
// 对于每个基本块,计算其支配结点
// 取其前驱结点的支配结点的交集和自己
for (auto pred : basicBlock->getPredecessors()) {
intersectOP4Dom(dom, blockAnalysisInfo[pred]->getDominants());
}
dom.emplace(basicBlock.get());
blockAnalysisInfo[basicBlock.get()]->setDominants(dom);
if (dom != olddom) {
changed = true;
}
}
}
}
}
}
// TODO SEMI-NCA算法改进
void ControlFlowAnalysis::computeDomTree() {
// 构造支配树
auto &functions = pModule->getFunctions();
for (const auto &function : functions) {
auto func = function.second.get();
auto basicBlocks = func->getBasicBlocks();
auto entry_block = func->getEntryBlock();
blockAnalysisInfo[entry_block]->setIdom(entry_block);
blockAnalysisInfo[entry_block]->setDomDepth(0); // 入口块深度为0
bool changed = true;
while (changed) {
changed = false;
for (auto &basicBlock : basicBlocks) {
if (basicBlock.get() == entry_block) continue;
BasicBlock *new_idom = nullptr;
for (auto pred : basicBlock->getPredecessors()) {
// 跳过未处理的前驱
if (blockAnalysisInfo[pred]->getIdom() == nullptr) continue;
// new_idom = (new_idom == nullptr) ? pred : findCommonDominator(new_idom, pred);
if (new_idom == nullptr)
new_idom = pred;
else
new_idom = findCommonDominator(new_idom, pred);
}
// 更新直接支配节点
if (new_idom && new_idom != blockAnalysisInfo[basicBlock.get()]->getIdom()) {
// 移除旧的支配关系
if (blockAnalysisInfo[basicBlock.get()]->getIdom()) {
blockAnalysisInfo[const_cast<BasicBlock*>(blockAnalysisInfo[basicBlock.get()]->getIdom())]->removeSdoms(basicBlock.get());
}
// 设置新的支配关系
// std::cout << "Block: " << basicBlock->getName()
// << " New Idom: " << new_idom->getName() << std::endl;
blockAnalysisInfo[basicBlock.get()]->setIdom(new_idom);
blockAnalysisInfo[new_idom]->addSdoms(basicBlock.get());
// 更新深度 = 直接支配节点深度 + 1
blockAnalysisInfo[basicBlock.get()]->setDomDepth(
blockAnalysisInfo[new_idom]->getDomDepth() + 1);
changed = true;
}
}
}
}
// for (auto &basicBlock : basicBlocks) {
// if (basicBlock.get() != func->getEntryBlock()) {
// auto dominats =
// blockAnalysisInfo[basicBlock.get()]->getDominants();
// bool found = false;
// // 从前驱结点开始寻找直接支配结点
// std::queue<BasicBlock *> q;
// for (auto pred : basicBlock->getPredecessors()) {
// q.push(pred);
// }
// // BFS遍历前驱结点直到找到直接支配结点
// while (!found && !q.empty()) {
// auto curr = q.front();
// q.pop();
// if (curr == basicBlock.get())
// continue;
// if (dominats.count(curr) != 0U) {
// blockAnalysisInfo[basicBlock.get()]->setIdom(curr);
// blockAnalysisInfo[curr]->addSdoms(basicBlock.get());
// found = true;
// } else {
// for (auto pred : curr->getPredecessors()) {
// q.push(pred);
// }
// }
// }
// }
// }
}
// std::unordered_set<BasicBlock *> ControlFlowAnalysis::computeDomFrontier(BasicBlock *block) {
// std::unordered_set<BasicBlock *> ret_list;
// // 计算 localDF
// for (auto local_successor : block->getSuccessors()) {
// if (local_successor->getIdom() != block) {
// ret_list.emplace(local_successor);
// }
// }
// // 计算 upDF
// for (auto up_successor : block->getSdoms()) {
// auto childrenDF = computeDF(up_successor);
// for (auto w : childrenDF) {
// if (block != w->getIdom() || block == w) {
// ret_list.emplace(w);
// }
// }
// }
// return ret_list;
// }
void ControlFlowAnalysis::computeDomFrontierAllBlk() {
auto &functions = pModule->getFunctions();
for (const auto &function : functions) {
auto func = function.second.get();
auto basicBlocks = func->getBasicBlocks();
// 按支配树深度排序(从深到浅)
std::vector<BasicBlock *> orderedBlocks;
for (auto &bb : basicBlocks) {
orderedBlocks.push_back(bb.get());
}
std::sort(orderedBlocks.begin(), orderedBlocks.end(),
[this](BasicBlock *a, BasicBlock *b) {
return blockAnalysisInfo[a]->getDomDepth() > blockAnalysisInfo[b]->getDomDepth();
});
// 计算支配边界
for (auto block : orderedBlocks) {
std::unordered_set<BasicBlock *> df;
// Local DF: 直接后继中不被当前块支配的
for (auto succ : block->getSuccessors()) {
// 当前块不支配该后继(即不是其直接支配节点)
if (blockAnalysisInfo[succ]->getIdom() != block) {
df.insert(succ);
}
}
// Up DF: 从支配子树中继承
for (auto child : blockAnalysisInfo[block]->getSdoms()) {
for (auto w : blockAnalysisInfo[child]->getDomFrontiers()) {
// 如果w不被当前块支配
if (block != blockAnalysisInfo[w]->getIdom()) {
df.insert(w);
}
}
}
blockAnalysisInfo[block]->setDomFrontiers(df);
}
}
}
// ==========================
// dataflow analysis utils
// ==========================
// 先引用学长的代码
// TODO: Worklist 增加逆后序遍历机制
void DataFlowAnalysisUtils::forwardAnalyze(Module *pModule){
std::map<DataFlowAnalysis *, bool> workAnalysis;
for (auto &dataflow : forwardAnalysisList) {
dataflow->init(pModule);
}
for (const auto &function : pModule->getFunctions()) {
for (auto &dataflow : forwardAnalysisList) {
workAnalysis.emplace(dataflow, false);
}
while (!workAnalysis.empty()) {
for (const auto &block : function.second->getBasicBlocks()) {
for (auto &elem : workAnalysis) {
if (elem.first->analyze(pModule, block.get())) {
elem.second = true;
}
}
}
std::map<DataFlowAnalysis *, bool> tmp;
std::remove_copy_if(workAnalysis.begin(), workAnalysis.end(), std::inserter(tmp, tmp.end()),
[](const std::pair<DataFlowAnalysis *, bool> &elem) -> bool { return !elem.second; });
workAnalysis.swap(tmp);
for (auto &elem : workAnalysis) {
elem.second = false;
}
}
}
}
void DataFlowAnalysisUtils::backwardAnalyze(Module *pModule) {
std::map<DataFlowAnalysis *, bool> workAnalysis;
for (auto &dataflow : backwardAnalysisList) {
dataflow->init(pModule);
}
for (const auto &function : pModule->getFunctions()) {
for (auto &dataflow : backwardAnalysisList) {
workAnalysis.emplace(dataflow, false);
}
while (!workAnalysis.empty()) {
for (const auto &block : function.second->getBasicBlocks()) {
for (auto &elem : workAnalysis) {
if (elem.first->analyze(pModule, block.get())) {
elem.second = true;
}
}
}
std::map<DataFlowAnalysis *, bool> tmp;
std::remove_copy_if(workAnalysis.begin(), workAnalysis.end(), std::inserter(tmp, tmp.end()),
[](const std::pair<DataFlowAnalysis *, bool> &elem) -> bool { return !elem.second; });
workAnalysis.swap(tmp);
for (auto &elem : workAnalysis) {
elem.second = false;
}
}
}
}
std::set<User *> ActiveVarAnalysis::getUsedSet(Instruction *inst) {
using Kind = Instruction::Kind;
std::vector<User *> operands;
for (const auto &operand : inst->getOperands()) {
operands.emplace_back(dynamic_cast<User *>(operand->getValue()));
}
std::set<User *> result;
switch (inst->getKind()) {
// phi op
case Kind::kPhi:
case Kind::kCall:
result.insert(std::next(operands.begin()), operands.end());
break;
case Kind::kCondBr:
result.insert(operands[0]);
break;
case Kind::kBr:
case Kind::kAlloca:
break;
// mem op
case Kind::kStore:
// StoreInst 的第一个操作数是被存储的值,第二个操作数是存储的变量
// 后续的是可能的数组维度
result.insert(operands[0]);
result.insert(operands.begin() + 2, operands.end());
break;
case Kind::kLoad:
case Kind::kLa: {
auto variable = dynamic_cast<AllocaInst *>(operands[0]);
auto global = dynamic_cast<GlobalValue *>(operands[0]);
auto constArray = dynamic_cast<ConstantVariable *>(operands[0]);
if ((variable != nullptr && variable->getNumDims() == 0) || (global != nullptr && global->getNumDims() == 0) ||
(constArray != nullptr && constArray->getNumDims() == 0)) {
result.insert(operands[0]);
}
result.insert(std::next(operands.begin()), operands.end());
break;
}
case Kind::kGetSubArray: {
for (unsigned i = 2; i < operands.size(); i++) {
// 数组的维度信息
result.insert(operands[i]);
}
break;
}
case Kind::kMemset: {
result.insert(std::next(operands.begin()), operands.end());
break;
}
case Kind::kInvalid:
// Binary
case Kind::kAdd:
case Kind::kSub:
case Kind::kMul:
case Kind::kDiv:
case Kind::kRem:
case Kind::kICmpEQ:
case Kind::kICmpNE:
case Kind::kICmpLT:
case Kind::kICmpLE:
case Kind::kICmpGT:
case Kind::kICmpGE:
case Kind::kFAdd:
case Kind::kFSub:
case Kind::kFMul:
case Kind::kFDiv:
case Kind::kFCmpEQ:
case Kind::kFCmpNE:
case Kind::kFCmpLT:
case Kind::kFCmpLE:
case Kind::kFCmpGT:
case Kind::kFCmpGE:
case Kind::kAnd:
case Kind::kOr:
// Unary
case Kind::kNeg:
case Kind::kNot:
case Kind::kFNot:
case Kind::kFNeg:
case Kind::kFtoI:
case Kind::kItoF:
// terminator
case Kind::kReturn:
result.insert(operands.begin(), operands.end());
break;
default:
assert(false);
break;
}
result.erase(nullptr);
return result;
}
User * ActiveVarAnalysis::getDefine(Instruction *inst) {
User *result = nullptr;
if (inst->isStore()) {
StoreInst* store = dynamic_cast<StoreInst *>(inst);
auto operand = store->getPointer();
AllocaInst* variable = dynamic_cast<AllocaInst *>(operand);
GlobalValue* global = dynamic_cast<GlobalValue *>(operand);
if ((variable != nullptr && variable->getNumDims() != 0) || (global != nullptr && global->getNumDims() != 0)) {
// 如果是数组变量或者全局变量,则不返回定义
// TODO兼容数组变量
result = nullptr;
} else {
result = dynamic_cast<User *>(operand);
}
} else if (inst->isPhi()) {
result = dynamic_cast<User *>(inst->getOperand(0));
} else if (inst->isBinary() || inst->isUnary() || inst->isCall() ||
inst->isLoad() || inst->isLa()) {
result = dynamic_cast<User *>(inst);
}
return result;
}
void ActiveVarAnalysis::init(Module *pModule) {
for (const auto &function : pModule->getFunctions()) {
for (const auto &block : function.second->getBasicBlocks()) {
activeTable.emplace(block.get(), std::vector<std::set<User *>>{});
for (unsigned i = 0; i < block->getNumInstructions() + 1; i++)
activeTable.at(block.get()).emplace_back();
}
}
}
// 活跃变量分析公式 每个块内的分析动作供分析器调用
bool ActiveVarAnalysis::analyze(Module *pModule, BasicBlock *block) {
bool changed = false; // 标记数据流结果是否有变化
std::set<User *> activeSet{}; // 当前计算的活跃变量集合
// 步骤1: 计算基本块出口的活跃变量集 (OUT[B])
// 公式: OUT[B] = _{S ∈ succ(B)} IN[S]
for (const auto &succ : block->getSuccessors()) {
// 获取后继块入口的活跃变量集 (IN[S])
auto succActiveSet = activeTable.at(succ).front();
// 合并所有后继块的入口活跃变量
activeSet.insert(succActiveSet.begin(), succActiveSet.end());
}
// 步骤2: 处理基本块出口处的活跃变量集
const auto &instructions = block->getInstructions();
const auto numInstructions = instructions.size();
// 获取旧的出口活跃变量集 (block出口对应索引numInstructions)
const auto &oldEndActiveSet = activeTable.at(block)[numInstructions];
// 检查出口活跃变量集是否有变化
if (!std::equal(activeSet.begin(), activeSet.end(),
oldEndActiveSet.begin(), oldEndActiveSet.end()))
{
changed = true; // 标记变化
activeTable.at(block)[numInstructions] = activeSet; // 更新出口活跃变量集
}
// 步骤3: 逆序遍历基本块中的指令
// 从最后一条指令开始向前计算每个程序点的活跃变量
auto instructionIter = instructions.end();
instructionIter--; // 指向最后一条指令
// 从出口向入口遍历 (索引从numInstructions递减到1)
for (unsigned i = numInstructions; i > 0; i--) {
auto inst = instructionIter->get(); // 当前指令
auto used = getUsedSet(inst);
User *defined = getDefine(inst);
// 步骤3.3: 计算指令入口的活跃变量 (IN[i])
// 公式: IN[i] = use_i (OUT[i] - def_i)
activeSet.erase(defined); // 移除被定义的变量 (OUT[i] - def_i)
activeSet.insert(used.begin(), used.end()); // 添加使用的变量
// 获取旧的入口活跃变量集 (位置i-1对应当前指令的入口)
const auto &oldActiveSet = activeTable.at(block)[i - 1];
// 检查活跃变量集是否有变化
if (!std::equal(activeSet.begin(), activeSet.end(),
oldActiveSet.begin(), oldActiveSet.end()))
{
changed = true; // 标记变化
activeTable.at(block)[i - 1] = activeSet; // 更新入口活跃变量集
}
instructionIter--; // 移动到前一条指令
}
return changed; // 返回数据流结果是否变化
}
} // namespace sysy

View File

@ -1,36 +0,0 @@
// PassManager.cpp
#include "SysYIRPassManager.h"
#include <iostream>
namespace sysy {
void PassManager::run(Module& M) {
// 首先运行Module级别的Pass
for (auto& pass : modulePasses) {
std::cout << "Running Module Pass: " << pass->getPassName() << std::endl;
pass->runOnModule(M);
}
// 然后对每个函数运行Function级别的Pass
auto& functions = M.getFunctions();
for (auto& pair : functions) {
Function& F = *(pair.second); // 获取Function的引用
std::cout << " Processing Function: " << F.getName() << std::endl;
// 在每个函数上运行FunctionPasses
bool changedInFunction;
do {
changedInFunction = false;
for (auto& pass : functionPasses) {
// 对于FunctionPasses可以考虑一个迭代执行的循环直到稳定
std::cout << " Running Function Pass: " << pass->getPassName() << std::endl;
changedInFunction |= pass->runOnFunction(F);
}
} while (changedInFunction); // 循环直到函数稳定这模拟了您SysYCFGOpt的while(changed)逻辑
}
// 分析Pass的运行可以在其他Pass需要时触发或者在特定的PassManager阶段触发
// 对于依赖于分析结果的Pass可以在其run方法中通过PassManager::getAnalysis()来获取
}
} // namespace sysy

View File

@ -0,0 +1,23 @@
# src/backend/RISCv64/CMakeLists.txt
add_library(riscv64_backend_lib STATIC
RISCv64AsmPrinter.cpp
RISCv64Backend.cpp
RISCv64ISel.cpp
RISCv64LLIR.cpp
RISCv64RegAlloc.cpp
Handler/CalleeSavedHandler.cpp
Handler/LegalizeImmediates.cpp
Handler/PrologueEpilogueInsertion.cpp
Optimize/Peephole.cpp
Optimize/PostRA_Scheduler.cpp
Optimize/PreRA_Scheduler.cpp
)
# 包含后端模块所需的头文件路径
target_include_directories(riscv64_backend_lib PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../../include/backend/RISCv64 # 后端顶层头文件
${CMAKE_CURRENT_SOURCE_DIR}/../../include/backend/RISCv64/Handler # 增加 Handler 头文件路径
${CMAKE_CURRENT_SOURCE_DIR}/../../include/backend/RISCv64/Optimize # 增加 Optimize 头文件路径
${CMAKE_CURRENT_SOURCE_DIR}/../../include/midend # 增加 midend 头文件路径 (已存在)
${CMAKE_CURRENT_SOURCE_DIR}/../../include/midend/Pass # 增加 midend 头文件路径 (已存在)
)

View File

@ -1,58 +1,18 @@
#include "RISCv64Passes.h"
#include <iostream>
#include "CalleeSavedHandler.h"
#include <set>
#include <algorithm>
namespace sysy {
// --- 寄存器分配前优化 ---
char CalleeSavedHandler::ID = 0;
void PreRA_Scheduler::runOnMachineFunction(MachineFunction* mfunc) {
// TODO: 在此实现寄存器分配前的指令调度。
// 遍历mfunc中的每一个MachineBasicBlock。
// 对每个基本块内的MachineInstr列表进行重排。
//
// 实现思路:
// 1. 分析每个基本块内指令的数据依赖关系,构建依赖图(DAG)。
// 2. 根据目标处理器的流水线特性(指令延迟等),使用列表调度等算法对指令进行重排。
// 3. 此时操作的是虚拟寄存器,只存在真依赖,调度自由度最大。
//
// std::cout << "Running Pre-RA Instruction Scheduler..." << std::endl;
}
// --- 寄存器分配后优化 ---
void PeepholeOptimizer::runOnMachineFunction(MachineFunction* mfunc) {
// TODO: 在此实现窥孔优化。
// 遍历mfunc中的每一个MachineBasicBlock。
// 对每个基本块内的MachineInstr列表进行扫描和替换。
//
// 实现思路:
// 1. 维护一个大小固定例如3-5条指令的滑动窗口。
// 2. 识别特定的冗余模式,例如:
// - `mv a0, a1` 后紧跟 `mv a1, a0` (可消除的交换)
// - `sw t0, 12(s0)` 后紧跟 `lw t1, 12(s0)` (冗余加载)
// - 强度削减: `mul x, x, 2` -> `slli x, x, 1`
// 3. 识别后直接修改MachineInstr列表删除、替换或插入指令
//
// std::cout << "Running Post-RA Peephole Optimizer..." << std::endl;
}
void PostRA_Scheduler::runOnMachineFunction(MachineFunction* mfunc) {
// TODO: 在此实现寄存器分配后的局部指令调度。
// 遍历mfunc中的每一个MachineBasicBlock。
// 重点关注由寄存器分配器插入的spill/fill代码。
//
// 实现思路:
// 1. 识别出用于spill/fill的lw/sw指令。
// 2. 在不违反数据依赖(包括物理寄存器引入的伪依赖)的前提下,
// 尝试将lw指令向上移动使其与使用它的指令之间有足够的距离以隐藏访存延迟。
// 3. 同样可以尝试将sw指令向下移动。
//
// std::cout << "Running Post-RA Local Scheduler..." << std::endl;
bool CalleeSavedHandler::runOnFunction(Function *F, AnalysisManager& AM) {
// This pass works on MachineFunction level, not IR level
return false;
}
void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
// 【最终方案】: 此 Pass 负责分析、分配栈空间并插入 callee-saved 寄存器的保存/恢复指令。
// 此 Pass 负责分析、分配栈空间并插入 callee-saved 寄存器的保存/恢复指令。
// 它通过与 FrameInfo 协作,确保为 callee-saved 寄存器分配的空间与局部变量/溢出槽的空间不冲突。
// 这样做可以使生成的 sd/ld 指令能被后续的优化 Pass (如 PostRA-Scheduler) 处理。
@ -123,16 +83,16 @@ void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
current_offset -= 8;
}
// 5. 【已修复】在函数结尾ret之前插入恢复指令使用反向遍历来避免迭代器失效
// 5. 在函数结尾ret之前插入恢复指令使用反向遍历来避免迭代器失效
for (auto& mbb : mfunc->getBlocks()) {
// 使用手动控制的反向循环
for (auto it = mbb->getInstructions().end(); it != mbb->getInstructions().begin(); ) {
// 在循环开始时就递减迭代器
--it;
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
if ((*it)->getOpcode() == RVOpcodes::RET) {
// 1. 创建一个临时vector来存储所有需要插入的恢复指令
std::vector<std::unique_ptr<MachineInstr>> restore_instrs;
int current_offset_load = base_offset;
// 以相同的顺序恢复(从 s1 开始)
// 以相同的顺序(例如 s1, s2, ...)创建恢复指令
for (PhysicalReg reg : sorted_regs) {
auto ld = std::make_unique<MachineInstr>(RVOpcodes::LD);
ld->addOperand(std::make_unique<RegOperand>(reg));
@ -140,11 +100,21 @@ void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(current_offset_load)
));
// 在 'it' (即 RET 指令) 之前插入。
// 因为我们是反向遍历,所以这不会影响下一次循环的 'it'。
mbb->getInstructions().insert(it, std::move(ld));
restore_instrs.push_back(std::move(ld));
current_offset_load -= 8;
}
// 2. 使用 make_move_iterator 一次性将所有恢复指令插入到 RET 指令之前
// 这可以高效地转移指令的所有权,并且只让迭代器失效一次。
if (!restore_instrs.empty()) {
mbb->getInstructions().insert(it,
std::make_move_iterator(restore_instrs.begin()),
std::make_move_iterator(restore_instrs.end())
);
}
// 找到了RET并处理完毕后就可以跳出内层循环继续寻找下一个基本块
break;
}
}
}

View File

@ -0,0 +1,168 @@
#include "LegalizeImmediates.h"
#include "RISCv64ISel.h" // 需要包含它以调用 getNewVReg()
#include "RISCv64AsmPrinter.h"
#include <vector>
#include <iostream>
// 声明外部调试控制变量
extern int DEBUG;
extern int DEEPDEBUG;
namespace sysy {
char LegalizeImmediatesPass::ID = 0;
// 辅助函数检查一个立即数是否在RISC-V的12位有符号范围内
static bool isLegalImmediate(int64_t imm) {
return imm >= -2048 && imm <= 2047;
}
void LegalizeImmediatesPass::runOnMachineFunction(MachineFunction* mfunc) {
if (DEBUG) {
std::cerr << "===== Running Legalize Immediates Pass on function: " << mfunc->getName() << " =====\n";
}
// 定义我们保留的、用于暂存的物理寄存器
const PhysicalReg TEMP_REG = PhysicalReg::T5;
// 创建一个临时的AsmPrinter用于打印指令方便调试
RISCv64AsmPrinter temp_printer(mfunc);
if (DEEPDEBUG) {
temp_printer.setStream(std::cerr);
}
for (auto& mbb : mfunc->getBlocks()) {
if (DEEPDEBUG) {
std::cerr << "--- Processing Basic Block: " << mbb->getName() << " ---\n";
}
// 创建一个新的指令列表,用于存放合法化后的指令
std::vector<std::unique_ptr<MachineInstr>> new_instructions;
for (auto& instr_ptr : mbb->getInstructions()) {
if (DEEPDEBUG) {
std::cerr << " Checking: ";
// 打印指令时末尾会带换行符,所以这里不用 std::endl
temp_printer.printInstruction(instr_ptr.get(), true);
}
bool legalized = false; // 标记当前指令是否已被展开处理
switch (instr_ptr->getOpcode()) {
case RVOpcodes::ADDI:
case RVOpcodes::ADDIW: {
auto& operands = instr_ptr->getOperands();
auto imm_op = static_cast<ImmOperand*>(operands.back().get());
if (!isLegalImmediate(imm_op->getValue())) {
if (DEEPDEBUG) {
std::cerr << " >> ILLEGAL immediate (" << imm_op->getValue() << "). Expanding...\n";
}
// 立即数超出范围,需要展开
auto rd_op = std::make_unique<RegOperand>(*static_cast<RegOperand*>(operands[0].get()));
auto rs1_op = std::make_unique<RegOperand>(*static_cast<RegOperand*>(operands[1].get()));
// 1. li t5, immediate
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(TEMP_REG));
li->addOperand(std::make_unique<ImmOperand>(imm_op->getValue()));
// 2. add/addw rd, rs1, t5
auto new_op = (instr_ptr->getOpcode() == RVOpcodes::ADDI) ? RVOpcodes::ADD : RVOpcodes::ADDW;
auto add = std::make_unique<MachineInstr>(new_op);
add->addOperand(std::move(rd_op));
add->addOperand(std::move(rs1_op));
add->addOperand(std::make_unique<RegOperand>(TEMP_REG));
if (DEEPDEBUG) {
std::cerr << " New sequence:\n ";
temp_printer.printInstruction(li.get(), true);
std::cerr << " ";
temp_printer.printInstruction(add.get(), true);
}
new_instructions.push_back(std::move(li));
new_instructions.push_back(std::move(add));
legalized = true;
}
break;
}
// 处理所有内存加载/存储指令
case RVOpcodes::LB: case RVOpcodes::LH: case RVOpcodes::LW: case RVOpcodes::LD:
case RVOpcodes::LBU: case RVOpcodes::LHU: case RVOpcodes::LWU:
case RVOpcodes::SB: case RVOpcodes::SH: case RVOpcodes::SW: case RVOpcodes::SD: {
auto& operands = instr_ptr->getOperands();
auto mem_op = static_cast<MemOperand*>(operands.back().get());
auto offset_op = mem_op->getOffset();
if (!isLegalImmediate(offset_op->getValue())) {
if (DEEPDEBUG) {
std::cerr << " >> ILLEGAL immediate offset (" << offset_op->getValue() << "). Expanding...\n";
}
// 偏移量超出范围,需要展开
auto data_reg_op = std::make_unique<RegOperand>(*static_cast<RegOperand*>(operands[0].get()));
auto base_reg_op = std::make_unique<RegOperand>(*mem_op->getBase());
// 1. li t5, offset
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(TEMP_REG));
li->addOperand(std::make_unique<ImmOperand>(offset_op->getValue()));
// 2. add t5, base_reg, t5 (计算最终地址结果也放在t5)
auto add = std::make_unique<MachineInstr>(RVOpcodes::ADD);
add->addOperand(std::make_unique<RegOperand>(TEMP_REG));
add->addOperand(std::move(base_reg_op));
add->addOperand(std::make_unique<RegOperand>(TEMP_REG));
// 3. lw/sw data_reg, 0(t5)
auto mem_instr = std::make_unique<MachineInstr>(instr_ptr->getOpcode());
mem_instr->addOperand(std::move(data_reg_op));
mem_instr->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(TEMP_REG),
std::make_unique<ImmOperand>(0)
));
if (DEEPDEBUG) {
std::cerr << " New sequence:\n ";
temp_printer.printInstruction(li.get(), true);
std::cerr << " ";
temp_printer.printInstruction(add.get(), true);
std::cerr << " ";
temp_printer.printInstruction(mem_instr.get(), true);
}
new_instructions.push_back(std::move(li));
new_instructions.push_back(std::move(add));
new_instructions.push_back(std::move(mem_instr));
legalized = true;
}
break;
}
default:
// 其他指令不需要处理
break;
}
if (!legalized) {
if (DEEPDEBUG) {
std::cerr << " -- Immediate is legal. Skipping.\n";
}
// 如果当前指令不需要合法化,直接将其移动到新列表中
new_instructions.push_back(std::move(instr_ptr));
}
}
// 用新的、已合法化的指令列表替换旧的列表
mbb->getInstructions() = std::move(new_instructions);
}
if (DEBUG) {
std::cerr << "===== Finished Legalize Immediates Pass =====\n\n";
}
}
} // namespace sysy

View File

@ -0,0 +1,118 @@
#include "PrologueEpilogueInsertion.h"
namespace sysy {
char PrologueEpilogueInsertionPass::ID = 0;
void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) {
StackFrameInfo& frame_info = mfunc->getFrameInfo();
// 完全遵循 AsmPrinter 中的计算逻辑
int total_stack_size = frame_info.locals_size +
frame_info.spill_size +
frame_info.callee_saved_size +
16; // 为 ra 和 s0 固定的16字节
int aligned_stack_size = (total_stack_size + 15) & ~15;
frame_info.total_size = aligned_stack_size;
// 只有在需要分配栈空间时才生成指令
if (aligned_stack_size > 0) {
// --- 1. 插入序言 ---
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
auto& entry_instrs = entry_block->getInstructions();
std::vector<std::unique_ptr<MachineInstr>> prologue_instrs;
// 严格按照 AsmPrinter 的打印顺序来创建和组织指令
// 1. addi sp, sp, -aligned_stack_size
auto alloc_stack = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
alloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
alloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
alloc_stack->addOperand(std::make_unique<ImmOperand>(-aligned_stack_size));
prologue_instrs.push_back(std::move(alloc_stack));
// 2. sd ra, (aligned_stack_size - 8)(sp)
auto save_ra = std::make_unique<MachineInstr>(RVOpcodes::SD);
save_ra->addOperand(std::make_unique<RegOperand>(PhysicalReg::RA));
save_ra->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::SP),
std::make_unique<ImmOperand>(aligned_stack_size - 8)
));
prologue_instrs.push_back(std::move(save_ra));
// 3. sd s0, (aligned_stack_size - 16)(sp)
auto save_fp = std::make_unique<MachineInstr>(RVOpcodes::SD);
save_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
save_fp->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::SP),
std::make_unique<ImmOperand>(aligned_stack_size - 16)
));
prologue_instrs.push_back(std::move(save_fp));
// 4. addi s0, sp, aligned_stack_size
auto set_fp = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
set_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
set_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
set_fp->addOperand(std::make_unique<ImmOperand>(aligned_stack_size));
prologue_instrs.push_back(std::move(set_fp));
// 确定插入点(在函数名标签之后)
auto insert_pos = entry_instrs.begin();
// [重要] 这里我们不再需要跳过LABEL因为AsmPrinter将不再打印函数名标签
// 第一个基本块的标签就是函数入口
// 一次性将所有序言指令插入
if (!prologue_instrs.empty()) {
entry_instrs.insert(insert_pos,
std::make_move_iterator(prologue_instrs.begin()),
std::make_move_iterator(prologue_instrs.end()));
}
// --- 2. 插入尾声 ---
for (auto& mbb : mfunc->getBlocks()) {
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
if ((*it)->getOpcode() == RVOpcodes::RET) {
std::vector<std::unique_ptr<MachineInstr>> epilogue_instrs;
// 同样严格按照 AsmPrinter 的打印顺序
// 1. ld ra, (aligned_stack_size - 8)(sp)
auto restore_ra = std::make_unique<MachineInstr>(RVOpcodes::LD);
restore_ra->addOperand(std::make_unique<RegOperand>(PhysicalReg::RA));
restore_ra->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::SP),
std::make_unique<ImmOperand>(aligned_stack_size - 8)
));
epilogue_instrs.push_back(std::move(restore_ra));
// 2. ld s0, (aligned_stack_size - 16)(sp)
auto restore_fp = std::make_unique<MachineInstr>(RVOpcodes::LD);
restore_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
restore_fp->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::SP),
std::make_unique<ImmOperand>(aligned_stack_size - 16)
));
epilogue_instrs.push_back(std::move(restore_fp));
// 3. addi sp, sp, aligned_stack_size
auto dealloc_stack = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
dealloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
dealloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
dealloc_stack->addOperand(std::make_unique<ImmOperand>(aligned_stack_size));
epilogue_instrs.push_back(std::move(dealloc_stack));
if (!epilogue_instrs.empty()) {
mbb->getInstructions().insert(it,
std::make_move_iterator(epilogue_instrs.begin()),
std::make_move_iterator(epilogue_instrs.end()));
}
// 处理完一个基本块中的RET后迭代器已失效需跳出
goto next_block;
}
}
next_block:;
}
}
}
} // namespace sysy

View File

@ -0,0 +1,652 @@
#include "Peephole.h"
#include <functional>
namespace sysy {
char PeepholeOptimizer::ID = 0;
bool PeepholeOptimizer::runOnFunction(Function *F, AnalysisManager& AM) {
// This pass works on MachineFunction level, not IR level
return false;
}
void PeepholeOptimizer::runOnMachineFunction(MachineFunction *mfunc) {
if (!mfunc)
return;
using namespace sysy;
// areRegsEqual: 检查两个寄存器操作数是否相等(考虑虚拟和物理寄存器)。
auto areRegsEqual = [](RegOperand *r1, RegOperand *r2) {
if (!r1 || !r2 || r1->isVirtual() != r2->isVirtual()) {
return false;
}
if (r1->isVirtual()) {
return r1->getVRegNum() == r2->getVRegNum();
} else {
return r1->getPReg() == r2->getPReg();
}
};
// 改进的 isRegUsedLater 函数 - 更完整和准确的实现
auto isRegUsedLater =
[&](const std::vector<std::unique_ptr<MachineInstr>> &instrs,
RegOperand *reg, size_t start_idx) -> bool {
for (size_t j = start_idx; j < instrs.size(); ++j) {
auto *instr = instrs[j].get();
auto opcode = instr->getOpcode();
// 检查所有操作数
for (size_t k = 0; k < instr->getOperands().size(); ++k) {
bool isDefOperand = false;
// 更完整的定义操作数判断逻辑
if (k == 0) { // 第一个操作数通常是目标寄存器
switch (opcode) {
// 算术和逻辑指令 - 第一个操作数是定义
case RVOpcodes::MV:
case RVOpcodes::ADDI:
case RVOpcodes::SLLI:
case RVOpcodes::SRLI:
case RVOpcodes::SRAI:
case RVOpcodes::SLTI:
case RVOpcodes::SLTIU:
case RVOpcodes::XORI:
case RVOpcodes::ORI:
case RVOpcodes::ANDI:
case RVOpcodes::ADD:
case RVOpcodes::SUB:
case RVOpcodes::SLL:
case RVOpcodes::SLT:
case RVOpcodes::SLTU:
case RVOpcodes::XOR:
case RVOpcodes::SRL:
case RVOpcodes::SRA:
case RVOpcodes::OR:
case RVOpcodes::AND:
case RVOpcodes::MUL:
case RVOpcodes::DIV:
case RVOpcodes::REM:
case RVOpcodes::LW:
case RVOpcodes::LH:
case RVOpcodes::LB:
case RVOpcodes::LHU:
case RVOpcodes::LBU:
// 存储指令 - 第一个操作数是使用(要存储的值)
case RVOpcodes::SW:
case RVOpcodes::SH:
case RVOpcodes::SB:
// 分支指令 - 第一个操作数是使用
case RVOpcodes::BEQ:
case RVOpcodes::BNE:
case RVOpcodes::BLT:
case RVOpcodes::BGE:
case RVOpcodes::BLTU:
case RVOpcodes::BGEU:
// 跳转指令 - 可能使用寄存器
case RVOpcodes::JALR:
isDefOperand = false;
break;
default:
// 对于未知指令,保守地假设第一个操作数可能是使用
isDefOperand = false;
break;
}
}
// 如果不是定义操作数,检查是否使用了目标寄存器
if (!isDefOperand) {
if (instr->getOperands()[k]->getKind() == MachineOperand::KIND_REG) {
auto *use_reg =
static_cast<RegOperand *>(instr->getOperands()[k].get());
if (areRegsEqual(reg, use_reg))
return true;
}
// 检查内存操作数中的基址寄存器
if (instr->getOperands()[k]->getKind() == MachineOperand::KIND_MEM) {
auto *mem =
static_cast<MemOperand *>(instr->getOperands()[k].get());
if (areRegsEqual(reg, mem->getBase()))
return true;
}
}
}
}
return false;
};
// 检查寄存器是否在指令中被重新定义(用于更精确的分析)
auto isRegRedefinedAt =
[](MachineInstr *instr, RegOperand *reg,
const std::function<bool(RegOperand *, RegOperand *)> &areRegsEqual)
-> bool {
if (instr->getOperands().empty())
return false;
auto opcode = instr->getOpcode();
// 只有当第一个操作数是定义操作数时才检查
switch (opcode) {
case RVOpcodes::MV:
case RVOpcodes::ADDI:
case RVOpcodes::ADD:
case RVOpcodes::SUB:
case RVOpcodes::MUL:
case RVOpcodes::LW:
// ... 其他定义指令
if (instr->getOperands()[0]->getKind() == MachineOperand::KIND_REG) {
auto *def_reg =
static_cast<RegOperand *>(instr->getOperands()[0].get());
return areRegsEqual(reg, def_reg);
}
break;
default:
break;
}
return false;
};
// 检查是否为存储-加载模式,支持不同大小的访问
auto isStoreLoadPattern = [](MachineInstr *store_instr,
MachineInstr *load_instr) -> bool {
auto store_op = store_instr->getOpcode();
auto load_op = load_instr->getOpcode();
// 检查存储-加载对应关系
return (store_op == RVOpcodes::SW && load_op == RVOpcodes::LW) || // 32位
(store_op == RVOpcodes::SH &&
load_op == RVOpcodes::LH) || // 16位有符号
(store_op == RVOpcodes::SH &&
load_op == RVOpcodes::LHU) || // 16位无符号
(store_op == RVOpcodes::SB &&
load_op == RVOpcodes::LB) || // 8位有符号
(store_op == RVOpcodes::SB &&
load_op == RVOpcodes::LBU) || // 8位无符号
(store_op == RVOpcodes::SD && load_op == RVOpcodes::LD); // 64位
};
// 检查两个内存访问是否访问相同的内存位置
auto areMemoryAccessesEqual =
[&areRegsEqual](MachineInstr *store_instr, MemOperand *store_mem,
MachineInstr *load_instr, MemOperand *load_mem) -> bool {
// 基址寄存器必须相同
if (!areRegsEqual(store_mem->getBase(), load_mem->getBase())) {
return false;
}
// 偏移量必须相同
if (store_mem->getOffset()->getValue() !=
load_mem->getOffset()->getValue()) {
return false;
}
// 检查访问大小是否兼容
auto store_op = store_instr->getOpcode();
auto load_op = load_instr->getOpcode();
// 获取访问大小(字节数)
auto getAccessSize = [](RVOpcodes opcode) -> int {
switch (opcode) {
case RVOpcodes::LB:
case RVOpcodes::LBU:
case RVOpcodes::SB:
return 1; // 8位
case RVOpcodes::LH:
case RVOpcodes::LHU:
case RVOpcodes::SH:
return 2; // 16位
case RVOpcodes::LW:
case RVOpcodes::SW:
return 4; // 32位
case RVOpcodes::LD:
case RVOpcodes::SD:
return 8; // 64位
default:
return -1; // 未知
}
};
int store_size = getAccessSize(store_op);
int load_size = getAccessSize(load_op);
// 只有访问大小完全匹配时才能进行优化
// 这避免了部分重叠访问的复杂情况
return store_size > 0 && store_size == load_size;
};
// 简单的内存别名分析:检查两个内存访问之间是否可能有冲突的内存操作
auto isMemoryAccessSafe =
[&](const std::vector<std::unique_ptr<MachineInstr>> &instrs,
size_t store_idx, size_t load_idx, MemOperand *mem) -> bool {
// 检查存储和加载之间是否有可能影响内存的指令
for (size_t j = store_idx + 1; j < load_idx; ++j) {
auto *between_instr = instrs[j].get();
auto between_op = between_instr->getOpcode();
// 检查是否有其他内存写入操作
switch (between_op) {
case RVOpcodes::SW:
case RVOpcodes::SH:
case RVOpcodes::SB:
case RVOpcodes::SD: {
// 如果有其他存储操作,需要检查是否可能访问相同的内存
if (between_instr->getOperands().size() >= 2 &&
between_instr->getOperands()[1]->getKind() ==
MachineOperand::KIND_MEM) {
auto *other_mem =
static_cast<MemOperand *>(between_instr->getOperands()[1].get());
// 保守的别名分析:如果使用不同的基址寄存器,假设可能别名
if (!areRegsEqual(mem->getBase(), other_mem->getBase())) {
return false; // 可能的别名,不安全
}
// 如果基址相同但偏移量不同,检查是否重叠
int64_t offset1 = mem->getOffset()->getValue();
int64_t offset2 = other_mem->getOffset()->getValue();
// 获取访问大小来检查重叠
auto getAccessSize = [](RVOpcodes opcode) -> int {
switch (opcode) {
case RVOpcodes::SB:
return 1;
case RVOpcodes::SH:
return 2;
case RVOpcodes::SW:
return 4;
case RVOpcodes::SD:
return 8;
default:
return 4; // 默认假设4字节
}
};
int size1 = getAccessSize(RVOpcodes::SW); // 从原存储指令推断
int size2 = getAccessSize(between_op);
// 检查内存区域是否重叠
bool overlaps =
!(offset1 + size1 <= offset2 || offset2 + size2 <= offset1);
if (overlaps) {
return false; // 内存重叠,不安全
}
}
break;
}
// 函数调用可能有副作用
case RVOpcodes::JAL:
case RVOpcodes::JALR:
return false; // 函数调用可能修改内存,不安全
// 原子操作或其他可能修改内存的指令
// 根据具体的RISC-V扩展添加更多指令
default:
// 对于未知指令,采用保守策略
// 可以根据具体需求调整
break;
}
}
return true; // 没有发现潜在的内存冲突
};
// isPowerOfTwo: 检查数值是否为2的幂次并返回其指数。
auto isPowerOfTwo = [](int64_t n) -> int {
if (n <= 0 || (n & (n - 1)) != 0)
return -1;
int shift = 0;
while (n > 1) {
n >>= 1;
shift++;
}
return shift;
};
for (auto &mbb_uptr : mfunc->getBlocks()) {
auto &mbb = *mbb_uptr;
auto &instrs = mbb.getInstructions();
if (instrs.size() < 2)
continue; // 基本块至少需要两条指令进行窥孔
// 遍历指令序列进行窥孔优化
for (size_t i = 0; i + 1 < instrs.size();) {
auto *mi1 = instrs[i].get();
auto *mi2 = instrs[i + 1].get();
bool changed = false;
// 1. 消除冗余交换移动: mv a, b; mv b, a -> mv a, b
if (mi1->getOpcode() == RVOpcodes::MV &&
mi2->getOpcode() == RVOpcodes::MV) {
if (mi1->getOperands().size() == 2 && mi2->getOperands().size() == 2) {
if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG &&
mi2->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi2->getOperands()[1]->getKind() == MachineOperand::KIND_REG) {
auto *dst1 = static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *src1 = static_cast<RegOperand *>(mi1->getOperands()[1].get());
auto *dst2 = static_cast<RegOperand *>(mi2->getOperands()[0].get());
auto *src2 = static_cast<RegOperand *>(mi2->getOperands()[1].get());
if (areRegsEqual(dst1, src2) && areRegsEqual(src1, dst2)) {
instrs.erase(instrs.begin() + i + 1); // 移除第二条指令
changed = true;
}
}
}
}
// 2. 冗余加载消除: sw t0, offset(base); lw t1, offset(base) -> 替换或消除
// lw 添加ld sd支持
else if (isStoreLoadPattern(mi1, mi2)) {
if (mi1->getOperands().size() == 2 && mi2->getOperands().size() == 2) {
if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_MEM &&
mi2->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi2->getOperands()[1]->getKind() == MachineOperand::KIND_MEM) {
auto *store_val =
static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *store_mem =
static_cast<MemOperand *>(mi1->getOperands()[1].get());
auto *load_val =
static_cast<RegOperand *>(mi2->getOperands()[0].get());
auto *load_mem =
static_cast<MemOperand *>(mi2->getOperands()[1].get());
// 检查内存访问是否匹配(基址、偏移量和访问大小)
if (areMemoryAccessesEqual(mi1, store_mem, mi2, load_mem)) {
// 进行简单的内存别名分析
if (isMemoryAccessSafe(instrs, i, i + 1, store_mem)) {
if (areRegsEqual(store_val, load_val)) {
// sw r1, mem; lw r1, mem -> 消除冗余的lw
instrs.erase(instrs.begin() + i + 1);
changed = true;
} else {
// sw r1, mem; lw r2, mem -> 替换lw为mv r2, r1
auto newInstr = std::make_unique<MachineInstr>(RVOpcodes::MV);
newInstr->addOperand(std::make_unique<RegOperand>(*load_val));
newInstr->addOperand(
std::make_unique<RegOperand>(*store_val));
instrs[i + 1] = std::move(newInstr);
changed = true;
}
}
}
}
}
}
// 3. 强度削减: mul y, x, 2^n -> slli y, x, n
else if (mi1->getOpcode() == RVOpcodes::MUL &&
mi1->getOperands().size() == 3) {
auto *dst_op = mi1->getOperands()[0].get();
auto *src1_op = mi1->getOperands()[1].get();
auto *src2_op = mi1->getOperands()[2].get();
if (dst_op->getKind() == MachineOperand::KIND_REG) {
auto *dst_reg = static_cast<RegOperand *>(dst_op);
RegOperand *src_reg = nullptr;
int shift = -1;
if (src1_op->getKind() == MachineOperand::KIND_REG &&
src2_op->getKind() == MachineOperand::KIND_IMM) {
shift =
isPowerOfTwo(static_cast<ImmOperand *>(src2_op)->getValue());
if (shift >= 0)
src_reg = static_cast<RegOperand *>(src1_op);
} else if (src1_op->getKind() == MachineOperand::KIND_IMM &&
src2_op->getKind() == MachineOperand::KIND_REG) {
shift =
isPowerOfTwo(static_cast<ImmOperand *>(src1_op)->getValue());
if (shift >= 0)
src_reg = static_cast<RegOperand *>(src2_op);
}
if (src_reg && shift >= 0 &&
shift <= 31) { // RISC-V 移位量限制 (0-31)
auto newInstr = std::make_unique<MachineInstr>(RVOpcodes::SLLI);
newInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
newInstr->addOperand(std::make_unique<RegOperand>(*src_reg));
newInstr->addOperand(std::make_unique<ImmOperand>(shift));
instrs[i] = std::move(newInstr);
changed = true;
}
}
}
// 4. 地址计算优化: addi dst, base, imm1; lw/sw val, imm2(dst) -> lw/sw
// val, (imm1+imm2)(base)
else if (mi1->getOpcode() == RVOpcodes::ADDI &&
mi1->getOperands().size() == 3) {
auto opcode2 = mi2->getOpcode();
if (opcode2 == RVOpcodes::LW || opcode2 == RVOpcodes::SW) {
if (mi2->getOperands().size() == 2 &&
mi2->getOperands()[1]->getKind() == MachineOperand::KIND_MEM &&
mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[2]->getKind() == MachineOperand::KIND_IMM) {
auto *addi_dst =
static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *addi_base =
static_cast<RegOperand *>(mi1->getOperands()[1].get());
auto *addi_imm =
static_cast<ImmOperand *>(mi1->getOperands()[2].get());
auto *mem_op =
static_cast<MemOperand *>(mi2->getOperands()[1].get());
auto *mem_base = mem_op->getBase();
auto *mem_imm = mem_op->getOffset();
// 检查 ADDI 的目标寄存器是否是内存操作的基址
if (areRegsEqual(addi_dst, mem_base)) {
// 改进的使用检查:考虑寄存器可能在后续被重新定义的情况
bool canOptimize = true;
// 检查从 i+2 开始的指令
for (size_t j = i + 2; j < instrs.size(); ++j) {
auto *later_instr = instrs[j].get();
// 如果寄存器被重新定义,那么它后面的使用就不相关了
if (isRegRedefinedAt(later_instr, addi_dst, areRegsEqual)) {
break; // 寄存器被重新定义,可以安全优化
}
// 如果寄存器被使用,则不能优化
if (isRegUsedLater(instrs, addi_dst, j)) {
canOptimize = false;
break;
}
}
if (canOptimize) {
int64_t new_offset = addi_imm->getValue() + mem_imm->getValue();
// 检查新偏移量是否符合 RISC-V 12位有符号立即数范围
if (new_offset >= -2048 && new_offset <= 2047) {
auto new_mem_op = std::make_unique<MemOperand>(
std::make_unique<RegOperand>(*addi_base),
std::make_unique<ImmOperand>(new_offset));
mi2->getOperands()[1] = std::move(new_mem_op);
instrs.erase(instrs.begin() + i);
changed = true;
}
}
}
}
}
}
// 5. 冗余移动指令消除: mv x, y; op z, x, ... -> op z, y, ... (如果 x
// 之后不再使用)
else if (mi1->getOpcode() == RVOpcodes::MV &&
mi1->getOperands().size() == 2) {
if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG) {
auto *mv_dst = static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *mv_src = static_cast<RegOperand *>(mi1->getOperands()[1].get());
// 检查第二条指令是否使用了 mv 的目标寄存器
std::vector<size_t> use_positions;
for (size_t k = 1; k < mi2->getOperands().size(); ++k) {
if (mi2->getOperands()[k]->getKind() == MachineOperand::KIND_REG) {
auto *use_reg =
static_cast<RegOperand *>(mi2->getOperands()[k].get());
if (areRegsEqual(mv_dst, use_reg)) {
use_positions.push_back(k);
}
}
// 也检查内存操作数中的基址寄存器
else if (mi2->getOperands()[k]->getKind() ==
MachineOperand::KIND_MEM) {
auto *mem =
static_cast<MemOperand *>(mi2->getOperands()[k].get());
if (areRegsEqual(mv_dst, mem->getBase())) {
// 对于内存操作数我们需要创建新的MemOperand
auto new_mem = std::make_unique<MemOperand>(
std::make_unique<RegOperand>(*mv_src),
std::make_unique<ImmOperand>(mem->getOffset()->getValue()));
mi2->getOperands()[k] = std::move(new_mem);
use_positions.push_back(k); // 标记已处理
}
}
}
if (!use_positions.empty()) {
// 改进的后续使用检查
bool canOptimize = true;
for (size_t j = i + 2; j < instrs.size(); ++j) {
auto *later_instr = instrs[j].get();
// 如果寄存器被重新定义,后续使用就不相关了
if (isRegRedefinedAt(later_instr, mv_dst, areRegsEqual)) {
break;
}
// 检查是否还有其他使用
if (isRegUsedLater(instrs, mv_dst, j)) {
canOptimize = false;
break;
}
}
if (canOptimize) {
// 替换所有寄存器使用(内存操作数已在上面处理)
for (size_t pos : use_positions) {
if (mi2->getOperands()[pos]->getKind() ==
MachineOperand::KIND_REG) {
mi2->getOperands()[pos] =
std::make_unique<RegOperand>(*mv_src);
}
}
instrs.erase(instrs.begin() + i);
changed = true;
}
}
}
}
// 6. 连续加法指令合并: addi t1, t0, imm1; addi t2, t1, imm2 -> addi t2,
// t0, (imm1+imm2)
else if (mi1->getOpcode() == RVOpcodes::ADDI &&
mi2->getOpcode() == RVOpcodes::ADDI) {
if (mi1->getOperands().size() == 3 && mi2->getOperands().size() == 3) {
if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[2]->getKind() == MachineOperand::KIND_IMM &&
mi2->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi2->getOperands()[1]->getKind() == MachineOperand::KIND_REG &&
mi2->getOperands()[2]->getKind() == MachineOperand::KIND_IMM) {
auto *addi1_dst =
static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *addi1_src =
static_cast<RegOperand *>(mi1->getOperands()[1].get());
auto *addi1_imm =
static_cast<ImmOperand *>(mi1->getOperands()[2].get());
auto *addi2_dst =
static_cast<RegOperand *>(mi2->getOperands()[0].get());
auto *addi2_src =
static_cast<RegOperand *>(mi2->getOperands()[1].get());
auto *addi2_imm =
static_cast<ImmOperand *>(mi2->getOperands()[2].get());
// 检查第一个ADDI的目标是否是第二个ADDI的源
if (areRegsEqual(addi1_dst, addi2_src)) {
// 改进的中间寄存器使用检查
bool canOptimize = true;
for (size_t j = i + 2; j < instrs.size(); ++j) {
auto *later_instr = instrs[j].get();
// 如果中间寄存器被重新定义,后续使用不相关
if (isRegRedefinedAt(later_instr, addi1_dst, areRegsEqual)) {
break;
}
// 检查是否有其他使用
if (isRegUsedLater(instrs, addi1_dst, j)) {
canOptimize = false;
break;
}
}
if (canOptimize) {
int64_t new_imm = addi1_imm->getValue() + addi2_imm->getValue();
// 检查新立即数范围
if (new_imm >= -2048 && new_imm <= 2047) {
auto newInstr =
std::make_unique<MachineInstr>(RVOpcodes::ADDI);
newInstr->addOperand(
std::make_unique<RegOperand>(*addi2_dst));
newInstr->addOperand(
std::make_unique<RegOperand>(*addi1_src));
newInstr->addOperand(std::make_unique<ImmOperand>(new_imm));
instrs[i + 1] = std::move(newInstr);
instrs.erase(instrs.begin() + i);
changed = true;
}
}
}
}
}
}
// 7. ADD with zero optimization: add r1, r2, zero -> mv r1, r2
else if (mi1->getOpcode() == RVOpcodes::ADD &&
mi1->getOperands().size() == 3) {
if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[2]->getKind() == MachineOperand::KIND_REG) {
auto *add_dst =
static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *add_src1 =
static_cast<RegOperand *>(mi1->getOperands()[1].get());
auto *add_src2 =
static_cast<RegOperand *>(mi1->getOperands()[2].get());
// 检查第二个源操作数是否为ZERO寄存器
if (!add_src2->isVirtual() &&
add_src2->getPReg() == PhysicalReg::ZERO) {
// 创建新的 MV 指令
auto newInstr = std::make_unique<MachineInstr>(RVOpcodes::MV);
newInstr->addOperand(std::make_unique<RegOperand>(*add_dst));
newInstr->addOperand(std::make_unique<RegOperand>(*add_src1));
instrs[i] = std::move(newInstr);
changed = true;
}
}
}
// 根据是否发生变化调整遍历索引
if (!changed) {
++i; // 没有优化,继续检查下一对指令
} else {
// 发生变化,适当回退以捕获新的优化机会。
// 这是一种安全的回退策略,可以触发连锁优化,且不会导致无限循环。
if (i > 0) {
--i;
}
}
}
}
}
} // namespace sysy

View File

@ -0,0 +1,383 @@
#include "PostRA_Scheduler.h"
#include <set>
#include <map>
#include <vector>
#include <algorithm>
#define MAX_SCHEDULING_BLOCK_SIZE 10000 // 限制调度块大小,避免过大导致性能问题
namespace sysy {
char PostRA_Scheduler::ID = 0;
// 检查指令是否是加载指令 (LW, LD)
bool isLoadInstr(MachineInstr* instr) {
RVOpcodes opcode = instr->getOpcode();
return opcode == RVOpcodes::LW || opcode == RVOpcodes::LD ||
opcode == RVOpcodes::LH || opcode == RVOpcodes::LB ||
opcode == RVOpcodes::LHU || opcode == RVOpcodes::LBU ||
opcode == RVOpcodes::LWU;
}
// 检查指令是否是存储指令 (SW, SD)
bool isStoreInstr(MachineInstr* instr) {
RVOpcodes opcode = instr->getOpcode();
return opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
opcode == RVOpcodes::SH || opcode == RVOpcodes::SB;
}
// 检查指令是否为控制流指令
bool isControlFlowInstr(MachineInstr* instr) {
RVOpcodes opcode = instr->getOpcode();
return opcode == RVOpcodes::RET || opcode == RVOpcodes::J ||
opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
opcode == RVOpcodes::CALL;
}
// 获取指令定义的寄存器 - 修复版本
std::set<PhysicalReg> getDefinedRegisters(MachineInstr* instr) {
std::set<PhysicalReg> defined_regs;
RVOpcodes opcode = instr->getOpcode();
// 特殊处理CALL指令
if (opcode == RVOpcodes::CALL) {
// CALL指令可能定义返回值寄存器
if (!instr->getOperands().empty() &&
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
if (!reg_op->isVirtual()) {
defined_regs.insert(reg_op->getPReg());
}
}
return defined_regs;
}
// 存储指令不定义寄存器
if (isStoreInstr(instr)) {
return defined_regs;
}
// 分支指令不定义寄存器
if (opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
opcode == RVOpcodes::J || opcode == RVOpcodes::RET) {
return defined_regs;
}
// 对于其他指令,第一个寄存器操作数通常是定义的
if (!instr->getOperands().empty() &&
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
if (!reg_op->isVirtual()) {
defined_regs.insert(reg_op->getPReg());
}
}
return defined_regs;
}
// 获取指令使用的寄存器 - 修复版本
std::set<PhysicalReg> getUsedRegisters(MachineInstr* instr) {
std::set<PhysicalReg> used_regs;
RVOpcodes opcode = instr->getOpcode();
// 特殊处理CALL指令
if (opcode == RVOpcodes::CALL) {
bool first_reg_skipped = false;
for (const auto& op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
if (!first_reg_skipped) {
first_reg_skipped = true;
continue; // 跳过返回值寄存器
}
auto reg_op = static_cast<RegOperand*>(op.get());
if (!reg_op->isVirtual()) {
used_regs.insert(reg_op->getPReg());
}
}
}
return used_regs;
}
// 对于存储指令,所有寄存器操作数都是使用的
if (isStoreInstr(instr)) {
for (const auto& op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(op.get());
if (!reg_op->isVirtual()) {
used_regs.insert(reg_op->getPReg());
}
} else if (op->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<MemOperand*>(op.get());
if (!mem_op->getBase()->isVirtual()) {
used_regs.insert(mem_op->getBase()->getPReg());
}
}
}
return used_regs;
}
// 对于分支指令,所有寄存器操作数都是使用的
if (opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU) {
for (const auto& op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(op.get());
if (!reg_op->isVirtual()) {
used_regs.insert(reg_op->getPReg());
}
}
}
return used_regs;
}
// 对于其他指令,除了第一个寄存器操作数(通常是定义),其余都是使用的
bool first_reg = true;
for (const auto& op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
if (first_reg) {
first_reg = false;
continue; // 跳过第一个寄存器(定义)
}
auto reg_op = static_cast<RegOperand*>(op.get());
if (!reg_op->isVirtual()) {
used_regs.insert(reg_op->getPReg());
}
} else if (op->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<MemOperand*>(op.get());
if (!mem_op->getBase()->isVirtual()) {
used_regs.insert(mem_op->getBase()->getPReg());
}
}
}
return used_regs;
}
// 获取内存访问的基址和偏移
struct MemoryAccess {
PhysicalReg base_reg;
int64_t offset;
bool valid;
MemoryAccess() : valid(false) {}
MemoryAccess(PhysicalReg base, int64_t off) : base_reg(base), offset(off), valid(true) {}
};
MemoryAccess getMemoryAccess(MachineInstr* instr) {
if (!isLoadInstr(instr) && !isStoreInstr(instr)) {
return MemoryAccess();
}
// 查找内存操作数
for (const auto& op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<MemOperand*>(op.get());
if (!mem_op->getBase()->isVirtual()) {
return MemoryAccess(mem_op->getBase()->getPReg(), mem_op->getOffset()->getValue());
}
}
}
return MemoryAccess();
}
// 检查内存依赖 - 加强版本
bool hasMemoryDependency(MachineInstr* instr1, MachineInstr* instr2) {
// 如果都不是内存指令,没有内存依赖
if (!isLoadInstr(instr1) && !isStoreInstr(instr1) &&
!isLoadInstr(instr2) && !isStoreInstr(instr2)) {
return false;
}
MemoryAccess mem1 = getMemoryAccess(instr1);
MemoryAccess mem2 = getMemoryAccess(instr2);
if (!mem1.valid || !mem2.valid) {
// 如果无法确定内存访问模式,保守地认为存在依赖
return true;
}
// 如果访问相同的内存位置
if (mem1.base_reg == mem2.base_reg && mem1.offset == mem2.offset) {
// Store->Load: RAW依赖
// Load->Store: WAR依赖
// Store->Store: WAW依赖
return isStoreInstr(instr1) || isStoreInstr(instr2);
}
// 不同内存位置通常没有依赖,但为了安全起见,
// 如果涉及store指令我们需要更保守
if (isStoreInstr(instr1) && isLoadInstr(instr2)) {
// 保守处理不同store和load之间可能有别名
return false; // 这里可以根据需要调整策略
}
return false;
}
// 检查两个指令之间是否存在依赖关系 - 修复版本
bool hasDependency(MachineInstr* instr1, MachineInstr* instr2) {
// 检查RAW依赖instr1定义的寄存器是否被instr2使用
auto defined_regs1 = getDefinedRegisters(instr1);
auto used_regs2 = getUsedRegisters(instr2);
for (const auto& reg : defined_regs1) {
if (used_regs2.find(reg) != used_regs2.end()) {
return true; // RAW依赖 - instr2读取instr1写入的值
}
}
// 检查WAR依赖instr1使用的寄存器是否被instr2定义
auto used_regs1 = getUsedRegisters(instr1);
auto defined_regs2 = getDefinedRegisters(instr2);
for (const auto& reg : used_regs1) {
if (defined_regs2.find(reg) != defined_regs2.end()) {
return true; // WAR依赖 - instr2覆盖instr1需要的值
}
}
// 检查WAW依赖两个指令定义相同寄存器
for (const auto& reg : defined_regs1) {
if (defined_regs2.find(reg) != defined_regs2.end()) {
return true; // WAW依赖 - 两条指令写入同一寄存器
}
}
// 检查内存依赖
if (hasMemoryDependency(instr1, instr2)) {
return true;
}
return false;
}
// 检查是否可以安全地将instr1和instr2交换位置
bool canSwapInstructions(MachineInstr* instr1, MachineInstr* instr2) {
// 不能移动控制流指令
if (isControlFlowInstr(instr1) || isControlFlowInstr(instr2)) {
return false;
}
// 检查双向依赖关系
return !hasDependency(instr1, instr2) && !hasDependency(instr2, instr1);
}
// 新增:验证调度结果的正确性
void validateSchedule(const std::vector<MachineInstr*>& instr_list) {
for (int i = 0; i < (int)instr_list.size(); i++) {
for (int j = i + 1; j < (int)instr_list.size(); j++) {
MachineInstr* earlier = instr_list[i];
MachineInstr* later = instr_list[j];
// 检查是否存在被违反的依赖关系
auto defined_regs = getDefinedRegisters(earlier);
auto used_regs = getUsedRegisters(later);
// 检查RAW依赖
for (const auto& reg : defined_regs) {
if (used_regs.find(reg) != used_regs.end()) {
// 这是正常的依赖关系earlier应该在later之前
continue;
}
}
// 检查内存依赖
if (hasMemoryDependency(earlier, later)) {
MemoryAccess mem1 = getMemoryAccess(earlier);
MemoryAccess mem2 = getMemoryAccess(later);
if (mem1.valid && mem2.valid &&
mem1.base_reg == mem2.base_reg && mem1.offset == mem2.offset) {
if (isStoreInstr(earlier) && isLoadInstr(later)) {
// Store->Load依赖顺序正确
continue;
}
}
}
}
}
}
// 在基本块内对指令进行调度优化 - 完全重写版本
void scheduleBlock(MachineBasicBlock* mbb) {
auto& instructions = mbb->getInstructions();
if (instructions.size() <= 1) return;
if (instructions.size() > MAX_SCHEDULING_BLOCK_SIZE) {
return; // 跳过超大块,防止卡住
}
std::vector<MachineInstr*> instr_list;
for (auto& instr : instructions) {
instr_list.push_back(instr.get());
}
// 使用更严格的调度策略,避免破坏依赖关系
bool changed = true;
int max_iterations = 10; // 限制迭代次数避免死循环
int iteration = 0;
while (changed && iteration < max_iterations) {
changed = false;
iteration++;
for (int i = 0; i < (int)instr_list.size() - 1; i++) {
MachineInstr* instr1 = instr_list[i];
MachineInstr* instr2 = instr_list[i + 1];
// 只进行非常保守的优化
bool should_swap = false;
// 策略1: 将load指令提前减少load-use延迟
if (isLoadInstr(instr2) && !isLoadInstr(instr1) && !isStoreInstr(instr1)) {
should_swap = canSwapInstructions(instr1, instr2);
}
// 策略2: 将非关键store指令延后为其他指令让路
else if (isStoreInstr(instr1) && !isLoadInstr(instr2) && !isStoreInstr(instr2)) {
should_swap = canSwapInstructions(instr1, instr2);
}
if (should_swap) {
std::swap(instr_list[i], instr_list[i + 1]);
changed = true;
// 调试输出
// std::cout << "Swapped instructions at positions " << i << " and " << (i+1) << std::endl;
}
}
}
// 验证调度结果的正确性
validateSchedule(instr_list);
// 将调度后的指令顺序写回
std::map<MachineInstr*, std::unique_ptr<MachineInstr>> instr_map;
for (auto& instr : instructions) {
instr_map[instr.get()] = std::move(instr);
}
instructions.clear();
for (auto instr : instr_list) {
instructions.push_back(std::move(instr_map[instr]));
}
}
bool PostRA_Scheduler::runOnFunction(Function *F, AnalysisManager& AM) {
// 这个函数在IR级别运行但我们需要在机器指令级别运行
// 所以我们返回false表示没有对IR进行修改
return false;
}
void PostRA_Scheduler::runOnMachineFunction(MachineFunction *mfunc) {
// std::cout << "Running Post-RA Local Scheduler... " << std::endl;
// 遍历每个机器基本块
for (auto& mbb : mfunc->getBlocks()) {
scheduleBlock(mbb.get());
}
}
} // namespace sysy

View File

@ -0,0 +1,410 @@
#include "PreRA_Scheduler.h"
#include "RISCv64LLIR.h"
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#define MAX_SCHEDULING_BLOCK_SIZE 1000 // 严格限制调度块大小
namespace sysy {
char PreRA_Scheduler::ID = 0;
// 检查指令是否是加载指令 (LW, LD)
static bool isLoadInstr(MachineInstr *instr) {
RVOpcodes opcode = instr->getOpcode();
return opcode == RVOpcodes::LW || opcode == RVOpcodes::LD ||
opcode == RVOpcodes::LH || opcode == RVOpcodes::LB ||
opcode == RVOpcodes::LHU || opcode == RVOpcodes::LBU ||
opcode == RVOpcodes::LWU;
}
// 检查指令是否是存储指令 (SW, SD)
static bool isStoreInstr(MachineInstr *instr) {
RVOpcodes opcode = instr->getOpcode();
return opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
opcode == RVOpcodes::SH || opcode == RVOpcodes::SB;
}
// 检查指令是否为分支指令
static bool isBranchInstr(MachineInstr *instr) {
RVOpcodes opcode = instr->getOpcode();
return opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU;
}
// 检查指令是否为跳转指令
static bool isJumpInstr(MachineInstr *instr) {
RVOpcodes opcode = instr->getOpcode();
return opcode == RVOpcodes::J;
}
// 检查指令是否为返回指令
static bool isReturnInstr(MachineInstr *instr) {
return instr->getOpcode() == RVOpcodes::RET;
}
// 检查指令是否为调用指令
static bool isCallInstr(MachineInstr *instr) {
return instr->getOpcode() == RVOpcodes::CALL;
}
// 检查指令是否为块终结指令(必须保持在块尾)
static bool isTerminatorInstr(MachineInstr *instr) {
return isBranchInstr(instr) || isJumpInstr(instr) || isReturnInstr(instr);
}
// 检查指令是否有副作用(需要谨慎处理)
static bool hasSideEffect(MachineInstr *instr) {
return isStoreInstr(instr) || isCallInstr(instr) || isTerminatorInstr(instr);
}
// 检查指令是否涉及内存操作
static bool hasMemoryAccess(MachineInstr *instr) {
return isLoadInstr(instr) || isStoreInstr(instr);
}
// 获取指令定义的虚拟寄存器
static std::set<unsigned> getDefinedVirtualRegisters(MachineInstr *instr) {
std::set<unsigned> defined_regs;
RVOpcodes opcode = instr->getOpcode();
// CALL指令可能定义返回值寄存器
if (opcode == RVOpcodes::CALL) {
if (!instr->getOperands().empty() &&
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
auto reg_op =
static_cast<RegOperand *>(instr->getOperands().front().get());
if (reg_op->isVirtual()) {
defined_regs.insert(reg_op->getVRegNum());
}
}
return defined_regs;
}
// 存储指令和终结指令不定义寄存器
if (isStoreInstr(instr) || isTerminatorInstr(instr)) {
return defined_regs;
}
// 其他指令的第一个操作数通常是目标寄存器
if (!instr->getOperands().empty() &&
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand *>(instr->getOperands().front().get());
if (reg_op->isVirtual()) {
defined_regs.insert(reg_op->getVRegNum());
}
}
return defined_regs;
}
// 获取指令使用的虚拟寄存器
static std::set<unsigned> getUsedVirtualRegisters(MachineInstr *instr) {
std::set<unsigned> used_regs;
RVOpcodes opcode = instr->getOpcode();
// CALL指令跳过第一个操作数返回值其余为参数
if (opcode == RVOpcodes::CALL) {
bool first_reg_skipped = false;
for (const auto &op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
if (!first_reg_skipped) {
first_reg_skipped = true;
continue;
}
auto reg_op = static_cast<RegOperand *>(op.get());
if (reg_op->isVirtual()) {
used_regs.insert(reg_op->getVRegNum());
}
}
}
return used_regs;
}
// 存储指令和终结指令:所有操作数都是使用的
if (isStoreInstr(instr) || isTerminatorInstr(instr)) {
for (const auto &op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand *>(op.get());
if (reg_op->isVirtual()) {
used_regs.insert(reg_op->getVRegNum());
}
} else if (op->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<MemOperand *>(op.get());
if (mem_op->getBase()->isVirtual()) {
used_regs.insert(mem_op->getBase()->getVRegNum());
}
}
}
return used_regs;
}
// 其他指令:跳过第一个操作数(目标寄存器),其余为源操作数
bool first_reg = true;
for (const auto &op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
if (first_reg) {
first_reg = false;
continue;
}
auto reg_op = static_cast<RegOperand *>(op.get());
if (reg_op->isVirtual()) {
used_regs.insert(reg_op->getVRegNum());
}
} else if (op->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<MemOperand *>(op.get());
if (mem_op->getBase()->isVirtual()) {
used_regs.insert(mem_op->getBase()->getVRegNum());
}
}
}
return used_regs;
}
// 获取内存访问位置信息
struct MemoryLocation {
unsigned base_reg;
int64_t offset;
bool is_valid;
MemoryLocation() : base_reg(0), offset(0), is_valid(false) {}
MemoryLocation(unsigned base, int64_t off)
: base_reg(base), offset(off), is_valid(true) {}
bool operator==(const MemoryLocation &other) const {
return is_valid && other.is_valid && base_reg == other.base_reg &&
offset == other.offset;
}
};
// 获取内存访问位置
static MemoryLocation getMemoryLocation(MachineInstr *instr) {
if (!isLoadInstr(instr) && !isStoreInstr(instr)) {
return MemoryLocation();
}
for (const auto &op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<MemOperand *>(op.get());
if (mem_op->getBase()->isVirtual()) {
return MemoryLocation(mem_op->getBase()->getVRegNum(),
mem_op->getOffset()->getValue());
}
}
}
return MemoryLocation();
}
// 检查两个内存位置是否可能别名
static bool mayAlias(const MemoryLocation &loc1, const MemoryLocation &loc2) {
if (!loc1.is_valid || !loc2.is_valid) {
return true; // 保守处理:未知位置可能别名
}
// 不同基址寄存器,保守假设可能别名
if (loc1.base_reg != loc2.base_reg) {
return true;
}
// 相同基址寄存器,检查偏移
return loc1.offset == loc2.offset;
}
// 检查两个指令之间是否存在数据依赖
static bool hasDataDependency(MachineInstr *first, MachineInstr *second) {
auto defined_regs_first = getDefinedVirtualRegisters(first);
auto used_regs_first = getUsedVirtualRegisters(first);
auto defined_regs_second = getDefinedVirtualRegisters(second);
auto used_regs_second = getUsedVirtualRegisters(second);
// RAW依赖: second读取first写入的寄存器
for (const auto &reg : defined_regs_first) {
if (used_regs_second.count(reg)) {
return true;
}
}
// WAR依赖: second写入first读取的寄存器
for (const auto &reg : used_regs_first) {
if (defined_regs_second.count(reg)) {
return true;
}
}
// WAW依赖: 两个指令写入同一寄存器
for (const auto &reg : defined_regs_first) {
if (defined_regs_second.count(reg)) {
return true;
}
}
return false;
}
// 检查两个指令之间是否存在内存依赖
static bool hasMemoryDependency(MachineInstr *first, MachineInstr *second) {
bool first_accesses_memory = isLoadInstr(first) || isStoreInstr(first);
bool second_accesses_memory = isLoadInstr(second) || isStoreInstr(second);
if (!first_accesses_memory || !second_accesses_memory) {
return false;
}
// 如果至少有一个是存储指令,需要检查别名
if (isStoreInstr(first) || isStoreInstr(second)) {
MemoryLocation loc1 = getMemoryLocation(first);
MemoryLocation loc2 = getMemoryLocation(second);
return mayAlias(loc1, loc2);
}
return false; // 两个加载指令之间没有依赖
}
// 检查两个指令之间是否存在控制依赖
static bool hasControlDependency(MachineInstr *first, MachineInstr *second) {
// 终结指令与任何其他指令都有控制依赖
if (isTerminatorInstr(first)) {
return true; // first是终结指令second不能移动到first之前
}
if (isTerminatorInstr(second)) {
return false; // second是终结指令可以保持在后面
}
// CALL指令具有控制副作用但可以参与有限的调度
if (isCallInstr(first) || isCallInstr(second)) {
// CALL指令之间保持顺序
if (isCallInstr(first) && isCallInstr(second)) {
return true;
}
// 其他情况允许调度(通过数据依赖控制)
}
return false;
}
// 综合检查两个指令是否可以交换
static bool canSwapInstructions(MachineInstr *first, MachineInstr *second) {
// 检查所有类型的依赖
if (hasDataDependency(first, second) || hasDataDependency(second, first)) {
return false;
}
if (hasMemoryDependency(first, second)) {
return false;
}
if (hasControlDependency(first, second) ||
hasControlDependency(second, first)) {
return false;
}
return true;
}
// 找到基本块中的调度边界
static std::vector<size_t>
findSchedulingBoundaries(const std::vector<MachineInstr *> &instrs) {
std::vector<size_t> boundaries;
boundaries.push_back(0); // 起始边界
for (size_t i = 0; i < instrs.size(); i++) {
// 终结指令前后都是边界
if (isTerminatorInstr(instrs[i])) {
if (i > 0)
boundaries.push_back(i);
if (i + 1 < instrs.size())
boundaries.push_back(i + 1);
}
// 跳转目标标签也可能是边界(这里简化处理)
}
boundaries.push_back(instrs.size()); // 结束边界
// 去重并排序
std::sort(boundaries.begin(), boundaries.end());
boundaries.erase(std::unique(boundaries.begin(), boundaries.end()),
boundaries.end());
return boundaries;
}
// 在单个调度区域内进行指令调度
static void scheduleRegion(std::vector<MachineInstr *> &instrs, size_t start,
size_t end) {
if (end - start <= 1) {
return; // 区域太小,无需调度
}
// 保守的调度策略:
// 1. 只对小规模区域进行调度
// 2. 优先将加载指令向前调度,以隐藏内存延迟
// 3. 确保不破坏数据依赖和内存依赖
// 简单的调度算法:只尝试将加载指令尽可能前移
for (size_t i = start + 1; i < end; i++) {
if (isLoadInstr(instrs[i])) {
// 尝试将加载指令向前移动
for (size_t j = i; j > start; j--) {
// 检查是否可以与前一条指令交换
if (canSwapInstructions(instrs[j - 1], instrs[j])) {
std::swap(instrs[j - 1], instrs[j]);
} else {
// 一旦遇到依赖关系就停止移动
break;
}
}
}
}
}
static void scheduleBlock(MachineBasicBlock *mbb) {
auto &instructions = mbb->getInstructions();
if (instructions.size() <= 1 ||
instructions.size() > MAX_SCHEDULING_BLOCK_SIZE) {
return;
}
// 构建指令列表
std::vector<MachineInstr *> instr_list;
for (auto &instr : instructions) {
instr_list.push_back(instr.get());
}
// 找到调度边界
std::vector<size_t> boundaries = findSchedulingBoundaries(instr_list);
// 在每个调度区域内进行局部调度
for (size_t i = 0; i < boundaries.size() - 1; i++) {
size_t region_start = boundaries[i];
size_t region_end = boundaries[i + 1];
scheduleRegion(instr_list, region_start, region_end);
}
// 重建指令序列
std::map<MachineInstr *, std::unique_ptr<MachineInstr>> instr_map;
for (auto &instr : instructions) {
instr_map[instr.get()] = std::move(instr);
}
instructions.clear();
for (auto *instr : instr_list) {
instructions.push_back(std::move(instr_map[instr]));
}
}
bool PreRA_Scheduler::runOnFunction(Function *F, AnalysisManager &AM) {
return false;
}
void PreRA_Scheduler::runOnMachineFunction(MachineFunction *mfunc) {
for (auto &mbb : mfunc->getBlocks()) {
scheduleBlock(mbb.get());
}
}
} // namespace sysy

View File

@ -22,41 +22,12 @@ void RISCv64AsmPrinter::run(std::ostream& os, bool debug) {
OS = &os;
*OS << ".globl " << MFunc->getName() << "\n";
*OS << MFunc->getName() << ":\n";
printPrologue();
for (auto& mbb : MFunc->getBlocks()) {
printBasicBlock(mbb.get(), debug);
}
}
// 在 RISCv64AsmPrinter.cpp 文件中
void RISCv64AsmPrinter::printPrologue() {
StackFrameInfo& frame_info = MFunc->getFrameInfo();
// 序言需要为保存ra和s0预留16字节
int total_stack_size = frame_info.locals_size + frame_info.spill_size + 16;
int aligned_stack_size = (total_stack_size + 15) & ~15;
frame_info.total_size = aligned_stack_size;
if (aligned_stack_size > 0) {
*OS << " addi sp, sp, -" << aligned_stack_size << "\n";
*OS << " sd ra, " << (aligned_stack_size - 8) << "(sp)\n";
*OS << " sd s0, " << (aligned_stack_size - 16) << "(sp)\n";
*OS << " addi s0, sp, " << aligned_stack_size << "\n";
}
}
void RISCv64AsmPrinter::printEpilogue() {
int aligned_stack_size = MFunc->getFrameInfo().total_size;
if (aligned_stack_size > 0) {
*OS << " ld ra, " << (aligned_stack_size - 8) << "(sp)\n";
*OS << " ld s0, " << (aligned_stack_size - 16) << "(sp)\n";
*OS << " addi sp, sp, " << aligned_stack_size << "\n";
}
}
void RISCv64AsmPrinter::printBasicBlock(MachineBasicBlock* mbb, bool debug) {
if (!mbb->getName().empty()) {
*OS << mbb->getName() << ":\n";
@ -68,9 +39,6 @@ void RISCv64AsmPrinter::printBasicBlock(MachineBasicBlock* mbb, bool debug) {
void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
auto opcode = instr->getOpcode();
if (opcode == RVOpcodes::RET) {
printEpilogue();
}
if (opcode == RVOpcodes::LABEL) {
// 标签直接打印,不加缩进
@ -115,7 +83,18 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
case RVOpcodes::MV: *OS << "mv "; break; case RVOpcodes::NEG: *OS << "neg "; break;
case RVOpcodes::NEGW: *OS << "negw "; break; case RVOpcodes::SEQZ: *OS << "seqz "; break;
case RVOpcodes::SNEZ: *OS << "snez "; break;
case RVOpcodes::CALL: *OS << "call "; break;
case RVOpcodes::CALL: { // [核心修改] 为CALL指令添加特殊处理逻辑
*OS << "call ";
// 遍历所有操作数,只寻找并打印函数名标签
for (const auto& op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_LABEL) {
printOperand(op.get());
break; // 找到标签后即可退出
}
}
*OS << "\n";
return; // 处理完毕,直接返回,不再执行后续的通用操作数打印
}
case RVOpcodes::LABEL:
break;
case RVOpcodes::FRAME_LOAD_W:

View File

@ -2,7 +2,7 @@
#include "RISCv64ISel.h"
#include "RISCv64RegAlloc.h"
#include "RISCv64AsmPrinter.h"
#include "RISCv64Passes.h" // 包含优化Pass的头文件
#include "RISCv64Passes.h"
#include <sstream>
namespace sysy {
@ -107,6 +107,7 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
RISCv64ISel isel;
std::unique_ptr<MachineFunction> mfunc = isel.runOnFunction(func);
// 第一次调试打印输出
std::stringstream ss1;
RISCv64AsmPrinter printer1(mfunc.get());
printer1.run(ss1, true);
@ -119,7 +120,7 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
RISCv64RegAlloc reg_alloc(mfunc.get());
reg_alloc.run();
// 阶段 3.5: 处理被调用者保存寄存器
// 阶段 3.1: 处理被调用者保存寄存器
CalleeSavedHandler callee_handler;
callee_handler.runOnMachineFunction(mfunc.get());
@ -131,6 +132,14 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
PostRA_Scheduler local_scheduler;
local_scheduler.runOnMachineFunction(mfunc.get());
// 阶段 3.2: 插入序言和尾声
PrologueEpilogueInsertionPass pei_pass;
pei_pass.runOnMachineFunction(mfunc.get());
// 阶段 3.3: 清理产生的大立即数
LegalizeImmediatesPass legalizer;
legalizer.runOnMachineFunction(mfunc.get());
// 阶段 6: 代码发射 (Code Emission)
std::stringstream ss;
RISCv64AsmPrinter printer(mfunc.get());

View File

@ -52,8 +52,18 @@ std::unique_ptr<MachineFunction> RISCv64ISel::runOnFunction(Function* func) {
// 指令选择主流程
void RISCv64ISel::select() {
// 遍历基本块为它们创建对应的MachineBasicBlock
bool is_first_block = true;
for (const auto& bb_ptr : F->getBasicBlocks()) {
auto mbb = std::make_unique<MachineBasicBlock>(bb_ptr->getName(), MFunc.get());
std::string mbb_name;
if (is_first_block) {
// 对于函数的第一个基本块,其标签必须与函数名完全相同
mbb_name = F->getName();
is_first_block = false;
} else {
// 对于后续的基本块继续使用它们在IR中的原始名称
mbb_name = bb_ptr->getName();
}
auto mbb = std::make_unique<MachineBasicBlock>(mbb_name, MFunc.get());
bb_map[bb_ptr.get()] = mbb.get();
MFunc->addBlock(std::move(mbb));
}
@ -582,7 +592,22 @@ void RISCv64ISel::selectNode(DAGNode* node) {
}
auto call_instr = std::make_unique<MachineInstr>(RVOpcodes::CALL);
// [协议] 如果函数有返回值,将它的目标虚拟寄存器作为第一个操作数
if (!call->getType()->isVoid()) {
unsigned dest_vreg = getVReg(call);
call_instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
}
// 将函数名标签作为后续操作数
call_instr->addOperand(std::make_unique<LabelOperand>(call->getCallee()->getName()));
// 将所有参数的虚拟寄存器也作为后续操作数供getInstrUseDef分析
for (size_t i = 0; i < num_operands; ++i) {
if (node->operands[i]->kind != DAGNode::CONSTANT) { // 常量参数已直接加载无需作为use
call_instr->addOperand(std::make_unique<RegOperand>(getVReg(node->operands[i]->value)));
}
}
CurMBB->addInstruction(std::move(call_instr));
if (num_operands > 8) {
@ -596,12 +621,12 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(dealloc_instr));
}
// 处理返回值从a0移动到目标虚拟寄存器
if (!call->getType()->isVoid()) {
auto mv_instr = std::make_unique<MachineInstr>(RVOpcodes::MV);
mv_instr->addOperand(std::make_unique<RegOperand>(getVReg(call)));
mv_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
CurMBB->addInstruction(std::move(mv_instr));
}
// if (!call->getType()->isVoid()) {
// auto mv_instr = std::make_unique<MachineInstr>(RVOpcodes::MV);
// mv_instr->addOperand(std::make_unique<RegOperand>(getVReg(call)));
// mv_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
// CurMBB->addInstruction(std::move(mv_instr));
// }
break;
}
@ -942,25 +967,52 @@ RISCv64ISel::DAGNode* RISCv64ISel::create_node(int kind_int, Value* val, std::ma
return raw_node_ptr;
}
RISCv64ISel::DAGNode* RISCv64ISel::get_operand_node(Value* val_ir, std::map<Value*, DAGNode*>& value_to_node, std::vector<std::unique_ptr<DAGNode>>& nodes_storage) {
RISCv64ISel::DAGNode* RISCv64ISel::get_operand_node(
Value* val_ir,
std::map<Value*, DAGNode*>& value_to_node,
std::vector<std::unique_ptr<DAGNode>>& nodes_storage
) {
// 空指针错误处理
if (val_ir == nullptr) {
throw std::runtime_error("get_operand_node received a null Value.");
}
// 规则1如果这个Value已经有对应的节点直接返回
if (value_to_node.count(val_ir)) {
return value_to_node[val_ir];
} else if (dynamic_cast<ConstantValue*>(val_ir)) {
return value_to_node.at(val_ir);
}
// 规则2识别各种类型的叶子节点并创建相应的DAG节点
if (dynamic_cast<ConstantValue*>(val_ir)) {
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
} else if (dynamic_cast<GlobalValue*>(val_ir)) {
}
if (dynamic_cast<GlobalValue*>(val_ir)) {
// 全局变量/常量数组被视为一个常量地址
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
} else if (dynamic_cast<AllocaInst*>(val_ir)) {
}
if (dynamic_cast<AllocaInst*>(val_ir)) {
return create_node(DAGNode::ALLOCA_ADDR, val_ir, value_to_node, nodes_storage);
} else if (dynamic_cast<Argument*>(val_ir)) {
// Argument 是一个叶子节点,它代表一个在函数入口就可用的值。
}
if (dynamic_cast<Argument*>(val_ir)) {
return create_node(DAGNode::ARGUMENT, val_ir, value_to_node, nodes_storage);
}
// 默认行为:如果一个操作数不是上面任何一种叶子节点,
// 并且没有在value_to_node中找到意味着它不是由另一条指令定义的
// 这是一个逻辑问题。但为了保持向前兼容我们暂时保留旧的LOAD行为
// 尽管在修复Argument后它不应该再被错误触发。
return create_node(DAGNode::LOAD, val_ir, value_to_node, nodes_storage);
if (dynamic_cast<ConstantVariable*>(val_ir)) {
// 全局常量数组和全局变量类似,在指令选择层面都表现为一个常量地址
// 因此也为它创建一个 CONSTANT 类型的节点
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
}
// 如果代码执行到这里意味着val_ir不是上述任何一种叶子节点
// 且它也不是在当前基本块中定义的否则它会在value_to_node中被找到
// 这说明它是一个来自前驱块的Live-In值。
// 我们将其视为一个与函数参数(Argument)类似的“块输入值”并为它创建一个ARGUMENT节点。
// 这样,后续的指令选择逻辑就知道这个值是直接可用的,无需在当前块内计算。
if (dynamic_cast<Instruction*>(val_ir)) {
return create_node(DAGNode::ARGUMENT, val_ir, value_to_node, nodes_storage);
}
// 如果一个Value不是任何已知类型也不是指令那说明出现了未处理的情况抛出异常。
throw std::runtime_error("Unhandled Value type in get_operand_node for value named: " + val_ir->getName());
}
std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicBlock* bb) {
@ -1110,6 +1162,7 @@ void RISCv64ISel::print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, co
case DAGNode::ALLOCA_ADDR: return "ALLOCA_ADDR";
case DAGNode::UNARY: return "UNARY";
case DAGNode::MEMSET: return "MEMSET";
case DAGNode::GET_ELEMENT_PTR: return "GET_ELEMENT_PTR";
default: return "UNKNOWN";
}
};

View File

@ -1,5 +1,7 @@
#include "RISCv64RegAlloc.h"
#include "RISCv64ISel.h"
#include "RISCv64AsmPrinter.h" // For DEBUG output
#include "LegalizeImmediates.h"
#include <algorithm>
#include <vector>
#include <iostream> // For DEBUG output
@ -9,19 +11,29 @@ namespace sysy {
RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) : MFunc(mfunc) {
allocable_int_regs = {
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3,
PhysicalReg::T4, /*PhysicalReg::T5,*/PhysicalReg::T6,
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3,
PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7,
PhysicalReg::S0, PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3,
PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
};
// 创建一个包含所有通用整数寄存器的临时列表
const std::vector<PhysicalReg> all_int_regs = {
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3,
PhysicalReg::T4, PhysicalReg::T5, PhysicalReg::T6,
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3,
PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7,
// PhysicalReg::S0,
PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3,
PhysicalReg::S0, PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3,
PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
};
// 映射物理寄存器到特殊的虚拟寄存器ID用于干扰图中的物理寄存器节点
// 确保这些特殊ID不会与vreg_counter生成的常规虚拟寄存器ID冲突
for (PhysicalReg preg : allocable_int_regs) {
for (PhysicalReg preg : all_int_regs) {
preg_to_vreg_id_map[preg] = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID) + static_cast<unsigned>(preg);
}
}
@ -31,7 +43,24 @@ void RISCv64RegAlloc::run() {
// 阶段 1: 处理函数调用约定(参数寄存器预着色)
handleCallingConvention();
// 阶段 2: 消除帧索引(为局部变量和栈参数分配栈偏移)
eliminateFrameIndices();
eliminateFrameIndices();
// 调试输出当前的LLIR状态
{ // 使用大括号创建一个局部作用域避免printer变量泄露
if (DEBUG) {
std::cerr << "\n===== LLIR after eliminateFrameIndices for function: "
<< MFunc->getName() << " =====\n";
// 1. 创建一个 AsmPrinter 实例,传入当前的 MachineFunction
RISCv64AsmPrinter printer(MFunc);
// 2. 调用 run 方法,将结果打印到标准错误流 (std::cerr)
// 3. 必须将 debug 参数设为 true
// 因为此时指令中仍然包含虚拟寄存器 (%vreg)
// debug模式下的 AsmPrinter 才能正确处理它们而不会报错。
printer.run(std::cerr, true);
std::cerr << "===== End of LLIR =====\n\n";
}
}
// 阶段 3: 活跃性分析
analyzeLiveness();
// 阶段 4: 构建干扰图包含CALL指令对调用者保存寄存器的影响
@ -43,18 +72,22 @@ void RISCv64RegAlloc::run() {
}
/**
* @brief
* @brief
*
* 1. (callee)
* 2. (caller)
*/
void RISCv64RegAlloc::handleCallingConvention() {
Function* F = MFunc->getFunc();
RISCv64ISel* isel = MFunc->getISel();
// --- 部分1处理函数传入参数的预着色 ---
// 获取函数的Argument对象列表
if (F) {
auto& args = F->getArguments();
// RISC-V RV64G调用约定前8个整型/指针参数通过 a0-a7 传递
int arg_idx = 0;
// 遍历 AllocaInst* 列表
// 遍历 Argument* 列表
for (Argument* arg : args) {
if (arg_idx >= 8) {
break;
@ -75,6 +108,30 @@ void RISCv64RegAlloc::handleCallingConvention() {
arg_idx++;
}
}
// // --- 部分2[新逻辑] 遍历所有指令为CALL指令的返回值预着色为 a0 ---
// // 这是为了强制寄存器分配器知道call的结果物理上出现在a0寄存器。
for (auto& mbb : MFunc->getBlocks()) {
for (auto& instr : mbb->getInstructions()) {
if (instr->getOpcode() == RVOpcodes::CALL) {
// 根据协议如果CALL有返回值其目标vreg是第一个操作数
if (!instr->getOperands().empty() &&
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG)
{
auto reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
if (reg_op->isVirtual()) {
unsigned ret_vreg = reg_op->getVRegNum();
// 强制将这个虚拟寄存器预着色为 a0
color_map[ret_vreg] = PhysicalReg::A0;
if (DEBUG) {
std::cout << "[DEBUG] Pre-coloring vreg" << ret_vreg
<< " to a0 for CALL instruction." << std::endl;
}
}
}
}
}
}
}
/**
@ -231,76 +288,92 @@ void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet&
// JAL 和 JALR 指令定义 ra (x1)
if (opcode == RVOpcodes::JAL || opcode == RVOpcodes::JALR) {
// 使用 ra 对应的特殊虚拟寄存器ID
def.insert(static_cast<unsigned>(PhysicalReg::RA));
def.insert(preg_to_vreg_id_map.at(PhysicalReg::RA));
first_reg_is_def = false; // JAL/JALR 的第一个操作数是 ra已经处理为 def
}
// 2. CALL 指令的特殊处理
if (opcode == RVOpcodes::CALL) {
// 1.1 处理返回值 (def)
// 约定如果CALL指令有返回值IR阶段会将返回值vreg作为指令的第一个操作数。
if (!instr->getOperands().empty() && instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
if (reg_op->isVirtual()) {
def.insert(reg_op->getVRegNum());
}
}
// 1.2 处理参数 (use)
// 参数通常是指令的后续操作数
bool first_operand_processed = false; // 用于跳过已作为def处理的返回值
for (const auto& op : instr->getOperands()) {
// 根据 s1 分支 ISel 定义的协议来解析操作数列表
bool first_reg_operand_is_def = true;
for (auto& op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
if (!first_operand_processed) { // 如果是第一个操作数
first_operand_processed = true;
// 如果第一个操作数是返回值已被加入def则跳过
if (def.count(static_cast<RegOperand*>(op.get())->getVRegNum())) {
continue;
}
}
// 否则,该寄存器是 use
auto reg_op = static_cast<RegOperand*>(op.get());
if (reg_op->isVirtual()) {
use.insert(reg_op->getVRegNum());
// 协议:第一个寄存器操作数是返回值 (def)
if (first_reg_operand_is_def) {
def.insert(reg_op->getVRegNum());
first_reg_operand_is_def = false;
} else {
// 后续所有寄存器操作数都是参数 (use)
use.insert(reg_op->getVRegNum());
}
} else { // [修复] CALL指令也可能定义物理寄存器如a0
if (first_reg_operand_is_def) {
if (preg_to_vreg_id_map.count(reg_op->getPReg())) {
def.insert(preg_to_vreg_id_map.at(reg_op->getPReg()));
}
first_reg_operand_is_def = false;
} else {
if (preg_to_vreg_id_map.count(reg_op->getPReg())) {
use.insert(preg_to_vreg_id_map.at(reg_op->getPReg()));
}
}
}
}
}
// **重要**: CALL指令隐式定义杀死了所有调用者保存的寄存器。
// **这部分逻辑不在getInstrUseDef中直接处理**。
// 而是通过`buildInterferenceGraph`中添加物理寄存器节点与活跃虚拟寄存器之间的干扰边来完成。
// 这样 Liveness Analysis 可以在虚拟寄存器层面进行,而物理寄存器干扰的复杂性则留给干扰图。
return; // CALL 指令处理完毕,直接返回
return; // CALL 指令处理完毕
}
// 3. 对其他所有指令的通用处理逻辑
// 3. 对其他所有指令的通用处理逻辑 [已重构和修复]
for (const auto& op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(op.get());
if (reg_op->isVirtual()) { // 只有虚拟寄存器才需要处理 Use/Def
// 如果是第一个寄存器操作数,且指令类型表明它是定义 (def),则加入 def 集合
// 否则,它是 use (读取)
if (first_reg_is_def) {
if (first_reg_is_def) {
// --- 处理定义Def ---
if (reg_op->isVirtual()) {
def.insert(reg_op->getVRegNum());
first_reg_is_def = false; // 确保每条指令只定义一个目标寄存器
} else {
} else { // 物理寄存器也可以是 Def
if (preg_to_vreg_id_map.count(reg_op->getPReg())) {
def.insert(preg_to_vreg_id_map.at(reg_op->getPReg()));
}
}
first_reg_is_def = false; // **关键**:处理完第一个寄存器后,立即更新标志
} else {
// --- 处理使用Use ---
if (reg_op->isVirtual()) {
use.insert(reg_op->getVRegNum());
} else { // 物理寄存器也可以是 Use
if (preg_to_vreg_id_map.count(reg_op->getPReg())) {
use.insert(preg_to_vreg_id_map.at(reg_op->getPReg()));
}
}
}
} else if (op->getKind() == MachineOperand::KIND_MEM) {
// 内存操作数 `offset(base)` 中的 `base` 寄存器是 `use`
// [保持不变] 内存操作数的处理逻辑看起来是正确的
auto mem_op = static_cast<MemOperand*>(op.get());
if (mem_op->getBase()->isVirtual()) {
use.insert(mem_op->getBase()->getVRegNum());
auto base_reg = mem_op->getBase();
if (base_reg->isVirtual()) {
use.insert(base_reg->getVRegNum());
} else {
PhysicalReg preg = base_reg->getPReg();
if (preg_to_vreg_id_map.count(preg)) {
use.insert(preg_to_vreg_id_map.at(preg));
}
}
// 对于存储内存指令 (SW, SD),要存储的值(第一个操作数)也是 `use`
if ((opcode == RVOpcodes::SW || opcode == RVOpcodes::SD) &&
!instr->getOperands().empty() && // 确保有操作数
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) { // 且第一个操作数是寄存器
!instr->getOperands().empty() &&
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
auto src_reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
if (src_reg_op->isVirtual()) {
use.insert(src_reg_op->getVRegNum());
} else {
if (preg_to_vreg_id_map.count(src_reg_op->getPReg())) {
use.insert(preg_to_vreg_id_map.at(src_reg_op->getPReg()));
}
}
}
}
@ -345,45 +418,104 @@ unsigned RISCv64RegAlloc::getTypeSizeInBytes(Type* type) {
}
void RISCv64RegAlloc::analyzeLiveness() {
// === 阶段 1: 预计算每个基本块的 use 和 def 集合 ===
// 这样可以避免在主循环中重复计算
std::map<MachineBasicBlock*, LiveSet> block_uses;
std::map<MachineBasicBlock*, LiveSet> block_defs;
for (auto& mbb_ptr : MFunc->getBlocks()) {
MachineBasicBlock* mbb = mbb_ptr.get();
LiveSet uses, defs;
for (auto& instr_ptr : mbb->getInstructions()) {
LiveSet instr_use, instr_def;
getInstrUseDef(instr_ptr.get(), instr_use, instr_def);
// use[B] = use[B] U (instr_use - def[B])
for (unsigned u : instr_use) {
if (defs.find(u) == defs.end()) {
uses.insert(u);
}
}
// def[B] = def[B] U instr_def
defs.insert(instr_def.begin(), instr_def.end());
}
block_uses[mbb] = uses;
block_defs[mbb] = defs;
}
// === 阶段 2: 在“块”粒度上进行迭代数据流分析,直到收敛 ===
std::map<MachineBasicBlock*, LiveSet> block_live_in;
std::map<MachineBasicBlock*, LiveSet> block_live_out;
bool changed = true;
while (changed) {
changed = false;
// 以逆后序遍历基本块,可以加速收敛,但简单的逆序对于大多数情况也有效
for (auto it = MFunc->getBlocks().rbegin(); it != MFunc->getBlocks().rend(); ++it) {
auto& mbb = *it;
LiveSet live_out;
// 2.1 计算 live_out[B] = U_{S in succ(B)} live_in[S]
LiveSet new_live_out;
for (auto succ : mbb->successors) {
if (!succ->getInstructions().empty()) {
auto first_instr = succ->getInstructions().front().get();
if (live_in_map.count(first_instr)) {
live_out.insert(live_in_map.at(first_instr).begin(), live_in_map.at(first_instr).end());
}
}
new_live_out.insert(block_live_in[succ].begin(), block_live_in[succ].end());
}
for (auto instr_it = mbb->getInstructions().rbegin(); instr_it != mbb->getInstructions().rend(); ++instr_it) {
MachineInstr* instr = instr_it->get();
LiveSet old_live_in = live_in_map[instr];
live_out_map[instr] = live_out;
LiveSet use, def;
getInstrUseDef(instr, use, def);
// 2.2 计算 live_in[B] = use[B] U (live_out[B] - def[B])
LiveSet live_out_minus_def = new_live_out;
for (unsigned d : block_defs[mbb.get()]) {
live_out_minus_def.erase(d);
}
LiveSet new_live_in = block_uses[mbb.get()];
new_live_in.insert(live_out_minus_def.begin(), live_out_minus_def.end());
LiveSet live_in = use;
LiveSet diff = live_out;
for (auto vreg : def) {
diff.erase(vreg);
}
live_in.insert(diff.begin(), diff.end());
live_in_map[instr] = live_in;
live_out = live_in;
if (live_in_map[instr] != old_live_in) {
changed = true;
}
// 2.3 检查 live_in 和 live_out 是否变化,以判断是否达到不动点
if (block_live_out[mbb.get()] != new_live_out) {
changed = true;
block_live_out[mbb.get()] = new_live_out;
}
if (block_live_in[mbb.get()] != new_live_in) {
changed = true;
block_live_in[mbb.get()] = new_live_in;
}
}
}
// === 阶段 3: 进行一次指令粒度的遍历,填充最终的 live_in_map 和 live_out_map ===
// 此时块级别的活跃信息已经稳定,我们只需遍历一次即可
for (auto& mbb_ptr : MFunc->getBlocks()) {
MachineBasicBlock* mbb = mbb_ptr.get();
LiveSet live_out = block_live_out[mbb]; // 从已收敛的块级 live_out 开始
for (auto instr_it = mbb->getInstructions().rbegin(); instr_it != mbb->getInstructions().rend(); ++instr_it) {
MachineInstr* instr = instr_it->get();
live_out_map[instr] = live_out;
LiveSet use, def;
getInstrUseDef(instr, use, def);
LiveSet live_in = use;
LiveSet diff = live_out;
for (auto vreg : def) {
diff.erase(vreg);
}
live_in.insert(diff.begin(), diff.end());
live_in_map[instr] = live_in;
// 更新 live_out为块内的上一条指令做准备
live_out = live_in;
}
}
}
// 辅助函数,用于清晰地打印寄存器集合。可以放在 .cpp 文件的顶部。
void RISCv64RegAlloc::printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os) {
os << " " << name << ": { ";
for (unsigned vreg : s) {
// 为了可读性将物理寄存器对应的特殊ID进行转换
if (vreg >= static_cast<unsigned>(sysy::PhysicalReg::PHYS_REG_START_ID)) {
os << "preg(" << (vreg - static_cast<unsigned>(sysy::PhysicalReg::PHYS_REG_START_ID)) << ") ";
} else {
os << "%vreg" << vreg << " ";
}
}
os << "}\n";
}
void RISCv64RegAlloc::buildInterferenceGraph() {
@ -402,42 +534,104 @@ void RISCv64RegAlloc::buildInterferenceGraph() {
all_vregs.insert(preg_to_vreg_id_map.at(preg));
}
// 初始化干扰图邻接表
for (auto vreg : all_vregs) { interference_graph[vreg] = {}; }
// 创建一个临时的AsmPrinter用于打印指令方便调试
RISCv64AsmPrinter temp_printer(MFunc);
temp_printer.setStream(std::cerr);
for (auto& mbb : MFunc->getBlocks()) {
for (auto& instr : mbb->getInstructions()) {
if (DEEPDEBUG) std::cerr << "--- Building Graph for Basic Block: " << mbb->getName() << " ---\n";
for (auto& instr_ptr : mbb->getInstructions()) {
MachineInstr* instr = instr_ptr.get();
if (DEEPDEBUG) {
// 打印当前正在处理的指令
std::cerr << " Instr: ";
temp_printer.printInstruction(instr, true); // 使用 true 来打印虚拟寄存器
}
LiveSet def, use;
getInstrUseDef(instr.get(), use, def);
const LiveSet& live_out = live_out_map.at(instr.get());
getInstrUseDef(instr, use, def);
const LiveSet& live_out = live_out_map.at(instr);
// [新增调试逻辑] 打印所有相关的寄存器集合
if (DEEPDEBUG) {
printLiveSet(use, "Use ", std::cerr);
printLiveSet(def, "Def ", std::cerr);
printLiveSet(live_out, "Live_Out", std::cerr); // 这是我们最关心的信息
}
// 标准干扰图构建def 与 live_out 中的其他变量干扰
for (unsigned d : def) {
for (unsigned l : live_out) {
if (d != l) {
// [新增调试逻辑] 打印添加的干扰边及其原因
if (DEEPDEBUG && interference_graph[d].find(l) == interference_graph[d].end()) {
std::cerr << " Edge (Def-LiveOut): %vreg" << d << " <-> %vreg" << l << "\n";
}
interference_graph[d].insert(l);
interference_graph[l].insert(d);
}
}
}
// *** 核心修改点:处理 CALL 指令的隐式 def ***
if (instr->getOpcode() == RVOpcodes::CALL) {
// CALL 指令会定义(杀死)所有调用者保存的寄存器。
// 因此,所有调用者保存的物理寄存器都与 CALL 指令的 live_out 中的所有变量冲突。
const std::vector<PhysicalReg>& caller_saved_regs = getCallerSavedIntRegs();
for (PhysicalReg cs_reg : caller_saved_regs) {
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg); // 获取物理寄存器对应的特殊vreg ID
// 将这个物理寄存器节点与 CALL 指令的 live_out 中的所有虚拟寄存器添加干扰边。
for (unsigned live_vreg_out : live_out) {
if (cs_vreg_id != live_vreg_out) { // 避免自己和自己干扰
interference_graph[cs_vreg_id].insert(live_vreg_out);
interference_graph[live_vreg_out].insert(cs_vreg_id);
// 在非move指令中def 与 use 互相干扰
if (instr->getOpcode() != RVOpcodes::MV) {
for (unsigned d : def) {
for (unsigned u : use) {
if (d != u) {
// [新增调试逻辑] 打印添加的干扰边及其原因
if (DEEPDEBUG && interference_graph[d].find(u) == interference_graph[d].end()) {
std::cerr << " Edge (Def-Use) : %vreg" << d << " <-> %vreg" << u << "\n";
}
interference_graph[d].insert(u);
interference_graph[u].insert(d);
}
}
}
}
// *** 处理 CALL 指令的隐式 def ***
if (instr->getOpcode() == RVOpcodes::CALL) {
// 你的原始CALL调试信息
if (DEEPDEBUG) {
std::string live_out_str;
for (unsigned vreg : live_out) {
live_out_str += "%vreg" + std::to_string(vreg) + " ";
}
std::cerr << "[DEEPDEBUG] buildInterferenceGraph: CALL instruction found. Live out set is: {"
<< live_out_str << "}" << std::endl;
}
// CALL 指令会定义(杀死)所有调用者保存的寄存器。
// 因此,所有调用者保存的物理寄存器都与 CALL 指令的 live_out 中的所有变量冲突。
const std::vector<PhysicalReg>& caller_saved_regs = getCallerSavedIntRegs();
for (PhysicalReg cs_reg : caller_saved_regs) {
if (preg_to_vreg_id_map.count(cs_reg)) {
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg); // 获取物理寄存器对应的特殊vreg ID
// 将这个物理寄存器节点与 CALL 指令的 live_out 中的所有虚拟寄存器添加干扰边。
for (unsigned live_vreg_out : live_out) {
if (cs_vreg_id != live_vreg_out) { // 避免自己和自己干扰
// [新增调试逻辑] 打印添加的干扰边及其原因
if (DEEPDEBUG && interference_graph[cs_vreg_id].find(live_vreg_out) == interference_graph[cs_vreg_id].end()) {
std::cerr << " Edge (CALL) : preg(" << static_cast<int>(cs_reg) << ") <-> %vreg" << live_vreg_out << "\n";
}
interference_graph[cs_vreg_id].insert(live_vreg_out);
interference_graph[live_vreg_out].insert(cs_vreg_id);
}
}
} else {
// 如果物理寄存器没有对应的特殊虚拟寄存器ID可能是因为它不是调用者保存的寄存器。
// 这种情况通常不应该发生,但我们可以在这里添加一个警告或错误处理。
if (DEEPDEBUG) {
std::cerr << "Warning: Physical register " << static_cast<int>(cs_reg)
<< " does not have a corresponding special vreg ID.\n";
}
}
}
}
if (DEEPDEBUG) std::cerr << " ----------------\n";
}
}
}
@ -445,7 +639,8 @@ void RISCv64RegAlloc::buildInterferenceGraph() {
void RISCv64RegAlloc::colorGraph() {
std::vector<unsigned> sorted_vregs;
for (auto const& [vreg, neighbors] : interference_graph) {
if (color_map.find(vreg) == color_map.end()) {
// 只为未预着色的虚拟寄存器排序和着色
if (color_map.find(vreg) == color_map.end() && vreg < static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID)) {
sorted_vregs.push_back(vreg);
}
}
@ -459,7 +654,7 @@ void RISCv64RegAlloc::colorGraph() {
for (unsigned vreg : sorted_vregs) {
std::set<PhysicalReg> used_colors;
for (unsigned neighbor_id : interference_graph.at(vreg)) {
// --- 修改开始 ---
// --- 关键改进 (来自 rec 分支) ---
// 情况 1: 邻居是一个已经被着色的虚拟寄存器
if (color_map.count(neighbor_id)) {
@ -467,18 +662,10 @@ void RISCv64RegAlloc::colorGraph() {
}
// 情况 2: 邻居本身就是一个代表物理寄存器的节点
else if (neighbor_id >= static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID)) {
// 需要一个反向映射来从特殊ID找回PhysicalReg
// 假设你有这样一个映射 inv_preg_to_vreg_id_map
// 或者,你可以重新计算
for (auto const& [preg, id] : preg_to_vreg_id_map) {
if (id == neighbor_id) {
used_colors.insert(preg);
break;
}
}
// 从特殊ID反向解析出是哪个物理寄存器
PhysicalReg neighbor_preg = static_cast<PhysicalReg>(neighbor_id - static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID));
used_colors.insert(neighbor_preg);
}
// --- 修改结束 ---
}
bool colored = false;

View File

@ -0,0 +1,17 @@
# src/frontend/CMakeLists.txt
add_library(frontend_lib STATIC
SysYBaseVisitor.cpp
SysY.g4
SysYLexer.cpp
SysYParser.cpp
SysYVisitor.cpp
)
# 包含前端模块所需的头文件路径
target_include_directories(frontend_lib PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../include/frontend # 前端头文件
${ANTLR_RUNTIME}/runtime/src # ANTLR 运行时头文件
)
# 链接 ANTLR 运行时库
target_link_libraries(frontend_lib PRIVATE antlr4_shared)

View File

@ -1,59 +0,0 @@
#pragma once
#include "IR.h" // 假设IR.h包含了Module, Function, BasicBlock, Instruction, Value, IRBuilder, Type等定义
#include "IRBuilder.h" // 需要IRBuilder来创建新指令
#include "SysYIRPrinter.h" // 新增: 用于调试输出
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include <list> // 用于迭代和修改指令列表
#include <algorithm> // for std::reverse (if needed, although not used in final version)
#include <iostream> // MODIFICATION: 用于警告输出
namespace sysy {
/**
* @brief AddressCalculationExpansion Pass
*
* 这是一个IR优化Pass用于将LoadInst和StoreInst中包含的多维数组索引
* 显式地转换为IR中的BinaryInst乘法和加法序列并生成带有线性偏移量的
* LoadInst/StoreInst。
*
* 目的确保在寄存器分配之前所有中间地址计算的结果都有明确的IR指令和对应的虚拟寄存器
* 从而避免在后端DAG构建时临时创建值而导致寄存器分配缺失的问题。
*
* SysY语言特性
* - 无指针类型所有数组访问的基地址是alloca或global的AllocaType/ArrayType
* - 数据类型只有int和float且都占用4字节。
* - LoadInst和StoreInst直接接受多个索引作为额外操作数。
*/
class AddressCalculationExpansion {
private:
Module* pModule;
IRBuilder* pBuilder; // 用于在IR中插入新指令
// 数组元素的固定大小根据SysY特性int和float都是4字节
static const int ELEMENT_SIZE = 4;
// 辅助函数:根据数组的维度信息和当前索引的维度,计算该索引的步长(字节数)
// dims: 包含所有维度大小的vector例如 {2, 3, 4}
// currentDimIndex: 当前正在处理的索引在 dims 中的位置 (0, 1, 2...)
int calculateStride(const std::vector<int>& dims, size_t currentDimIndex) {
int stride = ELEMENT_SIZE; // 最内层元素大小 (4字节)
// 乘以当前维度之后的所有维度的大小
for (size_t i = currentDimIndex + 1; i < dims.size(); ++i) {
stride *= dims[i];
}
return stride;
}
public:
AddressCalculationExpansion(Module* module, IRBuilder* builder)
: pModule(module), pBuilder(builder) {}
// 运行此Pass
bool run();
};
} // namespace sysy

View File

@ -1,75 +0,0 @@
#ifndef RISCV64_PASSES_H
#define RISCV64_PASSES_H
#include "RISCv64LLIR.h"
namespace sysy {
/**
* @class BackendPass
* @brief 所有优化Pass的抽象基类 (可选,但推荐)
* * 定义一个通用的接口,所有优化都应该实现它。
*/
class BackendPass {
public:
virtual ~BackendPass() = default;
virtual void runOnMachineFunction(MachineFunction* mfunc) = 0;
};
// --- 寄存器分配前优化 ---
/**
* @class PreRA_Scheduler
* @brief 寄存器分配前的指令调度器
* * 在虚拟寄存器上进行操作,此时调度自由度最大,
* 主要目标是隐藏指令延迟,提高流水线效率。
*/
class PreRA_Scheduler : public BackendPass {
public:
void runOnMachineFunction(MachineFunction* mfunc) override;
};
/**
* @class CalleeSavedHandler
* @brief 处理被调用者保存寄存器(Callee-Saved Registers)的Pass。
* * 这个Pass在寄存器分配之后运行。它的主要职责是
* 1. 扫描整个函数,找出所有被使用的 `s` 系列寄存器。
* 2. 在函数序言中插入 `sd` 指令来保存这些寄存器。
* 3. 在函数结尾ret指令前插入 `ld` 指令来恢复这些寄存器。
* 4. 正确计算因保存这些寄存器而需要的额外栈空间并更新StackFrameInfo。
*/
class CalleeSavedHandler : public BackendPass {
public:
void runOnMachineFunction(MachineFunction* mfunc) override;
};
// --- 寄存器分配后优化 ---
/**
* @class PeepholeOptimizer
* @brief 窥孔优化器
* * 在已分配物理寄存器的指令流上,通过一个小的滑动窗口来查找
* 并替换掉一些冗余或低效的指令模式。
*/
class PeepholeOptimizer : public BackendPass {
public:
void runOnMachineFunction(MachineFunction* mfunc) override;
};
/**
* @class PostRA_Scheduler
* @brief 寄存器分配后的局部指令调度器
* * 主要目标是优化寄存器分配器插入的spill/fill代码(lw/sw)
* 尝试将加载指令提前,以隐藏其访存延迟。
*/
class PostRA_Scheduler : public BackendPass {
public:
void runOnMachineFunction(MachineFunction* mfunc) override;
};
} // namespace sysy
#endif // RISCV64_PASSES_H

View File

@ -1,196 +0,0 @@
#pragma once
#include "IR.h"
namespace sysy {
// 稀疏条件常量传播类
// Sparse Conditional Constant Propagation
/*
伪代码
function SCCP_Optimization(Module):
for each Function in Module:
changed = true
while changed:
changed = false
// 阶段1: 常量传播与折叠
changed |= PropagateConstants(Function)
// 阶段2: 控制流简化
changed |= SimplifyControlFlow(Function)
end while
end for
function PropagateConstants(Function):
// 初始化
executableBlocks = {entryBlock}
valueState = map<Value, State> // 值->状态映射
instWorkList = Queue()
edgeWorkList = Queue()
// 初始化工作列表
for each inst in entryBlock:
instWorkList.push(inst)
// 迭代处理
while !instWorkList.empty() || !edgeWorkList.empty():
// 处理指令工作列表
while !instWorkList.empty():
inst = instWorkList.pop()
// 如果指令是可执行基本块中的
if executableBlocks.contains(inst.parent):
ProcessInstruction(inst)
// 处理边工作列表
while !edgeWorkList.empty():
edge = edgeWorkList.pop()
ProcessEdge(edge)
// 应用常量替换
for each inst in Function:
if valueState[inst] == CONSTANT:
ReplaceWithConstant(inst, valueState[inst].constant)
changed = true
return changed
function ProcessInstruction(Instruction inst):
switch inst.type:
//二元操作
case BINARY_OP:
lhs = GetValueState(inst.operands[0])
rhs = GetValueState(inst.operands[1])
if lhs == CONSTANT && rhs == CONSTANT:
newState = ComputeConstant(inst.op, lhs.value, rhs.value)
UpdateState(inst, newState)
else if lhs == BOTTOM || rhs == BOTTOM:
UpdateState(inst, BOTTOM)
//phi
case PHI:
mergedState =
for each incoming in inst.incomings:
// 检查每个输入的状态
if executableBlocks.contains(incoming.block):
incomingState = GetValueState(incoming.value)
mergedState = Meet(mergedState, incomingState)
UpdateState(inst, mergedState)
// 条件分支
case COND_BRANCH:
cond = GetValueState(inst.condition)
if cond == CONSTANT:
// 判断条件分支
if cond.value == true:
AddEdgeToWorkList(inst.parent, inst.trueTarget)
else:
AddEdgeToWorkList(inst.parent, inst.falseTarget)
else if cond == BOTTOM:
AddEdgeToWorkList(inst.parent, inst.trueTarget)
AddEdgeToWorkList(inst.parent, inst.falseTarget)
case UNCOND_BRANCH:
AddEdgeToWorkList(inst.parent, inst.target)
// 其他指令处理...
function ProcessEdge(Edge edge):
fromBB, toBB = edge
if !executableBlocks.contains(toBB):
executableBlocks.add(toBB)
for each inst in toBB:
if inst is PHI:
instWorkList.push(inst)
else:
instWorkList.push(inst) // 非PHI指令
// 更新PHI节点的输入
for each phi in toBB.phis:
instWorkList.push(phi)
function SimplifyControlFlow(Function):
changed = false
// 标记可达基本块
ReachableBBs = FindReachableBlocks(Function.entry)
// 删除不可达块
for each bb in Function.blocks:
if !ReachableBBs.contains(bb):
RemoveDeadBlock(bb)
changed = true
// 简化条件分支
for each bb in Function.blocks:
terminator = bb.terminator
if terminator is COND_BRANCH:
cond = GetValueState(terminator.condition)
if cond == CONSTANT:
SimplifyBranch(terminator, cond.value)
changed = true
return changed
function RemoveDeadBlock(BasicBlock bb):
// 1. 更新前驱块的分支指令
for each pred in bb.predecessors:
UpdateTerminator(pred, bb)
// 2. 更新后继块的PHI节点
for each succ in bb.successors:
RemovePhiIncoming(succ, bb)
// 3. 删除块内所有指令
for each inst in bb.instructions:
inst.remove()
// 4. 从函数中移除基本块
Function.removeBlock(bb)
function Meet(State a, State b):
if a == : return b
if b == : return a
if a == ⊥ || b == ⊥: return ⊥
if a.value == b.value: return a
return ⊥
function UpdateState(Value v, State newState):
oldState = valueState.get(v, )
if newState != oldState:
valueState[v] = newState
for each user in v.users:
if user is Instruction:
instWorkList.push(user)
*/
enum class LatticeValue {
Top, // (Unknown)
Constant, // c (Constant)
Bottom // ⊥ (Undefined / Varying)
};
// LatticeValue: 用于表示值的状态Top表示未知Constant表示常量Bottom表示未定义或变化的值。
// 这里的LatticeValue用于跟踪每个SSA值变量、指令结果的状态
// 以便在SCCP过程中进行常量传播和控制流简化。
//TODO: 下列数据结构考虑集成到类中,避免重命名问题
static std::set<Instruction *> Worklist;
static std::unordered_set<BasicBlock*> Executable_Blocks;
static std::queue<std::pair<BasicBlock *, BasicBlock *> > Executable_Edges;
static std::map<Value*, LatticeValue> valueState;
class SCCP {
private:
Module *pModule;
public:
SCCP(Module *pMoudle) : pModule(pMoudle) {}
void run();
bool PropagateConstants(Function *function);
bool SimplifyControlFlow(Function *function);
void ProcessInstruction(Instruction *inst);
void ProcessEdge(const std::pair<BasicBlock *, BasicBlock *> &edge);
void RemoveDeadBlock(BasicBlock *bb);
void UpdateState(Value *v, LatticeValue newState);
LatticeValue Meet(LatticeValue a, LatticeValue b);
LatticeValue GetValueState(Value *v);
};
} // namespace sysy

View File

@ -1,465 +0,0 @@
#pragma once
#include "IR.h"
namespace sysy {
// 前向声明
class Loop;
// 基本块分析信息类
class BlockAnalysisInfo {
public:
using block_list = std::vector<BasicBlock*>;
using block_set = std::unordered_set<BasicBlock*>;
protected:
// 支配树相关
int domdepth = 0; ///< 支配节点所在深度
BasicBlock* idom = nullptr; ///< 直接支配结点
block_list sdoms; ///< 支配树后继
block_set dominants; ///< 必经结点集合
block_set dominant_frontiers; ///< 支配边界
// 后续添加循环分析相关
// Loop* loopbelong = nullptr; ///< 所属循环
// int loopdepth = 0; ///< 循环深度
public:
// getterface
const int getDomDepth() const { return domdepth; }
const BasicBlock* getIdom() const { return idom; }
const block_list& getSdoms() const { return sdoms; }
const block_set& getDominants() const { return dominants; }
const block_set& getDomFrontiers() const { return dominant_frontiers; }
// 支配树操作
void setDomDepth(int depth) { domdepth = depth; }
void setIdom(BasicBlock* block) { idom = block; }
void addSdoms(BasicBlock* block) { sdoms.push_back(block); }
void clearSdoms() { sdoms.clear(); }
void removeSdoms(BasicBlock* block) {
sdoms.erase(std::remove(sdoms.begin(), sdoms.end(), block), sdoms.end());
}
void addDominants(BasicBlock* block) { dominants.emplace(block); }
void addDominants(const block_set& blocks) { dominants.insert(blocks.begin(), blocks.end()); }
void setDominants(BasicBlock* block) {
dominants.clear();
addDominants(block);
}
void setDominants(const block_set& doms) {
dominants = doms;
}
void setDomFrontiers(const block_set& df) {
dominant_frontiers = df;
}
// TODO循环分析操作方法
// 清空所有分析信息
void clear() {
domdepth = -1;
idom = nullptr;
sdoms.clear();
dominants.clear();
dominant_frontiers.clear();
// loopbelong = nullptr;
// loopdepth = 0;
}
};
// 函数分析信息类
class FunctionAnalysisInfo {
public:
// 函数属性
enum FunctionAttribute : uint64_t {
PlaceHolder = 0x0UL,
Pure = 0x1UL << 0,
SelfRecursive = 0x1UL << 1,
SideEffect = 0x1UL << 2,
NoPureCauseMemRead = 0x1UL << 3
};
// 数据结构
using Loop_list = std::list<std::unique_ptr<Loop>>;
using block_loop_map = std::unordered_map<BasicBlock*, Loop*>;
using value_block_map = std::unordered_map<Value*, BasicBlock*>;
using value_block_count_map = std::unordered_map<Value*, std::unordered_map<BasicBlock*, int>>;
// 分析数据
FunctionAttribute attribute = PlaceHolder; ///< 函数属性
std::set<Function*> callees; ///< 函数调用集合
Loop_list loops; ///< 所有循环
Loop_list topLoops; ///< 顶层循环
// block_loop_map basicblock2Loop; ///< 基本块到循环映射
std::list<std::unique_ptr<AllocaInst>> indirectAllocas; ///< 间接分配内存
// 值定义/使用信息
value_block_map value2AllocBlocks; ///< 值分配位置映射
value_block_count_map value2DefBlocks; ///< 值定义位置映射
value_block_count_map value2UseBlocks; ///< 值使用位置映射
// 函数属性操作
FunctionAttribute getAttribute() const { return attribute; }
void setAttribute(FunctionAttribute attr) { attribute = static_cast<FunctionAttribute>(attribute | attr); }
void clearAttribute() { attribute = PlaceHolder; }
// 调用关系操作
void addCallee(Function* callee) { callees.insert(callee); }
void removeCallee(Function* callee) { callees.erase(callee); }
void clearCallees() { callees.clear(); }
// 值-块映射操作
BasicBlock* getAllocBlockByValue(Value* value) {
auto it = value2AllocBlocks.find(value);
return it != value2AllocBlocks.end() ? it->second : nullptr;
}
std::unordered_set<BasicBlock *> getDefBlocksByValue(Value *value) {
std::unordered_set<BasicBlock *> blocks;
if (value2DefBlocks.count(value) > 0) {
for (const auto &pair : value2DefBlocks[value]) {
blocks.insert(pair.first);
}
}
return blocks;
}
std::unordered_set<BasicBlock *> getUseBlocksByValue(Value *value) {
std::unordered_set<BasicBlock *> blocks;
if (value2UseBlocks.count(value) > 0) {
for (const auto &pair : value2UseBlocks[value]) {
blocks.insert(pair.first);
}
}
return blocks;
}
// 值定义/使用操作
void addValue2AllocBlocks(Value* value, BasicBlock* block) { value2AllocBlocks[value] = block; }
void addValue2DefBlocks(Value* value, BasicBlock* block) { ++value2DefBlocks[value][block]; }
void addValue2UseBlocks(Value* value, BasicBlock* block) { ++value2UseBlocks[value][block]; }
// 获取值定义/使用信息
std::unordered_map<Value *, BasicBlock *>& getValue2AllocBlocks() {
return value2AllocBlocks;
}
std::unordered_map<Value *, std::unordered_map<BasicBlock *, int>>& getValue2DefBlocks() {
return value2DefBlocks;
}
std::unordered_map<Value *, std::unordered_map<BasicBlock *, int>>& getValue2UseBlocks() {
return value2UseBlocks;
}
std::unordered_set<Value *> getValuesOfDefBlock() {
std::unordered_set<Value *> values;
for (const auto &pair : value2DefBlocks) {
values.insert(pair.first);
}
return values;
}
// 删除信息操作
void removeValue2AllocBlock(Value *value) { value2AllocBlocks.erase(value); }
bool removeValue2DefBlock(Value *value, BasicBlock *block) {
bool changed = false;
if (--value2DefBlocks[value][block] == 0) {
value2DefBlocks[value].erase(block);
if (value2DefBlocks[value].empty()) {
value2DefBlocks.erase(value);
changed = true;
}
}
return changed;
}
bool removeValue2UseBlock(Value *value, BasicBlock *block) {
bool changed = false;
if (--value2UseBlocks[value][block] == 0) {
value2UseBlocks[value].erase(block);
if (value2UseBlocks[value].empty()) {
value2UseBlocks.erase(value);
changed = true;
}
}
return changed;
}
// 间接分配操作
void addIndirectAlloca(AllocaInst* alloca) { indirectAllocas.emplace_back(alloca); }
std::list<std::unique_ptr<AllocaInst>>& getIndirectAllocas() { return indirectAllocas; }
// TODO循环分析操作
// 清空所有分析信息
void clear() {
attribute = PlaceHolder;
callees.clear();
loops.clear();
topLoops.clear();
// basicblock2Loop.clear();
indirectAllocas.clear();
value2AllocBlocks.clear();
value2DefBlocks.clear();
value2UseBlocks.clear();
}
};
// 循环类 - 未实现优化
class Loop {
public:
using block_list = std::vector<BasicBlock *>;
using block_set = std::unordered_set<BasicBlock *>;
using Loop_list = std::vector<Loop *>;
protected:
Function *parent; // 所属函数
block_list blocksInLoop; // 循环内的基本块
BasicBlock *preheaderBlock = nullptr; // 前驱块
BasicBlock *headerBlock = nullptr; // 循环头
block_list latchBlock; // 回边块
block_set exitingBlocks; // 退出块
block_set exitBlocks; // 退出目标块
Loop *parentloop = nullptr; // 父循环
Loop_list subLoops; // 子循环
size_t loopID; // 循环ID
unsigned loopDepth; // 循环深度
Instruction *indCondVar = nullptr; // 循环条件变量
Instruction::Kind IcmpKind; // 比较类型
Value *indEnd = nullptr; // 循环结束值
AllocaInst *IndPhi = nullptr; // 循环变量
ConstantValue *indBegin = nullptr; // 循环起始值
ConstantValue *indStep = nullptr; // 循环步长
std::set<GlobalValue *> GlobalValuechange; // 循环内改变的全局变量
int StepType = 0; // 循环步长类型
bool parallelable = false; // 是否可并行
public:
explicit Loop(BasicBlock *header, const std::string &name = "")
: headerBlock(header) {
blocksInLoop.push_back(header);
}
void setloopID() {
static unsigned loopCount = 0;
loopCount = loopCount + 1;
loopID = loopCount;
}
ConstantValue* getindBegin() { return indBegin; }
ConstantValue* getindStep() { return indStep; }
void setindBegin(ConstantValue *indBegin2set) { indBegin = indBegin2set; }
void setindStep(ConstantValue *indStep2set) { indStep = indStep2set; }
void setStepType(int StepType2Set) { StepType = StepType2Set; }
int getStepType() { return StepType; }
size_t getLoopID() { return loopID; }
BasicBlock* getHeader() const { return headerBlock; }
BasicBlock* getPreheaderBlock() const { return preheaderBlock; }
block_list& getLatchBlocks() { return latchBlock; }
block_set& getExitingBlocks() { return exitingBlocks; }
block_set& getExitBlocks() { return exitBlocks; }
Loop* getParentLoop() const { return parentloop; }
void setParentLoop(Loop *parent) { parentloop = parent; }
void addBasicBlock(BasicBlock *bb) { blocksInLoop.push_back(bb); }
void addSubLoop(Loop *loop) { subLoops.push_back(loop); }
void setLoopDepth(unsigned depth) { loopDepth = depth; }
block_list& getBasicBlocks() { return blocksInLoop; }
Loop_list& getSubLoops() { return subLoops; }
unsigned getLoopDepth() const { return loopDepth; }
bool isLoopContainsBasicBlock(BasicBlock *bb) const {
return std::find(blocksInLoop.begin(), blocksInLoop.end(), bb) != blocksInLoop.end();
}
void addExitingBlock(BasicBlock *bb) { exitingBlocks.insert(bb); }
void addExitBlock(BasicBlock *bb) { exitBlocks.insert(bb); }
void addLatchBlock(BasicBlock *bb) { latchBlock.push_back(bb); }
void setPreheaderBlock(BasicBlock *bb) { preheaderBlock = bb; }
void setIndexCondInstr(Instruction *instr) { indCondVar = instr; }
void setIcmpKind(Instruction::Kind kind) { IcmpKind = kind; }
Instruction::Kind getIcmpKind() const { return IcmpKind; }
bool isSimpleLoopInvariant(Value *value) ;
void setIndEnd(Value *value) { indEnd = value; }
void setIndPhi(AllocaInst *phi) { IndPhi = phi; }
Value* getIndEnd() const { return indEnd; }
AllocaInst* getIndPhi() const { return IndPhi; }
Instruction* getIndCondVar() const { return indCondVar; }
void addGlobalValuechange(GlobalValue *globalvaluechange2add) {
GlobalValuechange.insert(globalvaluechange2add);
}
std::set<GlobalValue *>& getGlobalValuechange() {
return GlobalValuechange;
}
void setParallelable(bool flag) { parallelable = flag; }
bool isParallelable() const { return parallelable; }
};
// 控制流分析类
class ControlFlowAnalysis {
private:
Module *pModule; ///< 模块
std::unordered_map<BasicBlock*, BlockAnalysisInfo*> blockAnalysisInfo; // 基本块分析信息表
std::unordered_map<Function*, FunctionAnalysisInfo*> functionAnalysisInfo; // 函数分析信息
public:
explicit ControlFlowAnalysis(Module *pMoudle) : pModule(pMoudle) {}
// 获取基本块分析信息
BlockAnalysisInfo* getBlockAnalysisInfo(BasicBlock *block) {
auto it = blockAnalysisInfo.find(block);
if (it != blockAnalysisInfo.end()) {
return it->second;
}
return nullptr; // 如果未找到返回nullptr
}
FunctionAnalysisInfo* getFunctionAnalysisInfo(Function *func) {
auto it = functionAnalysisInfo.find(func);
if (it != functionAnalysisInfo.end()) {
return it->second;
}
return nullptr; // 如果未找到返回nullptr
}
void init(); // 初始化分析器
void computeDomNode(); // 计算必经结点
void computeDomTree(); // 构造支配树
// std::unordered_set<BasicBlock *> computeDomFrontier(BasicBlock *block) ; // 计算单个块的支配边界(弃用)
void computeDomFrontierAllBlk(); // 计算所有块的支配边界
void runControlFlowAnalysis(); // 运行控制流分析(主要是支配树和支配边界)
void clear(){
for (auto &pair : blockAnalysisInfo) {
delete pair.second; // 清理基本块分析信息
}
blockAnalysisInfo.clear();
for (auto &pair : functionAnalysisInfo) {
delete pair.second; // 清理函数分析信息
}
functionAnalysisInfo.clear();
} // 清空分析结果
~ControlFlowAnalysis() {
clear(); // 析构时清理所有分析信息
}
private:
void intersectOP4Dom(std::unordered_set<BasicBlock *> &dom, const std::unordered_set<BasicBlock *> &other); // 交集运算,
BasicBlock* findCommonDominator(BasicBlock *a, BasicBlock *b); // 查找两个基本块的共同支配结点
};
// 数据流分析类
// 该类为抽象类,具体的数据流分析器需要继承此类
// 因为每个数据流分析器的分析动作都不一样所以需要继承并实现analyze方法
class DataFlowAnalysis {
public:
virtual ~DataFlowAnalysis() = default;
public:
virtual void init(Module *pModule) {} ///< 分析器初始化
virtual auto analyze(Module *pModule, BasicBlock *block) -> bool { return true; } ///< 分析动作若完成则返回true;
virtual void clear() {} ///< 清空
};
// 数据流分析工具类
// 该类用于管理多个数据流分析器,提供统一的前向与后向分析接口
class DataFlowAnalysisUtils {
private:
std::vector<DataFlowAnalysis *> forwardAnalysisList; ///< 前向分析器列表
std::vector<DataFlowAnalysis *> backwardAnalysisList; ///< 后向分析器列表
public:
DataFlowAnalysisUtils() = default;
~DataFlowAnalysisUtils() {
clear(); // 析构时清理所有分析器
}
// 统一添加接口
void addAnalyzers(
std::vector<DataFlowAnalysis *> forwardList,
std::vector<DataFlowAnalysis *> backwardList = {})
{
forwardAnalysisList.insert(
forwardAnalysisList.end(),
forwardList.begin(),
forwardList.end());
backwardAnalysisList.insert(
backwardAnalysisList.end(),
backwardList.begin(),
backwardList.end());
}
// 单独添加接口
void addForwardAnalyzer(DataFlowAnalysis *analyzer) {
forwardAnalysisList.push_back(analyzer);
}
void addBackwardAnalyzer(DataFlowAnalysis *analyzer) {
backwardAnalysisList.push_back(analyzer);
}
// 设置分析器列表
void setAnalyzers(
std::vector<DataFlowAnalysis *> forwardList,
std::vector<DataFlowAnalysis *> backwardList)
{
forwardAnalysisList = std::move(forwardList);
backwardAnalysisList = std::move(backwardList);
}
// 清空列表
void clear() {
forwardAnalysisList.clear();
backwardAnalysisList.clear();
}
// 访问器
const auto& getForwardAnalyzers() const { return forwardAnalysisList; }
const auto& getBackwardAnalyzers() const { return backwardAnalysisList; }
public:
void forwardAnalyze(Module *pModule); ///< 执行前向分析
void backwardAnalyze(Module *pModule); ///< 执行后向分析
};
// 活跃变量分析类
// 提供def - use分析
// 未兼容数组变量但是考虑了维度的use信息
class ActiveVarAnalysis : public DataFlowAnalysis {
private:
std::map<BasicBlock *, std::vector<std::set<User *>>> activeTable; ///< 活跃信息表,存储每个基本块内的的活跃变量信息
public:
ActiveVarAnalysis() = default;
~ActiveVarAnalysis() override = default;
public:
static std::set<User*> getUsedSet(Instruction *inst);
static User* getDefine(Instruction *inst);
public:
void init(Module *pModule) override;
bool analyze(Module *pModule, BasicBlock *block) override;
// 外部活跃信息表访问器
const std::map<BasicBlock *, std::vector<std::set<User *>>> &getActiveTable() const;
void clear() override {
activeTable.clear(); // 清空活跃信息表
}
};
// 分析管理器 后续实现
// class AnalysisManager {
// };
} // namespace sysy

View File

@ -1,33 +0,0 @@
#pragma once
#include "IR.h"
namespace sysy {
// 优化工具类,包含一些通用的优化方法
// 这些方法可以在不同的优化 pass 中复用
// 例如删除use关系,判断是否是全局变量等
class SysYIROptUtils{
public:
// 仅仅删除use关系
static void usedelete(Instruction *instr) {
for (auto &use : instr->getOperands()) {
Value* val = use->getValue();
val->removeUse(use);
}
}
// 判断是否是全局变量
static bool isGlobal(Value *val) {
auto gval = dynamic_cast<GlobalValue *>(val);
return gval != nullptr;
}
// 判断是否是数组
static bool isArr(Value *val) {
auto aval = dynamic_cast<AllocaInst *>(val);
return aval != nullptr && aval->getNumDims() != 0;
}
};
}// namespace sysy

View File

@ -1,58 +0,0 @@
// PassManager.h
#pragma once
#include <vector>
#include <memory>
#include <typeindex> // For std::type_index
#include <unordered_map>
#include "SysYIRPass.h"
#include "IR.h" // 假设你的IR.h定义了Module, Function等
namespace sysy {
class PassManager {
public:
PassManager() = default;
// 添加一个FunctionPass
void addPass(std::unique_ptr<FunctionPass> pass) {
functionPasses.push_back(std::move(pass));
}
// 添加一个ModulePass
void addPass(std::unique_ptr<ModulePass> pass) {
modulePasses.push_back(std::move(pass));
}
// 添加一个AnalysisPass
template<typename T, typename... Args>
T* addAnalysisPass(Args&&... args) {
static_assert(std::is_base_of<AnalysisPass, T>::value, "T must derive from AnalysisPass");
auto analysis = std::make_unique<T>(std::forward<Args>(args)...);
T* rawPtr = analysis.get();
analysisPasses[std::type_index(typeid(T))] = std::move(analysis);
return rawPtr;
}
// 获取分析结果用于其他Pass访问
template<typename T>
T* getAnalysis() {
static_assert(std::is_base_of<AnalysisPass, T>::value, "T must derive from AnalysisPass");
auto it = analysisPasses.find(std::type_index(typeid(T)));
if (it != analysisPasses.end()) {
return static_cast<T*>(it->second.get());
}
return nullptr; // 或者抛出异常
}
// 运行所有注册的遍
void run(Module& M);
private:
std::vector<std::unique_ptr<FunctionPass>> functionPasses;
std::vector<std::unique_ptr<ModulePass>> modulePasses;
std::unordered_map<std::type_index, std::unique_ptr<AnalysisPass>> analysisPasses;
// 未来可以添加AnalysisPass的缓存机制
};
} // namespace sysy

View File

@ -0,0 +1,33 @@
#ifndef CALLEE_SAVED_HANDLER_H
#define CALLEE_SAVED_HANDLER_H
#include "RISCv64LLIR.h"
#include "Pass.h"
namespace sysy {
/**
* @class CalleeSavedHandler
* @brief 处理被调用者保存寄存器(Callee-Saved Registers)的Pass。
* * 这个Pass在寄存器分配之后运行。它的主要职责是
* 1. 扫描整个函数,找出所有被使用的 `s` 系列寄存器。
* 2. 在函数序言中插入 `sd` 指令来保存这些寄存器。
* 3. 在函数结尾ret指令前插入 `ld` 指令来恢复这些寄存器。
* 4. 正确计算因保存这些寄存器而需要的额外栈空间并更新StackFrameInfo。
*/
class CalleeSavedHandler : public Pass {
public:
static char ID;
CalleeSavedHandler() : Pass("callee-saved-handler", Granularity::Function, PassKind::Optimization) {}
void *getPassID() const override { return &ID; }
bool runOnFunction(Function *F, AnalysisManager& AM) override;
void runOnMachineFunction(MachineFunction* mfunc);
};
} // namespace sysy
#endif // CALLEE_SAVED_HANDLER_H

View File

@ -0,0 +1,36 @@
#ifndef SYSY_LEGALIZE_IMMEDIATES_H
#define SYSY_LEGALIZE_IMMEDIATES_H
#include "RISCv64LLIR.h"
#include "Pass.h"
namespace sysy {
// MachineFunction 的前向声明在这里是可选的,因为 RISCv64LLIR.h 已经定义了它
// class MachineFunction;
/**
* @class LegalizeImmediatesPass
* @brief 一个用于“合法化”机器指令的Pass。
*
* 这个Pass的主要职责是遍历所有机器指令查找那些包含了超出
* 目标架构RISC-V编码范围的大立即数immediate的指令
* 并将它们展开成一个等价的、只包含合法立即数的指令序列。
*
* 它在指令选择之后、寄存器分配之前运行,确保进入后续阶段的
* 所有指令都符合硬件约束。
*/
class LegalizeImmediatesPass : public Pass {
public:
static char ID;
LegalizeImmediatesPass() : Pass("legalize-immediates", Granularity::Function, PassKind::Optimization) {}
void *getPassID() const override { return &ID; }
void runOnMachineFunction(MachineFunction* mfunc);
};
} // namespace sysy
#endif // SYSY_LEGALIZE_IMMEDIATES_H

View File

@ -0,0 +1,35 @@
#ifndef SYSY_PROLOGUE_EPILOGUE_INSERTION_H
#define SYSY_PROLOGUE_EPILOGUE_INSERTION_H
#include "RISCv64LLIR.h"
#include "Pass.h"
namespace sysy {
class MachineFunction;
/**
* @class PrologueEpilogueInsertionPass
* @brief 在函数中插入序言和尾声的机器指令。
*
* 这个Pass在所有栈帧大小计算完毕后包括局部变量、溢出槽、被调用者保存寄存器
* 在寄存器分配之后运行。它的职责是:
* 1. 根据 StackFrameInfo 中的最终栈大小,生成用于分配和释放栈帧的指令 (addi sp, sp, +/-size)。
* 2. 生成用于保存和恢复返回地址(ra)和旧帧指针(s0)的指令。
* 3. 将这些指令作为 MachineInstr 对象插入到 MachineFunction 的入口块和所有返回块中。
* 4. 这个Pass可能会生成带有大立即数的指令需要后续的 LegalizeImmediatesPass 来处理。
*/
class PrologueEpilogueInsertionPass : public Pass {
public:
static char ID;
PrologueEpilogueInsertionPass() : Pass("prologue-epilogue-insertion", Granularity::Function, PassKind::Optimization) {}
void *getPassID() const override { return &ID; }
void runOnMachineFunction(MachineFunction* mfunc);
};
} // namespace sysy
#endif // SYSY_PROLOGUE_EPILOGUE_INSERTION_H

View File

@ -0,0 +1,30 @@
#ifndef RISCV64_PEEPHOLE_H
#define RISCV64_PEEPHOLE_H
#include "RISCv64LLIR.h"
#include "Pass.h"
namespace sysy {
/**
* @class PeepholeOptimizer
* @brief 窥孔优化器
* * 在已分配物理寄存器的指令流上,通过一个小的滑动窗口来查找
* 并替换掉一些冗余或低效的指令模式。
*/
class PeepholeOptimizer : public Pass {
public:
static char ID;
PeepholeOptimizer() : Pass("peephole-optimizer", Granularity::Function, PassKind::Optimization) {}
void *getPassID() const override { return &ID; }
bool runOnFunction(Function *F, AnalysisManager& AM) override;
void runOnMachineFunction(MachineFunction* mfunc);
};
} // namespace sysy
#endif // RISCV64_PEEPHOLE_H

View File

@ -0,0 +1,30 @@
#ifndef POST_RA_SCHEDULER_H
#define POST_RA_SCHEDULER_H
#include "RISCv64LLIR.h"
#include "Pass.h"
namespace sysy {
/**
* @class PostRA_Scheduler
* @brief 寄存器分配后的局部指令调度器
* * 主要目标是优化寄存器分配器插入的spill/fill代码(lw/sw)
* 尝试将加载指令提前,以隐藏其访存延迟。
*/
class PostRA_Scheduler : public Pass {
public:
static char ID;
PostRA_Scheduler() : Pass("post-ra-scheduler", Granularity::Function, PassKind::Optimization) {}
void *getPassID() const override { return &ID; }
bool runOnFunction(Function *F, AnalysisManager& AM) override;
void runOnMachineFunction(MachineFunction* mfunc);
};
} // namespace sysy
#endif // POST_RA_SCHEDULER_H

View File

@ -0,0 +1,30 @@
#ifndef PRE_RA_SCHEDULER_H
#define PRE_RA_SCHEDULER_H
#include "RISCv64LLIR.h"
#include "Pass.h"
namespace sysy {
/**
* @class PreRA_Scheduler
* @brief 寄存器分配前的指令调度器
* * 在虚拟寄存器上进行操作,此时调度自由度最大,
* 主要目标是隐藏指令延迟,提高流水线效率。
*/
class PreRA_Scheduler : public Pass {
public:
static char ID;
PreRA_Scheduler() : Pass("pre-ra-scheduler", Granularity::Function, PassKind::Optimization) {}
void *getPassID() const override { return &ID; }
bool runOnFunction(Function *F, AnalysisManager& AM) override;
void runOnMachineFunction(MachineFunction* mfunc);
};
} // namespace sysy
#endif // PRE_RA_SCHEDULER_H

View File

@ -12,22 +12,23 @@ namespace sysy {
class RISCv64AsmPrinter {
public:
RISCv64AsmPrinter(MachineFunction* mfunc);
// 主入口
void run(std::ostream& os, bool debug = false);
void printInstruction(MachineInstr* instr, bool debug = false);
// 辅助函数
void setStream(std::ostream& os) { OS = &os; }
private:
// 打印各个部分
void printPrologue();
void printEpilogue();
void printBasicBlock(MachineBasicBlock* mbb, bool debug = false);
void printInstruction(MachineInstr* instr, bool debug = false);
// 辅助函数
std::string regToString(PhysicalReg reg);
void printOperand(MachineOperand* op);
MachineFunction* MFunc;
std::ostream* OS;
std::ostream* OS = nullptr;
};
} // namespace sysy

View File

@ -39,8 +39,8 @@ enum class PhysicalReg {
// 用于内部表示物理寄存器在干扰图中的节点ID一个简单的特殊ID确保不与vreg_counter冲突
// 假设 vreg_counter 不会达到这么大的值
PHYS_REG_START_ID = 10000,
PHYS_REG_END_ID = PHYS_REG_START_ID + 32, // 预留足够的空间
PHYS_REG_START_ID = 100000,
PHYS_REG_END_ID = PHYS_REG_START_ID + 320, // 预留足够的空间
};
// RISC-V 指令操作码枚举

View File

@ -0,0 +1,17 @@
#ifndef RISCV64_PASSES_H
#define RISCV64_PASSES_H
#include "RISCv64LLIR.h"
#include "Peephole.h"
#include "PreRA_Scheduler.h"
#include "PostRA_Scheduler.h"
#include "CalleeSavedHandler.h"
#include "LegalizeImmediates.h"
#include "PrologueEpilogueInsertion.h"
#include "Pass.h"
namespace sysy {
} // namespace sysy
#endif // RISCV64_PASSES_H

View File

@ -4,6 +4,9 @@
#include "RISCv64LLIR.h"
#include "RISCv64ISel.h" // 包含 RISCv64ISel.h 以访问 ISel 和 Value 类型
extern int DEBUG;
extern int DEEPDEBUG;
namespace sysy {
class RISCv64RegAlloc {
@ -61,6 +64,9 @@ private:
// 用于计算类型大小的辅助函数
unsigned getTypeSizeInBytes(Type* type);
// 辅助函数,用于打印集合
static void printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os);
};

View File

@ -359,12 +359,25 @@ public:
// Helper methods to access constant values with appropriate casting
int getInt() const {
assert(getType()->isInt() && "Calling getInt() on non-integer type");
return std::get<int>(getVal());
auto val = getVal();
if (std::holds_alternative<int>(val)) {
return std::get<int>(val);
} else if (std::holds_alternative<float>(val)) {
return static_cast<int>(std::get<float>(val));
}
// Handle other possible types if needed
return 0; // Default fallback
}
float getFloat() const {
assert(getType()->isFloat() && "Calling getFloat() on non-float type");
return std::get<float>(getVal());
auto val = getVal();
if (std::holds_alternative<float>(val)) {
return std::get<float>(val);
} else if (std::holds_alternative<int>(val)) {
return static_cast<float>(std::get<int>(val));
}
// Handle other possible types if needed
return 0.0f; // Default fallback
}
template<typename T>
@ -501,12 +514,15 @@ public:
explicit BasicBlock(Function *parent, const std::string &name = "")
: Value(Type::getLabelType(), name), parent(parent) {}
~BasicBlock() override {
for (auto pre : predecessors) {
pre->removeSuccessor(this);
}
for (auto suc : successors) {
suc->removePredecessor(this);
}
// for (auto pre : predecessors) {
// pre->removeSuccessor(this);
// }
// for (auto suc : successors) {
// suc->removePredecessor(this);
// }
// 这些关系应该在 BasicBlock 被从 Function 中移除时,
// 由负责 CFG 优化的 Pass (例如 SCCP 的 RemoveDeadBlock) 显式地清理。
// 析构函数只负责清理 BasicBlock 自身拥有的资源(例如,指令列表)。
}
public:
@ -525,6 +541,10 @@ public:
iterator begin() { return instructions.begin(); }
iterator end() { return instructions.end(); }
iterator terminator() { return std::prev(end()); }
iterator findInstIterator(Instruction *inst) {
return std::find_if(instructions.begin(), instructions.end(),
[inst](const std::unique_ptr<Instruction> &i) { return i.get() == inst; });
} ///< 查找指定指令的迭代器
bool hasSuccessor(BasicBlock *block) const {
return std::find(successors.begin(), successors.end(), block) != successors.end();
} ///< 判断是否有后继块
@ -582,7 +602,7 @@ public:
prev->addSuccessor(next);
next->addPredecessor(prev);
}
void removeInst(iterator pos) { instructions.erase(pos); }
iterator removeInst(iterator pos) { return instructions.erase(pos); }
void removeInst(Instruction *inst) {
auto pos = std::find_if(instructions.begin(), instructions.end(),
[inst](const std::unique_ptr<Instruction> &i) { return i.get() == inst; });
@ -609,6 +629,21 @@ class User : public Value {
explicit User(Type *type, const std::string &name = "") : Value(type, name) {}
public:
// ~User() override {
// // 当 User 对象被销毁时例如LoadInst 或 StoreInst 被删除时),
// // 它必须通知它所使用的所有 Value将对应的 Use 关系从它们的 uses 列表中移除。
// // 这样可以防止 Value 的 uses 列表中出现悬空的 Use 对象。
// for (const auto &use_ptr : operands) {
// // 确保 use_ptr 非空,并且其内部指向的 Value* 也非空
// // (虽然通常情况下不会为空,但为了健壮性考虑)
// if (use_ptr && use_ptr->getValue()) {
// use_ptr->getValue()->removeUse(use_ptr);
// }
// }
// // operands 向量本身是 std::vector<std::shared_ptr<Use>>
// // 在此析构函数结束后operands 向量会被销毁,其内部的 shared_ptr 也会被释放,
// // 如果 shared_ptr 引用计数降为0Use 对象本身也会被销毁。
// }
unsigned getNumOperands() const { return operands.size(); } ///< 获取操作数数量
auto operand_begin() const { return operands.begin(); } ///< 返回操作数列表的开头迭代器
auto operand_end() const { return operands.end(); } ///< 返回操作数列表的结尾迭代器
@ -678,15 +713,13 @@ class Instruction : public User {
kCondBr = 0x1UL << 30,
kBr = 0x1UL << 31,
kReturn = 0x1UL << 32,
kUnreachable = 0x1UL << 33,
// mem op
kAlloca = 0x1UL << 33,
kLoad = 0x1UL << 34,
kStore = 0x1UL << 35,
kGetElementPtr = 0x1UL << 36,
kMemset = 0x1UL << 37,
// kGetSubArray = 0x1UL << 38,
// Constant Kind removed as Constants are now Values, not Instructions.
// kConstant = 0x1UL << 37, // Conflicts with kMemset if kept as is
kAlloca = 0x1UL << 34,
kLoad = 0x1UL << 35,
kStore = 0x1UL << 36,
kGetElementPtr = 0x1UL << 37,
kMemset = 0x1UL << 38,
// phi
kPhi = 0x1UL << 39,
kBitItoF = 0x1UL << 40,
@ -815,7 +848,7 @@ public:
return kind & MemoryOpMask;
}
bool isTerminator() const {
static constexpr uint64_t TerminatorOpMask = kCondBr | kBr | kReturn;
static constexpr uint64_t TerminatorOpMask = kCondBr | kBr | kReturn | kUnreachable;
return kind & TerminatorOpMask;
}
bool isCmp() const {
@ -835,6 +868,7 @@ public:
}
bool isUnconditional() const { return kind == kBr; }
bool isConditional() const { return kind == kCondBr; }
bool isCondBr() const { return kind == kCondBr; }
bool isPhi() const { return kind == kPhi; }
bool isAlloca() const { return kind == kAlloca; }
bool isLoad() const { return kind == kLoad; }
@ -843,6 +877,7 @@ public:
bool isMemset() const { return kind == kMemset; }
bool isCall() const { return kind == kCall; }
bool isReturn() const { return kind == kReturn; }
bool isUnreachable() const { return kind == kUnreachable; }
bool isDefine() const {
static constexpr uint64_t DefineOpMask = kAlloca | kStore | kPhi;
return (kind & DefineOpMask) != 0U;
@ -877,6 +912,9 @@ class PhiInst : public Instruction {
public:
Value* getValue(unsigned k) const {return getOperand(2 * k);} ///< 获取位置为k的值
BasicBlock* getBlock(unsigned k) const {return dynamic_cast<BasicBlock*>(getOperand(2 * k + 1));}
//增加llvm同名方法实现获取value和block
Value* getIncomingValue(unsigned k) const {return getOperand(2 * k);} ///< 获取位置为k的值
BasicBlock* getIncomingBlock(unsigned k) const {return dynamic_cast<BasicBlock*>(getOperand(2 * k + 1));}
auto& getincomings() const {return blk2val;} ///< 获取所有的基本块和对应的值
@ -1042,12 +1080,10 @@ class UncondBrInst : public Instruction {
friend class Function;
protected:
UncondBrInst(BasicBlock *block, std::vector<Value *> args,
UncondBrInst(BasicBlock *block,
BasicBlock *parent = nullptr)
: Instruction(kBr, Type::getVoidType(), parent, "") {
// assert(block->getNumArguments() == args.size());
addOperand(block);
addOperands(args);
}
public:
@ -1055,6 +1091,16 @@ public:
auto getArguments() const {
return make_range(std::next(operand_begin()), operand_end());
}
std::vector<BasicBlock *> getSuccessors() const {
std::vector<BasicBlock *> succs;
// 假设无条件分支的目标块是它的第一个操作数
if (getNumOperands() > 0) {
if (auto target_bb = dynamic_cast<BasicBlock *>(getOperand(0))) {
succs.push_back(target_bb);
}
}
return succs;
}
}; // class UncondBrInst
@ -1066,17 +1112,12 @@ class CondBrInst : public Instruction {
friend class Function;
protected:
CondBrInst(Value *condition, BasicBlock *thenBlock, BasicBlock *elseBlock,
const std::vector<Value *> &thenArgs,
const std::vector<Value *> &elseArgs, BasicBlock *parent = nullptr)
CondBrInst(Value *condition, BasicBlock *thenBlock, BasicBlock *elseBlock,
BasicBlock *parent = nullptr)
: Instruction(kCondBr, Type::getVoidType(), parent, "") {
// assert(thenBlock->getNumArguments() == thenArgs.size() and
// elseBlock->getNumArguments() == elseArgs.size());
addOperand(condition);
addOperand(thenBlock);
addOperand(elseBlock);
addOperands(thenArgs);
addOperands(elseArgs);
}
public:
Value* getCondition() const { return getOperand(0); }
@ -1086,36 +1127,46 @@ public:
BasicBlock* getElseBlock() const {
return dynamic_cast<BasicBlock *>(getOperand(2));
}
// auto getThenArguments() const {
// auto begin = std::next(operand_begin(), 3);
// // auto end = std::next(begin, getThenBlock()->getNumArguments());
// return make_range(begin, end);
// }
// auto getElseArguments() const {
// auto begin =
// std::next(operand_begin(), 3 + getThenBlock()->getNumArguments());
// auto end = operand_end();
// return make_range(begin, end);
// }
std::vector<BasicBlock *> getSuccessors() const {
std::vector<BasicBlock *> succs;
// 假设条件分支的真实块是第二个操作数,假块是第三个操作数
// 操作数通常是:[0] 条件值, [1] TrueTargetBlock, [2] FalseTargetBlock
if (getNumOperands() > 2) {
if (auto true_bb = getThenBlock()) {
succs.push_back(true_bb);
}
if (auto false_bb = getElseBlock()) {
succs.push_back(false_bb);
}
}
return succs;
}
}; // class CondBrInst
class UnreachableInst : public Instruction {
public:
// 构造函数:设置指令类型为 kUnreachable
explicit UnreachableInst(const std::string& name, BasicBlock *parent = nullptr)
: Instruction(kUnreachable, Type::getVoidType(), parent, "") {}
};
//! Allocate memory for stack variables, used for non-global variable declartion
class AllocaInst : public Instruction {
friend class IRBuilder;
friend class Function;
protected:
AllocaInst(Type *type, const std::vector<Value *> &dims = {},
AllocaInst(Type *type,
BasicBlock *parent = nullptr, const std::string &name = "")
: Instruction(kAlloca, type, parent, name) {
addOperands(dims);
}
public:
int getNumDims() const { return getNumOperands(); }
auto getDims() const { return getOperands(); }
Value* getDim(int index) { return getOperand(index); }
//! 获取分配的类型
Type* getAllocatedType() const {
return getType()->as<PointerType>()->getBaseType();
} ///< 获取分配的类型
}; // class AllocaInst
@ -1162,21 +1213,15 @@ class LoadInst : public Instruction {
friend class Function;
protected:
LoadInst(Value *pointer, const std::vector<Value *> &indices = {},
LoadInst(Value *pointer,
BasicBlock *parent = nullptr, const std::string &name = "")
: Instruction(kLoad, pointer->getType()->as<PointerType>()->getBaseType(),
parent, name) {
addOperand(pointer);
addOperands(indices);
}
public:
int getNumIndices() const { return getNumOperands() - 1; }
Value* getPointer() const { return getOperand(0); }
auto getIndices() const {
return make_range(std::next(operand_begin()), operand_end());
}
Value* getIndex(int index) const { return getOperand(index + 1); }
}; // class LoadInst
@ -1187,22 +1232,15 @@ class StoreInst : public Instruction {
protected:
StoreInst(Value *value, Value *pointer,
const std::vector<Value *> &indices = {},
BasicBlock *parent = nullptr, const std::string &name = "")
: Instruction(kStore, Type::getVoidType(), parent, name) {
addOperand(value);
addOperand(pointer);
addOperands(indices);
}
public:
int getNumIndices() const { return getNumOperands() - 2; }
Value* getValue() const { return getOperand(0); }
Value* getPointer() const { return getOperand(1); }
auto getIndices() const {
return make_range(std::next(operand_begin(), 2), operand_end());
}
Value* getIndex(int index) const { return getOperand(index + 2); }
}; // class StoreInst
@ -1331,7 +1369,7 @@ protected:
};
//! Global value declared at file scope
class GlobalValue : public User {
class GlobalValue : public Value {
friend class Module;
protected:
@ -1341,19 +1379,18 @@ protected:
protected:
GlobalValue(Module *parent, Type *type, const std::string &name,
const std::vector<Value *> &dims = {},
ValueCounter init = {})
: User(type, name), parent(parent) {
: Value(type, name), parent(parent) {
assert(type->isPointer());
addOperands(dims);
numDims = dims.size();
// 维度信息已经被记录到Type中dim只是为了方便初始化
numDims = 0;
if (init.size() == 0) {
unsigned num = 1;
for (unsigned i = 0; i < numDims; i++) {
// Assume dims elements are ConstantInteger and cast appropriately
auto dim_val = dynamic_cast<ConstantInteger*>(dims[i]);
assert(dim_val && "GlobalValue dims must be constant integers");
num *= dim_val->getInt();
auto arrayType = type->as<ArrayType>();
while (arrayType) {
numDims++;
num *= arrayType->getNumElements();
arrayType = arrayType->getElementType()->as<ArrayType>();
}
if (dynamic_cast<PointerType *>(type)->getBaseType() == Type::getFloatType()) {
init.push_back(ConstantFloating::get(0.0F), num); // Use new constant factory
@ -1365,20 +1402,31 @@ protected:
}
public:
unsigned getNumDims() const { return numDims; } ///< 获取维度数量
Value* getDim(unsigned index) const { return getOperand(index); } ///< 获取位置为index的维度
auto getDims() const { return getOperands(); } ///< 获取维度列表
unsigned getNumIndices() const {
return numDims;
} ///< 获取维度数量
unsigned getIndex(unsigned index) const {
assert(index < getNumIndices() && "Index out of bounds for GlobalValue!");
Type *GlobalValueType = getType()->as<PointerType>()->getBaseType();
for (unsigned i = 0; i < index; i++) {
GlobalValueType = GlobalValueType->as<ArrayType>()->getElementType();
}
return GlobalValueType->as<ArrayType>()->getNumElements();
} ///< 获取维度大小(从第0个开始)
Value* getByIndex(unsigned index) const {
return initValues.getValue(index);
} ///< 通过一维偏移量index获取初始值
Value* getByIndices(const std::vector<Value *> &indices) const {
Value* getByIndices(const std::vector<Value *> &indices) const {
int index = 0;
Type *GlobalValueType = getType()->as<PointerType>()->getBaseType();
for (size_t i = 0; i < indices.size(); i++) {
// Ensure dims[i] and indices[i] are ConstantInteger and retrieve their values correctly
auto dim_val = dynamic_cast<ConstantInteger*>(getDim(i));
// GlobalValueType->as<ArrayType>()->getNumElements();
auto dim_val = GlobalValueType->as<ArrayType>()->getNumElements();
auto idx_val = dynamic_cast<ConstantInteger*>(indices[i]);
assert(dim_val && idx_val && "Dims and indices must be constant integers");
index = dim_val->getInt() * index + idx_val->getInt();
index = dim_val * index + idx_val->getInt();
GlobalValueType = GlobalValueType->as<ArrayType>()->getElementType();
}
return getByIndex(index);
} ///< 通过多维索引indices获取初始值
@ -1386,7 +1434,7 @@ public:
}; // class GlobalValue
class ConstantVariable : public User {
class ConstantVariable : public Value {
friend class Module;
protected:
@ -1395,33 +1443,50 @@ class ConstantVariable : public User {
ValueCounter initValues; ///< 值
protected:
ConstantVariable(Module *parent, Type *type, const std::string &name, const ValueCounter &init,
const std::vector<Value *> &dims = {})
: User(type, name), parent(parent) {
ConstantVariable(Module *parent, Type *type, const std::string &name, const ValueCounter &init)
: Value(type, name), parent(parent) {
assert(type->isPointer());
numDims = dims.size();
// numDims = dims.size();
numDims = 0;
if(type->as<PointerType>()->getBaseType()->isArray()) {
auto arrayType = type->as<ArrayType>();
while (arrayType) {
numDims++;
arrayType = arrayType->getElementType()->as<ArrayType>();
}
}
initValues = init;
addOperands(dims);
}
public:
unsigned getNumIndices() const {
return numDims;
} ///< 获取索引数量
unsigned getIndex(unsigned index) const {
assert(index < getNumIndices() && "Index out of bounds for ConstantVariable!");
Type *ConstantVariableType = getType()->as<PointerType>()->getBaseType();
for (unsigned i = 0; i < index; i++) {
ConstantVariableType = ConstantVariableType->as<ArrayType>()->getElementType();
}
return ConstantVariableType->as<ArrayType>()->getNumElements();
} ///< 获取索引个数(从第0个开始)
Value* getByIndex(unsigned index) const { return initValues.getValue(index); } ///< 通过一维位置index获取值
Value* getByIndices(const std::vector<Value *> &indices) const {
int index = 0;
// 计算偏移量
Type *ConstantVariableType = getType()->as<PointerType>()->getBaseType();
for (size_t i = 0; i < indices.size(); i++) {
// Ensure dims[i] and indices[i] are ConstantInteger and retrieve their values correctly
auto dim_val = dynamic_cast<ConstantInteger*>(getDim(i));
// ConstantVariableType->as<ArrayType>()->getNumElements();
auto dim_val = ConstantVariableType->as<ArrayType>()->getNumElements();
auto idx_val = dynamic_cast<ConstantInteger*>(indices[i]);
assert(dim_val && idx_val && "Dims and indices must be constant integers");
index = dim_val->getInt() * index + idx_val->getInt();
index = dim_val * index + idx_val->getInt();
ConstantVariableType = ConstantVariableType->as<ArrayType>()->getElementType();
}
return getByIndex(index);
} ///< 通过多维索引indices获取初始值
unsigned getNumDims() const { return numDims; } ///< 获取维度数量
Value* getDim(unsigned index) const { return getOperand(index); } ///< 获取位置为index的维度
auto getDims() const { return getOperands(); } ///< 获取维度列表
const ValueCounter& getInitValues() const { return initValues; } ///< 获取初始值
};
@ -1437,7 +1502,7 @@ class SymbolTable {
SymbolTableNode *curNode{}; ///< 当前所在的作用域(符号表节点)
std::map<std::string, unsigned> variableIndex; ///< 变量命名索引表
std::vector<std::unique_ptr<GlobalValue>> globals; ///< 全局变量列表
std::vector<std::unique_ptr<ConstantVariable>> consts; ///< 常量列表
std::vector<std::unique_ptr<ConstantVariable>> globalconsts; ///< 全局常量列表
std::vector<std::unique_ptr<SymbolTableNode>> nodeList; ///< 符号表节点列表
public:
@ -1446,7 +1511,7 @@ class SymbolTable {
Value* getVariable(const std::string &name) const; ///< 根据名字name以及当前作用域获取变量
Value* addVariable(const std::string &name, Value *variable); ///< 添加变量
std::vector<std::unique_ptr<GlobalValue>>& getGlobals(); ///< 获取全局变量列表
const std::vector<std::unique_ptr<ConstantVariable>>& getConsts() const; ///< 获取常量列表
const std::vector<std::unique_ptr<ConstantVariable>>& getConsts() const; ///< 获取全局常量列表
void enterNewScope(); ///< 进入新的作用域
void leaveScope(); ///< 离开作用域
bool isInGlobalScope() const; ///< 是否位于全局作用域
@ -1480,13 +1545,12 @@ class Module {
return result.first->second.get();
} ///< 创建外部函数
///< 变量创建伴随着符号表的更新
GlobalValue* createGlobalValue(const std::string &name, Type *type, const std::vector<Value *> &dims = {},
const ValueCounter &init = {}) {
GlobalValue* createGlobalValue(const std::string &name, Type *type, const ValueCounter &init = {}) {
bool isFinished = variableTable.isCurNodeNull();
if (isFinished) {
variableTable.enterGlobalScope();
}
auto result = variableTable.addVariable(name, new GlobalValue(this, type, name, dims, init));
auto result = variableTable.addVariable(name, new GlobalValue(this, type, name, init));
if (isFinished) {
variableTable.leaveScope();
}
@ -1495,9 +1559,8 @@ class Module {
}
return dynamic_cast<GlobalValue *>(result);
} ///< 创建全局变量
ConstantVariable* createConstVar(const std::string &name, Type *type, const ValueCounter &init,
const std::vector<Value *> &dims = {}) {
auto result = variableTable.addVariable(name, new ConstantVariable(this, type, name, init, dims));
ConstantVariable* createConstVar(const std::string &name, Type *type, const ValueCounter &init) {
auto result = variableTable.addVariable(name, new ConstantVariable(this, type, name, init));
if (result == nullptr) {
return nullptr;
}

View File

@ -239,31 +239,30 @@ class IRBuilder {
block->getInstructions().emplace(position, inst);
return inst;
} ///< 创建return指令
UncondBrInst * createUncondBrInst(BasicBlock *thenBlock, const std::vector<Value *> &args) {
auto inst = new UncondBrInst(thenBlock, args, block);
UncondBrInst * createUncondBrInst(BasicBlock *thenBlock) {
auto inst = new UncondBrInst(thenBlock, block);
assert(inst);
block->getInstructions().emplace(position, inst);
return inst;
} ///< 创建无条件指令
CondBrInst * createCondBrInst(Value *condition, BasicBlock *thenBlock, BasicBlock *elseBlock,
const std::vector<Value *> &thenArgs, const std::vector<Value *> &elseArgs) {
auto inst = new CondBrInst(condition, thenBlock, elseBlock, thenArgs, elseArgs, block);
CondBrInst * createCondBrInst(Value *condition, BasicBlock *thenBlock, BasicBlock *elseBlock) {
auto inst = new CondBrInst(condition, thenBlock, elseBlock, block);
assert(inst);
block->getInstructions().emplace(position, inst);
return inst;
} ///< 创建条件跳转指令
AllocaInst * createAllocaInst(Type *type, const std::vector<Value *> &dims = {}, const std::string &name = "") {
auto inst = new AllocaInst(type, dims, block, name);
UnreachableInst * createUnreachableInst(const std::string &name = "") {
auto inst = new UnreachableInst(name, block);
assert(inst);
block->getInstructions().emplace(position, inst);
return inst;
} ///< 创建不可达指令
AllocaInst * createAllocaInst(Type *type, const std::string &name = "") {
auto inst = new AllocaInst(type, block, name);
assert(inst);
block->getInstructions().emplace(position, inst);
return inst;
} ///< 创建分配指令
AllocaInst * createAllocaInstWithoutInsert(Type *type, const std::vector<Value *> &dims = {}, BasicBlock *parent = nullptr,
const std::string &name = "") {
auto inst = new AllocaInst(type, dims, parent, name);
assert(inst);
return inst;
} ///< 创建不插入指令列表的分配指令[仅用于phi指令]
LoadInst * createLoadInst(Value *pointer, const std::vector<Value *> &indices = {}, const std::string &name = "") {
std::string newName;
if (name.empty()) {
@ -275,7 +274,7 @@ class IRBuilder {
newName = name;
}
auto inst = new LoadInst(pointer, indices, block, newName);
auto inst = new LoadInst(pointer, block, newName);
assert(inst);
block->getInstructions().emplace(position, inst);
return inst;
@ -286,37 +285,27 @@ class IRBuilder {
block->getInstructions().emplace(position, inst);
return inst;
} ///< 创建memset指令
StoreInst * createStoreInst(Value *value, Value *pointer, const std::vector<Value *> &indices = {},
const std::string &name = "") {
auto inst = new StoreInst(value, pointer, indices, block, name);
StoreInst * createStoreInst(Value *value, Value *pointer, const std::string &name = "") {
auto inst = new StoreInst(value, pointer, block, name);
assert(inst);
block->getInstructions().emplace(position, inst);
return inst;
} ///< 创建store指令
PhiInst * createPhiInst(Type *type, const std::vector<Value*> &vals = {}, const std::vector<BasicBlock*> &blks = {}, const std::string &name = "") {
auto inst = new PhiInst(type, vals, blks, block, name);
std::string newName;
if (name.empty()) {
std::stringstream ss;
ss << tmpIndex;
newName = ss.str();
tmpIndex++;
} else {
newName = name;
}
auto inst = new PhiInst(type, vals, blks, block, newName);
assert(inst);
block->getInstructions().emplace(block->begin(), inst);
return inst;
} ///< 创建Phi指令
// GetElementPtrInst* createGetElementPtrInst(Value *basePointer,
// const std::vector<Value *> &indices = {},
// const std::string &name = "") {
// std::string newName;
// if (name.empty()) {
// std::stringstream ss;
// ss << tmpIndex;
// newName = ss.str();
// tmpIndex++;
// } else {
// newName = name;
// }
// auto inst = new GetElementPtrInst(basePointer, indices, block, newName);
// assert(inst);
// block->getInstructions().emplace(position, inst);
// return inst;
// }
/**
* @brief LLVM GEP
*

View File

@ -16,17 +16,20 @@ public:
const std::set<BasicBlock*>* getDominators(BasicBlock* BB) const;
BasicBlock* getImmediateDominator(BasicBlock* BB) const;
const std::set<BasicBlock*>* getDominanceFrontier(BasicBlock* BB) const;
const std::set<BasicBlock*>* getDominatorTreeChildren(BasicBlock* BB) const;
const std::map<BasicBlock*, std::set<BasicBlock*>>& getDominatorsMap() const { return Dominators; }
const std::map<BasicBlock*, BasicBlock*>& getIDomsMap() const { return IDoms; }
const std::map<BasicBlock*, std::set<BasicBlock*>>& getDominanceFrontiersMap() const { return DominanceFrontiers; }
void computeDominators(Function* F);
void computeIDoms(Function* F);
void computeDominanceFrontiers(Function* F);
void computeDominatorTreeChildren(Function* F);
private:
Function* AssociatedFunction;
std::map<BasicBlock*, std::set<BasicBlock*>> Dominators;
std::map<BasicBlock*, BasicBlock*> IDoms;
std::map<BasicBlock*, std::set<BasicBlock*>> DominanceFrontiers;
std::map<BasicBlock*, std::set<BasicBlock*>> DominatorTreeChildren;
};

View File

@ -0,0 +1,118 @@
#pragma once
#include "Pass.h" // 包含Pass的基类定义
#include "IR.h" // 包含IR相关的定义如Instruction, Function, BasicBlock, AllocaInst, LoadInst, StoreInst, PhiInst等
#include "Dom.h" // 假设支配树分析的头文件,提供 DominatorTreeAnalysisResult
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <queue>
#include <stack> // 用于变量重命名阶段的SSA值栈
namespace sysy {
// 前向声明分析结果类,确保在需要时可以引用
class DominatorTree;
// Mem2RegContext 类,封装 mem2reg 遍的核心逻辑和状态
// 这样可以避免静态变量在多线程或多次运行时的冲突,并保持代码的模块化
class Mem2RegContext {
public:
Mem2RegContext(IRBuilder *builder) : builder(builder) {}
// 运行 mem2reg 优化的主要方法
// func: 当前要优化的函数
// tp: 分析管理器,用于获取支配树等分析结果
void run(Function* func, AnalysisManager* tp);
private:
IRBuilder *builder; // IR 构建器,用于插入指令
// 存储所有需要被提升的 AllocaInst
std::vector<AllocaInst*> promotableAllocas;
// 存储每个 AllocaInst 对应的 Phi 指令列表
// 键是 AllocaInst值是该 AllocaInst 在各个基本块中插入的 Phi 指令的列表
// (实际上,一个 AllocaInst 在一个基本块中只会有一个 Phi)
std::unordered_map<AllocaInst*, std::unordered_map<BasicBlock*, PhiInst*>> allocaToPhiMap;
// 存储每个 AllocaInst 对应的当前活跃 SSA 值栈
// 用于在变量重命名阶段追踪每个 AllocaInst 在不同控制流路径上的最新值
std::unordered_map<AllocaInst*, std::stack<Value*>> allocaToValueStackMap;
// 辅助映射,存储每个 AllocaInst 的所有 store 指令
std::unordered_map<AllocaInst*, std::unordered_set<StoreInst*>> allocaToStoresMap;
// 辅助映射,存储每个 AllocaInst 对应的定义基本块(包含 store 指令的块)
std::unordered_map<AllocaInst*, std::unordered_set<BasicBlock*>> allocaToDefBlocksMap;
// 支配树分析结果,用于 Phi 插入和变量重命名
DominatorTree* dt;
// --------------------------------------------------------------------
// 阶段1: 识别可提升的 AllocaInst
// --------------------------------------------------------------------
// 判断一个 AllocaInst 是否可以被提升到寄存器
// alloca: 要检查的 AllocaInst
// 返回值: 如果可以提升,则为 true否则为 false
bool isPromotableAlloca(AllocaInst* alloca);
// 收集所有对给定 AllocaInst 进行存储的 StoreInst
// alloca: 目标 AllocaInst
void collectStores(AllocaInst* alloca);
// --------------------------------------------------------------------
// 阶段2: 插入 Phi 指令 (Phi Insertion)
// --------------------------------------------------------------------
// 为给定的 AllocaInst 插入必要的 Phi 指令
// alloca: 目标 AllocaInst
// defBlocks: 包含对该 AllocaInst 进行 store 操作的基本块集合
void insertPhis(AllocaInst* alloca, const std::unordered_set<BasicBlock*>& defBlocks);
// --------------------------------------------------------------------
// 阶段3: 变量重命名 (Variable Renaming)
// --------------------------------------------------------------------
// 对支配树进行深度优先遍历,重命名变量并替换 load/store 指令
// alloca: 当前正在处理的 AllocaInst
// currentBB: 当前正在遍历的基本块
// dt: 支配树分析结果
// valueStack: 存储当前 AllocaInst 在当前路径上可见的 SSA 值栈
void renameVariables(AllocaInst* alloca, BasicBlock* currentBB);
// --------------------------------------------------------------------
// 阶段4: 清理
// --------------------------------------------------------------------
// 删除所有原始的 AllocaInst、LoadInst 和 StoreInst
void cleanup();
};
// Mem2Reg 优化遍类,继承自 OptimizationPass
// 粒度为 Function表示它在每个函数上独立运行
class Mem2Reg : public OptimizationPass {
private:
IRBuilder *builder;
public:
// 构造函数
Mem2Reg(IRBuilder *builder) : OptimizationPass("Mem2Reg", Granularity::Function), builder(builder) {}
// 静态成员作为该遍的唯一ID
static void *ID;
// 运行在函数上的优化逻辑
// F: 当前要优化的函数
// AM: 分析管理器,用于获取支配树等分析结果,或使分析结果失效
// 返回值: 如果IR被修改则为true否则为false
bool runOnFunction(Function *F, AnalysisManager& AM) override;
// 声明该遍的分析依赖和失效信息
// analysisDependencies: 该遍运行前需要哪些分析结果
// analysisInvalidations: 该遍运行后会使哪些分析结果失效
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,59 @@
#pragma once
#include "IR.h"
#include "IRBuilder.h" // 你的 IR Builder
#include "Liveness.h"
#include "Dom.h"
#include "Pass.h" // 你的 Pass 框架基类
#include <iostream> // 调试用
#include <map> // 用于 Value 到 AllocaInst 的映射
#include <set> // 可能用于其他辅助集合
#include <string>
#include <vector>
namespace sysy {
class Reg2MemContext {
public:
Reg2MemContext(IRBuilder *b) : builder(b) {}
// 运行 Reg2Mem 优化
void run(Function *func);
private:
IRBuilder *builder; // IR 构建器
// 存储 SSA Value 到对应的 AllocaInst 的映射
// 只有那些需要被"溢出"到内存的 SSA 值才会被记录在这里
std::map<Value *, AllocaInst *> valueToAllocaMap;
// 辅助函数:
// 1. 识别并为 SSA Value 分配 AllocaInst
void allocateMemoryForSSAValues(Function *func);
// 2. 将 SSA 值的使用替换为 Load/Store
void insertLoadsAndStores(Function *func);
// 3. 处理 Phi 指令,将其转换为 Load/Store
void rewritePhis(Function *func);
// 4. 清理 (例如,可能删除不再需要的 Phi 指令)
void cleanup(Function *func);
// 判断一个 Value 是否是 AllocaInst 可以为其分配内存的目标
// 通常指非指针类型的Instruction结果和Argument
bool isPromotableToMemory(Value *val);
};
class Reg2Mem : public OptimizationPass {
private:
IRBuilder *builder; ///< IR构建器用于插入指令
public:
static void *ID; ///< Pass的唯一标识符
Reg2Mem(IRBuilder* builder) : OptimizationPass("Reg2Mem", Pass::Granularity::Function), builder(builder) {}
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; } ///< 获取 Pass ID
};
} // namespace sysy

View File

@ -0,0 +1,139 @@
#pragma once
#include "IR.h"
#include "Pass.h"
#include "SysYIROptUtils.h"
#include <cassert>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <unordered_set>
#include <vector>
#include <variant>
#include <functional>
namespace sysy {
// 定义三值格 (Three-valued Lattice) 的状态
enum class LatticeVal {
Top, // (未知 / 未初始化)
Constant, // c (常量)
Bottom // ⊥ (不确定 / 变化 / 未定义)
};
// 新增枚举来区分常量的实际类型
enum class ValueType {
Integer,
Float,
Unknown // 用于 Top 和 Bottom 状态
};
// 用于表示 SSA 值的具体状态(包含格值和常量值)
struct SSAPValue {
LatticeVal state;
std::variant<int, float> constantVal; // 使用 std::variant 存储 int 或 float
ValueType constant_type; // 记录常量是整数还是浮点数
// 默认构造函数,初始化为 Top
SSAPValue() : state(LatticeVal::Top), constantVal(0), constant_type(ValueType::Unknown) {}
// 构造函数,用于创建 Bottom 状态
SSAPValue(LatticeVal s) : state(s), constantVal(0), constant_type(ValueType::Unknown) {
assert((s == LatticeVal::Top || s == LatticeVal::Bottom) && "SSAPValue(LatticeVal) only for Top/Bottom");
}
// 构造函数,用于创建 int Constant 状态
SSAPValue(int c) : state(LatticeVal::Constant), constantVal(c), constant_type(ValueType::Integer) {}
// 构造函数,用于创建 float Constant 状态
SSAPValue(float c) : state(LatticeVal::Constant), constantVal(c), constant_type(ValueType::Float) {}
// 比较操作符,用于判断状态是否改变
bool operator==(const SSAPValue &other) const {
if (state != other.state)
return false;
if (state == LatticeVal::Constant) {
if (constant_type != other.constant_type) return false; // 类型必须匹配
return constantVal == other.constantVal; // std::variant 会比较内部值
}
return true; // Top == Top, Bottom == Bottom
}
bool operator!=(const SSAPValue &other) const { return !(*this == other); }
};
// SCCP 上下文类,持有每个函数运行时的状态
class SCCPContext {
private:
IRBuilder *builder; // IR 构建器,用于插入指令和创建常量
// 工作列表
// 存储需要重新评估的指令
std::queue<Instruction *> instWorkList;
// 存储需要重新评估的控制流边 (pair: from_block, to_block)
std::queue<std::pair<BasicBlock *, BasicBlock *>> edgeWorkList;
// 格值映射SSA Value 到其当前状态
std::map<Value *, SSAPValue> valueState;
// 可执行基本块集合
std::unordered_set<BasicBlock *> executableBlocks;
// 追踪已访问的CFG边防止重复添加使用 SysYIROptUtils::PairHash
std::unordered_set<std::pair<BasicBlock*, BasicBlock*>, SysYIROptUtils::PairHash> visitedCFGEdges;
// 辅助函数:格操作 Meet
SSAPValue Meet(const SSAPValue &a, const SSAPValue &b);
// 辅助函数:获取值的当前状态,如果不存在则默认为 Top
SSAPValue GetValueState(Value *v);
// 辅助函数:更新值的状态,如果状态改变,将所有用户加入指令工作列表
void UpdateState(Value *v, SSAPValue newState);
// 辅助函数:将边加入边工作列表,并更新可执行块
void AddEdgeToWorkList(BasicBlock *fromBB, BasicBlock *toBB);
// 辅助函数:标记一个块为可执行
void MarkBlockExecutable(BasicBlock* block);
// 辅助函数:对二元操作进行常量折叠
SSAPValue ComputeConstant(BinaryInst *binaryinst, SSAPValue lhsVal, SSAPValue rhsVal);
// 辅助函数:对一元操作进行常量折叠
SSAPValue ComputeConstant(UnaryInst *unaryInst, SSAPValue operandVal);
// 主要优化阶段
// 阶段1: 常量传播与折叠
bool PropagateConstants(Function *func);
// 阶段2: 控制流简化
bool SimplifyControlFlow(Function *func);
// 辅助函数:处理单条指令
void ProcessInstruction(Instruction *inst);
// 辅助函数:处理单条控制流边
void ProcessEdge(const std::pair<BasicBlock *, BasicBlock *> &edge);
// 控制流简化辅助函数
// 查找所有可达的基本块 (基于常量条件)
std::unordered_set<BasicBlock *> FindReachableBlocks(Function *func);
// 移除死块
void RemoveDeadBlock(BasicBlock *bb, Function *func);
// 简化分支(将条件分支替换为无条件分支)
void SimplifyBranch(CondBrInst*brInst, bool condVal); // 保持 BranchInst
// 更新前驱块的终结指令(当一个后继块被移除时)
void UpdateTerminator(BasicBlock *predBB, BasicBlock *removedSucc);
// 移除 Phi 节点的入边(当其前驱块被移除时)
void RemovePhiIncoming(BasicBlock *phiParentBB, BasicBlock *removedPred);
public:
SCCPContext(IRBuilder *builder) : builder(builder) {}
// 运行 SCCP 优化
void run(Function *func, AnalysisManager &AM);
};
// SCCP 优化遍类,继承自 OptimizationPass
class SCCP : public OptimizationPass {
private:
IRBuilder *builder; // IR 构建器,作为 Pass 的成员,传入 Context
public:
SCCP(IRBuilder *builder) : OptimizationPass("SCCP", Granularity::Function), builder(builder) {}
static void *ID;
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,119 @@
#pragma once
#include "IR.h"
extern int DEBUG;
namespace sysy {
// 优化工具类,包含一些通用的优化方法
// 这些方法可以在不同的优化 pass 中复用
// 例如删除use关系,判断是否是全局变量等
class SysYIROptUtils{
public:
struct PairHash {
template <class T1, class T2>
std::size_t operator () (const std::pair<T1, T2>& p) const {
auto h1 = std::hash<T1>{}(p.first);
auto h2 = std::hash<T2>{}(p.second);
// 简单的组合哈希值,可以更复杂以减少冲突
// 使用 boost::hash_combine 的简化版本
return h1 ^ (h2 << 1);
}
};
static void RemoveUserOperandUses(User *user) {
if (!user) {
return;
}
// 遍历 User 的 operands 列表。
// 由于 operands 是 protected 成员,我们需要一个临时方法来访问它,
// 或者在 User 类中添加一个 friend 声明。
// 假设 User 内部有一个像 getOperands() 这样的公共方法返回 operands 的引用,
// 或者将 SysYIROptUtils 声明为 User 的 friend。
// 为了示例,我将假设可以直接访问 user->operands 或通过一个getter。
// 如果无法直接访问,请在 IR.h 的 User 类中添加:
// public: const std::vector<std::shared_ptr<Use>>& getOperands() const { return operands; }
// 迭代 copies of shared_ptr to avoid issues if removeUse modifies the list
// (though remove should handle it, iterating a copy is safer or reverse iteration).
// Since we'll clear the vector at the end, iterating forward is fine.
for (const auto& use_ptr : user->getOperands()) { // 假设 getOperands() 可用
if (use_ptr) {
Value *val = use_ptr->getValue(); // 获取 Use 指向的 Value (如 AllocaInst)
if (val) {
val->removeUse(use_ptr); // 通知 Value 从其 uses 列表中移除此 Use 关系
}
}
}
// 清空 User 的 operands 向量。这会递减 User 持有的 shared_ptr<Use> 的引用计数。
// 当引用计数降为 0 时Use 对象本身将被销毁。
// User::operands.clear(); // 这个步骤会在 Instruction 的析构函数中自动完成,因为它是 vector 成员
// 或者我们可以在 User::removeOperand 方法中确保 Use 对象从 operands 中移除。
// 实际上,只要 Value::removeUse(use_ptr) 被调用了,
// 当 Instruction 所在的 unique_ptr 销毁时,它的 operands vector 也会被销毁。
// 所以这里不需要显式 clear()
}
static void usedelete(Instruction *inst) {
assert(inst && "Instruction to delete cannot be null.");
BasicBlock *parentBlock = inst->getParent();
assert(parentBlock && "Instruction must have a parent BasicBlock to be deleted.");
// 步骤1: 处理所有使用者,将他们从使用 inst 变为使用 UndefinedValue
// 这将清理 inst 作为 Value 时的 uses 列表
if (!inst->getUses().empty()) {
inst->replaceAllUsesWith(UndefinedValue::get(inst->getType()));
}
// 步骤2: 清理 inst 作为 User 时的操作数关系
// 通知 inst 所使用的所有 Value (如 AllocaInst),移除对应的 Use 关系。
// 这里的 inst 实际上是一个 User*,所以可以安全地向下转型。
RemoveUserOperandUses(static_cast<User*>(inst));
// 步骤3: 物理删除指令
// 这会导致 Instruction 对象的 unique_ptr 销毁,从而调用其析构函数链。
parentBlock->removeInst(inst);
}
static BasicBlock::iterator usedelete(BasicBlock::iterator inst_it) {
Instruction *inst_to_delete = inst_it->get();
BasicBlock *parentBlock = inst_to_delete->getParent();
assert(parentBlock && "Instruction must have a parent BasicBlock for iterator deletion.");
// 步骤1: 处理所有使用者
if (!inst_to_delete->getUses().empty()) {
inst_to_delete->replaceAllUsesWith(UndefinedValue::get(inst_to_delete->getType()));
}
// 步骤2: 清理操作数关系
RemoveUserOperandUses(static_cast<User*>(inst_to_delete));
// 步骤3: 物理删除指令并返回下一个迭代器
return parentBlock->removeInst(inst_it);
}
// 判断是否是全局变量
static bool isGlobal(Value *val) {
auto gval = dynamic_cast<GlobalValue *>(val);
return gval != nullptr;
}
// 判断是否是数组
static bool isArr(Value *val) {
auto aval = dynamic_cast<AllocaInst *>(val);
// 如果是 AllocaInst 且通过Type::isArray()判断为数组类型
return aval && aval->getType()->as<PointerType>()->getBaseType()->isArray();
}
// 判断是否是指向数组的指针
static bool isArrPointer(Value *val) {
auto aval = dynamic_cast<AllocaInst *>(val);
// 如果是 AllocaInst 且通过Type::isPointer()判断为指针;
auto baseType = aval->getType()->as<PointerType>()->getBaseType();
// 在sysy中函数的数组参数会退化成指针
// 所以当AllocaInst的basetype是PointerType时一维数组或者是指向ArrayType的PointerType多位数组返回true
return aval && (baseType->isPointer() || baseType->as<PointerType>()->getBaseType()->isArray());
}
};
}// namespace sysy

View File

@ -11,6 +11,8 @@
#include "IR.h"
#include "IRBuilder.h"
extern int DEBUG; // 全局调试标志
namespace sysy {
//前向声明
@ -149,6 +151,9 @@ 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: {
@ -292,6 +297,9 @@ public:
AnalysisManager &getAnalysisManager() { return analysisManager; }
void clearPasses();
// 输出pass列表并打印IR信息供观察优化遍效果
void printPasses() const;
};
// ======================================================================

View File

@ -15,6 +15,7 @@ public:
public:
void printIR();
void printGlobalVariable();
void printGlobalConstant();
public:
@ -22,6 +23,8 @@ public:
static void printInst(Instruction *pInst);
static void printType(Type *type);
static void printValue(Value *value);
static void printBlock(BasicBlock *block);
static std::string getBlockName(BasicBlock *block);
static std::string getOperandName(Value *operand);
static std::string getTypeString(Type *type);
static std::string getValueName(Value *value);

24
src/midend/CMakeLists.txt Normal file
View File

@ -0,0 +1,24 @@
# src/midend/CMakeLists.txt
add_library(midend_lib STATIC
IR.cpp
SysYIRGenerator.cpp
SysYIRPrinter.cpp
Pass/Pass.cpp
Pass/Analysis/Dom.cpp
Pass/Analysis/Liveness.cpp
Pass/Optimize/DCE.cpp
Pass/Optimize/Mem2Reg.cpp
Pass/Optimize/Reg2Mem.cpp
Pass/Optimize/SysYIRCFGOpt.cpp
Pass/Optimize/SCCP.cpp
)
# 包含中端模块所需的头文件路径
target_include_directories(midend_lib PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../include/midend # 中端顶层头文件
${CMAKE_CURRENT_SOURCE_DIR}/../include/midend/Pass # 增加 Pass 头文件路径
${CMAKE_CURRENT_SOURCE_DIR}/../include/midend/Pass/Analysis # 增加 Pass/Analysis 头文件路径
${CMAKE_CURRENT_SOURCE_DIR}/../include/midend/Pass/Optimize # 增加 Pass/Optimize 头文件路径
${CMAKE_CURRENT_SOURCE_DIR}/../include/frontend # 增加 frontend 头文件路径 (已存在)
${ANTLR_RUNTIME}/runtime/src # ANTLR运行时库头文件
)

View File

@ -227,12 +227,13 @@ Function * Function::clone(const std::string &suffix) const {
auto oldAllocInst = dynamic_cast<AllocaInst *>(value);
if (oldAllocInst != nullptr) {
std::vector<Value *> dims;
for (const auto &dim : oldAllocInst->getDims()) {
dims.emplace_back(dim->getValue());
}
// TODO: 这里的dims用type推断
// for (const auto &dim : oldAllocInst->getDims()) {
// dims.emplace_back(dim->getValue());
// }
ss << oldAllocInst->getName() << suffix;
auto newAllocInst =
new AllocaInst(oldAllocInst->getType(), dims, oldNewBlockMap.at(oldAllocInst->getParent()), ss.str());
new AllocaInst(oldAllocInst->getType(), oldNewBlockMap.at(oldAllocInst->getParent()), ss.str());
ss.str("");
oldNewValueMap.emplace(oldAllocInst, newAllocInst);
if (isAddedToCreate.find(oldAllocInst) == isAddedToCreate.end()) {
@ -252,12 +253,13 @@ Function * Function::clone(const std::string &suffix) const {
if (oldNewValueMap.find(inst.get()) == oldNewValueMap.end()) {
auto oldAllocInst = dynamic_cast<AllocaInst *>(inst.get());
std::vector<Value *> dims;
for (const auto &dim : oldAllocInst->getDims()) {
dims.emplace_back(dim->getValue());
}
// TODO: 这里的dims用type推断
// for (const auto &dim : oldAllocInst->getDims()) {
// dims.emplace_back(dim->getValue());
// }
ss << oldAllocInst->getName() << suffix;
auto newAllocInst =
new AllocaInst(oldAllocInst->getType(), dims, oldNewBlockMap.at(oldAllocInst->getParent()), ss.str());
new AllocaInst(oldAllocInst->getType(), oldNewBlockMap.at(oldAllocInst->getParent()), ss.str());
ss.str("");
oldNewValueMap.emplace(oldAllocInst, newAllocInst);
if (isAddedToCreate.find(oldAllocInst) == isAddedToCreate.end()) {
@ -422,7 +424,7 @@ Function * Function::clone(const std::string &suffix) const {
Value *newCond;
newCond = oldNewValueMap.at(oldCond);
auto newCondBrInst = new CondBrInst(newCond, oldNewBlockMap.at(oldCondBrInst->getThenBlock()),
oldNewBlockMap.at(oldCondBrInst->getElseBlock()), {}, {},
oldNewBlockMap.at(oldCondBrInst->getElseBlock()),
oldNewBlockMap.at(oldCondBrInst->getParent()));
oldNewValueMap.emplace(oldCondBrInst, newCondBrInst);
break;
@ -431,7 +433,7 @@ Function * Function::clone(const std::string &suffix) const {
case Instruction::kBr: {
auto oldBrInst = dynamic_cast<UncondBrInst *>(inst);
auto newBrInst =
new UncondBrInst(oldNewBlockMap.at(oldBrInst->getBlock()), {}, oldNewBlockMap.at(oldBrInst->getParent()));
new UncondBrInst(oldNewBlockMap.at(oldBrInst->getBlock()), oldNewBlockMap.at(oldBrInst->getParent()));
oldNewValueMap.emplace(oldBrInst, newBrInst);
break;
}
@ -460,11 +462,12 @@ Function * Function::clone(const std::string &suffix) const {
newPointer = oldNewValueMap.at(oldPointer);
std::vector<Value *> newIndices;
for (const auto &index : oldLoadInst->getIndices()) {
newIndices.emplace_back(oldNewValueMap.at(index->getValue()));
}
// for (const auto &index : oldLoadInst->getIndices()) {
// newIndices.emplace_back(oldNewValueMap.at(index->getValue()));
// }
ss << oldLoadInst->getName() << suffix;
auto newLoadInst = new LoadInst(newPointer, newIndices, oldNewBlockMap.at(oldLoadInst->getParent()), ss.str());
// TODO : 这里的newLoadInst的类型需要根据oldLoadInst的类型来推断
auto newLoadInst = new LoadInst(newPointer, oldNewBlockMap.at(oldLoadInst->getParent()), ss.str());
ss.str("");
oldNewValueMap.emplace(oldLoadInst, newLoadInst);
break;
@ -479,10 +482,11 @@ Function * Function::clone(const std::string &suffix) const {
std::vector<Value *> newIndices;
newPointer = oldNewValueMap.at(oldPointer);
newValue = oldNewValueMap.at(oldValue);
for (const auto &index : oldStoreInst->getIndices()) {
newIndices.emplace_back(oldNewValueMap.at(index->getValue()));
}
auto newStoreInst = new StoreInst(newValue, newPointer, newIndices,
// TODO: 这里的newIndices需要根据oldStoreInst的类型来推断
// for (const auto &index : oldStoreInst->getIndices()) {
// newIndices.emplace_back(oldNewValueMap.at(index->getValue()));
// }
auto newStoreInst = new StoreInst(newValue, newPointer,
oldNewBlockMap.at(oldStoreInst->getParent()), oldStoreInst->getName());
oldNewValueMap.emplace(oldStoreInst, newStoreInst);
break;
@ -565,7 +569,7 @@ void User::replaceOperand(unsigned index, Value *value) {
* phi相关函数
*/
Value* PhiInst::getvalfromBlk(BasicBlock* blk){
Value* PhiInst::getvalfromBlk(BasicBlock* blk){
refreshB2VMap();
if( blk2val.find(blk) != blk2val.end()) {
return blk2val.at(blk);
@ -615,11 +619,13 @@ void PhiInst::delBlk(BasicBlock* blk){
void PhiInst::replaceBlk(BasicBlock* newBlk, unsigned k){
refreshB2VMap();
Value* val = blk2val.at(getBlock(k));
BasicBlock* oldBlk = getBlock(k);
Value* val = blk2val.at(oldBlk);
// Value* val = blk2val.at(getBlock(k));
// 替换基本块
setOperand(2 * k + 1, newBlk);
// 替换blk2val映射
blk2val.erase(getBlock(k));
blk2val.erase(oldBlk);
blk2val.emplace(newBlk, val);
}
@ -652,6 +658,7 @@ Function * CallInst::getCallee() const { return dynamic_cast<Function *>(getOper
/**
*
* nullptr
*/
auto SymbolTable::getVariable(const std::string &name) const -> Value * {
auto node = curNode;
@ -688,7 +695,7 @@ auto SymbolTable::addVariable(const std::string &name, Value *variable) -> Value
if (global != nullptr) {
globals.emplace_back(global);
} else if (constvar != nullptr) {
consts.emplace_back(constvar);
globalconsts.emplace_back(constvar);
}
result = variable;
@ -703,7 +710,7 @@ auto SymbolTable::getGlobals() -> std::vector<std::unique_ptr<GlobalValue>> & {
/**
*
*/
auto SymbolTable::getConsts() const -> const std::vector<std::unique_ptr<ConstantVariable>> & { return consts; }
auto SymbolTable::getConsts() const -> const std::vector<std::unique_ptr<ConstantVariable>> & { return globalconsts; }
/**
*
*/

View File

@ -38,6 +38,14 @@ const std::set<BasicBlock *> *DominatorTree::getDominanceFrontier(BasicBlock *BB
return nullptr;
}
const std::set<BasicBlock*>* DominatorTree::getDominatorTreeChildren(BasicBlock* BB) const {
auto it = DominatorTreeChildren.find(BB);
if (it != DominatorTreeChildren.end()) {
return &(it->second);
}
return nullptr;
}
void DominatorTree::computeDominators(Function *F) {
// 经典的迭代算法计算支配者集合
// TODO: 可以替换为更高效的算法,如 Lengauer-Tarjan 算法
@ -159,6 +167,19 @@ void DominatorTree::computeDominanceFrontiers(Function *F) {
}
}
void DominatorTree::computeDominatorTreeChildren(Function *F) {
for (auto &bb_ptr : F->getBasicBlocks()) {
BasicBlock *B = bb_ptr.get();
auto it = getImmediateDominator(B);
if (it != nullptr) {
BasicBlock *A = it;
if (A) {
DominatorTreeChildren[A].insert(B);
}
}
}
}
// ==============================================================
// DominatorTreeAnalysisPass 的实现
// ==============================================================
@ -169,6 +190,7 @@ bool DominatorTreeAnalysisPass::runOnFunction(Function* F, AnalysisManager &AM)
CurrentDominatorTree->computeDominators(F);
CurrentDominatorTree->computeIDoms(F);
CurrentDominatorTree->computeDominanceFrontiers(F);
CurrentDominatorTree->computeDominatorTreeChildren(F);
return false;
}

View File

@ -51,10 +51,8 @@ void DCEContext::run(Function *func, AnalysisManager *AM, bool &changed) {
// 如果指令不在活跃集合中,则删除它。
// 分支和返回指令由 isAlive 处理,并会被保留。
if (alive_insts.count(currentInst) == 0) {
// 删除指令,保留用户风格的 SysYIROptUtils::usedelete 和 erase
instIter = SysYIROptUtils::usedelete(instIter); // 删除后返回下一个迭代器
changed = true; // 标记 IR 已被修改
SysYIROptUtils::usedelete(currentInst);
instIter = basicBlock->getInstructions().erase(instIter); // 删除后返回下一个迭代器
} else {
++instIter; // 指令活跃,移动到下一个
}

View File

@ -0,0 +1,392 @@
#include "Mem2Reg.h" // 包含 Mem2Reg 遍的头文件
#include "Dom.h" // 包含支配树分析的头文件
#include "Liveness.h"
#include "IR.h" // 包含 IR 相关的定义
#include "SysYIROptUtils.h"
#include <cassert> // 用于断言
#include <iostream> // 用于调试输出
namespace sysy {
void *Mem2Reg::ID = (void *)&Mem2Reg::ID;
void Mem2RegContext::run(Function *func, AnalysisManager *AM) {
if (func->getBasicBlocks().empty()) {
return;
}
// 清空所有状态,确保每次运行都是新的状态
promotableAllocas.clear();
allocaToPhiMap.clear();
allocaToValueStackMap.clear();
allocaToStoresMap.clear();
allocaToDefBlocksMap.clear();
// 获取支配树分析结果
dt = AM->getAnalysisResult<DominatorTree, DominatorTreeAnalysisPass>(func);
assert(dt && "DominatorTreeAnalysisResult not available for Mem2Reg!");
// --------------------------------------------------------------------
// 阶段1: 识别可提升的 AllocaInst 并收集其 Store 指令
// --------------------------------------------------------------------
// 遍历函数入口块?中的所有指令,寻找 AllocaInst
// 必须是要入口块的吗
for (auto &inst : func->getEntryBlock()->getInstructions_Range()) {
Value *allocainst = inst.get();
if (auto alloca = dynamic_cast<AllocaInst *>(allocainst)) {
if (isPromotableAlloca(alloca)) {
promotableAllocas.push_back(alloca);
collectStores(alloca); // 收集所有对该 alloca 的 store
}
}
}
// --------------------------------------------------------------------
// 阶段2: 插入 Phi 指令
// --------------------------------------------------------------------
for (auto alloca : promotableAllocas) {
// 为每个可提升的 alloca 插入 Phi 指令
insertPhis(alloca, allocaToDefBlocksMap[alloca]);
}
// --------------------------------------------------------------------
// 阶段3: 变量重命名
// --------------------------------------------------------------------
// 为每个可提升的 alloca 初始化其值栈
for (auto alloca : promotableAllocas) {
// 初始值通常是 undef 或 null取决于 IR 类型系统
UndefinedValue *undefValue = UndefinedValue::get(alloca->getType()->as<PointerType>()->getBaseType());
allocaToValueStackMap[alloca].push(undefValue); // 压入一个初始的“未定义”值
}
// 从入口基本块开始,对支配树进行 DFS 遍历,进行变量重命名
renameVariables(nullptr, func->getEntryBlock()); // 第一个参数 alloca 在这里不使用,因为是递归入口点
// --------------------------------------------------------------------
// 阶段4: 清理
// --------------------------------------------------------------------
cleanup();
}
// 判断一个 AllocaInst 是否可以被提升到寄存器
bool Mem2RegContext::isPromotableAlloca(AllocaInst *alloca) {
// 1. 必须是标量类型非数组、非结构体sysy不支持结构体
if (alloca->getType()->as<PointerType>()->getBaseType()->isArray()) {
return false;
}
// 2. 其所有用途都必须是 LoadInst 或 StoreInst
// (或 GetElementPtrInst但 GEP 的结果也必须只被 Load/Store 使用)
for (auto use : alloca->getUses()) {
auto user = use->getUser();
if (!user)
return false; // 用户无效
if (dynamic_cast<LoadInst *>(user)) {
// OK
} else if (dynamic_cast<StoreInst *>(user)) {
// OK
} else if (auto gep = dynamic_cast<GetElementPtrInst *>(user)) {
// 如果是 GetElementPtrInst (GEP)
// 需要判断这个 GEP 是否代表了数组元素的访问,而非简单的指针操作
// LLVM 的 mem2reg 通常不提升用于数组元素访问的 alloca。
// 启发式判断:
// 如果 GEP 有多个索引(例如 `getelementptr i32, i32* %ptr, i32 0, i32 %idx`
// 或者第一个索引(对于指针类型)不是常量 0则很可能是数组访问。
// 对于 `alloca i32* %a.param` (对应 `int a[]` 参数),其 `allocatedType()` 是 `i32*`。
// 访问 `a[i]` 会生成类似 `getelementptr i32, i32* %a.param, i32 %i` 的 GEP。
// 这种 GEP 有两个操作数:基指针和索引。
// 检查 GEP 的操作数数量和索引值
// GEP 的操作数通常是:<base_pointer>, <index_1>, <index_2>, ...
// 对于一个 `i32*` 类型的 `alloca`,如果它被 GEP 使用,那么 GEP 的第一个索引通常是 `0`
// (表示解引用指针本身),后续索引才是数组元素的索引。
// 如果 GEP 的操作数数量大于 2 (即 `base_ptr` 和 `index_0` 之外还有其他索引)
// 或者 `index_0` 不是常量 0则它可能是一个复杂的数组访问。
// 假设 `gep->getNumOperands()` 和 `gep->getOperand(idx)->getValue()`
// 假设 `ConstantInt` 类用于表示常量整数值
if (gep->getNumOperands() > 2) { // 如果有超过一个索引(除了基指针的第一个隐式索引)
// std::cerr << "Mem2Reg: Not promotable (GEP with multiple indices): " << alloca->name() << std::endl;
return false; // 复杂 GEP通常表示数组或结构体字段访问
}
if (gep->getNumOperands() == 2) { // 只有基指针和一个索引
Value *firstIndexVal = gep->getOperand(1); // 获取第一个索引值
if (auto constInt = dynamic_cast<ConstantInteger *>(firstIndexVal)) {
if (constInt->getInt() != 0) {
// std::cerr << "Mem2Reg: Not promotable (GEP with non-zero first index): " << alloca->name() << std::endl;
return false; // 索引不是0表示访问数组的非第一个元素
}
} else {
// std::cerr << "Mem2Reg: Not promotable (GEP with non-constant first index): " << alloca->name() <<
// std::endl;
return false; // 索引不是常量,表示动态数组访问
}
}
// 此外GEP 的结果也必须只被 LoadInst 或 StoreInst 使用
for (auto gep_use : gep->getUses()) {
auto gep_user = gep_use->getUser();
if (!gep_user) {
// std::cerr << "Mem2Reg: Not promotable (GEP result null user): " << alloca->name() << std::endl;
return false;
}
if (!dynamic_cast<LoadInst *>(gep_user) && !dynamic_cast<StoreInst *>(gep_user)) {
// std::cerr << "Mem2Reg: Not promotable (GEP result used by non-load/store): " << alloca->name() <<
// std::endl;
return false; // GEP 结果被其他指令使用,地址逃逸或复杂用途
}
}
} else {
// 其他类型的用户,如 CallInst (如果地址逃逸),则不能提升
return false;
}
}
// 3. 不能是 volatile 内存访问 (假设 AllocaInst 有 isVolatile() 方法)
// if (alloca->isVolatile()) return false; // 如果有这样的属性
return true;
}
// 收集所有对给定 AllocaInst 进行存储的 StoreInst
void Mem2RegContext::collectStores(AllocaInst *alloca) {
// 遍历 alloca 的所有用途
for (auto use : alloca->getUses()) {
auto user = use->getUser();
if (!user)
continue;
if (auto storeInst = dynamic_cast<StoreInst *>(user)) {
allocaToStoresMap[alloca].insert(storeInst);
allocaToDefBlocksMap[alloca].insert(storeInst->getParent());
} else if (auto gep = dynamic_cast<GetElementPtrInst *>(user)) {
// 如果是 GEP递归收集其下游的 store
for (auto gep_use : gep->getUses()) {
if (auto gep_store = dynamic_cast<StoreInst *>(gep_use->getUser())) {
allocaToStoresMap[alloca].insert(gep_store);
allocaToDefBlocksMap[alloca].insert(gep_store->getParent());
}
}
}
}
}
// 为给定的 AllocaInst 插入必要的 Phi 指令
void Mem2RegContext::insertPhis(AllocaInst *alloca, const std::unordered_set<BasicBlock *> &defBlocks) {
std::queue<BasicBlock *> workQueue;
std::unordered_set<BasicBlock *> phiHasBeenInserted; // 记录已插入 Phi 的基本块
// 将所有定义块加入工作队列
for (auto bb : defBlocks) {
workQueue.push(bb);
}
while (!workQueue.empty()) {
BasicBlock *currentDefBlock = workQueue.front();
workQueue.pop();
// 遍历当前定义块的支配边界 (Dominance Frontier)
const std::set<BasicBlock *> *frontierBlocks = dt->getDominanceFrontier(currentDefBlock);
for (auto frontierBlock : *frontierBlocks) {
// 如果该支配边界块还没有为当前 alloca 插入 Phi 指令
if (phiHasBeenInserted.find(frontierBlock) == phiHasBeenInserted.end()) {
// 在支配边界块的开头插入一个新的 Phi 指令
// Phi 指令的类型与 alloca 的类型指向的类型相同
builder->setPosition(frontierBlock, frontierBlock->begin()); // 设置插入位置为基本块开头
PhiInst *phiInst = builder->createPhiInst(alloca->getAllocatedType(), {}, {}, "");
allocaToPhiMap[alloca][frontierBlock] = phiInst; // 记录 Phi 指令
phiHasBeenInserted.insert(frontierBlock); // 标记已插入 Phi
// 如果这个支配边界块本身也是一个定义块(即使没有 store但插入了 Phi
// 那么它的支配边界也可能需要插入 Phi
// 例如一个xx型的cfg如果在第一个交叉处插入phi节点那么第二个交叉处可能也需要插入phi
workQueue.push(frontierBlock);
}
}
}
}
// 对支配树进行深度优先遍历,重命名变量并替换 load/store 指令
void Mem2RegContext::renameVariables(AllocaInst *currentAlloca, BasicBlock *currentBB) {
// 维护一个局部栈,用于存储当前基本块中为 Phi 和 Store 创建的 SSA 值,以便在退出时弹出
std::stack<Value *> localStackPushed;
// --------------------------------------------------------------------
// 处理当前基本块的指令
// --------------------------------------------------------------------
for (auto instIter = currentBB->getInstructions().begin(); instIter != currentBB->getInstructions().end();) {
Instruction *inst = instIter->get();
bool instDeleted = false;
// 处理 Phi 指令 (如果是当前 alloca 的 Phi)
if (auto phiInst = dynamic_cast<PhiInst *>(inst)) {
// 检查这个 Phi 是否是为某个可提升的 alloca 插入的
for (auto alloca : promotableAllocas) {
if (allocaToPhiMap[alloca].count(currentBB) && allocaToPhiMap[alloca][currentBB] == phiInst) {
// 为 Phi 指令的输出创建一个新的 SSA 值,并压入值栈
allocaToValueStackMap[alloca].push(phiInst);
localStackPushed.push(phiInst); // 记录以便弹出
break; // 找到对应的 alloca处理下一个指令
}
}
}
// 处理 LoadInst
else if (auto loadInst = dynamic_cast<LoadInst *>(inst)) {
// 检查这个 LoadInst 是否是为某个可提升的 alloca
for (auto alloca : promotableAllocas) {
if (loadInst->getPointer() == alloca) {
// loadInst->getPointer() 返回 AllocaInst*
// 将 LoadInst 的所有用途替换为当前 alloca 值栈顶部的 SSA 值
assert(!allocaToValueStackMap[alloca].empty() && "Value stack empty for alloca during load replacement!");
if(DEBUG){
std::cout << "Mem2Reg: Replacing load " << loadInst->getPointer()->getName() << " with SSA value." << std::endl;
}
loadInst->replaceAllUsesWith(allocaToValueStackMap[alloca].top());
instIter = SysYIROptUtils::usedelete(instIter);
instDeleted = true;
// std::cerr << "Mem2Reg: Replaced load " << loadInst->name() << " with SSA value." << std::endl;
break;
}
}
}
// 处理 StoreInst
else if (auto storeInst = dynamic_cast<StoreInst *>(inst)) {
// 检查这个 StoreInst 是否是为某个可提升的 alloca
for (auto alloca : promotableAllocas) {
if (storeInst->getPointer() == alloca) {
// 假设 storeInst->getPointer() 返回 AllocaInst*
// 将 StoreInst 存储的值作为新的 SSA 值,压入值栈
if(DEBUG){
std::cout << "Mem2Reg: Replacing store to " << storeInst->getPointer()->getName() << " with SSA value." << std::endl;
}
allocaToValueStackMap[alloca].push(storeInst->getValue());
localStackPushed.push(storeInst->getValue()); // 记录以便弹出
instIter = SysYIROptUtils::usedelete(instIter);
instDeleted = true;
// std::cerr << "Mem2Reg: Replaced store to " << storeInst->ptr()->name() << " with SSA value." << std::endl;
break;
}
}
}
if (!instDeleted) {
++instIter; // 如果指令没有被删除,移动到下一个
}
}
// --------------------------------------------------------------------
// 处理后继基本块的 Phi 指令参数
// --------------------------------------------------------------------
for (auto successorBB : currentBB->getSuccessors()) {
if (!successorBB)
continue;
for (auto alloca : promotableAllocas) {
// 如果后继基本块包含为当前 alloca 插入的 Phi 指令
if (allocaToPhiMap[alloca].count(successorBB)) {
auto phiInst = allocaToPhiMap[alloca][successorBB];
// 为 Phi 指令添加来自当前基本块的参数
// 参数值是当前 alloca 值栈顶部的 SSA 值
assert(!allocaToValueStackMap[alloca].empty() && "Value stack empty for alloca when setting phi operand!");
phiInst->addIncoming(allocaToValueStackMap[alloca].top(), currentBB);
}
}
}
// --------------------------------------------------------------------
// 递归访问支配树的子节点
// --------------------------------------------------------------------
const std::set<BasicBlock *> *dominatedBlocks = dt->getDominatorTreeChildren(currentBB);
if(dominatedBlocks){
for (auto dominatedBB : *dominatedBlocks) {
if (dominatedBB) {
if(DEBUG){
std::cout << "Mem2Reg: Recursively renaming variables in dominated block: " << dominatedBB->getName() << std::endl;
}
renameVariables(currentAlloca, dominatedBB);
}
}
}
// --------------------------------------------------------------------
// 退出基本块时,弹出在此块中压入值栈的 SSA 值
// --------------------------------------------------------------------
while (!localStackPushed.empty()) {
Value *val = localStackPushed.top();
localStackPushed.pop();
// 找到是哪个 alloca 对应的栈
for (auto alloca : promotableAllocas) {
if (!allocaToValueStackMap[alloca].empty() && allocaToValueStackMap[alloca].top() == val) {
allocaToValueStackMap[alloca].pop();
break;
}
}
}
}
// 删除所有原始的 AllocaInst、LoadInst 和 StoreInst
void Mem2RegContext::cleanup() {
for (auto alloca : promotableAllocas) {
if (alloca && alloca->getParent()) {
// 删除 alloca 指令本身
SysYIROptUtils::usedelete(alloca);
// std::cerr << "Mem2Reg: Deleted alloca " << alloca->name() << std::endl;
}
}
// LoadInst 和 StoreInst 已经在 renameVariables 阶段被删除了
}
// Mem2Reg 遍的 runOnFunction 方法实现
bool Mem2Reg::runOnFunction(Function *F, AnalysisManager &AM) {
// 记录初始的指令数量,用于判断优化是否发生了改变
size_t initial_inst_count = 0;
for (auto &bb : F->getBasicBlocks()) {
initial_inst_count += bb->getInstructions().size();
}
Mem2RegContext ctx(builder);
ctx.run(F, &AM); // 运行 Mem2Reg 优化
// 运行优化后,再次计算指令数量
size_t final_inst_count = 0;
for (auto &bb : F->getBasicBlocks()) {
final_inst_count += bb->getInstructions().size();
}
// 如果指令数量发生变化(通常是减少,因为 load/store 被删除phi 被添加),说明 IR 被修改了
// TODO不保险后续修改为更精确的判断
// 直接在添加和删除指令时维护changed值
bool changed = (initial_inst_count != final_inst_count);
// 如果 IR 被修改,则使相关的分析结果失效
if (changed) {
// Mem2Reg 会显著改变 IR 结构,特别是数据流和控制流(通过 Phi
// 这会使几乎所有数据流分析和部分控制流分析失效。
// AM.invalidateAnalysis(&DominatorTreeAnalysisPass::ID, F); // 支配树可能间接改变(如果基本块被删除)
// AM.invalidateAnalysis(&LivenessAnalysisPass::ID, F); // 活跃性分析肯定失效
// AM.invalidateAnalysis(&LoopInfoAnalysisPass::ID, F); // 循环信息可能失效
// AM.invalidateAnalysis(&SideEffectInfoAnalysisPass::ID); // 副作用分析可能失效(如果 Alloca/Load/Store
// 被替换为寄存器)
// ... 其他数据流分析,如到达定义、可用表达式等,也应失效
}
return changed;
}
// 声明Mem2Reg遍的分析依赖和失效信息
void Mem2Reg::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
// Mem2Reg 强烈依赖于支配树分析来插入 Phi 指令
analysisDependencies.insert(&DominatorTreeAnalysisPass::ID); // 假设 DominatorTreeAnalysisPass 的 ID
// Mem2Reg 会删除 Alloca/Load/Store 指令,插入 Phi 指令,这会大幅改变 IR 结构。
// 因此,它会使许多分析结果失效。
analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID); // 支配树可能受影响
analysisInvalidations.insert(&LivenessAnalysisPass::ID); // 活跃性分析肯定失效
// analysisInvalidations.insert(&LoopInfoAnalysisPass::ID); // 循环信息可能失效
// analysisInvalidations.insert(&SideEffectInfoAnalysisPass::ID); // 副作用分析可能失效
// 其他所有依赖于数据流或 IR 结构的分析都可能失效。
}
} // namespace sysy

View File

@ -0,0 +1,288 @@
#include "Reg2Mem.h"
#include "SysYIROptUtils.h"
#include "SysYIRPrinter.h"
extern int DEBUG; // 全局调试标志
namespace sysy {
void *Reg2Mem::ID = (void *)&Reg2Mem::ID;
void Reg2MemContext::run(Function *func) {
if (func->getBasicBlocks().empty()) {
return;
}
// 清空状态,确保每次运行都是新的
valueToAllocaMap.clear();
// 阶段1: 识别并为 SSA Value 分配 AllocaInst
allocateMemoryForSSAValues(func);
// 阶段2: 将 Phi 指令转换为 Load/Store 逻辑 (此阶段需要先于通用 Load/Store 插入)
// 这样做是因为 Phi 指令的特殊性,它需要在前驱块的末尾插入 Store
// 如果先处理通用 Load/Store可能无法正确处理 Phi 的复杂性
rewritePhis(func); // Phi 指令可能在 rewritePhis 中被删除或标记删除
// 阶段3: 将其他 SSA Value 的使用替换为 Load/Store
insertLoadsAndStores(func);
// 阶段4: 清理(删除不再需要的 Phi 指令)
cleanup(func);
}
bool Reg2MemContext::isPromotableToMemory(Value *val) {
// 参数和指令结果是 SSA 值
if(DEBUG){
// if(val->getName() == ""){
// assert(false && "Value name should not be empty in Reg2MemContext::isPromotableToMemory");
// }
// std::cout << "Checking if value is promotable to memory: " << val->getName() << std::endl;
}
// if (dynamic_cast<Argument *>(val) || dynamic_cast<Instruction *>(val)) {
// // 如果值已经是指针类型,则通常不为其分配额外的内存,因为它已经是一个地址。
// // (除非我们想将其值也存储起来,这通常不用于 Reg2Mem
// // // Reg2Mem 关注的是将非指针值从寄存器语义转换为内存语义。
// if (val->getType()->isPointer()) {
// return false;
// }
// return true;
// }
// 1. 如果是 Argument则可以提升到内存
if (dynamic_cast<Argument *>(val)) {
// 参数类型i32, i32* 等)都可以为其分配内存
// 因为它们在 Mem2Reg 逆操作中,被认为是从寄存器分配到内存
return true;
}
if (dynamic_cast<PhiInst *>(val)) {
// Phi 指令的结果也是一个 SSA 值,需要将其转换为 Load/Store
return true;
}
return false;
}
void Reg2MemContext::allocateMemoryForSSAValues(Function *func) {
// AllocaInst 必须在函数的入口基本块中
BasicBlock *entryBlock = func->getEntryBlock();
if (!entryBlock) {
return; // 函数可能没有入口块 (例如声明)
}
// 1. 为函数参数分配内存
builder->setPosition(entryBlock, entryBlock->begin()); // 确保在入口块的开始位置插入
for (auto arg : func->getArguments()) {
// 默认情况下,将所有参数是提升到内存
if (isPromotableToMemory(arg)) {
// 参数的类型就是 AllocaInst 需要分配的类型
AllocaInst *alloca = builder->createAllocaInst(Type::getPointerType(arg->getType()), arg->getName() + ".reg2mem");
// 将参数值 store 到 alloca 中 (这是 Mem2Reg 逆转的关键一步)
valueToAllocaMap[arg] = alloca;
// 确保 alloca 位于入口块的顶部,但在所有参数的 store 指令之前
// 通常 alloca 都在 entry block 的最开始
// 这里我们只是创建,并让 builder 决定插入位置 (通常在当前插入点)
// 如果需要严格控制顺序,可能需要手动 insert 到 instruction list
}
}
// 2. 为指令结果分配内存
// 遍历所有基本块和指令,找出所有需要分配 Alloca 的指令结果
for (auto &bb : func->getBasicBlocks()) {
for (auto &inst : bb->getInstructions_Range()) {
// SysYPrinter::printInst(inst.get());
// 只有有结果的指令才可能需要分配内存
// (例如 BinaryInst, CallInst, LoadInst, PhiInst 等)
// StoreInst, BranchInst, ReturnInst 等没有结果的指令不需要
if (dynamic_cast<AllocaInst*>(inst.get()) || inst.get()->getType()->isVoid()) {
continue;
}
if (isPromotableToMemory(inst.get())) {
// 为指令的结果分配内存
// AllocaInst 应该在入口块,而不是当前指令所在块
// 这里我们只是创建,并稍后调整其位置
// 通常的做法是在循环结束后统一将 alloca 放到 entryBlock 的顶部
AllocaInst *alloca = builder->createAllocaInst(Type::getPointerType(inst.get()->getType()), inst.get()->getName() + ".reg2mem");
valueToAllocaMap[inst.get()] = alloca;
}
}
}
Instruction *firstNonAlloca = nullptr;
for (auto instIter = entryBlock->getInstructions().begin(); instIter != entryBlock->getInstructions().end(); instIter++) {
if (!dynamic_cast<AllocaInst*>(instIter->get())) {
firstNonAlloca = instIter->get();
break;
}
}
if (firstNonAlloca) {
builder->setPosition(entryBlock, entryBlock->findInstIterator(firstNonAlloca));
} else { // 如果 entryBlock 只有 AllocaInst 或为空,则设置到 terminator 前
builder->setPosition(entryBlock, entryBlock->terminator());
}
// 插入所有参数的初始 Store 指令
for (auto arg : func->getArguments()) {
if (valueToAllocaMap.count(arg)) { // 检查是否为其分配了 alloca
builder->createStoreInst(arg, valueToAllocaMap[arg]);
}
}
builder->setPosition(entryBlock, entryBlock->terminator());
}
void Reg2MemContext::rewritePhis(Function *func) {
std::vector<PhiInst *> phisToErase; // 收集要删除的 Phi
// 遍历所有基本块和其中的指令,查找 Phi 指令
for (auto &bb : func->getBasicBlocks()) {
// auto insts = bb->getInstructions(); // 复制一份,因为要修改
for (auto instIter = bb->getInstructions().begin(); instIter != bb->getInstructions().end(); instIter++) {
Instruction *inst = instIter->get();
if (auto phiInst = dynamic_cast<PhiInst *>(inst)) {
// 检查 Phi 指令是否是需要处理的 SSA 值
if (valueToAllocaMap.count(phiInst)) {
AllocaInst *alloca = valueToAllocaMap[phiInst];
// 1. 为 Phi 指令的每个入边,在前驱块的末尾插入 Store 指令
// PhiInst 假设有 getIncomingValues() 和 getIncomingBlocks()
for (unsigned i = 0; i < phiInst->getNumIncomingValues(); ++i) { // 假设 PhiInst 是通过操作数来管理入边的
Value *incomingValue = phiInst->getValue(i); // 获取入值
BasicBlock *incomingBlock = phiInst->getBlock(i); // 获取对应的入块
// 在入块的跳转指令之前插入 StoreInst
// 需要找到 incomingBlock 的终结指令 (Terminator Instruction)
// 并将 StoreInst 插入到它前面
if (incomingBlock->terminator()->get()->isTerminator()) {
builder->setPosition(incomingBlock, incomingBlock->terminator());
} else {
// 如果没有终结指令,插入到末尾
builder->setPosition(incomingBlock, incomingBlock->end());
}
builder->createStoreInst(incomingValue, alloca);
}
// 2. 在当前 Phi 所在基本块的开头,插入 Load 指令
// 将 Load 指令插入到 Phi 指令之后,因为 Phi 指令即将被删除
builder->setPosition(bb.get(), bb.get()->findInstIterator(phiInst));
LoadInst *newLoad = builder->createLoadInst(alloca);
// 3. 将 Phi 指令的所有用途替换为新的 Load 指令
phiInst->replaceAllUsesWith(newLoad);
// 标记 Phi 指令待删除
phisToErase.push_back(phiInst);
}
}
}
}
// 实际删除 Phi 指令
for (auto phi : phisToErase) {
if (phi && phi->getParent()) {
SysYIROptUtils::usedelete(phi);
}
}
}
void Reg2MemContext::insertLoadsAndStores(Function *func) {
// 收集所有需要替换的 uses避免在迭代时修改 use 链表
std::vector<std::pair<Use *, LoadInst *>> usesToReplace;
std::vector<Instruction *> instsToStore; // 收集需要插入 Store 的指令
// 遍历所有基本块和指令
for (auto &bb : func->getBasicBlocks()) {
for (auto instIter = bb->getInstructions().begin(); instIter != bb->getInstructions().end(); instIter++) {
Instruction *inst = instIter->get();
// 如果指令有结果且我们为其分配了 alloca (Phi 已在 rewritePhis 处理)
// 并且其类型不是 void
if (!inst->getType()->isVoid() && valueToAllocaMap.count(inst)) {
// 在指令之后插入 Store 指令
// StoreInst 应该插入到当前指令之后
builder->setPosition(bb.get(), bb.get()->findInstIterator(inst));
builder->createStoreInst(inst, valueToAllocaMap[inst]);
}
// 处理指令的操作数:如果操作数是一个 SSA 值,且为其分配了 alloca
// (并且这个操作数不是 Phi Inst 的 incoming value因为 Phi 的 incoming value 已经在 rewritePhis 中处理了)
// 注意Phi Inst 的操作数是特殊的,它们表示来自不同前驱块的值。
// 这里的处理主要是针对非 Phi 指令的操作数。
for (auto use = inst->getUses().begin(); use != inst->getUses().end(); ++use) {
// 如果当前 use 的 Value 是一个 Instruction 或 Argument
Value *operand = use->get()->getValue();
if (isPromotableToMemory(operand) && valueToAllocaMap.count(operand)) {
// 确保这个 operand 不是一个即将被删除的 Phi 指令
// (在 rewritePhis 阶段Phi 已经被处理并可能被标记删除)
// 或者检查 use 的 user 不是 PhiInst
if (dynamic_cast<PhiInst *>(inst)) {
continue; // Phi 的操作数已在 rewritePhis 中处理
}
AllocaInst *alloca = valueToAllocaMap[operand];
// 在使用点之前插入 Load 指令
// LoadInst 应该插入到使用它的指令之前
builder->setPosition(bb.get(), bb.get()->findInstIterator(inst));
LoadInst *newLoad = builder->createLoadInst(alloca);
// 记录要替换的 use
usesToReplace.push_back({use->get(), newLoad});
}
}
}
}
// 执行所有替换操作
for (auto &pair : usesToReplace) {
pair.first->setValue(pair.second); // 替换 use 的 Value
}
}
void Reg2MemContext::cleanup(Function *func) {
// 此时,所有原始的 Phi 指令应该已经被删除。
// 如果有其他需要删除的临时指令,可以在这里处理。
// 通常Reg2Mem 的清理比 Mem2Reg 简单,因为主要是在插入指令。
// 这里可以作为一个占位符,以防未来有其他清理需求。
}
bool Reg2Mem::runOnFunction(Function *F, AnalysisManager &AM) {
// 记录初始指令数量
size_t initial_inst_count = 0;
for (auto &bb : F->getBasicBlocks()) {
initial_inst_count += bb->getInstructions().size();
}
Reg2MemContext ctx(builder); // 假设 builder 是一个全局或可访问的 IRBuilder 实例
ctx.run(F);
// 记录最终指令数量
size_t final_inst_count = 0;
for (auto &bb : F->getBasicBlocks()) {
final_inst_count += bb->getInstructions().size();
}
// TODO: 添加更精确的变化检测逻辑例如在run函数中维护changed状态
bool changed = (initial_inst_count != final_inst_count); // 粗略判断是否改变
if (changed) {
// Reg2Mem 会显著改变 IR 结构,特别是数据流。
// 它会插入大量的 Load/Store 指令,改变 Value 的来源。
// 这会使几乎所有数据流分析失效。
// 例如:
// AM.invalidateAnalysis(&DominatorTreeAnalysisPass::ID, F); // 如果基本块结构改变,可能失效
// AM.invalidateAnalysis(&LivenessAnalysisPass::ID, F); // 活跃性分析肯定失效
// AM.invalidateAnalysis(&DCEPass::ID, F); // 可能产生新的死代码
// ... 其他所有数据流分析
}
return changed;
}
void Reg2Mem::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
// Reg2Mem 通常不需要特定的分析作为依赖,因为它主要是一个转换。
// 但它会使许多分析失效。
analysisInvalidations.insert(&LivenessAnalysisPass::ID); // 例如
analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID);
}
} // namespace sysy

View File

@ -0,0 +1,880 @@
#include "SCCP.h"
#include "Dom.h"
#include "Liveness.h"
#include <algorithm>
#include <cassert>
#include <cmath> // For std::fmod, std::fabs
#include <limits> // For std::numeric_limits
namespace sysy {
// Pass ID for SCCP
void *SCCP::ID = (void *)&SCCP::ID;
// SCCPContext methods
SSAPValue SCCPContext::Meet(const SSAPValue &a, const SSAPValue &b) {
if (a.state == LatticeVal::Bottom || b.state == LatticeVal::Bottom) {
return SSAPValue(LatticeVal::Bottom);
}
if (a.state == LatticeVal::Top) {
return b;
}
if (b.state == LatticeVal::Top) {
return a;
}
// Both are constants
if (a.constant_type != b.constant_type) {
return SSAPValue(LatticeVal::Bottom); // 不同类型的常量,结果为 Bottom
}
if (a.constantVal == b.constantVal) {
return a; // 相同常量
}
return SSAPValue(LatticeVal::Bottom); // 相同类型但值不同,结果为 Bottom
}
SSAPValue SCCPContext::GetValueState(Value *v) {
if (auto constVal = dynamic_cast<ConstantValue *>(v)) {
// 特殊处理 UndefinedValue将其视为 Bottom
if (dynamic_cast<UndefinedValue *>(constVal)) {
return SSAPValue(LatticeVal::Bottom);
}
// 处理常规的 ConstantInteger 和 ConstantFloating
if (constVal->getType()->isInt()) {
return SSAPValue(constVal->getInt());
} else if (constVal->getType()->isFloat()) {
return SSAPValue(constVal->getFloat());
} else {
// 对于其他 ConstantValue 类型例如ConstantArray 等),
// 如果它们的具体值不能用于标量常量传播,则保守地视为 Bottom。
return SSAPValue(LatticeVal::Bottom);
}
}
if (valueState.count(v)) {
return valueState[v];
}
return SSAPValue(); // 默认初始化为 Top
}
void SCCPContext::UpdateState(Value *v, SSAPValue newState) {
SSAPValue oldState = GetValueState(v);
if (newState != oldState) {
if (DEBUG) {
std::cout << "Updating state for " << v->getName() << " from (";
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";
std::cout << ") to (";
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;
}
valueState[v] = newState;
// 如果状态发生变化,将所有使用者添加到指令工作列表
for (auto &use_ptr : v->getUses()) {
if (auto userInst = dynamic_cast<Instruction *>(use_ptr->getUser())) {
instWorkList.push(userInst);
}
}
}
}
void SCCPContext::AddEdgeToWorkList(BasicBlock *fromBB, BasicBlock *toBB) {
// 检查边是否已经访问过,防止重复处理
if (visitedCFGEdges.count({fromBB, toBB})) {
return;
}
visitedCFGEdges.insert({fromBB, toBB});
if (DEBUG) {
std::cout << "Adding edge to worklist: " << fromBB->getName() << " -> " << toBB->getName() << std::endl;
}
edgeWorkList.push({fromBB, toBB});
}
void SCCPContext::MarkBlockExecutable(BasicBlock *block) {
if (executableBlocks.insert(block).second) { // insert 返回 pairsecond 为 true 表示插入成功
if (DEBUG) {
std::cout << "Marking block " << block->getName() << " as executable." << std::endl;
}
// 将新可执行块中的所有指令添加到指令工作列表
for (auto &inst_ptr : block->getInstructions()) {
instWorkList.push(inst_ptr.get());
}
}
}
// 辅助函数:对二元操作进行常量折叠
SSAPValue SCCPContext::ComputeConstant(BinaryInst *binaryInst, SSAPValue lhsVal, SSAPValue rhsVal) {
// 确保操作数是常量
if (lhsVal.state != LatticeVal::Constant || rhsVal.state != LatticeVal::Constant) {
return SSAPValue(LatticeVal::Bottom); // 如果不是常量,则不能折叠
}
// 处理整数运算 (kAdd, kSub, kMul, kDiv, kRem, kICmp*, kAnd, kOr)
if (lhsVal.constant_type == ValueType::Integer && rhsVal.constant_type == ValueType::Integer) {
int lhs = std::get<int>(lhsVal.constantVal);
int rhs = std::get<int>(rhsVal.constantVal);
int result = 0;
switch (binaryInst->getKind()) {
case Instruction::kAdd:
result = lhs + rhs;
break;
case Instruction::kSub:
result = lhs - rhs;
break;
case Instruction::kMul:
result = lhs * rhs;
break;
case Instruction::kDiv:
if (rhs == 0)
return SSAPValue(LatticeVal::Bottom); // 除零
result = lhs / rhs;
break;
case Instruction::kRem:
if (rhs == 0)
return SSAPValue(LatticeVal::Bottom); // 模零
result = lhs % rhs;
break;
case Instruction::kICmpEQ:
result = (lhs == rhs);
break;
case Instruction::kICmpNE:
result = (lhs != rhs);
break;
case Instruction::kICmpLT:
result = (lhs < rhs);
break;
case Instruction::kICmpGT:
result = (lhs > rhs);
break;
case Instruction::kICmpLE:
result = (lhs <= rhs);
break;
case Instruction::kICmpGE:
result = (lhs >= rhs);
break;
case Instruction::kAnd:
result = (lhs && rhs);
break;
case Instruction::kOr:
result = (lhs || rhs);
break;
default:
return SSAPValue(LatticeVal::Bottom); // 未知或不匹配的二元操作
}
return SSAPValue(result);
}
// 处理浮点运算 (kFAdd, kFSub, kFMul, kFDiv, kFCmp*)
else if (lhsVal.constant_type == ValueType::Float && rhsVal.constant_type == ValueType::Float) {
float lhs = std::get<float>(lhsVal.constantVal);
float rhs = std::get<float>(rhsVal.constantVal);
float f_result = 0.0f;
int i_result = 0; // For comparison results
switch (binaryInst->getKind()) {
case Instruction::kFAdd:
f_result = lhs + rhs;
break;
case Instruction::kFSub:
f_result = lhs - rhs;
break;
case Instruction::kFMul:
f_result = lhs * rhs;
break;
case Instruction::kFDiv:
if (rhs == 0.0f)
return SSAPValue(LatticeVal::Bottom); // 除零
f_result = lhs / rhs;
break;
// kRem 不支持浮点数,但如果你的 IR 定义了浮点模运算,需要使用 std::fmod
case Instruction::kFCmpEQ:
i_result = (lhs == rhs);
return SSAPValue(i_result);
case Instruction::kFCmpNE:
i_result = (lhs != rhs);
return SSAPValue(i_result);
case Instruction::kFCmpLT:
i_result = (lhs < rhs);
return SSAPValue(i_result);
case Instruction::kFCmpGT:
i_result = (lhs > rhs);
return SSAPValue(i_result);
case Instruction::kFCmpLE:
i_result = (lhs <= rhs);
return SSAPValue(i_result);
case Instruction::kFCmpGE:
i_result = (lhs >= rhs);
return SSAPValue(i_result);
default:
return SSAPValue(LatticeVal::Bottom); // 未知或不匹配的浮点二元操作
}
return SSAPValue(f_result);
}
return SSAPValue(LatticeVal::Bottom); // 类型不匹配或不支持的类型组合
}
// 辅助函数:对一元操作进行常量折叠
SSAPValue SCCPContext::ComputeConstant(UnaryInst *unaryInst, SSAPValue operandVal) {
if (operandVal.state != LatticeVal::Constant) {
return SSAPValue(LatticeVal::Bottom);
}
if (operandVal.constant_type == ValueType::Integer) {
int val = std::get<int>(operandVal.constantVal);
switch (unaryInst->getKind()) {
case Instruction::kAdd:
return SSAPValue(val);
case Instruction::kNeg:
return SSAPValue(-val);
case Instruction::kNot:
return SSAPValue(!val);
default:
return SSAPValue(LatticeVal::Bottom);
}
} else if (operandVal.constant_type == ValueType::Float) {
float val = std::get<float>(operandVal.constantVal);
switch (unaryInst->getKind()) {
case Instruction::kAdd:
return SSAPValue(val);
case Instruction::kFNeg:
return SSAPValue(-val);
case Instruction::kFNot:
return SSAPValue(static_cast<int>(val == 0.0f)); // 浮点数非0.0f 为真,其他为假
default:
return SSAPValue(LatticeVal::Bottom);
}
}
return SSAPValue(LatticeVal::Bottom);
}
// 辅助函数:处理单条指令
void SCCPContext::ProcessInstruction(Instruction *inst) {
SSAPValue oldState = GetValueState(inst);
SSAPValue newState;
if (!executableBlocks.count(inst->getParent())) {
// 如果指令所在的块不可执行,其值应保持 Top
// 除非它之前已经是 Bottom因为 Bottom 是单调的
if (oldState.state != LatticeVal::Bottom) {
newState = SSAPValue(); // Top
} else {
newState = oldState; // 保持 Bottom
}
UpdateState(inst, newState);
return; // 不处理不可达块中的指令的实际值
}
switch (inst->getKind()) {
case Instruction::kAdd:
case Instruction::kSub:
case Instruction::kMul:
case Instruction::kDiv:
case Instruction::kRem:
case Instruction::kICmpEQ:
case Instruction::kICmpNE:
case Instruction::kICmpLT:
case Instruction::kICmpGT:
case Instruction::kICmpLE:
case Instruction::kICmpGE:
case Instruction::kFAdd:
case Instruction::kFSub:
case Instruction::kFMul:
case Instruction::kFDiv:
case Instruction::kFCmpEQ:
case Instruction::kFCmpNE:
case Instruction::kFCmpLT:
case Instruction::kFCmpGT:
case Instruction::kFCmpLE:
case Instruction::kFCmpGE:
case Instruction::kAnd:
case Instruction::kOr: {
BinaryInst *binaryInst = static_cast<BinaryInst *>(inst);
SSAPValue lhs = GetValueState(binaryInst->getOperand(0));
SSAPValue rhs = GetValueState(binaryInst->getOperand(1));
// 如果任一操作数是 Bottom结果就是 Bottom
if (lhs.state == LatticeVal::Bottom || rhs.state == LatticeVal::Bottom) {
newState = SSAPValue(LatticeVal::Bottom);
} else if (lhs.state == LatticeVal::Top || rhs.state == LatticeVal::Top) {
newState = SSAPValue(); // Top
} else { // 都是常量
newState = ComputeConstant(binaryInst, lhs, rhs);
}
break;
}
case Instruction::kNeg:
case Instruction::kNot:
case Instruction::kFNeg:
case Instruction::kFNot: {
UnaryInst *unaryInst = static_cast<UnaryInst *>(inst);
SSAPValue operand = GetValueState(unaryInst->getOperand());
if (operand.state == LatticeVal::Bottom) {
newState = SSAPValue(LatticeVal::Bottom);
} else if (operand.state == LatticeVal::Top) {
newState = SSAPValue(); // Top
} else { // 是常量
newState = ComputeConstant(unaryInst, operand);
}
break;
}
// 直接处理类型转换指令
case Instruction::kFtoI: {
SSAPValue operand = GetValueState(inst->getOperand(0));
if (operand.state == LatticeVal::Constant && operand.constant_type == ValueType::Float) {
newState = SSAPValue(static_cast<int>(std::get<float>(operand.constantVal)));
} else if (operand.state == LatticeVal::Bottom) {
newState = SSAPValue(LatticeVal::Bottom);
} else { // Top
newState = SSAPValue();
}
break;
}
case Instruction::kItoF: {
SSAPValue operand = GetValueState(inst->getOperand(0));
if (operand.state == LatticeVal::Constant && operand.constant_type == ValueType::Integer) {
newState = SSAPValue(static_cast<float>(std::get<int>(operand.constantVal)));
} else if (operand.state == LatticeVal::Bottom) {
newState = SSAPValue(LatticeVal::Bottom);
} else { // Top
newState = SSAPValue();
}
break;
}
case Instruction::kBitFtoI: {
SSAPValue operand = GetValueState(inst->getOperand(0));
if (operand.state == LatticeVal::Constant && operand.constant_type == ValueType::Float) {
float fval = std::get<float>(operand.constantVal);
newState = SSAPValue(*reinterpret_cast<int *>(&fval));
} else if (operand.state == LatticeVal::Bottom) {
newState = SSAPValue(LatticeVal::Bottom);
} else { // Top
newState = SSAPValue();
}
break;
}
case Instruction::kBitItoF: {
SSAPValue operand = GetValueState(inst->getOperand(0));
if (operand.state == LatticeVal::Constant && operand.constant_type == ValueType::Integer) {
int ival = std::get<int>(operand.constantVal);
newState = SSAPValue(*reinterpret_cast<float *>(&ival));
} else if (operand.state == LatticeVal::Bottom) {
newState = SSAPValue(LatticeVal::Bottom);
} else { // Top
newState = SSAPValue();
}
break;
}
case Instruction::kLoad: {
// 对于 Load 指令,除非我们有特殊的别名分析,否则假定为 Bottom
// 或者如果它加载的是一个已知常量地址的全局常量
Value *ptr = inst->getOperand(0);
if (auto globalVal = dynamic_cast<GlobalValue *>(ptr)) {
// 如果 GlobalValue 有初始化器,并且它是常量,我们可以传播
// 这需要额外的逻辑来检查 globalVal 的初始化器
// 暂时保守地设置为 Bottom
newState = SSAPValue(LatticeVal::Bottom);
} else {
newState = SSAPValue(LatticeVal::Bottom);
}
break;
}
case Instruction::kStore:
// Store 指令不产生值,其 SSAPValue 不重要
newState = SSAPValue(); // 保持 Top
break;
case Instruction::kCall:
// 大多数 Call 指令都假定为 Bottom除非是纯函数且所有参数都是常量
newState = SSAPValue(LatticeVal::Bottom);
break;
case Instruction::kGetElementPtr: {
// GEP 指令计算地址,通常其结果值(地址指向的内容)是 Bottom
// 除非所有索引和基指针都是常量,指向一个确定常量值的内存位置
bool all_ops_constant = true;
for (unsigned i = 0; i < inst->getNumOperands(); ++i) {
if (GetValueState(inst->getOperand(i)).state != LatticeVal::Constant) {
all_ops_constant = false;
break;
}
}
// 即使地址是常量,地址处的内容通常不是。所以通常是 Bottom
newState = SSAPValue(LatticeVal::Bottom);
break;
}
case Instruction::kPhi: {
PhiInst *phi = static_cast<PhiInst *>(inst);
SSAPValue phiResult = SSAPValue(); // 初始为 Top
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则提前退出
}
}
newState = phiResult;
break;
}
case Instruction::kAlloca: // 对应 kAlloca
// Alloca 分配内存,返回一个指针,其内容是 Bottom
newState = SSAPValue(LatticeVal::Bottom);
break;
case Instruction::kBr: // 对应 kBr
case Instruction::kCondBr: // 对应 kCondBr
case Instruction::kReturn: // 对应 kReturn
case Instruction::kUnreachable: // 对应 kUnreachable
// 终结符指令不产生值
newState = SSAPValue(); // 保持 Top
break;
case Instruction::kMemset:
// Memset 不产生值,但有副作用,不进行常量传播
newState = SSAPValue(LatticeVal::Bottom);
break;
default:
if (DEBUG) {
std::cout << "Unimplemented instruction kind in SCCP: " << inst->getKind() << std::endl;
}
newState = SSAPValue(LatticeVal::Bottom); // 未知指令保守处理为 Bottom
break;
}
UpdateState(inst, newState);
// 特殊处理终结符指令,影响 CFG 边的可达性
if (inst->isTerminator()) {
if (inst->isBranch()) {
if (inst->isCondBr()) { // 使用 kCondBr
CondBrInst *branchInst = static_cast<CondBrInst *>(inst);
SSAPValue condVal = GetValueState(branchInst->getOperand(0));
if (condVal.state == LatticeVal::Constant) {
bool condition_is_true = false;
if (condVal.constant_type == ValueType::Integer) {
condition_is_true = (std::get<int>(condVal.constantVal) != 0);
} else if (condVal.constant_type == ValueType::Float) {
condition_is_true = (std::get<float>(condVal.constantVal) != 0.0f);
}
if (condition_is_true) {
AddEdgeToWorkList(branchInst->getParent(), branchInst->getThenBlock());
} else {
AddEdgeToWorkList(branchInst->getParent(), branchInst->getElseBlock());
}
} else { // 条件是 Top 或 Bottom两条路径都可能
AddEdgeToWorkList(branchInst->getParent(), branchInst->getThenBlock());
AddEdgeToWorkList(branchInst->getParent(), branchInst->getElseBlock());
}
} else { // 无条件分支 (kBr)
UncondBrInst *branchInst = static_cast<UncondBrInst *>(inst);
AddEdgeToWorkList(branchInst->getParent(), branchInst->getBlock());
}
}
}
}
// 辅助函数:处理单条控制流边
void SCCPContext::ProcessEdge(const std::pair<BasicBlock *, BasicBlock *> &edge) {
BasicBlock *fromBB = edge.first;
BasicBlock *toBB = edge.second;
MarkBlockExecutable(toBB);
// 对于目标块中的所有 Phi 指令,重新评估其值,因为可能有新的前驱被激活
for (auto &inst_ptr : toBB->getInstructions()) {
if (dynamic_cast<PhiInst *>(inst_ptr.get())) {
instWorkList.push(inst_ptr.get());
}
}
}
// 阶段1: 常量传播与折叠
bool SCCPContext::PropagateConstants(Function *func) {
bool changed = false;
// 初始化:所有值 Top所有块不可执行
for (auto &bb_ptr : func->getBasicBlocks()) {
executableBlocks.erase(bb_ptr.get());
for (auto &inst_ptr : bb_ptr->getInstructions()) {
valueState[inst_ptr.get()] = SSAPValue(); // Top
}
}
// 标记入口块为可执行
if (!func->getBasicBlocks().empty()) {
MarkBlockExecutable(func->getEntryBlock());
}
// 主循环:处理工作列表直到不动点
while (!instWorkList.empty() || !edgeWorkList.empty()) {
while (!edgeWorkList.empty()) {
ProcessEdge(edgeWorkList.front());
edgeWorkList.pop();
}
while (!instWorkList.empty()) {
Instruction *inst = instWorkList.front();
instWorkList.pop();
ProcessInstruction(inst);
}
}
// 应用常量替换和死代码消除
std::vector<Instruction *> instsToDelete;
for (auto &bb_ptr : func->getBasicBlocks()) {
BasicBlock *bb = bb_ptr.get();
if (!executableBlocks.count(bb)) {
// 整个块是死块,标记所有指令删除
for (auto &inst_ptr : bb->getInstructions()) {
instsToDelete.push_back(inst_ptr.get());
}
changed = true;
continue;
}
for (auto it = bb->begin(); it != bb->end();) {
Instruction *inst = it->get();
SSAPValue ssaPVal = GetValueState(inst);
if (ssaPVal.state == LatticeVal::Constant) {
ConstantValue *constVal = nullptr;
if (ssaPVal.constant_type == ValueType::Integer) {
constVal = ConstantInteger::get(std::get<int>(ssaPVal.constantVal));
} else if (ssaPVal.constant_type == ValueType::Float) {
constVal = ConstantFloating::get(std::get<float>(ssaPVal.constantVal));
} else {
constVal = UndefinedValue::get(inst->getType()); // 不应发生
}
if (DEBUG) {
std::cout << "Replacing " << inst->getName() << " with constant ";
if (ssaPVal.constant_type == ValueType::Integer)
std::cout << std::get<int>(ssaPVal.constantVal);
else
std::cout << std::get<float>(ssaPVal.constantVal);
std::cout << std::endl;
}
inst->replaceAllUsesWith(constVal);
instsToDelete.push_back(inst);
++it;
changed = true;
} else {
// 如果操作数是常量,直接替换为常量值(常量折叠)
for (unsigned i = 0; i < inst->getNumOperands(); ++i) {
Value *operand = inst->getOperand(i);
SSAPValue opVal = GetValueState(operand);
if (opVal.state == LatticeVal::Constant) {
ConstantValue *constOp = nullptr;
if (opVal.constant_type == ValueType::Integer) {
constOp = ConstantInteger::get(std::get<int>(opVal.constantVal));
} else if (opVal.constant_type == ValueType::Float) {
constOp = ConstantFloating::get(std::get<float>(opVal.constantVal));
} else {
constOp = UndefinedValue::get(operand->getType());
}
if (constOp != operand) {
inst->setOperand(i, constOp);
changed = true;
}
}
}
++it;
}
}
}
// 实际删除指令
// TODO: 删除的逻辑需要考虑修改
for (Instruction *inst : instsToDelete) {
// 在尝试删除之前,先检查指令是否仍然附加到其父基本块。
// 如果它已经没有父块,可能说明它已被其他方式处理或已处于无效状态。
if (inst->getParent() != nullptr) {
// 调用负责完整删除的函数该函数应负责清除uses并将其从父块中移除。
SysYIROptUtils::usedelete(inst);
}
else {
// 指令已不属于任何父块,无需再次删除。
if (DEBUG) {
std::cerr << "Info: Instruction " << inst->getName() << " was already detached or is not in a parent block." << std::endl;
}
}
}
return changed;
}
// 阶段2: 控制流简化
bool SCCPContext::SimplifyControlFlow(Function *func) {
bool changed = false;
// 重新确定可达块,因为 PropagateConstants 可能改变了分支条件
std::unordered_set<BasicBlock *> newReachableBlocks = FindReachableBlocks(func);
// 移除不可达块
std::vector<BasicBlock *> blocksToDelete;
for (auto &bb_ptr : func->getBasicBlocks()) {
if (bb_ptr.get() == func->getEntryBlock())
continue; // 入口块不能删除
if (newReachableBlocks.find(bb_ptr.get()) == newReachableBlocks.end()) {
blocksToDelete.push_back(bb_ptr.get());
changed = true;
}
}
for (BasicBlock *bb : blocksToDelete) {
RemoveDeadBlock(bb, func);
}
// 简化分支指令
for (auto &bb_ptr : func->getBasicBlocks()) {
BasicBlock *bb = bb_ptr.get();
if (!newReachableBlocks.count(bb))
continue; // 只处理可达块
Instruction *terminator = bb->terminator()->get();
if (terminator->isBranch()) {
if (terminator->isCondBr()) { // 检查是否是条件分支 (kCondBr)
CondBrInst *branchInst = static_cast<CondBrInst *>(terminator);
SSAPValue condVal = GetValueState(branchInst->getOperand(0));
if (condVal.state == LatticeVal::Constant) {
bool condition_is_true = false;
if (condVal.constant_type == ValueType::Integer) {
condition_is_true = (std::get<int>(condVal.constantVal) != 0);
} else if (condVal.constant_type == ValueType::Float) {
condition_is_true = (std::get<float>(condVal.constantVal) != 0.0f);
}
SimplifyBranch(branchInst, condition_is_true);
changed = true;
}
}
}
}
return changed;
}
// 查找所有可达的基本块 (基于常量条件)
std::unordered_set<BasicBlock *> SCCPContext::FindReachableBlocks(Function *func) {
std::unordered_set<BasicBlock *> reachable;
std::queue<BasicBlock *> q;
if (func->getEntryBlock()) {
q.push(func->getEntryBlock());
reachable.insert(func->getEntryBlock());
}
while (!q.empty()) {
BasicBlock *currentBB = q.front();
q.pop();
Instruction *terminator = currentBB->terminator()->get();
if (!terminator)
continue;
if (terminator->isBranch()) {
if (terminator->isCondBr()) { // 检查是否是条件分支 (kCondBr)
CondBrInst *branchInst = static_cast<CondBrInst *>(terminator);
SSAPValue condVal = GetValueState(branchInst->getOperand(0));
if (condVal.state == LatticeVal::Constant) {
bool condition_is_true = false;
if (condVal.constant_type == ValueType::Integer) {
condition_is_true = (std::get<int>(condVal.constantVal) != 0);
} else if (condVal.constant_type == ValueType::Float) {
condition_is_true = (std::get<float>(condVal.constantVal) != 0.0f);
}
if (condition_is_true) {
BasicBlock *trueBlock = branchInst->getThenBlock();
if (reachable.find(trueBlock) == reachable.end()) {
reachable.insert(trueBlock);
q.push(trueBlock);
}
} else {
BasicBlock *falseBlock = branchInst->getElseBlock();
if (reachable.find(falseBlock) == reachable.end()) {
reachable.insert(falseBlock);
q.push(falseBlock);
}
}
} else { // 条件是 Top 或 Bottom两条路径都可达
for (auto succ : branchInst->getSuccessors()) {
if (reachable.find(succ) == reachable.end()) {
reachable.insert(succ);
q.push(succ);
}
}
}
} else { // 无条件分支 (kBr)
UncondBrInst *branchInst = static_cast<UncondBrInst *>(terminator);
BasicBlock *targetBlock = branchInst->getBlock();
if (reachable.find(targetBlock) == reachable.end()) {
reachable.insert(targetBlock);
q.push(targetBlock);
}
}
} else if (terminator->isReturn() || terminator->isUnreachable()) {
// ReturnInst 没有后继,不需要处理
// UnreachableInst 也没有后继,不需要处理
}
}
return reachable;
}
// 移除死块
void SCCPContext::RemoveDeadBlock(BasicBlock *bb, Function *func) {
if (DEBUG) {
std::cout << "Removing dead block: " << bb->getName() << std::endl;
}
// 首先更新其所有前驱的终结指令,移除指向死块的边
std::vector<BasicBlock *> preds_to_update;
for (auto &pred : bb->getPredecessors()) {
if (pred != nullptr) { // 检查是否为空指针
preds_to_update.push_back(pred);
}
}
for (BasicBlock *pred : preds_to_update) {
if (executableBlocks.count(pred)) {
UpdateTerminator(pred, bb);
}
}
// 移除其后继的 Phi 节点的入边
std::vector<BasicBlock *> succs_to_update;
for (auto succ : bb->getSuccessors()) {
succs_to_update.push_back(succ);
}
for (BasicBlock *succ : succs_to_update) {
RemovePhiIncoming(succ, bb);
succ->removePredecessor(bb);
}
func->removeBasicBlock(bb); // 从函数中移除基本块
}
// 简化分支(将条件分支替换为无条件分支)
void SCCPContext::SimplifyBranch(CondBrInst *brInst, bool condVal) {
BasicBlock *parentBB = brInst->getParent();
BasicBlock *trueBlock = brInst->getThenBlock();
BasicBlock *falseBlock = brInst->getElseBlock();
if (DEBUG) {
std::cout << "Simplifying branch in " << parentBB->getName() << ": cond is " << (condVal ? "true" : "false")
<< std::endl;
}
builder->setPosition(parentBB, parentBB->findInstIterator(brInst));
if (condVal) { // 条件为真,跳转到真分支
builder->createUncondBrInst(trueBlock); // 插入无条件分支 kBr
SysYIROptUtils::usedelete(brInst); // 移除旧的条件分支指令
parentBB->removeSuccessor(falseBlock);
falseBlock->removePredecessor(parentBB);
RemovePhiIncoming(falseBlock, parentBB);
} else { // 条件为假,跳转到假分支
builder->createUncondBrInst(falseBlock); // 插入无条件分支 kBr
SysYIROptUtils::usedelete(brInst); // 移除旧的条件分支指令
parentBB->removeSuccessor(trueBlock);
trueBlock->removePredecessor(parentBB);
RemovePhiIncoming(trueBlock, parentBB);
}
}
// 更新前驱块的终结指令(当一个后继块被移除时)
void SCCPContext::UpdateTerminator(BasicBlock *predBB, BasicBlock *removedSucc) {
Instruction *terminator = predBB->terminator()->get();
if (!terminator)
return;
if (terminator->isBranch()) {
if (terminator->isCondBr()) { // 如果是条件分支
CondBrInst *branchInst = static_cast<CondBrInst *>(terminator);
if (branchInst->getThenBlock() == removedSucc) {
if (DEBUG) {
std::cout << "Updating cond br in " << predBB->getName() << ": True block (" << removedSucc->getName()
<< ") removed. Converting to Br to " << branchInst->getElseBlock()->getName() << std::endl;
}
builder->setPosition(predBB, predBB->findInstIterator(branchInst));
builder->createUncondBrInst(branchInst->getElseBlock());
SysYIROptUtils::usedelete(branchInst);
predBB->removeSuccessor(removedSucc);
} else if (branchInst->getElseBlock() == removedSucc) {
if (DEBUG) {
std::cout << "Updating cond br in " << predBB->getName() << ": False block (" << removedSucc->getName()
<< ") removed. Converting to Br to " << branchInst->getThenBlock()->getName() << std::endl;
}
builder->setPosition(predBB, predBB->findInstIterator(branchInst));
builder->createUncondBrInst(branchInst->getThenBlock());
SysYIROptUtils::usedelete(branchInst);
predBB->removeSuccessor(removedSucc);
}
} else { // 无条件分支 (kBr)
UncondBrInst *branchInst = static_cast<UncondBrInst *>(terminator);
if (branchInst->getBlock() == removedSucc) {
if (DEBUG) {
std::cout << "Updating unconditional br in " << predBB->getName() << ": Target block ("
<< removedSucc->getName() << ") removed. Replacing with Unreachable." << std::endl;
}
SysYIROptUtils::usedelete(branchInst);
predBB->removeSuccessor(removedSucc);
builder->setPosition(predBB, predBB->end());
builder->createUnreachableInst();
}
}
}
}
// 移除 Phi 节点的入边(当其前驱块被移除时)
void SCCPContext::RemovePhiIncoming(BasicBlock *phiParentBB, BasicBlock *removedPred) { // 修正 removedPred 类型
std::vector<Instruction *> insts_to_check;
for (auto &inst_ptr : phiParentBB->getInstructions()) {
insts_to_check.push_back(inst_ptr.get());
}
for (Instruction *inst : insts_to_check) {
if (auto phi = dynamic_cast<PhiInst *>(inst)) {
phi->delBlk(removedPred);
}
}
}
// 运行 SCCP 优化
void SCCPContext::run(Function *func, AnalysisManager &AM) {
bool changed_constant_propagation = PropagateConstants(func);
bool changed_control_flow = SimplifyControlFlow(func);
// 如果任何一个阶段修改了 IR标记分析结果为失效
if (changed_constant_propagation || changed_control_flow) {
// AM.invalidate(); // 假设有这样的方法来使所有分析结果失效
}
}
// SCCP Pass methods
bool SCCP::runOnFunction(Function *F, AnalysisManager &AM) {
if (DEBUG) {
std::cout << "Running SCCP on function: " << F->getName() << std::endl;
}
SCCPContext context(builder);
context.run(F, AM);
return true;
}
void SCCP::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
// analysisInvalidations.insert(nullptr); // 表示使所有默认分析失效
analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID); // 支配树可能受影响
analysisInvalidations.insert(&LivenessAnalysisPass::ID); // 活跃性分析很可能失效
}
} // namespace sysy

View File

@ -91,13 +91,11 @@ bool SysYCFGOptUtils::SysYBlockMerge(Function *func) {
auto thelastinstinst = block->end();
(--thelastinstinst);
if (thelastinstinst->get()->isUnconditional()) {
SysYIROptUtils::usedelete(thelastinstinst->get());
thelastinstinst = block->getInstructions().erase(thelastinstinst);
thelastinstinst = SysYIROptUtils::usedelete(thelastinstinst);
} else if (thelastinstinst->get()->isConditional()) {
// 如果是条件分支,判断条件是否相同,主要优化相同布尔表达式
if (thelastinstinst->get()->getOperand(1)->getName() == thelastinstinst->get()->getOperand(1)->getName()) {
SysYIROptUtils::usedelete(thelastinstinst->get());
thelastinstinst = block->getInstructions().erase(thelastinstinst);
thelastinstinst = SysYIROptUtils::usedelete(thelastinstinst);
}
}
}
@ -164,8 +162,7 @@ bool SysYCFGOptUtils::SysYDelNoPreBLock(Function *func) {
if (!blockIter->get()->getreachable()) {
for (auto instIter = blockIter->get()->getInstructions().begin();
instIter != blockIter->get()->getInstructions().end();) {
SysYIROptUtils::usedelete(instIter->get());
instIter = blockIter->get()->getInstructions().erase(instIter);
instIter = SysYIROptUtils::usedelete(instIter);
}
}
}
@ -306,10 +303,9 @@ bool SysYCFGOptUtils::SysYDelEmptyBlock(Function *func, IRBuilder* pBuilder) {
if (dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)) ==
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) {
auto thebrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
SysYIROptUtils::usedelete(thelastinst->get());
thelastinst = basicBlock->getInstructions().erase(thelastinst);
thelastinst = SysYIROptUtils::usedelete(thelastinst);
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
pBuilder->createUncondBrInst(thebrBlock, {});
pBuilder->createUncondBrInst(thebrBlock);
changed = true; // 标记IR被修改
continue;
}
@ -345,10 +341,9 @@ bool SysYCFGOptUtils::SysYDelEmptyBlock(Function *func, IRBuilder* pBuilder) {
if (dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)) ==
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) {
auto thebrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
SysYIROptUtils::usedelete(thelastinst->get());
thelastinst = basicBlock->getInstructions().erase(thelastinst);
thelastinst = SysYIROptUtils::usedelete(thelastinst);
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
pBuilder->createUncondBrInst(thebrBlock, {});
pBuilder->createUncondBrInst(thebrBlock);
changed = true; // 标记IR被修改
continue;
}
@ -425,9 +420,7 @@ bool SysYCFGOptUtils::SysYDelEmptyBlock(Function *func, IRBuilder* pBuilder) {
for (auto instIter = iter->get()->getInstructions().begin();
instIter != iter->get()->getInstructions().end();) {
SysYIROptUtils::usedelete(instIter->get()); // 仅删除 use 关系
// 显式地从基本块中删除指令并更新迭代器
instIter = iter->get()->getInstructions().erase(instIter);
instIter = SysYIROptUtils::usedelete(instIter);
}
// 删除不可达基本块的phi指令的操作数
for (auto &succ : iter->get()->getSuccessors()) {
@ -523,12 +516,11 @@ bool SysYCFGOptUtils::SysYCondBr2Br(Function *func, IRBuilder* pBuilder) {
auto thenBlock = dynamic_cast<BasicBlock *>(thelast->get()->getOperand(1));
auto elseBlock = dynamic_cast<BasicBlock *>(thelast->get()->getOperand(2));
SysYIROptUtils::usedelete(thelast->get());
thelast = basicblock->getInstructions().erase(thelast);
thelast = SysYIROptUtils::usedelete(thelast);
if ((constfloat_Use && constfloat == 1.0F) || (constint_Use && constint == 1)) {
// cond为true或非0
pBuilder->setPosition(basicblock.get(), basicblock->end());
pBuilder->createUncondBrInst(thenBlock, {});
pBuilder->createUncondBrInst(thenBlock);
// 更新CFG关系
basicblock->removeSuccessor(elseBlock);
@ -546,7 +538,7 @@ bool SysYCFGOptUtils::SysYCondBr2Br(Function *func, IRBuilder* pBuilder) {
} else { // cond为false或0
pBuilder->setPosition(basicblock.get(), basicblock->end());
pBuilder->createUncondBrInst(elseBlock, {});
pBuilder->createUncondBrInst(elseBlock);
// 更新CFG关系
basicblock->removeSuccessor(thenBlock);

View File

@ -3,6 +3,9 @@
#include "SysYIRCFGOpt.h"
#include "SysYIRPrinter.h"
#include "DCE.h"
#include "Mem2Reg.h"
#include "Reg2Mem.h"
#include "SCCP.h"
#include "Pass.h"
#include <iostream>
#include <queue>
@ -44,6 +47,12 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
registerOptimizationPass<SysYCondBr2BrPass>(builderIR);
registerOptimizationPass<SysYAddReturnPass>(builderIR);
registerOptimizationPass<DCE>();
registerOptimizationPass<Mem2Reg>(builderIR);
registerOptimizationPass<Reg2Mem>(builderIR);
registerOptimizationPass<SCCP>(builderIR);
if (optLevel >= 1) {
//经过设计安排优化遍的执行顺序以及执行逻辑
if (DEBUG) std::cout << "Applying -O1 optimizations.\n";
@ -58,10 +67,47 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
this->addPass(&SysYAddReturnPass::ID);
this->run();
if(DEBUG) {
std::cout << "=== IR After CFGOpt Optimizations ===\n";
printPasses();
}
this->clearPasses();
this->addPass(&DCE::ID);
this->run();
if(DEBUG) {
std::cout << "=== IR After DCE Optimizations ===\n";
printPasses();
}
this->clearPasses();
this->addPass(&Mem2Reg::ID);
this->run();
if(DEBUG) {
std::cout << "=== IR After Mem2Reg Optimizations ===\n";
printPasses();
}
this->clearPasses();
this->addPass(&SCCP::ID);
this->run();
if(DEBUG) {
std::cout << "=== IR After SCCP Optimizations ===\n";
printPasses();
}
this->clearPasses();
this->addPass(&Reg2Mem::ID);
this->run();
if(DEBUG) {
std::cout << "=== IR After Reg2Mem Optimizations ===\n";
printPasses();
}
if (DEBUG) std::cout << "--- Custom optimization sequence finished ---\n";
}
@ -152,6 +198,20 @@ bool PassManager::run() {
}
void PassManager::printPasses() const {
std::cout << "Registered Passes:\n";
for (const auto &p : passes) {
std::cout << " - " << p->getName() << " (Granularity: "
<< static_cast<int>(p->getGranularity())
<< ", Kind: " << static_cast<int>(p->getPassKind()) << ")\n";
}
std::cout << "Total Passes: " << passes.size() << "\n";
if (pmodule) {
SysYPrinter printer(pmodule);
std::cout << "Module IR:\n";
printer.printIR();
}
}
template <typename AnalysisPassType> void registerAnalysisPass() {
PassRegistry::getPassRegistry().registerPass(&AnalysisPassType::ID,

View File

@ -94,7 +94,11 @@ std::any SysYIRGenerator::visitGlobalConstDecl(SysYParser::GlobalConstDeclContex
Utils::tree2Array(type, root, dims, dims.size(), values, &builder);
delete root;
// 创建全局常量变量,并更新符号表
module->createConstVar(name, Type::getPointerType(type), values, dims);
Type* variableType = type;
if (!dims.empty()) { // 如果有维度,说明是数组
variableType = buildArrayType(type, dims); // 构建完整的 ArrayType
}
module->createConstVar(name, Type::getPointerType(variableType), values);
}
return std::any();
}
@ -123,13 +127,13 @@ std::any SysYIRGenerator::visitGlobalVarDecl(SysYParser::GlobalVarDeclContext *c
if (!dims.empty()) { // 如果有维度,说明是数组
variableType = buildArrayType(type, dims); // 构建完整的 ArrayType
}
module->createGlobalValue(name, Type::getPointerType(variableType), dims, values);
module->createGlobalValue(name, Type::getPointerType(variableType), values);
}
return std::any();
}
std::any SysYIRGenerator::visitConstDecl(SysYParser::ConstDeclContext *ctx){
Type* type = std::any_cast<Type *>(visitBType(ctx->bType()));
std::any SysYIRGenerator::visitConstDecl(SysYParser::ConstDeclContext *ctx) {
Type *type = std::any_cast<Type *>(visitBType(ctx->bType()));
for (const auto constDef : ctx->constDef()) {
std::vector<Value *> dims = {};
std::string name = constDef->Ident()->getText();
@ -140,14 +144,112 @@ std::any SysYIRGenerator::visitConstDecl(SysYParser::ConstDeclContext *ctx){
}
}
ArrayValueTree* root = std::any_cast<ArrayValueTree *>(constDef->constInitVal()->accept(this));
Type *variableType = type;
if (!dims.empty()) {
variableType = buildArrayType(type, dims); // 构建完整的 ArrayType
}
// 显式地为局部常量在栈上分配空间
// alloca 的类型将是指针指向常量类型,例如 `int*` 或 `int[2][3]*`
AllocaInst *alloca = builder.createAllocaInst(Type::getPointerType(variableType), name);
ArrayValueTree *root = std::any_cast<ArrayValueTree *>(constDef->constInitVal()->accept(this));
ValueCounter values;
Utils::tree2Array(type, root, dims, dims.size(), values, &builder);
delete root;
module->createConstVar(name, Type::getPointerType(type), values, dims);
// 根据维度信息进行 store 初始化
if (dims.empty()) { // 标量常量初始化
// 局部常量必须有初始值,且通常是单个值
if (!values.getValues().empty()) {
builder.createStoreInst(values.getValue(0), alloca);
} else {
// 错误处理:局部标量常量缺少初始化值
// 或者可以考虑默认初始化为0但这通常不符合常量的语义
assert(false && "Local scalar constant must have an initialization value!");
return std::any(); // 直接返回,避免继续执行
}
} else { // 数组常量初始化
const std::vector<sysy::Value *> &counterValues = values.getValues();
const std::vector<unsigned> &counterNumbers = values.getNumbers();
int numElements = 1;
std::vector<int> dimSizes;
for (Value *dimVal : dims) {
if (ConstantInteger *constInt = dynamic_cast<ConstantInteger *>(dimVal)) {
int dimSize = constInt->getInt();
numElements *= dimSize;
dimSizes.push_back(dimSize);
}
// TODO else 错误处理:数组维度必须是常量(对于静态分配)
else {
assert(false && "Array dimension must be a constant integer!");
return std::any(); // 直接返回,避免继续执行
}
}
unsigned int elementSizeInBytes = type->getSize();
unsigned int totalSizeInBytes = numElements * elementSizeInBytes;
// 检查是否所有初始化值都是零
bool allValuesAreZero = false;
if (counterValues.empty()) { // 如果没有提供初始化值,通常视为全零初始化
allValuesAreZero = true;
} else {
allValuesAreZero = true;
for (Value *val : counterValues) {
if (ConstantInteger *constInt = dynamic_cast<ConstantInteger *>(val)) {
if (constInt->getInt() != 0) {
allValuesAreZero = false;
break;
}
} else { // 如果不是常量整数,则不能确定是零
allValuesAreZero = false;
break;
}
}
}
if (allValuesAreZero) {
builder.createMemsetInst(alloca, ConstantInteger::get(0), ConstantInteger::get(totalSizeInBytes),
ConstantInteger::get(0));
} else {
int linearIndexOffset = 0; // 用于追踪当前处理的线性索引的偏移量
for (int k = 0; k < counterValues.size(); ++k) {
// 当前 Value 的值和重复次数
Value *currentValue = counterValues[k];
unsigned currentRepeatNum = counterNumbers[k];
for (unsigned i = 0; i < currentRepeatNum; ++i) {
std::vector<Value *> currentIndices;
int tempLinearIndex = linearIndexOffset + i; // 使用偏移量和当前重复次数内的索引
// 将线性索引转换为多维索引
for (int dimIdx = dimSizes.size() - 1; dimIdx >= 0; --dimIdx) {
currentIndices.insert(currentIndices.begin(),
ConstantInteger::get(static_cast<int>(tempLinearIndex % dimSizes[dimIdx])));
tempLinearIndex /= dimSizes[dimIdx];
}
// 对于局部数组alloca 本身就是 GEP 的基指针。
// GEP 的第一个索引必须是 0用于“步过”整个数组。
std::vector<Value *> gepIndicesForInit;
gepIndicesForInit.push_back(ConstantInteger::get(0));
gepIndicesForInit.insert(gepIndicesForInit.end(), currentIndices.begin(), currentIndices.end());
// 计算元素的地址
Value *elementAddress = getGEPAddressInst(alloca, gepIndicesForInit);
// 生成 store 指令
builder.createStoreInst(currentValue, elementAddress);
}
// 更新线性索引偏移量,以便下一次迭代从正确的位置开始
linearIndexOffset += currentRepeatNum;
}
}
}
// 更新符号表,将常量名称与 AllocaInst 关联起来
module->addVariable(name, alloca);
}
return 0;
return std::any();
}
std::any SysYIRGenerator::visitVarDecl(SysYParser::VarDeclContext *ctx) {
@ -170,7 +272,7 @@ std::any SysYIRGenerator::visitVarDecl(SysYParser::VarDeclContext *ctx) {
// 对于数组alloca 的类型将是指针指向数组类型,例如 `int[2][3]*`
// 对于标量alloca 的类型将是指针指向标量类型,例如 `int*`
AllocaInst* alloca =
builder.createAllocaInst(Type::getPointerType(variableType), {}, name);
builder.createAllocaInst(Type::getPointerType(variableType), name);
if (varDef->initVal() != nullptr) {
ValueCounter values;
@ -408,7 +510,7 @@ std::any SysYIRGenerator::visitFuncDef(SysYParser::FuncDefContext *ctx){
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]);
AllocaInst *alloca = builder.createAllocaInst(Type::getPointerType(paramActualTypes[i]), paramNames[i]);
allocas.push_back(alloca);
module->addVariable(paramNames[i], alloca);
}
@ -423,7 +525,7 @@ std::any SysYIRGenerator::visitFuncDef(SysYParser::FuncDefContext *ctx){
BasicBlock* funcBodyEntry = function->addBasicBlock("funcBodyEntry_" + name);
// 从 entryBB 无条件跳转到 funcBodyEntry
builder.createUncondBrInst(funcBodyEntry, {});
builder.createUncondBrInst(funcBodyEntry);
builder.setPosition(funcBodyEntry,funcBodyEntry->end()); // 将插入点设置到 funcBodyEntry
for (auto item : ctx->blockStmt()->blockItem()) {
@ -518,12 +620,25 @@ std::any SysYIRGenerator::visitAssignStmt(SysYParser::AssignStmtContext *ctx) {
Type* RType = RValue->getType();
if (LType != RType) {
ConstantValue * constValue = dynamic_cast<ConstantValue *>(RValue);
ConstantValue *constValue = dynamic_cast<ConstantValue *>(RValue);
if (constValue != nullptr) {
if (LType == Type::getFloatType()) {
RValue = ConstantFloating::get(static_cast<float>(constValue->getFloat()));
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()) {
@ -575,7 +690,7 @@ std::any SysYIRGenerator::visitIfStmt(SysYParser::IfStmtContext *ctx) {
ctx->stmt(0)->accept(this);
module->leaveScope();
}
builder.createUncondBrInst(exitBlock, {});
builder.createUncondBrInst(exitBlock);
BasicBlock::conectBlocks(builder.getBasicBlock(), exitBlock);
labelstring << "if_else.L" << builder.getLabelIndex();
@ -592,7 +707,7 @@ std::any SysYIRGenerator::visitIfStmt(SysYParser::IfStmtContext *ctx) {
ctx->stmt(1)->accept(this);
module->leaveScope();
}
builder.createUncondBrInst(exitBlock, {});
builder.createUncondBrInst(exitBlock);
BasicBlock::conectBlocks(builder.getBasicBlock(), exitBlock);
labelstring << "if_exit.L" << builder.getLabelIndex();
@ -622,7 +737,7 @@ std::any SysYIRGenerator::visitIfStmt(SysYParser::IfStmtContext *ctx) {
ctx->stmt(0)->accept(this);
module->leaveScope();
}
builder.createUncondBrInst(exitBlock, {});
builder.createUncondBrInst(exitBlock);
BasicBlock::conectBlocks(builder.getBasicBlock(), exitBlock);
labelstring << "if_exit.L" << builder.getLabelIndex();
@ -644,7 +759,7 @@ std::any SysYIRGenerator::visitWhileStmt(SysYParser::WhileStmtContext *ctx) {
labelstring << "while_head.L" << builder.getLabelIndex();
BasicBlock *headBlock = function->addBasicBlock(labelstring.str());
labelstring.str("");
builder.createUncondBrInst(headBlock, {});
builder.createUncondBrInst(headBlock);
BasicBlock::conectBlocks(curBlock, headBlock);
builder.setPosition(headBlock, headBlock->end());
@ -677,7 +792,7 @@ std::any SysYIRGenerator::visitWhileStmt(SysYParser::WhileStmtContext *ctx) {
module->leaveScope();
}
builder.createUncondBrInst(headBlock, {});
builder.createUncondBrInst(headBlock);
BasicBlock::conectBlocks(builder.getBasicBlock(), exitBlock);
builder.popBreakBlock();
builder.popContinueBlock();
@ -693,14 +808,14 @@ std::any SysYIRGenerator::visitWhileStmt(SysYParser::WhileStmtContext *ctx) {
std::any SysYIRGenerator::visitBreakStmt(SysYParser::BreakStmtContext *ctx) {
BasicBlock* breakBlock = builder.getBreakBlock();
builder.createUncondBrInst(breakBlock, {});
builder.createUncondBrInst(breakBlock);
BasicBlock::conectBlocks(builder.getBasicBlock(), breakBlock);
return std::any();
}
std::any SysYIRGenerator::visitContinueStmt(SysYParser::ContinueStmtContext *ctx) {
BasicBlock* continueBlock = builder.getContinueBlock();
builder.createUncondBrInst(continueBlock, {});
builder.createUncondBrInst(continueBlock);
BasicBlock::conectBlocks(builder.getBasicBlock(), continueBlock);
return std::any();
}
@ -712,22 +827,34 @@ std::any SysYIRGenerator::visitReturnStmt(SysYParser::ReturnStmtContext *ctx) {
}
Type* funcType = builder.getBasicBlock()->getParent()->getReturnType();
if (funcType!= returnValue->getType() && returnValue != nullptr) {
ConstantValue * constValue = dynamic_cast<ConstantValue *>(returnValue);
if (constValue != nullptr) {
if (funcType == Type::getFloatType()) {
returnValue = ConstantInteger::get(static_cast<float>(constValue->getInt()));
} else {
returnValue = ConstantFloating::get(static_cast<int>(constValue->getFloat()));
if (returnValue != nullptr && funcType!= returnValue->getType()) {
ConstantValue * constValue = dynamic_cast<ConstantValue *>(returnValue);
if (constValue != nullptr) {
if (funcType == Type::getFloatType()) {
if(dynamic_cast<ConstantInteger *>(constValue)) {
// 如果是整型常量,转换为浮点型
returnValue = ConstantFloating::get(static_cast<float>(constValue->getInt()));
} else if (dynamic_cast<ConstantFloating *>(constValue)) {
// 如果是浮点型常量,直接使用
returnValue = ConstantFloating::get(static_cast<float>(constValue->getInt()));
}
} else {
if (funcType == Type::getFloatType()) {
returnValue = builder.createIToFInst(returnValue);
} else {
returnValue = builder.createFtoIInst(returnValue);
if(dynamic_cast<ConstantFloating *>(constValue)) {
// 如果是浮点型常量,转换为整型
returnValue = ConstantInteger::get(static_cast<int>(constValue->getFloat()));
} else if (dynamic_cast<ConstantInteger *>(constValue)) {
// 如果是整型常量,直接使用
returnValue = ConstantInteger::get(static_cast<int>(constValue->getFloat()));
}
}
} else {
if (funcType == Type::getFloatType()) {
returnValue = builder.createIToFInst(returnValue);
} else {
returnValue = builder.createFtoIInst(returnValue);
}
}
}
builder.createReturnInst(returnValue);
return std::any();
@ -1045,20 +1172,34 @@ std::any SysYIRGenerator::visitMulExp(SysYParser::MulExpContext *ctx) {
// 如果有一个操作数是浮点数,则将两个操作数都转换为浮点数
if (operandType != floatType) {
ConstantValue * constValue = dynamic_cast<ConstantValue *>(operand);
if (constValue != nullptr)
operand = ConstantFloating::get(static_cast<float>(constValue->getInt()));
if (constValue != nullptr) {
if(dynamic_cast<ConstantInteger *>(constValue)) {
// 如果是整型常量,转换为浮点型
operand = ConstantFloating::get(static_cast<float>(constValue->getInt()));
} else if (dynamic_cast<ConstantFloating *>(constValue)) {
// 如果是浮点型常量,直接使用
operand = ConstantFloating::get(static_cast<float>(constValue->getFloat()));
}
}
else
operand = builder.createIToFInst(operand);
} else if (resultType != floatType) {
ConstantValue* constResult = dynamic_cast<ConstantValue *>(result);
if (constResult != nullptr)
result = ConstantFloating::get(static_cast<float>(constResult->getInt()));
else
if (constResult != nullptr) {
if(dynamic_cast<ConstantInteger *>(constResult)) {
// 如果是整型常量,转换为浮点型
result = ConstantFloating::get(static_cast<float>(constResult->getInt()));
} else if (dynamic_cast<ConstantFloating *>(constResult)) {
// 如果是浮点型常量,直接使用
result = ConstantFloating::get(static_cast<float>(constResult->getFloat()));
}
}
else
result = builder.createIToFInst(result);
}
ConstantValue* constResult = dynamic_cast<ConstantValue *>(result);
ConstantValue* constOperand = dynamic_cast<ConstantValue *>(operand);
ConstantFloating* constResult = dynamic_cast<ConstantFloating *>(result);
ConstantFloating* constOperand = dynamic_cast<ConstantFloating *>(operand);
if (opType == SysYParser::MUL) {
if ((constOperand != nullptr) && (constResult != nullptr)) {
result = ConstantFloating::get(constResult->getFloat() *
@ -1079,8 +1220,8 @@ std::any SysYIRGenerator::visitMulExp(SysYParser::MulExpContext *ctx) {
assert(false);
}
} else {
ConstantValue * constResult = dynamic_cast<ConstantValue *>(result);
ConstantValue * constOperand = dynamic_cast<ConstantValue *>(operand);
ConstantInteger *constResult = dynamic_cast<ConstantInteger *>(result);
ConstantInteger *constOperand = dynamic_cast<ConstantInteger *>(operand);
if (opType == SysYParser::MUL) {
if ((constOperand != nullptr) && (constResult != nullptr))
result = ConstantInteger::get(constResult->getInt() * constOperand->getInt());
@ -1120,20 +1261,34 @@ std::any SysYIRGenerator::visitAddExp(SysYParser::AddExpContext *ctx) {
// 类型转换
if (operandType != floatType) {
ConstantValue * constOperand = dynamic_cast<ConstantValue *>(operand);
if (constOperand != nullptr)
operand = ConstantFloating::get(static_cast<float>(constOperand->getInt()));
if (constOperand != nullptr) {
if(dynamic_cast<ConstantInteger *>(constOperand)) {
// 如果是整型常量,转换为浮点型
operand = ConstantFloating::get(static_cast<float>(constOperand->getInt()));
} else if (dynamic_cast<ConstantFloating *>(constOperand)) {
// 如果是浮点型常量,直接使用
operand = ConstantFloating::get(static_cast<float>(constOperand->getFloat()));
}
}
else
operand = builder.createIToFInst(operand);
} else if (resultType != floatType) {
ConstantValue * constResult = dynamic_cast<ConstantValue *>(result);
if (constResult != nullptr)
result = ConstantFloating::get(static_cast<float>(constResult->getInt()));
if (constResult != nullptr) {
if(dynamic_cast<ConstantInteger *>(constResult)) {
// 如果是整型常量,转换为浮点型
result = ConstantFloating::get(static_cast<float>(constResult->getInt()));
} else if (dynamic_cast<ConstantFloating *>(constResult)) {
// 如果是浮点型常量,直接使用
result = ConstantFloating::get(static_cast<float>(constResult->getFloat()));
}
}
else
result = builder.createIToFInst(result);
}
ConstantValue * constResult = dynamic_cast<ConstantValue *>(result);
ConstantValue * constOperand = dynamic_cast<ConstantValue *>(operand);
ConstantFloating *constResult = dynamic_cast<ConstantFloating *>(result);
ConstantFloating *constOperand = dynamic_cast<ConstantFloating *>(operand);
if (opType == SysYParser::ADD) {
if ((constResult != nullptr) && (constOperand != nullptr))
result = ConstantFloating::get(constResult->getFloat() + constOperand->getFloat());
@ -1146,8 +1301,8 @@ std::any SysYIRGenerator::visitAddExp(SysYParser::AddExpContext *ctx) {
result = builder.createFSubInst(result, operand);
}
} else {
ConstantValue * constResult = dynamic_cast<ConstantValue *>(result);
ConstantValue * constOperand = dynamic_cast<ConstantValue *>(operand);
ConstantInteger *constResult = dynamic_cast<ConstantInteger *>(result);
ConstantInteger *constOperand = dynamic_cast<ConstantInteger *>(operand);
if (opType == SysYParser::ADD) {
if ((constResult != nullptr) && (constOperand != nullptr))
result = ConstantInteger::get(constResult->getInt() + constOperand->getInt());
@ -1201,15 +1356,29 @@ std::any SysYIRGenerator::visitRelExp(SysYParser::RelExpContext *ctx) {
// 浮点数处理
if (resultType == floatType || operandType == floatType) {
if (resultType != floatType) {
if (constResult != nullptr)
result = ConstantFloating::get(static_cast<float>(constResult->getInt()));
if (constResult != nullptr){
if(dynamic_cast<ConstantInteger *>(constResult)) {
// 如果是整型常量,转换为浮点型
result = ConstantFloating::get(static_cast<float>(constResult->getInt()));
} else if (dynamic_cast<ConstantFloating *>(constResult)) {
// 如果是浮点型常量,直接使用
result = ConstantFloating::get(static_cast<float>(constResult->getFloat()));
}
}
else
result = builder.createIToFInst(result);
}
if (operandType != floatType) {
if (constOperand != nullptr)
operand = ConstantFloating::get(static_cast<float>(constOperand->getInt()));
if (constOperand != nullptr) {
if(dynamic_cast<ConstantInteger *>(constOperand)) {
// 如果是整型常量,转换为浮点型
operand = ConstantFloating::get(static_cast<float>(constOperand->getInt()));
} else if (dynamic_cast<ConstantFloating *>(constOperand)) {
// 如果是浮点型常量,直接使用
operand = ConstantFloating::get(static_cast<float>(constOperand->getFloat()));
}
}
else
operand = builder.createIToFInst(operand);
@ -1266,14 +1435,28 @@ std::any SysYIRGenerator::visitEqExp(SysYParser::EqExpContext *ctx) {
if (resultType == floatType || operandType == floatType) {
if (resultType != floatType) {
if (constResult != nullptr)
result = ConstantFloating::get(static_cast<float>(constResult->getInt()));
if (constResult != nullptr){
if(dynamic_cast<ConstantInteger *>(constResult)) {
// 如果是整型常量,转换为浮点型
result = ConstantFloating::get(static_cast<float>(constResult->getInt()));
} else if (dynamic_cast<ConstantFloating *>(constResult)) {
// 如果是浮点型常量,直接使用
result = ConstantFloating::get(static_cast<float>(constResult->getFloat()));
}
}
else
result = builder.createIToFInst(result);
}
if (operandType != floatType) {
if (constOperand != nullptr)
operand = ConstantFloating::get(static_cast<float>(constOperand->getInt()));
if (constOperand != nullptr) {
if(dynamic_cast<ConstantInteger *>(constOperand)) {
// 如果是整型常量,转换为浮点型
operand = ConstantFloating::get(static_cast<float>(constOperand->getInt()));
} else if (dynamic_cast<ConstantFloating *>(constOperand)) {
// 如果是浮点型常量,直接使用
operand = ConstantFloating::get(static_cast<float>(constOperand->getFloat()));
}
}
else
operand = builder.createIToFInst(operand);
}
@ -1321,7 +1504,7 @@ std::any SysYIRGenerator::visitLAndExp(SysYParser::LAndExpContext *ctx){
labelstring.str("");
auto cond = std::any_cast<Value *>(visitEqExp(ctx->eqExp(i)));
builder.createCondBrInst(cond, newtrueBlock, falseBlock, {}, {});
builder.createCondBrInst(cond, newtrueBlock, falseBlock);
BasicBlock::conectBlocks(curBlock, newtrueBlock);
BasicBlock::conectBlocks(curBlock, falseBlock);
@ -1331,7 +1514,7 @@ std::any SysYIRGenerator::visitLAndExp(SysYParser::LAndExpContext *ctx){
}
auto cond = std::any_cast<Value *>(visitEqExp(conds.back()));
builder.createCondBrInst(cond, trueBlock, falseBlock, {}, {});
builder.createCondBrInst(cond, trueBlock, falseBlock);
BasicBlock::conectBlocks(curBlock, trueBlock);
BasicBlock::conectBlocks(curBlock, falseBlock);
@ -1375,15 +1558,27 @@ void Utils::tree2Array(Type *type, ArrayValueTree *root,
} else {
if (type == Type::getFloatType()) {
ConstantValue* constValue = dynamic_cast<ConstantValue *>(value);
if (constValue != nullptr)
result.push_back(ConstantFloating::get(static_cast<float>(constValue->getInt())));
if (constValue != nullptr) {
if(dynamic_cast<ConstantInteger *>(constValue))
result.push_back(ConstantFloating::get(static_cast<float>(constValue->getInt())));
else if (dynamic_cast<ConstantFloating *>(constValue))
result.push_back(ConstantFloating::get(static_cast<float>(constValue->getFloat())));
else
assert(false && "Unknown constant type for float conversion.");
}
else
result.push_back(builder->createIToFInst(value));
} else {
ConstantValue* constValue = dynamic_cast<ConstantValue *>(value);
if (constValue != nullptr)
result.push_back(ConstantInteger::get(static_cast<int>(constValue->getFloat())));
if (constValue != nullptr){
if(dynamic_cast<ConstantInteger *>(constValue))
result.push_back(ConstantInteger::get(constValue->getInt()));
else if (dynamic_cast<ConstantFloating *>(constValue))
result.push_back(ConstantInteger::get(static_cast<int>(constValue->getFloat())));
else
assert(false && "Unknown constant type for int conversion.");
}
else
result.push_back(builder->createFtoIInst(value));
@ -1436,7 +1631,7 @@ void Utils::createExternalFunction(
for (int i = 0; i < paramTypes.size(); ++i) {
auto arg = new Argument(paramTypes[i], function, i, paramNames[i]);
auto alloca = pBuilder->createAllocaInst(
Type::getPointerType(paramTypes[i]), {}, paramNames[i]);
Type::getPointerType(paramTypes[i]), paramNames[i]);
function->insertArgument(arg);
auto store = pBuilder->createStoreInst(arg, alloca);
pModule->addVariable(paramNames[i], alloca);

View File

@ -13,6 +13,7 @@ void SysYPrinter::printIR() {
//TODO: Print target datalayout and triple (minimal required by LLVM)
printGlobalVariable();
printGlobalConstant();
for (const auto &iter : functions) {
if (iter.second->getName() == "main") {
@ -79,6 +80,15 @@ std::string SysYPrinter::getValueName(Value *value) {
return "";
}
std::string SysYPrinter::getBlockName(BasicBlock *block) {
static int blockId = 0; // 用于生成唯一的基本块ID
if (block->getName().empty()) {
return "bb" + std::to_string(blockId++); // 如果没有名字生成一个唯一的基本块ID
} else {
return block->getName();
}
}
void SysYPrinter::printType(Type *type) {
std::cout << getTypeString(type);
}
@ -128,6 +138,52 @@ void SysYPrinter::printGlobalVariable() {
}
}
void SysYPrinter::printGlobalConstant() {
auto &globalConstants = pModule->getConsts();
for (const auto &globalConstant : globalConstants) {
std::cout << "@" << globalConstant->getName() << " = global constant ";
// 全局变量的类型是一个指针,指向其基类型 (可能是 ArrayType 或 Integer/FloatType)
auto globalVarBaseType = dynamic_cast<PointerType *>(globalConstant->getType())->getBaseType();
printType(globalVarBaseType); // 打印全局变量的实际类型 (例如 i32 或 [10 x i32])
std::cout << " ";
// 检查是否是数组类型 (通过检查 globalVarBaseType 是否是 ArrayType)
if (globalVarBaseType->isArray()) {
// 数组初始化器
std::cout << "["; // LLVM IR 数组初始化器格式: [type value, type value, ...]
auto values = globalConstant->getInitValues(); // 假设 getInitValues() 返回一个 ValueCounter
const std::vector<sysy::Value *> &counterValues = values.getValues(); // 获取所有值
for (size_t i = 0; i < counterValues.size(); i++) {
if (i > 0) std::cout << ", ";
// 打印元素类型,这个元素类型应该是数组的最终元素类型,例如 i32 或 float
// 可以从 globalVarBaseType 逐层剥离得到最终元素类型,但这里简化为直接从值获取
printType(counterValues[i]->getType());
std::cout << " ";
printValue(counterValues[i]);
}
std::cout << "]";
} else {
// 标量初始化器
// 假设标量全局变量的初始化值通过 getByIndex(0) 获取
Value* initVal = globalConstant->getByIndex(0);
printType(initVal->getType()); // 打印标量值的类型
std::cout << " ";
printValue(initVal); // 打印标量值
}
std::cout << ", align 4" << std::endl;
}
}
void SysYPrinter::printBlock(BasicBlock *block) {
std::cout << getBlockName(block);
}
void SysYPrinter::printFunction(Function *function) {
// Function signature
std::cout << "define ";
@ -344,27 +400,22 @@ void SysYPrinter::printInst(Instruction *pInst) {
}
std::cout << std::endl;
} break;
case Kind::kUnreachable: {
std::cout << "Unreachable" << std::endl;
} break;
case Kind::kAlloca: {
auto allocaInst = dynamic_cast<AllocaInst *>(pInst);
std::cout << "%" << allocaInst->getName() << " = alloca ";
// AllocaInst 的类型现在应该是一个 PointerType指向正确的 ArrayType 或 ScalarType
// 例如alloca i32, align 4 或者 alloca [10 x i32], align 4
auto allocatedType = dynamic_cast<PointerType *>(allocaInst->getType())->getBaseType();
// auto allocatedType = dynamic_cast<PointerType *>(allocaInst->getType())->getBaseType();
auto allocatedType = allocaInst->getAllocatedType();
printType(allocatedType);
// 仍然打印维度信息,如果存在的话
if (allocaInst->getNumDims() > 0) {
std::cout << ", ";
for (size_t i = 0; i < allocaInst->getNumDims(); i++) {
if (i > 0) std::cout << ", ";
printType(Type::getIntType()); // 维度大小通常是 i32 类型
std::cout << " ";
printValue(allocaInst->getDim(i));
}
}
std::cout << ", align 4" << std::endl;
} break;
@ -377,17 +428,6 @@ void SysYPrinter::printInst(Instruction *pInst) {
std::cout << " ";
printValue(loadInst->getPointer()); // 要加载的地址
// 仍然打印索引信息,如果存在的话
if (loadInst->getNumIndices() > 0) {
std::cout << ", indices "; // 或者其他分隔符,取决于你期望的格式
for (size_t i = 0; i < loadInst->getNumIndices(); i++) {
if (i > 0) std::cout << ", ";
printType(loadInst->getIndex(i)->getType());
std::cout << " ";
printValue(loadInst->getIndex(i));
}
}
std::cout << ", align 4" << std::endl;
} break;
@ -402,16 +442,6 @@ void SysYPrinter::printInst(Instruction *pInst) {
std::cout << " ";
printValue(storeInst->getPointer()); // 目标地址
// 仍然打印索引信息,如果存在的话
if (storeInst->getNumIndices() > 0) {
std::cout << ", indices "; // 或者其他分隔符
for (size_t i = 0; i < storeInst->getNumIndices(); i++) {
if (i > 0) std::cout << ", ";
printType(storeInst->getIndex(i)->getType());
std::cout << " ";
printValue(storeInst->getIndex(i));
}
}
std::cout << ", align 4" << std::endl;
} break;
@ -466,13 +496,13 @@ void SysYPrinter::printInst(Instruction *pInst) {
// 如果你的 PhiInst 存储方式是 getIncomingValues() 和 getIncomingBlocks(),请相应调整
// LLVM IR 格式: phi type [value1, block1], [value2, block2]
bool firstPair = true;
for (unsigned i = 0; i < phiInst->getNumOperands() / 2; ++i) { // 遍历成对的操作数
for (unsigned i = 0; i < phiInst->getNumIncomingValues(); ++i) { // 遍历成对的操作数
if (!firstPair) std::cout << ", ";
firstPair = false;
std::cout << "[ ";
printValue(phiInst->getOperand(i * 2)); // value
printValue(phiInst->getValue(i));
std::cout << ", %";
printValue(phiInst->getOperand(i * 2 + 1)); // block
printBlock(phiInst->getBlock(i));
std::cout << " ]";
}
std::cout << std::endl;

View File

@ -16,7 +16,6 @@ using namespace antlr4;
#include "SysYIRCFGOpt.h" // 包含 CFG 优化
#include "RISCv64Backend.h"
#include "Pass.h" // 包含新的 Pass 框架
#include "AddressCalculationExpansion.h"
using namespace sysy;
@ -139,69 +138,6 @@ int main(int argc, char **argv) {
// 好像都不用传递module和builder了因为 PassManager 初始化了
passManager.runOptimizationPipeline(moduleIR, builder, optLevel);
AddressCalculationExpansion ace(moduleIR, builder);
if (ace.run()) {
if (DEBUG) cout << "AddressCalculationExpansion made changes.\n";
// 如果 ACE 改变了IR并且 DEBUG 模式开启可以考虑打印IR
if (DEBUG) {
cout << "=== After AddressCalculationExpansion ===\n";
SysYPrinter(moduleIR).printIR();
}
} else {
if (DEBUG) cout << "AddressCalculationExpansion made no changes.\n";
}
// 根据优化级别,执行额外的优化 pass
if (optLevel >= 1) {
if (DEBUG) cout << "Applying additional -O" << optLevel << " optimizations...\n";
// 放置 -O1 及其以上级别要启用的额外优化 pass
// 例如:
// MyNewOptimizationPass newOpt(moduleIR, builder);
// newOpt.run();
// 占位符注释,替换为你的具体优化 pass
// cout << "--- Additional Pass: MyCustomOpt1 ---" << endl;
// MyCustomOpt1 opt1_pass(moduleIR, builder);
// opt1_pass.run();
// cout << "--- Additional Pass: MyCustomOpt2 ---" << endl;
// MyCustomOpt2 opt2_pass(moduleIR, builder, &cfa); // 假设需要CFA
// opt2_pass.run();
// ... 更多 -O1 特有的优化
// DeadCodeElimination dce(moduleIR, &cfa, &ava);
// dce.runDCEPipeline();
// if (DEBUG) {
// cout << "=== After 1st DCE (Default) ===\n";
// SysYPrinter(moduleIR).printIR();
// }
// Mem2Reg mem2reg(moduleIR, builder, &cfa, &ava);
// mem2reg.mem2regPipeline();
// if (DEBUG) {
// cout << "=== After Mem2Reg (Default) ===\n";
// SysYPrinter(moduleIR).printIR();
// }
// Reg2Mem reg2mem(moduleIR, builder);
// reg2mem.DeletePhiInst();
// if (DEBUG) {
// cout << "=== After Reg2Mem (Default) ===\n";
// SysYPrinter(moduleIR).printIR();
// }
// dce.runDCEPipeline(); // 第二次 DCE (默认)
// if (DEBUG) {
// cout << "=== After 2nd DCE (Default) ===\n";
// SysYPrinter(moduleIR).printIR();
// }
} else {
if (DEBUG) cout << "No additional middle-end optimizations applied for -O" << optLevel << ".\n";
}
// 5. 根据 argStopAfter 决定后续操作
// a) 如果指定停止在 IR 阶段,则打印最终 IR 并退出
if (argStopAfter == "ir" || argStopAfter == "ird") {
@ -218,6 +154,7 @@ int main(int argc, char **argv) {
DEBUG = 1;
DEEPDEBUG = 1;
}
sysy::RISCv64CodeGen codegen(moduleIR); // 传入优化后的 moduleIR
string asmCode = codegen.code_gen();

View File

@ -1,8 +0,0 @@
//test add
int main(){
int a, b;
a = 10;
b = 2;
return a + b;
}

View File

@ -1,14 +0,0 @@
//test file for backend lab
int main() {
const int a = 1;
const int b = 2;
int c;
if (a != b)
c = b - a + 20; // 21 <- this
else
c = a * b + b + b + 10; // 16
return c;
}

View File

@ -1,13 +0,0 @@
//test add
int mul(int x, int y) {
return x * y;
}
int main(){
int a, b;
a = 10;
b = 3;
a = mul(a, b); //60
return a + b; //66
}

View File

@ -1,20 +0,0 @@
//test file for loop-invariant code motion (licm) and strength reduction (sr is optional)
int main(){
const int a = 1;
const int b = 2;
int c, d, f;
int i = 0;
while(i < 100){
c = a + b;
d = c * 2;
if(i > 50){
f = i * d;
}
i = i + 1;
}
return f;
}

View File

@ -1,18 +0,0 @@
//test file for common subexpression eliminiation (cse)
int main(){
int a = 1;
int b = 2;
int c, d, e, f;
c = a + b;
if(c > 0){
b = 3;
d = a + b;
}
e = a + b;
return e;
}

View File

@ -1,15 +0,0 @@
//test file for dead code eliminiation (dce)
int main(){
int i = 0;
int j = 0;
int a[100];
while(j < 100){
a[j] = j;
i = i * 2;
j = j + 1;
}
return a[j-1];
}

View File

@ -1,11 +0,0 @@
//test file for value numbering (vn)
int main(){
int a, b, c, d;
a = 1;
b = a + 1;
c = a;
d = c + 1;
return d;
}

View File

@ -1,14 +0,0 @@
//test file for constant propogation (cp) and constant folding (cf)
int main(){
int b = 5;
int c = 4 * b;
int d, g;
if(c > 8){
d = b + c;
}
g = c * d;
return g;
}

View File

@ -1,94 +0,0 @@
int a1 = 1;
int a2 = 2;
int a3 = 3;
int a4 = 4;
int a5 = 5;
int a6 = 6;
int a7 = 7;
int a8 = 8;
int a9 = 9;
int a10 = 10;
int a11 = 11;
int a12 = 12;
int a13 = 13;
int a14 = 14;
int a15 = 15;
int a16 = 16;
int a17 = 1;
int a18 = 2;
int a19 = 3;
int a20 = 4;
int a21 = 5;
int a22 = 6;
int a23 = 7;
int a24 = 8;
int a25 = 9;
int a26 = 10;
int a27 = 11;
int a28 = 12;
int a29 = 13;
int a30 = 14;
int a31 = 15;
int a32 = 16;
int func(int a, int b){
int i;
i = a + b;
int c1;int c2;int c3;int c4;
int d1;int d2;int d3;int d4;
int e1;int e2;int e3;int e4;
int f1;int f2;int f3;int f4;
int g1;int g2;int g3;int g4;
int h1;int h2;int h3;int h4;
int i1;int i2;int i3;int i4;
int j1;int j2;int j3;int j4;
int k1;int k2;int k3;int k4;
c1 = getint();c2 = getint();c3 = getint();c4 = getint();
d1 = 1 + c1 + a1;d2 = 2 + c2 + a2;d3 = 3 + c3 + a3;d4 = 4 + c4 + a4;
e1 = 1 + d1 + a5;e2 = 2 + d2 + a6;e3 = 3 + d3 + a7;e4 = 4 + d4 + a8;
f1 = 1 + e1 + a9;f2 = 2 + e2 + a10;f3 = 3 + e3 + a11;f4 = 4 + e4 + a12;
g1 = 1 + f1 + a13;g2 = 2 + f2 + a14;g3 = 3 + f3 + a15;g4 = 4 + f4 + a16;
h1 = 1 + g1 + a17;h2 = 2 + g2 + a18;h3 = 3 + g3 + a19;h4 = 4 + g4 + a20;
i1 = 1 + h1 + a21;i2 = 2 + h2 + a22;i3 = 3 + h3 + a23;i4 = 4 + h4 + a24;
j1 = 1 + i1 + a25;j2 = 2 + i2 + a26;j3 = 3 + i3 + a27;j4 = 4 + i4 + a28;
k1 = 1 + j1 + a29;k2 = 2 + j2 + a30;k3 = 3 + j3 + a31;k4 = 4 + j4 + a32;
i = a - b + 10;
k1 = 1 + j1 + a29;k2 = 2 + j2 + a30;k3 = 3 + j3 + a31;k4 = 4 + j4 + a32;
j1 = 1 + i1 + a25;j2 = 2 + i2 + a26;j3 = 3 + i3 + a27;j4 = 4 + i4 + a28;
i1 = 1 + h1 + a21;i2 = 2 + h2 + a22;i3 = 3 + h3 + a23;i4 = 4 + h4 + a24;
h1 = 1 + g1 + a17;h2 = 2 + g2 + a18;h3 = 3 + g3 + a19;h4 = 4 + g4 + a20;
g1 = 1 + f1 + a13;g2 = 2 + f2 + a14;g3 = 3 + f3 + a15;g4 = 4 + f4 + a16;
f1 = 1 + e1 + a9;f2 = 2 + e2 + a10;f3 = 3 + e3 + a11;f4 = 4 + e4 + a12;
e1 = 1 + d1 + a5;e2 = 2 + d2 + a6;e3 = 3 + d3 + a7;e4 = 4 + d4 + a8;
d1 = 1 + c1 + a1;d2 = 2 + c2 + a2;d3 = 3 + c3 + a3;d4 = 4 + c4 + a4;
d1 = 1 + c1 + a1;d2 = 2 + c2 + a2;d3 = 3 + c3 + a3;d4 = 4 + c4 + a4;
return i + c1 + c2 + c3 + c4
- d1 - d2 - d3 - d4
+ e1 + e2 + e3 + e4
- f1 - f2 - f3 - f4
+ g1 + g2 + g3 + g4
- h1 - h2 - h3 - h4
+ i1 + i2 + i3 + i4
- j1 - j2 - j3 - j4
+ k1 + k2 + k3 + k4
+ a1 - a2 + a3 - a4
+ a5 - a6 + a7 - a8
+ a9 - a10 + a11 - a12
+ a13 - a14 + a15 - a16
+ a17 - a18 + a19 - a20
+ a21 - a22 + a23 - a24
+ a25 - a26 + a27 - a28
+ a29 - a30 + a31 - a32;
}
int main(){
int a;
int b;
a = getint();
b = a + 2 * 9;
a = func(a, b);
putint(a);
return a;
}

View File

@ -1,7 +0,0 @@
// bug1: getint(;
int main() {
int a;
a = getint(;
return 0;
}

View File

@ -1,31 +0,0 @@
int get_one(int a) {
return 1;
}
int deepWhileBr(int a, int b) {
int c;
c = a + b;
while (c < 75) {
int d;
d = 42;
if (c < 100) {
c = c + d;
if (c > 99) {
int e;
e = d * 2;
if (get_one(0) == 1) {
c = e * 2;
}
}
}
}
return (c);
}
int main() {
int p;
p = 2;
p = deepWhileBr(p, p);
putint(p);
return 0;
}

View File

@ -1,30 +0,0 @@
int get_one(int a)
{
return 1;
}
int deepWhileBr(int a,int b){
int c;
c = a + b;
while(c<75) {
int d; d=42;
if (c<100) {
c =c+d;
if (c > 99) {
int e;
e = d*2;
if (get_one(0)==1) c=e * 2;
}
}
}
return (c);
}
int main() {
int p;
p = 2;
p = deepWhileBr(p, p);
putint(p);
return 0;
}

View File

@ -1 +0,0 @@
1,0xa , 011, "hellow",1.1

View File

@ -1,3 +0,0 @@
rm -rf tmp/*
rm -rf *.s *.ll *clang *sysyc
rm -rf *_riscv32

View File

@ -1,49 +0,0 @@
#!/bin/bash
# 定义输入目录
input_dir="./tmp"
# 获取tmp目录下的所有符合条件的可执行文件并按前缀数字升序排序
executable_files=$(ls "$input_dir" | grep -E '^[0-9]+_.*' | grep -E '_gcc_riscv32$|_sysyc_riscv32$' | sort -t '_' -k1,1n)
# 用于存储前缀数字和返回值
declare -A gcc_results
declare -A sysyc_results
# 遍历所有符合条件的可执行文件
for file in $executable_files; do
# 提取文件名前缀和后缀
prefix=$(echo "$file" | cut -d '_' -f 1)
suffix=$(echo "$file" | cut -d '_' -f 2)
# 检查是否已经处理过该前缀的两个文件
if [[ ${gcc_results["$prefix"]} && ${sysyc_results["$prefix"]} ]]; then
continue
fi
# 执行可执行文件并捕获返回值
echo "Executing: $file"
qemu-riscv32 "$input_dir/$file"
ret_code=$?
# 明确记录返回值
echo "Return code for $file: $ret_code"
# 根据后缀存储返回值
if [[ "$suffix" == "gcc" ]]; then
gcc_results["$prefix"]=$ret_code
elif [[ "$suffix" == "sysyc" ]]; then
sysyc_results["$prefix"]=$ret_code
fi
# 如果同一个前缀的两个文件都已执行,比较它们的返回值
if [[ ${gcc_results["$prefix"]} && ${sysyc_results["$prefix"]} ]]; then
gcc_ret=${gcc_results["$prefix"]}
sysyc_ret=${sysyc_results["$prefix"]}
if [[ "$gcc_ret" -ne "$sysyc_ret" ]]; then
echo -e "\e[31mWARNING: Return codes differ for prefix $prefix: _gcc=$gcc_ret, _sysyc=$sysyc_ret\e[0m"
else
echo "Return codes match for prefix $prefix: $gcc_ret"
fi
fi
done

View File

@ -1,49 +0,0 @@
#!/bin/bash
# 定义输入目录
input_dir="."
# 获取当前目录下的所有符合条件的可执行文件,并按前缀数字升序排序
executable_files=$(ls "$input_dir" | grep -E '^[0-9]+_.*' | grep -E '_clang$|_sysyc$' | sort -t '_' -k1,1n)
# 用于存储前缀数字和返回值
declare -A clang_results
declare -A sysyc_results
# 遍历所有符合条件的可执行文件
for file in $executable_files; do
# 提取文件名前缀和后缀
prefix=$(echo "$file" | cut -d '_' -f 1)
suffix=$(echo "$file" | cut -d '_' -f 2)
# 检查是否已经处理过该前缀的两个文件
if [[ ${clang_results["$prefix"]} && ${sysyc_results["$prefix"]} ]]; then
continue
fi
# 执行可执行文件并捕获返回值
echo "Executing: $file"
"./$file"
ret_code=$?
# 明确记录返回值
echo "Return code for $file: $ret_code"
# 根据后缀存储返回值
if [[ "$suffix" == "clang" ]]; then
clang_results["$prefix"]=$ret_code
elif [[ "$suffix" == "sysyc" ]]; then
sysyc_results["$prefix"]=$ret_code
fi
# 如果同一个前缀的两个文件都已执行,比较它们的返回值
if [[ ${clang_results["$prefix"]} && ${sysyc_results["$prefix"]} ]]; then
clang_ret=${clang_results["$prefix"]}
sysyc_ret=${sysyc_results["$prefix"]}
if [[ "$clang_ret" -ne "$sysyc_ret" ]]; then
echo -e "\e[31mWARNING: Return codes differ for prefix $prefix: _clang=$clang_ret, _sysyc=$sysyc_ret\e[0m"
else
echo "Return codes match for prefix $prefix: $clang_ret"
fi
fi
done

View File

@ -1,57 +0,0 @@
#!/bin/bash
# 定义输入和输出路径
input_dir="../test/"
output_dir="./tmp"
# 默认不生成可执行文件
generate_executable=false
# 解析命令行参数
while [[ "$#" -gt 0 ]]; do
case $1 in
--executable|-e)
generate_executable=true
shift
;;
*)
echo "Unknown parameter: $1"
exit 1
;;
esac
done
# 确保输出目录存在
mkdir -p "$output_dir"
# 遍历输入路径中的所有 .sy 文件
for sy_file in "$input_dir"*.sy; do
# 获取文件名(不带路径和扩展名)
base_name=$(basename "$sy_file" .sy)
# 定义输出文件路径
output_file="${output_dir}/${base_name}_gcc_riscv32.s"
# 使用 gcc 编译 .sy 文件为 .ll 文件
riscv32-unknown-elf-gcc -x c -S "$sy_file" -o "$output_file"
# 检查是否成功
if [ $? -eq 0 ]; then
echo "Compiled $sy_file -> $output_file"
else
echo "Failed to compile $sy_file"
continue
fi
# 如果指定了 --executable 或 -e 参数,则进一步编译为可执行文件
if $generate_executable; then
executable_file="${output_dir}/${base_name}_gcc_riscv32"
riscv32-unknown-elf-gcc "$output_file" -o "$executable_file"
if [ $? -eq 0 ]; then
echo "Generated executable: $executable_file"
else
echo "Failed to generate executable from $output_file"
fi
fi
done

View File

@ -1,57 +0,0 @@
#!/bin/bash
# 定义输入和输出路径
input_dir="../test/"
output_dir="./"
# 默认不生成可执行文件
generate_executable=false
# 解析命令行参数
while [[ "$#" -gt 0 ]]; do
case $1 in
--executable|-e)
generate_executable=true
shift
;;
*)
echo "Unknown parameter: $1"
exit 1
;;
esac
done
# 确保输出目录存在
mkdir -p "$output_dir"
# 遍历输入路径中的所有 .sy 文件
for sy_file in "$input_dir"*.sy; do
# 获取文件名(不带路径和扩展名)
base_name=$(basename "$sy_file" .sy)
# 定义输出文件路径
output_file="${base_name}_clang.ll"
# 使用 clang 编译 .sy 文件为 .ll 文件
clang -x c -S -emit-llvm "$sy_file" -o "$output_file"
# 检查是否成功
if [ $? -eq 0 ]; then
echo "Compiled $sy_file -> $output_file"
else
echo "Failed to compile $sy_file"
continue
fi
# 如果指定了 --executable 或 -e 参数,则进一步编译为可执行文件
if $generate_executable; then
executable_file="${base_name}_clang"
clang "$output_file" -o "$executable_file"
if [ $? -eq 0 ]; then
echo "Generated executable: $executable_file"
else
echo "Failed to generate executable from $output_file"
fi
fi
done

View File

@ -1,57 +0,0 @@
#!/bin/bash
# 定义输入和输出路径
input_dir="../test/"
output_dir="./tmp"
# 默认不生成可执行文件
generate_executable=false
# 解析命令行参数
while [[ "$#" -gt 0 ]]; do
case $1 in
--executable|-e)
generate_executable=true
shift
;;
*)
echo "Unknown parameter: $1"
exit 1
;;
esac
done
# 确保输出目录存在
mkdir -p "$output_dir"
# 遍历输入路径中的所有 .sy 文件
for sy_file in "$input_dir"*.sy; do
# 获取文件名(不带路径和扩展名)
base_name=$(basename "$sy_file" .sy)
# 定义输出文件路径
output_file="${output_dir}/${base_name}_sysyc_riscv32.s"
# 使用 sysyc 编译 .sy 文件为 .s 文件
../build/bin/sysyc -s asm "$sy_file" > "$output_file"
# 检查是否成功
if [ $? -eq 0 ]; then
echo "Compiled $sy_file -> $output_file"
else
echo "Failed to compile $sy_file"
continue
fi
# 如果指定了 --executable 或 -e 参数,则进一步编译为可执行文件
if $generate_executable; then
executable_file="${output_dir}/${base_name}_sysyc_riscv32"
riscv32-unknown-elf-gcc "$output_file" -o "$executable_file"
if [ $? -eq 0 ]; then
echo "Generated executable: $executable_file"
else
echo "Failed to generate executable from $output_file"
fi
fi
done

View File

@ -1,57 +0,0 @@
#!/bin/bash
# 定义输入和输出路径
input_dir="../test/"
output_dir="./"
# 默认不生成可执行文件
generate_executable=false
# 解析命令行参数
while [[ "$#" -gt 0 ]]; do
case $1 in
--executable|-e)
generate_executable=true
shift
;;
*)
echo "Unknown parameter: $1"
exit 1
;;
esac
done
# 确保输出目录存在
mkdir -p "$output_dir"
# 遍历输入路径中的所有 .sy 文件
for sy_file in "$input_dir"*.sy; do
# 获取文件名(不带路径和扩展名)
base_name=$(basename "$sy_file" .sy)
# 定义输出文件路径
output_file="${base_name}_sysyc.ll"
# 使用 sysyc 编译 .sy 文件为 .ll 文件
../build/bin/sysyc -s ir "$sy_file" > "$output_file"
# 检查是否成功
if [ $? -eq 0 ]; then
echo "Compiled $sy_file -> $output_file"
else
echo "Failed to compile $sy_file"
continue
fi
# 如果指定了 --executable 或 -e 参数,则进一步编译为可执行文件
if $generate_executable; then
executable_file="${base_name}_sysyc"
clang "$output_file" -o "$executable_file"
if [ $? -eq 0 ]; then
echo "Generated executable: $executable_file"
else
echo "Failed to generate executable from $output_file"
fi
fi
done

View File

@ -1,3 +0,0 @@
sh ./gcc-riscv32.sh -e
sh ./sysy-riscv32.sh -e
sh ./exe-riscv32.sh