Compare commits
151 Commits
deploy-202
...
backend-IR
| Author | SHA1 | Date | |
|---|---|---|---|
| 004ef82488 | |||
| 8f1d592d4e | |||
| 537533ee43 | |||
| bfe218be07 | |||
| 384f7c548b | |||
| 57fe17dc21 | |||
| e48cddab9f | |||
| aef10b48e8 | |||
| 373726b02f | |||
| a0b69f20fb | |||
| 999f2c6615 | |||
| 1eedb55ca0 | |||
| 8fe9867f33 | |||
| 166d0fc372 | |||
| 873dbf64d0 | |||
| f387aecc03 | |||
| c268191826 | |||
| 03e88eee70 | |||
| 0f1fcc835d | |||
| c5af4f1c49 | |||
| 9a53e1b917 | |||
| ef09bc70d4 | |||
| aed4577490 | |||
| 35b421b60b | |||
| f3f603a032 | |||
| de0f8422e9 | |||
| 35691ab7bc | |||
| 61768fa180 | |||
| 520ebd96f0 | |||
| 6868f638d7 | |||
| e8699d6d25 | |||
| 0727d5a6d8 | |||
| fc7afdbb35 | |||
| bfe2b248cd | |||
| 6d60522ce2 | |||
| 807fb3f560 | |||
| 82288464c3 | |||
| 7e8b90ffd4 | |||
| b3cf3cba29 | |||
| 03b62b138f | |||
| 8e94f89931 | |||
| b388dc4542 | |||
| 48b0aec6c3 | |||
| 1fb5cd398d | |||
| 206a0af424 | |||
| 877a0f5dc2 | |||
| a3c4d5a2b8 | |||
| 39c13c46ec | |||
| dd38bdc133 | |||
| 38bee5d5ac | |||
| 98511efd91 | |||
| 507096a0f6 | |||
| 7f2e501cea | |||
| 860ebcd447 | |||
| 31b6711d74 | |||
| 42dce9820b | |||
| 09ae47924e | |||
| f5922d0178 | |||
| 63906d0648 | |||
| 6ba05e0d8c | |||
| e4fd16e36a | |||
| 32bdc17dc3 | |||
| 8deb4ed076 | |||
| 37e99e37a3 | |||
| 8e69992b29 | |||
| 15fe69187a | |||
| fff19ca1ea | |||
| 4a329eeaf2 | |||
| 3dc4b28c92 | |||
| 202e6d7cd8 | |||
| 3e4cac089e | |||
| 76d7b14b2e | |||
| 9ba08126fb | |||
| 875100ec01 | |||
| b0cecca081 | |||
| 434bcea98e | |||
| da5c2bb41d | |||
| fcc3806342 | |||
| 792dc9c1f6 | |||
| 429e477776 | |||
| 535a935bf1 | |||
| efe74cba6c | |||
| 634a84f29c | |||
| 2e8b564d8f | |||
| 2dd6a17fca | |||
| 78dee0d72a | |||
| af318b6c0e | |||
| 9bea4d5343 | |||
| 540742be0c | |||
| 8ae7478ef3 | |||
| a616ec085e | |||
| 828515bc2f | |||
| a231267fc5 | |||
| 4b181261ce | |||
| 3df9b3bb06 | |||
| e57ac7709d | |||
| 2643eb1edd | |||
| 5bfa6d72a2 | |||
| 14fb3dbe48 | |||
| 04c5c6b44d | |||
| e2c97fd171 | |||
| 12f63a0bf5 | |||
| d50912ee4c | |||
| 259d71cde5 | |||
| 1e6f6ed711 | |||
| 96c6b0ab6e | |||
| 10a533b0cc | |||
| 5f8bf15d4d | |||
| 18dc8dbfee | |||
| 9c56bc1310 | |||
| c68b031c01 | |||
| 2556ab7315 | |||
| 4b9d067c12 | |||
| f4d231b989 | |||
| 56b376914b | |||
| 2157cf6aa6 | |||
| 0e492cd6d7 | |||
| 87d38be255 | |||
| 2040670f8c | |||
| 3df3d7a097 | |||
| b20bda2f52 | |||
| f61b51b2fa | |||
| 20a5c5cbfb | |||
| cf88ca77cb | |||
| fd6fe22020 | |||
| e8fe710c26 | |||
| 9c87cb397b | |||
| c45938d41d | |||
| 3baccbc03a | |||
| 24d8e730f1 | |||
| bbfbf96b5e | |||
| a72fc541fb | |||
| 550f4017be | |||
| f7e811b756 | |||
| 88604c1f94 | |||
| de696b2b53 | |||
| 18e7cbd413 | |||
| 20cd16bf52 | |||
| 80dee78f04 | |||
| 8f1e477e73 | |||
| 10b011a1de | |||
| 34b5a93aaf | |||
| a5d97185e1 | |||
| fdc946c1b5 | |||
| 725da2858d | |||
| 631ef80de2 | |||
| 77fae4d662 | |||
| 009f54863e | |||
| f7e318e623 | |||
| 00348c1931 | |||
| 5a6cfbee1e |
3
.gitignore
vendored
3
.gitignore
vendored
@ -23,7 +23,6 @@
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
@ -37,6 +36,7 @@ doxygen
|
||||
|
||||
!/testdata/functional/*.out
|
||||
!/testdata/h_functional/*.out
|
||||
!/testdata/performance/*.out
|
||||
build/
|
||||
.antlr
|
||||
.vscode/
|
||||
@ -54,3 +54,4 @@ __init__.py
|
||||
.DS_*
|
||||
|
||||
antlr/
|
||||
.clang-format
|
||||
|
||||
246
Pass_ID_List.md
Normal file
246
Pass_ID_List.md
Normal file
@ -0,0 +1,246 @@
|
||||
# 记录中端遍的开发进度
|
||||
|
||||
| 名称 | 优化级别 | 开发进度 |
|
||||
| ------------ | ------------ | ---------- |
|
||||
| CFG优化 | 函数级 | 已完成 |
|
||||
| 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过程
|
||||
34
README.md
34
README.md
@ -38,3 +38,37 @@ mysysy/ $ bash setup.sh
|
||||
|
||||
### 配套脚本
|
||||
(TODO: 需要完善)
|
||||
|
||||
|
||||
### TODO_list:
|
||||
|
||||
除开注释中的TODO后续时间充足可以考虑的TODO:
|
||||
|
||||
- store load指令由于gep指令的引入, 维度信息的记录是非必须的, 考虑删除
|
||||
|
||||
- use def关系经过mem2reg和phi函数明确转换为ssa形式, 以及函数参数通过value数组明确定义, 使得基本块的args参数信息记录非必须, 考虑删除
|
||||
|
||||
---
|
||||
|
||||
## 编译器后端 TODO 列表
|
||||
|
||||
### 1. `CALL` 指令处理不完善 (高优先级)
|
||||
|
||||
* **问题描述**:当前 `RISCv64RegAlloc::getInstrUseDef()` 方法中,对 `CALL` 指令的 `use`/`def` 分析不完整。它正确识别了返回值为 `def` 和参数为 `use`,但**没有将所有调用者保存 (Caller-saved) 的物理寄存器(`T0-T6`, `A0-A7`)标记为隐式 `def` (即 `CALL` 会破坏它们)**。
|
||||
* **潜在后果**:
|
||||
* **活跃性分析错误**:寄存器分配器可能会错误地认为某个跨函数调用活跃的虚拟寄存器是安全的,并将其分配给 `T` 或 `A` 寄存器。
|
||||
* **值被破坏**:在 `CALL` 指令执行后,这些 `T` 或 `A` 寄存器中本应保留的值会被被调用的函数破坏,导致程序行为异常。
|
||||
* **参考文件**:`RISCv64RegAlloc.cpp` (在 `getInstrUseDef` 函数中对 `RVOpcodes::CALL` 的处理)。
|
||||
|
||||
### 2. `T6` 寄存器作为溢出寄存器的问题 (中等优先级)
|
||||
|
||||
* **问题描述**:`RISCv64RegAlloc::rewriteFunction()` 方法中,所有未能成功着色并被溢出 (spilled) 的虚拟寄存器,都被统一替换为物理寄存器 `T6`。
|
||||
* **问题 2.1:`T6` 是调用者保存寄存器,但未被调用者保存**:
|
||||
* `T6` 属于调用者保存寄存器 (`T0-T6` 范围)。
|
||||
* 标准 ABI 要求,如果一个调用者保存寄存器在函数调用前后都活跃(例如,它存储了一个被溢出的变量,而这个变量在 `CALL` 指令之后还需要用到),那么**调用者**有责任在 `CALL` 前保存该寄存器,并在 `CALL` 后恢复它。
|
||||
* 目前的 `rewriteFunction` 没有为 `T6` 插入这种保存/恢复逻辑。
|
||||
* **潜在后果**:如果一个溢出变量被分配到 `T6`,并且它跨函数调用活跃,那么 `putint` 或其他任何被调用的函数可能会随意使用 `T6`,从而破坏该溢出变量的值。
|
||||
* **问题 2.2:所有溢出变量共用一个 `T6`**:
|
||||
* 将所有溢出变量映射到同一个物理寄存器 `T6` 是一种简化的溢出策略。
|
||||
* **潜在后果**:这意味着,每当需要使用一个溢出变量时,其值必须从栈中加载到 `T6`;每当一个溢出变量被定义时,其值必须从 `T6` 存储回栈。这会引入大量的 `load`/`store` 指令,并导致 `T6` 本身成为一个高度冲突的寄存器,严重降低代码效率。
|
||||
* **参考文件**:`RISCv64RegAlloc.cpp` (在 `rewriteFunction` 函数中处理 `spilled_vregs` 的部分)。
|
||||
|
||||
BIN
lib/libsysy_arm.a
Normal file
BIN
lib/libsysy_arm.a
Normal file
Binary file not shown.
BIN
lib/libsysy_riscv.a
Normal file
BIN
lib/libsysy_riscv.a
Normal file
Binary file not shown.
255
script/runit-riscv64-single.sh
Normal file
255
script/runit-riscv64-single.sh
Normal file
@ -0,0 +1,255 @@
|
||||
#!/bin/bash
|
||||
|
||||
# runit-riscv64-single.sh - 用于在 RISC-V 虚拟机内部测试单个或少量 .s 文件的脚本
|
||||
# 模仿 runit-riscv64.sh 的功能,但以具体文件路径作为输入。
|
||||
|
||||
# --- 配置区 ---
|
||||
# 假设此脚本位于项目根目录 (例如 /home/ubuntu/debug)
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
|
||||
LIB_DIR="${SCRIPT_DIR}/lib"
|
||||
TMP_DIR="${SCRIPT_DIR}/tmp" # 临时可执行文件将存放在这里
|
||||
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 # 对比失败时显示的最大行数
|
||||
S_FILES=() # 存储用户提供的 .s 文件列表
|
||||
PASSED_CASES=0
|
||||
FAILED_CASES_LIST=""
|
||||
|
||||
# --- 函数定义 ---
|
||||
show_help() {
|
||||
echo "用法: $0 [文件1.s] [文件2.s] ... [选项]"
|
||||
echo "在 VM 内部编译并测试指定的 .s 文件。"
|
||||
echo ""
|
||||
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)。"
|
||||
echo " -h, --help 显示此帮助信息并退出。"
|
||||
}
|
||||
|
||||
# 显示文件内容并根据行数截断的函数
|
||||
display_file_content() {
|
||||
local file_path="$1"
|
||||
local title="$2"
|
||||
local max_lines="$3"
|
||||
|
||||
if [ ! -f "$file_path" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "$title"
|
||||
local line_count
|
||||
line_count=$(wc -l < "$file_path")
|
||||
|
||||
if [ "$line_count" -gt "$max_lines" ]; then
|
||||
head -n "$max_lines" "$file_path"
|
||||
echo -e "\e[33m[... 输出已截断,共 ${line_count} 行 ...]\e[0m"
|
||||
else
|
||||
cat "$file_path"
|
||||
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)
|
||||
# 选项和其值将在下一个循环中处理
|
||||
;;
|
||||
-h|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
-*)
|
||||
# 检查是否是带值的选项
|
||||
if ! [[ ${args_processed+x} ]]; then
|
||||
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 ;;
|
||||
*.s) S_FILES+=("$1") ;;
|
||||
*) if ! [[ "$1" =~ ^[0-9]+$ ]]; then echo "未知选项或无效文件: $1"; show_help; exit 1; fi ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
fi
|
||||
;;
|
||||
*.s)
|
||||
if [[ -f "$arg" ]]; then
|
||||
S_FILES+=("$arg")
|
||||
else
|
||||
echo "警告: 文件不存在,已忽略: $arg"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
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
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "${TMP_DIR}"
|
||||
TOTAL_CASES=${#S_FILES[@]}
|
||||
|
||||
echo "SysY VM 内单例测试运行器启动..."
|
||||
echo "超时设置: gcc=${GCC_TIMEOUT}s, 运行=${EXEC_TIMEOUT}s"
|
||||
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
|
||||
echo ""
|
||||
|
||||
for s_file in "${S_FILES[@]}"; do
|
||||
is_passed=1
|
||||
|
||||
# 从 .s 文件名反向推导原始测试用例路径
|
||||
base_name_from_s_file=$(basename "$s_file" .s)
|
||||
original_test_name_underscored=$(echo "$base_name_from_s_file" | sed 's/_sysyc_riscv64$//')
|
||||
category=$(echo "$original_test_name_underscored" | cut -d'_' -f1)
|
||||
test_file_base=$(echo "$original_test_name_underscored" | cut -d'_' -f2-)
|
||||
original_relative_path="${category}/${test_file_base}"
|
||||
|
||||
executable_file="${TMP_DIR}/${base_name_from_s_file}"
|
||||
input_file="${TESTDATA_DIR}/${original_relative_path}.in"
|
||||
output_reference_file="${TESTDATA_DIR}/${original_relative_path}.out"
|
||||
output_actual_file="${TMP_DIR}/${base_name_from_s_file}.actual_out"
|
||||
|
||||
echo "======================================================================"
|
||||
echo "正在处理: ${s_file}"
|
||||
echo " (关联测试用例: ${original_relative_path}.sy)"
|
||||
|
||||
# 步骤 1: GCC 编译
|
||||
echo " 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${GCC_TIMEOUT} "${GCC_NATIVE}" "${s_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static -g
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "\e[31m错误: GCC 编译失败或超时。\e[0m"
|
||||
is_passed=0
|
||||
fi
|
||||
|
||||
# 步骤 2: 执行与测试
|
||||
if [ "$is_passed" -eq 1 ]; then
|
||||
# 检查是自动化测试还是交互模式
|
||||
if [ -f "${input_file}" ] || [ -f "${output_reference_file}" ]; then
|
||||
# --- 自动化测试模式 ---
|
||||
echo " 检测到 .in/.out 文件,进入自动化测试模式..."
|
||||
echo " 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
|
||||
|
||||
exec_cmd="\"${executable_file}\""
|
||||
[ -f "${input_file}" ] && exec_cmd+=" < \"${input_file}\""
|
||||
exec_cmd+=" > \"${output_actual_file}\""
|
||||
|
||||
eval "timeout -s KILL ${EXEC_TIMEOUT} ${exec_cmd}"
|
||||
ACTUAL_RETURN_CODE=$?
|
||||
|
||||
if [ "$ACTUAL_RETURN_CODE" -eq 124 ]; then
|
||||
echo -e "\e[31m 执行超时。\e[0m"
|
||||
is_passed=0
|
||||
else
|
||||
if [ -f "${output_reference_file}" ]; then
|
||||
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
|
||||
if [[ "$LAST_LINE_TRIMMED" =~ ^[-+]?[0-9]+$ ]]; then
|
||||
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
|
||||
EXPECTED_STDOUT_FILE="${TMP_DIR}/${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
|
||||
|
||||
# --- 本次修改点: 使用 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
|
||||
# --- 本次修改点: 使用 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"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# --- 交互模式 ---
|
||||
echo -e "\e[33m"
|
||||
echo " **********************************************************"
|
||||
echo " ** 未找到 .in 或 .out 文件,进入交互模式。 **"
|
||||
echo " ** 程序即将运行,你可以直接在终端中输入。 **"
|
||||
echo " ** 按下 Ctrl+D (EOF) 或以其他方式结束程序以继续。 **"
|
||||
echo " **********************************************************"
|
||||
echo -e "\e[0m"
|
||||
"${executable_file}"
|
||||
INTERACTIVE_RET_CODE=$?
|
||||
echo -e "\e[33m\n 交互模式执行完毕,程序返回码: ${INTERACTIVE_RET_CODE}\e[0m"
|
||||
echo " 注意: 交互模式的结果未经验证。"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$is_passed" -eq 1 ]; then
|
||||
echo -e "\e[32m状态: 通过\e[0m"
|
||||
((PASSED_CASES++))
|
||||
else
|
||||
echo -e "\e[31m状态: 失败\e[0m"
|
||||
FAILED_CASES_LIST+="${original_relative_path}.sy\n"
|
||||
fi
|
||||
done
|
||||
|
||||
# --- 打印最终总结 ---
|
||||
echo "======================================================================"
|
||||
echo "所有测试完成"
|
||||
echo "测试通过率: [${PASSED_CASES}/${TOTAL_CASES}]"
|
||||
|
||||
if [ -n "$FAILED_CASES_LIST" ]; then
|
||||
echo ""
|
||||
echo -e "\e[31m未通过的测例:\e[0m"
|
||||
echo -e "${FAILED_CASES_LIST}"
|
||||
fi
|
||||
|
||||
echo "======================================================================"
|
||||
|
||||
if [ "$PASSED_CASES" -eq "$TOTAL_CASES" ]; then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
232
script/runit-riscv64.sh
Normal file
232
script/runit-riscv64.sh
Normal file
@ -0,0 +1,232 @@
|
||||
#!/bin/bash
|
||||
|
||||
# runit-riscv64.sh - 用于在 RISC-V 虚拟机内部汇编、链接和测试 SysY 程序的脚本
|
||||
# 此脚本应位于您的项目根目录 (例如 /home/ubuntu/debug)
|
||||
# 假设当前运行环境已经是 RISC-V 64 位架构,可以直接执行编译后的程序。
|
||||
|
||||
# 定义相对于脚本位置的目录
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
|
||||
TMP_DIR="${SCRIPT_DIR}/tmp"
|
||||
LIB_DIR="${SCRIPT_DIR}/lib"
|
||||
TESTDATA_DIR="${SCRIPT_DIR}/testdata"
|
||||
|
||||
# 定义编译器 (这里假设 gcc 在 VM 内部是可用的)
|
||||
GCC_NATIVE="gcc" # VM 内部的 gcc
|
||||
|
||||
# --- 新增功能: 初始化变量 ---
|
||||
GCC_TIMEOUT=10 # 默认 gcc 编译超时 (秒)
|
||||
EXEC_TIMEOUT=5 # 默认运行时超时 (秒)
|
||||
MAX_OUTPUT_LINES=50 # 对比失败时显示的最大行数
|
||||
TOTAL_CASES=0
|
||||
PASSED_CASES=0
|
||||
FAILED_CASES_LIST="" # 用于存储未通过的测例列表
|
||||
|
||||
# 显示帮助信息的函数
|
||||
show_help() {
|
||||
echo "用法: $0 [选项]"
|
||||
echo "此脚本用于在 RISC-V 虚拟机内部,对之前生成的 .s 汇编文件进行汇编、链接和测试。"
|
||||
echo "测试会按文件名升序进行。"
|
||||
echo ""
|
||||
echo "选项:"
|
||||
echo " -c, --clean 清理 'tmp' 目录下的所有生成文件。"
|
||||
echo " -ct M 设置 gcc 编译的超时时间为 M 秒 (默认: 10)。"
|
||||
echo " -t N 设置每个测试用例的运行时超时为 N 秒 (默认: 5)。"
|
||||
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 50)。"
|
||||
echo " -h, --help 显示此帮助信息并退出。"
|
||||
}
|
||||
|
||||
# 显示文件内容并根据行数截断的函数
|
||||
display_file_content() {
|
||||
local file_path="$1"
|
||||
local title="$2"
|
||||
local max_lines="$3"
|
||||
|
||||
if [ ! -f "$file_path" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "$title"
|
||||
local line_count
|
||||
line_count=$(wc -l < "$file_path")
|
||||
|
||||
if [ "$line_count" -gt "$max_lines" ]; then
|
||||
head -n "$max_lines" "$file_path"
|
||||
echo -e "\e[33m[... 输出已截断,共 ${line_count} 行 ...]\e[0m"
|
||||
else
|
||||
cat "$file_path"
|
||||
fi
|
||||
}
|
||||
|
||||
# 清理临时文件的函数
|
||||
clean_tmp() {
|
||||
echo "正在清理临时目录: ${TMP_DIR}"
|
||||
rm -rf "${TMP_DIR}"/*.s \
|
||||
"${TMP_DIR}"/*_sysyc_riscv64 \
|
||||
"${TMP_DIR}"/*_sysyc_riscv64.actual_out \
|
||||
"${TMP_DIR}"/*_sysyc_riscv64.expected_stdout \
|
||||
"${TMP_DIR}"/*_sysyc_riscv64.o
|
||||
echo "清理完成。"
|
||||
}
|
||||
|
||||
# 如果临时目录不存在,则创建它
|
||||
mkdir -p "${TMP_DIR}"
|
||||
|
||||
# 解析命令行参数
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-c|--clean)
|
||||
clean_tmp
|
||||
exit 0
|
||||
;;
|
||||
-t)
|
||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift; else echo "错误: -t 需要一个正整数参数。" >&2; exit 1; fi
|
||||
;;
|
||||
-ct)
|
||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift; else echo "错误: -ct 需要一个正整数参数。" >&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
|
||||
;;
|
||||
-h|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "未知选项: $1"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift # 移过参数名
|
||||
done
|
||||
|
||||
echo "SysY VM 内部测试运行器启动..."
|
||||
echo "GCC 编译超时设置为: ${GCC_TIMEOUT} 秒"
|
||||
echo "运行时超时设置为: ${EXEC_TIMEOUT} 秒"
|
||||
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
|
||||
echo "汇编文件目录: ${TMP_DIR}"
|
||||
echo ""
|
||||
|
||||
# 查找 tmp 目录下的所有 .s 汇编文件并排序
|
||||
s_files=$(find "${TMP_DIR}" -maxdepth 1 -name "*.s" | sort -V)
|
||||
TOTAL_CASES=$(echo "$s_files" | wc -w)
|
||||
|
||||
# 使用 here-string (<<<) 避免子 shell 问题
|
||||
while IFS= read -r s_file; do
|
||||
is_passed=1 # 1 表示通过, 0 表示失败
|
||||
|
||||
base_name_from_s_file=$(basename "$s_file" .s)
|
||||
original_test_name_underscored=$(echo "$base_name_from_s_file" | sed 's/_sysyc_riscv64$//')
|
||||
|
||||
category=$(echo "$original_test_name_underscored" | cut -d'_' -f1)
|
||||
test_file_base=$(echo "$original_test_name_underscored" | cut -d'_' -f2-)
|
||||
original_relative_path="${category}/${test_file_base}"
|
||||
|
||||
executable_file="${TMP_DIR}/${base_name_from_s_file}"
|
||||
input_file="${TESTDATA_DIR}/${original_relative_path}.in"
|
||||
output_reference_file="${TESTDATA_DIR}/${original_relative_path}.out"
|
||||
output_actual_file="${TMP_DIR}/${base_name_from_s_file}.actual_out"
|
||||
|
||||
echo "正在处理汇编文件: $(basename "$s_file")"
|
||||
echo " 对应的测试用例路径: ${original_relative_path}"
|
||||
|
||||
# 步骤 1: 使用 VM 内部的 gcc 编译 .s 到可执行文件
|
||||
echo " 使用 gcc 汇编并链接 (超时 ${GCC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${GCC_TIMEOUT} "${GCC_NATIVE}" "${s_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static -g
|
||||
GCC_STATUS=$?
|
||||
if [ $GCC_STATUS -eq 124 ]; then
|
||||
echo -e "\e[31m错误: GCC 编译/链接 ${s_file} 超时\e[0m"
|
||||
is_passed=0
|
||||
elif [ $GCC_STATUS -ne 0 ]; then
|
||||
echo -e "\e[31m错误: GCC 汇编/链接 ${s_file} 失败,退出码: ${GCC_STATUS}\e[0m"
|
||||
is_passed=0
|
||||
fi
|
||||
|
||||
# 步骤 2: 只有当编译成功时才执行
|
||||
if [ "$is_passed" -eq 1 ]; then
|
||||
echo " 生成的可执行文件: ${executable_file}"
|
||||
echo " 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
|
||||
|
||||
exec_cmd="\"${executable_file}\""
|
||||
if [ -f "${input_file}" ]; then
|
||||
exec_cmd+=" < \"${input_file}\""
|
||||
fi
|
||||
exec_cmd+=" > \"${output_actual_file}\""
|
||||
|
||||
eval "timeout -s KILL ${EXEC_TIMEOUT} ${exec_cmd}"
|
||||
ACTUAL_RETURN_CODE=$?
|
||||
|
||||
if [ "$ACTUAL_RETURN_CODE" -eq 124 ]; then
|
||||
echo -e "\e[31m 执行超时: ${original_relative_path}.sy 运行超过 ${EXEC_TIMEOUT} 秒\e[0m"
|
||||
is_passed=0
|
||||
else
|
||||
if [ -f "${output_reference_file}" ]; then
|
||||
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
|
||||
|
||||
if [[ "$LAST_LINE_TRIMMED" =~ ^[-+]?[0-9]+$ ]]; then
|
||||
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
|
||||
EXPECTED_STDOUT_FILE="${TMP_DIR}/${base_name_from_s_file}.expected_stdout"
|
||||
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
|
||||
|
||||
if [ "$ACTUAL_RETURN_CODE" -eq "$EXPECTED_RETURN_CODE" ]; then
|
||||
echo -e "\e[32m 返回码测试成功: (${ACTUAL_RETURN_CODE}) 与期望值 (${EXPECTED_RETURN_CODE}) 匹配\e[0m"
|
||||
else
|
||||
echo -e "\e[31m 返回码测试失败: 期望: ${EXPECTED_RETURN_CODE}, 实际: ${ACTUAL_RETURN_CODE}\e[0m"
|
||||
is_passed=0
|
||||
fi
|
||||
|
||||
# --- 本次修改点: 使用 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 [ $ACTUAL_RETURN_CODE -ne 0 ]; then
|
||||
echo -e "\e[33m警告: 程序以非零状态 ${ACTUAL_RETURN_CODE} 退出 (纯输出比较模式)。\e[0m"
|
||||
fi
|
||||
|
||||
# --- 本次修改点: 使用 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"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$is_passed" -eq 1 ]; then
|
||||
((PASSED_CASES++))
|
||||
else
|
||||
FAILED_CASES_LIST+="${original_relative_path}.sy\n"
|
||||
fi
|
||||
echo ""
|
||||
done <<< "$s_files"
|
||||
|
||||
echo "========================================"
|
||||
echo "测试完成"
|
||||
echo "测试通过率: [${PASSED_CASES}/${TOTAL_CASES}]"
|
||||
|
||||
if [ -n "$FAILED_CASES_LIST" ]; then
|
||||
echo ""
|
||||
echo -e "\e[31m未通过的测例:\e[0m"
|
||||
echo -e "${FAILED_CASES_LIST}"
|
||||
fi
|
||||
|
||||
echo "========================================"
|
||||
|
||||
if [ "$PASSED_CASES" -eq "$TOTAL_CASES" ]; then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
296
script/runit-single.sh
Normal file
296
script/runit-single.sh
Normal file
@ -0,0 +1,296 @@
|
||||
#!/bin/bash
|
||||
|
||||
# runit-single.sh - 用于编译和测试单个或少量 SysY 程序的脚本
|
||||
# 模仿 runit.sh 的功能,但以具体文件路径作为输入。
|
||||
|
||||
# --- 配置区 ---
|
||||
# 请根据你的环境修改这些路径
|
||||
# 假设此脚本位于你的项目根目录或一个脚本目录中
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
|
||||
# 默认寻找项目根目录下的 build 和 lib
|
||||
BUILD_BIN_DIR="${SCRIPT_DIR}/../build/bin"
|
||||
LIB_DIR="${SCRIPT_DIR}/../lib"
|
||||
# 临时文件会存储在脚本所在目录的 tmp 子目录中
|
||||
TMP_DIR="${SCRIPT_DIR}/tmp"
|
||||
|
||||
# 定义编译器和模拟器
|
||||
SYSYC="${BUILD_BIN_DIR}/sysyc"
|
||||
GCC_RISCV64="riscv64-linux-gnu-gcc"
|
||||
QEMU_RISCV64="qemu-riscv64"
|
||||
|
||||
# --- 初始化变量 ---
|
||||
EXECUTE_MODE=false
|
||||
CLEAN_MODE=false
|
||||
SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒)
|
||||
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
|
||||
EXEC_TIMEOUT=5 # qemu 自动化执行超时 (秒)
|
||||
MAX_OUTPUT_LINES=50 # 对比失败时显示的最大行数
|
||||
SY_FILES=() # 存储用户提供的 .sy 文件列表
|
||||
PASSED_CASES=0
|
||||
FAILED_CASES_LIST=""
|
||||
|
||||
# --- 函数定义 ---
|
||||
show_help() {
|
||||
echo "用法: $0 [文件1.sy] [文件2.sy] ... [选项]"
|
||||
echo "编译并测试指定的 .sy 文件。"
|
||||
echo ""
|
||||
echo "如果找到对应的 .in/.out 文件,则进行自动化测试。否则,进入交互模式。"
|
||||
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)。"
|
||||
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 50)。"
|
||||
echo " -h, --help 显示此帮助信息并退出。"
|
||||
}
|
||||
|
||||
# --- 新增功能: 显示文件内容并根据行数截断 ---
|
||||
display_file_content() {
|
||||
local file_path="$1"
|
||||
local title="$2"
|
||||
local max_lines="$3"
|
||||
|
||||
if [ ! -f "$file_path" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "$title"
|
||||
local line_count
|
||||
line_count=$(wc -l < "$file_path")
|
||||
|
||||
if [ "$line_count" -gt "$max_lines" ]; then
|
||||
head -n "$max_lines" "$file_path"
|
||||
echo -e "\e[33m[... 输出已截断,共 ${line_count} 行 ...]\e[0m"
|
||||
else
|
||||
cat "$file_path"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- 参数解析 ---
|
||||
# 使用标准的 while 循环来健壮地处理任意顺序的参数
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-e|--executable)
|
||||
EXECUTE_MODE=true
|
||||
shift # 消耗选项
|
||||
;;
|
||||
-c|--clean)
|
||||
CLEAN_MODE=true
|
||||
shift # 消耗选项
|
||||
;;
|
||||
-sct)
|
||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift 2; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi
|
||||
;;
|
||||
-gct)
|
||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift 2; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi
|
||||
;;
|
||||
-et)
|
||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift 2; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi
|
||||
;;
|
||||
-ml|--max-lines)
|
||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi
|
||||
;;
|
||||
-h|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
-*) # 未知选项
|
||||
echo "未知选项: $1"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
*) # 其他参数被视为文件路径
|
||||
if [[ -f "$1" && "$1" == *.sy ]]; then
|
||||
SY_FILES+=("$1")
|
||||
else
|
||||
echo "警告: 无效文件或不是 .sy 文件,已忽略: $1"
|
||||
fi
|
||||
shift # 消耗文件参数
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
if ${CLEAN_MODE}; then
|
||||
echo "检测到 -c/--clean 选项,正在清空 ${TMP_DIR}..."
|
||||
if [ -d "${TMP_DIR}" ]; then
|
||||
rm -rf "${TMP_DIR}"/* 2>/dev/null
|
||||
echo "清理完成。"
|
||||
else
|
||||
echo "临时目录 ${TMP_DIR} 不存在,无需清理。"
|
||||
fi
|
||||
|
||||
if [ ${#SY_FILES[@]} -eq 0 ] && ! ${EXECUTE_MODE}; then
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- 主逻辑开始 ---
|
||||
if ! ${EXECUTE_MODE}; then
|
||||
echo "错误: 请提供 -e 或 --executable 选项来运行测试。"
|
||||
show_help
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ${#SY_FILES[@]} -eq 0 ]; then
|
||||
echo "错误: 未提供任何 .sy 文件作为输入。"
|
||||
show_help
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "${TMP_DIR}"
|
||||
TOTAL_CASES=${#SY_FILES[@]}
|
||||
|
||||
echo "SysY 单例测试运行器启动..."
|
||||
echo "超时设置: sysyc=${SYSYC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
|
||||
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
|
||||
echo ""
|
||||
|
||||
for sy_file in "${SY_FILES[@]}"; do
|
||||
is_passed=1
|
||||
base_name=$(basename "${sy_file}" .sy)
|
||||
source_dir=$(dirname "${sy_file}")
|
||||
|
||||
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"
|
||||
output_actual_file="${TMP_DIR}/${base_name}.actual_out"
|
||||
|
||||
echo "======================================================================"
|
||||
echo "正在处理: ${sy_file}"
|
||||
|
||||
# --- 本次修改点: 拷贝源文件到 tmp 目录 ---
|
||||
echo " 拷贝源文件到 ${TMP_DIR}..."
|
||||
cp "${sy_file}" "${TMP_DIR}/$(basename "${sy_file}")"
|
||||
if [ -f "${input_file}" ]; then
|
||||
cp "${input_file}" "${TMP_DIR}/$(basename "${input_file}")"
|
||||
fi
|
||||
if [ -f "${output_reference_file}" ]; then
|
||||
cp "${output_reference_file}" "${TMP_DIR}/$(basename "${output_reference_file}")"
|
||||
fi
|
||||
|
||||
# 步骤 1: sysyc 编译
|
||||
echo " 使用 sysyc 编译 (超时 ${SYSYC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" > "${ir_file}"
|
||||
SYSYC_STATUS=$?
|
||||
if [ $SYSYC_STATUS -eq 124 ]; then
|
||||
echo -e "\e[31m错误: SysY 编译 ${sy_file} IR超时\e[0m"
|
||||
is_passed=0
|
||||
elif [ $SYSYC_STATUS -ne 0 ]; then
|
||||
echo -e "\e[31m错误: SysY 编译 ${sy_file} IR失败,退出码: ${SYSYC_STATUS}\e[0m"
|
||||
is_passed=0
|
||||
fi
|
||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file}"
|
||||
if [ $? -ne 0 ]; then
|
||||
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
|
||||
echo " 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "\e[31m错误: GCC 编译失败或超时。\e[0m"
|
||||
is_passed=0
|
||||
fi
|
||||
fi
|
||||
|
||||
# 步骤 3: 执行与测试
|
||||
if [ "$is_passed" -eq 1 ]; then
|
||||
# 检查是自动化测试还是交互模式
|
||||
if [ -f "${input_file}" ] || [ -f "${output_reference_file}" ]; then
|
||||
# --- 自动化测试模式 ---
|
||||
echo " 检测到 .in/.out 文件,进入自动化测试模式..."
|
||||
echo " 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
|
||||
|
||||
exec_cmd="${QEMU_RISCV64} \"${executable_file}\""
|
||||
[ -f "${input_file}" ] && exec_cmd+=" < \"${input_file}\""
|
||||
exec_cmd+=" > \"${output_actual_file}\""
|
||||
|
||||
eval "timeout -s KILL ${EXEC_TIMEOUT} ${exec_cmd}"
|
||||
ACTUAL_RETURN_CODE=$?
|
||||
|
||||
if [ "$ACTUAL_RETURN_CODE" -eq 124 ]; then
|
||||
echo -e "\e[31m 执行超时。\e[0m"
|
||||
is_passed=0
|
||||
else
|
||||
if [ -f "${output_reference_file}" ]; then
|
||||
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
|
||||
if [[ "$LAST_LINE_TRIMMED" =~ ^[-+]?[0-9]+$ ]]; then
|
||||
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
|
||||
EXPECTED_STDOUT_FILE="${TMP_DIR}/${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 <(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 <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
|
||||
echo -e "\e[32m 标准输出测试成功。\e[0m"
|
||||
else
|
||||
echo -e "\e[31m 标准输出测试失败。\e[0m"
|
||||
is_passed=0
|
||||
display_file_content "${output_reference_file}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
echo -e " \e[36m----------------\e[0m"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# --- 交互模式 ---
|
||||
echo -e "\e[33m"
|
||||
echo " **********************************************************"
|
||||
echo " ** 未找到 .in 或 .out 文件,进入交互模式。 **"
|
||||
echo " ** 程序即将运行,你可以直接在终端中输入。 **"
|
||||
echo " ** 按下 Ctrl+D (EOF) 或以其他方式结束程序以继续。 **"
|
||||
echo " **********************************************************"
|
||||
echo -e "\e[0m"
|
||||
"${QEMU_RISCV64}" "${executable_file}"
|
||||
INTERACTIVE_RET_CODE=$?
|
||||
echo -e "\e[33m\n 交互模式执行完毕,程序返回码: ${INTERACTIVE_RET_CODE}\e[0m"
|
||||
echo " 注意: 交互模式的结果未经验证。"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$is_passed" -eq 1 ]; then
|
||||
echo -e "\e[32m状态: 通过\e[0m"
|
||||
((PASSED_CASES++))
|
||||
else
|
||||
echo -e "\e[31m状态: 失败\e[0m"
|
||||
FAILED_CASES_LIST+="${sy_file}\n"
|
||||
fi
|
||||
done
|
||||
|
||||
# --- 打印最终总结 ---
|
||||
echo "======================================================================"
|
||||
echo "所有测试完成"
|
||||
echo "测试通过率: [${PASSED_CASES}/${TOTAL_CASES}]"
|
||||
|
||||
if [ -n "$FAILED_CASES_LIST" ]; then
|
||||
echo ""
|
||||
echo -e "\e[31m未通过的测例:\e[0m"
|
||||
echo -e "${FAILED_CASES_LIST}"
|
||||
fi
|
||||
|
||||
echo "======================================================================"
|
||||
|
||||
if [ "$PASSED_CASES" -eq "$TOTAL_CASES" ]; then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
@ -9,7 +9,7 @@ TESTDATA_DIR="${SCRIPT_DIR}/../testdata"
|
||||
BUILD_BIN_DIR="${SCRIPT_DIR}/../build/bin"
|
||||
LIB_DIR="${SCRIPT_DIR}/../lib"
|
||||
# TMP_DIR="${SCRIPT_DIR}/tmp"
|
||||
TMP_DIR="/home/ladev987/paraComp/debug/share_folder/tmp"
|
||||
TMP_DIR="${SCRIPT_DIR}/tmp"
|
||||
|
||||
# 定义编译器和模拟器
|
||||
SYSYC="${BUILD_BIN_DIR}/sysyc"
|
||||
@ -21,6 +21,8 @@ EXECUTE_MODE=false
|
||||
SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒)
|
||||
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
|
||||
EXEC_TIMEOUT=5 # qemu 执行超时 (秒)
|
||||
MAX_OUTPUT_LINES=50 # 对比失败时显示的最大行数
|
||||
TEST_SETS=() # 用于存储要运行的测试集
|
||||
TOTAL_CASES=0
|
||||
PASSED_CASES=0
|
||||
FAILED_CASES_LIST="" # 用于存储未通过的测例列表
|
||||
@ -33,12 +35,36 @@ show_help() {
|
||||
echo "选项:"
|
||||
echo " -e, --executable 编译为可执行文件并运行测试。"
|
||||
echo " -c, --clean 清理 'tmp' 目录下的所有生成文件。"
|
||||
echo " -set [f|h|p|all]... 指定要运行的测试集 (functional, h_functional, performance)。可多选,默认为 all。"
|
||||
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 10)。"
|
||||
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
||||
echo " -et N 设置 qemu 执行超时为 N 秒 (默认: 5)。"
|
||||
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 50)。"
|
||||
echo " -h, --help 显示此帮助信息并退出。"
|
||||
}
|
||||
|
||||
# 显示文件内容并根据行数截断的函数
|
||||
display_file_content() {
|
||||
local file_path="$1"
|
||||
local title="$2"
|
||||
local max_lines="$3"
|
||||
|
||||
if [ ! -f "$file_path" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "$title"
|
||||
local line_count
|
||||
line_count=$(wc -l < "$file_path")
|
||||
|
||||
if [ "$line_count" -gt "$max_lines" ]; then
|
||||
head -n "$max_lines" "$file_path"
|
||||
echo -e "\e[33m[... 输出已截断,共 ${line_count} 行 ...]\e[0m"
|
||||
else
|
||||
cat "$file_path"
|
||||
fi
|
||||
}
|
||||
|
||||
# 清理临时文件的函数
|
||||
clean_tmp() {
|
||||
echo "正在清理临时目录: ${TMP_DIR}"
|
||||
@ -53,19 +79,31 @@ while [[ "$#" -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-e|--executable)
|
||||
EXECUTE_MODE=true
|
||||
shift
|
||||
;;
|
||||
-c|--clean)
|
||||
clean_tmp
|
||||
exit 0
|
||||
;;
|
||||
-set)
|
||||
shift # 移过 '-set'
|
||||
# 消耗所有后续参数直到遇到下一个选项
|
||||
while [[ "$#" -gt 0 && ! "$1" =~ ^- ]]; do
|
||||
TEST_SETS+=("$1")
|
||||
shift
|
||||
done
|
||||
;;
|
||||
-sct)
|
||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi
|
||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift 2; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi
|
||||
;;
|
||||
-gct)
|
||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi
|
||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift 2; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi
|
||||
;;
|
||||
-et)
|
||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi
|
||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift 2; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi
|
||||
;;
|
||||
-ml|--max-lines)
|
||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi
|
||||
;;
|
||||
-h|--help)
|
||||
show_help
|
||||
@ -77,24 +115,54 @@ while [[ "$#" -gt 0 ]]; do
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# --- 本次修改点: 根据 -set 参数构建查找路径 ---
|
||||
declare -A SET_MAP
|
||||
SET_MAP[f]="functional"
|
||||
SET_MAP[h]="h_functional"
|
||||
SET_MAP[p]="performance"
|
||||
|
||||
SEARCH_PATHS=()
|
||||
|
||||
# 如果未指定测试集,或指定了 'all',则搜索所有目录
|
||||
if [ ${#TEST_SETS[@]} -eq 0 ] || [[ " ${TEST_SETS[@]} " =~ " all " ]]; then
|
||||
SEARCH_PATHS+=("${TESTDATA_DIR}")
|
||||
else
|
||||
for set in "${TEST_SETS[@]}"; do
|
||||
if [[ -v SET_MAP[$set] ]]; then
|
||||
SEARCH_PATHS+=("${TESTDATA_DIR}/${SET_MAP[$set]}")
|
||||
else
|
||||
echo -e "\e[33m警告: 未知的测试集 '$set',已忽略。\e[0m"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# 如果没有有效的搜索路径,则退出
|
||||
if [ ${#SEARCH_PATHS[@]} -eq 0 ]; then
|
||||
echo -e "\e[31m错误: 没有找到有效的测试集目录,测试中止。\e[0m"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "SysY 测试运行器启动..."
|
||||
echo "输入目录: ${TESTDATA_DIR}"
|
||||
echo "输入目录: ${SEARCH_PATHS[@]}"
|
||||
echo "临时目录: ${TMP_DIR}"
|
||||
echo "执行模式: ${EXECUTE_MODE}"
|
||||
if ${EXECUTE_MODE}; then
|
||||
echo "超时设置: sysyc=${SYSYC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
|
||||
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- 修改点: 查找所有 .sy 文件并按文件名前缀数字排序 ---
|
||||
sy_files=$(find "${TESTDATA_DIR}" -name "*.sy" | sort -V)
|
||||
# 使用构建好的路径查找 .sy 文件并排序
|
||||
sy_files=$(find "${SEARCH_PATHS[@]}" -name "*.sy" | sort -V)
|
||||
if [ -z "$sy_files" ]; then
|
||||
echo "在指定目录中未找到任何 .sy 文件。"
|
||||
exit 0
|
||||
fi
|
||||
TOTAL_CASES=$(echo "$sy_files" | wc -w)
|
||||
|
||||
# --- 本次修复: 使用 here-string (<<<) 代替管道 (|) 来避免子 shell 问题 ---
|
||||
# 这样可以确保循环内的 PASSED_CASES 变量修改在循环结束后依然有效
|
||||
# --- 修复: 使用 here-string (<<<) 代替管道 (|) 来避免子 shell 问题 ---
|
||||
while IFS= read -r sy_file; do
|
||||
is_passed=1 # 1 表示通过, 0 表示失败
|
||||
|
||||
@ -111,7 +179,7 @@ while IFS= read -r sy_file; do
|
||||
|
||||
# 步骤 1: 使用 sysyc 编译 .sy 到 .s
|
||||
echo " 使用 sysyc 编译 (超时 ${SYSYC_TIMEOUT}s)..."
|
||||
timeout ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file}"
|
||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file}"
|
||||
SYSYC_STATUS=$?
|
||||
if [ $SYSYC_STATUS -eq 124 ]; then
|
||||
echo -e "\e[31m错误: SysY 编译 ${sy_file} 超时\e[0m"
|
||||
@ -125,7 +193,7 @@ while IFS= read -r sy_file; do
|
||||
if ${EXECUTE_MODE} && [ "$is_passed" -eq 1 ]; then
|
||||
# 步骤 2: 使用 riscv64-linux-gnu-gcc 编译 .s 到可执行文件
|
||||
echo " 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
|
||||
timeout ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
|
||||
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
|
||||
GCC_STATUS=$?
|
||||
if [ $GCC_STATUS -eq 124 ]; then
|
||||
echo -e "\e[31m错误: GCC 编译 ${assembly_file} 超时\e[0m"
|
||||
@ -136,11 +204,9 @@ while IFS= read -r sy_file; do
|
||||
fi
|
||||
elif ! ${EXECUTE_MODE}; then
|
||||
echo " 跳过执行模式。仅生成汇编文件。"
|
||||
# 如果只编译不执行,只要编译成功就算通过
|
||||
if [ "$is_passed" -eq 1 ]; then
|
||||
((PASSED_CASES++))
|
||||
else
|
||||
# --- 本次修改点 ---
|
||||
FAILED_CASES_LIST+="${relative_path_no_ext}.sy\n"
|
||||
fi
|
||||
echo ""
|
||||
@ -151,22 +217,19 @@ while IFS= read -r sy_file; do
|
||||
if [ "$is_passed" -eq 1 ]; then
|
||||
echo " 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
|
||||
|
||||
# 准备执行命令
|
||||
exec_cmd="${QEMU_RISCV64} \"${executable_file}\""
|
||||
if [ -f "${input_file}" ]; then
|
||||
exec_cmd+=" < \"${input_file}\""
|
||||
fi
|
||||
exec_cmd+=" > \"${output_actual_file}\""
|
||||
|
||||
# 执行并捕获返回码
|
||||
eval "timeout ${EXEC_TIMEOUT} ${exec_cmd}"
|
||||
eval "timeout -s KILL ${EXEC_TIMEOUT} ${exec_cmd}"
|
||||
ACTUAL_RETURN_CODE=$?
|
||||
|
||||
if [ "$ACTUAL_RETURN_CODE" -eq 124 ]; then
|
||||
echo -e "\e[31m 执行超时: ${sy_file} 运行超过 ${EXEC_TIMEOUT} 秒\e[0m"
|
||||
is_passed=0
|
||||
else
|
||||
# 检查是否存在 .out 文件以进行比较
|
||||
if [ -f "${output_reference_file}" ]; then
|
||||
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
|
||||
|
||||
@ -175,70 +238,56 @@ while IFS= read -r sy_file; do
|
||||
EXPECTED_STDOUT_FILE="${TMP_DIR}/${output_base_name}_sysyc_riscv64.expected_stdout"
|
||||
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
|
||||
|
||||
# 比较返回码
|
||||
if [ "$ACTUAL_RETURN_CODE" -eq "$EXPECTED_RETURN_CODE" ]; then
|
||||
echo -e "\e[32m 返回码测试成功: (${ACTUAL_RETURN_CODE}) 与期望值 (${EXPECTED_RETURN_CODE}) 匹配\e[0m"
|
||||
else
|
||||
echo -e "\e[31m 返回码测试失败: 期望: ${EXPECTED_RETURN_CODE}, 实际: ${ACTUAL_RETURN_CODE}\e[0m"
|
||||
is_passed=0
|
||||
fi
|
||||
# 比较标准输出
|
||||
if diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
||||
echo -e "\e[32m 标准输出测试成功\e[0m"
|
||||
else
|
||||
|
||||
if ! diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
||||
echo -e "\e[31m 标准输出测试失败\e[0m"
|
||||
is_passed=0
|
||||
echo -e " \e[36m---------- 期望输出 ----------\e[0m"
|
||||
cat "${EXPECTED_STDOUT_FILE}"
|
||||
echo -e " \e[36m---------- 实际输出 ----------\e[0m"
|
||||
cat "${output_actual_file}"
|
||||
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
display_file_content "${output_actual_file}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
echo -e " \e[36m------------------------------\e[0m"
|
||||
fi
|
||||
else
|
||||
# 纯标准输出比较
|
||||
if [ $ACTUAL_RETURN_CODE -ne 0 ]; then
|
||||
echo -e "\e[33m警告: 程序以非零状态 ${ACTUAL_RETURN_CODE} 退出 (纯输出比较模式)。\e[0m"
|
||||
fi
|
||||
if diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${output_reference_file}") >/dev/null 2>&1; then
|
||||
|
||||
if diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
|
||||
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
|
||||
else
|
||||
echo -e "\e[31m 失败: 输出不匹配\e[0m"
|
||||
is_passed=0
|
||||
echo -e " \e[36m---------- 期望输出 ----------\e[0m"
|
||||
cat "${output_reference_file}"
|
||||
echo -e " \e[36m---------- 实际输出 ----------\e[0m"
|
||||
cat "${output_actual_file}"
|
||||
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
display_file_content "${output_actual_file}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
echo -e " \e[36m------------------------------\e[0m"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# 没有 .out 文件,只报告返回码
|
||||
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# 更新通过用例计数
|
||||
# --- 本次修改点 ---
|
||||
if [ "$is_passed" -eq 1 ]; then
|
||||
((PASSED_CASES++))
|
||||
else
|
||||
# 将失败的用例名称添加到列表中
|
||||
FAILED_CASES_LIST+="${relative_path_no_ext}.sy\n"
|
||||
fi
|
||||
echo "" # 添加空行以提高可读性
|
||||
echo ""
|
||||
done <<< "$sy_files"
|
||||
|
||||
# --- 新增功能: 打印最终总结 ---
|
||||
echo "========================================"
|
||||
echo "测试完成"
|
||||
echo "测试通过率: [${PASSED_CASES}/${TOTAL_CASES}]"
|
||||
|
||||
# --- 本次修改点: 打印未通过的测例列表 ---
|
||||
if [ -n "$FAILED_CASES_LIST" ]; then
|
||||
echo ""
|
||||
echo -e "\e[31m未通过的测例:\e[0m"
|
||||
# 使用 -e 来解释换行符 \n
|
||||
echo -e "${FAILED_CASES_LIST}"
|
||||
fi
|
||||
|
||||
@ -1,160 +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)) {
|
||||
std::cerr << "Warning: GlobalValue dimension handling needs explicit implementation for GEP expansion. Skipping GEP for: ";
|
||||
SysYPrinter::printValue(globalValue);
|
||||
std::cerr << "\n";
|
||||
++it;
|
||||
continue;
|
||||
} 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 或 StoreInst,indices 为空
|
||||
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
|
||||
@ -1,51 +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
|
||||
SysYIROptPre.cpp
|
||||
SysYIRAnalyser.cpp
|
||||
# DeadCodeElimination.cpp
|
||||
AddressCalculationExpansion.cpp
|
||||
# Mem2Reg.cpp
|
||||
# Reg2Mem.cpp
|
||||
RISCv64Backend.cpp
|
||||
RISCv64ISel.cpp
|
||||
RISCv64RegAlloc.cpp
|
||||
RISCv64AsmPrinter.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)
|
||||
@ -1,73 +0,0 @@
|
||||
#include "RISCv64Backend.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include "RISCv64RegAlloc.h"
|
||||
#include "RISCv64AsmPrinter.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 顶层入口
|
||||
std::string RISCv64CodeGen::code_gen() {
|
||||
return module_gen();
|
||||
}
|
||||
|
||||
// 模块级代码生成 (移植自原文件,处理.data段和驱动函数生成)
|
||||
std::string RISCv64CodeGen::module_gen() {
|
||||
std::stringstream ss;
|
||||
|
||||
// 1. 处理全局变量 (.data段)
|
||||
if (!module->getGlobals().empty()) {
|
||||
ss << ".data\n";
|
||||
for (const auto& global : module->getGlobals()) {
|
||||
ss << ".globl " << global->getName() << "\n";
|
||||
ss << global->getName() << ":\n";
|
||||
const auto& init_values = global->getInitValues();
|
||||
for (size_t i = 0; i < init_values.getValues().size(); ++i) {
|
||||
auto val = init_values.getValues()[i];
|
||||
auto count = init_values.getNumbers()[i];
|
||||
if (auto constant = dynamic_cast<ConstantValue*>(val)) {
|
||||
for (unsigned j = 0; j < count; ++j) {
|
||||
if (constant->isInt()) {
|
||||
ss << " .word " << constant->getInt() << "\n";
|
||||
} else {
|
||||
float f = constant->getFloat();
|
||||
uint32_t float_bits = *(uint32_t*)&f;
|
||||
ss << " .word " << float_bits << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 处理函数 (.text段)
|
||||
if (!module->getFunctions().empty()) {
|
||||
ss << ".text\n";
|
||||
for (const auto& func_pair : module->getFunctions()) {
|
||||
if (func_pair.second.get()) {
|
||||
ss << function_gen(func_pair.second.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
// function_gen 现在是新的、模块化的处理流水线
|
||||
std::string RISCv64CodeGen::function_gen(Function* func) {
|
||||
// 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers)
|
||||
RISCv64ISel isel;
|
||||
std::unique_ptr<MachineFunction> mfunc = isel.runOnFunction(func);
|
||||
|
||||
// 阶段 2: 寄存器分配 (包含栈帧布局, 活跃性分析, 图着色, spill/rewrite)
|
||||
RISCv64RegAlloc reg_alloc(mfunc.get());
|
||||
reg_alloc.run();
|
||||
|
||||
// 阶段 3: 代码发射 (LLIR with physical regs -> Assembly Text)
|
||||
std::stringstream ss;
|
||||
RISCv64AsmPrinter printer(mfunc.get());
|
||||
printer.run(ss);
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@ -1,635 +0,0 @@
|
||||
#include "RISCv64ISel.h"
|
||||
#include <stdexcept>
|
||||
#include <set>
|
||||
#include <functional>
|
||||
#include <cmath> // For std::fabs
|
||||
#include <limits> // For std::numeric_limits
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// DAG节点定义 (内部实现)
|
||||
struct RISCv64ISel::DAGNode {
|
||||
enum NodeKind { CONSTANT, LOAD, STORE, BINARY, CALL, RETURN, BRANCH, ALLOCA_ADDR, UNARY, MEMSET };
|
||||
NodeKind kind;
|
||||
Value* value = nullptr;
|
||||
std::vector<DAGNode*> operands;
|
||||
std::vector<DAGNode*> users;
|
||||
DAGNode(NodeKind k) : kind(k) {}
|
||||
};
|
||||
|
||||
RISCv64ISel::RISCv64ISel() : vreg_counter(0), local_label_counter(0) {}
|
||||
|
||||
// 为一个IR Value获取或分配一个新的虚拟寄存器
|
||||
unsigned RISCv64ISel::getVReg(Value* val) {
|
||||
if (!val) {
|
||||
throw std::runtime_error("Cannot get vreg for a null Value.");
|
||||
}
|
||||
if (vreg_map.find(val) == vreg_map.end()) {
|
||||
if (vreg_counter == 0) {
|
||||
vreg_counter = 1; // vreg 0 保留
|
||||
}
|
||||
vreg_map[val] = vreg_counter++;
|
||||
}
|
||||
return vreg_map.at(val);
|
||||
}
|
||||
|
||||
// 主入口函数
|
||||
std::unique_ptr<MachineFunction> RISCv64ISel::runOnFunction(Function* func) {
|
||||
F = func;
|
||||
if (!F) return nullptr;
|
||||
MFunc = std::make_unique<MachineFunction>(F, this);
|
||||
vreg_map.clear();
|
||||
bb_map.clear();
|
||||
vreg_counter = 0;
|
||||
local_label_counter = 0;
|
||||
|
||||
select();
|
||||
|
||||
return std::move(MFunc);
|
||||
}
|
||||
|
||||
// 指令选择主流程
|
||||
void RISCv64ISel::select() {
|
||||
for (const auto& bb_ptr : F->getBasicBlocks()) {
|
||||
auto mbb = std::make_unique<MachineBasicBlock>(bb_ptr->getName(), MFunc.get());
|
||||
bb_map[bb_ptr.get()] = mbb.get();
|
||||
MFunc->addBlock(std::move(mbb));
|
||||
}
|
||||
|
||||
if (F->getEntryBlock()) {
|
||||
for (auto* arg_alloca : F->getEntryBlock()->getArguments()) {
|
||||
getVReg(arg_alloca);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& bb_ptr : F->getBasicBlocks()) {
|
||||
selectBasicBlock(bb_ptr.get());
|
||||
}
|
||||
|
||||
for (const auto& bb_ptr : F->getBasicBlocks()) {
|
||||
CurMBB = bb_map.at(bb_ptr.get());
|
||||
for (auto succ : bb_ptr->getSuccessors()) {
|
||||
CurMBB->successors.push_back(bb_map.at(succ));
|
||||
}
|
||||
for (auto pred : bb_ptr->getPredecessors()) {
|
||||
CurMBB->predecessors.push_back(bb_map.at(pred));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理单个基本块
|
||||
void RISCv64ISel::selectBasicBlock(BasicBlock* bb) {
|
||||
CurMBB = bb_map.at(bb);
|
||||
auto dag = build_dag(bb);
|
||||
|
||||
std::map<Value*, DAGNode*> value_to_node;
|
||||
for(const auto& node : dag) {
|
||||
if (node->value) {
|
||||
value_to_node[node->value] = node.get();
|
||||
}
|
||||
}
|
||||
|
||||
std::set<DAGNode*> selected_nodes;
|
||||
std::function<void(DAGNode*)> select_recursive =
|
||||
[&](DAGNode* node) {
|
||||
if (!node || selected_nodes.count(node)) return;
|
||||
for (auto operand : node->operands) {
|
||||
select_recursive(operand);
|
||||
}
|
||||
selectNode(node);
|
||||
selected_nodes.insert(node);
|
||||
};
|
||||
|
||||
for (const auto& inst_ptr : bb->getInstructions()) {
|
||||
DAGNode* node_to_select = nullptr;
|
||||
if (value_to_node.count(inst_ptr.get())) {
|
||||
node_to_select = value_to_node.at(inst_ptr.get());
|
||||
} else {
|
||||
for(const auto& node : dag) {
|
||||
if(node->value == inst_ptr.get()) {
|
||||
node_to_select = node.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(node_to_select) {
|
||||
select_recursive(node_to_select);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 核心函数:为DAG节点选择并生成MachineInstr (忠实移植版)
|
||||
void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
switch (node->kind) {
|
||||
case DAGNode::CONSTANT:
|
||||
case DAGNode::ALLOCA_ADDR:
|
||||
if (node->value) getVReg(node->value);
|
||||
break;
|
||||
|
||||
case DAGNode::LOAD: {
|
||||
auto dest_vreg = getVReg(node->value);
|
||||
Value* ptr_val = node->operands[0]->value;
|
||||
|
||||
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_LOAD);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(getVReg(alloca)));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_val)) {
|
||||
auto addr_vreg = getNewVReg();
|
||||
auto la = std::make_unique<MachineInstr>(RVOpcodes::LA);
|
||||
la->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
||||
la->addOperand(std::make_unique<LabelOperand>(global->getName()));
|
||||
CurMBB->addInstruction(std::move(la));
|
||||
|
||||
auto lw = std::make_unique<MachineInstr>(RVOpcodes::LW);
|
||||
lw->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
lw->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(addr_vreg),
|
||||
std::make_unique<ImmOperand>(0)
|
||||
));
|
||||
CurMBB->addInstruction(std::move(lw));
|
||||
} else {
|
||||
auto ptr_vreg = getVReg(ptr_val);
|
||||
auto lw = std::make_unique<MachineInstr>(RVOpcodes::LW);
|
||||
lw->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
lw->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(ptr_vreg),
|
||||
std::make_unique<ImmOperand>(0)
|
||||
));
|
||||
CurMBB->addInstruction(std::move(lw));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::STORE: {
|
||||
Value* val_to_store = node->operands[0]->value;
|
||||
Value* ptr_val = node->operands[1]->value;
|
||||
|
||||
if (auto val_const = dynamic_cast<ConstantValue*>(val_to_store)) {
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(getVReg(val_const)));
|
||||
li->addOperand(std::make_unique<ImmOperand>(val_const->getInt()));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
}
|
||||
auto val_vreg = getVReg(val_to_store);
|
||||
|
||||
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_STORE);
|
||||
instr->addOperand(std::make_unique<RegOperand>(val_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(getVReg(alloca)));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_val)) {
|
||||
auto addr_vreg = getNewVReg();
|
||||
auto la = std::make_unique<MachineInstr>(RVOpcodes::LA);
|
||||
la->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
||||
la->addOperand(std::make_unique<LabelOperand>(global->getName()));
|
||||
CurMBB->addInstruction(std::move(la));
|
||||
|
||||
auto sw = std::make_unique<MachineInstr>(RVOpcodes::SW);
|
||||
sw->addOperand(std::make_unique<RegOperand>(val_vreg));
|
||||
sw->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(addr_vreg),
|
||||
std::make_unique<ImmOperand>(0)
|
||||
));
|
||||
CurMBB->addInstruction(std::move(sw));
|
||||
} else {
|
||||
auto ptr_vreg = getVReg(ptr_val);
|
||||
auto sw = std::make_unique<MachineInstr>(RVOpcodes::SW);
|
||||
sw->addOperand(std::make_unique<RegOperand>(val_vreg));
|
||||
sw->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(ptr_vreg),
|
||||
std::make_unique<ImmOperand>(0)
|
||||
));
|
||||
CurMBB->addInstruction(std::move(sw));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::BINARY: {
|
||||
auto bin = dynamic_cast<BinaryInst*>(node->value);
|
||||
Value* lhs = bin->getLhs();
|
||||
Value* rhs = bin->getRhs();
|
||||
|
||||
auto load_val_if_const = [&](Value* val) {
|
||||
if (auto c = dynamic_cast<ConstantValue*>(val)) {
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(getVReg(c)));
|
||||
li->addOperand(std::make_unique<ImmOperand>(c->getInt()));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
}
|
||||
};
|
||||
load_val_if_const(lhs);
|
||||
load_val_if_const(rhs);
|
||||
|
||||
auto dest_vreg = getVReg(bin);
|
||||
auto lhs_vreg = getVReg(lhs);
|
||||
auto rhs_vreg = getVReg(rhs);
|
||||
|
||||
if (bin->getKind() == BinaryInst::kAdd) {
|
||||
if (auto rhs_const = dynamic_cast<ConstantValue*>(rhs)) {
|
||||
if (rhs_const->getInt() >= -2048 && rhs_const->getInt() < 2048) {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::ADDIW);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<ImmOperand>(rhs_const->getInt()));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (bin->getKind()) {
|
||||
case BinaryInst::kAdd: {
|
||||
RVOpcodes opcode = (lhs->getType()->isPointer() || rhs->getType()->isPointer()) ? RVOpcodes::ADD : RVOpcodes::ADDW;
|
||||
auto instr = std::make_unique<MachineInstr>(opcode);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case BinaryInst::kSub: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case BinaryInst::kMul: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::MULW);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kDiv: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::DIVW);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kRem: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::REMW);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case BinaryInst::kICmpEQ: {
|
||||
auto sub = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
|
||||
sub->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
sub->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
sub->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(sub));
|
||||
|
||||
auto seqz = std::make_unique<MachineInstr>(RVOpcodes::SEQZ);
|
||||
seqz->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
seqz->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
CurMBB->addInstruction(std::move(seqz));
|
||||
break;
|
||||
}
|
||||
case BinaryInst::kICmpNE: {
|
||||
auto sub = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
|
||||
sub->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
sub->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
sub->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(sub));
|
||||
|
||||
auto snez = std::make_unique<MachineInstr>(RVOpcodes::SNEZ);
|
||||
snez->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
snez->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
CurMBB->addInstruction(std::move(snez));
|
||||
break;
|
||||
}
|
||||
case BinaryInst::kICmpLT: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SLT);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case BinaryInst::kICmpGT: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SLT);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case BinaryInst::kICmpLE: {
|
||||
auto slt = std::make_unique<MachineInstr>(RVOpcodes::SLT);
|
||||
slt->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
slt->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
slt->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
CurMBB->addInstruction(std::move(slt));
|
||||
|
||||
auto xori = std::make_unique<MachineInstr>(RVOpcodes::XORI);
|
||||
xori->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
xori->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
xori->addOperand(std::make_unique<ImmOperand>(1));
|
||||
CurMBB->addInstruction(std::move(xori));
|
||||
break;
|
||||
}
|
||||
case BinaryInst::kICmpGE: {
|
||||
auto slt = std::make_unique<MachineInstr>(RVOpcodes::SLT);
|
||||
slt->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
slt->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
slt->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(slt));
|
||||
|
||||
auto xori = std::make_unique<MachineInstr>(RVOpcodes::XORI);
|
||||
xori->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
xori->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
xori->addOperand(std::make_unique<ImmOperand>(1));
|
||||
CurMBB->addInstruction(std::move(xori));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("Unsupported binary instruction in ISel");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::UNARY: {
|
||||
auto unary = dynamic_cast<UnaryInst*>(node->value);
|
||||
auto dest_vreg = getVReg(unary);
|
||||
auto src_vreg = getVReg(unary->getOperand());
|
||||
|
||||
switch (unary->getKind()) {
|
||||
case UnaryInst::kNeg: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||
instr->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case UnaryInst::kNot: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SEQZ);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("Unsupported unary instruction in ISel");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::CALL: {
|
||||
auto call = dynamic_cast<CallInst*>(node->value);
|
||||
for (size_t i = 0; i < node->operands.size() && i < 8; ++i) {
|
||||
DAGNode* arg_node = node->operands[i];
|
||||
auto arg_preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + i);
|
||||
|
||||
if (arg_node->kind == DAGNode::CONSTANT) {
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(arg_node->value)) {
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(arg_preg));
|
||||
li->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
}
|
||||
} else {
|
||||
auto src_vreg = getVReg(arg_node->value);
|
||||
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
mv->addOperand(std::make_unique<RegOperand>(arg_preg));
|
||||
mv->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
CurMBB->addInstruction(std::move(mv));
|
||||
}
|
||||
}
|
||||
|
||||
auto call_instr = std::make_unique<MachineInstr>(RVOpcodes::CALL);
|
||||
call_instr->addOperand(std::make_unique<LabelOperand>(call->getCallee()->getName()));
|
||||
CurMBB->addInstruction(std::move(call_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;
|
||||
}
|
||||
|
||||
case DAGNode::RETURN: {
|
||||
auto ret_inst_ir = dynamic_cast<ReturnInst*>(node->value);
|
||||
if (ret_inst_ir && ret_inst_ir->hasReturnValue()) {
|
||||
Value* ret_val = ret_inst_ir->getReturnValue();
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(ret_val)) {
|
||||
auto li_instr = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
|
||||
li_instr->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
|
||||
CurMBB->addInstruction(std::move(li_instr));
|
||||
} else {
|
||||
auto mv_instr = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
mv_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
|
||||
mv_instr->addOperand(std::make_unique<RegOperand>(getVReg(ret_val)));
|
||||
CurMBB->addInstruction(std::move(mv_instr));
|
||||
}
|
||||
}
|
||||
auto ret_mi = std::make_unique<MachineInstr>(RVOpcodes::RET);
|
||||
CurMBB->addInstruction(std::move(ret_mi));
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::BRANCH: {
|
||||
if (auto cond_br = dynamic_cast<CondBrInst*>(node->value)) {
|
||||
auto br_instr = std::make_unique<MachineInstr>(RVOpcodes::BNE);
|
||||
br_instr->addOperand(std::make_unique<RegOperand>(getVReg(cond_br->getCondition())));
|
||||
br_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||
br_instr->addOperand(std::make_unique<LabelOperand>(cond_br->getThenBlock()->getName()));
|
||||
CurMBB->addInstruction(std::move(br_instr));
|
||||
} else if (auto uncond_br = dynamic_cast<UncondBrInst*>(node->value)) {
|
||||
auto j_instr = std::make_unique<MachineInstr>(RVOpcodes::J);
|
||||
j_instr->addOperand(std::make_unique<LabelOperand>(uncond_br->getBlock()->getName()));
|
||||
CurMBB->addInstruction(std::move(j_instr));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::MEMSET: {
|
||||
auto memset = dynamic_cast<MemsetInst*>(node->value);
|
||||
auto r_dest_addr = getVReg(memset->getPointer());
|
||||
auto r_num_bytes = getVReg(memset->getSize());
|
||||
auto r_value_byte = getVReg(memset->getValue());
|
||||
auto r_counter = getNewVReg();
|
||||
auto r_end_addr = getNewVReg();
|
||||
auto r_current_addr = getNewVReg();
|
||||
auto r_temp_val = getNewVReg();
|
||||
|
||||
auto add_instr = [&](RVOpcodes op, unsigned rd, unsigned rs1, unsigned rs2) {
|
||||
auto i = std::make_unique<MachineInstr>(op);
|
||||
i->addOperand(std::make_unique<RegOperand>(rd));
|
||||
i->addOperand(std::make_unique<RegOperand>(rs1));
|
||||
i->addOperand(std::make_unique<RegOperand>(rs2));
|
||||
CurMBB->addInstruction(std::move(i));
|
||||
};
|
||||
auto addi_instr = [&](RVOpcodes op, unsigned rd, unsigned rs1, int64_t imm) {
|
||||
auto i = std::make_unique<MachineInstr>(op);
|
||||
i->addOperand(std::make_unique<RegOperand>(rd));
|
||||
i->addOperand(std::make_unique<RegOperand>(rs1));
|
||||
i->addOperand(std::make_unique<ImmOperand>(imm));
|
||||
CurMBB->addInstruction(std::move(i));
|
||||
};
|
||||
auto store_instr = [&](RVOpcodes op, unsigned src, unsigned base, int64_t off) {
|
||||
auto i = std::make_unique<MachineInstr>(op);
|
||||
i->addOperand(std::make_unique<RegOperand>(src));
|
||||
i->addOperand(std::make_unique<MemOperand>(std::make_unique<RegOperand>(base), std::make_unique<ImmOperand>(off)));
|
||||
CurMBB->addInstruction(std::move(i));
|
||||
};
|
||||
auto branch_instr = [&](RVOpcodes op, unsigned rs1, unsigned rs2, const std::string& label) {
|
||||
auto i = std::make_unique<MachineInstr>(op);
|
||||
i->addOperand(std::make_unique<RegOperand>(rs1));
|
||||
i->addOperand(std::make_unique<RegOperand>(rs2));
|
||||
i->addOperand(std::make_unique<LabelOperand>(label));
|
||||
CurMBB->addInstruction(std::move(i));
|
||||
};
|
||||
auto jump_instr = [&](const std::string& label) {
|
||||
auto i = std::make_unique<MachineInstr>(RVOpcodes::J);
|
||||
i->addOperand(std::make_unique<LabelOperand>(label));
|
||||
CurMBB->addInstruction(std::move(i));
|
||||
};
|
||||
auto label_instr = [&](const std::string& name) {
|
||||
auto i = std::make_unique<MachineInstr>(RVOpcodes::LABEL);
|
||||
i->addOperand(std::make_unique<LabelOperand>(name));
|
||||
CurMBB->addInstruction(std::move(i));
|
||||
};
|
||||
|
||||
int unique_id = this->local_label_counter++;
|
||||
std::string loop_start_label = MFunc->getName() + "_memset_loop_start_" + std::to_string(unique_id);
|
||||
std::string loop_end_label = MFunc->getName() + "_memset_loop_end_" + std::to_string(unique_id);
|
||||
std::string remainder_label = MFunc->getName() + "_memset_remainder_" + std::to_string(unique_id);
|
||||
std::string done_label = MFunc->getName() + "_memset_done_" + std::to_string(unique_id);
|
||||
|
||||
addi_instr(RVOpcodes::ANDI, r_temp_val, r_value_byte, 255);
|
||||
addi_instr(RVOpcodes::SLLI, r_value_byte, r_temp_val, 8);
|
||||
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte);
|
||||
addi_instr(RVOpcodes::SLLI, r_value_byte, r_temp_val, 16);
|
||||
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte);
|
||||
addi_instr(RVOpcodes::SLLI, r_value_byte, r_temp_val, 32);
|
||||
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte);
|
||||
add_instr(RVOpcodes::ADD, r_end_addr, r_dest_addr, r_num_bytes);
|
||||
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
mv->addOperand(std::make_unique<RegOperand>(r_current_addr));
|
||||
mv->addOperand(std::make_unique<RegOperand>(r_dest_addr));
|
||||
CurMBB->addInstruction(std::move(mv));
|
||||
addi_instr(RVOpcodes::ANDI, r_counter, r_num_bytes, -8);
|
||||
add_instr(RVOpcodes::ADD, r_counter, r_dest_addr, r_counter);
|
||||
label_instr(loop_start_label);
|
||||
branch_instr(RVOpcodes::BGEU, r_current_addr, r_counter, loop_end_label);
|
||||
store_instr(RVOpcodes::SD, r_temp_val, r_current_addr, 0);
|
||||
addi_instr(RVOpcodes::ADDI, r_current_addr, r_current_addr, 8);
|
||||
jump_instr(loop_start_label);
|
||||
label_instr(loop_end_label);
|
||||
label_instr(remainder_label);
|
||||
branch_instr(RVOpcodes::BGEU, r_current_addr, r_end_addr, done_label);
|
||||
store_instr(RVOpcodes::SB, r_temp_val, r_current_addr, 0);
|
||||
addi_instr(RVOpcodes::ADDI, r_current_addr, r_current_addr, 1);
|
||||
jump_instr(remainder_label);
|
||||
label_instr(done_label);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw std::runtime_error("Unsupported DAGNode kind in ISel");
|
||||
}
|
||||
}
|
||||
|
||||
// 以下是忠实移植的DAG构建函数
|
||||
RISCv64ISel::DAGNode* RISCv64ISel::create_node(int kind_int, Value* val, std::map<Value*, DAGNode*>& value_to_node, std::vector<std::unique_ptr<DAGNode>>& nodes_storage) {
|
||||
auto kind = static_cast<DAGNode::NodeKind>(kind_int);
|
||||
if (val && value_to_node.count(val) && kind != DAGNode::STORE && kind != DAGNode::RETURN && kind != DAGNode::BRANCH && kind != DAGNode::MEMSET) {
|
||||
return value_to_node[val];
|
||||
}
|
||||
auto node = std::make_unique<DAGNode>(kind);
|
||||
node->value = val;
|
||||
DAGNode* raw_node_ptr = node.get();
|
||||
nodes_storage.push_back(std::move(node));
|
||||
if (val && !val->getType()->isVoid() && (dynamic_cast<Instruction*>(val) || dynamic_cast<GlobalValue*>(val))) {
|
||||
value_to_node[val] = raw_node_ptr;
|
||||
}
|
||||
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) {
|
||||
if (value_to_node.count(val_ir)) {
|
||||
return value_to_node[val_ir];
|
||||
} else 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)) {
|
||||
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
|
||||
} else if (dynamic_cast<AllocaInst*>(val_ir)) {
|
||||
return create_node(DAGNode::ALLOCA_ADDR, val_ir, value_to_node, nodes_storage);
|
||||
}
|
||||
return create_node(DAGNode::LOAD, val_ir, value_to_node, nodes_storage);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicBlock* bb) {
|
||||
std::vector<std::unique_ptr<DAGNode>> nodes_storage;
|
||||
std::map<Value*, DAGNode*> value_to_node;
|
||||
|
||||
for (const auto& inst_ptr : bb->getInstructions()) {
|
||||
Instruction* inst = inst_ptr.get();
|
||||
if (auto alloca = dynamic_cast<AllocaInst*>(inst)) {
|
||||
create_node(DAGNode::ALLOCA_ADDR, alloca, value_to_node, nodes_storage);
|
||||
} else if (auto store = dynamic_cast<StoreInst*>(inst)) {
|
||||
auto store_node = create_node(DAGNode::STORE, store, value_to_node, nodes_storage);
|
||||
store_node->operands.push_back(get_operand_node(store->getValue(), value_to_node, nodes_storage));
|
||||
store_node->operands.push_back(get_operand_node(store->getPointer(), value_to_node, nodes_storage));
|
||||
} else if (auto memset = dynamic_cast<MemsetInst*>(inst)) {
|
||||
auto memset_node = create_node(DAGNode::MEMSET, memset, value_to_node, nodes_storage);
|
||||
memset_node->operands.push_back(get_operand_node(memset->getPointer(), value_to_node, nodes_storage));
|
||||
memset_node->operands.push_back(get_operand_node(memset->getBegin(), value_to_node, nodes_storage));
|
||||
memset_node->operands.push_back(get_operand_node(memset->getSize(), value_to_node, nodes_storage));
|
||||
memset_node->operands.push_back(get_operand_node(memset->getValue(), value_to_node, nodes_storage));
|
||||
} else if (auto load = dynamic_cast<LoadInst*>(inst)) {
|
||||
auto load_node = create_node(DAGNode::LOAD, load, value_to_node, nodes_storage);
|
||||
load_node->operands.push_back(get_operand_node(load->getPointer(), value_to_node, nodes_storage));
|
||||
} else if (auto bin = dynamic_cast<BinaryInst*>(inst)) {
|
||||
if(value_to_node.count(bin)) continue;
|
||||
if (bin->getKind() == BinaryInst::kSub) {
|
||||
if (auto const_lhs = dynamic_cast<ConstantValue*>(bin->getLhs())) {
|
||||
if (const_lhs->getInt() == 0) {
|
||||
auto unary_node = create_node(DAGNode::UNARY, bin, value_to_node, nodes_storage);
|
||||
unary_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto bin_node = create_node(DAGNode::BINARY, bin, value_to_node, nodes_storage);
|
||||
bin_node->operands.push_back(get_operand_node(bin->getLhs(), value_to_node, nodes_storage));
|
||||
bin_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
|
||||
} else if (auto un = dynamic_cast<UnaryInst*>(inst)) {
|
||||
if(value_to_node.count(un)) continue;
|
||||
auto unary_node = create_node(DAGNode::UNARY, un, value_to_node, nodes_storage);
|
||||
unary_node->operands.push_back(get_operand_node(un->getOperand(), value_to_node, nodes_storage));
|
||||
} else if (auto call = dynamic_cast<CallInst*>(inst)) {
|
||||
if(value_to_node.count(call)) continue;
|
||||
auto call_node = create_node(DAGNode::CALL, call, value_to_node, nodes_storage);
|
||||
for (auto arg : call->getArguments()) {
|
||||
call_node->operands.push_back(get_operand_node(arg->getValue(), value_to_node, nodes_storage));
|
||||
}
|
||||
} else if (auto ret = dynamic_cast<ReturnInst*>(inst)) {
|
||||
auto ret_node = create_node(DAGNode::RETURN, ret, value_to_node, nodes_storage);
|
||||
if (ret->hasReturnValue()) {
|
||||
ret_node->operands.push_back(get_operand_node(ret->getReturnValue(), value_to_node, nodes_storage));
|
||||
}
|
||||
} else if (auto cond_br = dynamic_cast<CondBrInst*>(inst)) {
|
||||
auto br_node = create_node(DAGNode::BRANCH, cond_br, value_to_node, nodes_storage);
|
||||
br_node->operands.push_back(get_operand_node(cond_br->getCondition(), value_to_node, nodes_storage));
|
||||
} else if (auto uncond_br = dynamic_cast<UncondBrInst*>(inst)) {
|
||||
create_node(DAGNode::BRANCH, uncond_br, value_to_node, nodes_storage);
|
||||
}
|
||||
}
|
||||
return nodes_storage;
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@ -1,8 +0,0 @@
|
||||
// RISCv64Passes.cpp
|
||||
#include "RISCv64Passes.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 此处为未来优化Pass的实现
|
||||
|
||||
} // namespace sysy
|
||||
@ -1,322 +0,0 @@
|
||||
#include "RISCv64RegAlloc.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
void RISCv64RegAlloc::run() {
|
||||
eliminateFrameIndices();
|
||||
analyzeLiveness();
|
||||
buildInterferenceGraph();
|
||||
colorGraph();
|
||||
rewriteFunction();
|
||||
}
|
||||
|
||||
void RISCv64RegAlloc::eliminateFrameIndices() {
|
||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||
int current_offset = 0;
|
||||
Function* F = MFunc->getFunc();
|
||||
RISCv64ISel* isel = MFunc->getISel();
|
||||
|
||||
for (auto& bb : F->getBasicBlocks()) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
if (auto alloca = dynamic_cast<AllocaInst*>(inst.get())) {
|
||||
int size = 4;
|
||||
if (!alloca->getDims().empty()) {
|
||||
int num_elements = 1;
|
||||
for (const auto& dim_use : alloca->getDims()) {
|
||||
if (auto const_dim = dynamic_cast<ConstantValue*>(dim_use->getValue())) {
|
||||
num_elements *= const_dim->getInt();
|
||||
}
|
||||
}
|
||||
size *= num_elements;
|
||||
}
|
||||
current_offset += size;
|
||||
unsigned alloca_vreg = isel->getVReg(alloca);
|
||||
frame_info.alloca_offsets[alloca_vreg] = -current_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
frame_info.locals_size = current_offset;
|
||||
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
std::vector<std::unique_ptr<MachineInstr>> new_instructions;
|
||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||
if (instr_ptr->getOpcode() == RVOpcodes::FRAME_LOAD) {
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
unsigned dest_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
|
||||
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
|
||||
int offset = frame_info.alloca_offsets.at(alloca_vreg);
|
||||
auto addr_vreg = isel->getNewVReg();
|
||||
|
||||
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
addi->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
||||
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
addi->addOperand(std::make_unique<ImmOperand>(offset));
|
||||
new_instructions.push_back(std::move(addi));
|
||||
|
||||
auto lw = std::make_unique<MachineInstr>(RVOpcodes::LW);
|
||||
lw->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
lw->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(addr_vreg),
|
||||
std::make_unique<ImmOperand>(0)));
|
||||
new_instructions.push_back(std::move(lw));
|
||||
|
||||
} else if (instr_ptr->getOpcode() == RVOpcodes::FRAME_STORE) {
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
unsigned src_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
|
||||
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
|
||||
int offset = frame_info.alloca_offsets.at(alloca_vreg);
|
||||
auto addr_vreg = isel->getNewVReg();
|
||||
|
||||
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
addi->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
||||
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
addi->addOperand(std::make_unique<ImmOperand>(offset));
|
||||
new_instructions.push_back(std::move(addi));
|
||||
|
||||
auto sw = std::make_unique<MachineInstr>(RVOpcodes::SW);
|
||||
sw->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
sw->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(addr_vreg),
|
||||
std::make_unique<ImmOperand>(0)));
|
||||
new_instructions.push_back(std::move(sw));
|
||||
} else {
|
||||
new_instructions.push_back(std::move(instr_ptr));
|
||||
}
|
||||
}
|
||||
mbb->getInstructions() = std::move(new_instructions);
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def) {
|
||||
bool is_def = true;
|
||||
auto opcode = instr->getOpcode();
|
||||
|
||||
// 预定义def和use规则
|
||||
if (opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
|
||||
opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
|
||||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
|
||||
opcode == RVOpcodes::RET || opcode == RVOpcodes::J) {
|
||||
is_def = false;
|
||||
}
|
||||
if (opcode == RVOpcodes::CALL) {
|
||||
// CALL会杀死所有调用者保存寄存器,这是一个简化处理
|
||||
// 同时也使用了传入a0-a7的参数
|
||||
}
|
||||
|
||||
for (const auto& op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||
if (reg_op->isVirtual()) {
|
||||
if (is_def) {
|
||||
def.insert(reg_op->getVRegNum());
|
||||
is_def = false;
|
||||
} else {
|
||||
use.insert(reg_op->getVRegNum());
|
||||
}
|
||||
}
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto mem_op = static_cast<MemOperand*>(op.get());
|
||||
if (mem_op->getBase()->isVirtual()) {
|
||||
use.insert(mem_op->getBase()->getVRegNum());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64RegAlloc::analyzeLiveness() {
|
||||
bool changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
for (auto it = MFunc->getBlocks().rbegin(); it != MFunc->getBlocks().rend(); ++it) {
|
||||
auto& mbb = *it;
|
||||
LiveSet 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64RegAlloc::buildInterferenceGraph() {
|
||||
std::set<unsigned> all_vregs;
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
for(auto& instr : mbb->getInstructions()) {
|
||||
LiveSet use, def;
|
||||
getInstrUseDef(instr.get(), use, def);
|
||||
for(auto u : use) all_vregs.insert(u);
|
||||
for(auto d : def) all_vregs.insert(d);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto vreg : all_vregs) { interference_graph[vreg] = {}; }
|
||||
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
for (auto& instr : mbb->getInstructions()) {
|
||||
LiveSet def, use;
|
||||
getInstrUseDef(instr.get(), use, def);
|
||||
const LiveSet& live_out = live_out_map.at(instr.get());
|
||||
|
||||
for (unsigned d : def) {
|
||||
for (unsigned l : live_out) {
|
||||
if (d != l) {
|
||||
interference_graph[d].insert(l);
|
||||
interference_graph[l].insert(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64RegAlloc::colorGraph() {
|
||||
std::vector<unsigned> sorted_vregs;
|
||||
for (auto const& [vreg, neighbors] : interference_graph) {
|
||||
sorted_vregs.push_back(vreg);
|
||||
}
|
||||
|
||||
std::sort(sorted_vregs.begin(), sorted_vregs.end(), [&](unsigned a, unsigned b) {
|
||||
return interference_graph[a].size() > interference_graph[b].size();
|
||||
});
|
||||
|
||||
for (unsigned vreg : sorted_vregs) {
|
||||
std::set<PhysicalReg> used_colors;
|
||||
for (unsigned neighbor : interference_graph.at(vreg)) {
|
||||
if (color_map.count(neighbor)) {
|
||||
used_colors.insert(color_map.at(neighbor));
|
||||
}
|
||||
}
|
||||
|
||||
bool colored = false;
|
||||
for (PhysicalReg preg : allocable_int_regs) {
|
||||
if (used_colors.find(preg) == used_colors.end()) {
|
||||
color_map[vreg] = preg;
|
||||
colored = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!colored) {
|
||||
spilled_vregs.insert(vreg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64RegAlloc::rewriteFunction() {
|
||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||
int current_offset = frame_info.locals_size;
|
||||
for (unsigned vreg : spilled_vregs) {
|
||||
current_offset += 4;
|
||||
frame_info.spill_offsets[vreg] = -current_offset;
|
||||
}
|
||||
frame_info.spill_size = current_offset - frame_info.locals_size;
|
||||
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
std::vector<std::unique_ptr<MachineInstr>> new_instructions;
|
||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||
LiveSet use, def;
|
||||
getInstrUseDef(instr_ptr.get(), use, def);
|
||||
|
||||
for (unsigned vreg : use) {
|
||||
if (spilled_vregs.count(vreg)) {
|
||||
int offset = frame_info.spill_offsets.at(vreg);
|
||||
auto load = std::make_unique<MachineInstr>(RVOpcodes::LW);
|
||||
load->addOperand(std::make_unique<RegOperand>(vreg));
|
||||
load->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(offset)
|
||||
));
|
||||
new_instructions.push_back(std::move(load));
|
||||
}
|
||||
}
|
||||
|
||||
new_instructions.push_back(std::move(instr_ptr));
|
||||
|
||||
for (unsigned vreg : def) {
|
||||
if (spilled_vregs.count(vreg)) {
|
||||
int offset = frame_info.spill_offsets.at(vreg);
|
||||
auto store = std::make_unique<MachineInstr>(RVOpcodes::SW);
|
||||
store->addOperand(std::make_unique<RegOperand>(vreg));
|
||||
store->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(offset)
|
||||
));
|
||||
new_instructions.push_back(std::move(store));
|
||||
}
|
||||
}
|
||||
}
|
||||
mbb->getInstructions() = std::move(new_instructions);
|
||||
}
|
||||
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||
for (auto& op_ptr : instr_ptr->getOperands()) {
|
||||
if(op_ptr->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(op_ptr.get());
|
||||
if (reg_op->isVirtual()) {
|
||||
unsigned vreg = reg_op->getVRegNum();
|
||||
if (color_map.count(vreg)) {
|
||||
reg_op->setPReg(color_map.at(vreg));
|
||||
} else if (spilled_vregs.count(vreg)) {
|
||||
reg_op->setPReg(PhysicalReg::T6); // 溢出统一用t6
|
||||
}
|
||||
}
|
||||
} else if (op_ptr->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto mem_op = static_cast<MemOperand*>(op_ptr.get());
|
||||
auto base_reg_op = mem_op->getBase();
|
||||
if(base_reg_op->isVirtual()){
|
||||
unsigned vreg = base_reg_op->getVRegNum();
|
||||
if(color_map.count(vreg)) {
|
||||
base_reg_op->setPReg(color_map.at(vreg));
|
||||
} else if (spilled_vregs.count(vreg)) {
|
||||
base_reg_op->setPReg(PhysicalReg::T6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@ -1,532 +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的所有前驱结点
|
||||
// 迭代计算支配结点,直到不再变化
|
||||
// 这里使用迭代法,直到支配结点不再变化
|
||||
// TODO:Lengauer-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; // 返回数据流结果是否变化
|
||||
}
|
||||
|
||||
|
||||
auto ActiveVarAnalysis::getActiveTable() const -> const std::map<BasicBlock *, std::vector<std::set<User *>>> & {
|
||||
return activeTable;
|
||||
}
|
||||
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,484 +0,0 @@
|
||||
#include "SysYIROptPre.h"
|
||||
#include <cassert>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include "IR.h"
|
||||
#include "IRBuilder.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
/**
|
||||
* use删除operand,以免扰乱后续分析
|
||||
* instr: 要删除的指令
|
||||
*/
|
||||
void SysYOptPre::usedelete(Instruction *instr) {
|
||||
for (auto &use : instr->getOperands()) {
|
||||
Value* val = use->getValue();
|
||||
// std::cout << delete << val->getName() << std::endl;
|
||||
val->removeUse(use);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 删除br后的无用指令
|
||||
void SysYOptPre::SysYDelInstAfterBr() {
|
||||
auto &functions = pModule->getFunctions();
|
||||
for (auto &function : functions) {
|
||||
auto basicBlocks = function.second->getBasicBlocks();
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
bool Branch = false;
|
||||
auto &instructions = basicBlock->getInstructions();
|
||||
auto Branchiter = instructions.end();
|
||||
for (auto iter = instructions.begin(); iter != instructions.end(); ++iter) {
|
||||
if (Branch)
|
||||
usedelete(iter->get());
|
||||
else if ((*iter)->isTerminator()){
|
||||
Branch = true;
|
||||
Branchiter = iter;
|
||||
}
|
||||
}
|
||||
if (Branchiter != instructions.end()) ++Branchiter;
|
||||
while (Branchiter != instructions.end())
|
||||
Branchiter = instructions.erase(Branchiter);
|
||||
|
||||
if (Branch) { // 更新前驱后继关系
|
||||
auto thelastinstinst = basicBlock->getInstructions().end();
|
||||
--thelastinstinst;
|
||||
auto &Successors = basicBlock->getSuccessors();
|
||||
for (auto iterSucc = Successors.begin(); iterSucc != Successors.end();) {
|
||||
(*iterSucc)->removePredecessor(basicBlock.get());
|
||||
basicBlock->removeSuccessor(*iterSucc);
|
||||
}
|
||||
if (thelastinstinst->get()->isUnconditional()) {
|
||||
BasicBlock* branchBlock = dynamic_cast<BasicBlock *>(thelastinstinst->get()->getOperand(0));
|
||||
basicBlock->addSuccessor(branchBlock);
|
||||
branchBlock->addPredecessor(basicBlock.get());
|
||||
} else if (thelastinstinst->get()->isConditional()) {
|
||||
BasicBlock* thenBlock = dynamic_cast<BasicBlock *>(thelastinstinst->get()->getOperand(1));
|
||||
BasicBlock* elseBlock = dynamic_cast<BasicBlock *>(thelastinstinst->get()->getOperand(2));
|
||||
basicBlock->addSuccessor(thenBlock);
|
||||
basicBlock->addSuccessor(elseBlock);
|
||||
thenBlock->addPredecessor(basicBlock.get());
|
||||
elseBlock->addPredecessor(basicBlock.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SysYOptPre::SysYBlockMerge() {
|
||||
auto &functions = pModule->getFunctions(); //std::map<std::string, std::unique_ptr<Function>>
|
||||
for (auto &function : functions) {
|
||||
// auto basicBlocks = function.second->getBasicBlocks();
|
||||
auto &func = function.second;
|
||||
for (auto blockiter = func->getBasicBlocks().begin();
|
||||
blockiter != func->getBasicBlocks().end();) {
|
||||
if (blockiter->get()->getNumSuccessors() == 1) {
|
||||
// 如果当前块只有一个后继块
|
||||
// 且后继块只有一个前驱块
|
||||
// 则将当前块和后继块合并
|
||||
if (((blockiter->get())->getSuccessors()[0])->getNumPredecessors() == 1) {
|
||||
// std::cout << "merge block: " << blockiter->get()->getName() << std::endl;
|
||||
BasicBlock* block = blockiter->get();
|
||||
BasicBlock* nextBlock = blockiter->get()->getSuccessors()[0];
|
||||
auto nextarguments = nextBlock->getArguments();
|
||||
// 删除br指令
|
||||
if (block->getNumInstructions() != 0) {
|
||||
auto thelastinstinst = block->end();
|
||||
(--thelastinstinst);
|
||||
if (thelastinstinst->get()->isUnconditional()) {
|
||||
usedelete(thelastinstinst->get());
|
||||
block->getInstructions().erase(thelastinstinst);
|
||||
} else if (thelastinstinst->get()->isConditional()) {
|
||||
// 如果是条件分支,判断条件是否相同,主要优化相同布尔表达式
|
||||
if (thelastinstinst->get()->getOperand(1)->getName() == thelastinstinst->get()->getOperand(1)->getName()) {
|
||||
usedelete(thelastinstinst->get());
|
||||
block->getInstructions().erase(thelastinstinst);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 将后继块的指令移动到当前块
|
||||
// 并将后继块的父指针改为当前块
|
||||
for (auto institer = nextBlock->begin(); institer != nextBlock->end();) {
|
||||
institer->get()->setParent(block);
|
||||
block->getInstructions().emplace_back(institer->release());
|
||||
institer = nextBlock->getInstructions().erase(institer);
|
||||
}
|
||||
// 合并参数
|
||||
// TODO:是否需要去重?
|
||||
for (auto &argm : nextarguments) {
|
||||
argm->setParent(block);
|
||||
block->insertArgument(argm);
|
||||
}
|
||||
// 更新前驱后继关系,类似树节点操作
|
||||
block->removeSuccessor(nextBlock);
|
||||
nextBlock->removePredecessor(block);
|
||||
std::list<BasicBlock *> succshoulddel;
|
||||
for (auto &succ : nextBlock->getSuccessors()) {
|
||||
block->addSuccessor(succ);
|
||||
succ->replacePredecessor(nextBlock, block);
|
||||
succshoulddel.push_back(succ);
|
||||
}
|
||||
for (auto del : succshoulddel) {
|
||||
nextBlock->removeSuccessor(del);
|
||||
}
|
||||
|
||||
func->removeBasicBlock(nextBlock);
|
||||
|
||||
} else {
|
||||
blockiter++;
|
||||
}
|
||||
} else {
|
||||
blockiter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除无前驱块,兼容SSA后的处理
|
||||
void SysYOptPre::SysYDelNoPreBLock() {
|
||||
|
||||
auto &functions = pModule->getFunctions(); // std::map<std::string, std::unique_ptr<sysy::Function>>
|
||||
for (auto &function : functions) {
|
||||
auto &func = function.second;
|
||||
|
||||
for (auto &block : func->getBasicBlocks()) {
|
||||
block->setreachableFalse();
|
||||
}
|
||||
// 对函数基本块做一个拓扑排序,排查不可达基本块
|
||||
auto entryBlock = func->getEntryBlock();
|
||||
entryBlock->setreachableTrue();
|
||||
std::queue<BasicBlock *> blockqueue;
|
||||
blockqueue.push(entryBlock);
|
||||
while (!blockqueue.empty()) {
|
||||
auto block = blockqueue.front();
|
||||
blockqueue.pop();
|
||||
for (auto &succ : block->getSuccessors()) {
|
||||
if (!succ->getreachable()) {
|
||||
succ->setreachableTrue();
|
||||
blockqueue.push(succ);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除不可达基本块指令
|
||||
for (auto blockIter = func->getBasicBlocks().begin(); blockIter != func->getBasicBlocks().end();blockIter++) {
|
||||
|
||||
if (!blockIter->get()->getreachable())
|
||||
for (auto &iterInst : blockIter->get()->getInstructions())
|
||||
usedelete(iterInst.get());
|
||||
|
||||
}
|
||||
|
||||
|
||||
for (auto blockIter = func->getBasicBlocks().begin(); blockIter != func->getBasicBlocks().end();) {
|
||||
if (!blockIter->get()->getreachable()) {
|
||||
for (auto succblock : blockIter->get()->getSuccessors()) {
|
||||
int indexphi = 1;
|
||||
for (auto pred : succblock->getPredecessors()) {
|
||||
if (pred == blockIter->get()) {
|
||||
break;
|
||||
}
|
||||
indexphi++;
|
||||
}
|
||||
for (auto &phiinst : succblock->getInstructions()) {
|
||||
if (phiinst->getKind() != Instruction::kPhi) {
|
||||
break;
|
||||
}
|
||||
phiinst->removeOperand(indexphi);
|
||||
}
|
||||
}
|
||||
// 删除不可达基本块,注意迭代器不可达问题
|
||||
func->removeBasicBlock((blockIter++)->get());
|
||||
} else {
|
||||
blockIter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SysYOptPre::SysYDelEmptyBlock() {
|
||||
auto &functions = pModule->getFunctions();
|
||||
for (auto &function : functions) {
|
||||
// 收集不可达基本块
|
||||
// 这里的不可达基本块是指没有实际指令的基本块
|
||||
// 当一个基本块没有实际指令例如只有phi指令和一个uncondbr指令时,也会被视作不可达
|
||||
auto basicBlocks = function.second->getBasicBlocks();
|
||||
std::map<sysy::BasicBlock *, BasicBlock *> EmptyBlocks;
|
||||
// 空块儿和后继的基本块的映射
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
if (basicBlock->getNumInstructions() == 0) {
|
||||
if (basicBlock->getNumSuccessors() == 1) {
|
||||
EmptyBlocks[basicBlock.get()] = basicBlock->getSuccessors().front();
|
||||
}
|
||||
}
|
||||
else{
|
||||
// 如果只有phi指令和一个uncondbr。(phi)*(uncondbr)?
|
||||
// 判断除了最后一个指令之外是不是只有phi指令
|
||||
bool onlyPhi = true;
|
||||
for (auto &inst : basicBlock->getInstructions()) {
|
||||
if (!inst->isPhi() && !inst->isUnconditional()) {
|
||||
onlyPhi = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(onlyPhi)
|
||||
EmptyBlocks[basicBlock.get()] = basicBlock->getSuccessors().front();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
// 更新基本块信息,增加必要指令
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
// 把空块转换成只有跳转指令的不可达块
|
||||
if (distance(basicBlock->begin(), basicBlock->end()) == 0) {
|
||||
if (basicBlock->getNumSuccessors() == 0) {
|
||||
continue;
|
||||
}
|
||||
if (basicBlock->getNumSuccessors() > 1) {
|
||||
assert("");
|
||||
}
|
||||
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||
pBuilder->createUncondBrInst(basicBlock->getSuccessors()[0], {});
|
||||
continue;
|
||||
}
|
||||
|
||||
auto thelastinst = basicBlock->getInstructions().end();
|
||||
--thelastinst;
|
||||
|
||||
// 根据br指令传递的后继块信息,跳过空块链
|
||||
if (thelastinst->get()->isUnconditional()) {
|
||||
BasicBlock* OldBrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
||||
BasicBlock *thelastBlockOld = nullptr;
|
||||
// 如果空块链表为多个块
|
||||
while (EmptyBlocks.find(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))) !=
|
||||
EmptyBlocks.end()) {
|
||||
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
||||
thelastinst->get()->replaceOperand(0, EmptyBlocks[thelastBlockOld]);
|
||||
}
|
||||
|
||||
basicBlock->removeSuccessor(OldBrBlock);
|
||||
OldBrBlock->removePredecessor(basicBlock.get());
|
||||
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0)));
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->addPredecessor(basicBlock.get());
|
||||
|
||||
if (thelastBlockOld != nullptr) {
|
||||
int indexphi = 0;
|
||||
for (auto &pred : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getPredecessors()) {
|
||||
if (pred == thelastBlockOld) {
|
||||
break;
|
||||
}
|
||||
indexphi++;
|
||||
}
|
||||
|
||||
// 更新phi指令的操作数
|
||||
// 移除thelastBlockOld对应的phi操作数
|
||||
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getInstructions()) {
|
||||
if (InstInNew->isPhi()) {
|
||||
dynamic_cast<PhiInst *>(InstInNew.get())->removeOperand(indexphi + 1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (thelastinst->get()->getKind() == Instruction::kCondBr) {
|
||||
auto OldThenBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||
auto OldElseBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2));
|
||||
|
||||
BasicBlock *thelastBlockOld = nullptr;
|
||||
while (EmptyBlocks.find(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))) !=
|
||||
EmptyBlocks.end()) {
|
||||
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||
thelastinst->get()->replaceOperand(
|
||||
1, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))]);
|
||||
}
|
||||
basicBlock->removeSuccessor(OldThenBlock);
|
||||
OldThenBlock->removePredecessor(basicBlock.get());
|
||||
// 处理 then 和 else 分支合并的情况
|
||||
if (dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)) ==
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) {
|
||||
auto thebrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||
usedelete(thelastinst->get());
|
||||
thelastinst = basicBlock->getInstructions().erase(thelastinst);
|
||||
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||
pBuilder->createUncondBrInst(thebrBlock, {});
|
||||
continue;
|
||||
}
|
||||
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)));
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->addPredecessor(basicBlock.get());
|
||||
// auto indexInNew = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getPredecessors().
|
||||
|
||||
if (thelastBlockOld != nullptr) {
|
||||
int indexphi = 0;
|
||||
for (auto &pred : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->getPredecessors()) {
|
||||
if (pred == thelastBlockOld) {
|
||||
break;
|
||||
}
|
||||
indexphi++;
|
||||
}
|
||||
|
||||
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->getInstructions()) {
|
||||
if (InstInNew->isPhi()) {
|
||||
dynamic_cast<PhiInst *>(InstInNew.get())->removeOperand(indexphi + 1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thelastBlockOld = nullptr;
|
||||
while (EmptyBlocks.find(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) !=
|
||||
EmptyBlocks.end()) {
|
||||
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2));
|
||||
thelastinst->get()->replaceOperand(
|
||||
2, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))]);
|
||||
}
|
||||
basicBlock->removeSuccessor(OldElseBlock);
|
||||
OldElseBlock->removePredecessor(basicBlock.get());
|
||||
// 处理 then 和 else 分支合并的情况
|
||||
if (dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)) ==
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) {
|
||||
auto thebrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||
usedelete(thelastinst->get());
|
||||
thelastinst = basicBlock->getInstructions().erase(thelastinst);
|
||||
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||
pBuilder->createUncondBrInst(thebrBlock, {});
|
||||
continue;
|
||||
}
|
||||
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2)));
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->addPredecessor(basicBlock.get());
|
||||
|
||||
if (thelastBlockOld != nullptr) {
|
||||
int indexphi = 0;
|
||||
for (auto &pred : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->getPredecessors()) {
|
||||
if (pred == thelastBlockOld) {
|
||||
break;
|
||||
}
|
||||
indexphi++;
|
||||
}
|
||||
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->getInstructions()) {
|
||||
if (InstInNew->isPhi()) {
|
||||
dynamic_cast<PhiInst *>(InstInNew.get())->removeOperand(indexphi + 1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (basicBlock->getNumSuccessors() == 1) {
|
||||
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||
pBuilder->createUncondBrInst(basicBlock->getSuccessors()[0], {});
|
||||
auto thelastinst = basicBlock->getInstructions().end();
|
||||
(--thelastinst);
|
||||
auto OldBrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
||||
sysy::BasicBlock *thelastBlockOld = nullptr;
|
||||
while (EmptyBlocks.find(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))) !=
|
||||
EmptyBlocks.end()) {
|
||||
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
||||
|
||||
thelastinst->get()->replaceOperand(
|
||||
0, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))]);
|
||||
}
|
||||
|
||||
basicBlock->removeSuccessor(OldBrBlock);
|
||||
OldBrBlock->removePredecessor(basicBlock.get());
|
||||
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0)));
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->addPredecessor(basicBlock.get());
|
||||
if (thelastBlockOld != nullptr) {
|
||||
int indexphi = 0;
|
||||
for (auto &pred : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getPredecessors()) {
|
||||
if (pred == thelastBlockOld) {
|
||||
break;
|
||||
}
|
||||
indexphi++;
|
||||
}
|
||||
|
||||
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getInstructions()) {
|
||||
if (InstInNew->isPhi()) {
|
||||
dynamic_cast<PhiInst *>(InstInNew.get())->removeOperand(indexphi + 1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto iter = function.second->getBasicBlocks().begin(); iter != function.second->getBasicBlocks().end();) {
|
||||
|
||||
if (EmptyBlocks.find(iter->get()) != EmptyBlocks.end()) {
|
||||
// EntryBlock跳过
|
||||
if (iter->get() == function.second->getEntryBlock()) {
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto &iterInst : iter->get()->getInstructions())
|
||||
usedelete(iterInst.get());
|
||||
// 删除不可达基本块的phi指令的操作数
|
||||
for (auto &succ : iter->get()->getSuccessors()) {
|
||||
int index = 0;
|
||||
for (auto &pred : succ->getPredecessors()) {
|
||||
if (pred == iter->get()) {
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
for (auto &instinsucc : succ->getInstructions()) {
|
||||
if (instinsucc->isPhi()) {
|
||||
dynamic_cast<PhiInst *>(instinsucc.get())->removeOperand(index);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function.second->removeBasicBlock((iter++)->get());
|
||||
} else {
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果函数没有返回指令,则添加一个默认返回指令(主要解决void函数没有返回指令的问题)
|
||||
void SysYOptPre::SysYAddReturn() {
|
||||
auto &functions = pModule->getFunctions();
|
||||
for (auto &function : functions) {
|
||||
auto &func = function.second;
|
||||
auto basicBlocks = func->getBasicBlocks();
|
||||
for (auto &block : basicBlocks) {
|
||||
if (block->getNumSuccessors() == 0) {
|
||||
// 如果基本块没有后继块,则添加一个返回指令
|
||||
if (block->getNumInstructions() == 0) {
|
||||
pBuilder->setPosition(block.get(), block->end());
|
||||
pBuilder->createReturnInst();
|
||||
}
|
||||
auto thelastinst = block->getInstructions().end();
|
||||
--thelastinst;
|
||||
if (thelastinst->get()->getKind() != Instruction::kReturn) {
|
||||
// std::cout << "Warning: Function " << func->getName() << " has no return instruction, adding default return." << std::endl;
|
||||
|
||||
pBuilder->setPosition(block.get(), block->end());
|
||||
// TODO: 如果int float函数缺少返回值是否需要报错
|
||||
if (func->getReturnType()->isInt()) {
|
||||
pBuilder->createReturnInst(ConstantInteger::get(0));
|
||||
} else if (func->getReturnType()->isFloat()) {
|
||||
pBuilder->createReturnInst(ConstantFloating::get(0.0F));
|
||||
} else {
|
||||
pBuilder->createReturnInst();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@ -1,483 +0,0 @@
|
||||
#include "SysYIRPrinter.h"
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "IR.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
void SysYPrinter::printIR() {
|
||||
|
||||
const auto &functions = pModule->getFunctions();
|
||||
|
||||
//TODO: Print target datalayout and triple (minimal required by LLVM)
|
||||
|
||||
printGlobalVariable();
|
||||
|
||||
for (const auto &iter : functions) {
|
||||
if (iter.second->getName() == "main") {
|
||||
printFunction(iter.second.get());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &iter : functions) {
|
||||
if (iter.second->getName() != "main") {
|
||||
printFunction(iter.second.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string SysYPrinter::getTypeString(Type *type) {
|
||||
if (type->isVoid()) {
|
||||
return "void";
|
||||
} else if (type->isInt()) {
|
||||
return "i32";
|
||||
} else if (type->isFloat()) {
|
||||
return "float";
|
||||
|
||||
} else if (auto ptrType = dynamic_cast<PointerType*>(type)) {
|
||||
return getTypeString(ptrType->getBaseType()) + "*";
|
||||
} else if (auto ptrType = dynamic_cast<FunctionType*>(type)) {
|
||||
return getTypeString(ptrType->getReturnType());
|
||||
}
|
||||
assert(false && "Unsupported type");
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string SysYPrinter::getValueName(Value *value) {
|
||||
if (auto global = dynamic_cast<GlobalValue*>(value)) {
|
||||
return "@" + global->getName();
|
||||
} else if (auto inst = dynamic_cast<Instruction*>(value)) {
|
||||
return "%" + inst->getName();
|
||||
} else if (auto constVal = dynamic_cast<ConstantValue*>(value)) {
|
||||
if (constVal->isFloat()) {
|
||||
return std::to_string(constVal->getFloat());
|
||||
}
|
||||
return std::to_string(constVal->getInt());
|
||||
} else if (auto constVar = dynamic_cast<ConstantVariable*>(value)) {
|
||||
return constVar->getName();
|
||||
}
|
||||
assert(false && "Unknown value type");
|
||||
return "";
|
||||
}
|
||||
|
||||
void SysYPrinter::printType(Type *type) {
|
||||
std::cout << getTypeString(type);
|
||||
}
|
||||
|
||||
void SysYPrinter::printValue(Value *value) {
|
||||
std::cout << getValueName(value);
|
||||
}
|
||||
|
||||
void SysYPrinter::printGlobalVariable() {
|
||||
auto &globals = pModule->getGlobals();
|
||||
|
||||
for (const auto &global : globals) {
|
||||
std::cout << "@" << global->getName() << " = global ";
|
||||
|
||||
auto baseType = dynamic_cast<PointerType *>(global->getType())->getBaseType();
|
||||
printType(baseType);
|
||||
|
||||
if (global->getNumDims() > 0) {
|
||||
// Array type
|
||||
std::cout << " [";
|
||||
for (unsigned i = 0; i < global->getNumDims(); i++) {
|
||||
if (i > 0) std::cout << " x ";
|
||||
std::cout << getValueName(global->getDim(i));
|
||||
}
|
||||
std::cout << "]";
|
||||
}
|
||||
|
||||
std::cout << " ";
|
||||
|
||||
if (global->getNumDims() > 0) {
|
||||
// Array initializer
|
||||
std::cout << "[";
|
||||
auto values = global->getInitValues();
|
||||
auto counterValues = values.getValues();
|
||||
auto counterNumbers = values.getNumbers();
|
||||
|
||||
for (size_t i = 0; i < counterNumbers.size(); i++) {
|
||||
if (i > 0) std::cout << ", ";
|
||||
if (baseType->isFloat()) {
|
||||
std::cout << "float " << dynamic_cast<ConstantValue*>(counterValues[i])->getFloat();
|
||||
} else {
|
||||
std::cout << "i32 " << dynamic_cast<ConstantValue*>(counterValues[i])->getInt();
|
||||
}
|
||||
}
|
||||
std::cout << "]";
|
||||
} else {
|
||||
// Scalar initializer
|
||||
if (baseType->isFloat()) {
|
||||
std::cout << "float " << dynamic_cast<ConstantValue*>(global->getByIndex(0))->getFloat();
|
||||
} else {
|
||||
std::cout << "i32 " << dynamic_cast<ConstantValue*>(global->getByIndex(0))->getInt();
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << ", align 4" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void SysYPrinter::printFunction(Function *function) {
|
||||
// Function signature
|
||||
std::cout << "define ";
|
||||
printType(function->getReturnType());
|
||||
std::cout << " @" << function->getName() << "(";
|
||||
|
||||
auto entryBlock = function->getEntryBlock();
|
||||
const auto &args_types = function->getParamTypes();
|
||||
auto &args = entryBlock->getArguments();
|
||||
|
||||
int i = 0;
|
||||
for (const auto &args_type : args_types) {
|
||||
if (i > 0) std::cout << ", ";
|
||||
printType(args_type);
|
||||
std::cout << " %" << args[i]->getName();
|
||||
i++;
|
||||
}
|
||||
|
||||
std::cout << ") {" << std::endl;
|
||||
|
||||
// Function body
|
||||
for (const auto &blockIter : function->getBasicBlocks()) {
|
||||
// Basic block label
|
||||
BasicBlock* blockPtr = blockIter.get();
|
||||
if (blockPtr == function->getEntryBlock()) {
|
||||
std::cout << "entry:" << std::endl;
|
||||
} else if (!blockPtr->getName().empty()) {
|
||||
std::cout << blockPtr->getName() << ":" << std::endl;
|
||||
}
|
||||
|
||||
// Instructions
|
||||
for (const auto &instIter : blockIter->getInstructions()) {
|
||||
auto inst = instIter.get();
|
||||
std::cout << " ";
|
||||
printInst(inst);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "}" << std::endl << std::endl;
|
||||
}
|
||||
|
||||
void SysYPrinter::printInst(Instruction *pInst) {
|
||||
using Kind = Instruction::Kind;
|
||||
|
||||
switch (pInst->getKind()) {
|
||||
case Kind::kAdd:
|
||||
case Kind::kSub:
|
||||
case Kind::kMul:
|
||||
case Kind::kDiv:
|
||||
case Kind::kRem:
|
||||
case Kind::kFAdd:
|
||||
case Kind::kFSub:
|
||||
case Kind::kFMul:
|
||||
case Kind::kFDiv:
|
||||
case Kind::kICmpEQ:
|
||||
case Kind::kICmpNE:
|
||||
case Kind::kICmpLT:
|
||||
case Kind::kICmpGT:
|
||||
case Kind::kICmpLE:
|
||||
case Kind::kICmpGE:
|
||||
case Kind::kFCmpEQ:
|
||||
case Kind::kFCmpNE:
|
||||
case Kind::kFCmpLT:
|
||||
case Kind::kFCmpGT:
|
||||
case Kind::kFCmpLE:
|
||||
case Kind::kFCmpGE:
|
||||
case Kind::kAnd:
|
||||
case Kind::kOr: {
|
||||
auto binInst = dynamic_cast<BinaryInst *>(pInst);
|
||||
|
||||
// Print result variable if exists
|
||||
if (!binInst->getName().empty()) {
|
||||
std::cout << "%" << binInst->getName() << " = ";
|
||||
}
|
||||
|
||||
// Operation name
|
||||
switch (pInst->getKind()) {
|
||||
case Kind::kAdd: std::cout << "add"; break;
|
||||
case Kind::kSub: std::cout << "sub"; break;
|
||||
case Kind::kMul: std::cout << "mul"; break;
|
||||
case Kind::kDiv: std::cout << "sdiv"; break;
|
||||
case Kind::kRem: std::cout << "srem"; break;
|
||||
case Kind::kFAdd: std::cout << "fadd"; break;
|
||||
case Kind::kFSub: std::cout << "fsub"; break;
|
||||
case Kind::kFMul: std::cout << "fmul"; break;
|
||||
case Kind::kFDiv: std::cout << "fdiv"; break;
|
||||
case Kind::kICmpEQ: std::cout << "icmp eq"; break;
|
||||
case Kind::kICmpNE: std::cout << "icmp ne"; break;
|
||||
case Kind::kICmpLT: std::cout << "icmp slt"; break;
|
||||
case Kind::kICmpGT: std::cout << "icmp sgt"; break;
|
||||
case Kind::kICmpLE: std::cout << "icmp sle"; break;
|
||||
case Kind::kICmpGE: std::cout << "icmp sge"; break;
|
||||
case Kind::kFCmpEQ: std::cout << "fcmp oeq"; break;
|
||||
case Kind::kFCmpNE: std::cout << "fcmp one"; break;
|
||||
case Kind::kFCmpLT: std::cout << "fcmp olt"; break;
|
||||
case Kind::kFCmpGT: std::cout << "fcmp ogt"; break;
|
||||
case Kind::kFCmpLE: std::cout << "fcmp ole"; break;
|
||||
case Kind::kFCmpGE: std::cout << "fcmp oge"; break;
|
||||
case Kind::kAnd: std::cout << "and"; break;
|
||||
case Kind::kOr: std::cout << "or"; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
// Types and operands
|
||||
std::cout << " ";
|
||||
printType(binInst->getType());
|
||||
std::cout << " ";
|
||||
printValue(binInst->getLhs());
|
||||
std::cout << ", ";
|
||||
printValue(binInst->getRhs());
|
||||
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kNeg:
|
||||
case Kind::kNot:
|
||||
case Kind::kFNeg:
|
||||
case Kind::kFNot:
|
||||
case Kind::kFtoI:
|
||||
case Kind::kBitFtoI:
|
||||
case Kind::kItoF:
|
||||
case Kind::kBitItoF: {
|
||||
auto unyInst = dynamic_cast<UnaryInst *>(pInst);
|
||||
|
||||
if (!unyInst->getName().empty()) {
|
||||
std::cout << "%" << unyInst->getName() << " = ";
|
||||
}
|
||||
|
||||
switch (pInst->getKind()) {
|
||||
case Kind::kNeg: std::cout << "sub "; break;
|
||||
case Kind::kNot: std::cout << "not "; break;
|
||||
case Kind::kFNeg: std::cout << "fneg "; break;
|
||||
case Kind::kFNot: std::cout << "fneg "; break; // FNot not standard, map to fneg
|
||||
case Kind::kFtoI: std::cout << "fptosi "; break;
|
||||
case Kind::kBitFtoI: std::cout << "bitcast "; break;
|
||||
case Kind::kItoF: std::cout << "sitofp "; break;
|
||||
case Kind::kBitItoF: std::cout << "bitcast "; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
printType(unyInst->getType());
|
||||
std::cout << " ";
|
||||
|
||||
// Special handling for negation
|
||||
if (pInst->getKind() == Kind::kNeg || pInst->getKind() == Kind::kNot) {
|
||||
std::cout << "i32 0, ";
|
||||
}
|
||||
|
||||
printValue(pInst->getOperand(0));
|
||||
|
||||
// For bitcast, need to specify destination type
|
||||
if (pInst->getKind() == Kind::kBitFtoI || pInst->getKind() == Kind::kBitItoF) {
|
||||
std::cout << " to ";
|
||||
printType(unyInst->getType());
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kCall: {
|
||||
auto callInst = dynamic_cast<CallInst *>(pInst);
|
||||
auto function = callInst->getCallee();
|
||||
|
||||
if (!callInst->getName().empty()) {
|
||||
std::cout << "%" << callInst->getName() << " = ";
|
||||
}
|
||||
|
||||
std::cout << "call ";
|
||||
printType(callInst->getType());
|
||||
std::cout << " @" << function->getName() << "(";
|
||||
|
||||
auto params = callInst->getArguments();
|
||||
bool first = true;
|
||||
for (auto ¶m : params) {
|
||||
if (!first) std::cout << ", ";
|
||||
first = false;
|
||||
printType(param->getValue()->getType());
|
||||
std::cout << " ";
|
||||
printValue(param->getValue());
|
||||
}
|
||||
|
||||
std::cout << ")" << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kCondBr: {
|
||||
auto condBrInst = dynamic_cast<CondBrInst *>(pInst);
|
||||
std::cout << "br i1 ";
|
||||
printValue(condBrInst->getCondition());
|
||||
std::cout << ", label %" << condBrInst->getThenBlock()->getName();
|
||||
std::cout << ", label %" << condBrInst->getElseBlock()->getName();
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kBr: {
|
||||
auto brInst = dynamic_cast<UncondBrInst *>(pInst);
|
||||
std::cout << "br label %" << brInst->getBlock()->getName();
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kReturn: {
|
||||
auto retInst = dynamic_cast<ReturnInst *>(pInst);
|
||||
std::cout << "ret ";
|
||||
if (retInst->getNumOperands() != 0) {
|
||||
printType(retInst->getOperand(0)->getType());
|
||||
std::cout << " ";
|
||||
printValue(retInst->getOperand(0));
|
||||
} else {
|
||||
std::cout << "void";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kAlloca: {
|
||||
auto allocaInst = dynamic_cast<AllocaInst *>(pInst);
|
||||
std::cout << "%" << allocaInst->getName() << " = alloca ";
|
||||
|
||||
auto baseType = dynamic_cast<PointerType *>(allocaInst->getType())->getBaseType();
|
||||
printType(baseType);
|
||||
|
||||
if (allocaInst->getNumDims() > 0) {
|
||||
std::cout << ", ";
|
||||
for (size_t i = 0; i < allocaInst->getNumDims(); i++) {
|
||||
if (i > 0) std::cout << ", ";
|
||||
printType(Type::getIntType());
|
||||
std::cout << " ";
|
||||
printValue(allocaInst->getDim(i));
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << ", align 4" << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kLoad: {
|
||||
auto loadInst = dynamic_cast<LoadInst *>(pInst);
|
||||
std::cout << "%" << loadInst->getName() << " = load ";
|
||||
printType(loadInst->getType());
|
||||
std::cout << ", ";
|
||||
printType(loadInst->getPointer()->getType());
|
||||
std::cout << " ";
|
||||
printValue(loadInst->getPointer());
|
||||
|
||||
if (loadInst->getNumIndices() > 0) {
|
||||
std::cout << ", ";
|
||||
for (size_t i = 0; i < loadInst->getNumIndices(); i++) {
|
||||
if (i > 0) std::cout << ", ";
|
||||
printType(Type::getIntType());
|
||||
std::cout << " ";
|
||||
printValue(loadInst->getIndex(i));
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << ", align 4" << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kLa: {
|
||||
auto laInst = dynamic_cast<LaInst *>(pInst);
|
||||
std::cout << "%" << laInst->getName() << " = getelementptr inbounds ";
|
||||
|
||||
auto ptrType = dynamic_cast<PointerType*>(laInst->getPointer()->getType());
|
||||
printType(ptrType->getBaseType());
|
||||
std::cout << ", ";
|
||||
printType(laInst->getPointer()->getType());
|
||||
std::cout << " ";
|
||||
printValue(laInst->getPointer());
|
||||
std::cout << ", ";
|
||||
|
||||
for (size_t i = 0; i < laInst->getNumIndices(); i++) {
|
||||
if (i > 0) std::cout << ", ";
|
||||
printType(Type::getIntType());
|
||||
std::cout << " ";
|
||||
printValue(laInst->getIndex(i));
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kStore: {
|
||||
auto storeInst = dynamic_cast<StoreInst *>(pInst);
|
||||
std::cout << "store ";
|
||||
printType(storeInst->getValue()->getType());
|
||||
std::cout << " ";
|
||||
printValue(storeInst->getValue());
|
||||
std::cout << ", ";
|
||||
printType(storeInst->getPointer()->getType());
|
||||
std::cout << " ";
|
||||
printValue(storeInst->getPointer());
|
||||
|
||||
if (storeInst->getNumIndices() > 0) {
|
||||
std::cout << ", ";
|
||||
for (size_t i = 0; i < storeInst->getNumIndices(); i++) {
|
||||
if (i > 0) std::cout << ", ";
|
||||
printType(Type::getIntType());
|
||||
std::cout << " ";
|
||||
printValue(storeInst->getIndex(i));
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << ", align 4" << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kMemset: {
|
||||
auto memsetInst = dynamic_cast<MemsetInst *>(pInst);
|
||||
std::cout << "call void @llvm.memset.p0.";
|
||||
printType(memsetInst->getPointer()->getType());
|
||||
std::cout << "(";
|
||||
printType(memsetInst->getPointer()->getType());
|
||||
std::cout << " ";
|
||||
printValue(memsetInst->getPointer());
|
||||
std::cout << ", i8 ";
|
||||
printValue(memsetInst->getValue());
|
||||
std::cout << ", i32 ";
|
||||
printValue(memsetInst->getSize());
|
||||
std::cout << ", i1 false)" << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kPhi: {
|
||||
auto phiInst = dynamic_cast<PhiInst *>(pInst);
|
||||
printValue(phiInst->getOperand(0));
|
||||
std::cout << " = phi ";
|
||||
printType(phiInst->getType());
|
||||
|
||||
for (unsigned i = 1; i < phiInst->getNumOperands(); i++) {
|
||||
if (i > 0) std::cout << ", ";
|
||||
std::cout << "[ ";
|
||||
printValue(phiInst->getOperand(i));
|
||||
std::cout << " ]";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kGetSubArray: {
|
||||
auto getSubArrayInst = dynamic_cast<GetSubArrayInst *>(pInst);
|
||||
std::cout << "%" << getSubArrayInst->getName() << " = getelementptr inbounds ";
|
||||
|
||||
auto ptrType = dynamic_cast<PointerType*>(getSubArrayInst->getFatherArray()->getType());
|
||||
printType(ptrType->getBaseType());
|
||||
std::cout << ", ";
|
||||
printType(getSubArrayInst->getFatherArray()->getType());
|
||||
std::cout << " ";
|
||||
printValue(getSubArrayInst->getFatherArray());
|
||||
std::cout << ", ";
|
||||
bool firstIndex = true;
|
||||
for (auto &index : getSubArrayInst->getIndices()) {
|
||||
if (!firstIndex) std::cout << ", ";
|
||||
firstIndex = false;
|
||||
printType(Type::getIntType());
|
||||
std::cout << " ";
|
||||
printValue(index->getValue());
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
default:
|
||||
assert(false && "Unsupported instruction kind");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
24
src/backend/RISCv64/CMakeLists.txt
Normal file
24
src/backend/RISCv64/CMakeLists.txt
Normal file
@ -0,0 +1,24 @@
|
||||
# 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
|
||||
Handler/EliminateFrameIndices.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 头文件路径 (已存在)
|
||||
)
|
||||
51
src/backend/RISCv64/Handler/CalleeSavedHandler.cpp
Normal file
51
src/backend/RISCv64/Handler/CalleeSavedHandler.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
#include "CalleeSavedHandler.h"
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
char CalleeSavedHandler::ID = 0;
|
||||
|
||||
bool CalleeSavedHandler::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
// This pass works on MachineFunction level, not IR level
|
||||
return false;
|
||||
}
|
||||
|
||||
void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
||||
const std::set<PhysicalReg>& used_callee_saved = frame_info.used_callee_saved_regs;
|
||||
|
||||
if (used_callee_saved.empty()) {
|
||||
frame_info.callee_saved_size = 0;
|
||||
frame_info.callee_saved_regs_to_store.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 计算被调用者保存寄存器所需的总空间大小
|
||||
// s0 总是由 PEI Pass 单独处理,这里不计入大小,但要确保它在列表中
|
||||
int size = 0;
|
||||
std::set<PhysicalReg> regs_to_save = used_callee_saved;
|
||||
if (regs_to_save.count(PhysicalReg::S0)) {
|
||||
regs_to_save.erase(PhysicalReg::S0);
|
||||
}
|
||||
size = regs_to_save.size() * 8; // 每个寄存器占8字节 (64-bit)
|
||||
frame_info.callee_saved_size = size;
|
||||
|
||||
// 2. 创建一个有序的、需要保存的寄存器列表,以便后续 Pass 确定地生成代码
|
||||
// s0 不应包含在此列表中,因为它由 PEI Pass 特殊处理
|
||||
std::vector<PhysicalReg> sorted_regs(regs_to_save.begin(), regs_to_save.end());
|
||||
std::sort(sorted_regs.begin(), sorted_regs.end(), [](PhysicalReg a, PhysicalReg b){
|
||||
return static_cast<int>(a) < static_cast<int>(b);
|
||||
});
|
||||
frame_info.callee_saved_regs_to_store = sorted_regs;
|
||||
|
||||
// 3. [关键修正] 更新栈帧总大小。
|
||||
// 这是初步计算,PEI Pass 会进行最终的对齐。
|
||||
frame_info.total_size = frame_info.locals_size +
|
||||
frame_info.spill_size +
|
||||
frame_info.callee_saved_size;
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
198
src/backend/RISCv64/Handler/EliminateFrameIndices.cpp
Normal file
198
src/backend/RISCv64/Handler/EliminateFrameIndices.cpp
Normal file
@ -0,0 +1,198 @@
|
||||
#include "EliminateFrameIndices.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include <cassert>
|
||||
#include <vector> // [新增] 为插入指令而包含
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// getTypeSizeInBytes 是一个通用辅助函数,保持不变
|
||||
unsigned EliminateFrameIndicesPass::getTypeSizeInBytes(Type* type) {
|
||||
if (!type) {
|
||||
assert(false && "Cannot get size of a null type.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (type->getKind()) {
|
||||
case Type::kInt:
|
||||
case Type::kFloat:
|
||||
return 4;
|
||||
case Type::kPointer:
|
||||
return 8;
|
||||
case Type::kArray: {
|
||||
auto arrayType = type->as<ArrayType>();
|
||||
return arrayType->getNumElements() * getTypeSizeInBytes(arrayType->getElementType());
|
||||
}
|
||||
default:
|
||||
assert(false && "Unsupported type for size calculation.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void EliminateFrameIndicesPass::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
||||
Function* F = mfunc->getFunc();
|
||||
RISCv64ISel* isel = mfunc->getISel();
|
||||
|
||||
// 1. [已移除] 不再处理栈传递的参数
|
||||
// 原先处理栈参数 (arg_idx >= 8) 的逻辑已被移除。
|
||||
// 这项职责已完全转移到 PrologueEpilogueInsertionPass,以避免逻辑冲突和错误。
|
||||
// [注释更新] -> 上述注释已过时。根据新方案,我们将在这里处理栈传递的参数,
|
||||
// 以便在寄存器分配前就将数据流显式化,修复溢出逻辑的BUG。
|
||||
|
||||
// 2. 只为局部变量(AllocaInst)分配栈空间和计算偏移量
|
||||
// 局部变量从 s0 下方(负偏移量)开始分配,紧接着为 ra 和 s0 预留的16字节之后
|
||||
int local_var_offset = 16;
|
||||
|
||||
if(F) { // 确保函数指针有效
|
||||
for (auto& bb : F->getBasicBlocks()) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
if (auto alloca = dynamic_cast<AllocaInst*>(inst.get())) {
|
||||
Type* allocated_type = alloca->getType()->as<PointerType>()->getBaseType();
|
||||
int size = getTypeSizeInBytes(allocated_type);
|
||||
|
||||
// RISC-V要求栈地址8字节对齐
|
||||
size = (size + 7) & ~7;
|
||||
if (size == 0) size = 8; // 至少分配8字节
|
||||
|
||||
local_var_offset += size;
|
||||
unsigned alloca_vreg = isel->getVReg(alloca);
|
||||
// 局部变量使用相对于s0的负向偏移
|
||||
frame_info.alloca_offsets[alloca_vreg] = -local_var_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 记录仅由AllocaInst分配的局部变量的总大小
|
||||
frame_info.locals_size = local_var_offset - 16;
|
||||
|
||||
// 3. [核心修改] 在函数入口为所有栈传递的参数插入load指令
|
||||
// 这个步骤至关重要:它在寄存器分配之前,为这些参数的vreg创建了明确的“定义(def)”指令。
|
||||
// 这解决了在高寄存器压力下,当这些vreg被溢出时,`rewriteProgram`找不到其定义点而崩溃的问题。
|
||||
if (F && isel && !mfunc->getBlocks().empty()) {
|
||||
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
|
||||
std::vector<std::unique_ptr<MachineInstr>> arg_load_instrs;
|
||||
int arg_idx = 0;
|
||||
for (Argument* arg : F->getArguments()) {
|
||||
// 根据ABI,前8个整型/指针参数通过寄存器传递,这里只处理超出部分。
|
||||
if (arg_idx >= 8) {
|
||||
// 计算参数在调用者栈帧中的位置,该位置相对于被调用者的帧指针s0是正向偏移。
|
||||
// 第9个参数(arg_idx=8)位于 0(s0),第10个(arg_idx=9)位于 8(s0),以此类推。
|
||||
int offset = (arg_idx - 8) * 8;
|
||||
unsigned arg_vreg = isel->getVReg(arg);
|
||||
Type* arg_type = arg->getType();
|
||||
|
||||
// 根据参数类型选择正确的加载指令
|
||||
RVOpcodes load_op;
|
||||
if (arg_type->isFloat()) {
|
||||
load_op = RVOpcodes::FLW; // 单精度浮点
|
||||
} else if (arg_type->isPointer()) {
|
||||
load_op = RVOpcodes::LD; // 64位指针
|
||||
} else {
|
||||
load_op = RVOpcodes::LW; // 32位整数
|
||||
}
|
||||
|
||||
// 创建加载指令: lw/ld/flw vreg, offset(s0)
|
||||
auto load_instr = std::make_unique<MachineInstr>(load_op);
|
||||
load_instr->addOperand(std::make_unique<RegOperand>(arg_vreg));
|
||||
load_instr->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0), // 基址为帧指针
|
||||
std::make_unique<ImmOperand>(offset)
|
||||
));
|
||||
arg_load_instrs.push_back(std::move(load_instr));
|
||||
}
|
||||
arg_idx++;
|
||||
}
|
||||
|
||||
// 将所有新创建的参数加载指令一次性插入到入口块的起始位置
|
||||
auto& entry_instrs = entry_block->getInstructions();
|
||||
entry_instrs.insert(entry_instrs.begin(),
|
||||
std::make_move_iterator(arg_load_instrs.begin()),
|
||||
std::make_move_iterator(arg_load_instrs.end()));
|
||||
}
|
||||
|
||||
|
||||
// 4. 遍历所有机器指令,将访问局部变量的伪指令展开为真实指令
|
||||
// 由于处理参数的逻辑已移除,这里的展开现在只针对局部变量,因此是正确的。
|
||||
// [注释更新] -> 上述注释已过时。此部分逻辑保持不变,它正确地处理了局部变量。
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
std::vector<std::unique_ptr<MachineInstr>> new_instructions;
|
||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||
RVOpcodes opcode = instr_ptr->getOpcode();
|
||||
|
||||
if (opcode == RVOpcodes::FRAME_LOAD_W || opcode == RVOpcodes::FRAME_LOAD_D || opcode == RVOpcodes::FRAME_LOAD_F) {
|
||||
RVOpcodes real_load_op;
|
||||
if (opcode == RVOpcodes::FRAME_LOAD_W) real_load_op = RVOpcodes::LW;
|
||||
else if (opcode == RVOpcodes::FRAME_LOAD_D) real_load_op = RVOpcodes::LD;
|
||||
else real_load_op = RVOpcodes::FLW;
|
||||
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
unsigned dest_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
|
||||
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
|
||||
int offset = frame_info.alloca_offsets.at(alloca_vreg);
|
||||
auto addr_vreg = isel->getNewVReg(Type::getPointerType(Type::getIntType()));
|
||||
|
||||
// 展开为: addi addr_vreg, s0, offset
|
||||
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
addi->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
||||
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
addi->addOperand(std::make_unique<ImmOperand>(offset));
|
||||
new_instructions.push_back(std::move(addi));
|
||||
|
||||
// 展开为: lw/ld/flw dest_vreg, 0(addr_vreg)
|
||||
auto load_instr = std::make_unique<MachineInstr>(real_load_op);
|
||||
load_instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
load_instr->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(addr_vreg),
|
||||
std::make_unique<ImmOperand>(0)));
|
||||
new_instructions.push_back(std::move(load_instr));
|
||||
|
||||
} else if (opcode == RVOpcodes::FRAME_STORE_W || opcode == RVOpcodes::FRAME_STORE_D || opcode == RVOpcodes::FRAME_STORE_F) {
|
||||
RVOpcodes real_store_op;
|
||||
if (opcode == RVOpcodes::FRAME_STORE_W) real_store_op = RVOpcodes::SW;
|
||||
else if (opcode == RVOpcodes::FRAME_STORE_D) real_store_op = RVOpcodes::SD;
|
||||
else real_store_op = RVOpcodes::FSW;
|
||||
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
unsigned src_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
|
||||
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
|
||||
int offset = frame_info.alloca_offsets.at(alloca_vreg);
|
||||
auto addr_vreg = isel->getNewVReg(Type::getPointerType(Type::getIntType()));
|
||||
|
||||
// 展开为: addi addr_vreg, s0, offset
|
||||
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
addi->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
||||
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
addi->addOperand(std::make_unique<ImmOperand>(offset));
|
||||
new_instructions.push_back(std::move(addi));
|
||||
|
||||
// 展开为: sw/sd/fsw src_vreg, 0(addr_vreg)
|
||||
auto store_instr = std::make_unique<MachineInstr>(real_store_op);
|
||||
store_instr->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
store_instr->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(addr_vreg),
|
||||
std::make_unique<ImmOperand>(0)));
|
||||
new_instructions.push_back(std::move(store_instr));
|
||||
|
||||
} else if (instr_ptr->getOpcode() == RVOpcodes::FRAME_ADDR) {
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
unsigned dest_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
|
||||
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
|
||||
int offset = frame_info.alloca_offsets.at(alloca_vreg);
|
||||
|
||||
// 将 `frame_addr rd, rs` 展开为 `addi rd, s0, offset`
|
||||
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
addi->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
addi->addOperand(std::make_unique<ImmOperand>(offset));
|
||||
new_instructions.push_back(std::move(addi));
|
||||
|
||||
} else {
|
||||
new_instructions.push_back(std::move(instr_ptr));
|
||||
}
|
||||
}
|
||||
mbb->getInstructions() = std::move(new_instructions);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
171
src/backend/RISCv64/Handler/LegalizeImmediates.cpp
Normal file
171
src/backend/RISCv64/Handler/LegalizeImmediates.cpp
Normal file
@ -0,0 +1,171 @@
|
||||
#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();
|
||||
// 确保操作数足够多,以防万一
|
||||
if (operands.size() < 3) break;
|
||||
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:
|
||||
case RVOpcodes::FLW: case RVOpcodes::FSW: {
|
||||
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
|
||||
186
src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp
Normal file
186
src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp
Normal file
@ -0,0 +1,186 @@
|
||||
#include "PrologueEpilogueInsertion.h"
|
||||
#include "RISCv64LLIR.h" // 假设包含了 PhysicalReg, RVOpcodes 等定义
|
||||
#include "RISCv64ISel.h"
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
char PrologueEpilogueInsertionPass::ID = 0;
|
||||
|
||||
void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
||||
Function* F = mfunc->getFunc();
|
||||
RISCv64ISel* isel = mfunc->getISel();
|
||||
|
||||
// 1. 清理 KEEPALIVE 伪指令
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
auto& instrs = mbb->getInstructions();
|
||||
instrs.erase(
|
||||
std::remove_if(instrs.begin(), instrs.end(),
|
||||
[](const std::unique_ptr<MachineInstr>& instr) {
|
||||
return instr->getOpcode() == RVOpcodes::PSEUDO_KEEPALIVE;
|
||||
}
|
||||
),
|
||||
instrs.end()
|
||||
);
|
||||
}
|
||||
|
||||
// 2. [新增] 确定需要保存的被调用者保存寄存器 (callee-saved)
|
||||
// 这部分逻辑从 CalleeSavedHandler Pass 移入,以集中管理序言生成
|
||||
auto& vreg_to_preg_map = frame_info.vreg_to_preg_map;
|
||||
std::set<PhysicalReg> used_callee_saved_regs_set;
|
||||
const auto& callee_saved_int = getCalleeSavedIntRegs();
|
||||
const auto& callee_saved_fp = getCalleeSavedFpRegs();
|
||||
|
||||
for (const auto& pair : vreg_to_preg_map) {
|
||||
PhysicalReg preg = pair.second;
|
||||
// 检查是否在整数或浮点 callee-saved 集合中
|
||||
// 注意:s0作为帧指针,由序言/尾声逻辑特殊处理,不在此处保存
|
||||
bool is_int_cs = std::find(callee_saved_int.begin(), callee_saved_int.end(), preg) != callee_saved_int.end();
|
||||
bool is_fp_cs = std::find(callee_saved_fp.begin(), callee_saved_fp.end(), preg) != callee_saved_fp.end();
|
||||
if ((is_int_cs && preg != PhysicalReg::S0) || is_fp_cs) {
|
||||
used_callee_saved_regs_set.insert(preg);
|
||||
}
|
||||
}
|
||||
// 为了确定性排序,并存入 frame_info 供尾声使用
|
||||
frame_info.callee_saved_regs_to_store.assign(
|
||||
used_callee_saved_regs_set.begin(), used_callee_saved_regs_set.end()
|
||||
);
|
||||
std::sort(frame_info.callee_saved_regs_to_store.begin(), frame_info.callee_saved_regs_to_store.end());
|
||||
frame_info.callee_saved_size = frame_info.callee_saved_regs_to_store.size() * 8; // 每个寄存器8字节
|
||||
|
||||
// 3. 计算最终的栈帧总大小
|
||||
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; // 16字节对齐
|
||||
frame_info.total_size = aligned_stack_size;
|
||||
|
||||
// 只有在需要分配栈空间时才生成序言和尾声
|
||||
if (aligned_stack_size > 0) {
|
||||
// --- 4. 插入完整的序言 ---
|
||||
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
|
||||
auto& entry_instrs = entry_block->getInstructions();
|
||||
std::vector<std::unique_ptr<MachineInstr>> prologue_instrs;
|
||||
|
||||
// 4.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));
|
||||
|
||||
// 4.2. 保存 ra 和 s0
|
||||
// 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));
|
||||
// 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.3. 设置新的帧指针 s0: 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));
|
||||
|
||||
// 4.4. [新增] 保存所有使用到的被调用者保存寄存器
|
||||
// 它们保存在 s0 下方,紧接着 ra/s0 的位置
|
||||
int callee_saved_offset = -16;
|
||||
for (const auto& reg : frame_info.callee_saved_regs_to_store) {
|
||||
callee_saved_offset -= 8;
|
||||
RVOpcodes store_op = (reg >= PhysicalReg::F0 && reg <= PhysicalReg::F31) ? RVOpcodes::FSD : RVOpcodes::SD;
|
||||
auto save_cs_reg = std::make_unique<MachineInstr>(store_op);
|
||||
save_cs_reg->addOperand(std::make_unique<RegOperand>(reg));
|
||||
save_cs_reg->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(callee_saved_offset)
|
||||
));
|
||||
prologue_instrs.push_back(std::move(save_cs_reg));
|
||||
}
|
||||
|
||||
// 4.5. [核心修改] 加载栈传递参数的逻辑已从此移除
|
||||
// 这项工作已经前移至 `EliminateFrameIndicesPass` 中完成,
|
||||
// 以确保在寄存器分配前就将相关虚拟寄存器定义,从而修复溢出逻辑的bug。
|
||||
|
||||
// 4.6. 将所有生成的序言指令一次性插入到函数入口
|
||||
entry_instrs.insert(entry_instrs.begin(),
|
||||
std::make_move_iterator(prologue_instrs.begin()),
|
||||
std::make_move_iterator(prologue_instrs.end()));
|
||||
|
||||
// --- 5. 插入完整的尾声 ---
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
// [修正] 使用前向迭代器查找RET指令,以确保在正确的位置(RET之前)插入尾声。
|
||||
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
|
||||
if ((*it)->getOpcode() == RVOpcodes::RET) {
|
||||
std::vector<std::unique_ptr<MachineInstr>> epilogue_instrs;
|
||||
|
||||
// 5.1. [新增] 恢复被调用者保存寄存器
|
||||
callee_saved_offset = -16;
|
||||
for (const auto& reg : frame_info.callee_saved_regs_to_store) {
|
||||
callee_saved_offset -= 8;
|
||||
RVOpcodes load_op = (reg >= PhysicalReg::F0 && reg <= PhysicalReg::F31) ? RVOpcodes::FLD : RVOpcodes::LD;
|
||||
auto restore_cs_reg = std::make_unique<MachineInstr>(load_op);
|
||||
restore_cs_reg->addOperand(std::make_unique<RegOperand>(reg));
|
||||
restore_cs_reg->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(callee_saved_offset)
|
||||
));
|
||||
epilogue_instrs.push_back(std::move(restore_cs_reg));
|
||||
}
|
||||
|
||||
// 5.2. 恢复 ra 和 s0 (注意基址现在是sp)
|
||||
// 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));
|
||||
// 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));
|
||||
|
||||
// 5.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));
|
||||
|
||||
// 将尾声指令插入到 RET 指令之前
|
||||
mbb->getInstructions().insert(it,
|
||||
std::make_move_iterator(epilogue_instrs.begin()),
|
||||
std::make_move_iterator(epilogue_instrs.end()));
|
||||
|
||||
// 一个基本块通常只有一个终止指令,处理完就可以跳到下一个块
|
||||
goto next_block;
|
||||
}
|
||||
}
|
||||
next_block:;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
652
src/backend/RISCv64/Optimize/Peephole.cpp
Normal file
652
src/backend/RISCv64/Optimize/Peephole.cpp
Normal 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
|
||||
416
src/backend/RISCv64/Optimize/PostRA_Scheduler.cpp
Normal file
416
src/backend/RISCv64/Optimize/PostRA_Scheduler.cpp
Normal file
@ -0,0 +1,416 @@
|
||||
#include "PostRA_Scheduler.h"
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#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;
|
||||
}
|
||||
|
||||
// 预计算指令信息的缓存
|
||||
static std::unordered_map<MachineInstr *, InstrRegInfo> instr_info_cache;
|
||||
|
||||
// 获取指令定义的寄存器 - 优化版本
|
||||
std::unordered_set<PhysicalReg> getDefinedRegisters(MachineInstr *instr) {
|
||||
std::unordered_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::unordered_set<PhysicalReg> getUsedRegisters(MachineInstr *instr) {
|
||||
std::unordered_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;
|
||||
}
|
||||
|
||||
// 获取内存访问的基址和偏移
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
// 预计算指令信息
|
||||
InstrRegInfo &getInstrInfo(MachineInstr *instr) {
|
||||
auto it = instr_info_cache.find(instr);
|
||||
if (it != instr_info_cache.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
InstrRegInfo &info = instr_info_cache[instr];
|
||||
info.defined_regs = getDefinedRegisters(instr);
|
||||
info.used_regs = getUsedRegisters(instr);
|
||||
info.is_load = isLoadInstr(instr);
|
||||
info.is_store = isStoreInstr(instr);
|
||||
info.is_control_flow = isControlFlowInstr(instr);
|
||||
info.mem_access = getMemoryAccess(instr);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
// 检查内存依赖 - 优化版本
|
||||
bool hasMemoryDependency(const InstrRegInfo &info1, const InstrRegInfo &info2) {
|
||||
// 如果都不是内存指令,没有内存依赖
|
||||
if (!info1.is_load && !info1.is_store && !info2.is_load && !info2.is_store) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const MemoryAccess &mem1 = info1.mem_access;
|
||||
const MemoryAccess &mem2 = info2.mem_access;
|
||||
|
||||
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 info1.is_store || info2.is_store;
|
||||
}
|
||||
|
||||
// 不同内存位置通常没有依赖,但为了安全起见,
|
||||
// 如果涉及store指令,我们需要更保守
|
||||
if (info1.is_store && info2.is_load) {
|
||||
// 保守处理:不同store和load之间可能有别名
|
||||
return false; // 这里可以根据需要调整策略
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查两个指令之间是否存在依赖关系 - 优化版本
|
||||
bool hasDependency(MachineInstr *instr1, MachineInstr *instr2) {
|
||||
const InstrRegInfo &info1 = getInstrInfo(instr1);
|
||||
const InstrRegInfo &info2 = getInstrInfo(instr2);
|
||||
|
||||
// 检查RAW依赖:instr1定义的寄存器是否被instr2使用
|
||||
for (const auto ® : info1.defined_regs) {
|
||||
if (info2.used_regs.find(reg) != info2.used_regs.end()) {
|
||||
return true; // RAW依赖 - instr2读取instr1写入的值
|
||||
}
|
||||
}
|
||||
|
||||
// 检查WAR依赖:instr1使用的寄存器是否被instr2定义
|
||||
for (const auto ® : info1.used_regs) {
|
||||
if (info2.defined_regs.find(reg) != info2.defined_regs.end()) {
|
||||
return true; // WAR依赖 - instr2覆盖instr1需要的值
|
||||
}
|
||||
}
|
||||
|
||||
// 检查WAW依赖:两个指令定义相同寄存器
|
||||
for (const auto ® : info1.defined_regs) {
|
||||
if (info2.defined_regs.find(reg) != info2.defined_regs.end()) {
|
||||
return true; // WAW依赖 - 两条指令写入同一寄存器
|
||||
}
|
||||
}
|
||||
|
||||
// 检查内存依赖
|
||||
if (hasMemoryDependency(info1, info2)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否可以安全地将instr1和instr2交换位置 - 优化版本
|
||||
bool canSwapInstructions(MachineInstr *instr1, MachineInstr *instr2) {
|
||||
const InstrRegInfo &info1 = getInstrInfo(instr1);
|
||||
const InstrRegInfo &info2 = getInstrInfo(instr2);
|
||||
|
||||
// 不能移动控制流指令
|
||||
if (info1.is_control_flow || info2.is_control_flow) {
|
||||
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];
|
||||
|
||||
const InstrRegInfo &info_earlier = getInstrInfo(earlier);
|
||||
const InstrRegInfo &info_later = getInstrInfo(later);
|
||||
|
||||
// 检查是否存在被违反的依赖关系
|
||||
// 检查RAW依赖
|
||||
for (const auto ® : info_earlier.defined_regs) {
|
||||
if (info_later.used_regs.find(reg) != info_later.used_regs.end()) {
|
||||
// 这是正常的依赖关系,earlier应该在later之前
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查内存依赖
|
||||
if (hasMemoryDependency(info_earlier, info_later)) {
|
||||
const MemoryAccess &mem1 = info_earlier.mem_access;
|
||||
const MemoryAccess &mem2 = info_later.mem_access;
|
||||
|
||||
if (mem1.valid && mem2.valid && mem1.base_reg == mem2.base_reg &&
|
||||
mem1.offset == mem2.offset) {
|
||||
if (info_earlier.is_store && info_later.is_load) {
|
||||
// Store->Load依赖,顺序正确
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 在基本块内对指令进行调度优化 - 优化版本
|
||||
void scheduleBlock(MachineBasicBlock *mbb) {
|
||||
auto &instructions = mbb->getInstructions();
|
||||
if (instructions.size() <= 1)
|
||||
return;
|
||||
if (instructions.size() > MAX_SCHEDULING_BLOCK_SIZE) {
|
||||
return; // 跳过超大块,防止卡住
|
||||
}
|
||||
|
||||
// 清理缓存,避免无效指针
|
||||
instr_info_cache.clear();
|
||||
|
||||
std::vector<MachineInstr *> instr_list;
|
||||
instr_list.reserve(instructions.size()); // 预分配容量
|
||||
for (auto &instr : instructions) {
|
||||
instr_list.push_back(instr.get());
|
||||
}
|
||||
|
||||
// 预计算所有指令的信息
|
||||
for (auto *instr : instr_list) {
|
||||
getInstrInfo(instr);
|
||||
}
|
||||
|
||||
// 使用更严格的调度策略,避免破坏依赖关系
|
||||
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];
|
||||
|
||||
const InstrRegInfo &info1 = getInstrInfo(instr1);
|
||||
const InstrRegInfo &info2 = getInstrInfo(instr2);
|
||||
|
||||
// 只进行非常保守的优化
|
||||
bool should_swap = false;
|
||||
|
||||
// 策略1: 将load指令提前,减少load-use延迟
|
||||
if (info2.is_load && !info1.is_load && !info1.is_store) {
|
||||
should_swap = canSwapInstructions(instr1, instr2);
|
||||
}
|
||||
// 策略2: 将非关键store指令延后,为其他指令让路
|
||||
else if (info1.is_store && !info2.is_load && !info2.is_store) {
|
||||
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::unordered_map<MachineInstr *, std::unique_ptr<MachineInstr>> instr_map;
|
||||
instr_map.reserve(instructions.size()); // 预分配容量
|
||||
for (auto &instr : instructions) {
|
||||
instr_map[instr.get()] = std::move(instr);
|
||||
}
|
||||
|
||||
instructions.clear();
|
||||
instructions.reserve(instr_list.size()); // 预分配容量
|
||||
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());
|
||||
}
|
||||
|
||||
// 清理全局缓存
|
||||
instr_info_cache.clear();
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
466
src/backend/RISCv64/Optimize/PreRA_Scheduler.cpp
Normal file
466
src/backend/RISCv64/Optimize/PreRA_Scheduler.cpp
Normal file
@ -0,0 +1,466 @@
|
||||
#include "PreRA_Scheduler.h"
|
||||
#include "RISCv64LLIR.h"
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include <unordered_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);
|
||||
}
|
||||
|
||||
// 获取内存访问位置信息
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
// 缓存指令分析信息
|
||||
struct InstrInfo {
|
||||
std::unordered_set<unsigned> defined_regs;
|
||||
std::unordered_set<unsigned> used_regs;
|
||||
MemoryLocation mem_location;
|
||||
bool is_load;
|
||||
bool is_store;
|
||||
bool is_terminator;
|
||||
bool is_call;
|
||||
bool has_side_effect;
|
||||
bool has_memory_access;
|
||||
|
||||
InstrInfo() : is_load(false), is_store(false), is_terminator(false),
|
||||
is_call(false), has_side_effect(false), has_memory_access(false) {}
|
||||
};
|
||||
|
||||
// 指令信息缓存
|
||||
static std::unordered_map<MachineInstr*, InstrInfo> instr_info_cache;
|
||||
|
||||
// 获取指令定义的虚拟寄存器 - 优化版本
|
||||
static std::unordered_set<unsigned> getDefinedVirtualRegisters(MachineInstr *instr) {
|
||||
std::unordered_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::unordered_set<unsigned> getUsedVirtualRegisters(MachineInstr *instr) {
|
||||
std::unordered_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;
|
||||
}
|
||||
|
||||
// 获取内存访问位置
|
||||
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 const InstrInfo& getInstrInfo(MachineInstr *instr) {
|
||||
auto it = instr_info_cache.find(instr);
|
||||
if (it != instr_info_cache.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
InstrInfo& info = instr_info_cache[instr];
|
||||
info.defined_regs = getDefinedVirtualRegisters(instr);
|
||||
info.used_regs = getUsedVirtualRegisters(instr);
|
||||
info.mem_location = getMemoryLocation(instr);
|
||||
info.is_load = isLoadInstr(instr);
|
||||
info.is_store = isStoreInstr(instr);
|
||||
info.is_terminator = isTerminatorInstr(instr);
|
||||
info.is_call = isCallInstr(instr);
|
||||
info.has_side_effect = hasSideEffect(instr);
|
||||
info.has_memory_access = hasMemoryAccess(instr);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
// 检查两个内存位置是否可能别名
|
||||
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) {
|
||||
const InstrInfo& info_first = getInstrInfo(first);
|
||||
const InstrInfo& info_second = getInstrInfo(second);
|
||||
|
||||
// RAW依赖: second读取first写入的寄存器
|
||||
for (const auto ® : info_first.defined_regs) {
|
||||
if (info_second.used_regs.find(reg) != info_second.used_regs.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// WAR依赖: second写入first读取的寄存器
|
||||
for (const auto ® : info_first.used_regs) {
|
||||
if (info_second.defined_regs.find(reg) != info_second.defined_regs.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// WAW依赖: 两个指令写入同一寄存器
|
||||
for (const auto ® : info_first.defined_regs) {
|
||||
if (info_second.defined_regs.find(reg) != info_second.defined_regs.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查两个指令之间是否存在内存依赖 - 优化版本
|
||||
static bool hasMemoryDependency(MachineInstr *first, MachineInstr *second) {
|
||||
const InstrInfo& info_first = getInstrInfo(first);
|
||||
const InstrInfo& info_second = getInstrInfo(second);
|
||||
|
||||
if (!info_first.has_memory_access || !info_second.has_memory_access) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 如果至少有一个是存储指令,需要检查别名
|
||||
if (info_first.is_store || info_second.is_store) {
|
||||
return mayAlias(info_first.mem_location, info_second.mem_location);
|
||||
}
|
||||
|
||||
return false; // 两个加载指令之间没有依赖
|
||||
}
|
||||
|
||||
// 检查两个指令之间是否存在控制依赖 - 优化版本
|
||||
static bool hasControlDependency(MachineInstr *first, MachineInstr *second) {
|
||||
const InstrInfo& info_first = getInstrInfo(first);
|
||||
const InstrInfo& info_second = getInstrInfo(second);
|
||||
|
||||
// 终结指令与任何其他指令都有控制依赖
|
||||
if (info_first.is_terminator) {
|
||||
return true; // first是终结指令,second不能移动到first之前
|
||||
}
|
||||
|
||||
if (info_second.is_terminator) {
|
||||
return false; // second是终结指令,可以保持在后面
|
||||
}
|
||||
|
||||
// CALL指令具有控制副作用,但可以参与有限的调度
|
||||
if (info_first.is_call || info_second.is_call) {
|
||||
// CALL指令之间保持顺序
|
||||
if (info_first.is_call && info_second.is_call) {
|
||||
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.reserve(instrs.size() / 10); // 预估边界数量
|
||||
boundaries.push_back(0); // 起始边界
|
||||
|
||||
for (size_t i = 0; i < instrs.size(); i++) {
|
||||
const InstrInfo& info = getInstrInfo(instrs[i]);
|
||||
// 终结指令前后都是边界
|
||||
if (info.is_terminator) {
|
||||
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++) {
|
||||
const InstrInfo& info = getInstrInfo(instrs[i]);
|
||||
if (info.is_load) {
|
||||
// 尝试将加载指令向前移动
|
||||
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;
|
||||
}
|
||||
|
||||
// 清理缓存,避免无效指针
|
||||
instr_info_cache.clear();
|
||||
|
||||
// 构建指令列表
|
||||
std::vector<MachineInstr *> instr_list;
|
||||
instr_list.reserve(instructions.size()); // 预分配容量
|
||||
for (auto &instr : instructions) {
|
||||
instr_list.push_back(instr.get());
|
||||
}
|
||||
|
||||
// 预计算所有指令信息
|
||||
for (auto* instr : instr_list) {
|
||||
getInstrInfo(instr);
|
||||
}
|
||||
|
||||
// 找到调度边界
|
||||
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::unordered_map<MachineInstr *, std::unique_ptr<MachineInstr>> instr_map;
|
||||
instr_map.reserve(instructions.size()); // 预分配容量
|
||||
for (auto &instr : instructions) {
|
||||
instr_map[instr.get()] = std::move(instr);
|
||||
}
|
||||
|
||||
instructions.clear();
|
||||
instructions.reserve(instr_list.size()); // 预分配容量
|
||||
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());
|
||||
}
|
||||
|
||||
// 清理全局缓存
|
||||
instr_info_cache.clear();
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@ -7,9 +7,15 @@ namespace sysy {
|
||||
// 检查是否为内存加载/存储指令,以处理特殊的打印格式
|
||||
bool isMemoryOp(RVOpcodes opcode) {
|
||||
switch (opcode) {
|
||||
// --- 整数加载/存储 (原有逻辑) ---
|
||||
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:
|
||||
case RVOpcodes::FLW:
|
||||
case RVOpcodes::FSW:
|
||||
// 如果未来支持双精度,也在这里添加FLD/FSD
|
||||
// case RVOpcodes::FLD:
|
||||
// case RVOpcodes::FSD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -18,78 +24,37 @@ bool isMemoryOp(RVOpcodes opcode) {
|
||||
|
||||
RISCv64AsmPrinter::RISCv64AsmPrinter(MachineFunction* mfunc) : MFunc(mfunc) {}
|
||||
|
||||
void RISCv64AsmPrinter::run(std::ostream& os) {
|
||||
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());
|
||||
printBasicBlock(mbb.get(), debug);
|
||||
}
|
||||
}
|
||||
|
||||
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 << " mv s0, sp\n";
|
||||
}
|
||||
|
||||
// 忠实还原保存函数入口参数的逻辑
|
||||
Function* F = MFunc->getFunc();
|
||||
if (F && F->getEntryBlock()) {
|
||||
int arg_idx = 0;
|
||||
RISCv64ISel* isel = MFunc->getISel();
|
||||
for (AllocaInst* alloca_for_param : F->getEntryBlock()->getArguments()) {
|
||||
if (arg_idx >= 8) break;
|
||||
|
||||
unsigned vreg = isel->getVReg(alloca_for_param);
|
||||
if (frame_info.alloca_offsets.count(vreg)) {
|
||||
int offset = frame_info.alloca_offsets.at(vreg);
|
||||
auto arg_reg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + arg_idx);
|
||||
*OS << " sw " << regToString(arg_reg) << ", " << offset << "(s0)\n";
|
||||
}
|
||||
arg_idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
void RISCv64AsmPrinter::printBasicBlock(MachineBasicBlock* mbb, bool debug) {
|
||||
if (!mbb->getName().empty()) {
|
||||
*OS << mbb->getName() << ":\n";
|
||||
}
|
||||
for (auto& instr : mbb->getInstructions()) {
|
||||
printInstruction(instr.get());
|
||||
printInstruction(instr.get(), debug);
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64AsmPrinter::printInstruction(MachineInstr* instr) {
|
||||
void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
|
||||
auto opcode = instr->getOpcode();
|
||||
if (opcode == RVOpcodes::RET) {
|
||||
printEpilogue();
|
||||
|
||||
if (opcode == RVOpcodes::LABEL) {
|
||||
// 标签直接打印,不加缩进
|
||||
printOperand(instr->getOperands()[0].get());
|
||||
*OS << ":\n";
|
||||
return; // 处理完毕,直接返回
|
||||
}
|
||||
if (opcode != RVOpcodes::LABEL) {
|
||||
|
||||
// 对于所有非标签指令,先打印缩进
|
||||
*OS << " ";
|
||||
}
|
||||
|
||||
switch (opcode) {
|
||||
case RVOpcodes::ADD: *OS << "add "; break; case RVOpcodes::ADDI: *OS << "addi "; break;
|
||||
@ -114,7 +79,9 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr) {
|
||||
case RVOpcodes::LHU: *OS << "lhu "; break; case RVOpcodes::LBU: *OS << "lbu "; break;
|
||||
case RVOpcodes::SW: *OS << "sw "; break; case RVOpcodes::SH: *OS << "sh "; break;
|
||||
case RVOpcodes::SB: *OS << "sb "; break; case RVOpcodes::LD: *OS << "ld "; break;
|
||||
case RVOpcodes::SD: *OS << "sd "; break;
|
||||
case RVOpcodes::SD: *OS << "sd "; break; case RVOpcodes::FLW: *OS << "flw "; break;
|
||||
case RVOpcodes::FSW: *OS << "fsw "; break; case RVOpcodes::FLD: *OS << "fld "; break;
|
||||
case RVOpcodes::FSD: *OS << "fsd "; break;
|
||||
case RVOpcodes::J: *OS << "j "; break; case RVOpcodes::JAL: *OS << "jal "; break;
|
||||
case RVOpcodes::JALR: *OS << "jalr "; break; case RVOpcodes::RET: *OS << "ret"; break;
|
||||
case RVOpcodes::BEQ: *OS << "beq "; break; case RVOpcodes::BNE: *OS << "bne "; break;
|
||||
@ -124,15 +91,62 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr) {
|
||||
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::FADD_S: *OS << "fadd.s "; break;
|
||||
case RVOpcodes::FSUB_S: *OS << "fsub.s "; break;
|
||||
case RVOpcodes::FMUL_S: *OS << "fmul.s "; break;
|
||||
case RVOpcodes::FDIV_S: *OS << "fdiv.s "; break;
|
||||
case RVOpcodes::FNEG_S: *OS << "fneg.s "; break;
|
||||
case RVOpcodes::FEQ_S: *OS << "feq.s "; break;
|
||||
case RVOpcodes::FLT_S: *OS << "flt.s "; break;
|
||||
case RVOpcodes::FLE_S: *OS << "fle.s "; break;
|
||||
case RVOpcodes::FCVT_S_W: *OS << "fcvt.s.w "; break;
|
||||
case RVOpcodes::FCVT_W_S: *OS << "fcvt.w.s "; break;
|
||||
case RVOpcodes::FMV_S: *OS << "fmv.s "; break;
|
||||
case RVOpcodes::FMV_W_X: *OS << "fmv.w.x "; break;
|
||||
case RVOpcodes::FMV_X_W: *OS << "fmv.x.w "; 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:
|
||||
printOperand(instr->getOperands()[0].get());
|
||||
*OS << ":";
|
||||
break;
|
||||
case RVOpcodes::FRAME_LOAD:
|
||||
case RVOpcodes::FRAME_STORE:
|
||||
// These should have been eliminated by RegAlloc
|
||||
throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
|
||||
case RVOpcodes::FRAME_LOAD_W:
|
||||
// It should have been eliminated by RegAlloc
|
||||
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
|
||||
*OS << "frame_load_w "; break;
|
||||
case RVOpcodes::FRAME_LOAD_D:
|
||||
// It should have been eliminated by RegAlloc
|
||||
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
|
||||
*OS << "frame_load_d "; break;
|
||||
case RVOpcodes::FRAME_STORE_W:
|
||||
// It should have been eliminated by RegAlloc
|
||||
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
|
||||
*OS << "frame_store_w "; break;
|
||||
case RVOpcodes::FRAME_STORE_D:
|
||||
// It should have been eliminated by RegAlloc
|
||||
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
|
||||
*OS << "frame_store_d "; break;
|
||||
case RVOpcodes::FRAME_ADDR:
|
||||
// It should have been eliminated by RegAlloc
|
||||
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
|
||||
*OS << "frame_addr "; break;
|
||||
case RVOpcodes::FRAME_LOAD_F:
|
||||
if (!debug) throw std::runtime_error("FRAME_LOAD_F not eliminated before AsmPrinter");
|
||||
*OS << "frame_load_f "; break;
|
||||
case RVOpcodes::FRAME_STORE_F:
|
||||
if (!debug) throw std::runtime_error("FRAME_STORE_F not eliminated before AsmPrinter");
|
||||
*OS << "frame_store_f "; break;
|
||||
case RVOpcodes::PSEUDO_KEEPALIVE:
|
||||
if (!debug) throw std::runtime_error("PSEUDO_KEEPALIVE not eliminated before AsmPrinter");
|
||||
*OS << "keepalive "; break;
|
||||
default:
|
||||
throw std::runtime_error("Unknown opcode in AsmPrinter");
|
||||
}
|
||||
392
src/backend/RISCv64/RISCv64Backend.cpp
Normal file
392
src/backend/RISCv64/RISCv64Backend.cpp
Normal file
@ -0,0 +1,392 @@
|
||||
#include "RISCv64Backend.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include "RISCv64RegAlloc.h"
|
||||
#include "RISCv64AsmPrinter.h"
|
||||
#include "RISCv64Passes.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 顶层入口
|
||||
std::string RISCv64CodeGen::code_gen() {
|
||||
return module_gen();
|
||||
}
|
||||
|
||||
unsigned RISCv64CodeGen::getTypeSizeInBytes(Type* type) {
|
||||
if (!type) {
|
||||
assert(false && "Cannot get size of a null type.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (type->getKind()) {
|
||||
// 对于SysY语言,基本类型int和float都占用4字节
|
||||
case Type::kInt:
|
||||
case Type::kFloat:
|
||||
return 4;
|
||||
|
||||
// 指针类型在RISC-V 64位架构下占用8字节
|
||||
// 虽然SysY没有'int*'语法,但数组变量在IR层面本身就是指针类型
|
||||
case Type::kPointer:
|
||||
return 8;
|
||||
|
||||
// 数组类型的总大小 = 元素数量 * 单个元素的大小
|
||||
case Type::kArray: {
|
||||
auto arrayType = type->as<ArrayType>();
|
||||
// 递归调用以计算元素大小
|
||||
return arrayType->getNumElements() * getTypeSizeInBytes(arrayType->getElementType());
|
||||
}
|
||||
|
||||
// 其他类型,如Void, Label等不占用栈空间,或者不应该出现在这里
|
||||
default:
|
||||
// 如果遇到未处理的类型,触发断言,方便调试
|
||||
// assert(false && "Unsupported type for size calculation.");
|
||||
return 0; // 对于像Label或Void这样的类型,返回0是合理的
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void printInitializer(std::stringstream& ss, const ValueCounter& init_values) {
|
||||
for (size_t i = 0; i < init_values.getValues().size(); ++i) {
|
||||
auto val = init_values.getValues()[i];
|
||||
auto count = init_values.getNumbers()[i];
|
||||
if (auto constant = dynamic_cast<ConstantValue*>(val)) {
|
||||
for (unsigned j = 0; j < count; ++j) {
|
||||
if (constant->isInt()) {
|
||||
ss << " .word " << constant->getInt() << "\n";
|
||||
} else {
|
||||
float f = constant->getFloat();
|
||||
uint32_t float_bits = *(uint32_t*)&f;
|
||||
ss << " .word " << float_bits << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string RISCv64CodeGen::module_gen() {
|
||||
std::stringstream ss;
|
||||
|
||||
// --- 步骤1:将全局变量(GlobalValue)分为.data和.bss两组 ---
|
||||
std::vector<GlobalValue*> data_globals;
|
||||
std::vector<GlobalValue*> bss_globals;
|
||||
|
||||
for (const auto& global_ptr : module->getGlobals()) {
|
||||
GlobalValue* global = global_ptr.get();
|
||||
|
||||
// [核心修改] 使用更健壮的逻辑来判断是否为大型零初始化数组
|
||||
bool is_all_zeros = true;
|
||||
const auto& init_values = global->getInitValues();
|
||||
|
||||
// 检查初始化值是否全部为0
|
||||
if (init_values.getValues().empty()) {
|
||||
// 如果 ValueCounter 为空,GlobalValue 的构造函数会确保它是零初始化的
|
||||
is_all_zeros = true;
|
||||
} else {
|
||||
for (auto val : init_values.getValues()) {
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(val)) {
|
||||
if (!const_val->isZero()) {
|
||||
is_all_zeros = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// 如果初始值包含非常量(例如,另一个全局变量的地址),则不认为是纯零初始化
|
||||
is_all_zeros = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 使用 getTypeSizeInBytes 检查总大小是否超过阈值 (16个整数 = 64字节)
|
||||
Type* allocated_type = global->getType()->as<PointerType>()->getBaseType();
|
||||
unsigned total_size = getTypeSizeInBytes(allocated_type);
|
||||
|
||||
bool is_large_zero_array = is_all_zeros && (total_size > 64);
|
||||
|
||||
if (is_large_zero_array) {
|
||||
bss_globals.push_back(global);
|
||||
} else {
|
||||
data_globals.push_back(global);
|
||||
}
|
||||
}
|
||||
|
||||
// --- 步骤2:生成 .bss 段的代码 ---
|
||||
if (!bss_globals.empty()) {
|
||||
ss << ".bss\n";
|
||||
for (GlobalValue* global : bss_globals) {
|
||||
Type* allocated_type = global->getType()->as<PointerType>()->getBaseType();
|
||||
unsigned total_size = getTypeSizeInBytes(allocated_type);
|
||||
|
||||
ss << " .align 3\n";
|
||||
ss << ".globl " << global->getName() << "\n";
|
||||
ss << ".type " << global->getName() << ", @object\n";
|
||||
ss << ".size " << global->getName() << ", " << total_size << "\n";
|
||||
ss << global->getName() << ":\n";
|
||||
ss << " .space " << total_size << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// --- 步骤3:生成 .data 段的代码 ---
|
||||
if (!data_globals.empty() || !module->getConsts().empty()) {
|
||||
ss << ".data\n";
|
||||
|
||||
// a. 处理普通的全局变量 (GlobalValue)
|
||||
for (GlobalValue* global : data_globals) {
|
||||
Type* allocated_type = global->getType()->as<PointerType>()->getBaseType();
|
||||
unsigned total_size = getTypeSizeInBytes(allocated_type);
|
||||
|
||||
ss << " .align 3\n";
|
||||
ss << ".globl " << global->getName() << "\n";
|
||||
ss << ".type " << global->getName() << ", @object\n";
|
||||
ss << ".size " << global->getName() << ", " << total_size << "\n";
|
||||
ss << global->getName() << ":\n";
|
||||
printInitializer(ss, global->getInitValues());
|
||||
}
|
||||
|
||||
// b. 处理全局常量 (ConstantVariable)
|
||||
for (const auto& const_ptr : module->getConsts()) {
|
||||
ConstantVariable* cnst = const_ptr.get();
|
||||
Type* allocated_type = cnst->getType()->as<PointerType>()->getBaseType();
|
||||
unsigned total_size = getTypeSizeInBytes(allocated_type);
|
||||
|
||||
ss << " .align 3\n";
|
||||
ss << ".globl " << cnst->getName() << "\n";
|
||||
ss << ".type " << cnst->getName() << ", @object\n";
|
||||
ss << ".size " << cnst->getName() << ", " << total_size << "\n";
|
||||
ss << cnst->getName() << ":\n";
|
||||
printInitializer(ss, cnst->getInitValues());
|
||||
}
|
||||
}
|
||||
|
||||
// --- 步骤4:处理函数 (.text段) 的逻辑 ---
|
||||
if (!module->getFunctions().empty()) {
|
||||
ss << ".text\n";
|
||||
for (const auto& func_pair : module->getFunctions()) {
|
||||
if (func_pair.second.get() && !func_pair.second->getBasicBlocks().empty()) {
|
||||
ss << function_gen(func_pair.second.get());
|
||||
if (DEBUG) std::cerr << "Function: " << func_pair.first << " generated.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string RISCv64CodeGen::function_gen(Function* func) {
|
||||
if (DEBUG) {
|
||||
// === 完整的后端处理流水线 ===
|
||||
|
||||
// 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers)
|
||||
DEBUG = 0;
|
||||
DEEPDEBUG = 0;
|
||||
|
||||
RISCv64ISel isel;
|
||||
std::unique_ptr<MachineFunction> mfunc = isel.runOnFunction(func);
|
||||
|
||||
// 第一次调试打印输出
|
||||
std::stringstream ss_after_isel;
|
||||
RISCv64AsmPrinter printer_isel(mfunc.get());
|
||||
printer_isel.run(ss_after_isel, true);
|
||||
// if (DEBUG) {
|
||||
// std::cout << ss_after_isel.str();
|
||||
// }
|
||||
DEBUG = 0;
|
||||
DEEPDEBUG = 0;
|
||||
DEBUG = 1;
|
||||
DEEPDEBUG = 1;
|
||||
if (DEBUG) {
|
||||
std::cerr << "====== Intermediate Representation after Instruction Selection ======\n"
|
||||
<< ss_after_isel.str();
|
||||
}
|
||||
// DEBUG = 0;
|
||||
// DEEPDEBUG = 0;
|
||||
// [新增] 阶段 2: 消除帧索引 (展开伪指令,计算局部变量偏移)
|
||||
// 这个Pass必须在寄存器分配之前运行
|
||||
EliminateFrameIndicesPass efi_pass;
|
||||
efi_pass.runOnMachineFunction(mfunc.get());
|
||||
|
||||
if (DEBUG) {
|
||||
std::cerr << "====== stack info after eliminate frame indices ======\n";
|
||||
mfunc->dumpStackFrameInfo(std::cerr);
|
||||
// std::stringstream ss_after_eli;
|
||||
// printer_isel.run(ss_after_eli, true);
|
||||
// std::cerr << "====== LLIR after eliminate frame indices ======\n"
|
||||
// << ss_after_eli.str();
|
||||
}
|
||||
|
||||
// // 阶段 2: 指令调度 (Instruction Scheduling)
|
||||
// PreRA_Scheduler scheduler;
|
||||
// scheduler.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// DEBUG = 0;
|
||||
// DEEPDEBUG = 0;
|
||||
// DEBUG = 1;
|
||||
// DEEPDEBUG = 1;
|
||||
// 阶段 3: 物理寄存器分配 (Register Allocation)
|
||||
RISCv64RegAlloc reg_alloc(mfunc.get());
|
||||
reg_alloc.run();
|
||||
|
||||
// DEBUG = 0;
|
||||
// DEEPDEBUG = 0;
|
||||
DEBUG = 1;
|
||||
DEEPDEBUG = 1;
|
||||
if (DEBUG) {
|
||||
std::cerr << "====== stack info after reg alloc ======\n";
|
||||
mfunc->dumpStackFrameInfo(std::cerr);
|
||||
}
|
||||
|
||||
// 阶段 3.1: 处理被调用者保存寄存器
|
||||
CalleeSavedHandler callee_handler;
|
||||
callee_handler.runOnMachineFunction(mfunc.get());
|
||||
|
||||
if (DEBUG) {
|
||||
std::cerr << "====== stack info after callee handler ======\n";
|
||||
mfunc->dumpStackFrameInfo(std::cerr);
|
||||
}
|
||||
|
||||
// // 阶段 4: 窥孔优化 (Peephole Optimization)
|
||||
// PeepholeOptimizer peephole;
|
||||
// peephole.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 5: 局部指令调度 (Local Scheduling)
|
||||
// PostRA_Scheduler local_scheduler;
|
||||
// local_scheduler.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 3.2: 插入序言和尾声
|
||||
PrologueEpilogueInsertionPass pei_pass;
|
||||
pei_pass.runOnMachineFunction(mfunc.get());
|
||||
|
||||
DEBUG = 0;
|
||||
DEEPDEBUG = 0;
|
||||
|
||||
// 阶段 3.3: 大立即数合法化
|
||||
LegalizeImmediatesPass legalizer;
|
||||
legalizer.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 6: 代码发射 (Code Emission)
|
||||
std::stringstream ss;
|
||||
RISCv64AsmPrinter printer(mfunc.get());
|
||||
printer.run(ss);
|
||||
|
||||
if (DEBUG) {
|
||||
ss << "\n\n; --- Intermediate Representation after Instruction Selection ---\n"
|
||||
<< ss_after_isel.str();
|
||||
}
|
||||
DEBUG = 1;
|
||||
DEEPDEBUG = 1;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
else {
|
||||
// === 完整的后端处理流水线 ===
|
||||
|
||||
// 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers)
|
||||
DEBUG = 0;
|
||||
DEEPDEBUG = 0;
|
||||
|
||||
RISCv64ISel isel;
|
||||
std::unique_ptr<MachineFunction> mfunc = isel.runOnFunction(func);
|
||||
|
||||
// 第一次调试打印输出
|
||||
std::stringstream ss_after_isel;
|
||||
RISCv64AsmPrinter printer_isel(mfunc.get());
|
||||
printer_isel.run(ss_after_isel, true);
|
||||
// if (DEBUG) {
|
||||
// std::cout << ss_after_isel.str();
|
||||
// }
|
||||
DEBUG = 0;
|
||||
DEEPDEBUG = 0;
|
||||
// DEBUG = 1;
|
||||
// DEEPDEBUG = 1;
|
||||
if (DEBUG) {
|
||||
std::cerr << "====== Intermediate Representation after Instruction Selection ======\n"
|
||||
<< ss_after_isel.str();
|
||||
}
|
||||
// DEBUG = 0;
|
||||
// DEEPDEBUG = 0;
|
||||
// [新增] 阶段 2: 消除帧索引 (展开伪指令,计算局部变量偏移)
|
||||
// 这个Pass必须在寄存器分配之前运行
|
||||
EliminateFrameIndicesPass efi_pass;
|
||||
efi_pass.runOnMachineFunction(mfunc.get());
|
||||
|
||||
if (DEBUG) {
|
||||
std::cerr << "====== stack info after eliminate frame indices ======\n";
|
||||
mfunc->dumpStackFrameInfo(std::cerr);
|
||||
std::stringstream ss_after_eli;
|
||||
printer_isel.run(ss_after_eli, true);
|
||||
std::cerr << "====== LLIR after eliminate frame indices ======\n"
|
||||
<< ss_after_eli.str();
|
||||
}
|
||||
|
||||
// // 阶段 2: 指令调度 (Instruction Scheduling)
|
||||
// PreRA_Scheduler scheduler;
|
||||
// scheduler.runOnMachineFunction(mfunc.get());
|
||||
|
||||
DEBUG = 0;
|
||||
DEEPDEBUG = 0;
|
||||
// DEBUG = 1;
|
||||
// DEEPDEBUG = 1;
|
||||
// 阶段 3: 物理寄存器分配 (Register Allocation)
|
||||
RISCv64RegAlloc reg_alloc(mfunc.get());
|
||||
reg_alloc.run();
|
||||
|
||||
DEBUG = 0;
|
||||
DEEPDEBUG = 0;
|
||||
// DEBUG = 1;
|
||||
// DEEPDEBUG = 1;
|
||||
if (DEBUG) {
|
||||
std::cerr << "====== stack info after reg alloc ======\n";
|
||||
mfunc->dumpStackFrameInfo(std::cerr);
|
||||
}
|
||||
|
||||
// 阶段 3.1: 处理被调用者保存寄存器
|
||||
CalleeSavedHandler callee_handler;
|
||||
callee_handler.runOnMachineFunction(mfunc.get());
|
||||
|
||||
if (DEBUG) {
|
||||
std::cerr << "====== stack info after callee handler ======\n";
|
||||
mfunc->dumpStackFrameInfo(std::cerr);
|
||||
}
|
||||
|
||||
// // 阶段 4: 窥孔优化 (Peephole Optimization)
|
||||
// PeepholeOptimizer peephole;
|
||||
// peephole.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 5: 局部指令调度 (Local Scheduling)
|
||||
// PostRA_Scheduler local_scheduler;
|
||||
// local_scheduler.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 3.2: 插入序言和尾声
|
||||
PrologueEpilogueInsertionPass pei_pass;
|
||||
pei_pass.runOnMachineFunction(mfunc.get());
|
||||
|
||||
DEBUG = 0;
|
||||
DEEPDEBUG = 0;
|
||||
|
||||
// 阶段 3.3: 大立即数合法化
|
||||
LegalizeImmediatesPass legalizer;
|
||||
legalizer.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 6: 代码发射 (Code Emission)
|
||||
std::stringstream ss;
|
||||
RISCv64AsmPrinter printer(mfunc.get());
|
||||
printer.run(ss);
|
||||
|
||||
if (DEBUG) {
|
||||
ss << "\n\n; --- Intermediate Representation after Instruction Selection ---\n"
|
||||
<< ss_after_isel.str();
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
1648
src/backend/RISCv64/RISCv64ISel.cpp
Normal file
1648
src/backend/RISCv64/RISCv64ISel.cpp
Normal file
File diff suppressed because it is too large
Load Diff
122
src/backend/RISCv64/RISCv64LLIR.cpp
Normal file
122
src/backend/RISCv64/RISCv64LLIR.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
#include "RISCv64LLIR.h"
|
||||
#include <vector>
|
||||
#include <iostream> // 用于 std::ostream 和 std::cerr
|
||||
#include <string> // 用于 std::string
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 辅助函数:将 PhysicalReg 枚举转换为可读的字符串
|
||||
std::string regToString(PhysicalReg reg) {
|
||||
switch (reg) {
|
||||
case PhysicalReg::ZERO: return "x0"; case PhysicalReg::RA: return "ra";
|
||||
case PhysicalReg::SP: return "sp"; case PhysicalReg::GP: return "gp";
|
||||
case PhysicalReg::TP: return "tp"; case PhysicalReg::T0: return "t0";
|
||||
case PhysicalReg::T1: return "t1"; case PhysicalReg::T2: return "t2";
|
||||
case PhysicalReg::S0: return "s0"; case PhysicalReg::S1: return "s1";
|
||||
case PhysicalReg::A0: return "a0"; case PhysicalReg::A1: return "a1";
|
||||
case PhysicalReg::A2: return "a2"; case PhysicalReg::A3: return "a3";
|
||||
case PhysicalReg::A4: return "a4"; case PhysicalReg::A5: return "a5";
|
||||
case PhysicalReg::A6: return "a6"; case PhysicalReg::A7: return "a7";
|
||||
case PhysicalReg::S2: return "s2"; case PhysicalReg::S3: return "s3";
|
||||
case PhysicalReg::S4: return "s4"; case PhysicalReg::S5: return "s5";
|
||||
case PhysicalReg::S6: return "s6"; case PhysicalReg::S7: return "s7";
|
||||
case PhysicalReg::S8: return "s8"; case PhysicalReg::S9: return "s9";
|
||||
case PhysicalReg::S10: return "s10"; case PhysicalReg::S11: return "s11";
|
||||
case PhysicalReg::T3: return "t3"; case PhysicalReg::T4: return "t4";
|
||||
case PhysicalReg::T5: return "t5"; case PhysicalReg::T6: return "t6";
|
||||
case PhysicalReg::F0: return "f0"; case PhysicalReg::F1: return "f1";
|
||||
case PhysicalReg::F2: return "f2"; case PhysicalReg::F3: return "f3";
|
||||
case PhysicalReg::F4: return "f4"; case PhysicalReg::F5: return "f5";
|
||||
case PhysicalReg::F6: return "f6"; case PhysicalReg::F7: return "f7";
|
||||
case PhysicalReg::F8: return "f8"; case PhysicalReg::F9: return "f9";
|
||||
case PhysicalReg::F10: return "f10"; case PhysicalReg::F11: return "f11";
|
||||
case PhysicalReg::F12: return "f12"; case PhysicalReg::F13: return "f13";
|
||||
case PhysicalReg::F14: return "f14"; case PhysicalReg::F15: return "f15";
|
||||
case PhysicalReg::F16: return "f16"; case PhysicalReg::F17: return "f17";
|
||||
case PhysicalReg::F18: return "f18"; case PhysicalReg::F19: return "f19";
|
||||
case PhysicalReg::F20: return "f20"; case PhysicalReg::F21: return "f21";
|
||||
case PhysicalReg::F22: return "f22"; case PhysicalReg::F23: return "f23";
|
||||
case PhysicalReg::F24: return "f24"; case PhysicalReg::F25: return "f25";
|
||||
case PhysicalReg::F26: return "f26"; case PhysicalReg::F27: return "f27";
|
||||
case PhysicalReg::F28: return "f28"; case PhysicalReg::F29: return "f29";
|
||||
case PhysicalReg::F30: return "f30"; case PhysicalReg::F31: return "f31";
|
||||
default: return "UNKNOWN_REG";
|
||||
}
|
||||
}
|
||||
|
||||
// [新增] 打印栈帧信息的完整实现
|
||||
void MachineFunction::dumpStackFrameInfo(std::ostream& os) const {
|
||||
const StackFrameInfo& info = frame_info;
|
||||
|
||||
os << "--- Stack Frame Info for function '" << getName() << "' ---\n";
|
||||
|
||||
// 打印尺寸信息
|
||||
os << " Sizes:\n";
|
||||
os << " Total Size: " << info.total_size << " bytes\n";
|
||||
os << " Locals Size: " << info.locals_size << " bytes\n";
|
||||
os << " Spill Size: " << info.spill_size << " bytes\n";
|
||||
os << " Callee-Saved Size: " << info.callee_saved_size << " bytes\n";
|
||||
os << "\n";
|
||||
|
||||
// 打印 Alloca 变量的偏移量
|
||||
os << " Alloca Offsets (vreg -> offset from FP):\n";
|
||||
if (info.alloca_offsets.empty()) {
|
||||
os << " (None)\n";
|
||||
} else {
|
||||
for (const auto& pair : info.alloca_offsets) {
|
||||
os << " %vreg" << pair.first << " -> " << pair.second << "\n";
|
||||
}
|
||||
}
|
||||
os << "\n";
|
||||
|
||||
// 打印溢出变量的偏移量
|
||||
os << " Spill Offsets (vreg -> offset from FP):\n";
|
||||
if (info.spill_offsets.empty()) {
|
||||
os << " (None)\n";
|
||||
} else {
|
||||
for (const auto& pair : info.spill_offsets) {
|
||||
os << " %vreg" << pair.first << " -> " << pair.second << "\n";
|
||||
}
|
||||
}
|
||||
os << "\n";
|
||||
|
||||
// 打印使用的被调用者保存寄存器
|
||||
os << " Used Callee-Saved Registers:\n";
|
||||
if (info.used_callee_saved_regs.empty()) {
|
||||
os << " (None)\n";
|
||||
} else {
|
||||
os << " { ";
|
||||
for (const auto& reg : info.used_callee_saved_regs) {
|
||||
os << regToString(reg) << " ";
|
||||
}
|
||||
os << "}\n";
|
||||
}
|
||||
os << "\n";
|
||||
|
||||
// 打印需要保存/恢复的被调用者保存寄存器 (有序)
|
||||
os << " Callee-Saved Registers to Store/Restore:\n";
|
||||
if (info.callee_saved_regs_to_store.empty()) {
|
||||
os << " (None)\n";
|
||||
} else {
|
||||
os << " [ ";
|
||||
for (const auto& reg : info.callee_saved_regs_to_store) {
|
||||
os << regToString(reg) << " ";
|
||||
}
|
||||
os << "]\n";
|
||||
}
|
||||
os << "\n";
|
||||
|
||||
// 打印最终的寄存器分配结果
|
||||
os << " Final Register Allocation Map (vreg -> preg):\n";
|
||||
if (info.vreg_to_preg_map.empty()) {
|
||||
os << " (None)\n";
|
||||
} else {
|
||||
for (const auto& pair : info.vreg_to_preg_map) {
|
||||
os << " %vreg" << pair.first << " -> " << regToString(pair.second) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
os << "---------------------------------------------------\n";
|
||||
}
|
||||
|
||||
}
|
||||
1497
src/backend/RISCv64/RISCv64RegAlloc.cpp
Normal file
1497
src/backend/RISCv64/RISCv64RegAlloc.cpp
Normal file
File diff suppressed because it is too large
Load Diff
17
src/frontend/CMakeLists.txt
Normal file
17
src/frontend/CMakeLists.txt
Normal 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)
|
||||
@ -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
|
||||
@ -1,39 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "IR.h"
|
||||
#include "SysYIRAnalyser.h"
|
||||
#include "SysYIRPrinter.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
class DeadCodeElimination {
|
||||
private:
|
||||
Module *pModule;
|
||||
ControlFlowAnalysis *pCFA; // 控制流分析指针
|
||||
ActiveVarAnalysis *pAVA; // 活跃变量分析指针
|
||||
DataFlowAnalysisUtils dataFlowAnalysisUtils; // 数据流分析工具类
|
||||
|
||||
public:
|
||||
explicit DeadCodeElimination(Module *pMoudle,
|
||||
ControlFlowAnalysis *pCFA = nullptr,
|
||||
ActiveVarAnalysis *pAVA = nullptr)
|
||||
: pModule(pMoudle), pCFA(pCFA), pAVA(pAVA), dataFlowAnalysisUtils() {} // 构造函数
|
||||
|
||||
// TODO:根据参数传入的passes来运行不同的死代码删除流程
|
||||
// void runDCEPipeline(const std::vector<std::string>& passes = {
|
||||
// "dead-store", "redundant-load-store", "dead-load", "dead-alloca", "dead-global"
|
||||
// });
|
||||
void runDCEPipeline(); // 运行死代码删除
|
||||
|
||||
void eliminateDeadStores(Function* func, bool& changed); // 消除无用存储
|
||||
void eliminateDeadLoads(Function* func, bool& changed); // 消除无用加载
|
||||
void eliminateDeadAllocas(Function* func, bool& changed); // 消除无用内存分配
|
||||
void eliminateDeadGlobals(bool& changed); // 消除无用全局变量
|
||||
void eliminateDeadIndirectiveAllocas(Function* func, bool& changed); // 消除无用间接内存分配(phi节点)
|
||||
void eliminateDeadRedundantLoadStore(Function* func, bool& changed); // 消除冗余加载和存储
|
||||
bool isGlobal(Value *val);
|
||||
bool isArr(Value *val);
|
||||
void usedelete(Instruction *instr);
|
||||
|
||||
};
|
||||
} // namespace sysy
|
||||
@ -1,59 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include "IR.h"
|
||||
#include "IRBuilder.h"
|
||||
#include "SysYIRAnalyser.h"
|
||||
|
||||
namespace sysy {
|
||||
/**
|
||||
* 实现静态单变量赋值核心类 mem2reg
|
||||
*/
|
||||
class Mem2Reg {
|
||||
private:
|
||||
Module *pModule;
|
||||
IRBuilder *pBuilder;
|
||||
ControlFlowAnalysis *controlFlowAnalysis; // 控制流分析
|
||||
ActiveVarAnalysis *activeVarAnalysis; // 活跃变量分析
|
||||
DataFlowAnalysisUtils dataFlowAnalysisUtils;
|
||||
|
||||
public:
|
||||
Mem2Reg(Module *pMoudle, IRBuilder *pBuilder,
|
||||
ControlFlowAnalysis *pCFA = nullptr, ActiveVarAnalysis *pAVA = nullptr) :
|
||||
pModule(pMoudle), pBuilder(pBuilder), controlFlowAnalysis(pCFA), activeVarAnalysis(pAVA), dataFlowAnalysisUtils()
|
||||
{} // 初始化函数
|
||||
|
||||
void mem2regPipeline(); ///< mem2reg
|
||||
|
||||
private:
|
||||
|
||||
// phi节点的插入需要计算IDF
|
||||
std::unordered_set<BasicBlock *> computeIterDf(const std::unordered_set<BasicBlock *> &blocks); ///< 计算定义块集合的迭代支配边界
|
||||
|
||||
auto computeValue2Blocks() -> void; ///< 计算value2block的映射(不包括数组和global)
|
||||
|
||||
auto preOptimize1() -> void; ///< llvm memtoreg预优化1: 删除不含load的alloc和store
|
||||
auto preOptimize2() -> void; ///< llvm memtoreg预优化2: 针对某个变量的Defblocks只有一个块的情况
|
||||
auto preOptimize3() -> void; ///< llvm memtoreg预优化3: 针对某个变量的所有读写都在同一个块中的情况
|
||||
|
||||
auto insertPhi() -> void; ///< 为所有变量的迭代支配边界插入phi结点
|
||||
|
||||
auto rename(BasicBlock *block, std::unordered_map<Value *, int> &count,
|
||||
std::unordered_map<Value *, std::stack<Instruction *>> &stacks) -> void; ///< 单个块的重命名
|
||||
auto renameAll() -> void; ///< 重命名所有块
|
||||
|
||||
// private helper function.
|
||||
private:
|
||||
auto getPredIndex(BasicBlock *n, BasicBlock *s) -> int; ///< 获取前驱索引
|
||||
auto cascade(Instruction *instr, bool &changed, Function *func, BasicBlock *block,
|
||||
std::list<std::unique_ptr<Instruction>> &instrs) -> void; ///< 消除级联关系
|
||||
auto isGlobal(Value *val) -> bool; ///< 判断是否是全局变量
|
||||
auto isArr(Value *val) -> bool; ///< 判断是否是数组
|
||||
auto usedelete(Instruction *instr) -> void; ///< 删除指令相关的value-use-user关系
|
||||
|
||||
};
|
||||
} // namespace sysy
|
||||
@ -1,18 +0,0 @@
|
||||
// RISCv64Passes.h
|
||||
#ifndef RISCV64_PASSES_H
|
||||
#define RISCV64_PASSES_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 此处为未来优化Pass的基类或独立类定义
|
||||
// 例如:
|
||||
// class PeepholeOptimizer {
|
||||
// public:
|
||||
// void runOnMachineFunction(MachineFunction* mfunc);
|
||||
// };
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // RISCV64_PASSES_H
|
||||
@ -1,56 +0,0 @@
|
||||
#ifndef RISCV64_REGALLOC_H
|
||||
#define RISCV64_REGALLOC_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
class RISCv64RegAlloc {
|
||||
public:
|
||||
RISCv64RegAlloc(MachineFunction* mfunc);
|
||||
|
||||
// 模块主入口
|
||||
void run();
|
||||
|
||||
private:
|
||||
using LiveSet = std::set<unsigned>; // 活跃虚拟寄存器集合
|
||||
using InterferenceGraph = std::map<unsigned, std::set<unsigned>>;
|
||||
|
||||
// 栈帧管理
|
||||
void eliminateFrameIndices();
|
||||
|
||||
// 活跃性分析
|
||||
void analyzeLiveness();
|
||||
|
||||
// 构建干扰图
|
||||
void buildInterferenceGraph();
|
||||
|
||||
// 图着色分配寄存器
|
||||
void colorGraph();
|
||||
|
||||
// 重写函数,替换vreg并插入溢出代码
|
||||
void rewriteFunction();
|
||||
|
||||
// 辅助函数,获取指令的Use/Def集合
|
||||
void getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def);
|
||||
|
||||
MachineFunction* MFunc;
|
||||
|
||||
// 活跃性分析结果
|
||||
std::map<const MachineInstr*, LiveSet> live_in_map;
|
||||
std::map<const MachineInstr*, LiveSet> live_out_map;
|
||||
|
||||
// 干扰图
|
||||
InterferenceGraph interference_graph;
|
||||
|
||||
// 图着色结果
|
||||
std::map<unsigned, PhysicalReg> color_map; // vreg -> preg
|
||||
std::set<unsigned> spilled_vregs; // 被溢出的vreg集合
|
||||
|
||||
// 可用的物理寄存器池
|
||||
std::vector<PhysicalReg> allocable_int_regs;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // RISCV64_REGALLOC_H
|
||||
@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "IR.h"
|
||||
#include "IRBuilder.h"
|
||||
|
||||
namespace sysy {
|
||||
/**
|
||||
* Reg2Mem(后端未做phi指令翻译)
|
||||
*/
|
||||
class Reg2Mem {
|
||||
private:
|
||||
Module *pModule;
|
||||
IRBuilder *pBuilder;
|
||||
|
||||
public:
|
||||
Reg2Mem(Module *pMoudle, IRBuilder *pBuilder) : pModule(pMoudle), pBuilder(pBuilder) {}
|
||||
|
||||
void DeletePhiInst();
|
||||
// 删除UD关系, 因为删除了phi指令会修改ud关系
|
||||
void usedelete(Instruction *instr);
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
@ -1,340 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "SysYBaseVisitor.h"
|
||||
#include "SysYParser.h"
|
||||
#include <ostream>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
class SysYFormatter : public SysYBaseVisitor {
|
||||
protected:
|
||||
std::ostream &os;
|
||||
int indent = 0;
|
||||
|
||||
public:
|
||||
SysYFormatter(std::ostream &os) : os(os), indent(0) {}
|
||||
|
||||
protected:
|
||||
struct Indentor {
|
||||
static constexpr int TabSize = 2;
|
||||
int &indent;
|
||||
Indentor(int &indent) : indent(indent) { indent += TabSize; }
|
||||
~Indentor() { indent -= TabSize; }
|
||||
};
|
||||
std::ostream &space() { return os << std::string(indent, ' '); }
|
||||
template <typename T>
|
||||
std::ostream &interleave(const T &container, const std::string sep = ", ") {
|
||||
auto b = container.begin(), e = container.end();
|
||||
(*b)->accept(this);
|
||||
for (b = std::next(b); b != e; b = std::next(b)) {
|
||||
os << sep;
|
||||
(*b)->accept(this);
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
public:
|
||||
// virtual std::any visitModule(SysYParser::ModuleContext *ctx) override {
|
||||
// return visitChildren(ctx);
|
||||
// }
|
||||
|
||||
virtual std::any visitBtype(SysYParser::BtypeContext *ctx) override {
|
||||
os << ctx->getText();
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitDecl(SysYParser::DeclContext *ctx) override {
|
||||
space();
|
||||
if (ctx->CONST())
|
||||
os << ctx->CONST()->getText() << ' ';
|
||||
ctx->btype()->accept(this);
|
||||
os << ' ';
|
||||
interleave(ctx->varDef(), ", ") << ';' << '\n';
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitVarDef(SysYParser::VarDefContext *ctx) override {
|
||||
ctx->lValue()->accept(this);
|
||||
if (ctx->initValue()) {
|
||||
os << ' ' << '=' << ' ';
|
||||
ctx->initValue()->accept(this);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitInitValue(SysYParser::InitValueContext *ctx) override {
|
||||
if (not ctx->exp()) {
|
||||
os << '{';
|
||||
auto values = ctx->initValue();
|
||||
if (values.size())
|
||||
interleave(values, ", ");
|
||||
os << '}';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitFunc(SysYParser::FuncContext *ctx) override {
|
||||
ctx->funcType()->accept(this);
|
||||
os << ' ' << ctx->ID()->getText() << '(';
|
||||
if (ctx->funcFParams())
|
||||
ctx->funcFParams()->accept(this);
|
||||
os << ')' << ' ';
|
||||
ctx->blockStmt()->accept(this);
|
||||
os << '\n';
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitFuncType(SysYParser::FuncTypeContext *ctx) override {
|
||||
os << ctx->getText();
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any
|
||||
visitFuncFParams(SysYParser::FuncFParamsContext *ctx) override {
|
||||
interleave(ctx->funcFParam(), ", ");
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any
|
||||
visitFuncFParam(SysYParser::FuncFParamContext *ctx) override {
|
||||
ctx->btype()->accept(this);
|
||||
os << ' ' << ctx->ID()->getText();
|
||||
if (not ctx->LBRACKET().empty()) {
|
||||
os << '[';
|
||||
auto exp = ctx->exp();
|
||||
if (not exp.empty()) {
|
||||
os << '[';
|
||||
interleave(exp, "][") << ']';
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitBlockStmt(SysYParser::BlockStmtContext *ctx) override {
|
||||
os << '{' << '\n';
|
||||
{
|
||||
Indentor indentor(indent);
|
||||
auto items = ctx->blockItem();
|
||||
if (not items.empty())
|
||||
interleave(items, "");
|
||||
}
|
||||
space() << ctx->RBRACE()->getText() << '\n';
|
||||
return 0;
|
||||
}
|
||||
|
||||
// virtual std::any visitBlockItem(SysYParser::BlockItemContext *ctx)
|
||||
// override {
|
||||
// return visitChildren(ctx);
|
||||
// }
|
||||
|
||||
// virtual std::any visitStmt(SysYParser::StmtContext *ctx) override {
|
||||
// return visitChildren(ctx);
|
||||
// }
|
||||
|
||||
virtual std::any
|
||||
visitAssignStmt(SysYParser::AssignStmtContext *ctx) override {
|
||||
space();
|
||||
ctx->lValue()->accept(this);
|
||||
os << " = ";
|
||||
ctx->exp()->accept(this);
|
||||
os << ';' << '\n';
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitExpStmt(SysYParser::ExpStmtContext *ctx) override {
|
||||
space();
|
||||
ctx->exp()->accept(this);
|
||||
os << ';' << '\n';
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wrapBlock(SysYParser::StmtContext *stmt) {
|
||||
bool isBlock = stmt->blockStmt();
|
||||
if (isBlock) {
|
||||
stmt->accept(this);
|
||||
} else {
|
||||
os << "{\n";
|
||||
{
|
||||
Indentor indentor(indent);
|
||||
stmt->accept(this);
|
||||
}
|
||||
space() << "}\n";
|
||||
}
|
||||
};
|
||||
virtual std::any visitIfStmt(SysYParser::IfStmtContext *ctx) override {
|
||||
space();
|
||||
os << ctx->IF()->getText() << " (";
|
||||
ctx->exp()->accept(this);
|
||||
os << ") ";
|
||||
auto stmt = ctx->stmt();
|
||||
auto ifStmt = stmt[0];
|
||||
wrapBlock(ifStmt);
|
||||
if (stmt.size() == 2) {
|
||||
auto elseStmt = stmt[1];
|
||||
wrapBlock(elseStmt);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitWhileStmt(SysYParser::WhileStmtContext *ctx) override {
|
||||
space();
|
||||
os << ctx->WHILE()->getText() << " (";
|
||||
ctx->exp()->accept(this);
|
||||
os << ") ";
|
||||
wrapBlock(ctx->stmt());
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitBreakStmt(SysYParser::BreakStmtContext *ctx) override {
|
||||
space() << ctx->BREAK()->getText() << ';' << '\n';
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any
|
||||
visitContinueStmt(SysYParser::ContinueStmtContext *ctx) override {
|
||||
space() << ctx->CONTINUE()->getText() << ';' << '\n';
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any
|
||||
visitReturnStmt(SysYParser::ReturnStmtContext *ctx) override {
|
||||
space() << ctx->RETURN()->getText();
|
||||
if (ctx->exp()) {
|
||||
os << ' ';
|
||||
ctx->exp()->accept(this);
|
||||
}
|
||||
os << ';' << '\n';
|
||||
return 0;
|
||||
}
|
||||
|
||||
// virtual std::any visitEmptyStmt(SysYParser::EmptyStmtContext *ctx)
|
||||
// override {
|
||||
// return visitChildren(ctx);
|
||||
// }
|
||||
|
||||
virtual std::any
|
||||
visitRelationExp(SysYParser::RelationExpContext *ctx) override {
|
||||
auto lhs = ctx->exp(0);
|
||||
auto rhs = ctx->exp(1);
|
||||
std::string op =
|
||||
ctx->LT() ? "<" : (ctx->LE() ? "<=" : (ctx->GT() ? ">" : ">="));
|
||||
lhs->accept(this);
|
||||
os << ' ' << op << ' ';
|
||||
rhs->accept(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any
|
||||
visitMultiplicativeExp(SysYParser::MultiplicativeExpContext *ctx) override {
|
||||
auto lhs = ctx->exp(0);
|
||||
auto rhs = ctx->exp(1);
|
||||
std::string op = ctx->MUL() ? "*" : (ctx->DIV() ? "/" : "%");
|
||||
lhs->accept(this);
|
||||
os << ' ' << op << ' ';
|
||||
rhs->accept(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// virtual std::any visitLValueExp(SysYParser::LValueExpContext *ctx)
|
||||
// override {
|
||||
// return visitChildren(ctx);
|
||||
// }
|
||||
|
||||
// virtual std::any visitNumberExp(SysYParser::NumberExpContext *ctx)
|
||||
// override {
|
||||
// return visitChildren(ctx);
|
||||
// }
|
||||
|
||||
virtual std::any visitAndExp(SysYParser::AndExpContext *ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
os << " && ";
|
||||
ctx->exp(1)->accept(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitUnaryExp(SysYParser::UnaryExpContext *ctx) override {
|
||||
std::string op = ctx->ADD() ? "+" : (ctx->SUB() ? "-" : "!");
|
||||
os << op;
|
||||
ctx->exp()->accept(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitParenExp(SysYParser::ParenExpContext *ctx) override {
|
||||
os << '(';
|
||||
ctx->exp()->accept(this);
|
||||
os << ')';
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitStringExp(SysYParser::StringExpContext *ctx) override {
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
virtual std::any visitOrExp(SysYParser::OrExpContext *ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
os << " || ";
|
||||
ctx->exp(1)->accept(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// virtual std::any visitCallExp(SysYParser::CallExpContext *ctx) override {
|
||||
// return visitChildren(ctx);
|
||||
// }
|
||||
|
||||
virtual std::any
|
||||
visitAdditiveExp(SysYParser::AdditiveExpContext *ctx) override {
|
||||
auto lhs = ctx->exp(0);
|
||||
auto rhs = ctx->exp(1);
|
||||
std::string op = ctx->ADD() ? "+" : "-";
|
||||
lhs->accept(this);
|
||||
os << ' ' << op << ' ';
|
||||
rhs->accept(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitEqualExp(SysYParser::EqualExpContext *ctx) override {
|
||||
auto lhs = ctx->exp(0);
|
||||
auto rhs = ctx->exp(1);
|
||||
std::string op = ctx->EQ() ? "==" : "!=";
|
||||
lhs->accept(this);
|
||||
os << ' ' << op << ' ';
|
||||
rhs->accept(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitCall(SysYParser::CallContext *ctx) override {
|
||||
os << ctx->ID()->getText() << '(';
|
||||
if (ctx->funcRParams())
|
||||
ctx->funcRParams()->accept(this);
|
||||
os << ')';
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitLValue(SysYParser::LValueContext *ctx) override {
|
||||
os << ctx->ID()->getText();
|
||||
auto exp = ctx->exp();
|
||||
if (not exp.empty()) {
|
||||
os << '[';
|
||||
interleave(exp, "][") << ']';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitNumber(SysYParser::NumberContext *ctx) override {
|
||||
os << ctx->getText();
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitString(SysYParser::StringContext *ctx) override {
|
||||
os << ctx->getText();
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any
|
||||
visitFuncRParams(SysYParser::FuncRParamsContext *ctx) override {
|
||||
interleave(ctx->exp(), ", ");
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
@ -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
|
||||
@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "IR.h"
|
||||
#include "IRBuilder.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 优化前对SysY IR的预处理,也可以视作部分CFG优化
|
||||
// 主要包括删除无用指令、合并基本块、删除空块等
|
||||
// 这些操作可以在SysY IR生成时就完成,但为了简化IR生成过程,
|
||||
// 这里将其放在SysY IR生成后进行预处理
|
||||
// 同时兼容phi节点的处理,可以再mem2reg后再次调用优化
|
||||
class SysYOptPre {
|
||||
private:
|
||||
Module *pModule;
|
||||
IRBuilder *pBuilder;
|
||||
|
||||
public:
|
||||
SysYOptPre(Module *pMoudle, IRBuilder *pBuilder) : pModule(pMoudle), pBuilder(pBuilder) {}
|
||||
|
||||
void SysYOptimizateAfterIR(){
|
||||
SysYDelInstAfterBr();
|
||||
SysYBlockMerge();
|
||||
SysYDelNoPreBLock();
|
||||
SysYDelEmptyBlock();
|
||||
SysYAddReturn();
|
||||
}
|
||||
void SysYDelInstAfterBr(); // 删除br后面的指令
|
||||
void SysYDelEmptyBlock(); // 空块删除
|
||||
void SysYDelNoPreBLock(); // 删除无前驱块
|
||||
void SysYBlockMerge(); // 合并基本块(主要针对嵌套if while的exit块,
|
||||
// 也可以修改IR生成实现回填机制
|
||||
void SysYAddReturn(); // 添加return指令(主要针对Void函数)
|
||||
void usedelete(Instruction *instr); // use删除
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
33
src/include/backend/RISCv64/Handler/CalleeSavedHandler.h
Normal file
33
src/include/backend/RISCv64/Handler/CalleeSavedHandler.h
Normal 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
|
||||
20
src/include/backend/RISCv64/Handler/EliminateFrameIndices.h
Normal file
20
src/include/backend/RISCv64/Handler/EliminateFrameIndices.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef ELIMINATE_FRAME_INDICES_H
|
||||
#define ELIMINATE_FRAME_INDICES_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
class EliminateFrameIndicesPass {
|
||||
public:
|
||||
// Pass 的主入口函数
|
||||
void runOnMachineFunction(MachineFunction* mfunc);
|
||||
|
||||
private:
|
||||
// 帮助计算类型大小的辅助函数,从原RegAlloc中移出
|
||||
unsigned getTypeSizeInBytes(Type* type);
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // ELIMINATE_FRAME_INDICES_H
|
||||
36
src/include/backend/RISCv64/Handler/LegalizeImmediates.h
Normal file
36
src/include/backend/RISCv64/Handler/LegalizeImmediates.h
Normal 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
|
||||
@ -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
|
||||
30
src/include/backend/RISCv64/Optimize/Peephole.h
Normal file
30
src/include/backend/RISCv64/Optimize/Peephole.h
Normal 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
|
||||
50
src/include/backend/RISCv64/Optimize/PostRA_Scheduler.h
Normal file
50
src/include/backend/RISCv64/Optimize/PostRA_Scheduler.h
Normal file
@ -0,0 +1,50 @@
|
||||
#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),
|
||||
* 尝试将加载指令提前,以隐藏其访存延迟。
|
||||
*/
|
||||
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) {}
|
||||
};
|
||||
|
||||
struct InstrRegInfo {
|
||||
std::unordered_set<PhysicalReg> defined_regs;
|
||||
std::unordered_set<PhysicalReg> used_regs;
|
||||
bool is_load;
|
||||
bool is_store;
|
||||
bool is_control_flow;
|
||||
MemoryAccess mem_access;
|
||||
|
||||
InstrRegInfo() : is_load(false), is_store(false), is_control_flow(false) {}
|
||||
};
|
||||
|
||||
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
|
||||
30
src/include/backend/RISCv64/Optimize/PreRA_Scheduler.h
Normal file
30
src/include/backend/RISCv64/Optimize/PreRA_Scheduler.h
Normal 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
|
||||
@ -4,27 +4,31 @@
|
||||
#include "RISCv64LLIR.h"
|
||||
#include <iostream>
|
||||
|
||||
extern int DEBUG;
|
||||
extern int DEEPDEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
class RISCv64AsmPrinter {
|
||||
public:
|
||||
RISCv64AsmPrinter(MachineFunction* mfunc);
|
||||
|
||||
// 主入口
|
||||
void run(std::ostream& os);
|
||||
|
||||
private:
|
||||
// 打印各个部分
|
||||
void printPrologue();
|
||||
void printEpilogue();
|
||||
void printBasicBlock(MachineBasicBlock* mbb);
|
||||
void printInstruction(MachineInstr* instr);
|
||||
|
||||
void run(std::ostream& os, bool debug = false);
|
||||
void printInstruction(MachineInstr* instr, bool debug = false);
|
||||
// 辅助函数
|
||||
void setStream(std::ostream& os) { OS = &os; }
|
||||
// 辅助函数
|
||||
std::string regToString(PhysicalReg reg);
|
||||
private:
|
||||
// 打印各个部分
|
||||
void printBasicBlock(MachineBasicBlock* mbb, bool debug = false);
|
||||
// 辅助函数
|
||||
void printOperand(MachineOperand* op);
|
||||
|
||||
MachineFunction* MFunc;
|
||||
std::ostream* OS;
|
||||
std::ostream* OS = nullptr;
|
||||
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
@ -4,6 +4,9 @@
|
||||
#include "IR.h"
|
||||
#include <string>
|
||||
|
||||
extern int DEBUG;
|
||||
extern int DEEPDEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// RISCv64CodeGen 现在是一个高层驱动器
|
||||
@ -19,6 +22,9 @@ private:
|
||||
// 函数级代码生成 (实现新的流水线)
|
||||
std::string function_gen(Function* func);
|
||||
|
||||
// 私有辅助函数,用于根据类型计算其占用的字节数。
|
||||
unsigned getTypeSizeInBytes(Type* type);
|
||||
|
||||
Module* module;
|
||||
};
|
||||
|
||||
@ -3,6 +3,9 @@
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
|
||||
extern int DEBUG;
|
||||
extern int DEEPDEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
class RISCv64ISel {
|
||||
@ -14,6 +17,11 @@ public:
|
||||
// 公开接口,以便后续模块(如RegAlloc)可以查询或创建vreg
|
||||
unsigned getVReg(Value* val);
|
||||
unsigned getNewVReg() { return vreg_counter++; }
|
||||
unsigned getNewVReg(Type* type);
|
||||
// 获取 vreg_map 的公共接口
|
||||
const std::map<Value*, unsigned>& getVRegMap() const { return vreg_map; }
|
||||
const std::map<unsigned, Value*>& getVRegValueMap() const { return vreg_to_value_map; }
|
||||
const std::map<unsigned, Type*>& getVRegTypeMap() const { return vreg_type_map; }
|
||||
|
||||
private:
|
||||
// DAG节点定义,作为ISel的内部实现细节
|
||||
@ -30,6 +38,11 @@ private:
|
||||
std::vector<std::unique_ptr<DAGNode>> build_dag(BasicBlock* bb);
|
||||
DAGNode* get_operand_node(Value* val_ir, std::map<Value*, DAGNode*>&, std::vector<std::unique_ptr<DAGNode>>&);
|
||||
DAGNode* create_node(int kind, Value* val, std::map<Value*, DAGNode*>&, std::vector<std::unique_ptr<DAGNode>>&);
|
||||
// 用于计算类型大小的辅助函数
|
||||
unsigned getTypeSizeInBytes(Type* type);
|
||||
|
||||
// 打印DAG图以供调试
|
||||
void print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, const std::string& bb_name);
|
||||
|
||||
// 状态
|
||||
Function* F; // 当前处理的高层IR函数
|
||||
@ -38,6 +51,8 @@ private:
|
||||
|
||||
// 映射关系
|
||||
std::map<Value*, unsigned> vreg_map;
|
||||
std::map<unsigned, Value*> vreg_to_value_map;
|
||||
std::map<unsigned, Type*> vreg_type_map;
|
||||
std::map<const BasicBlock*, MachineBasicBlock*> bb_map;
|
||||
|
||||
unsigned vreg_counter;
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
#include "IR.h" // 确保包含了您自己的IR头文件
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
@ -18,8 +19,28 @@ namespace sysy {
|
||||
|
||||
// 物理寄存器定义
|
||||
enum class PhysicalReg {
|
||||
ZERO, RA, SP, GP, TP, T0, T1, T2, S0, S1, A0, A1, A2, A3, A4, A5, A6, A7, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, T3, T4, T5, T6,
|
||||
F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15,F16, F17, F18, F19, F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, F31
|
||||
// --- 特殊功能寄存器 ---
|
||||
ZERO, RA, SP, GP, TP,
|
||||
|
||||
// --- 整数寄存器 (按调用约定分组) ---
|
||||
// 临时寄存器 (调用者保存)
|
||||
T0, T1, T2, T3, T4, T5, T6,
|
||||
|
||||
// 保存寄存器 (被调用者保存)
|
||||
S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11,
|
||||
|
||||
// 参数/返回值寄存器 (调用者保存)
|
||||
A0, A1, A2, A3, A4, A5, A6, A7,
|
||||
|
||||
// --- 浮点寄存器 ---
|
||||
F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11,
|
||||
F12, F13, F14, F15, F16, F17, F18, F19, F20, F21,
|
||||
F22, F23, F24, F25, F26, F27, F28, F29, F30, F31,
|
||||
|
||||
// 用于内部表示物理寄存器在干扰图中的节点ID(一个简单的特殊ID,确保不与vreg_counter冲突)
|
||||
// 假设 vreg_counter 不会达到这么大的值
|
||||
PHYS_REG_START_ID = 100000,
|
||||
PHYS_REG_END_ID = PHYS_REG_START_ID + 320, // 预留足够的空间
|
||||
};
|
||||
|
||||
// RISC-V 指令操作码枚举
|
||||
@ -43,11 +64,99 @@ enum class RVOpcodes {
|
||||
CALL,
|
||||
// 特殊标记,非指令
|
||||
LABEL,
|
||||
// 新增伪指令,用于解耦栈帧处理
|
||||
FRAME_LOAD, // 从栈帧加载 (AllocaInst)
|
||||
FRAME_STORE, // 保存到栈帧 (AllocaInst)
|
||||
|
||||
// 浮点指令 (RISC-V 'F' 扩展)
|
||||
// 浮点加载与存储
|
||||
FLW, // flw rd, offset(rs1)
|
||||
FSW, // fsw rs2, offset(rs1)
|
||||
FLD, // fld rd, offset(rs1)
|
||||
FSD, // fsd rs2, offset(rs1)
|
||||
|
||||
// 浮点算术运算 (单精度)
|
||||
FADD_S, // fadd.s rd, rs1, rs2
|
||||
FSUB_S, // fsub.s rd, rs1, rs2
|
||||
FMUL_S, // fmul.s rd, rs1, rs2
|
||||
FDIV_S, // fdiv.s rd, rs1, rs2
|
||||
|
||||
// 浮点比较 (单精度)
|
||||
FEQ_S, // feq.s rd, rs1, rs2 (结果写入整数寄存器rd)
|
||||
FLT_S, // flt.s rd, rs1, rs2 (less than)
|
||||
FLE_S, // fle.s rd, rs1, rs2 (less than or equal)
|
||||
|
||||
// 浮点转换
|
||||
FCVT_S_W, // fcvt.s.w rd, rs1 (有符号整数 -> 单精度浮点)
|
||||
FCVT_W_S, // fcvt.w.s rd, rs1 (单精度浮点 -> 有符号整数)
|
||||
|
||||
// 浮点传送/移动
|
||||
FMV_S, // fmv.s rd, rs1 (浮点寄存器之间)
|
||||
FMV_W_X, // fmv.w.x rd, rs1 (整数寄存器位模式 -> 浮点寄存器)
|
||||
FMV_X_W, // fmv.x.w rd, rs1 (浮点寄存器位模式 -> 整数寄存器)
|
||||
FNEG_S, // fneg.s rd, rs (浮点取负)
|
||||
|
||||
// 伪指令
|
||||
FRAME_LOAD_W, // 从栈帧加载 32位 Word (对应 lw)
|
||||
FRAME_LOAD_D, // 从栈帧加载 64位 Doubleword (对应 ld)
|
||||
FRAME_STORE_W, // 保存 32位 Word 到栈帧 (对应 sw)
|
||||
FRAME_STORE_D, // 保存 64位 Doubleword 到栈帧 (对应 sd)
|
||||
FRAME_LOAD_F, // 从栈帧加载单精度浮点数
|
||||
FRAME_STORE_F, // 将单精度浮点数存入栈帧
|
||||
FRAME_ADDR, // 获取栈帧变量的地址
|
||||
PSEUDO_KEEPALIVE, // 保持寄存器活跃,防止优化器删除
|
||||
};
|
||||
|
||||
inline bool isGPR(PhysicalReg reg) {
|
||||
return reg >= PhysicalReg::ZERO && reg <= PhysicalReg::T6;
|
||||
}
|
||||
|
||||
// 判断一个物理寄存器是否是浮点寄存器 (FPR)
|
||||
inline bool isFPR(PhysicalReg reg) {
|
||||
return reg >= PhysicalReg::F0 && reg <= PhysicalReg::F31;
|
||||
}
|
||||
|
||||
// 获取所有调用者保存的整数寄存器 (t0-t6, a0-a7)
|
||||
inline const std::vector<PhysicalReg>& getCallerSavedIntRegs() {
|
||||
static const std::vector<PhysicalReg> 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
|
||||
};
|
||||
return regs;
|
||||
}
|
||||
|
||||
// 获取所有被调用者保存的整数寄存器 (s0-s11)
|
||||
inline const std::vector<PhysicalReg>& getCalleeSavedIntRegs() {
|
||||
static const std::vector<PhysicalReg> regs = {
|
||||
PhysicalReg::S0, PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3,
|
||||
PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
|
||||
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11
|
||||
};
|
||||
return regs;
|
||||
}
|
||||
|
||||
// 获取所有调用者保存的浮点寄存器 (ft0-ft11, fa0-fa7)
|
||||
inline const std::vector<PhysicalReg>& getCallerSavedFpRegs() {
|
||||
static const std::vector<PhysicalReg> regs = {
|
||||
PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3,
|
||||
PhysicalReg::F4, PhysicalReg::F5, PhysicalReg::F6, PhysicalReg::F7,
|
||||
PhysicalReg::F8, PhysicalReg::F9, PhysicalReg::F10, PhysicalReg::F11, // ft0-ft11 和 fa0-fa7 在标准ABI中重叠
|
||||
PhysicalReg::F12, PhysicalReg::F13, PhysicalReg::F14, PhysicalReg::F15,
|
||||
PhysicalReg::F16, PhysicalReg::F17
|
||||
};
|
||||
return regs;
|
||||
}
|
||||
|
||||
// 获取所有被调用者保存的浮点寄存器 (fs0-fs11)
|
||||
inline const std::vector<PhysicalReg>& getCalleeSavedFpRegs() {
|
||||
static const std::vector<PhysicalReg> regs = {
|
||||
PhysicalReg::F18, PhysicalReg::F19, PhysicalReg::F20, PhysicalReg::F21,
|
||||
PhysicalReg::F22, PhysicalReg::F23, PhysicalReg::F24, PhysicalReg::F25,
|
||||
PhysicalReg::F26, PhysicalReg::F27, PhysicalReg::F28, PhysicalReg::F29,
|
||||
PhysicalReg::F30, PhysicalReg::F31
|
||||
};
|
||||
return regs;
|
||||
}
|
||||
|
||||
class MachineOperand;
|
||||
class RegOperand;
|
||||
class ImmOperand;
|
||||
@ -87,6 +196,11 @@ public:
|
||||
preg = new_preg;
|
||||
is_virtual = false;
|
||||
}
|
||||
|
||||
void setVRegNum(unsigned new_vreg_num) {
|
||||
vreg_num = new_vreg_num;
|
||||
is_virtual = true; // 确保设置vreg时,操作数状态正确
|
||||
}
|
||||
private:
|
||||
unsigned vreg_num = 0;
|
||||
PhysicalReg preg = PhysicalReg::ZERO;
|
||||
@ -168,8 +282,12 @@ struct StackFrameInfo {
|
||||
int locals_size = 0; // 仅为AllocaInst分配的大小
|
||||
int spill_size = 0; // 仅为溢出分配的大小
|
||||
int total_size = 0; // 总大小
|
||||
int callee_saved_size = 0; // 保存寄存器的大小
|
||||
std::map<unsigned, int> alloca_offsets; // <AllocaInst的vreg, 栈偏移>
|
||||
std::map<unsigned, int> spill_offsets; // <溢出vreg, 栈偏移>
|
||||
std::set<PhysicalReg> used_callee_saved_regs; // 使用的保存寄存器
|
||||
std::map<unsigned, PhysicalReg> vreg_to_preg_map; // [新增] RegAlloc最终的分配结果
|
||||
std::vector<PhysicalReg> callee_saved_regs_to_store; // [新增] 已排序的、需要存取的被调用者保存寄存器
|
||||
};
|
||||
|
||||
// 机器函数
|
||||
@ -183,7 +301,7 @@ public:
|
||||
StackFrameInfo& getFrameInfo() { return frame_info; }
|
||||
const std::vector<std::unique_ptr<MachineBasicBlock>>& getBlocks() const { return blocks; }
|
||||
std::vector<std::unique_ptr<MachineBasicBlock>>& getBlocks() { return blocks; }
|
||||
|
||||
void dumpStackFrameInfo(std::ostream& os = std::cerr) const;
|
||||
void addBlock(std::unique_ptr<MachineBasicBlock> block) {
|
||||
blocks.push_back(std::move(block));
|
||||
}
|
||||
18
src/include/backend/RISCv64/RISCv64Passes.h
Normal file
18
src/include/backend/RISCv64/RISCv64Passes.h
Normal file
@ -0,0 +1,18 @@
|
||||
#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 "EliminateFrameIndices.h"
|
||||
#include "Pass.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // RISCV64_PASSES_H
|
||||
122
src/include/backend/RISCv64/RISCv64RegAlloc.h
Normal file
122
src/include/backend/RISCv64/RISCv64RegAlloc.h
Normal file
@ -0,0 +1,122 @@
|
||||
#ifndef RISCV64_REGALLOC_H
|
||||
#define RISCV64_REGALLOC_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "RISCv64ISel.h" // 包含 RISCv64ISel.h 以访问 ISel 和 Value 类型
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <stack>
|
||||
|
||||
extern int DEBUG;
|
||||
extern int DEEPDEBUG;
|
||||
extern int DEBUGLENGTH; // 用于限制调试输出的长度
|
||||
extern int DEEPERDEBUG; // 用于更深层次的调试输出
|
||||
|
||||
namespace sysy {
|
||||
|
||||
class RISCv64RegAlloc {
|
||||
public:
|
||||
RISCv64RegAlloc(MachineFunction* mfunc);
|
||||
|
||||
// 模块主入口
|
||||
void run();
|
||||
|
||||
private:
|
||||
// 类型定义,与Python版本对应
|
||||
using VRegSet = std::set<unsigned>;
|
||||
using InterferenceGraph = std::map<unsigned, VRegSet>;
|
||||
using VRegStack = std::vector<unsigned>; // 使用vector模拟栈,方便遍历
|
||||
using MoveList = std::map<unsigned, std::set<const MachineInstr*>>;
|
||||
using AliasMap = std::map<unsigned, unsigned>;
|
||||
using ColorMap = std::map<unsigned, PhysicalReg>;
|
||||
using VRegMoveSet = std::set<const MachineInstr*>;
|
||||
|
||||
// --- 核心算法流程 ---
|
||||
void initialize();
|
||||
void build();
|
||||
void makeWorklist();
|
||||
void simplify();
|
||||
void coalesce();
|
||||
void freeze();
|
||||
void selectSpill();
|
||||
void assignColors();
|
||||
void rewriteProgram();
|
||||
bool doAllocation();
|
||||
void applyColoring();
|
||||
|
||||
void dumpState(const std::string &stage);
|
||||
|
||||
void precolorByCallingConvention();
|
||||
|
||||
// --- 辅助函数 ---
|
||||
void getInstrUseDef(const MachineInstr* instr, VRegSet& use, VRegSet& def);
|
||||
void getInstrUseDef_Liveness(const MachineInstr *instr, VRegSet &use, VRegSet &def);
|
||||
void addEdge(unsigned u, unsigned v);
|
||||
VRegSet adjacent(unsigned n);
|
||||
VRegMoveSet nodeMoves(unsigned n);
|
||||
bool moveRelated(unsigned n);
|
||||
void decrementDegree(unsigned m);
|
||||
void enableMoves(const VRegSet& nodes);
|
||||
unsigned getAlias(unsigned n);
|
||||
void addWorklist(unsigned u);
|
||||
bool briggsHeuristic(unsigned u, unsigned v);
|
||||
bool georgeHeuristic(unsigned u, unsigned v);
|
||||
void combine(unsigned u, unsigned v);
|
||||
void freezeMoves(unsigned u);
|
||||
void collectUsedCalleeSavedRegs();
|
||||
bool isFPVReg(unsigned vreg) const;
|
||||
std::string regToString(PhysicalReg reg);
|
||||
std::string regIdToString(unsigned id);
|
||||
|
||||
// --- 活跃性分析 ---
|
||||
void analyzeLiveness();
|
||||
|
||||
MachineFunction* MFunc;
|
||||
RISCv64ISel* ISel;
|
||||
|
||||
// --- 算法数据结构 ---
|
||||
// 寄存器池
|
||||
std::vector<PhysicalReg> allocable_int_regs;
|
||||
std::vector<PhysicalReg> allocable_fp_regs;
|
||||
int K_int; // 整数寄存器数量
|
||||
int K_fp; // 浮点寄存器数量
|
||||
|
||||
// 节点集合
|
||||
VRegSet precolored; // 预着色的节点 (物理寄存器)
|
||||
VRegSet initial; // 初始的、所有待处理的虚拟寄存器节点
|
||||
VRegSet simplifyWorklist;
|
||||
VRegSet freezeWorklist;
|
||||
VRegSet spillWorklist;
|
||||
VRegSet spilledNodes;
|
||||
VRegSet coalescedNodes;
|
||||
VRegSet coloredNodes;
|
||||
VRegStack selectStack;
|
||||
|
||||
// Move指令相关
|
||||
std::set<const MachineInstr*> coalescedMoves;
|
||||
std::set<const MachineInstr*> constrainedMoves;
|
||||
std::set<const MachineInstr*> frozenMoves;
|
||||
std::set<const MachineInstr*> worklistMoves;
|
||||
std::set<const MachineInstr*> activeMoves;
|
||||
|
||||
// 数据结构
|
||||
InterferenceGraph adjSet;
|
||||
std::map<unsigned, VRegSet> adjList; // 邻接表
|
||||
std::map<unsigned, int> degree;
|
||||
MoveList moveList;
|
||||
AliasMap alias;
|
||||
ColorMap color_map;
|
||||
|
||||
// 活跃性分析结果
|
||||
std::map<const MachineInstr*, VRegSet> live_in_map;
|
||||
std::map<const MachineInstr*, VRegSet> live_out_map;
|
||||
|
||||
// VReg -> Value* 和 VReg -> Type* 的映射
|
||||
const std::map<unsigned, Value*>& vreg_to_value_map;
|
||||
const std::map<unsigned, Type*>& vreg_type_map;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // RISCV64_REGALLOC_H
|
||||
@ -49,6 +49,7 @@ class Type {
|
||||
kLabel,
|
||||
kPointer,
|
||||
kFunction,
|
||||
kArray,
|
||||
};
|
||||
|
||||
Kind kind; ///< 表示具体类型的变量
|
||||
@ -65,6 +66,7 @@ class Type {
|
||||
static Type* getPointerType(Type *baseType); ///< 返回表示指向baseType类型的Pointer类型的Type指针
|
||||
static Type* getFunctionType(Type *returnType, const std::vector<Type *> ¶mTypes = {});
|
||||
///< 返回表示返回类型为returnType,形参类型列表为paramTypes的函数类型的Type指针
|
||||
static Type* getArrayType(Type *elementType, unsigned numElements);
|
||||
|
||||
public:
|
||||
Kind getKind() const { return kind; } ///< 返回Type对象代表原始标量类型
|
||||
@ -74,6 +76,7 @@ class Type {
|
||||
bool isLabel() const { return kind == kLabel; } ///< 判定是否为Label类型
|
||||
bool isPointer() const { return kind == kPointer; } ///< 判定是否为Pointer类型
|
||||
bool isFunction() const { return kind == kFunction; } ///< 判定是否为Function类型
|
||||
bool isArray() const { return kind == Kind::kArray; }
|
||||
unsigned getSize() const; ///< 返回类型所占的空间大小(字节)
|
||||
/// 尝试将一个变量转换为给定的Type及其派生类类型的变量
|
||||
template <typename T>
|
||||
@ -115,6 +118,22 @@ class FunctionType : public Type {
|
||||
unsigned getNumParams() const { return paramTypes.size(); } ///< 获取形参数量
|
||||
};
|
||||
|
||||
class ArrayType : public Type {
|
||||
public:
|
||||
// elements:数组的元素类型 (例如,int[3] 的 elementType 是 int)
|
||||
// numElements:该维度的大小 (例如,int[3] 的 numElements 是 3)
|
||||
static ArrayType *get(Type *elementType, unsigned numElements);
|
||||
|
||||
Type *getElementType() const { return elementType; }
|
||||
unsigned getNumElements() const { return numElements; }
|
||||
|
||||
protected:
|
||||
ArrayType(Type *elementType, unsigned numElements)
|
||||
: Type(Kind::kArray), elementType(elementType), numElements(numElements) {}
|
||||
Type *elementType;
|
||||
unsigned numElements; // 当前维度的大小
|
||||
};
|
||||
|
||||
/*!
|
||||
* @}
|
||||
*/
|
||||
@ -340,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>
|
||||
@ -449,7 +481,6 @@ public:
|
||||
|
||||
// --- End of refactored ConstantValue and related classes ---
|
||||
|
||||
|
||||
class Instruction;
|
||||
class Function;
|
||||
class BasicBlock;
|
||||
@ -468,7 +499,6 @@ public:
|
||||
|
||||
using inst_list = std::list<std::unique_ptr<Instruction>>;
|
||||
using iterator = inst_list::iterator;
|
||||
using arg_list = std::vector<AllocaInst *>;
|
||||
using block_list = std::vector<BasicBlock *>;
|
||||
using block_set = std::unordered_set<BasicBlock *>;
|
||||
|
||||
@ -476,7 +506,6 @@ protected:
|
||||
|
||||
Function *parent; ///< 从属的函数
|
||||
inst_list instructions; ///< 拥有的指令序列
|
||||
arg_list arguments; ///< 分配空间后的形式参数列表
|
||||
block_list successors; ///< 前驱列表
|
||||
block_list predecessors; ///< 后继列表
|
||||
bool reachable = false;
|
||||
@ -485,30 +514,43 @@ 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:
|
||||
|
||||
unsigned getNumInstructions() const { return instructions.size(); }
|
||||
unsigned getNumArguments() const { return arguments.size(); }
|
||||
unsigned getNumPredecessors() const { return predecessors.size(); }
|
||||
unsigned getNumSuccessors() const { return successors.size(); }
|
||||
Function* getParent() const { return parent; }
|
||||
void setParent(Function *func) { parent = func; }
|
||||
inst_list& getInstructions() { return instructions; }
|
||||
arg_list& getArguments() { return arguments; }
|
||||
const block_list& getPredecessors() const { return predecessors; }
|
||||
auto getInstructions_Range() const { return make_range(instructions); }
|
||||
block_list& getPredecessors() { return predecessors; }
|
||||
void clearPredecessors() { predecessors.clear(); }
|
||||
block_list& getSuccessors() { return successors; }
|
||||
void clearSuccessors() { successors.clear(); }
|
||||
iterator begin() { return instructions.begin(); }
|
||||
iterator end() { return instructions.end(); }
|
||||
iterator terminator() { return std::prev(end()); }
|
||||
void insertArgument(AllocaInst *inst) { arguments.push_back(inst); }
|
||||
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();
|
||||
} ///< 判断是否有后继块
|
||||
bool hasPredecessor(BasicBlock *block) const {
|
||||
return std::find(predecessors.begin(), predecessors.end(), block) != predecessors.end();
|
||||
} ///< 判断是否有前驱块
|
||||
void addPredecessor(BasicBlock *block) {
|
||||
if (std::find(predecessors.begin(), predecessors.end(), block) == predecessors.end()) {
|
||||
predecessors.push_back(block);
|
||||
@ -534,7 +576,9 @@ public:
|
||||
if (iter != predecessors.end()) {
|
||||
predecessors.erase(iter);
|
||||
} else {
|
||||
assert(false);
|
||||
// 如果没有找到前驱块,可能是因为它已经被移除或不存在
|
||||
// 这可能是一个错误情况,或者是因为在CFG优化过程中已经处理
|
||||
// assert(false && "Predecessor block not found in BasicBlock");
|
||||
}
|
||||
}
|
||||
void removeSuccessor(BasicBlock *block) {
|
||||
@ -542,7 +586,9 @@ public:
|
||||
if (iter != successors.end()) {
|
||||
successors.erase(iter);
|
||||
} else {
|
||||
assert(false);
|
||||
// 如果没有找到后继块,可能是因为它已经被移除或不存在
|
||||
// 这可能是一个错误情况,或者是因为在CFG优化过程中已经处理
|
||||
// assert(false && "Successor block not found in BasicBlock");
|
||||
}
|
||||
}
|
||||
void replacePredecessor(BasicBlock *oldBlock, BasicBlock *newBlock) {
|
||||
@ -560,7 +606,16 @@ 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; });
|
||||
if (pos != instructions.end()) {
|
||||
instructions.erase(pos);
|
||||
} else {
|
||||
assert(false && "Instruction not found in BasicBlock");
|
||||
}
|
||||
} ///< 移除指定位置的指令
|
||||
iterator moveInst(iterator sourcePos, iterator targetPos, BasicBlock *block);
|
||||
};
|
||||
|
||||
@ -578,6 +633,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 引用计数降为0,Use 对象本身也会被销毁。
|
||||
// }
|
||||
unsigned getNumOperands() const { return operands.size(); } ///< 获取操作数数量
|
||||
auto operand_begin() const { return operands.begin(); } ///< 返回操作数列表的开头迭代器
|
||||
auto operand_end() const { return operands.end(); } ///< 返回操作数列表的结尾迭代器
|
||||
@ -602,49 +672,6 @@ class User : public Value {
|
||||
void setOperand(unsigned index, Value *value); ///< 设置操作数
|
||||
};
|
||||
|
||||
class GetSubArrayInst;
|
||||
/**
|
||||
* 左值 具有地址的对象
|
||||
*/
|
||||
class LVal {
|
||||
friend class GetSubArrayInst;
|
||||
|
||||
protected:
|
||||
LVal *fatherLVal{}; ///< 父左值
|
||||
std::list<std::unique_ptr<LVal>> childrenLVals; ///< 子左值
|
||||
GetSubArrayInst *defineInst{}; /// 定义该左值的GetSubArray指令
|
||||
|
||||
protected:
|
||||
LVal() = default;
|
||||
|
||||
public:
|
||||
virtual ~LVal() = default;
|
||||
virtual std::vector<Value *> getLValDims() const = 0; ///< 获取左值的维度
|
||||
virtual unsigned getLValNumDims() const = 0; ///< 获取左值的维度数量
|
||||
|
||||
public:
|
||||
LVal* getFatherLVal() const { return fatherLVal; } ///< 获取父左值
|
||||
const std::list<std::unique_ptr<LVal>>& getChildrenLVals() const {
|
||||
return childrenLVals;
|
||||
} ///< 获取子左值列表
|
||||
LVal* getAncestorLVal() const {
|
||||
auto curLVal = const_cast<LVal *>(this);
|
||||
while (curLVal->getFatherLVal() != nullptr) {
|
||||
curLVal = curLVal->getFatherLVal();
|
||||
}
|
||||
return curLVal;
|
||||
} ///< 获取祖先左值
|
||||
void setFatherLVal(LVal *father) { fatherLVal = father; } ///< 设置父左值
|
||||
void setDefineInst(GetSubArrayInst *inst) { defineInst = inst; } ///< 设置定义指令
|
||||
void addChild(LVal *child) { childrenLVals.emplace_back(child); } ///< 添加子左值
|
||||
void removeChild(LVal *child) {
|
||||
auto iter = std::find_if(childrenLVals.begin(), childrenLVals.end(),
|
||||
[child](const std::unique_ptr<LVal> &ptr) { return ptr.get() == child; });
|
||||
childrenLVals.erase(iter);
|
||||
} ///< 移除子左值
|
||||
GetSubArrayInst* getDefineInst() const { return defineInst; } ///< 获取定义指令
|
||||
};
|
||||
|
||||
/*!
|
||||
* Base of all concrete instruction types.
|
||||
*/
|
||||
@ -690,19 +717,17 @@ 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,
|
||||
kLa = 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,
|
||||
kBitFtoI = 0x1UL << 41
|
||||
kBitFtoI = 0x1UL << 41,
|
||||
};
|
||||
|
||||
protected:
|
||||
@ -793,14 +818,12 @@ public:
|
||||
return "Load";
|
||||
case kStore:
|
||||
return "Store";
|
||||
case kLa:
|
||||
return "La";
|
||||
case kGetElementPtr:
|
||||
return "GetElementPtr";
|
||||
case kMemset:
|
||||
return "Memset";
|
||||
case kPhi:
|
||||
return "Phi";
|
||||
case kGetSubArray:
|
||||
return "GetSubArray";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
@ -829,7 +852,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 {
|
||||
@ -849,15 +872,16 @@ 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; }
|
||||
bool isStore() const { return kind == kStore; }
|
||||
bool isLa() const { return kind == kLa; }
|
||||
bool isGetElementPtr() const { return kind == kGetElementPtr; }
|
||||
bool isMemset() const { return kind == kMemset; }
|
||||
bool isGetSubArray() const { return kind == kGetSubArray; }
|
||||
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;
|
||||
@ -867,26 +891,6 @@ public:
|
||||
class Function;
|
||||
//! Function call.
|
||||
|
||||
class LaInst : public Instruction {
|
||||
friend class Function;
|
||||
friend class IRBuilder;
|
||||
|
||||
protected:
|
||||
explicit LaInst(Value *pointer, const std::vector<Value *> &indices = {}, BasicBlock *parent = nullptr,
|
||||
const std::string &name = "")
|
||||
: Instruction(Kind::kLa, pointer->getType(), parent, name) {
|
||||
assert(pointer);
|
||||
addOperand(pointer);
|
||||
addOperands(indices);
|
||||
}
|
||||
|
||||
public:
|
||||
unsigned getNumIndices() const { return getNumOperands() - 1; } ///< 获取索引长度
|
||||
Value* getPointer() const { return getOperand(0); } ///< 获取目标变量的Value指针
|
||||
auto getIndices() const { return make_range(std::next(operand_begin()), operand_end()); } ///< 获取索引列表
|
||||
Value* getIndex(unsigned index) const { return getOperand(index + 1); } ///< 获取位置为index的索引分量
|
||||
};
|
||||
|
||||
class PhiInst : public Instruction {
|
||||
friend class IRBuilder;
|
||||
friend class Function;
|
||||
@ -912,11 +916,27 @@ 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));}
|
||||
|
||||
Value* getIncomingValue(BasicBlock* blk) const {
|
||||
return getvalfromBlk(blk);
|
||||
} ///< 获取指定基本块的传入值
|
||||
|
||||
BasicBlock* getIncomingBlock(Value* val) const {
|
||||
return getBlkfromVal(val);
|
||||
} ///< 获取指定值的传入基本块
|
||||
|
||||
void replaceIncoming(BasicBlock *oldBlock, BasicBlock *newBlock, Value *newValue){
|
||||
delBlk(oldBlock);
|
||||
addIncoming(newValue, newBlock);
|
||||
}
|
||||
|
||||
auto& getincomings() const {return blk2val;} ///< 获取所有的基本块和对应的值
|
||||
|
||||
Value* getvalfromBlk(BasicBlock* blk);
|
||||
BasicBlock* getBlkfromVal(Value* val);
|
||||
Value* getvalfromBlk(BasicBlock* blk) const ;
|
||||
BasicBlock* getBlkfromVal(Value* val) const ;
|
||||
|
||||
unsigned getNumIncomingValues() const { return vsize; } ///< 获取传入值的数量
|
||||
void addIncoming(Value *value, BasicBlock *block) {
|
||||
@ -927,6 +947,10 @@ class PhiInst : public Instruction {
|
||||
vsize++;
|
||||
} ///< 添加传入值和对应的基本块
|
||||
|
||||
void removeIncoming(BasicBlock *block){
|
||||
delBlk(block);
|
||||
}
|
||||
|
||||
void delValue(Value* val);
|
||||
void delBlk(BasicBlock* blk);
|
||||
|
||||
@ -1077,12 +1101,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:
|
||||
@ -1090,26 +1112,33 @@ 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
|
||||
|
||||
//! Conditional branch
|
||||
// 这里的args是指向条件分支的两个分支的参数列表但是现在弃用了
|
||||
// 通过mem2reg优化后,数据流分析将不会由arguments来传递
|
||||
class CondBrInst : public Instruction {
|
||||
friend class IRBuilder;
|
||||
friend class Function;
|
||||
|
||||
protected:
|
||||
CondBrInst(Value *condition, BasicBlock *thenBlock, BasicBlock *elseBlock,
|
||||
const std::vector<Value *> &thenArgs,
|
||||
const std::vector<Value *> &elseArgs, BasicBlock *parent = nullptr)
|
||||
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); }
|
||||
@ -1119,79 +1148,84 @@ 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);
|
||||
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);
|
||||
}
|
||||
auto getElseArguments() const {
|
||||
auto begin =
|
||||
std::next(operand_begin(), 3 + getThenBlock()->getNumArguments());
|
||||
auto end = operand_end();
|
||||
return make_range(begin, end);
|
||||
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 , public LVal {
|
||||
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:
|
||||
std::vector<Value *> getLValDims() const override {
|
||||
std::vector<Value *> dims;
|
||||
for (const auto &dim : getOperands()) {
|
||||
dims.emplace_back(dim->getValue());
|
||||
}
|
||||
return dims;
|
||||
} ///< 获取作为左值的维度数组
|
||||
unsigned getLValNumDims() const override { return getNumOperands(); }
|
||||
|
||||
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
|
||||
|
||||
|
||||
class GetSubArrayInst : public Instruction {
|
||||
class GetElementPtrInst : public Instruction {
|
||||
friend class IRBuilder;
|
||||
friend class Function;
|
||||
|
||||
public:
|
||||
GetSubArrayInst(LVal *fatherArray, LVal *childArray, const std::vector<Value *> &indices,
|
||||
protected:
|
||||
// GEP的构造函数:
|
||||
// resultType: GEP计算出的地址的类型 (通常是指向目标元素类型的指针)
|
||||
// basePointer: 基指针 (第一个操作数)
|
||||
// indices: 索引列表 (后续操作数)
|
||||
GetElementPtrInst(Type *resultType,
|
||||
Value *basePointer,
|
||||
const std::vector<Value *> &indices = {},
|
||||
BasicBlock *parent = nullptr, const std::string &name = "")
|
||||
: Instruction(Kind::kGetSubArray, Type::getVoidType(), parent, name) {
|
||||
auto predicate = [childArray](const std::unique_ptr<LVal> &child) -> bool { return child.get() == childArray; };
|
||||
if (std::find_if(fatherArray->childrenLVals.begin(), fatherArray->childrenLVals.end(), predicate) ==
|
||||
fatherArray->childrenLVals.end()) {
|
||||
fatherArray->childrenLVals.emplace_back(childArray);
|
||||
: Instruction(Kind::kGetElementPtr, resultType, parent, name) {
|
||||
assert(basePointer && "GEP base pointer cannot be null!");
|
||||
// TODO : 安全检查
|
||||
assert(basePointer->getType()->isPointer() );
|
||||
addOperand(basePointer); // 第一个操作数是基指针
|
||||
addOperands(indices); // 随后的操作数是索引
|
||||
}
|
||||
childArray->fatherLVal = fatherArray;
|
||||
childArray->defineInst = this;
|
||||
auto fatherArrayValue = dynamic_cast<Value *>(fatherArray);
|
||||
auto childArrayValue = dynamic_cast<Value *>(childArray);
|
||||
assert(fatherArrayValue);
|
||||
assert(childArrayValue);
|
||||
addOperand(fatherArrayValue);
|
||||
addOperand(childArrayValue);
|
||||
addOperands(indices);
|
||||
public:
|
||||
Value* getBasePointer() const { return getOperand(0); }
|
||||
unsigned getNumIndices() const { return getNumOperands() - 1; }
|
||||
auto getIndices() const { return make_range(std::next(operand_begin()), operand_end());}
|
||||
Value* getIndex(unsigned index) const {
|
||||
assert(index < getNumIndices() && "Index out of bounds for GEP!");
|
||||
return getOperand(index + 1);
|
||||
}
|
||||
|
||||
public:
|
||||
Value* getFatherArray() const { return getOperand(0); } ///< 获取父数组
|
||||
Value* getChildArray() const { return getOperand(1); } ///< 获取子数组
|
||||
LVal* getFatherLVal() const { return dynamic_cast<LVal *>(getOperand(0)); } ///< 获取父左值
|
||||
LVal* getChildLVal() const { return dynamic_cast<LVal *>(getOperand(1)); } ///< 获取子左值
|
||||
auto getIndices() const { return make_range(std::next(operand_begin(), 2), operand_end()); } ///< 获取索引
|
||||
unsigned getNumIndices() const { return getNumOperands() - 2; } ///< 获取索引数量
|
||||
// 静态工厂方法,用于创建GEP指令 (如果需要外部直接创建而非通过IRBuilder)
|
||||
static GetElementPtrInst* create(Type *resultType, Value *basePointer,
|
||||
const std::vector<Value *> &indices = {},
|
||||
BasicBlock *parent = nullptr, const std::string &name = "") {
|
||||
return new GetElementPtrInst(resultType, basePointer, indices, parent, name);
|
||||
}
|
||||
};
|
||||
|
||||
//! Load a value from memory address specified by a pointer value
|
||||
@ -1200,37 +1234,16 @@ 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); }
|
||||
std::list<Value *> getAncestorIndices() const {
|
||||
std::list<Value *> indices;
|
||||
for (const auto &index : getIndices()) {
|
||||
indices.emplace_back(index->getValue());
|
||||
}
|
||||
auto curPointer = dynamic_cast<LVal *>(getPointer());
|
||||
while (curPointer->getFatherLVal() != nullptr) {
|
||||
auto inserter = std::next(indices.begin());
|
||||
for (const auto &index : curPointer->getDefineInst()->getIndices()) {
|
||||
indices.insert(inserter, index->getValue());
|
||||
}
|
||||
curPointer = curPointer->getFatherLVal();
|
||||
}
|
||||
|
||||
return indices;
|
||||
} ///< 获取相对于祖先数组的索引列表
|
||||
}; // class LoadInst
|
||||
|
||||
//! Store a value to memory address specified by a pointer value
|
||||
@ -1240,38 +1253,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); }
|
||||
std::list<Value *> getAncestorIndices() const {
|
||||
std::list<Value *> indices;
|
||||
for (const auto &index : getIndices()) {
|
||||
indices.emplace_back(index->getValue());
|
||||
}
|
||||
auto curPointer = dynamic_cast<LVal *>(getPointer());
|
||||
while (curPointer->getFatherLVal() != nullptr) {
|
||||
auto inserter = std::next(indices.begin());
|
||||
for (const auto &index : curPointer->getDefineInst()->getIndices()) {
|
||||
indices.insert(inserter, index->getValue());
|
||||
}
|
||||
curPointer = curPointer->getFatherLVal();
|
||||
}
|
||||
|
||||
return indices;
|
||||
} ///< 获取相对于祖先数组的索引列表
|
||||
|
||||
}; // class StoreInst
|
||||
|
||||
@ -1308,17 +1298,33 @@ public:
|
||||
class GlobalValue;
|
||||
|
||||
|
||||
class Argument : public Value {
|
||||
protected:
|
||||
Function *func;
|
||||
int index;
|
||||
|
||||
public:
|
||||
Argument(Type *type, Function *func, int index, const std::string &name = "")
|
||||
: Value(type, name), func(func), index(index) {}
|
||||
|
||||
public:
|
||||
Function* getParent() const { return func; }
|
||||
int getIndex() const { return index; }
|
||||
};
|
||||
|
||||
|
||||
class Module;
|
||||
//! Function definitionclass
|
||||
class Function : public Value {
|
||||
friend class Module;
|
||||
protected:
|
||||
Function(Module *parent, Type *type, const std::string &name) : Value(type, name), parent(parent) {
|
||||
blocks.emplace_back(new BasicBlock(this));
|
||||
blocks.emplace_back(new BasicBlock(this, "entry_" + name)); ///< 创建一个入口基本块
|
||||
}
|
||||
|
||||
public:
|
||||
using block_list = std::list<std::unique_ptr<BasicBlock>>;
|
||||
using arg_list = std::vector<Argument *>;
|
||||
enum FunctionAttribute : uint64_t {
|
||||
PlaceHolder = 0x0UL,
|
||||
Pure = 0x1UL << 0,
|
||||
@ -1330,6 +1336,7 @@ public:
|
||||
protected:
|
||||
Module *parent; ///< 函数的父模块
|
||||
block_list blocks; ///< 函数包含的基本块列表
|
||||
arg_list arguments; ///< 函数参数列表
|
||||
FunctionAttribute attribute = PlaceHolder; ///< 函数属性
|
||||
std::set<Function *> callees; ///< 函数调用的函数集合
|
||||
public:
|
||||
@ -1354,6 +1361,16 @@ protected:
|
||||
auto getBasicBlocks() { return make_range(blocks); }
|
||||
block_list& getBasicBlocks_NoRange() { return blocks; }
|
||||
BasicBlock* getEntryBlock() { return blocks.front().get(); }
|
||||
void insertArgument(Argument *arg) { arguments.push_back(arg); }
|
||||
arg_list& getArguments() { return arguments; }
|
||||
unsigned getNumArguments() const { return arguments.size(); }
|
||||
Argument* getArgument(unsigned index) const {
|
||||
assert(index < arguments.size() && "Argument index out of bounds");
|
||||
return arguments[index];
|
||||
} ///< 获取位置为index的参数
|
||||
auto getArgumentsRange() const {
|
||||
return make_range(arguments.begin(), arguments.end());
|
||||
} ///< 获取参数列表的范围
|
||||
void removeBasicBlock(BasicBlock *blockToRemove) {
|
||||
auto is_same_ptr = [blockToRemove](const std::unique_ptr<BasicBlock> &ptr) { return ptr.get() == blockToRemove; };
|
||||
blocks.remove_if(is_same_ptr);
|
||||
@ -1373,7 +1390,7 @@ protected:
|
||||
};
|
||||
|
||||
//! Global value declared at file scope
|
||||
class GlobalValue : public User, public LVal {
|
||||
class GlobalValue : public Value {
|
||||
friend class Module;
|
||||
|
||||
protected:
|
||||
@ -1383,19 +1400,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
|
||||
@ -1407,30 +1423,31 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
unsigned getLValNumDims() const override { return numDims; } ///< 获取作为左值的维度数量
|
||||
std::vector<Value *> getLValDims() const override {
|
||||
std::vector<Value *> dims;
|
||||
for (const auto &dim : getOperands()) {
|
||||
dims.emplace_back(dim->getValue());
|
||||
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 dims;
|
||||
} ///< 获取作为左值的维度列表
|
||||
|
||||
unsigned getNumDims() const { return numDims; } ///< 获取维度数量
|
||||
Value* getDim(unsigned index) const { return getOperand(index); } ///< 获取位置为index的维度
|
||||
auto getDims() const { return getOperands(); } ///< 获取维度列表
|
||||
return GlobalValueType->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 *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获取初始值
|
||||
@ -1438,7 +1455,7 @@ public:
|
||||
}; // class GlobalValue
|
||||
|
||||
|
||||
class ConstantVariable : public User, public LVal {
|
||||
class ConstantVariable : public Value {
|
||||
friend class Module;
|
||||
|
||||
protected:
|
||||
@ -1447,49 +1464,57 @@ class ConstantVariable : public User, public LVal {
|
||||
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 getLValNumDims() const override { return numDims; } ///< 获取作为左值的维度数量
|
||||
std::vector<Value *> getLValDims() const override {
|
||||
std::vector<Value *> dims;
|
||||
for (const auto &dim : getOperands()) {
|
||||
dims.emplace_back(dim->getValue());
|
||||
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 dims;
|
||||
} ///< 获取作为左值的维度列表
|
||||
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; } ///< 获取初始值
|
||||
};
|
||||
|
||||
using SymbolTableNode = struct SymbolTableNode {
|
||||
SymbolTableNode *pNode; ///< 父节点
|
||||
std::vector<SymbolTableNode *> children; ///< 子节点列表
|
||||
std::map<std::string, User *> varList; ///< 变量列表
|
||||
std::map<std::string, Value *> varList; ///< 变量列表
|
||||
};
|
||||
|
||||
|
||||
@ -1498,16 +1523,16 @@ 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:
|
||||
SymbolTable() = default;
|
||||
|
||||
User* getVariable(const std::string &name) const; ///< 根据名字name以及当前作用域获取变量
|
||||
User* addVariable(const std::string &name, User *variable); ///< 添加变量
|
||||
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; ///< 是否位于全局作用域
|
||||
@ -1541,13 +1566,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();
|
||||
}
|
||||
@ -1556,9 +1580,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;
|
||||
}
|
||||
@ -1567,7 +1590,7 @@ class Module {
|
||||
void addVariable(const std::string &name, AllocaInst *variable) {
|
||||
variableTable.addVariable(name, variable);
|
||||
} ///< 添加变量
|
||||
User* getVariable(const std::string &name) {
|
||||
Value* getVariable(const std::string &name) {
|
||||
return variableTable.getVariable(name);
|
||||
} ///< 根据名字name和当前作用域获取变量
|
||||
Function* getFunction(const std::string &name) const {
|
||||
@ -126,7 +126,7 @@ class IRBuilder {
|
||||
UnaryInst * createFNotInst(Value *operand, const std::string &name = "") {
|
||||
return createUnaryInst(Instruction::kFNot, Type::getIntType(), operand, name);
|
||||
} ///< 创建浮点取非指令
|
||||
UnaryInst * createIToFInst(Value *operand, const std::string &name = "") {
|
||||
UnaryInst * createItoFInst(Value *operand, const std::string &name = "") {
|
||||
return createUnaryInst(Instruction::kItoF, Type::getFloatType(), operand, name);
|
||||
} ///< 创建整型转浮点指令
|
||||
UnaryInst * createBitItoFInst(Value *operand, const std::string &name = "") {
|
||||
@ -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,12 +274,50 @@ 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;
|
||||
} ///< 创建load指令
|
||||
LaInst * createLaInst(Value *pointer, const std::vector<Value *> &indices = {}, const std::string &name = "") {
|
||||
MemsetInst * createMemsetInst(Value *pointer, Value *begin, Value *size, Value *value, const std::string &name = "") {
|
||||
auto inst = new MemsetInst(pointer, begin, size, value, block, name);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建memset指令
|
||||
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 = "") {
|
||||
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指令
|
||||
/**
|
||||
* @brief 根据 LLVM 设计模式创建 GEP 指令。
|
||||
* 它会自动推断返回类型,无需手动指定。
|
||||
*/
|
||||
GetElementPtrInst *createGetElementPtrInst(Value *basePointer, const std::vector<Value *> &indices,
|
||||
const std::string &name = "") {
|
||||
Type *ResultElementType = getIndexedType(basePointer->getType(), indices);
|
||||
if (!ResultElementType) {
|
||||
assert(false && "Invalid GEP indexing!");
|
||||
return nullptr;
|
||||
}
|
||||
Type *ResultType = PointerType::get(ResultElementType);
|
||||
std::string newName;
|
||||
if (name.empty()) {
|
||||
std::stringstream ss;
|
||||
@ -291,55 +328,57 @@ class IRBuilder {
|
||||
newName = name;
|
||||
}
|
||||
|
||||
auto inst = new LaInst(pointer, indices, block, newName);
|
||||
auto inst = new GetElementPtrInst(ResultType, basePointer, indices, block, newName);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建la指令
|
||||
GetSubArrayInst * createGetSubArray(LVal *fatherArray, const std::vector<Value *> &indices, const std::string &name = "") {
|
||||
assert(fatherArray->getLValNumDims() > indices.size());
|
||||
std::vector<Value *> subDims;
|
||||
auto dims = fatherArray->getLValDims();
|
||||
auto iter = std::next(dims.begin(), indices.size());
|
||||
while (iter != dims.end()) {
|
||||
subDims.emplace_back(*iter);
|
||||
iter++;
|
||||
}
|
||||
|
||||
std::string childArrayName;
|
||||
std::stringstream ss;
|
||||
ss << "A"
|
||||
<< "%" << tmpIndex;
|
||||
childArrayName = ss.str();
|
||||
tmpIndex++;
|
||||
static Type *getIndexedType(Type *pointerType, const std::vector<Value *> &indices) {
|
||||
assert(pointerType->isPointer() && "base must be a pointer type!");
|
||||
// GEP 的类型推断从基指针所指向的类型开始。
|
||||
// 例如:
|
||||
// - 如果 pointerType 是 `[20 x [10 x i32]]*`,`currentWalkType` 初始为 `[20 x [10 x i32]]`。
|
||||
// - 如果 pointerType 是 `i32*`,`currentWalkType` 初始为 `i32`。
|
||||
// - 如果 pointerType 是 `i32**`,`currentWalkType` 初始为 `i32*`。
|
||||
Type *currentWalkType = pointerType->as<PointerType>()->getBaseType();
|
||||
|
||||
auto fatherArrayValue = dynamic_cast<Value *>(fatherArray);
|
||||
auto childArray = new AllocaInst(fatherArrayValue->getType(), subDims, block, childArrayName);
|
||||
auto inst = new GetSubArrayInst(fatherArray, childArray, indices, block, childArrayName);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建获取部分数组指令
|
||||
MemsetInst * createMemsetInst(Value *pointer, Value *begin, Value *size, Value *value, const std::string &name = "") {
|
||||
auto inst = new MemsetInst(pointer, begin, size, value, block, name);
|
||||
assert(inst);
|
||||
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);
|
||||
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 predNum = block->getNumPredecessors();
|
||||
auto inst = new PhiInst(type, vals, blks, block, name);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(block->begin(), inst);
|
||||
return inst;
|
||||
} ///< 创建Phi指令
|
||||
// 遍历所有索引来深入类型层次结构。
|
||||
// `indices` 向量包含了所有 GEP 索引,包括由 `visitLValue` 等函数添加的初始 `0` 索引。
|
||||
for (int i = 0; i < indices.size(); ++i) {
|
||||
if (currentWalkType->isArray()) {
|
||||
// 情况一:当前遍历类型是 `ArrayType`。
|
||||
// 索引用于选择数组元素,`currentWalkType` 更新为数组的元素类型。
|
||||
currentWalkType = currentWalkType->as<ArrayType>()->getElementType();
|
||||
} else if (currentWalkType->isPointer()) {
|
||||
// 情况二:当前遍历类型是 `PointerType`。
|
||||
// 这意味着我们正在通过一个指针来访问其指向的内存。
|
||||
// 索引用于选择该指针所指向的“数组”的元素。
|
||||
// `currentWalkType` 更新为该指针所指向的基础类型。
|
||||
// 例如:如果 `currentWalkType` 是 `i32*`,它将变为 `i32`。
|
||||
// 如果 `currentWalkType` 是 `[10 x i32]*`,它将变为 `[10 x i32]`。
|
||||
currentWalkType = currentWalkType->as<PointerType>()->getBaseType();
|
||||
} else {
|
||||
// 情况三:当前遍历类型是标量类型 (例如 `i32`, `float` 等非聚合、非指针类型)。
|
||||
//
|
||||
// 如果 `currentWalkType` 是标量,并且当前索引 `i` **不是** `indices` 向量中的最后一个索引,
|
||||
// 这意味着尝试对一个标量类型进行进一步的结构性索引,这是**无效的**。
|
||||
// 例如:`int x; x[0];` 对应的 GEP 链中,`x` 的类型是 `i32`,再加 `[0]` 索引就是错误。
|
||||
//
|
||||
// 如果 `currentWalkType` 是标量,且这是**最后一个索引** (`i == indices.size() - 1`),
|
||||
// 那么 GEP 是合法的,它只是计算一个偏移地址,最终的类型就是这个标量类型。
|
||||
// 此时 `currentWalkType` 保持不变,循环结束。
|
||||
if (i < indices.size() - 1) {
|
||||
assert(false && "Invalid GEP indexing: attempting to index into a non-aggregate/non-pointer type with further indices.");
|
||||
return nullptr; // 返回空指针表示类型推断失败
|
||||
}
|
||||
// 如果是最后一个索引,且当前类型是标量,则类型保持不变,这是合法的。
|
||||
// 循环会自然结束,返回正确的 `currentWalkType`。
|
||||
}
|
||||
}
|
||||
// 所有索引处理完毕后,`currentWalkType` 就是 GEP 指令最终计算出的地址所指向的元素的类型。
|
||||
return currentWalkType;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
55
src/include/midend/Pass/Analysis/Dom.h
Normal file
55
src/include/midend/Pass/Analysis/Dom.h
Normal file
@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include "Pass.h" // 包含 Pass 框架
|
||||
#include "IR.h" // 包含 IR 定义
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 支配树分析结果类 (保持不变)
|
||||
class DominatorTree : public AnalysisResultBase {
|
||||
public:
|
||||
DominatorTree(Function* F);
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
// 支配树分析遍
|
||||
class DominatorTreeAnalysisPass : public AnalysisPass {
|
||||
public:
|
||||
// 唯一的 Pass ID
|
||||
static void *ID;
|
||||
|
||||
DominatorTreeAnalysisPass() : AnalysisPass("DominatorTreeAnalysis", Pass::Granularity::Function) {}
|
||||
|
||||
// 实现 getPassID
|
||||
void* getPassID() const override { return &ID; }
|
||||
|
||||
bool runOnFunction(Function* F, AnalysisManager &AM) override;
|
||||
|
||||
std::unique_ptr<AnalysisResultBase> getResult() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<DominatorTree> CurrentDominatorTree;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
72
src/include/midend/Pass/Analysis/Liveness.h
Normal file
72
src/include/midend/Pass/Analysis/Liveness.h
Normal file
@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include "IR.h" // 包含 IR 定义
|
||||
#include "Pass.h" // 包含 Pass 框架
|
||||
#include <algorithm> // for std::set_union, std::set_difference
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 前向声明
|
||||
class Function;
|
||||
class BasicBlock;
|
||||
class Value;
|
||||
class Instruction;
|
||||
|
||||
// 活跃变量分析结果类
|
||||
// 它将包含 LiveIn 和 LiveOut 集合
|
||||
class LivenessAnalysisResult : public AnalysisResultBase {
|
||||
public:
|
||||
LivenessAnalysisResult(Function *F) : AssociatedFunction(F) {}
|
||||
|
||||
// 获取给定基本块的 LiveIn 集合
|
||||
const std::set<Value *> *getLiveIn(BasicBlock *BB) const;
|
||||
|
||||
// 获取给定基本块的 LiveOut 集合
|
||||
const std::set<Value *> *getLiveOut(BasicBlock *BB) const;
|
||||
|
||||
// 暴露内部数据结构,如果需要更直接的访问
|
||||
const std::map<BasicBlock *, std::set<Value *>> &getLiveInSets() const { return liveInSets; }
|
||||
const std::map<BasicBlock *, std::set<Value *>> &getLiveOutSets() const { return liveOutSets; }
|
||||
|
||||
// 核心计算方法,由 LivenessAnalysisPass 调用
|
||||
void computeLiveness(Function *F);
|
||||
|
||||
private:
|
||||
Function *AssociatedFunction; // 这个活跃变量分析是为哪个函数计算的
|
||||
std::map<BasicBlock *, std::set<Value *>> liveInSets;
|
||||
std::map<BasicBlock *, std::set<Value *>> liveOutSets;
|
||||
|
||||
// 辅助函数:计算基本块的 Def 和 Use 集合
|
||||
// Def: 块内定义,且定义在所有使用之前的值
|
||||
// Use: 块内使用,且使用在所有定义之前的值
|
||||
void computeDefUse(BasicBlock *BB, std::set<Value *> &def, std::set<Value *> &use);
|
||||
};
|
||||
|
||||
// 活跃变量分析遍
|
||||
class LivenessAnalysisPass : public AnalysisPass {
|
||||
public:
|
||||
// 唯一的 Pass ID
|
||||
static void *ID; // LLVM 风格的唯一 ID
|
||||
|
||||
LivenessAnalysisPass() : AnalysisPass("LivenessAnalysis", Pass::Granularity::Function) {}
|
||||
|
||||
// 实现 getPassID
|
||||
void *getPassID() const override { return &ID; }
|
||||
|
||||
// 运行分析并返回结果。现在接受 AnalysisManager& AM 参数
|
||||
bool runOnFunction(Function *F, AnalysisManager &AM) override;
|
||||
|
||||
// 获取分析结果的指针。
|
||||
// 注意:AnalysisManager 将会调用此方法来获取结果并进行缓存。
|
||||
std::unique_ptr<AnalysisResultBase> getResult() override;
|
||||
|
||||
private:
|
||||
// 存储当前分析计算出的 LivenessAnalysisResult 实例
|
||||
// runOnFunction 每次调用都会创建新的 LivenessAnalysisResult 对象
|
||||
std::unique_ptr<LivenessAnalysisResult> CurrentLivenessResult;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
63
src/include/midend/Pass/Optimize/DCE.h
Normal file
63
src/include/midend/Pass/Optimize/DCE.h
Normal file
@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include "Pass.h"
|
||||
#include "IR.h"
|
||||
#include "SysYIROptUtils.h"
|
||||
#include "Dom.h"
|
||||
#include <unordered_set>
|
||||
#include <queue>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 前向声明分析结果类,确保在需要时可以引用
|
||||
// class DominatorTreeAnalysisResult; // Pass.h 中已包含,这里不再需要
|
||||
class SideEffectInfoAnalysisResult; // 假设有副作用分析结果类
|
||||
|
||||
// DCEContext 类,用于封装DCE的内部逻辑和状态
|
||||
// 这样可以避免静态变量在多线程或多次运行时的冲突,并保持代码的模块化
|
||||
class DCEContext {
|
||||
public:
|
||||
// 运行DCE的主要方法
|
||||
// func: 当前要优化的函数
|
||||
// tp: 分析管理器,用于获取其他分析结果(如果需要)
|
||||
void run(Function* func, AnalysisManager* AM, bool &changed);
|
||||
|
||||
private:
|
||||
// 存储活跃指令的集合
|
||||
std::unordered_set<Instruction*> alive_insts;
|
||||
|
||||
// 判断指令是否是“天然活跃”的(即总是保留的)
|
||||
// inst: 要检查的指令
|
||||
// 返回值: 如果指令是天然活跃的,则为true,否则为false
|
||||
bool isAlive(Instruction* inst);
|
||||
|
||||
// 递归地将活跃指令及其依赖加入到 alive_insts 集合中
|
||||
// inst: 要标记为活跃的指令
|
||||
void addAlive(Instruction* inst);
|
||||
};
|
||||
|
||||
// DCE 优化遍类,继承自 OptimizationPass
|
||||
class DCE : public OptimizationPass {
|
||||
public:
|
||||
// 构造函数
|
||||
DCE() : OptimizationPass("DCE", Granularity::Function) {}
|
||||
|
||||
// 静态成员,作为该遍的唯一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;
|
||||
|
||||
// Pass 基类中的纯虚函数,必须实现
|
||||
void *getPassID() const override { return &ID; }
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
114
src/include/midend/Pass/Optimize/Mem2Reg.h
Normal file
114
src/include/midend/Pass/Optimize/Mem2Reg.h
Normal file
@ -0,0 +1,114 @@
|
||||
#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 指令
|
||||
void renameVariables(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
|
||||
59
src/include/midend/Pass/Optimize/Reg2Mem.h
Normal file
59
src/include/midend/Pass/Optimize/Reg2Mem.h
Normal 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
|
||||
139
src/include/midend/Pass/Optimize/SCCP.h
Normal file
139
src/include/midend/Pass/Optimize/SCCP.h
Normal 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
|
||||
101
src/include/midend/Pass/Optimize/SysYIRCFGOpt.h
Normal file
101
src/include/midend/Pass/Optimize/SysYIRCFGOpt.h
Normal file
@ -0,0 +1,101 @@
|
||||
#pragma once
|
||||
|
||||
#include "IR.h"
|
||||
#include "IRBuilder.h"
|
||||
#include "Pass.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 优化前对SysY IR的预处理,也可以视作部分CFG优化
|
||||
// 主要包括删除无用指令、合并基本块、删除空块等
|
||||
// 这些操作可以在SysY IR生成时就完成,但为了简化IR生成过程,
|
||||
// 这里将其放在SysY IR生成后进行预处理
|
||||
// 同时兼容phi节点的处理,可以再mem2reg后再次调用优化
|
||||
|
||||
//TODO: 可增加的CFG优化和方法
|
||||
// - 检查基本块跳转关系正确性
|
||||
// - 简化条件分支(Branch Simplification),如条件恒真/恒假转为直接跳转
|
||||
// - 合并连续的跳转指令(Jump Threading)在合并不可达块中似乎已经实现了
|
||||
// - 基本块重排序(Block Reordering),提升局部性
|
||||
|
||||
// 辅助工具类,包含实际的CFG优化逻辑
|
||||
// 这些方法可以被独立的Pass调用
|
||||
class SysYCFGOptUtils {
|
||||
public:
|
||||
static bool SysYDelInstAfterBr(Function *func); // 删除br后面的指令
|
||||
static bool SysYDelEmptyBlock(Function *func, IRBuilder* pBuilder); // 空块删除
|
||||
static bool SysYDelNoPreBLock(Function *func); // 删除无前驱块(不可达块)
|
||||
static bool SysYBlockMerge(Function *func); // 合并基本块
|
||||
static bool SysYAddReturn(Function *func, IRBuilder* pBuilder); // 添加return指令
|
||||
static bool SysYCondBr2Br(Function *func, IRBuilder* pBuilder); // 条件分支转换为无条件分支
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
// 独立的CFG优化遍
|
||||
// ======================================================================
|
||||
|
||||
class SysYDelInstAfterBrPass : public OptimizationPass {
|
||||
public:
|
||||
static void *ID; // 唯一ID
|
||||
SysYDelInstAfterBrPass() : OptimizationPass("SysYDelInstAfterBrPass", Granularity::Function) {}
|
||||
bool runOnFunction(Function *F, AnalysisManager& AM) override;
|
||||
void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const override {
|
||||
// 这个优化可能改变CFG结构,使一些CFG相关的分析失效
|
||||
// 可以在这里指定哪些分析会失效,例如支配树、活跃变量等
|
||||
// analysisInvalidations.insert(DominatorTreeAnalysisPass::ID); // 示例
|
||||
}
|
||||
void *getPassID() const override { return &ID; }
|
||||
};
|
||||
|
||||
class SysYDelEmptyBlockPass : public OptimizationPass {
|
||||
private:
|
||||
IRBuilder *pBuilder;
|
||||
public:
|
||||
static void *ID;
|
||||
SysYDelEmptyBlockPass(IRBuilder *builder) : OptimizationPass("SysYDelEmptyBlockPass", Granularity::Function), pBuilder(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; }
|
||||
};
|
||||
|
||||
class SysYDelNoPreBLockPass : public OptimizationPass {
|
||||
public:
|
||||
static void *ID;
|
||||
SysYDelNoPreBLockPass() : OptimizationPass("SysYDelNoPreBLockPass", Granularity::Function) {}
|
||||
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; }
|
||||
};
|
||||
|
||||
class SysYBlockMergePass : public OptimizationPass {
|
||||
public:
|
||||
static void *ID;
|
||||
SysYBlockMergePass() : OptimizationPass("SysYBlockMergePass", Granularity::Function) {}
|
||||
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; }
|
||||
};
|
||||
|
||||
class SysYAddReturnPass : public OptimizationPass {
|
||||
private:
|
||||
IRBuilder *pBuilder;
|
||||
public:
|
||||
static void *ID;
|
||||
SysYAddReturnPass(IRBuilder *builder) : OptimizationPass("SysYAddReturnPass", Granularity::Function), pBuilder(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; }
|
||||
};
|
||||
|
||||
class SysYCondBr2BrPass : public OptimizationPass {
|
||||
private:
|
||||
IRBuilder *pBuilder;
|
||||
public:
|
||||
static void *ID;
|
||||
SysYCondBr2BrPass(IRBuilder *builder) : OptimizationPass("SysYCondBr2BrPass", Granularity::Function), pBuilder(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; }
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
119
src/include/midend/Pass/Optimize/SysYIROptUtils.h
Normal file
119
src/include/midend/Pass/Optimize/SysYIROptUtils.h
Normal 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
|
||||
324
src/include/midend/Pass/Pass.h
Normal file
324
src/include/midend/Pass/Pass.h
Normal file
@ -0,0 +1,324 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional> // For std::function
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <typeindex> // For std::type_index (although void* ID is more common in LLVM)
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
#include "IR.h"
|
||||
#include "IRBuilder.h"
|
||||
|
||||
extern int DEBUG; // 全局调试标志
|
||||
|
||||
namespace sysy {
|
||||
|
||||
//前向声明
|
||||
class PassManager;
|
||||
class AnalysisManager;
|
||||
|
||||
// 抽象基类:分析结果
|
||||
class AnalysisResultBase {
|
||||
public:
|
||||
virtual ~AnalysisResultBase() = default;
|
||||
};
|
||||
|
||||
// 抽象基类:Pass
|
||||
class Pass {
|
||||
public:
|
||||
enum class Granularity { Module, Function, BasicBlock };
|
||||
|
||||
enum class PassKind { Analysis, Optimization };
|
||||
|
||||
Pass(const std::string &name, Granularity g, PassKind k) : Name(name), G(g), K(k) {}
|
||||
virtual ~Pass() = default;
|
||||
|
||||
const std::string &getName() const { return Name; }
|
||||
Granularity getGranularity() const { return G; }
|
||||
PassKind getPassKind() const { return K; }
|
||||
|
||||
virtual bool runOnModule(Module *M, AnalysisManager& AM) { return false; }
|
||||
virtual bool runOnFunction(Function *F, AnalysisManager& AM) { return false; }
|
||||
virtual bool runOnBasicBlock(BasicBlock *BB, AnalysisManager& AM) { return false; }
|
||||
|
||||
// 所有 Pass 都必须提供一个唯一的 ID
|
||||
// 这通常是一个静态成员,并在 Pass 类外部定义
|
||||
virtual void *getPassID() const = 0;
|
||||
|
||||
protected:
|
||||
std::string Name;
|
||||
Granularity G;
|
||||
PassKind K;
|
||||
};
|
||||
|
||||
// 抽象基类:分析遍
|
||||
class AnalysisPass : public Pass {
|
||||
public:
|
||||
AnalysisPass(const std::string &name, Granularity g) : Pass(name, g, PassKind::Analysis) {}
|
||||
|
||||
virtual std::unique_ptr<AnalysisResultBase> getResult() = 0;
|
||||
};
|
||||
|
||||
// 抽象基类:优化遍
|
||||
class OptimizationPass : public Pass {
|
||||
public:
|
||||
OptimizationPass(const std::string &name, Granularity g) : Pass(name, g, PassKind::Optimization) {}
|
||||
|
||||
virtual void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
|
||||
// 默认不依赖也不修改任何分析
|
||||
}
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
// PassRegistry: 全局 Pass 注册表 (单例)
|
||||
// ======================================================================
|
||||
class PassRegistry {
|
||||
public:
|
||||
// Pass 工厂函数类型:返回 Pass 的唯一指针
|
||||
using PassFactory = std::function<std::unique_ptr<Pass>()>;
|
||||
|
||||
// 获取 PassRegistry 实例 (单例模式)
|
||||
static PassRegistry &getPassRegistry() {
|
||||
static PassRegistry instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
// 注册一个 Pass
|
||||
// passID 是 Pass 类的唯一静态 ID (例如 MyPass::ID 的地址)
|
||||
// factory 是一个 lambda 或函数指针,用于创建该 Pass 的实例
|
||||
void registerPass(void *passID, PassFactory factory) {
|
||||
if (factories.count(passID)) {
|
||||
// Error: Pass with this ID already registered
|
||||
// You might want to throw an exception or log an error
|
||||
return;
|
||||
}
|
||||
factories[passID] = std::move(factory);
|
||||
}
|
||||
|
||||
// 通过 Pass ID 创建一个 Pass 实例
|
||||
std::unique_ptr<Pass> createPass(void *passID) {
|
||||
auto it = factories.find(passID);
|
||||
if (it == factories.end()) {
|
||||
// Error: Pass with this ID not registered
|
||||
return nullptr;
|
||||
}
|
||||
return it->second(); // 调用工厂函数创建实例
|
||||
}
|
||||
|
||||
private:
|
||||
PassRegistry() = default; // 私有构造函数,实现单例
|
||||
~PassRegistry() = default;
|
||||
PassRegistry(const PassRegistry &) = delete; // 禁用拷贝构造
|
||||
PassRegistry &operator=(const PassRegistry &) = delete; // 禁用赋值操作
|
||||
|
||||
std::map<void *, PassFactory> factories;
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
// AnalysisManager: 负责管理和提供分析结果
|
||||
// ======================================================================
|
||||
class AnalysisManager {
|
||||
private:
|
||||
Module *pModuleRef; // 指向被分析的Module
|
||||
|
||||
// 缓存不同粒度的分析结果
|
||||
std::map<void *, std::unique_ptr<AnalysisResultBase>> moduleCachedResults;
|
||||
std::map<std::pair<Function *, void *>, std::unique_ptr<AnalysisResultBase>> functionCachedResults;
|
||||
std::map<std::pair<BasicBlock *, void *>, std::unique_ptr<AnalysisResultBase>> basicBlockCachedResults;
|
||||
|
||||
|
||||
public:
|
||||
// 构造函数接收 Module 指针
|
||||
AnalysisManager(Module *M) : pModuleRef(M) {}
|
||||
AnalysisManager() = delete; // 禁止无参构造
|
||||
|
||||
~AnalysisManager() = default;
|
||||
|
||||
// 获取分析结果的通用模板函数
|
||||
// T 是 AnalysisResult 的具体类型,E 是 AnalysisPass 的具体类型
|
||||
// F 和 BB 参数用于提供上下文,根据分析遍的粒度来使用
|
||||
template <typename T, typename E> T *getAnalysisResult(Function *F = nullptr, BasicBlock *BB = nullptr) {
|
||||
void *analysisID = E::ID; // 获取分析遍的唯一 ID
|
||||
|
||||
// 尝试从注册表创建分析遍实例
|
||||
std::unique_ptr<Pass> basePass = PassRegistry::getPassRegistry().createPass(analysisID);
|
||||
if (!basePass) {
|
||||
// Error: Analysis pass not registered
|
||||
std::cerr << "Error: Analysis pass with ID " << analysisID << " not registered.\n";
|
||||
return nullptr;
|
||||
}
|
||||
AnalysisPass *analysisPass = static_cast<AnalysisPass *>(basePass.get());
|
||||
|
||||
if(DEBUG){
|
||||
std::cout << "Running Analysis Pass: " << analysisPass->getName() << "\n";
|
||||
}
|
||||
// 根据分析遍的粒度处理
|
||||
switch (analysisPass->getGranularity()) {
|
||||
case Pass::Granularity::Module: {
|
||||
// 检查是否已存在有效结果
|
||||
auto it = moduleCachedResults.find(analysisID);
|
||||
if (it != moduleCachedResults.end()) {
|
||||
return static_cast<T *>(it->second.get()); // 返回缓存结果
|
||||
}
|
||||
// 运行模块级分析遍
|
||||
if (!pModuleRef) {
|
||||
std::cerr << "Error: Module reference not set for AnalysisManager to run Module Pass.\n";
|
||||
return nullptr;
|
||||
}
|
||||
analysisPass->runOnModule(pModuleRef, *this);
|
||||
// 获取结果并缓存
|
||||
std::unique_ptr<AnalysisResultBase> result = analysisPass->getResult();
|
||||
T *specificResult = static_cast<T *>(result.get());
|
||||
moduleCachedResults[analysisID] = std::move(result); // 缓存结果
|
||||
return specificResult;
|
||||
}
|
||||
case Pass::Granularity::Function: {
|
||||
// 检查请求的上下文是否正确
|
||||
if (!F) {
|
||||
std::cerr << "Error: Function context required for Function-level Analysis Pass.\n";
|
||||
return nullptr;
|
||||
}
|
||||
// 检查是否已存在有效结果
|
||||
auto it = functionCachedResults.find({F, analysisID});
|
||||
if (it != functionCachedResults.end()) {
|
||||
return static_cast<T *>(it->second.get()); // 返回缓存结果
|
||||
}
|
||||
// 运行函数级分析遍
|
||||
analysisPass->runOnFunction(F, *this);
|
||||
// 获取结果并缓存
|
||||
std::unique_ptr<AnalysisResultBase> result = analysisPass->getResult();
|
||||
T *specificResult = static_cast<T *>(result.get());
|
||||
functionCachedResults[{F, analysisID}] = std::move(result); // 缓存结果
|
||||
return specificResult;
|
||||
}
|
||||
case Pass::Granularity::BasicBlock: {
|
||||
// 检查请求的上下文是否正确
|
||||
if (!BB) {
|
||||
std::cerr << "Error: BasicBlock context required for BasicBlock-level Analysis Pass.\n";
|
||||
return nullptr;
|
||||
}
|
||||
// 检查是否已存在有效结果
|
||||
auto it = basicBlockCachedResults.find({BB, analysisID});
|
||||
if (it != basicBlockCachedResults.end()) {
|
||||
return static_cast<T *>(it->second.get()); // 返回缓存结果
|
||||
}
|
||||
// 运行基本块级分析遍
|
||||
analysisPass->runOnBasicBlock(BB, *this);
|
||||
// 获取结果并缓存
|
||||
std::unique_ptr<AnalysisResultBase> result = analysisPass->getResult();
|
||||
T *specificResult = static_cast<T *>(result.get());
|
||||
basicBlockCachedResults[{BB, analysisID}] = std::move(result); // 缓存结果
|
||||
return specificResult;
|
||||
}
|
||||
}
|
||||
return nullptr; // 不会到达这里
|
||||
}
|
||||
|
||||
// 使所有分析结果失效 (当 IR 被修改时调用)
|
||||
void invalidateAllAnalyses() {
|
||||
moduleCachedResults.clear();
|
||||
functionCachedResults.clear();
|
||||
basicBlockCachedResults.clear();
|
||||
}
|
||||
|
||||
// 使特定分析结果失效
|
||||
// void *analysisID: 要失效的分析的ID
|
||||
// Function *F: 如果是函数级分析,指定函数;如果是模块级或基本块级,则为nullptr (取决于调用方式)
|
||||
// BasicBlock *BB: 如果是基本块级分析,指定基本块;否则为nullptr
|
||||
void invalidateAnalysis(void *analysisID, Function *F = nullptr, BasicBlock *BB = nullptr) {
|
||||
if (BB) {
|
||||
// 使特定基本块的特定分析结果失效
|
||||
basicBlockCachedResults.erase({BB, analysisID});
|
||||
} else if (F) {
|
||||
// 使特定函数的特定分析结果失效 (也可能包含聚合的BasicBlock结果)
|
||||
functionCachedResults.erase({F, analysisID});
|
||||
// 遍历所有属于F的基本块,使其BasicBlockCache失效 (如果该分析是BasicBlock粒度的)
|
||||
// 这需要遍历F的所有基本块,效率较低,更推荐在BasicBlockPass的invalidateAnalysisUsage中精确指定
|
||||
// 或者在Function级别的invalidate时,清空该Function的所有BasicBlock分析
|
||||
// 这里的实现简单地清空该Function下所有该ID的BasicBlock缓存
|
||||
for (auto it = basicBlockCachedResults.begin(); it != basicBlockCachedResults.end(); ) {
|
||||
// 假设BasicBlock::getParent()方法存在,可以获取所属Function
|
||||
if (it->first.second == analysisID /* && it->first.first->getParent() == F */) { // 需要BasicBlock能获取其父函数
|
||||
it = basicBlockCachedResults.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// 使所有函数的特定分析结果失效 (Module级和所有Function/BasicBlock级)
|
||||
moduleCachedResults.erase(analysisID);
|
||||
for (auto it = functionCachedResults.begin(); it != functionCachedResults.end(); ) {
|
||||
if (it->first.second == analysisID) {
|
||||
it = functionCachedResults.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
for (auto it = basicBlockCachedResults.begin(); it != basicBlockCachedResults.end(); ) {
|
||||
if (it->first.second == analysisID) {
|
||||
it = basicBlockCachedResults.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
// PassManager:遍管理器
|
||||
// ======================================================================
|
||||
class PassManager {
|
||||
private:
|
||||
std::vector<std::unique_ptr<Pass>> passes;
|
||||
AnalysisManager analysisManager;
|
||||
Module *pmodule;
|
||||
IRBuilder *pBuilder;
|
||||
|
||||
public:
|
||||
PassManager() = default;
|
||||
~PassManager() = default;
|
||||
|
||||
PassManager(Module *module, IRBuilder *builder) : pmodule(module) ,pBuilder(builder), analysisManager(module) {}
|
||||
|
||||
// 运行所有注册的遍
|
||||
bool run();
|
||||
|
||||
// 运行优化管道主要负责注册和运行优化遍
|
||||
// 这里可以根据 optLevel 和 DEBUG 控制不同的优化遍
|
||||
void runOptimizationPipeline(Module* moduleIR, IRBuilder* builder, int optLevel);
|
||||
|
||||
// 添加遍:现在接受 Pass 的 ID,而不是直接的 unique_ptr
|
||||
void addPass(void *passID);
|
||||
|
||||
AnalysisManager &getAnalysisManager() { return analysisManager; }
|
||||
|
||||
void clearPasses();
|
||||
|
||||
// 输出pass列表并打印IR信息供观察优化遍效果
|
||||
void printPasses() const;
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
// 辅助宏或函数,用于简化 Pass 的注册
|
||||
// ======================================================================
|
||||
|
||||
// 用于分析遍的注册
|
||||
template <typename AnalysisPassType> void registerAnalysisPass();
|
||||
|
||||
// (1) 针对需要 IRBuilder 参数的优化遍的重载
|
||||
// 这个模板只在 OptimizationPassType 可以通过 IRBuilder* 构造时才有效
|
||||
template <typename OptimizationPassType, typename std::enable_if<
|
||||
std::is_constructible<OptimizationPassType, IRBuilder*>::value, int>::type = 0>
|
||||
void registerOptimizationPass(IRBuilder* builder);
|
||||
|
||||
// (2) 针对不需要 IRBuilder 参数的所有其他优化遍的重载
|
||||
// 这个模板只在 OptimizationPassType 不能通过 IRBuilder* 构造时才有效
|
||||
template <typename OptimizationPassType, typename std::enable_if<
|
||||
!std::is_constructible<OptimizationPassType, IRBuilder*>::value, int>::type = 0>
|
||||
void registerOptimizationPass();
|
||||
|
||||
} // namespace sysy
|
||||
@ -59,15 +59,43 @@ private:
|
||||
std::unique_ptr<Module> module;
|
||||
IRBuilder builder;
|
||||
|
||||
using ValueOrOperator = std::variant<Value*, int>;
|
||||
std::vector<ValueOrOperator> BinaryExpStack; ///< 用于存储二元表达式的中缀表达式
|
||||
std::vector<int> BinaryExpLenStack; ///< 用于存储该层次的二元表达式的长度
|
||||
// 下面是用于后缀表达式的计算的数据结构
|
||||
std::vector<ValueOrOperator> BinaryRPNStack; ///< 用于存储二元表达式的后缀表达式
|
||||
std::vector<int> BinaryOpStack; ///< 用于存储二元表达式中缀表达式转换到后缀表达式的操作符栈
|
||||
std::vector<Value *> BinaryValueStack; ///< 用于存储后缀表达式计算的操作数栈
|
||||
|
||||
// 约定操作符:
|
||||
// 1: 'ADD', 2: 'SUB', 3: 'MUL', 4: 'DIV', 5: '%', 6: 'PLUS', 7: 'NEG', 8: 'NOT', 9: 'LPAREN', 10: 'RPAREN'
|
||||
// 这里的操作符是为了方便后缀表达式的计算而设计
|
||||
// 其中,'ADD', 'SUB', 'MUL', 'DIV', '%'
|
||||
// 分别对应加法、减法、乘法、除法和取模
|
||||
// 'PLUS' 和 'NEG' 分别对应一元加法和一元减法
|
||||
// 'NOT' 对应逻辑非
|
||||
// 'LPAREN' 和 'RPAREN' 分别对应左括号和右括号
|
||||
enum BinaryOp {
|
||||
ADD = 1, SUB = 2, MUL = 3, DIV = 4, MOD = 5, PLUS = 6, NEG = 7, NOT = 8, LPAREN = 9, RPAREN = 10,
|
||||
};
|
||||
int getOperatorPrecedence(int op) {
|
||||
switch (op) {
|
||||
case MUL: case DIV: case MOD: return 2;
|
||||
case ADD: case SUB: return 1;
|
||||
case PLUS: case NEG: case NOT: return 3;
|
||||
case LPAREN: case RPAREN: return 0; // Parentheses have lowest precedence for stack logic
|
||||
default: return -1; // Unknown operator
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
SysYIRGenerator() = default;
|
||||
|
||||
bool HasReturnInst;
|
||||
|
||||
public:
|
||||
Module *get() const { return module.get(); }
|
||||
IRBuilder *getBuilder(){ return &builder; }
|
||||
public:
|
||||
|
||||
std::any visitCompUnit(SysYParser::CompUnitContext *ctx) override;
|
||||
|
||||
std::any visitGlobalConstDecl(SysYParser::GlobalConstDeclContext *ctx) override;
|
||||
@ -98,7 +126,7 @@ public:
|
||||
std::any visitBlockStmt(SysYParser::BlockStmtContext* ctx) override;
|
||||
// std::any visitStmt(SysYParser::StmtContext *ctx) override;
|
||||
std::any visitAssignStmt(SysYParser::AssignStmtContext *ctx) override;
|
||||
// std::any visitExpStmt(SysYParser::ExpStmtContext *ctx) override;
|
||||
std::any visitExpStmt(SysYParser::ExpStmtContext *ctx) override;
|
||||
// std::any visitBlkStmt(SysYParser::BlkStmtContext *ctx) override;
|
||||
std::any visitIfStmt(SysYParser::IfStmtContext *ctx) override;
|
||||
std::any visitWhileStmt(SysYParser::WhileStmtContext *ctx) override;
|
||||
@ -132,7 +160,20 @@ public:
|
||||
std::any visitLAndExp(SysYParser::LAndExpContext *ctx) override;
|
||||
std::any visitLOrExp(SysYParser::LOrExpContext *ctx) override;
|
||||
|
||||
// std::any visitConstExp(SysYParser::ConstExpContext *ctx) override;
|
||||
std::any visitConstExp(SysYParser::ConstExpContext *ctx) override;
|
||||
|
||||
bool isRightAssociative(int op);
|
||||
Value* promoteType(Value* value, Type* targetType);
|
||||
Value* computeExp(SysYParser::ExpContext *ctx, Type* targetType = nullptr);
|
||||
Value* computeAddExp(SysYParser::AddExpContext *ctx, Type* targetType = nullptr);
|
||||
void compute();
|
||||
public:
|
||||
// 获取GEP指令的地址
|
||||
Value* getGEPAddressInst(Value* basePointer, const std::vector<Value*>& indices);
|
||||
// 构建数组类型
|
||||
Type* buildArrayType(Type* baseType, const std::vector<Value*>& dims);
|
||||
|
||||
unsigned countArrayDimensions(Type* type);
|
||||
|
||||
|
||||
}; // class SysYIRGenerator
|
||||
@ -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
24
src/midend/CMakeLists.txt
Normal 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运行时库头文件
|
||||
)
|
||||
@ -49,6 +49,11 @@ auto Type::getFunctionType(Type *returnType, const std::vector<Type *> ¶mTyp
|
||||
return FunctionType::get(returnType, paramTypes);
|
||||
}
|
||||
|
||||
auto Type::getArrayType(Type *elementType, unsigned numElements) -> Type * {
|
||||
// forward to ArrayType
|
||||
return ArrayType::get(elementType, numElements);
|
||||
}
|
||||
|
||||
auto Type::getSize() const -> unsigned {
|
||||
switch (kind) {
|
||||
case kInt:
|
||||
@ -58,6 +63,10 @@ auto Type::getSize() const -> unsigned {
|
||||
case kPointer:
|
||||
case kFunction:
|
||||
return 8;
|
||||
case Kind::kArray: {
|
||||
const ArrayType* arrType = static_cast<const ArrayType*>(this);
|
||||
return arrType->getElementType()->getSize() * arrType->getNumElements();
|
||||
}
|
||||
case kVoid:
|
||||
return 0;
|
||||
}
|
||||
@ -95,6 +104,20 @@ FunctionType*FunctionType::get(Type *returnType, const std::vector<Type *> ¶
|
||||
return result.first->get();
|
||||
}
|
||||
|
||||
ArrayType *ArrayType::get(Type *elementType, unsigned numElements) {
|
||||
static std::set<std::unique_ptr<ArrayType>> arrayTypes;
|
||||
auto iter = std::find_if(arrayTypes.begin(), arrayTypes.end(), [&](const std::unique_ptr<ArrayType> &type) -> bool {
|
||||
return elementType == type->getElementType() && numElements == type->getNumElements();
|
||||
});
|
||||
if (iter != arrayTypes.end()) {
|
||||
return iter->get();
|
||||
}
|
||||
auto type = new ArrayType(elementType, numElements);
|
||||
assert(type);
|
||||
auto result = arrayTypes.emplace(type);
|
||||
return result.first->get();
|
||||
}
|
||||
|
||||
void Value::replaceAllUsesWith(Value *value) {
|
||||
for (auto &use : uses) {
|
||||
use->getUser()->setOperand(use->getIndex(), value);
|
||||
@ -204,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()) {
|
||||
@ -229,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()) {
|
||||
@ -399,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;
|
||||
@ -408,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;
|
||||
}
|
||||
@ -437,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;
|
||||
@ -456,53 +482,17 @@ 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;
|
||||
}
|
||||
|
||||
case Instruction::kLa: {
|
||||
auto oldLaInst = dynamic_cast<LaInst *>(inst);
|
||||
auto oldPointer = oldLaInst->getPointer();
|
||||
Value *newPointer;
|
||||
std::vector<Value *> newIndices;
|
||||
newPointer = oldNewValueMap.at(oldPointer);
|
||||
|
||||
for (const auto &index : oldLaInst->getIndices()) {
|
||||
newIndices.emplace_back(oldNewValueMap.at(index->getValue()));
|
||||
}
|
||||
ss << oldLaInst->getName() << suffix;
|
||||
auto newLaInst = new LaInst(newPointer, newIndices, oldNewBlockMap.at(oldLaInst->getParent()), ss.str());
|
||||
ss.str("");
|
||||
oldNewValueMap.emplace(oldLaInst, newLaInst);
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::kGetSubArray: {
|
||||
auto oldGetSubArrayInst = dynamic_cast<GetSubArrayInst *>(inst);
|
||||
auto oldFather = oldGetSubArrayInst->getFatherArray();
|
||||
auto oldChild = oldGetSubArrayInst->getChildArray();
|
||||
Value *newFather;
|
||||
Value *newChild;
|
||||
std::vector<Value *> newIndices;
|
||||
newFather = oldNewValueMap.at(oldFather);
|
||||
newChild = oldNewValueMap.at(oldChild);
|
||||
|
||||
for (const auto &index : oldGetSubArrayInst->getIndices()) {
|
||||
newIndices.emplace_back(oldNewValueMap.at(index->getValue()));
|
||||
}
|
||||
ss << oldGetSubArrayInst->getName() << suffix;
|
||||
auto newGetSubArrayInst =
|
||||
new GetSubArrayInst(dynamic_cast<LVal *>(newFather), dynamic_cast<LVal *>(newChild), newIndices,
|
||||
oldNewBlockMap.at(oldGetSubArrayInst->getParent()), ss.str());
|
||||
ss.str("");
|
||||
oldNewValueMap.emplace(oldGetSubArrayInst, newGetSubArrayInst);
|
||||
break;
|
||||
}
|
||||
// TODO:复制GEP指令
|
||||
|
||||
case Instruction::kMemset: {
|
||||
auto oldMemsetInst = dynamic_cast<MemsetInst *>(inst);
|
||||
@ -544,8 +534,14 @@ Function * Function::clone(const std::string &suffix) const {
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto ¶m : blocks.front()->getArguments()) {
|
||||
newFunction->getEntryBlock()->insertArgument(dynamic_cast<AllocaInst *>(oldNewValueMap.at(param)));
|
||||
// for (const auto ¶m : blocks.front()->getArguments()) {
|
||||
// newFunction->getEntryBlock()->insertArgument(dynamic_cast<AllocaInst *>(oldNewValueMap.at(param)));
|
||||
// }
|
||||
for (const auto &arg : arguments) {
|
||||
auto newArg = dynamic_cast<Argument *>(oldNewValueMap.at(arg));
|
||||
if (newArg != nullptr) {
|
||||
newFunction->insertArgument(newArg);
|
||||
}
|
||||
}
|
||||
|
||||
return newFunction;
|
||||
@ -573,15 +569,15 @@ void User::replaceOperand(unsigned index, Value *value) {
|
||||
* phi相关函数
|
||||
*/
|
||||
|
||||
Value* PhiInst::getvalfromBlk(BasicBlock* blk){
|
||||
refreshB2VMap();
|
||||
Value* PhiInst::getvalfromBlk(BasicBlock* blk) const {
|
||||
// refreshB2VMap();
|
||||
if( blk2val.find(blk) != blk2val.end()) {
|
||||
return blk2val.at(blk);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BasicBlock* PhiInst::getBlkfromVal(Value* val){
|
||||
BasicBlock* PhiInst::getBlkfromVal(Value* val) const {
|
||||
// 返回第一个值对应的基本块
|
||||
for(unsigned i = 0; i < vsize; i++) {
|
||||
if(getValue(i) == val) {
|
||||
@ -595,6 +591,9 @@ void PhiInst::delValue(Value* val){
|
||||
//根据value删除对应的基本块和值
|
||||
unsigned i = 0;
|
||||
BasicBlock* blk = getBlkfromVal(val);
|
||||
if(blk == nullptr) {
|
||||
return; // 如果val没有对应的基本块,直接返回
|
||||
}
|
||||
for(i = 0; i < vsize; i++) {
|
||||
if(getValue(i) == val) {
|
||||
break;
|
||||
@ -610,6 +609,9 @@ void PhiInst::delBlk(BasicBlock* blk){
|
||||
//根据Blk删除对应的基本块和值
|
||||
unsigned i = 0;
|
||||
Value* val = getvalfromBlk(blk);
|
||||
if(val == nullptr) {
|
||||
return; // 如果blk没有对应的值,直接返回
|
||||
}
|
||||
for(i = 0; i < vsize; i++) {
|
||||
if(getBlock(i) == blk) {
|
||||
break;
|
||||
@ -622,17 +624,22 @@ void PhiInst::delBlk(BasicBlock* blk){
|
||||
}
|
||||
|
||||
void PhiInst::replaceBlk(BasicBlock* newBlk, unsigned k){
|
||||
refreshB2VMap();
|
||||
Value* val = blk2val.at(getBlock(k));
|
||||
// refreshB2VMap();
|
||||
BasicBlock* oldBlk = getBlock(k);
|
||||
Value* val = blk2val.at(oldBlk);
|
||||
if(newBlk == oldBlk || oldBlk == nullptr) {
|
||||
return; // 如果新旧基本块相同,直接返回
|
||||
}
|
||||
// Value* val = blk2val.at(getBlock(k));
|
||||
// 替换基本块
|
||||
setOperand(2 * k + 1, newBlk);
|
||||
// 替换blk2val映射
|
||||
blk2val.erase(getBlock(k));
|
||||
blk2val.erase(oldBlk);
|
||||
blk2val.emplace(newBlk, val);
|
||||
}
|
||||
|
||||
void PhiInst::replaceold2new(BasicBlock* oldBlk, BasicBlock* newBlk){
|
||||
refreshB2VMap();
|
||||
// refreshB2VMap();
|
||||
Value* val = blk2val.at(oldBlk);
|
||||
// 替换基本块
|
||||
delBlk(oldBlk);
|
||||
@ -660,8 +667,9 @@ Function * CallInst::getCallee() const { return dynamic_cast<Function *>(getOper
|
||||
|
||||
/**
|
||||
* 获取变量指针
|
||||
* 如果在当前作用域或父作用域中找到变量,则返回该变量的指针,否则返回nullptr
|
||||
*/
|
||||
auto SymbolTable::getVariable(const std::string &name) const -> User * {
|
||||
auto SymbolTable::getVariable(const std::string &name) const -> Value * {
|
||||
auto node = curNode;
|
||||
while (node != nullptr) {
|
||||
auto iter = node->varList.find(name);
|
||||
@ -676,8 +684,8 @@ auto SymbolTable::getVariable(const std::string &name) const -> User * {
|
||||
/**
|
||||
* 添加变量到符号表
|
||||
*/
|
||||
auto SymbolTable::addVariable(const std::string &name, User *variable) -> User * {
|
||||
User *result = nullptr;
|
||||
auto SymbolTable::addVariable(const std::string &name, Value *variable) -> Value * {
|
||||
Value *result = nullptr;
|
||||
if (curNode != nullptr) {
|
||||
std::stringstream ss;
|
||||
auto iter = variableIndex.find(name);
|
||||
@ -696,7 +704,7 @@ auto SymbolTable::addVariable(const std::string &name, User *variable) -> User *
|
||||
if (global != nullptr) {
|
||||
globals.emplace_back(global);
|
||||
} else if (constvar != nullptr) {
|
||||
consts.emplace_back(constvar);
|
||||
globalconsts.emplace_back(constvar);
|
||||
}
|
||||
|
||||
result = variable;
|
||||
@ -711,7 +719,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; }
|
||||
/**
|
||||
* 进入新的作用域
|
||||
*/
|
||||
297
src/midend/Pass/Analysis/Dom.cpp
Normal file
297
src/midend/Pass/Analysis/Dom.cpp
Normal file
@ -0,0 +1,297 @@
|
||||
#include "Dom.h"
|
||||
#include <algorithm> // for std::set_intersection, std::set_difference, std::set_union
|
||||
#include <iostream> // for debug output
|
||||
#include <limits> // for std::numeric_limits
|
||||
#include <queue>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 初始化 支配树静态 ID
|
||||
void *DominatorTreeAnalysisPass::ID = (void *)&DominatorTreeAnalysisPass::ID;
|
||||
// ==============================================================
|
||||
// DominatorTree 结果类的实现
|
||||
// ==============================================================
|
||||
|
||||
DominatorTree::DominatorTree(Function *F) : AssociatedFunction(F) {
|
||||
// 构造时可以不计算,在分析遍运行里计算并填充
|
||||
}
|
||||
|
||||
const std::set<BasicBlock *> *DominatorTree::getDominators(BasicBlock *BB) const {
|
||||
auto it = Dominators.find(BB);
|
||||
if (it != Dominators.end()) {
|
||||
return &(it->second);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BasicBlock *DominatorTree::getImmediateDominator(BasicBlock *BB) const {
|
||||
auto it = IDoms.find(BB);
|
||||
if (it != IDoms.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::set<BasicBlock *> *DominatorTree::getDominanceFrontier(BasicBlock *BB) const {
|
||||
auto it = DominanceFrontiers.find(BB);
|
||||
if (it != DominanceFrontiers.end()) {
|
||||
return &(it->second);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// 辅助函数:打印 BasicBlock 集合
|
||||
void printBBSet(const std::string &prefix, const std::set<BasicBlock *> &s) {
|
||||
if (!DEBUG)
|
||||
return;
|
||||
std::cout << prefix << "{";
|
||||
bool first = true;
|
||||
for (const auto &bb : s) {
|
||||
if (!first)
|
||||
std::cout << ", ";
|
||||
std::cout << bb->getName();
|
||||
first = false;
|
||||
}
|
||||
std::cout << "}" << std::endl;
|
||||
}
|
||||
|
||||
void DominatorTree::computeDominators(Function *F) {
|
||||
if (DEBUG)
|
||||
std::cout << "--- Computing Dominators ---" << std::endl;
|
||||
|
||||
BasicBlock *entryBlock = F->getEntryBlock();
|
||||
std::vector<BasicBlock *> bbs_in_order; // 用于确定遍历顺序,如果需要的话
|
||||
|
||||
// 初始化:入口块只被自己支配,其他块被所有块支配
|
||||
for (const auto &bb_ptr : F->getBasicBlocks()) {
|
||||
BasicBlock *bb = bb_ptr.get();
|
||||
bbs_in_order.push_back(bb); // 收集所有块
|
||||
if (bb == entryBlock) {
|
||||
Dominators[bb].insert(bb);
|
||||
if (DEBUG)
|
||||
std::cout << "Init Dominators[" << bb->getName() << "]: {" << bb->getName() << "}" << std::endl;
|
||||
} else {
|
||||
for (const auto &all_bb_ptr : F->getBasicBlocks()) {
|
||||
Dominators[bb].insert(all_bb_ptr.get());
|
||||
}
|
||||
if (DEBUG) {
|
||||
std::cout << "Init Dominators[" << bb->getName() << "]: ";
|
||||
printBBSet("", Dominators[bb]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool changed = true;
|
||||
int iteration = 0;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
iteration++;
|
||||
if (DEBUG)
|
||||
std::cout << "Iteration " << iteration << std::endl;
|
||||
|
||||
// 确保遍历顺序一致性,例如可以按照DFS或BFS顺序,或者简单的迭代器顺序
|
||||
// 如果Function::getBasicBlocks()返回的迭代器顺序稳定,则无需bbs_in_order
|
||||
for (const auto &bb_ptr : F->getBasicBlocks()) { // 假设这个迭代器顺序稳定
|
||||
BasicBlock *bb = bb_ptr.get();
|
||||
if (bb == entryBlock)
|
||||
continue;
|
||||
|
||||
// 计算所有前驱的支配者集合的交集
|
||||
std::set<BasicBlock *> newDom;
|
||||
bool firstPredProcessed = false;
|
||||
|
||||
for (BasicBlock *pred : bb->getPredecessors()) {
|
||||
// 确保前驱的支配者集合已经计算过
|
||||
if (Dominators.count(pred)) {
|
||||
if (!firstPredProcessed) {
|
||||
newDom = Dominators[pred];
|
||||
firstPredProcessed = true;
|
||||
} else {
|
||||
std::set<BasicBlock *> intersection;
|
||||
std::set_intersection(newDom.begin(), newDom.end(), Dominators[pred].begin(), Dominators[pred].end(),
|
||||
std::inserter(intersection, intersection.begin()));
|
||||
newDom = intersection;
|
||||
}
|
||||
}
|
||||
}
|
||||
newDom.insert(bb); // BB 永远支配自己
|
||||
|
||||
if (newDom != Dominators[bb]) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Dominators[" << bb->getName() << "] changed from ";
|
||||
printBBSet("", Dominators[bb]);
|
||||
std::cout << " to ";
|
||||
printBBSet("", newDom);
|
||||
}
|
||||
Dominators[bb] = newDom;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DEBUG)
|
||||
std::cout << "--- Dominators Computation Finished ---" << std::endl;
|
||||
}
|
||||
|
||||
void DominatorTree::computeIDoms(Function *F) {
|
||||
if (DEBUG)
|
||||
std::cout << "--- Computing Immediate Dominators (IDoms) ---" << std::endl;
|
||||
|
||||
BasicBlock *entryBlock = F->getEntryBlock();
|
||||
IDoms[entryBlock] = nullptr; // 入口块没有即时支配者
|
||||
|
||||
// 遍历所有非入口块
|
||||
for (const auto &bb_ptr : F->getBasicBlocks()) {
|
||||
BasicBlock *bb = bb_ptr.get();
|
||||
if (bb == entryBlock)
|
||||
continue;
|
||||
|
||||
BasicBlock *currentIDom = nullptr;
|
||||
const std::set<BasicBlock *> *domsOfBB = getDominators(bb);
|
||||
if (!domsOfBB) {
|
||||
if (DEBUG)
|
||||
std::cerr << "Warning: Dominators for " << bb->getName() << " not found!" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 遍历bb的所有严格支配者 D (即 bb 的支配者中除了 bb 自身)
|
||||
for (BasicBlock *D_candidate : *domsOfBB) {
|
||||
if (D_candidate == bb)
|
||||
continue; // 跳过bb自身
|
||||
|
||||
bool D_candidate_is_IDom = true;
|
||||
// 检查是否存在另一个块 X,使得 D_candidate 严格支配 X 且 X 严格支配 bb
|
||||
// 或者更直接的,检查 D_candidate 是否被 bb 的所有其他严格支配者所支配
|
||||
for (BasicBlock *X_other_dom : *domsOfBB) {
|
||||
if (X_other_dom == bb || X_other_dom == D_candidate)
|
||||
continue; // 跳过bb自身和D_candidate
|
||||
|
||||
// 如果 X_other_dom 严格支配 bb (它在 domsOfBB 中且不是bb自身)
|
||||
// 并且 X_other_dom 不被 D_candidate 支配,那么 D_candidate 就不是 IDom
|
||||
const std::set<BasicBlock *> *domsOfX_other_dom = getDominators(X_other_dom);
|
||||
if (domsOfX_other_dom && domsOfX_other_dom->count(D_candidate)) { // X_other_dom 支配 D_candidate
|
||||
// D_candidate 被另一个支配者 X_other_dom 支配
|
||||
// 这说明 D_candidate 位于 X_other_dom 的“下方”,X_other_dom 更接近 bb
|
||||
// 因此 D_candidate 不是 IDom
|
||||
D_candidate_is_IDom = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (D_candidate_is_IDom) {
|
||||
currentIDom = D_candidate;
|
||||
break; // 找到即时支配者,可以退出循环,因为它是唯一的
|
||||
}
|
||||
}
|
||||
IDoms[bb] = currentIDom;
|
||||
if (DEBUG) {
|
||||
std::cout << " IDom[" << bb->getName() << "] = " << (currentIDom ? currentIDom->getName() : "nullptr")
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
if (DEBUG)
|
||||
std::cout << "--- Immediate Dominators Computation Finished ---" << std::endl;
|
||||
}
|
||||
|
||||
/*
|
||||
for each node n in a postorder traversal of the dominator tree:
|
||||
df[n] = empty set
|
||||
// compute DF_local(n)
|
||||
for each child y of n in the CFG:
|
||||
if idom[y] != n:
|
||||
df[n] = df[n] U {y}
|
||||
// compute DF_up(n)
|
||||
for each child c of n in the dominator tree:
|
||||
for each element w in df[c]:
|
||||
if idom[w] != n:
|
||||
df[n] = df[n] U {w}
|
||||
*/
|
||||
|
||||
void DominatorTree::computeDominanceFrontiers(Function *F) {
|
||||
if (DEBUG)
|
||||
std::cout << "--- Computing Dominance Frontiers ---" << std::endl;
|
||||
|
||||
for (const auto &bb_ptr_X : F->getBasicBlocks()) {
|
||||
BasicBlock *X = bb_ptr_X.get();
|
||||
DominanceFrontiers[X].clear();
|
||||
|
||||
// 遍历所有可能的 Z (X支配Z,或者Z就是X)
|
||||
for (const auto &bb_ptr_Z : F->getBasicBlocks()) {
|
||||
BasicBlock *Z = bb_ptr_Z.get();
|
||||
const std::set<BasicBlock *> *domsOfZ = getDominators(Z);
|
||||
|
||||
// 如果 X 不支配 Z,则 Z 与 DF(X) 无关
|
||||
if (!domsOfZ || domsOfZ->find(X) == domsOfZ->end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 遍历 Z 的所有后继 Y
|
||||
for (BasicBlock *Y : Z->getSuccessors()) {
|
||||
// 如果 Y 不被 X 严格支配,则 Y 在 DF(X) 中
|
||||
// Y 不被 X 严格支配意味着 (Y不被X支配) 或 (Y就是X)
|
||||
const std::set<BasicBlock *> *domsOfY = getDominators(Y);
|
||||
if (Y == X || (domsOfY && domsOfY->find(X) == domsOfY->end())) {
|
||||
DominanceFrontiers[X].insert(Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DEBUG) {
|
||||
std::cout << " DF(" << X->getName() << "): ";
|
||||
printBBSet("", DominanceFrontiers[X]);
|
||||
}
|
||||
}
|
||||
if (DEBUG)
|
||||
std::cout << "--- Dominance Frontiers Computation Finished ---" << std::endl;
|
||||
}
|
||||
|
||||
void DominatorTree::computeDominatorTreeChildren(Function *F) {
|
||||
if (DEBUG)
|
||||
std::cout << "--- Computing Dominator Tree Children ---" << std::endl;
|
||||
// 首先清空,确保重新计算时是空的
|
||||
for (auto &bb_ptr : F->getBasicBlocks()) {
|
||||
DominatorTreeChildren[bb_ptr.get()].clear();
|
||||
}
|
||||
|
||||
for (auto &bb_ptr : F->getBasicBlocks()) {
|
||||
BasicBlock *B = bb_ptr.get();
|
||||
BasicBlock *A = getImmediateDominator(B); // A 是 B 的即时支配者
|
||||
|
||||
if (A) { // 如果 B 有即时支配者 A (即 B 不是入口块)
|
||||
DominatorTreeChildren[A].insert(B);
|
||||
if (DEBUG) {
|
||||
std::cout << " " << B->getName() << " is child of " << A->getName() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DEBUG)
|
||||
std::cout << "--- Dominator Tree Children Computation Finished ---" << std::endl;
|
||||
}
|
||||
|
||||
// ==============================================================
|
||||
// DominatorTreeAnalysisPass 的实现
|
||||
// ==============================================================
|
||||
|
||||
bool DominatorTreeAnalysisPass::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
// 每次运行时清空旧数据,确保重新计算
|
||||
CurrentDominatorTree = std::make_unique<DominatorTree>(F);
|
||||
// 不需要手动清空map,unique_ptr会创建新的DominatorTree对象,其map是空的
|
||||
|
||||
CurrentDominatorTree->computeDominators(F);
|
||||
CurrentDominatorTree->computeIDoms(F); // 修正后的IDoms算法
|
||||
CurrentDominatorTree->computeDominanceFrontiers(F);
|
||||
CurrentDominatorTree->computeDominatorTreeChildren(F);
|
||||
return false; // 分析遍通常返回 false,表示不修改 IR
|
||||
}
|
||||
|
||||
std::unique_ptr<AnalysisResultBase> DominatorTreeAnalysisPass::getResult() {
|
||||
// 返回计算好的 DominatorTree 实例,所有权转移给 AnalysisManager
|
||||
return std::move(CurrentDominatorTree);
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
160
src/midend/Pass/Analysis/Liveness.cpp
Normal file
160
src/midend/Pass/Analysis/Liveness.cpp
Normal file
@ -0,0 +1,160 @@
|
||||
#include "Liveness.h"
|
||||
#include <algorithm> // For std::set_union, std::set_difference
|
||||
#include <iostream>
|
||||
#include <queue> // Potentially for worklist, though not strictly needed for the iterative approach below
|
||||
#include <set> // For std::set
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 初始化静态 ID
|
||||
void *LivenessAnalysisPass::ID = (void *)&LivenessAnalysisPass::ID;
|
||||
// ==============================================================
|
||||
// LivenessAnalysisResult 结果类的实现
|
||||
// ==============================================================
|
||||
|
||||
const std::set<Value *> *LivenessAnalysisResult::getLiveIn(BasicBlock *BB) const {
|
||||
auto it = liveInSets.find(BB);
|
||||
if (it != liveInSets.end()) {
|
||||
return &(it->second);
|
||||
}
|
||||
// 返回一个空集合,表示未找到或不存在
|
||||
static const std::set<Value *> emptySet;
|
||||
return &emptySet;
|
||||
}
|
||||
|
||||
const std::set<Value *> *LivenessAnalysisResult::getLiveOut(BasicBlock *BB) const {
|
||||
auto it = liveOutSets.find(BB);
|
||||
if (it != liveOutSets.end()) {
|
||||
return &(it->second);
|
||||
}
|
||||
static const std::set<Value *> emptySet;
|
||||
return &emptySet;
|
||||
}
|
||||
|
||||
void LivenessAnalysisResult::computeDefUse(BasicBlock *BB, std::set<Value *> &def, std::set<Value *> &use) {
|
||||
def.clear(); // 将持有在 BB 中定义的值
|
||||
use.clear(); // 将持有在 BB 中使用但在其定义之前的值
|
||||
|
||||
// 临时集合,用于跟踪当前基本块中已经定义过的变量
|
||||
std::set<Value *> defined_in_block_so_far;
|
||||
|
||||
// 按照指令在块中的顺序遍历
|
||||
for (const auto &inst_ptr : BB->getInstructions()) {
|
||||
Instruction *inst = inst_ptr.get();
|
||||
|
||||
// 1. 处理指令的操作数 (Use) - 在定义之前的使用
|
||||
for (const auto &use_ptr : inst->getOperands()) { // 修正迭代器类型
|
||||
Value *operand = use_ptr->getValue(); // 从 shared_ptr<Use> 获取 Value*
|
||||
|
||||
// 过滤掉常量和全局变量,因为它们通常不被视为活跃变量
|
||||
ConstantValue *constValue = dynamic_cast<ConstantValue *>(operand);
|
||||
GlobalValue *globalValue = dynamic_cast<GlobalValue *>(operand);
|
||||
if (constValue || globalValue) {
|
||||
continue; // 跳过常量和全局变量
|
||||
}
|
||||
|
||||
// 如果操作数是一个变量(Instruction 或 Argument),并且它在此基本块的当前点之前尚未被定义
|
||||
if (defined_in_block_so_far.find(operand) == defined_in_block_so_far.end()) {
|
||||
use.insert(operand);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 处理指令自身产生的定义 (Def)
|
||||
if (inst->isDefine()) { // 使用 isDefine() 方法
|
||||
// 指令自身定义了一个值。将其添加到块的 def 集合,
|
||||
// 并添加到当前块中已定义的值的临时集合。
|
||||
def.insert(inst); // inst 本身就是被定义的值(例如,虚拟寄存器)
|
||||
defined_in_block_so_far.insert(inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LivenessAnalysisResult::computeLiveness(Function *F) {
|
||||
// 每次计算前清空旧结果
|
||||
liveInSets.clear(); // 直接清空 map,不再使用 F 作为键
|
||||
liveOutSets.clear(); // 直接清空 map
|
||||
|
||||
// 初始化所有基本块的 LiveIn 和 LiveOut 集合为空
|
||||
for (const auto &bb_ptr : F->getBasicBlocks()) {
|
||||
BasicBlock *bb = bb_ptr.get();
|
||||
liveInSets[bb] = {}; // 直接以 bb 为键
|
||||
liveOutSets[bb] = {}; // 直接以 bb 为键
|
||||
}
|
||||
|
||||
bool changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
|
||||
// TODO : 目前为逆序遍历基本块,考虑反向拓扑序遍历基本块
|
||||
|
||||
// 逆序遍历基本块
|
||||
// std::list<std::unique_ptr<BasicBlock>> basicBlocks(F->getBasicBlocks().begin(), F->getBasicBlocks().end());
|
||||
// std::reverse(basicBlocks.begin(), basicBlocks.end());
|
||||
// 然后遍历 basicBlocks
|
||||
// 创建一个 BasicBlock* 的列表来存储指针,避免拷贝 unique_ptr
|
||||
// Option 1: Using std::vector<BasicBlock*> (preferred for performance with reverse)
|
||||
std::vector<BasicBlock*> basicBlocksPointers;
|
||||
for (const auto& bb_ptr : F->getBasicBlocks()) {
|
||||
basicBlocksPointers.push_back(bb_ptr.get());
|
||||
}
|
||||
std::reverse(basicBlocksPointers.begin(), basicBlocksPointers.end());
|
||||
|
||||
for (auto bb_iter = basicBlocksPointers.begin(); bb_iter != basicBlocksPointers.end(); ++bb_iter) {
|
||||
BasicBlock *bb = *bb_iter; // 获取 BasicBlock 指针
|
||||
if (!bb)
|
||||
continue; // 避免空指针
|
||||
|
||||
std::set<Value *> oldLiveIn = liveInSets[bb];
|
||||
std::set<Value *> oldLiveOut = liveOutSets[bb];
|
||||
|
||||
// 1. 计算 LiveOut(BB) = Union(LiveIn(Succ) for Succ in Successors(BB))
|
||||
std::set<Value *> newLiveOut;
|
||||
for (BasicBlock *succ : bb->getSuccessors()) {
|
||||
const std::set<Value *> *succLiveIn = getLiveIn(succ); // 获取后继的 LiveIn
|
||||
if (succLiveIn) {
|
||||
newLiveOut.insert(succLiveIn->begin(), succLiveIn->end());
|
||||
}
|
||||
}
|
||||
liveOutSets[bb] = newLiveOut;
|
||||
|
||||
// 2. 计算 LiveIn(BB) = Use(BB) Union (LiveOut(BB) - Def(BB))
|
||||
std::set<Value *> defSet, useSet;
|
||||
computeDefUse(bb, defSet, useSet); // 计算当前块的 Def 和 Use
|
||||
|
||||
std::set<Value *> liveOutMinusDef;
|
||||
std::set_difference(newLiveOut.begin(), newLiveOut.end(), defSet.begin(), defSet.end(),
|
||||
std::inserter(liveOutMinusDef, liveOutMinusDef.begin()));
|
||||
|
||||
std::set<Value *> newLiveIn = useSet;
|
||||
newLiveIn.insert(liveOutMinusDef.begin(), liveOutMinusDef.end());
|
||||
liveInSets[bb] = newLiveIn;
|
||||
|
||||
// 检查是否发生变化
|
||||
if (oldLiveIn != newLiveIn || oldLiveOut != newLiveOut) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================================================
|
||||
// LivenessAnalysisPass 的实现
|
||||
// ==============================================================
|
||||
|
||||
bool LivenessAnalysisPass::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
// 每次运行创建一个新的 LivenessAnalysisResult 对象来存储结果
|
||||
CurrentLivenessResult = std::make_unique<LivenessAnalysisResult>(F);
|
||||
|
||||
// 调用 LivenessAnalysisResult 内部的方法来计算分析结果
|
||||
CurrentLivenessResult->computeLiveness(F);
|
||||
|
||||
// 分析遍通常不修改 IR,所以返回 false
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<AnalysisResultBase> LivenessAnalysisPass::getResult() {
|
||||
// 返回计算好的 LivenessAnalysisResult 实例,所有权转移给 AnalysisManager
|
||||
return std::move(CurrentLivenessResult);
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
138
src/midend/Pass/Optimize/DCE.cpp
Normal file
138
src/midend/Pass/Optimize/DCE.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
#include "DCE.h" // 包含DCE遍的头文件
|
||||
#include "IR.h" // 包含IR相关的定义
|
||||
#include "SysYIROptUtils.h" // 包含SysY IR优化工具类的定义
|
||||
#include <cassert> // 用于断言
|
||||
#include <iostream> // 用于调试输出
|
||||
#include <set> // 包含set,虽然DCEContext内部用unordered_set,但这里保留
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// DCE 遍的静态 ID
|
||||
void *DCE::ID = (void *)&DCE::ID;
|
||||
|
||||
// ======================================================================
|
||||
// DCEContext 类的实现
|
||||
// 封装了 DCE 遍的核心逻辑和状态,确保每次函数优化运行时状态独立
|
||||
// ======================================================================
|
||||
|
||||
// DCEContext 的 run 方法实现
|
||||
void DCEContext::run(Function *func, AnalysisManager *AM, bool &changed) {
|
||||
// 清空活跃指令集合,确保每次运行都是新的状态
|
||||
alive_insts.clear();
|
||||
|
||||
// 第一次遍历:扫描所有指令,识别“天然活跃”的指令并将其及其依赖标记为活跃
|
||||
// 使用 func->getBasicBlocks() 获取基本块列表,保留用户风格
|
||||
auto basicBlocks = func->getBasicBlocks();
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
// 确保基本块有效
|
||||
if (!basicBlock)
|
||||
continue;
|
||||
// 使用 basicBlock->getInstructions() 获取指令列表,保留用户风格
|
||||
for (auto &inst : basicBlock->getInstructions()) {
|
||||
// 确保指令有效
|
||||
if (!inst)
|
||||
continue;
|
||||
// 调用 DCEContext 自身的 isAlive 和 addAlive 方法
|
||||
if (isAlive(inst.get())) {
|
||||
addAlive(inst.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 第二次遍历:删除所有未被标记为活跃的指令。
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
if (!basicBlock)
|
||||
continue;
|
||||
// 使用传统的迭代器循环,并手动管理迭代器,
|
||||
// 以便在删除元素后正确前进。保留用户风格
|
||||
for (auto instIter = basicBlock->getInstructions().begin(); instIter != basicBlock->getInstructions().end();) {
|
||||
auto &inst = *instIter;
|
||||
Instruction *currentInst = inst.get();
|
||||
// 如果指令不在活跃集合中,则删除它。
|
||||
// 分支和返回指令由 isAlive 处理,并会被保留。
|
||||
if (alive_insts.count(currentInst) == 0) {
|
||||
instIter = SysYIROptUtils::usedelete(instIter); // 删除后返回下一个迭代器
|
||||
changed = true; // 标记 IR 已被修改
|
||||
} else {
|
||||
++instIter; // 指令活跃,移动到下一个
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 判断指令是否是“天然活跃”的实现
|
||||
// 只有具有副作用的指令(如存储、函数调用、原子操作)
|
||||
// 和控制流指令(如分支、返回)是天然活跃的。
|
||||
bool DCEContext::isAlive(Instruction *inst) {
|
||||
// TODO: 后续程序并发考虑原子操作
|
||||
// 其结果不被其他指令使用的指令(例如 StoreInst, BranchInst, ReturnInst)。
|
||||
// dynamic_cast<ir::CallInst>(inst) 检查是否是函数调用指令,
|
||||
// 函数调用通常有副作用。
|
||||
// 终止指令 (BranchInst, ReturnInst) 必须是活跃的,因为它控制了程序的执行流程。
|
||||
// 保留用户提供的 isAlive 逻辑
|
||||
bool isBranchOrReturn = inst->isBranch() || inst->isReturn();
|
||||
bool isCall = inst->isCall();
|
||||
bool isStoreOrMemset = inst->isStore() || inst->isMemset();
|
||||
return isBranchOrReturn || isCall || isStoreOrMemset;
|
||||
}
|
||||
|
||||
// 递归地将活跃指令及其依赖加入到 alive_insts 集合中
|
||||
void DCEContext::addAlive(Instruction *inst) {
|
||||
// 如果指令已经存在于活跃集合中,则无需重复处理
|
||||
if (alive_insts.count(inst) > 0) {
|
||||
return;
|
||||
}
|
||||
// 将当前指令标记为活跃
|
||||
alive_insts.insert(inst);
|
||||
// 遍历当前指令的所有操作数
|
||||
// 保留用户提供的 getOperands() 和 getValue()
|
||||
for (auto operand : inst->getOperands()) {
|
||||
// 如果操作数是一个指令(即它是一个值的定义),
|
||||
// 并且它还没有被标记为活跃
|
||||
if (auto opInst = dynamic_cast<Instruction *>(operand->getValue())) {
|
||||
addAlive(opInst); // 递归地将操作数指令标记为活跃
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// DCE Pass 类的实现
|
||||
// 主要负责与 PassManager 交互,创建 DCEContext 实例并运行优化
|
||||
// ======================================================================
|
||||
|
||||
// DCE 遍的 runOnFunction 方法实现
|
||||
bool DCE::runOnFunction(Function *func, AnalysisManager &AM) {
|
||||
|
||||
DCEContext ctx;
|
||||
bool changed = false;
|
||||
ctx.run(func, &AM, changed); // 运行 DCE 优化
|
||||
|
||||
// 如果 IR 被修改,则使相关的分析结果失效
|
||||
if (changed) {
|
||||
// DCE 会删除指令,这会影响数据流分析,尤其是活跃性分析。
|
||||
// 如果删除导致基本块变空,也可能间接影响 CFG 和支配树。
|
||||
// AM.invalidateAnalysis(&LivenessAnalysisPass::ID, func); // 活跃性分析失效
|
||||
// AM.invalidateAnalysis(&DominatorTreeAnalysisPass::ID, func); // 支配树分析可能失效
|
||||
// 其他所有依赖于数据流或 IR 结构的分析都可能失效。
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
// 声明DCE遍的分析依赖和失效信息
|
||||
void DCE::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
|
||||
// DCE不依赖特定的分析结果,它通过遍历和副作用判断来工作。
|
||||
|
||||
// DCE会删除指令,这会影响许多分析结果。
|
||||
// 至少,它会影响活跃性分析、支配树、控制流图(如果删除导致基本块为空并被合并)。
|
||||
// 假设存在LivenessAnalysisPass和DominatorTreeAnalysisPass
|
||||
// analysisInvalidations.insert(&LivenessAnalysisPass::ID);
|
||||
// analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID);
|
||||
// 任何改变IR结构的优化,都可能导致通用分析(如活跃性、支配树、循环信息)失效。
|
||||
// 最保守的做法是使所有函数粒度的分析失效,或者只声明你明确知道会受影响的分析。
|
||||
// 考虑到这个DCE仅删除指令,如果它不删除基本块,CFG可能不变,但数据流分析会失效。
|
||||
// 对于更激进的DCE(如ADCE),CFG也会改变。
|
||||
// 这里我们假设它主要影响数据流分析,并且可能间接影响CFG相关分析。
|
||||
// 如果有SideEffectInfo,它也可能被修改,但通常SideEffectInfo是静态的,不因DCE而变。
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
428
src/midend/Pass/Optimize/Mem2Reg.cpp
Normal file
428
src/midend/Pass/Optimize/Mem2Reg.cpp
Normal file
@ -0,0 +1,428 @@
|
||||
#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(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 指令
|
||||
// 移除了 AllocaInst *currentAlloca 参数,因为这个函数是为整个基本块处理所有可提升的 Alloca
|
||||
void Mem2RegContext::renameVariables(BasicBlock *currentBB) {
|
||||
// 1. 在函数开始时,记录每个 promotableAlloca 的当前栈深度。
|
||||
// 这将用于在函数返回时精确地回溯栈状态。
|
||||
std::map<AllocaInst *, size_t> originalStackSizes;
|
||||
for (auto alloca : promotableAllocas) {
|
||||
originalStackSizes[alloca] = allocaToValueStackMap[alloca].size();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 处理当前基本块的指令
|
||||
// --------------------------------------------------------------------
|
||||
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);
|
||||
if (DEBUG) {
|
||||
std::cout << "Mem2Reg: Pushed Phi " << (phiInst->getName().empty() ? "anonymous" : phiInst->getName()) << " for alloca " << alloca->getName()
|
||||
<< ". Stack size: " << allocaToValueStackMap[alloca].size() << std::endl;
|
||||
}
|
||||
break; // 找到对应的 alloca,处理下一个指令
|
||||
}
|
||||
}
|
||||
}
|
||||
// 处理 LoadInst
|
||||
else if (auto loadInst = dynamic_cast<LoadInst *>(inst)) {
|
||||
for (auto alloca : promotableAllocas) {
|
||||
// 检查 LoadInst 的指针是否直接是 alloca,或者是指向 alloca 的 GEP
|
||||
Value *ptrOperand = loadInst->getPointer();
|
||||
if (ptrOperand == alloca || (dynamic_cast<GetElementPtrInst *>(ptrOperand) &&
|
||||
dynamic_cast<GetElementPtrInst *>(ptrOperand)->getBasePointer() == alloca)) {
|
||||
assert(!allocaToValueStackMap[alloca].empty() && "Value stack empty for alloca during load replacement!");
|
||||
if (DEBUG) {
|
||||
std::cout << "Mem2Reg: Replacing load "
|
||||
<< (ptrOperand->getName().empty() ? "anonymous" : ptrOperand->getName()) << " with SSA value "
|
||||
<< (allocaToValueStackMap[alloca].top()->getName().empty()
|
||||
? "anonymous"
|
||||
: allocaToValueStackMap[alloca].top()->getName())
|
||||
<< " for alloca " << alloca->getName() << std::endl;
|
||||
std::cout << "Mem2Reg: allocaToValueStackMap[" << alloca->getName()
|
||||
<< "] size: " << allocaToValueStackMap[alloca].size() << std::endl;
|
||||
}
|
||||
loadInst->replaceAllUsesWith(allocaToValueStackMap[alloca].top());
|
||||
instIter = SysYIROptUtils::usedelete(instIter);
|
||||
instDeleted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 处理 StoreInst
|
||||
else if (auto storeInst = dynamic_cast<StoreInst *>(inst)) {
|
||||
for (auto alloca : promotableAllocas) {
|
||||
// 检查 StoreInst 的指针是否直接是 alloca,或者是指向 alloca 的 GEP
|
||||
Value *ptrOperand = storeInst->getPointer();
|
||||
if (ptrOperand == alloca || (dynamic_cast<GetElementPtrInst *>(ptrOperand) &&
|
||||
dynamic_cast<GetElementPtrInst *>(ptrOperand)->getBasePointer() == alloca)) {
|
||||
if (DEBUG) {
|
||||
std::cout << "Mem2Reg: Replacing store to "
|
||||
<< (ptrOperand->getName().empty() ? "anonymous" : ptrOperand->getName()) << " with SSA value "
|
||||
<< (storeInst->getValue()->getName().empty() ? "anonymous" : storeInst->getValue()->getName())
|
||||
<< " for alloca " << alloca->getName() << std::endl;
|
||||
std::cout << "Mem2Reg: allocaToValueStackMap[" << alloca->getName()
|
||||
<< "] size before push: " << allocaToValueStackMap[alloca].size() << std::endl;
|
||||
}
|
||||
allocaToValueStackMap[alloca].push(storeInst->getValue());
|
||||
instIter = SysYIROptUtils::usedelete(instIter);
|
||||
instDeleted = true;
|
||||
if (DEBUG) {
|
||||
std::cout << "Mem2Reg: allocaToValueStackMap[" << alloca->getName()
|
||||
<< "] size after push: " << allocaToValueStackMap[alloca].size() << 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);
|
||||
if (DEBUG) {
|
||||
std::cout << "Mem2Reg: Added incoming arg to Phi "
|
||||
<< (phiInst->getName().empty() ? "anonymous" : phiInst->getName()) << " from "
|
||||
<< currentBB->getName() << " with value "
|
||||
<< (allocaToValueStackMap[alloca].top()->getName().empty()
|
||||
? "anonymous"
|
||||
: allocaToValueStackMap[alloca].top()->getName())
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// --------------------------------------------------------------------
|
||||
// 递归访问支配树的子节点
|
||||
// --------------------------------------------------------------------
|
||||
const std::set<BasicBlock *> *dominatedBlocks = dt->getDominatorTreeChildren(currentBB);
|
||||
if (dominatedBlocks) { // 检查是否存在子节点
|
||||
if(DEBUG){
|
||||
std::cout << "Mem2Reg: Processing dominated blocks for " << currentBB->getName() << std::endl;
|
||||
for (auto dominatedBB : *dominatedBlocks) {
|
||||
std::cout << "Mem2Reg: Dominated block: " << (dominatedBB ? dominatedBB->getName() : "null") << std::endl;
|
||||
}
|
||||
}
|
||||
for (auto dominatedBB : *dominatedBlocks) {
|
||||
if (dominatedBB) { // 确保子块有效
|
||||
if (DEBUG) {
|
||||
std::cout << "Mem2Reg: Recursively renaming variables in dominated block: " << dominatedBB->getName()
|
||||
<< std::endl;
|
||||
}
|
||||
renameVariables(dominatedBB); // 递归调用,不再传递 currentAlloca
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 退出基本块时,弹出在此块中压入值栈的 SSA 值,恢复栈到进入该块时的状态
|
||||
// --------------------------------------------------------------------
|
||||
for (auto alloca : promotableAllocas) {
|
||||
while (allocaToValueStackMap[alloca].size() > originalStackSizes[alloca]) {
|
||||
if (DEBUG) {
|
||||
std::cout << "Mem2Reg: Popping value "
|
||||
<< (allocaToValueStackMap[alloca].top()->getName().empty()
|
||||
? "anonymous"
|
||||
: allocaToValueStackMap[alloca].top()->getName())
|
||||
<< " for alloca " << alloca->getName() << ". Stack size: " << allocaToValueStackMap[alloca].size()
|
||||
<< " -> " << (allocaToValueStackMap[alloca].size() - 1) << std::endl;
|
||||
}
|
||||
allocaToValueStackMap[alloca].pop();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 删除所有原始的 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
|
||||
288
src/midend/Pass/Optimize/Reg2Mem.cpp
Normal file
288
src/midend/Pass/Optimize/Reg2Mem.cpp
Normal 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
|
||||
880
src/midend/Pass/Optimize/SCCP.cpp
Normal file
880
src/midend/Pass/Optimize/SCCP.cpp
Normal 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 返回 pair,second 为 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
|
||||
706
src/midend/Pass/Optimize/SysYIRCFGOpt.cpp
Normal file
706
src/midend/Pass/Optimize/SysYIRCFGOpt.cpp
Normal file
@ -0,0 +1,706 @@
|
||||
#include "SysYIRCFGOpt.h"
|
||||
#include "SysYIROptUtils.h"
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <queue> // 引入队列,SysYDelNoPreBLock需要
|
||||
#include <string>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 定义静态ID
|
||||
void *SysYDelInstAfterBrPass::ID = (void *)&SysYDelInstAfterBrPass::ID;
|
||||
void *SysYDelEmptyBlockPass::ID = (void *)&SysYDelEmptyBlockPass::ID;
|
||||
void *SysYDelNoPreBLockPass::ID = (void *)&SysYDelNoPreBLockPass::ID;
|
||||
void *SysYBlockMergePass::ID = (void *)&SysYBlockMergePass::ID;
|
||||
void *SysYAddReturnPass::ID = (void *)&SysYAddReturnPass::ID;
|
||||
void *SysYCondBr2BrPass::ID = (void *)&SysYCondBr2BrPass::ID;
|
||||
|
||||
// ======================================================================
|
||||
// SysYCFGOptUtils: 辅助工具类,包含实际的CFG优化逻辑
|
||||
// ======================================================================
|
||||
|
||||
// 删除br后的无用指令
|
||||
bool SysYCFGOptUtils::SysYDelInstAfterBr(Function *func) {
|
||||
bool changed = false;
|
||||
|
||||
auto basicBlocks = func->getBasicBlocks();
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
bool Branch = false;
|
||||
auto &instructions = basicBlock->getInstructions();
|
||||
auto Branchiter = instructions.end();
|
||||
for (auto iter = instructions.begin(); iter != instructions.end(); ++iter) {
|
||||
if ((*iter)->isTerminator()) {
|
||||
Branch = true;
|
||||
Branchiter = iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Branchiter != instructions.end())
|
||||
++Branchiter;
|
||||
while (Branchiter != instructions.end()) {
|
||||
changed = true;
|
||||
Branchiter = instructions.erase(Branchiter);
|
||||
}
|
||||
|
||||
if (Branch) { // 更新前驱后继关系
|
||||
auto thelastinstinst = basicBlock->terminator();
|
||||
auto &Successors = basicBlock->getSuccessors();
|
||||
for (auto iterSucc = Successors.begin(); iterSucc != Successors.end();) {
|
||||
(*iterSucc)->removePredecessor(basicBlock.get());
|
||||
basicBlock->removeSuccessor(*iterSucc);
|
||||
}
|
||||
if (thelastinstinst->get()->isUnconditional()) {
|
||||
auto brinst = dynamic_cast<UncondBrInst *>(thelastinstinst->get());
|
||||
BasicBlock *branchBlock = dynamic_cast<BasicBlock *>(brinst->getBlock());
|
||||
basicBlock->addSuccessor(branchBlock);
|
||||
branchBlock->addPredecessor(basicBlock.get());
|
||||
} else if (thelastinstinst->get()->isConditional()) {
|
||||
auto brinst = dynamic_cast<CondBrInst *>(thelastinstinst->get());
|
||||
BasicBlock *thenBlock = dynamic_cast<BasicBlock *>(brinst->getThenBlock());
|
||||
BasicBlock *elseBlock = dynamic_cast<BasicBlock *>(brinst->getElseBlock());
|
||||
basicBlock->addSuccessor(thenBlock);
|
||||
basicBlock->addSuccessor(elseBlock);
|
||||
thenBlock->addPredecessor(basicBlock.get());
|
||||
elseBlock->addPredecessor(basicBlock.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
// 合并基本块
|
||||
bool SysYCFGOptUtils::SysYBlockMerge(Function *func) {
|
||||
bool changed = false;
|
||||
|
||||
for (auto blockiter = func->getBasicBlocks().begin(); blockiter != func->getBasicBlocks().end();) {
|
||||
if (blockiter->get()->getNumSuccessors() == 1) {
|
||||
// 如果当前块只有一个后继块
|
||||
// 且后继块只有一个前驱块
|
||||
// 则将当前块和后继块合并
|
||||
if (((blockiter->get())->getSuccessors()[0])->getNumPredecessors() == 1) {
|
||||
// std::cout << "merge block: " << blockiter->get()->getName() << std::endl;
|
||||
BasicBlock *block = blockiter->get();
|
||||
BasicBlock *nextBlock = blockiter->get()->getSuccessors()[0];
|
||||
// auto nextarguments = nextBlock->getArguments();
|
||||
// 删除br指令
|
||||
if (block->getNumInstructions() != 0) {
|
||||
auto thelastinstinst = block->terminator();
|
||||
if (thelastinstinst->get()->isUnconditional()) {
|
||||
thelastinstinst = SysYIROptUtils::usedelete(thelastinstinst);
|
||||
} else if (thelastinstinst->get()->isConditional()) {
|
||||
// 按道理不会走到这个分支
|
||||
// 如果是条件分支,查看then else是否相同
|
||||
auto brinst = dynamic_cast<CondBrInst *>(thelastinstinst->get());
|
||||
if (brinst->getThenBlock() == brinst->getElseBlock()) {
|
||||
thelastinstinst = SysYIROptUtils::usedelete(thelastinstinst);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 将后继块的指令移动到当前块
|
||||
// 并将后继块的父指针改为当前块
|
||||
for (auto institer = nextBlock->begin(); institer != nextBlock->end();) {
|
||||
institer->get()->setParent(block);
|
||||
block->getInstructions().emplace_back(institer->release());
|
||||
institer = nextBlock->getInstructions().erase(institer);
|
||||
}
|
||||
// 更新前驱后继关系,类似树节点操作
|
||||
block->removeSuccessor(nextBlock);
|
||||
nextBlock->removePredecessor(block);
|
||||
std::list<BasicBlock *> succshoulddel;
|
||||
for (auto &succ : nextBlock->getSuccessors()) {
|
||||
block->addSuccessor(succ);
|
||||
succ->replacePredecessor(nextBlock, block);
|
||||
succshoulddel.push_back(succ);
|
||||
}
|
||||
for (auto del : succshoulddel) {
|
||||
nextBlock->removeSuccessor(del);
|
||||
}
|
||||
|
||||
func->removeBasicBlock(nextBlock);
|
||||
changed = true;
|
||||
|
||||
} else {
|
||||
blockiter++;
|
||||
}
|
||||
} else {
|
||||
blockiter++;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
// 删除无前驱块,兼容SSA后的处理
|
||||
bool SysYCFGOptUtils::SysYDelNoPreBLock(Function *func) {
|
||||
bool changed = false; // 标记是否有基本块被删除
|
||||
std::set<BasicBlock *> reachableBlocks; // 用于存储所有可达的基本块
|
||||
std::queue<BasicBlock *> blockQueue; // BFS 遍历队列
|
||||
|
||||
BasicBlock *entryBlock = func->getEntryBlock();
|
||||
if (entryBlock) { // 确保函数有入口块
|
||||
reachableBlocks.insert(entryBlock); // 将入口块标记为可达
|
||||
blockQueue.push(entryBlock); // 入口块入队
|
||||
}
|
||||
// 如果没有入口块(比如一个空函数),则没有块是可达的,所有块都将被删除。
|
||||
|
||||
while (!blockQueue.empty()) { // BFS 遍历:只要队列不空
|
||||
BasicBlock *currentBlock = blockQueue.front();
|
||||
blockQueue.pop(); // 取出当前块
|
||||
|
||||
for (auto &succ : currentBlock->getSuccessors()) { // 遍历当前块的所有后继
|
||||
// 如果后继块不在 reachableBlocks 中(即尚未被访问过)
|
||||
if (reachableBlocks.find(succ) == reachableBlocks.end()) {
|
||||
reachableBlocks.insert(succ); // 标记为可达
|
||||
blockQueue.push(succ); // 入队,以便继续遍历
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<BasicBlock *> blocksToDelete; // 用于存储所有不可达的基本块
|
||||
|
||||
for (auto &blockPtr : func->getBasicBlocks()) {
|
||||
BasicBlock *block = blockPtr.get();
|
||||
// 如果当前块不在 reachableBlocks 集合中,说明它是不可达的
|
||||
if (reachableBlocks.find(block) == reachableBlocks.end()) {
|
||||
blocksToDelete.push_back(block); // 将其加入待删除列表
|
||||
changed = true; // 只要找到一个不可达块,就说明函数发生了改变
|
||||
}
|
||||
}
|
||||
|
||||
for (BasicBlock *unreachableBlock : blocksToDelete) {
|
||||
// 遍历不可达块中的所有指令,并删除它们
|
||||
for (auto instIter = unreachableBlock->getInstructions().begin();
|
||||
instIter != unreachableBlock->getInstructions().end();) {
|
||||
instIter = SysYIROptUtils::usedelete(instIter);
|
||||
}
|
||||
}
|
||||
|
||||
for (BasicBlock *unreachableBlock : blocksToDelete) {
|
||||
for (BasicBlock *succBlock : unreachableBlock->getSuccessors()) {
|
||||
// 只有当后继块自身是可达的(没有被删除)时才需要处理
|
||||
if (reachableBlocks.count(succBlock)) {
|
||||
for (auto &phiInstPtr : succBlock->getInstructions()) {
|
||||
// Phi 指令总是在基本块的开头。一旦遇到非 Phi 指令即可停止。
|
||||
if (phiInstPtr->getKind() != Instruction::kPhi) {
|
||||
break;
|
||||
}
|
||||
// 将这个 Phi 节点中来自不可达前驱(unreachableBlock)的输入参数删除
|
||||
dynamic_cast<PhiInst *>(phiInstPtr.get())->delBlk(unreachableBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto blockIter = func->getBasicBlocks().begin(); blockIter != func->getBasicBlocks().end();) {
|
||||
BasicBlock *currentBlock = blockIter->get();
|
||||
// 如果当前块不在可达块集合中,则将其从函数中移除
|
||||
if (reachableBlocks.find(currentBlock) == reachableBlocks.end()) {
|
||||
// func->removeBasicBlock 应该返回下一个有效的迭代器
|
||||
func->removeBasicBlock((blockIter++)->get());
|
||||
} else {
|
||||
blockIter++; // 如果可达,则移动到下一个块
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool SysYCFGOptUtils::SysYDelEmptyBlock(Function *func, IRBuilder *pBuilder) {
|
||||
bool changed = false;
|
||||
|
||||
// 步骤 1: 识别并映射所有符合“空块”定义的基本块及其目标后继
|
||||
// 使用 std::map 来存储 <空块, 空块跳转目标>
|
||||
// 这样可以处理空块链:A -> B -> C,如果 B 是空块,A 应该跳到 C
|
||||
std::map<BasicBlock *, BasicBlock *> emptyBlockRedirectMap;
|
||||
|
||||
// 为了避免在遍历 func->getBasicBlocks() 时修改它导致迭代器失效,
|
||||
// 我们先收集所有的基本块。
|
||||
std::vector<BasicBlock *> allBlocks;
|
||||
for (auto &blockPtr : func->getBasicBlocks()) {
|
||||
allBlocks.push_back(blockPtr.get());
|
||||
}
|
||||
|
||||
for (BasicBlock *block : allBlocks) {
|
||||
// 入口块通常不应该被认为是空块并删除,除非它没有实际指令且只有一个后继,
|
||||
// 但为了安全起见,通常会跳过入口块的删除。
|
||||
// 如果入口块是空的,它应该被合并到它的后继,但处理起来更复杂,这里先不处理入口块为空的情况
|
||||
if (block == func->getEntryBlock()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查基本块是否是空的:除了Phi指令外,只包含一个终止指令 (Terminator)
|
||||
// 且该终止指令必须是无条件跳转。
|
||||
// 空块必须只有一个后继才能被简化
|
||||
if (block->getNumSuccessors() == 1) {
|
||||
bool hasNonPhiNonTerminator = false;
|
||||
// 遍历除了最后一个指令之外的指令
|
||||
for (auto instIter = block->getInstructions().begin(); instIter != block->getInstructions().end();) {
|
||||
// 如果是终止指令(例如 br, ret),且不是最后一个指令,则该块有问题
|
||||
if ((*instIter)->isTerminator() && instIter != block->terminator()) {
|
||||
hasNonPhiNonTerminator = true;
|
||||
break;
|
||||
}
|
||||
// 如果不是 Phi 指令且不是终止指令
|
||||
if (!(*instIter)->isPhi() && !(*instIter)->isTerminator()) {
|
||||
hasNonPhiNonTerminator = true;
|
||||
break;
|
||||
}
|
||||
++instIter;
|
||||
if (!hasNonPhiNonTerminator &&
|
||||
instIter == block->getInstructions().end()) { // 如果块中只有 Phi 指令和一个 Terminator
|
||||
// 确保最后一个指令是无条件跳转
|
||||
auto lastInst = block->terminator()->get();
|
||||
if (lastInst && lastInst->isUnconditional()) {
|
||||
emptyBlockRedirectMap[block] = block->getSuccessors().front();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 步骤 2: 遍历 emptyBlockRedirectMap,处理空块链
|
||||
// 确保每个空块都直接重定向到其最终的非空后继块
|
||||
for (auto const &[emptyBlock, directSucc] : emptyBlockRedirectMap) {
|
||||
BasicBlock *targetBlock = directSucc;
|
||||
// 沿着空块链一直找到最终的非空块目标
|
||||
while (emptyBlockRedirectMap.count(targetBlock)) {
|
||||
targetBlock = emptyBlockRedirectMap[targetBlock];
|
||||
}
|
||||
emptyBlockRedirectMap[emptyBlock] = targetBlock; // 更新映射到最终目标
|
||||
}
|
||||
|
||||
// 步骤 3: 遍历所有基本块,重定向其终止指令,绕过空块
|
||||
// 注意:这里需要再次遍历所有块,包括可能成为新目标的块
|
||||
for (BasicBlock *currentBlock : allBlocks) {
|
||||
// 如果 currentBlock 本身就是个空块,它会通过其前驱的重定向被处理,这里跳过
|
||||
if (emptyBlockRedirectMap.count(currentBlock)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取当前块的最后一个指令(终止指令)
|
||||
if (currentBlock->getInstructions().empty()) {
|
||||
// 理论上,除了入口块和可能被合并的空块外,所有块都应该有终止指令
|
||||
// 如果这里碰到空块,可能是逻辑错误或者需要特殊处理
|
||||
continue;
|
||||
}
|
||||
|
||||
std::function<Value *(Value *, BasicBlock *)> getUltimateSourceValue = [&](Value *val,
|
||||
BasicBlock *currentDefBlock) -> Value * {
|
||||
// 如果值不是指令,例如常量或函数参数,则它本身就是最终来源
|
||||
if (auto instr = dynamic_cast<Instruction *>(val)) { // Assuming Value* has a method to check if it's an instruction
|
||||
return val;
|
||||
}
|
||||
|
||||
Instruction *inst = dynamic_cast<Instruction *>(val);
|
||||
// 如果定义指令不在任何空块中,它就是最终来源
|
||||
if (!emptyBlockRedirectMap.count(currentDefBlock)) {
|
||||
return val;
|
||||
}
|
||||
|
||||
// 如果是 Phi 指令,且它在空块中,则继续追溯其在空块链中前驱的传入值
|
||||
if (inst->getKind() == Instruction::kPhi) {
|
||||
PhiInst *phi = dynamic_cast<PhiInst *>(inst);
|
||||
// 查找哪个前驱是空块链中的上一个块
|
||||
for (size_t i = 0; i < phi->getNumOperands(); i += 2) {
|
||||
BasicBlock *incomingBlock = dynamic_cast<BasicBlock *>(phi->getOperand(i + 1));
|
||||
// 检查 incomingBlock 是否是当前空块的前驱,且也在空块映射中(或就是 P)
|
||||
// 找到在空块链中导致 currentDefBlock 的那个前驱块
|
||||
if (emptyBlockRedirectMap.count(incomingBlock) || incomingBlock == currentBlock) {
|
||||
// 递归追溯该传入值
|
||||
return getUltimateSourceValue(phi->getIncomingValue(incomingBlock), incomingBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 如果是其他指令或者无法追溯到Phi链,则认为它在空块中产生,无法安全传播,返回null或原值
|
||||
// 在严格的空块定义下,除了Phi和Terminator,不应有其他指令产生值。
|
||||
return val; // Fallback: If not a Phi, or unable to trace, return itself (may be dangling)
|
||||
};
|
||||
|
||||
auto lastInst = currentBlock->getInstructions().back().get();
|
||||
|
||||
if (lastInst->isUnconditional()) { // 无条件跳转
|
||||
UncondBrInst *brInst = dynamic_cast<UncondBrInst *>(lastInst);
|
||||
BasicBlock *oldTarget = dynamic_cast<BasicBlock *>(brInst->getBlock()); // 原始跳转目标
|
||||
|
||||
if (emptyBlockRedirectMap.count(oldTarget)) { // 如果目标是空块
|
||||
BasicBlock *newTarget = emptyBlockRedirectMap[oldTarget]; // 获取最终目标
|
||||
|
||||
// 更新 CFG 关系
|
||||
currentBlock->removeSuccessor(oldTarget);
|
||||
oldTarget->removePredecessor(currentBlock);
|
||||
|
||||
brInst->replaceOperand(0, newTarget); // 更新跳转指令的操作数
|
||||
currentBlock->addSuccessor(newTarget);
|
||||
newTarget->addPredecessor(currentBlock);
|
||||
|
||||
changed = true; // 标记发生改变
|
||||
|
||||
for (auto &phiInstPtr : newTarget->getInstructions()) {
|
||||
if (phiInstPtr->getKind() == Instruction::kPhi) {
|
||||
PhiInst *phiInst = dynamic_cast<PhiInst *>(phiInstPtr.get());
|
||||
BasicBlock *actualEmptyPredecessorOfS = nullptr;
|
||||
for (size_t i = 0; i < phiInst->getNumOperands(); i += 2) {
|
||||
BasicBlock *incomingBlock = dynamic_cast<BasicBlock *>(phiInst->getOperand(i + 1));
|
||||
if (incomingBlock && emptyBlockRedirectMap.count(incomingBlock) &&
|
||||
emptyBlockRedirectMap[incomingBlock] == newTarget) {
|
||||
actualEmptyPredecessorOfS = incomingBlock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (actualEmptyPredecessorOfS) {
|
||||
// 获取 Phi 节点原本从 actualEmptyPredecessorOfS 接收的值
|
||||
Value *valueFromEmptyPredecessor = phiInst->getIncomingValue(actualEmptyPredecessorOfS);
|
||||
|
||||
// 追溯这个值,找到它在非空块中的最终来源
|
||||
// currentBlock 是 P
|
||||
// oldTarget 是 E1 (链的起点)
|
||||
// actualEmptyPredecessorOfS 是 En (链的终点,S 的前驱)
|
||||
Value *ultimateSourceValue = getUltimateSourceValue(valueFromEmptyPredecessor, actualEmptyPredecessorOfS);
|
||||
|
||||
// 替换 Phi 节点的传入块和传入值
|
||||
if (ultimateSourceValue) { // 确保成功追溯到有效来源
|
||||
phiInst->replaceIncoming(actualEmptyPredecessorOfS, currentBlock, ultimateSourceValue);
|
||||
} else {
|
||||
assert(false && "[DelEmptyBlock] Unable to trace a valid source for Phi instruction");
|
||||
// 无法追溯到有效来源,这可能是个错误或特殊情况
|
||||
// 此时可能需要移除该 Phi 项,或者插入一个 undef 值
|
||||
phiInst->removeIncoming(actualEmptyPredecessorOfS);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (lastInst->getKind() == Instruction::kCondBr) { // 条件跳转
|
||||
CondBrInst *condBrInst = dynamic_cast<CondBrInst *>(lastInst);
|
||||
BasicBlock *oldThenTarget = dynamic_cast<BasicBlock *>(condBrInst->getThenBlock());
|
||||
BasicBlock *oldElseTarget = dynamic_cast<BasicBlock *>(condBrInst->getElseBlock());
|
||||
|
||||
bool thenPathChanged = false;
|
||||
bool elsePathChanged = false;
|
||||
|
||||
// 处理 Then 分支
|
||||
if (emptyBlockRedirectMap.count(oldThenTarget)) {
|
||||
BasicBlock *newThenTarget = emptyBlockRedirectMap[oldThenTarget];
|
||||
condBrInst->replaceOperand(1, newThenTarget); // 更新跳转指令操作数
|
||||
|
||||
currentBlock->removeSuccessor(oldThenTarget);
|
||||
oldThenTarget->removePredecessor(currentBlock);
|
||||
currentBlock->addSuccessor(newThenTarget);
|
||||
newThenTarget->addPredecessor(currentBlock);
|
||||
thenPathChanged = true;
|
||||
changed = true;
|
||||
|
||||
// 处理新 Then 目标块中的 Phi 指令
|
||||
// for (auto &phiInstPtr : newThenTarget->getInstructions()) {
|
||||
// if (phiInstPtr->getKind() == Instruction::kPhi) {
|
||||
// dynamic_cast<PhiInst *>(phiInstPtr.get())->delBlk(oldThenTarget);
|
||||
// } else {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
for (auto &phiInstPtr : newThenTarget->getInstructions()) {
|
||||
if (phiInstPtr->getKind() == Instruction::kPhi) {
|
||||
PhiInst *phiInst = dynamic_cast<PhiInst *>(phiInstPtr.get());
|
||||
BasicBlock *actualEmptyPredecessorOfS = nullptr;
|
||||
for (size_t i = 0; i < phiInst->getNumOperands(); i += 2) {
|
||||
BasicBlock *incomingBlock = dynamic_cast<BasicBlock *>(phiInst->getOperand(i + 1));
|
||||
if (incomingBlock && emptyBlockRedirectMap.count(incomingBlock) &&
|
||||
emptyBlockRedirectMap[incomingBlock] == newThenTarget) {
|
||||
actualEmptyPredecessorOfS = incomingBlock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (actualEmptyPredecessorOfS) {
|
||||
// 获取 Phi 节点原本从 actualEmptyPredecessorOfS 接收的值
|
||||
Value *valueFromEmptyPredecessor = phiInst->getIncomingValue(actualEmptyPredecessorOfS);
|
||||
|
||||
// 追溯这个值,找到它在非空块中的最终来源
|
||||
// currentBlock 是 P
|
||||
// oldTarget 是 E1 (链的起点)
|
||||
// actualEmptyPredecessorOfS 是 En (链的终点,S 的前驱)
|
||||
Value *ultimateSourceValue = getUltimateSourceValue(valueFromEmptyPredecessor, actualEmptyPredecessorOfS);
|
||||
|
||||
// 替换 Phi 节点的传入块和传入值
|
||||
if (ultimateSourceValue) { // 确保成功追溯到有效来源
|
||||
phiInst->replaceIncoming(actualEmptyPredecessorOfS, currentBlock, ultimateSourceValue);
|
||||
} else {
|
||||
assert(false && "[DelEmptyBlock] Unable to trace a valid source for Phi instruction");
|
||||
// 无法追溯到有效来源,这可能是个错误或特殊情况
|
||||
// 此时可能需要移除该 Phi 项,或者插入一个 undef 值
|
||||
phiInst->removeIncoming(actualEmptyPredecessorOfS);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 处理 Else 分支
|
||||
if (emptyBlockRedirectMap.count(oldElseTarget)) {
|
||||
BasicBlock *newElseTarget = emptyBlockRedirectMap[oldElseTarget];
|
||||
condBrInst->replaceOperand(2, newElseTarget); // 更新跳转指令操作数
|
||||
|
||||
currentBlock->removeSuccessor(oldElseTarget);
|
||||
oldElseTarget->removePredecessor(currentBlock);
|
||||
currentBlock->addSuccessor(newElseTarget);
|
||||
newElseTarget->addPredecessor(currentBlock);
|
||||
elsePathChanged = true;
|
||||
changed = true;
|
||||
|
||||
// 处理新 Else 目标块中的 Phi 指令
|
||||
// for (auto &phiInstPtr : newElseTarget->getInstructions()) {
|
||||
// if (phiInstPtr->getKind() == Instruction::kPhi) {
|
||||
// dynamic_cast<PhiInst *>(phiInstPtr.get())->delBlk(oldElseTarget);
|
||||
// } else {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
for (auto &phiInstPtr : newElseTarget->getInstructions()) {
|
||||
if (phiInstPtr->getKind() == Instruction::kPhi) {
|
||||
PhiInst *phiInst = dynamic_cast<PhiInst *>(phiInstPtr.get());
|
||||
BasicBlock *actualEmptyPredecessorOfS = nullptr;
|
||||
for (size_t i = 0; i < phiInst->getNumOperands(); i += 2) {
|
||||
BasicBlock *incomingBlock = dynamic_cast<BasicBlock *>(phiInst->getOperand(i + 1));
|
||||
if (incomingBlock && emptyBlockRedirectMap.count(incomingBlock) &&
|
||||
emptyBlockRedirectMap[incomingBlock] == newElseTarget) {
|
||||
actualEmptyPredecessorOfS = incomingBlock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (actualEmptyPredecessorOfS) {
|
||||
// 获取 Phi 节点原本从 actualEmptyPredecessorOfS 接收的值
|
||||
Value *valueFromEmptyPredecessor = phiInst->getIncomingValue(actualEmptyPredecessorOfS);
|
||||
|
||||
// 追溯这个值,找到它在非空块中的最终来源
|
||||
// currentBlock 是 P
|
||||
// oldTarget 是 E1 (链的起点)
|
||||
// actualEmptyPredecessorOfS 是 En (链的终点,S 的前驱)
|
||||
Value *ultimateSourceValue = getUltimateSourceValue(valueFromEmptyPredecessor, actualEmptyPredecessorOfS);
|
||||
|
||||
// 替换 Phi 节点的传入块和传入值
|
||||
if (ultimateSourceValue) { // 确保成功追溯到有效来源
|
||||
phiInst->replaceIncoming(actualEmptyPredecessorOfS, currentBlock, ultimateSourceValue);
|
||||
} else {
|
||||
assert(false && "[DelEmptyBlock] Unable to trace a valid source for Phi instruction");
|
||||
// 无法追溯到有效来源,这可能是个错误或特殊情况
|
||||
// 此时可能需要移除该 Phi 项,或者插入一个 undef 值
|
||||
phiInst->removeIncoming(actualEmptyPredecessorOfS);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 额外处理:如果条件跳转的两个分支现在指向同一个块,则可以简化为无条件跳转
|
||||
if (condBrInst->getThenBlock() == condBrInst->getElseBlock()) {
|
||||
BasicBlock *commonTarget = dynamic_cast<BasicBlock *>(condBrInst->getThenBlock());
|
||||
SysYIROptUtils::usedelete(lastInst); // 删除旧的条件跳转指令
|
||||
pBuilder->setPosition(currentBlock, currentBlock->end());
|
||||
pBuilder->createUncondBrInst(commonTarget); // 插入新的无条件跳转指令
|
||||
|
||||
// 更安全地更新 CFG 关系
|
||||
std::set<BasicBlock *> currentSuccessors;
|
||||
currentSuccessors.insert(oldThenTarget);
|
||||
currentSuccessors.insert(oldElseTarget);
|
||||
|
||||
// 移除旧的后继关系
|
||||
for (BasicBlock *succ : currentSuccessors) {
|
||||
currentBlock->removeSuccessor(succ);
|
||||
succ->removePredecessor(currentBlock);
|
||||
}
|
||||
// 添加新的后继关系
|
||||
currentBlock->addSuccessor(commonTarget);
|
||||
commonTarget->addPredecessor(currentBlock);
|
||||
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 步骤 4: 真正地删除空基本块
|
||||
// 注意:只能在所有跳转和 Phi 指令都更新完毕后才能删除这些块
|
||||
for (auto blockIter = func->getBasicBlocks().begin(); blockIter != func->getBasicBlocks().end();) {
|
||||
BasicBlock *currentBlock = blockIter->get();
|
||||
if (emptyBlockRedirectMap.count(currentBlock)) { // 如果在空块映射中
|
||||
// 入口块不应该被删除,即使它符合空块定义,因为函数需要一个入口
|
||||
if (currentBlock == func->getEntryBlock()) {
|
||||
++blockIter;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 在删除块之前,确保其内部指令被正确删除(虽然这类块指令很少)
|
||||
for (auto instIter = currentBlock->getInstructions().begin();
|
||||
instIter != currentBlock->getInstructions().end();) {
|
||||
instIter = SysYIROptUtils::usedelete(instIter);
|
||||
}
|
||||
|
||||
// 移除块
|
||||
func->removeBasicBlock((blockIter++)->get());
|
||||
changed = true;
|
||||
} else {
|
||||
++blockIter;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
// 如果函数没有返回指令,则添加一个默认返回指令(主要解决void函数没有返回指令的问题)
|
||||
bool SysYCFGOptUtils::SysYAddReturn(Function *func, IRBuilder *pBuilder) {
|
||||
bool changed = false;
|
||||
auto basicBlocks = func->getBasicBlocks();
|
||||
for (auto &block : basicBlocks) {
|
||||
if (block->getNumSuccessors() == 0) {
|
||||
// 如果基本块没有后继块,则添加一个返回指令
|
||||
if (block->getNumInstructions() == 0) {
|
||||
pBuilder->setPosition(block.get(), block->end());
|
||||
pBuilder->createReturnInst();
|
||||
changed = true; // 标记IR被修改
|
||||
} else {
|
||||
auto thelastinst = block->getInstructions().end();
|
||||
--thelastinst;
|
||||
if (thelastinst->get()->getKind() != Instruction::kReturn) {
|
||||
// std::cout << "Warning: Function " << func->getName() << " has no return instruction, adding default
|
||||
// return." << std::endl;
|
||||
|
||||
pBuilder->setPosition(block.get(), block->end());
|
||||
// TODO: 如果int float函数缺少返回值是否需要报错
|
||||
if (func->getReturnType()->isInt()) {
|
||||
pBuilder->createReturnInst(ConstantInteger::get(0));
|
||||
} else if (func->getReturnType()->isFloat()) {
|
||||
pBuilder->createReturnInst(ConstantFloating::get(0.0F));
|
||||
} else {
|
||||
pBuilder->createReturnInst();
|
||||
}
|
||||
changed = true; // 标记IR被修改
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
// 条件分支转换为无条件分支
|
||||
// 主要针对已知条件值的分支转换为无条件分支
|
||||
// 例如 if (cond) { ... } else { ... } 中的 cond 已经
|
||||
// 确定为 true 或 false 的情况
|
||||
bool SysYCFGOptUtils::SysYCondBr2Br(Function *func, IRBuilder *pBuilder) {
|
||||
bool changed = false;
|
||||
|
||||
for (auto &basicblock : func->getBasicBlocks()) {
|
||||
if (basicblock->getNumInstructions() == 0)
|
||||
continue;
|
||||
|
||||
auto thelast = basicblock->terminator();
|
||||
|
||||
if (thelast->get()->isConditional()) {
|
||||
auto condBrInst = dynamic_cast<CondBrInst *>(thelast->get());
|
||||
ConstantValue *constOperand = dynamic_cast<ConstantValue *>(condBrInst->getCondition());
|
||||
std::string opname;
|
||||
int constint = 0;
|
||||
float constfloat = 0.0F;
|
||||
bool constint_Use = false;
|
||||
bool constfloat_Use = false;
|
||||
if (constOperand != nullptr) {
|
||||
if (constOperand->isFloat()) {
|
||||
constfloat = constOperand->getFloat();
|
||||
constfloat_Use = true;
|
||||
} else {
|
||||
constint = constOperand->getInt();
|
||||
constint_Use = true;
|
||||
}
|
||||
}
|
||||
// 如果可以计算
|
||||
if (constfloat_Use || constint_Use) {
|
||||
changed = true;
|
||||
|
||||
auto thenBlock = dynamic_cast<BasicBlock *>(condBrInst->getThenBlock());
|
||||
auto elseBlock = dynamic_cast<BasicBlock *>(condBrInst->getElseBlock());
|
||||
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);
|
||||
|
||||
// 更新CFG关系
|
||||
basicblock->removeSuccessor(elseBlock);
|
||||
elseBlock->removePredecessor(basicblock.get());
|
||||
|
||||
// 删除elseBlock的phi指令中对应的basicblock.get()的传入值
|
||||
for (auto &phiinst : elseBlock->getInstructions()) {
|
||||
if (phiinst->getKind() != Instruction::kPhi) {
|
||||
break;
|
||||
}
|
||||
// 使用 delBlk 方法删除 basicblock.get() 对应的传入值
|
||||
dynamic_cast<PhiInst *>(phiinst.get())->removeIncoming(basicblock.get());
|
||||
}
|
||||
|
||||
} else { // cond为false或0
|
||||
|
||||
pBuilder->setPosition(basicblock.get(), basicblock->end());
|
||||
pBuilder->createUncondBrInst(elseBlock);
|
||||
|
||||
// 更新CFG关系
|
||||
basicblock->removeSuccessor(thenBlock);
|
||||
thenBlock->removePredecessor(basicblock.get());
|
||||
|
||||
// 删除thenBlock的phi指令中对应的basicblock.get()的传入值
|
||||
for (auto &phiinst : thenBlock->getInstructions()) {
|
||||
if (phiinst->getKind() != Instruction::kPhi) {
|
||||
break;
|
||||
}
|
||||
// 使用 delBlk 方法删除 basicblock.get() 对应的传入值
|
||||
dynamic_cast<PhiInst *>(phiinst.get())->removeIncoming(basicblock.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// 独立的CFG优化遍的实现
|
||||
// ======================================================================
|
||||
|
||||
bool SysYDelInstAfterBrPass::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
return SysYCFGOptUtils::SysYDelInstAfterBr(F);
|
||||
}
|
||||
|
||||
bool SysYDelEmptyBlockPass::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
return SysYCFGOptUtils::SysYDelEmptyBlock(F, pBuilder);
|
||||
}
|
||||
|
||||
bool SysYDelNoPreBLockPass::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
return SysYCFGOptUtils::SysYDelNoPreBLock(F);
|
||||
}
|
||||
|
||||
bool SysYBlockMergePass::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
return SysYCFGOptUtils::SysYBlockMerge(F);
|
||||
}
|
||||
|
||||
bool SysYAddReturnPass::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
return SysYCFGOptUtils::SysYAddReturn(F, pBuilder);
|
||||
}
|
||||
|
||||
bool SysYCondBr2BrPass::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
return SysYCFGOptUtils::SysYCondBr2Br(F, pBuilder);
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
235
src/midend/Pass/Pass.cpp
Normal file
235
src/midend/Pass/Pass.cpp
Normal file
@ -0,0 +1,235 @@
|
||||
#include "Dom.h"
|
||||
#include "Liveness.h"
|
||||
#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>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
extern int DEBUG; // 全局调试标志
|
||||
namespace sysy {
|
||||
|
||||
// ======================================================================
|
||||
// 封装优化流程的函数:包含Pass注册和迭代运行逻辑
|
||||
// ======================================================================
|
||||
|
||||
void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR, int optLevel) {
|
||||
if (DEBUG) std::cout << "--- Starting Middle-End Optimizations (Level -O" << optLevel << ") ---\n";
|
||||
|
||||
/*
|
||||
中端开发框架基本流程:
|
||||
1) 分析pass
|
||||
1. 实现分析pass并引入Pass.cpp
|
||||
2. 注册分析pass
|
||||
2) 优化pass
|
||||
1. 实现优化pass并引入Pass.cpp
|
||||
2. 注册优化pass
|
||||
3. 添加优化passid
|
||||
*/
|
||||
// 注册分析遍
|
||||
registerAnalysisPass<sysy::DominatorTreeAnalysisPass>();
|
||||
registerAnalysisPass<sysy::LivenessAnalysisPass>();
|
||||
|
||||
// 注册优化遍
|
||||
registerOptimizationPass<SysYDelInstAfterBrPass>();
|
||||
registerOptimizationPass<SysYDelNoPreBLockPass>();
|
||||
registerOptimizationPass<SysYBlockMergePass>();
|
||||
|
||||
registerOptimizationPass<SysYDelEmptyBlockPass>(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";
|
||||
if (DEBUG) std::cout << "--- Running custom optimization sequence ---\n";
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&SysYDelInstAfterBrPass::ID);
|
||||
this->addPass(&SysYDelNoPreBLockPass::ID);
|
||||
this->addPass(&SysYBlockMergePass::ID);
|
||||
this->addPass(&SysYDelEmptyBlockPass::ID);
|
||||
this->addPass(&SysYCondBr2BrPass::ID);
|
||||
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";
|
||||
}
|
||||
|
||||
// 2. 创建遍管理器
|
||||
// 3. 根据优化级别添加不同的优化遍
|
||||
// TODO : 根据 optLevel 添加不同的优化遍
|
||||
// 讨论 是不动点迭代进行优化遍还是手动客制化优化遍的顺序?
|
||||
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "=== Final IR After Middle-End Optimizations (Level -O" << optLevel << ") ===\n";
|
||||
SysYPrinter printer(moduleIR);
|
||||
printer.printIR();
|
||||
}
|
||||
}
|
||||
|
||||
void PassManager::clearPasses() {
|
||||
passes.clear();
|
||||
}
|
||||
|
||||
void PassManager::addPass(void *passID) {
|
||||
|
||||
PassRegistry ®istry = PassRegistry::getPassRegistry();
|
||||
std::unique_ptr<Pass> P = registry.createPass(passID);
|
||||
if (!P) {
|
||||
// Error: Pass not found or failed to create
|
||||
return;
|
||||
}
|
||||
|
||||
passes.push_back(std::move(P));
|
||||
}
|
||||
|
||||
// 运行所有注册的遍
|
||||
bool PassManager::run() {
|
||||
bool changed = false;
|
||||
for (const auto &p : passes) {
|
||||
bool passChanged = false; // 记录当前遍是否修改了 IR
|
||||
|
||||
// 处理优化遍的分析依赖和失效
|
||||
if (p->getPassKind() == Pass::PassKind::Optimization) {
|
||||
OptimizationPass *optPass = static_cast<OptimizationPass *>(p.get());
|
||||
std::set<void *> analysisDependencies;
|
||||
std::set<void *> analysisInvalidations;
|
||||
optPass->getAnalysisUsage(analysisDependencies, analysisInvalidations);
|
||||
|
||||
// PassManager 不显式运行分析依赖。
|
||||
// 而是优化遍在 runOnFunction 内部通过 AnalysisManager.getAnalysisResult 按需请求。
|
||||
}
|
||||
|
||||
if (p->getGranularity() == Pass::Granularity::Module) {
|
||||
passChanged = p->runOnModule(pmodule, analysisManager);
|
||||
} else if (p->getGranularity() == Pass::Granularity::Function) {
|
||||
for (auto &funcPair : pmodule->getFunctions()) {
|
||||
Function *F = funcPair.second.get();
|
||||
passChanged = p->runOnFunction(F, analysisManager) || passChanged;
|
||||
|
||||
if (passChanged && p->getPassKind() == Pass::PassKind::Optimization) {
|
||||
OptimizationPass *optPass = static_cast<OptimizationPass *>(p.get());
|
||||
std::set<void *> analysisDependencies;
|
||||
std::set<void *> analysisInvalidations;
|
||||
optPass->getAnalysisUsage(analysisDependencies, analysisInvalidations);
|
||||
for (void *invalidationID : analysisInvalidations) {
|
||||
analysisManager.invalidateAnalysis(invalidationID, F);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (p->getGranularity() == Pass::Granularity::BasicBlock) {
|
||||
for (auto &funcPair : pmodule->getFunctions()) {
|
||||
Function *F = funcPair.second.get();
|
||||
for (auto &bbPtr : funcPair.second->getBasicBlocks()) {
|
||||
passChanged = p->runOnBasicBlock(bbPtr.get(), analysisManager) || passChanged;
|
||||
|
||||
if (passChanged && p->getPassKind() == Pass::PassKind::Optimization) {
|
||||
OptimizationPass *optPass = static_cast<OptimizationPass *>(p.get());
|
||||
std::set<void *> analysisDependencies;
|
||||
std::set<void *> analysisInvalidations;
|
||||
optPass->getAnalysisUsage(analysisDependencies, analysisInvalidations);
|
||||
for (void *invalidationID : analysisInvalidations) {
|
||||
analysisManager.invalidateAnalysis(invalidationID, F);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
changed = changed || passChanged;
|
||||
}
|
||||
return changed;
|
||||
|
||||
}
|
||||
|
||||
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,
|
||||
[]() { return std::make_unique<AnalysisPassType>(); });
|
||||
}
|
||||
|
||||
template <typename OptimizationPassType, typename std::enable_if<
|
||||
std::is_constructible<OptimizationPassType, IRBuilder*>::value, int>::type>
|
||||
void registerOptimizationPass(IRBuilder* builder) {
|
||||
PassRegistry::getPassRegistry().registerPass(&OptimizationPassType::ID,
|
||||
[builder]() { return std::make_unique<OptimizationPassType>(builder); });
|
||||
}
|
||||
|
||||
template <typename OptimizationPassType, typename std::enable_if<
|
||||
!std::is_constructible<OptimizationPassType, IRBuilder*>::value, int>::type>
|
||||
void registerOptimizationPass() {
|
||||
PassRegistry::getPassRegistry().registerPass(&OptimizationPassType::ID,
|
||||
[]() { return std::make_unique<OptimizationPassType>(); });
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
2124
src/midend/SysYIRGenerator.cpp
Normal file
2124
src/midend/SysYIRGenerator.cpp
Normal file
File diff suppressed because it is too large
Load Diff
529
src/midend/SysYIRPrinter.cpp
Normal file
529
src/midend/SysYIRPrinter.cpp
Normal file
@ -0,0 +1,529 @@
|
||||
#include "SysYIRPrinter.h"
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include "IR.h" // 确保IR.h包含了ArrayType、GetElementPtrInst等的定义
|
||||
|
||||
namespace sysy {
|
||||
|
||||
void SysYPrinter::printIR() {
|
||||
const auto &functions = pModule->getFunctions();
|
||||
|
||||
//TODO: Print target datalayout and triple (minimal required by LLVM)
|
||||
|
||||
printGlobalVariable();
|
||||
printGlobalConstant();
|
||||
|
||||
for (const auto &iter : functions) {
|
||||
if (iter.second->getName() == "main") {
|
||||
printFunction(iter.second.get());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &iter : functions) {
|
||||
if (iter.second->getName() != "main") {
|
||||
printFunction(iter.second.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string SysYPrinter::getTypeString(Type *type) {
|
||||
if (type->isVoid()) {
|
||||
return "void";
|
||||
} else if (type->isInt()) {
|
||||
return "i32";
|
||||
} else if (type->isFloat()) {
|
||||
return "float";
|
||||
} else if (auto ptrType = dynamic_cast<PointerType*>(type)) {
|
||||
// 递归打印指针指向的类型,然后加上 '*'
|
||||
return getTypeString(ptrType->getBaseType()) + "*";
|
||||
} else if (auto funcType = dynamic_cast<FunctionType*>(type)) {
|
||||
// 对于函数类型,打印其返回类型
|
||||
// 注意:这里可能需要更完整的函数签名打印,取决于你的IR表示方式
|
||||
// 比如:`retType (paramType1, paramType2, ...)`
|
||||
// 但为了简化和LLVM IR兼容性,通常在定义时完整打印
|
||||
return getTypeString(funcType->getReturnType());
|
||||
} else if (auto arrayType = dynamic_cast<ArrayType*>(type)) { // 新增:处理数组类型
|
||||
// 打印格式为 [num_elements x element_type]
|
||||
return "[" + std::to_string(arrayType->getNumElements()) + " x " + getTypeString(arrayType->getElementType()) + "]";
|
||||
}
|
||||
assert(false && "Unsupported type");
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string SysYPrinter::getValueName(Value *value) {
|
||||
if (auto global = dynamic_cast<GlobalValue*>(value)) {
|
||||
return "@" + global->getName();
|
||||
} else if (auto inst = dynamic_cast<Instruction*>(value)) {
|
||||
return "%" + inst->getName();
|
||||
} else if (auto constInt = dynamic_cast<ConstantInteger*>(value)) { // 优先匹配具体的常量类型
|
||||
return std::to_string(constInt->getInt());
|
||||
} else if (auto constFloat = dynamic_cast<ConstantFloating*>(value)) { // 优先匹配具体的常量类型
|
||||
std::ostringstream oss;
|
||||
oss << std::scientific << std::setprecision(std::numeric_limits<float>::max_digits10) << constFloat->getFloat();
|
||||
return oss.str();
|
||||
} else if (auto constUndef = dynamic_cast<UndefinedValue*>(value)) { // 如果有Undef类型
|
||||
return "undef";
|
||||
} else if (auto constVal = dynamic_cast<ConstantValue*>(value)) { // fallback for generic ConstantValue
|
||||
// 这里的逻辑可能需要根据你ConstantValue的实际设计调整
|
||||
// 确保它能处理所有可能的ConstantValue
|
||||
if (auto constInt = dynamic_cast<ConstantInteger*>(value)) { // 优先匹配具体的常量类型
|
||||
return std::to_string(constInt->getInt());
|
||||
} else if (auto constFloat = dynamic_cast<ConstantFloating*>(value)) { // 优先匹配具体的常量类型
|
||||
std::ostringstream oss;
|
||||
oss << std::scientific << std::setprecision(std::numeric_limits<float>::max_digits10) << constFloat->getFloat();
|
||||
return oss.str();
|
||||
}
|
||||
} else if (auto constVar = dynamic_cast<ConstantVariable*>(value)) {
|
||||
return constVar->getName(); // 假设ConstantVariable有自己的名字或通过getByIndices获取值
|
||||
} else if (auto argVar = dynamic_cast<Argument*>(value)) {
|
||||
return "%" + argVar->getName(); // 假设ArgumentVariable有自己的名字
|
||||
}
|
||||
assert(false && "Unknown value type or unable to get value name");
|
||||
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);
|
||||
}
|
||||
|
||||
void SysYPrinter::printValue(Value *value) {
|
||||
std::cout << getValueName(value);
|
||||
}
|
||||
|
||||
void SysYPrinter::printGlobalVariable() {
|
||||
auto &globals = pModule->getGlobals();
|
||||
|
||||
for (const auto &global : globals) {
|
||||
std::cout << "@" << global->getName() << " = global ";
|
||||
|
||||
// 全局变量的类型是一个指针,指向其基类型 (可能是 ArrayType 或 Integer/FloatType)
|
||||
auto globalVarBaseType = dynamic_cast<PointerType *>(global->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 = global->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 = global->getByIndex(0);
|
||||
printType(initVal->getType()); // 打印标量值的类型
|
||||
std::cout << " ";
|
||||
printValue(initVal); // 打印标量值
|
||||
}
|
||||
|
||||
std::cout << ", align 4" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 ";
|
||||
printType(function->getReturnType());
|
||||
std::cout << " @" << function->getName() << "(";
|
||||
|
||||
auto entryBlock = function->getEntryBlock();
|
||||
const auto &args_types = function->getParamTypes();
|
||||
auto &args = function->getArguments();
|
||||
|
||||
int i = 0;
|
||||
for (const auto &args_type : args_types) {
|
||||
if (i > 0) std::cout << ", ";
|
||||
printType(args_type);
|
||||
std::cout << " %" << args[i]->getName();
|
||||
i++;
|
||||
}
|
||||
|
||||
std::cout << ") {" << std::endl;
|
||||
|
||||
// Function body
|
||||
for (const auto &blockIter : function->getBasicBlocks()) {
|
||||
// Basic block label
|
||||
BasicBlock* blockPtr = blockIter.get();
|
||||
if (!blockPtr->getName().empty()) {
|
||||
std::cout << blockPtr->getName() << ":" << std::endl;
|
||||
}
|
||||
|
||||
// Instructions
|
||||
for (const auto &instIter : blockIter->getInstructions()) {
|
||||
auto inst = instIter.get();
|
||||
std::cout << " ";
|
||||
printInst(inst);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "}" << std::endl << std::endl;
|
||||
}
|
||||
|
||||
void SysYPrinter::printInst(Instruction *pInst) {
|
||||
using Kind = Instruction::Kind;
|
||||
|
||||
switch (pInst->getKind()) {
|
||||
case Kind::kAdd:
|
||||
case Kind::kSub:
|
||||
case Kind::kMul:
|
||||
case Kind::kDiv:
|
||||
case Kind::kRem:
|
||||
case Kind::kFAdd:
|
||||
case Kind::kFSub:
|
||||
case Kind::kFMul:
|
||||
case Kind::kFDiv:
|
||||
case Kind::kICmpEQ:
|
||||
case Kind::kICmpNE:
|
||||
case Kind::kICmpLT:
|
||||
case Kind::kICmpGT:
|
||||
case Kind::kICmpLE:
|
||||
case Kind::kICmpGE:
|
||||
case Kind::kFCmpEQ:
|
||||
case Kind::kFCmpNE:
|
||||
case Kind::kFCmpLT:
|
||||
case Kind::kFCmpGT:
|
||||
case Kind::kFCmpLE:
|
||||
case Kind::kFCmpGE:
|
||||
case Kind::kAnd:
|
||||
case Kind::kOr: {
|
||||
auto binInst = dynamic_cast<BinaryInst *>(pInst);
|
||||
|
||||
// Print result variable if exists
|
||||
if (!binInst->getName().empty()) {
|
||||
std::cout << "%" << binInst->getName() << " = ";
|
||||
}
|
||||
|
||||
// Operation name
|
||||
switch (pInst->getKind()) {
|
||||
case Kind::kAdd: std::cout << "add"; break;
|
||||
case Kind::kSub: std::cout << "sub"; break;
|
||||
case Kind::kMul: std::cout << "mul"; break;
|
||||
case Kind::kDiv: std::cout << "sdiv"; break;
|
||||
case Kind::kRem: std::cout << "srem"; break;
|
||||
case Kind::kFAdd: std::cout << "fadd"; break;
|
||||
case Kind::kFSub: std::cout << "fsub"; break;
|
||||
case Kind::kFMul: std::cout << "fmul"; break;
|
||||
case Kind::kFDiv: std::cout << "fdiv"; break;
|
||||
case Kind::kICmpEQ: std::cout << "icmp eq"; break;
|
||||
case Kind::kICmpNE: std::cout << "icmp ne"; break;
|
||||
case Kind::kICmpLT: std::cout << "icmp slt"; break; // LLVM uses slt/sgt for signed less/greater than
|
||||
case Kind::kICmpGT: std::cout << "icmp sgt"; break;
|
||||
case Kind::kICmpLE: std::cout << "icmp sle"; break;
|
||||
case Kind::kICmpGE: std::cout << "icmp sge"; break;
|
||||
case Kind::kFCmpEQ: std::cout << "fcmp oeq"; break; // oeq for ordered equal
|
||||
case Kind::kFCmpNE: std::cout << "fcmp one"; break; // one for ordered not equal
|
||||
case Kind::kFCmpLT: std::cout << "fcmp olt"; break; // olt for ordered less than
|
||||
case Kind::kFCmpGT: std::cout << "fcmp ogt"; break; // ogt for ordered greater than
|
||||
case Kind::kFCmpLE: std::cout << "fcmp ole"; break; // ole for ordered less than or equal
|
||||
case Kind::kFCmpGE: std::cout << "fcmp oge"; break; // oge for ordered greater than or equal
|
||||
case Kind::kAnd: std::cout << "and"; break;
|
||||
case Kind::kOr: std::cout << "or"; break;
|
||||
default: break; // Should not reach here
|
||||
}
|
||||
|
||||
// Types and operands
|
||||
std::cout << " ";
|
||||
printType(binInst->getType());
|
||||
std::cout << " ";
|
||||
printValue(binInst->getLhs());
|
||||
std::cout << ", ";
|
||||
printValue(binInst->getRhs());
|
||||
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kNeg:
|
||||
case Kind::kNot:
|
||||
case Kind::kFNeg:
|
||||
case Kind::kFtoI:
|
||||
case Kind::kBitFtoI:
|
||||
case Kind::kItoF:
|
||||
case Kind::kBitItoF: {
|
||||
auto unyInst = dynamic_cast<UnaryInst *>(pInst);
|
||||
|
||||
if (!unyInst->getName().empty()) {
|
||||
std::cout << "%" << unyInst->getName() << " = ";
|
||||
}
|
||||
|
||||
switch (pInst->getKind()) {
|
||||
case Kind::kNeg: std::cout << "sub "; break; // integer negation is `sub i32 0, operand`
|
||||
case Kind::kNot: std::cout << "xor "; break; // logical/bitwise NOT is `xor i32 -1, operand` or `xor i1 true, operand`
|
||||
case Kind::kFNeg: std::cout << "fneg "; break; // float negation
|
||||
case Kind::kFtoI: std::cout << "fptosi "; break; // float to signed integer
|
||||
case Kind::kBitFtoI: std::cout << "bitcast "; break; // bitcast float to int
|
||||
case Kind::kItoF: std::cout << "sitofp "; break; // signed integer to float
|
||||
case Kind::kBitItoF: std::cout << "bitcast "; break; // bitcast int to float
|
||||
default: break; // Should not reach here
|
||||
}
|
||||
|
||||
printType(unyInst->getOperand()->getType()); // Print operand type
|
||||
std::cout << " ";
|
||||
|
||||
// Special handling for integer negation and logical NOT
|
||||
if (pInst->getKind() == Kind::kNeg) {
|
||||
std::cout << "0, "; // for 'sub i32 0, operand'
|
||||
} else if (pInst->getKind() == Kind::kNot) {
|
||||
// For logical NOT (i1 -> i1), use 'xor i1 true, operand'
|
||||
// For bitwise NOT (i32 -> i32), use 'xor i32 -1, operand'
|
||||
if (unyInst->getOperand()->getType()->isInt()) { // Assuming i32 for bitwise NOT
|
||||
std::cout << "NOT, "; // or specific bitmask for NOT
|
||||
} else { // Assuming i1 for logical NOT
|
||||
std::cout << "true, ";
|
||||
}
|
||||
}
|
||||
|
||||
printValue(pInst->getOperand(0));
|
||||
|
||||
// For type conversions (fptosi, sitofp, bitcast), need to specify destination type
|
||||
if (pInst->getKind() == Kind::kFtoI || pInst->getKind() == Kind::kItoF ||
|
||||
pInst->getKind() == Kind::kBitFtoI || pInst->getKind() == Kind::kBitItoF) {
|
||||
std::cout << " to ";
|
||||
printType(unyInst->getType()); // Print result type
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kCall: {
|
||||
auto callInst = dynamic_cast<CallInst *>(pInst);
|
||||
auto function = callInst->getCallee();
|
||||
|
||||
if (!callInst->getName().empty()) {
|
||||
std::cout << "%" << callInst->getName() << " = ";
|
||||
}
|
||||
|
||||
std::cout << "call ";
|
||||
printType(callInst->getType()); // Return type of the call
|
||||
std::cout << " @" << function->getName() << "(";
|
||||
|
||||
auto params = callInst->getArguments();
|
||||
bool first = true;
|
||||
for (auto ¶m : params) {
|
||||
if (!first) std::cout << ", ";
|
||||
first = false;
|
||||
printType(param->getValue()->getType()); // Type of argument
|
||||
std::cout << " ";
|
||||
printValue(param->getValue()); // Value of argument
|
||||
}
|
||||
|
||||
std::cout << ")" << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kCondBr: {
|
||||
auto condBrInst = dynamic_cast<CondBrInst *>(pInst);
|
||||
std::cout << "br i1 "; // Condition type should be i1
|
||||
printValue(condBrInst->getCondition());
|
||||
std::cout << ", label %" << condBrInst->getThenBlock()->getName();
|
||||
std::cout << ", label %" << condBrInst->getElseBlock()->getName();
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kBr: {
|
||||
auto brInst = dynamic_cast<UncondBrInst *>(pInst);
|
||||
std::cout << "br label %" << brInst->getBlock()->getName();
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kReturn: {
|
||||
auto retInst = dynamic_cast<ReturnInst *>(pInst);
|
||||
std::cout << "ret ";
|
||||
if (retInst->getNumOperands() != 0) {
|
||||
printType(retInst->getOperand(0)->getType());
|
||||
std::cout << " ";
|
||||
printValue(retInst->getOperand(0));
|
||||
} else {
|
||||
std::cout << "void";
|
||||
}
|
||||
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 = allocaInst->getAllocatedType();
|
||||
printType(allocatedType);
|
||||
|
||||
std::cout << ", align 4" << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kLoad: {
|
||||
auto loadInst = dynamic_cast<LoadInst *>(pInst);
|
||||
std::cout << "%" << loadInst->getName() << " = load ";
|
||||
printType(loadInst->getType()); // 加载的结果类型
|
||||
std::cout << ", ";
|
||||
printType(loadInst->getPointer()->getType()); // 指针类型
|
||||
std::cout << " ";
|
||||
printValue(loadInst->getPointer()); // 要加载的地址
|
||||
|
||||
std::cout << ", align 4" << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kStore: {
|
||||
auto storeInst = dynamic_cast<StoreInst *>(pInst);
|
||||
std::cout << "store ";
|
||||
printType(storeInst->getValue()->getType()); // 要存储的值的类型
|
||||
std::cout << " ";
|
||||
printValue(storeInst->getValue()); // 要存储的值
|
||||
std::cout << ", ";
|
||||
printType(storeInst->getPointer()->getType()); // 目标指针的类型
|
||||
std::cout << " ";
|
||||
printValue(storeInst->getPointer()); // 目标地址
|
||||
|
||||
|
||||
std::cout << ", align 4" << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kGetElementPtr: { // 新增:GetElementPtrInst 打印
|
||||
auto gepInst = dynamic_cast<GetElementPtrInst*>(pInst);
|
||||
std::cout << "%" << gepInst->getName() << " = getelementptr inbounds "; // 假设总是 inbounds
|
||||
|
||||
// GEP 的第一个操作数是基指针,其类型是一个指向聚合类型的指针
|
||||
// 第一个参数是基指针所指向的聚合类型的类型 (e.g., [10 x i32])
|
||||
auto basePtrType = dynamic_cast<PointerType*>(gepInst->getBasePointer()->getType());
|
||||
printType(basePtrType->getBaseType()); // 打印基指针指向的类型
|
||||
|
||||
std::cout << ", ";
|
||||
printType(gepInst->getBasePointer()->getType()); // 打印基指针自身的类型 (e.g., [10 x i32]*)
|
||||
std::cout << " ";
|
||||
printValue(gepInst->getBasePointer()); // 打印基指针
|
||||
|
||||
// 打印所有索引
|
||||
for (auto indexVal : gepInst->getIndices()) { // 使用 getIndices() 迭代器
|
||||
std::cout << ", ";
|
||||
printType(indexVal->getValue()->getType()); // 打印索引的类型 (通常是 i32)
|
||||
std::cout << " ";
|
||||
printValue(indexVal->getValue()); // 打印索引值
|
||||
}
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kMemset: {
|
||||
auto memsetInst = dynamic_cast<MemsetInst *>(pInst);
|
||||
std::cout << "call void @llvm.memset.p0.";
|
||||
printType(memsetInst->getPointer()->getType());
|
||||
std::cout << "(";
|
||||
printType(memsetInst->getPointer()->getType());
|
||||
std::cout << " ";
|
||||
printValue(memsetInst->getPointer());
|
||||
std::cout << ", i8 ";
|
||||
printValue(memsetInst->getValue());
|
||||
std::cout << ", i32 ";
|
||||
printValue(memsetInst->getSize());
|
||||
std::cout << ", i1 false)" << std::endl; // alignment for memset is typically i1
|
||||
} break;
|
||||
|
||||
case Kind::kPhi: {
|
||||
auto phiInst = dynamic_cast<PhiInst *>(pInst);
|
||||
// Phi 指令的名称通常是结果变量
|
||||
std::cout << "%" << phiInst->getName() << " = phi ";
|
||||
printType(phiInst->getType()); // Phi 结果类型
|
||||
|
||||
// Phi 指令的操作数是成对的 [value, basic_block]
|
||||
// 这里假设 getOperands() 返回的是 (val1, block1, val2, block2...)
|
||||
// 如果你的 PhiInst 存储方式是 getIncomingValues() 和 getIncomingBlocks(),请相应调整
|
||||
// LLVM IR 格式: phi type [value1, block1], [value2, block2]
|
||||
bool firstPair = true;
|
||||
for (unsigned i = 0; i < phiInst->getNumIncomingValues(); ++i) { // 遍历成对的操作数
|
||||
if (!firstPair) std::cout << ", ";
|
||||
firstPair = false;
|
||||
std::cout << "[ ";
|
||||
printValue(phiInst->getValue(i));
|
||||
std::cout << ", %";
|
||||
printBlock(phiInst->getBlock(i));
|
||||
std::cout << " ]";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
// 以下两个 Kind 应该删除或替换为 kGEP
|
||||
// case Kind::kLa: { /* REMOVED */ } break;
|
||||
// case Kind::kGetSubArray: { /* REMOVED */ } break;
|
||||
|
||||
default:
|
||||
assert(false && "Unsupported instruction kind in SysYPrinter");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@ -13,18 +13,16 @@ using namespace antlr4;
|
||||
|
||||
#include "SysYIRGenerator.h"
|
||||
#include "SysYIRPrinter.h"
|
||||
#include "SysYIROptPre.h"
|
||||
#include "SysYIRCFGOpt.h" // 包含 CFG 优化
|
||||
#include "RISCv64Backend.h"
|
||||
#include "SysYIRAnalyser.h"
|
||||
// #include "DeadCodeElimination.h"
|
||||
#include "AddressCalculationExpansion.h"
|
||||
// #include "Mem2Reg.h"
|
||||
// #include "Reg2Mem.h"
|
||||
#include "Pass.h" // 包含新的 Pass 框架
|
||||
|
||||
using namespace sysy;
|
||||
|
||||
int DEBUG = 0;
|
||||
int DEEPDEBUG = 0;
|
||||
int DEEPERDEBUG = 0;
|
||||
int DEBUGLENGTH = 50;
|
||||
|
||||
static string argStopAfter;
|
||||
static string argInputFile;
|
||||
@ -131,78 +129,16 @@ int main(int argc, char **argv) {
|
||||
if (argStopAfter == "ird") {
|
||||
DEBUG = 1; // 这里可能需要更精细地控制 DEBUG 的开启时机和范围
|
||||
}
|
||||
// 默认优化 pass (在所有优化级别都会执行)
|
||||
SysYOptPre optPre(moduleIR, builder);
|
||||
optPre.SysYOptimizateAfterIR();
|
||||
|
||||
ControlFlowAnalysis cfa(moduleIR);
|
||||
cfa.init();
|
||||
ActiveVarAnalysis ava;
|
||||
ava.init(moduleIR);
|
||||
|
||||
if (DEBUG) {
|
||||
cout << "=== After CFA & AVA (Default) ===\n";
|
||||
cout << "=== Init IR ===\n";
|
||||
SysYPrinter(moduleIR).printIR(); // 临时打印器用于调试
|
||||
}
|
||||
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";
|
||||
}
|
||||
// 创建 Pass 管理器并运行优化管道
|
||||
PassManager passManager(moduleIR, builder); // 创建 Pass 管理器
|
||||
// 好像都不用传递module和builder了,因为 PassManager 初始化了
|
||||
passManager.runOptimizationPipeline(moduleIR, builder, optLevel);
|
||||
|
||||
// 5. 根据 argStopAfter 决定后续操作
|
||||
// a) 如果指定停止在 IR 阶段,则打印最终 IR 并退出
|
||||
@ -218,8 +154,9 @@ int main(int argc, char **argv) {
|
||||
// 设置 DEBUG 模式(如果指定了 'asmd')
|
||||
if (argStopAfter == "asmd") {
|
||||
DEBUG = 1;
|
||||
// DEEPDEBUG = 1;
|
||||
DEEPDEBUG = 1;
|
||||
}
|
||||
|
||||
sysy::RISCv64CodeGen codegen(moduleIR); // 传入优化后的 moduleIR
|
||||
string asmCode = codegen.code_gen();
|
||||
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
//test add
|
||||
|
||||
int main(){
|
||||
int a, b;
|
||||
a = 10;
|
||||
b = 2;
|
||||
return a + b;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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];
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user