Compare commits
212 Commits
deploy-202
...
midend-m2r
| Author | SHA1 | Date | |
|---|---|---|---|
| d465fb02a5 | |||
| 3c49183280 | |||
| 7af3827098 | |||
| 1ab937961f | |||
| 06b4df79ee | |||
| d79857feb9 | |||
| 91d4a39c9a | |||
| 042b1a5d99 | |||
| 0fdcd0dd69 | |||
| d7bf4b061f | |||
| 937833117e | |||
| 094b4c7c39 | |||
| f4617b357e | |||
| babb576317 | |||
| 0720a622c1 | |||
| ad74e435ba | |||
| acb0302a29 | |||
| 5c34cbc7b8 | |||
| c9a0c700e1 | |||
| b57a3f1953 | |||
| f317010d76 | |||
| 8ca64610eb | |||
| 969a78a088 | |||
| d77aedaf8b | |||
| 8763c0a11a | |||
| d83dc7a2e7 | |||
| e32585fd25 | |||
| 07fd22def1 | |||
| c4eb1c3980 | |||
| 5ef01ada90 | |||
| 072cd3e9b5 | |||
| d038884ffb | |||
| 467f2f6b24 | |||
| 7be5d25372 | |||
| fdba73d5e1 | |||
| 8cabb1f195 | |||
| fa33bf5134 | |||
| a3435e7c26 | |||
| 7547d34598 | |||
| 06a368db39 | |||
| 48865fa805 | |||
| 8b5123460b | |||
| cd27f5fda9 | |||
| 60cb8d6e49 | |||
| ea944f6ba0 | |||
| 0c8a156485 | |||
| debda205cc | |||
| baef82677b | |||
| f634273852 | |||
| 70f6a25ebc | |||
| 8cb807c8b9 | |||
| 1fab6a43f9 | |||
| 1e3791a801 | |||
| a1cca3c95a | |||
| 1361156b0d | |||
| 46179e3866 | |||
| 038552f58b | |||
| 4d0e2d73ea | |||
| ad19a6715f | |||
| d1ba140657 | |||
| 2c5e4cead1 | |||
| 6b92020bc4 | |||
| c867bda9b4 | |||
| 6b9ad0566d | |||
| 6a7355ed28 | |||
| be9ac89584 | |||
| ac3358d7e3 | |||
| a958435836 | |||
| bd23f6154d | |||
| 126c38a1d9 | |||
| c4c91412d1 | |||
| f17e44f8d4 | |||
| a406e44df3 | |||
| b1a46b7d58 | |||
| bd02f5f1eb | |||
| c507b98199 | |||
| ba21bb3203 | |||
| 8aa5ba692f | |||
| d732800149 | |||
| f083e38615 | |||
| 37f2a01783 | |||
| 5d343f42a5 | |||
| a4406e0112 | |||
| 08fcda939b | |||
| 33ca8ecf34 | |||
| d439ef7e8e | |||
| 3ba12bf320 | |||
| 167c2ac2ae | |||
| 32684d8255 | |||
| f2477c4af3 | |||
| b1efd481b4 | |||
| 676880ca05 | |||
| df50eedaeb | |||
| dcc075b39c | |||
| f7f1cf2b41 | |||
| 881c2a9723 | |||
| 5f63554ca3 | |||
| b5f14d9385 | |||
| 72b06c67ca | |||
| 4db3cc3fb5 | |||
| 17f1bed310 | |||
| b848ffca5a | |||
| 603506d142 | |||
| 0179c13cf4 | |||
| 7e5f6800b7 | |||
| 64ba25a77e | |||
| 208d5528b5 | |||
| a269366ac5 | |||
| 1b9a7a4827 | |||
| b2c2f3289d | |||
| 0ecd47f0ac | |||
| 6550c8a25b | |||
| f24cc7ec88 | |||
| c8a8bf9a37 | |||
| 446a6a6fcb | |||
| d8b004e5e5 | |||
| cd814de495 | |||
| e4ad23a1a5 | |||
| 58c8cd53f5 | |||
| ec91a4e259 | |||
| 91f755959b | |||
| 92c89f7616 | |||
| 66047dc6a3 | |||
| 22cf18a1d6 | |||
| 19a433c94f | |||
| 45dfbc8d59 | |||
| ef9d7c4d03 | |||
| f8e423f579 | |||
| 5b43f208ac | |||
| 845f969c2e | |||
| 9c5d9ea78c | |||
| 0ce742a86e | |||
| 1c7c85dd2f | |||
| f312792fe9 | |||
| 32ea24df56 | |||
| a1cf60c420 | |||
| f879a0f521 | |||
| aa7f2bb0f5 | |||
| 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 | |||
| 535a935bf1 | |||
| efe74cba6c |
1
.gitignore
vendored
1
.gitignore
vendored
@ -36,6 +36,7 @@ doxygen
|
||||
|
||||
!/testdata/functional/*.out
|
||||
!/testdata/h_functional/*.out
|
||||
!/testdata/performance/*.out
|
||||
build/
|
||||
.antlr
|
||||
.vscode/
|
||||
|
||||
425
Pass_ID_List.md
425
Pass_ID_List.md
@ -3,4 +3,427 @@
|
||||
| 名称 | 优化级别 | 开发进度 |
|
||||
| ------------ | ------------ | ---------- |
|
||||
| CFG优化 | 函数级 | 已完成 |
|
||||
| DCE | 函数级 | 待测试 |
|
||||
| DCE | 函数级 | 待正确性测试 |
|
||||
| Mem2Reg | 函数级 | 待正确性测试 |
|
||||
| Reg2Mem | 函数级 | 待正确性测试 |
|
||||
|
||||
|
||||
# 部分优化遍的说明
|
||||
|
||||
## Mem2Reg
|
||||
|
||||
Mem2Reg 遍的主要目标是将那些不必要的、只用于局部标量变量的内存分配 (alloca 指令) 消除,并将这些变量的值转换为 SSA 形式。这有助于减少内存访问,提高代码效率,并为后续的优化创造更好的条件。
|
||||
|
||||
通过Mem2Reg理解删除指令时对use关系的维护:
|
||||
|
||||
在 `Mem2Reg` 优化遍中,当 `load` 和 `store` 指令被删除时,其 `use` 关系(即它们作为操作数与其他 `Value` 对象之间的连接)的正确消除是一个关键问题,尤其涉及到 `AllocaInst`。
|
||||
|
||||
结合您提供的 `Mem2RegContext::renameVariables` 代码和我们之前讨论的 `usedelete` 逻辑,下面是 `use` 关系如何被正确消除的详细过程:
|
||||
|
||||
### 问题回顾:`Use` 关系的双向性
|
||||
|
||||
在您的 IR 设计中,`Use` 对象扮演着连接 `User`(使用者,如 `LoadInst`)和 `Value`(被使用者,如 `AllocaInst`)的双向角色:
|
||||
|
||||
* 一个 `User` 持有对其操作数 `Value` 的 `Use` 对象(通过 `User::operands` 列表)。
|
||||
* 一个 `Value` 持有所有使用它的 `User` 的 `Use` 对象(通过 `Value::uses` 列表)。
|
||||
|
||||
原始问题是:当一个 `LoadInst` 或 `StoreInst` 被删除时,如果不对其作为操作数与 `AllocaInst` 之间的 `Use` 关系进行明确清理,`AllocaInst` 的 `uses` 列表中就会留下指向已删除 `LoadInst` / `StoreInst` 的 `Use` 对象,导致内部的 `User*` 指针悬空,在后续访问时引发 `segmentation fault`。
|
||||
|
||||
### `Mem2Reg` 中 `load`/`store` 指令的删除行为
|
||||
|
||||
在 `Mem2RegContext::renameVariables` 函数中,`load` 和 `store` 指令被处理时,其行为如下:
|
||||
|
||||
1. **处理 `LoadInst`:**
|
||||
当找到一个指向可提升 `AllocaInst` 的 `LoadInst` 时,其用途会被 `replaceAllUsesWith(allocaToValueStackMap[alloca].top())` 替换。这意味着任何原本使用 `LoadInst` 本身计算结果的指令,现在都直接使用 SSA 值栈顶部的 `Value`。
|
||||
**重点:** 这一步处理的是 `LoadInst` 作为**被使用的值 (Value)** 时,其 `uses` 列表的清理。即,将 `LoadInst` 的所有使用者重定向到新的 SSA 值,并把这些 `Use` 对象从 `LoadInst` 的 `uses` 列表中移除。
|
||||
|
||||
2. **处理 `StoreInst`:**
|
||||
当找到一个指向可提升 `AllocaInst` 的 `StoreInst` 时,`StoreInst` 存储的值会被压入值栈。`StoreInst` 本身并不产生可被其他指令直接使用的值(其类型是 `void`),所以它没有 `uses` 列表需要替换。
|
||||
**重点:** `StoreInst` 的主要作用是更新内存状态,在 SSA 形式下,它被移除后需要清理它作为**使用者 (User)** 时的操作数关系。
|
||||
|
||||
在这两种情况下,一旦 `load` 或 `store` 指令的 SSA 转换完成,它们都会通过 `instIter = SysYIROptUtils::usedelete(instIter)` 被显式删除。
|
||||
|
||||
### `SysYIROptUtils::usedelete` 如何正确消除 `Use` 关系
|
||||
|
||||
关键在于对 `SysYIROptUtils::usedelete` 函数的修改,使其在删除指令时,同时处理该指令作为 `User` 和 `Value` 的两种 `Use` 关系:
|
||||
|
||||
1. **清理指令作为 `Value` 时的 `uses` 列表 (由 `replaceAllUsesWith` 完成):**
|
||||
在 `usedelete` 函数中,`inst->replaceAllUsesWith(UndefinedValue::get(inst->getType()))` 的调用至关重要。这确保了:
|
||||
* 如果被删除的 `Instruction`(例如 `LoadInst`)产生了结果值并被其他指令使用,所有这些使用者都会被重定向到 `UndefinedValue`(或者 `Mem2Reg` 中具体的 SSA 值)。
|
||||
* 这个过程会遍历 `LoadInst` 的 `uses` 列表,并将这些 `Use` 对象从 `LoadInst` 的 `uses` 列表中移除。这意味着 `LoadInst` 自己不再被任何其他指令使用。
|
||||
|
||||
2. **清理指令作为 `User` 时其操作数的 `uses` 列表 (由 `RemoveUserOperandUses` 完成):**
|
||||
这是您提出的、并已集成到 `usedelete` 中的关键改进点。对于一个被删除的 `Instruction`(它同时也是 `User`),我们需要清理它**自己使用的操作数**所维护的 `use` 关系。
|
||||
* 例如,`LoadInst %op1` 使用了 `%op1`(一个 `AllocaInst`)。当 `LoadInst` 被删除时,`AllocaInst` 的 `uses` 列表中有一个 `Use` 对象指向这个 `LoadInst`。
|
||||
* `RemoveUserOperandUses` 函数会遍历被删除 `User`(即 `LoadInst` 或 `StoreInst`)的 `operands` 列表。
|
||||
* 对于 `operands` 列表中的每个 `std::shared_ptr<Use> use_ptr`,它会获取 `Use` 对象内部指向的 `Value`(例如 `AllocaInst*`),然后调用 `value->removeUse(use_ptr)`。
|
||||
* 这个 `removeUse` 调用会负责将 `use_ptr` 从 `AllocaInst` 的 `uses` 列表中删除。
|
||||
|
||||
### 总结
|
||||
|
||||
通过在 `SysYIROptUtils::usedelete` 中同时执行这两个步骤:
|
||||
|
||||
* `replaceAllUsesWith`:处理被删除指令**作为结果被使用**时的 `use` 关系。
|
||||
* `RemoveUserOperandUses`:处理被删除指令**作为使用者(User)时,其操作数**的 `use` 关系。
|
||||
|
||||
这就确保了当 `Mem2Reg` 遍历并删除 `load` 和 `store` 指令时,无论是它们作为 `Value` 的使用者,还是它们作为 `User` 的操作数,所有相关的 `Use` 对象都能被正确地从 `Value` 的 `uses` 列表中移除,从而避免了悬空指针和后续的 `segmentation fault`。
|
||||
|
||||
最后,当所有指向某个 `AllocaInst` 的 `load` 和 `store` 指令都被移除后,`AllocaInst` 的 `uses` 列表将变得干净(只包含 Phi 指令,如果它们在 SSA 转换中需要保留 Alloca 作为操作数),这时在 `Mem2RegContext::cleanup()` 阶段,`SysYIROptUtils::usedelete(alloca)` 就可以安全地删除 `AllocaInst` 本身了。
|
||||
|
||||
## Reg2Mem
|
||||
|
||||
我们的Reg2Mem 遍的主要目标是作为 Mem2Reg 的一种逆操作,但更具体是解决后端无法识别 PhiInst 指令的问题。主要的速录是将函数参数和 PhiInst 指令的结果从 SSA 形式转换回内存形式,通过插入 alloca、load 和 store 指令来实现。其他非 Phi 的指令结果将保持 SSA 形式。
|
||||
|
||||
## SCCP
|
||||
|
||||
SCCP(稀疏条件常量传播)是一种编译器优化技术,它结合了常量传播和死代码消除。其核心思想是在程序执行过程中,尝试识别并替换那些在编译时就能确定其值的变量(常量),同时移除那些永远不会被执行到的代码块(不可达代码)。
|
||||
|
||||
以下是 SCCP 的实现思路:
|
||||
|
||||
1. 核心数据结构与工作列表:
|
||||
|
||||
Lattice 值(Lattice Value): SCCP 使用三值格(Three-Valued Lattice)来表示变量的状态:
|
||||
|
||||
Top (T): 初始状态,表示变量的值未知,但可能是一个常量。
|
||||
|
||||
Constant (C): 表示变量的值已经确定为一个具体的常量。
|
||||
|
||||
Bottom (⊥): 表示变量的值不确定或不是一个常量(例如,它可能在运行时有多个不同的值,或者从内存中加载)。一旦变量状态变为 Bottom,它就不能再变回 Constant 或 Top。
|
||||
|
||||
SSAPValue: 封装了 Lattice 值和常量具体值(如果状态是 Constant)。
|
||||
|
||||
*valState (map<Value, SSAPValue>):** 存储程序中每个 Value(变量、指令结果等)的当前 SCCP Lattice 状态。
|
||||
|
||||
*ExecutableBlocks (set<BasicBlock>):** 存储在分析过程中被确定为可执行的基本块。
|
||||
|
||||
工作列表 (Worklists):
|
||||
|
||||
cfgWorkList (queue<pair<BasicBlock, BasicBlock>>):** 存储待处理的控制流图(CFG)边。当一个块被标记为可执行时,它的后继边会被添加到这个列表。
|
||||
|
||||
*ssaWorkList (queue<Instruction>):** 存储待处理的 SSA (Static Single Assignment) 指令。当一个指令的任何操作数的状态发生变化时,该指令就会被添加到这个列表,需要重新评估。
|
||||
|
||||
2. 初始化:
|
||||
|
||||
所有 Value 的状态都被初始化为 Top。
|
||||
|
||||
所有基本块都被初始化为不可执行。
|
||||
|
||||
函数的入口基本块被标记为可执行,并且该块中的所有指令被添加到 ssaWorkList。
|
||||
|
||||
3. 迭代过程 (Fixed-Point Iteration):
|
||||
|
||||
SCCP 的核心是一个迭代过程,它交替处理 CFG 工作列表和 SSA 工作列表,直到达到一个不动点(即没有更多的状态变化)。
|
||||
|
||||
处理 cfgWorkList:
|
||||
|
||||
从 cfgWorkList 中取出一个边 (prev, next)。
|
||||
|
||||
如果 next 块之前是不可执行的,现在通过 prev 块可达,则将其标记为可执行 (markBlockExecutable)。
|
||||
|
||||
一旦 next 块变为可执行,其内部的所有指令(特别是 Phi 指令)都需要被重新评估,因此将它们添加到 ssaWorkList。
|
||||
|
||||
处理 ssaWorkList:
|
||||
|
||||
从 ssaWorkList 中取出一个指令 inst。
|
||||
|
||||
重要: 只有当 inst 所在的块是可执行的,才处理该指令。不可执行块中的指令不参与常量传播。
|
||||
|
||||
计算新的 Lattice 值 (computeLatticeValue): 根据指令类型和其操作数的当前 Lattice 状态,计算 inst 的新的 Lattice 状态。
|
||||
|
||||
常量折叠: 如果所有操作数都是常量,则可以直接执行运算并得到一个新的常量结果。
|
||||
|
||||
Bottom 传播: 如果任何操作数是 Bottom,或者运算规则导致不确定(例如除以零),则结果为 Bottom。
|
||||
|
||||
Phi 指令的特殊处理: Phi 指令的值取决于其所有可执行的前驱块传入的值。
|
||||
|
||||
如果所有可执行前驱都提供了相同的常量 C,则 Phi 结果为 C。
|
||||
|
||||
如果有任何可执行前驱提供了 Bottom,或者不同的可执行前驱提供了不同的常量,则 Phi 结果为 Bottom。
|
||||
|
||||
如果所有可执行前驱都提供了 Top,则 Phi 结果仍为 Top。
|
||||
|
||||
更新状态: 如果 inst 的新计算出的 Lattice 值与它当前存储的值不同,则更新 valState[inst]。
|
||||
|
||||
传播变化: 如果 inst 的状态发生变化,那么所有使用 inst 作为操作数的指令都可能受到影响,需要重新评估。因此,将 inst 的所有使用者添加到 ssaWorkList。
|
||||
|
||||
处理终结符指令 (BranchInst, ReturnInst):
|
||||
|
||||
对于条件分支 BranchInst,如果其条件操作数变为常量:
|
||||
|
||||
如果条件为真,则只有真分支的目标块是可达的,将该边添加到 cfgWorkList。
|
||||
|
||||
如果条件为假,则只有假分支的目标块是可达的,将该边添加到 cfgWorkList。
|
||||
|
||||
如果条件不是常量(Top 或 Bottom),则两个分支都可能被执行,将两边的边都添加到 cfgWorkList。
|
||||
|
||||
这会影响 CFG 的可达性分析,可能导致新的块被标记为可执行。
|
||||
|
||||
4. 应用优化 (Transformation):
|
||||
|
||||
当两个工作列表都为空,达到不动点后,程序代码开始进行实际的修改:
|
||||
|
||||
常量替换:
|
||||
|
||||
遍历所有指令。如果指令的 valState 为 Constant,则用相应的 ConstantValue 替换该指令的所有用途 (replaceAllUsesWith)。
|
||||
|
||||
将该指令标记为待删除。
|
||||
|
||||
对于指令的操作数,如果其 valState 为 Constant,则直接将操作数替换为对应的 ConstantValue(常量折叠)。
|
||||
|
||||
删除死指令: 遍历所有标记为待删除的指令,并从其父基本块中删除它们。
|
||||
|
||||
删除不可达基本块: 遍历函数中的所有基本块。如果一个基本块没有被标记为可执行 (ExecutableBlocks 中不存在),则将其从函数中删除。但入口块不能删除。
|
||||
|
||||
简化分支指令:
|
||||
|
||||
遍历所有可执行的基本块的终结符指令。
|
||||
|
||||
对于条件分支 BranchInst,如果其条件操作数在 valState 中是 Constant:
|
||||
|
||||
如果条件为真,则将该条件分支替换为一个无条件跳转到真分支目标块的指令。
|
||||
|
||||
如果条件为假,则将该条件分支替换为一个无条件跳转到假分支目标块的指令。
|
||||
|
||||
更新 CFG,移除不可达的分支边和其前驱信息。
|
||||
|
||||
computeLatticeValue 的具体逻辑:
|
||||
|
||||
这个函数是 SCCP 的核心逻辑,它定义了如何根据指令类型和操作数的当前 Lattice 状态来计算指令结果的 Lattice 状态。
|
||||
|
||||
二元运算 (Add, Sub, Mul, Div, Rem, ICmp, And, Or):
|
||||
|
||||
如果任何一个操作数是 Bottom,结果就是 Bottom。
|
||||
|
||||
如果任何一个操作数是 Top,结果就是 Top。
|
||||
|
||||
如果两个操作数都是 Constant,执行实际的常量运算,结果是一个新的 Constant。
|
||||
|
||||
一元运算 (Neg, Not):
|
||||
|
||||
如果操作数是 Bottom,结果就是 Bottom。
|
||||
|
||||
如果操作数是 Top,结果就是 Top。
|
||||
|
||||
如果操作数是 Constant,执行实际的常量运算,结果是一个新的 Constant。
|
||||
|
||||
Load 指令: 通常情况下,Load 的结果会被标记为 Bottom,因为内存内容通常在编译时无法确定。但如果加载的是已知的全局常量,可能可以确定。在提供的代码中,它通常返回 Bottom。
|
||||
|
||||
Store 指令: Store 不产生值,所以其 SSAPValue 保持 Top 或不关心。
|
||||
|
||||
Call 指令: 大多数 Call 指令(尤其是对外部或有副作用的函数)的结果都是 Bottom。对于纯函数,如果所有参数都是常量,理论上可以折叠,但这需要额外的分析。
|
||||
|
||||
GetElementPtr (GEP) 指令: GEP 计算内存地址。如果所有索引都是常量,地址本身是常量。但 SCCP 关注的是数据值,因此这里通常返回 Bottom,除非有特定的指针常量跟踪。
|
||||
|
||||
Phi 指令: 如上所述,基于所有可执行前驱的传入值进行聚合。
|
||||
|
||||
Alloc 指令: Alloc 分配内存,返回一个指针。其内容通常是 Bottom。
|
||||
|
||||
Branch 和 Return 指令: 这些是终结符指令,不产生一个可用于其他指令的值,通常 SSAPValue 保持 Top 或不关心。
|
||||
|
||||
类型转换 (ZExt, SExt, Trunc, FtoI, ItoF): 如果操作数是 Constant,则执行相应的类型转换,结果仍为 Constant。对于浮点数转换,由于 SSAPValue 的 constantVal 为 int 类型,所以对浮点数的操作会保守地返回 Bottom。
|
||||
|
||||
未处理的指令: 默认情况下,任何未明确处理的指令都被保守地假定为产生 Bottom 值。
|
||||
|
||||
浮点数处理的注意事项:
|
||||
|
||||
在提供的代码中,SSAPValue 的 constantVal 是 int 类型。这使得浮点数常量传播变得复杂。对于浮点数相关的指令(kFAdd, kFMul, kFCmp, kFNeg, kFNot, kItoF, kFtoI 等),如果不能将浮点值准确地存储在 int 中,或者不能可靠地执行浮点运算,那么通常会保守地将结果设置为 Bottom。一个更完善的 SCCP 实现会使用 std::variant<int, float> 或独立的浮点常量存储来处理浮点数。
|
||||
|
||||
## LoopSR循环归纳变量强度削弱 关于魔数计算的说明
|
||||
|
||||
魔数除法的核心思想是:将除法转换为乘法和移位
|
||||
|
||||
数学原理:x / d ≈ (x * m) >> (32 + s)
|
||||
|
||||
m 是魔数 (magic number)
|
||||
s 是额外的移位量 (shift)
|
||||
>> 是算术右移
|
||||
|
||||
2^(32+s) / d ≤ m < 2^(32+s) / d + 2^s / d
|
||||
|
||||
cd /home/downright/Compiler_Opt/mysysy && python3 -c "
|
||||
# 真正的迭代原因:精度要求
|
||||
def explain_precision_requirement():
|
||||
d = 10
|
||||
|
||||
print('魔数算法需要找到精确的边界值:')
|
||||
print('目标:2^p > d * (2^31 - r),其中r是余数')
|
||||
print()
|
||||
|
||||
# 模拟我们算法的迭代过程
|
||||
p = 31
|
||||
two_p = 2**p
|
||||
r = two_p % d # 余数
|
||||
m = two_p // d # 商
|
||||
|
||||
print(f'初始状态 (p={p}):')
|
||||
print(f' 2^{p} = {two_p:,}')
|
||||
print(f' 2^{p} / {d} = {m:,} 余 {r}')
|
||||
print(f' 需要检查: 2^{p} > {d} * (2^31 - {r}) = {d * (2**31 - r):,}')
|
||||
print(f' 条件满足: {two_p > d * (2**31 - r)}')
|
||||
print()
|
||||
|
||||
# 继续迭代直到条件满足
|
||||
iteration = 0
|
||||
while r != 0 and m < 2**31:
|
||||
iteration += 1
|
||||
p += 1
|
||||
two_p *= 2
|
||||
m *= 2
|
||||
r *= 2
|
||||
if r >= d:
|
||||
m += 1
|
||||
r -= d
|
||||
|
||||
print(f'迭代 {iteration} (p={p}):')
|
||||
print(f' m = {m:,}, r = {r}')
|
||||
print(f' m < 2^31? {m < 2**31} (2^31 = {2**31:,})')
|
||||
|
||||
if m >= 2**31:
|
||||
print(f' ✗ 魔数 {m:,} 超出32位范围!')
|
||||
break
|
||||
elif r == 0:
|
||||
print(f' ✓ 余数为0,找到精确解')
|
||||
break
|
||||
|
||||
if iteration > 10: # 防止无限循环
|
||||
print(' ... (限制迭代次数)')
|
||||
break
|
||||
|
||||
explain_precision_requirement()
|
||||
"
|
||||
|
||||
问题在于精度要求。理论魔数需要非常精确,不能简单地用 2^32 / d。让我展示真正的迭代原因:
|
||||
|
||||
cd /home/downright/Compiler_Opt/mysysy && python3 -c "
|
||||
# 真正的迭代原因:精度要求
|
||||
def explain_precision_requirement():
|
||||
d = 10
|
||||
|
||||
print('魔数算法需要找到精确的边界值:')
|
||||
print('目标:2^p > d * (2^31 - r),其中r是余数')
|
||||
print()
|
||||
|
||||
# 模拟我们算法的迭代过程
|
||||
p = 31
|
||||
two_p = 2**p
|
||||
r = two_p % d # 余数
|
||||
m = two_p // d # 商
|
||||
|
||||
print(f'初始状态 (p={p}):')
|
||||
print(f' 2^{p} = {two_p:,}')
|
||||
print(f' 2^{p} / {d} = {m:,} 余 {r}')
|
||||
print(f' 需要检查: 2^{p} > {d} * (2^31 - {r}) = {d * (2**31 - r):,}')
|
||||
print(f' 条件满足: {two_p > d * (2**31 - r)}')
|
||||
print()
|
||||
|
||||
# 继续迭代直到条件满足
|
||||
iteration = 0
|
||||
while r != 0 and m < 2**31:
|
||||
iteration += 1
|
||||
p += 1
|
||||
two_p *= 2
|
||||
m *= 2
|
||||
r *= 2
|
||||
if r >= d:
|
||||
m += 1
|
||||
r -= d
|
||||
|
||||
print(f'迭代 {iteration} (p={p}):')
|
||||
print(f' m = {m:,}, r = {r}')
|
||||
print(f' m < 2^31? {m < 2**31} (2^31 = {2**31:,})')
|
||||
|
||||
if m >= 2**31:
|
||||
print(f' ✗ 魔数 {m:,} 超出32位范围!')
|
||||
break
|
||||
elif r == 0:
|
||||
print(f' ✓ 余数为0,找到精确解')
|
||||
break
|
||||
|
||||
if iteration > 10: # 防止无限循环
|
||||
print(' ... (限制迭代次数)')
|
||||
break
|
||||
|
||||
explain_precision_requirement()
|
||||
"
|
||||
|
||||
|
||||
cd /home/downright/Compiler_Opt/mysysy && python3 -c "
|
||||
# 检查初始状态是否会溢出
|
||||
def check_initial_overflow():
|
||||
int32_max = 2**31 - 1
|
||||
|
||||
print('检查不同除数的初始魔数是否会溢出:')
|
||||
print(f'32位有符号整数最大值: {int32_max:,}')
|
||||
print()
|
||||
|
||||
# 检查各种除数
|
||||
divisors = [2, 3, 5, 7, 9, 10, 11, 13, 17, 25, 100, 1000]
|
||||
|
||||
for d in divisors:
|
||||
# 初始魔数 = 2^31 / d
|
||||
initial_magic = (2**31) // d
|
||||
|
||||
overflow = initial_magic > int32_max
|
||||
status = \"溢出\" if overflow else \"安全\"
|
||||
|
||||
print(f'd={d:4d}: 初始魔数 = 2^31/{d} = {initial_magic:10,} [{status}]')
|
||||
|
||||
print()
|
||||
print('结论: 初始状态下魔数不会溢出,溢出发生在迭代过程中')
|
||||
|
||||
check_initial_overflow()
|
||||
"
|
||||
|
||||
总结
|
||||
迭代的必要性:
|
||||
|
||||
不是为了避免初始溢出(初始状态安全)
|
||||
是为了找到最精确的魔数,减少舍入误差
|
||||
每次迭代提高一倍精度,但魔数也翻倍
|
||||
溢出发生时机:
|
||||
|
||||
初始状态:2^31 / d 总是在32位范围内
|
||||
迭代过程:2^32 / d, 2^33 / d, ... 逐渐超出32位范围
|
||||
回退值的正确性:
|
||||
|
||||
回退值是基于数学理论和实践验证的标准值
|
||||
来自LLVM、GCC等成熟编译器的实现
|
||||
通过测试验证,对各种输入都能产生正确结果
|
||||
算法设计哲学:
|
||||
|
||||
先尝试最优解:通过迭代寻找最精确的魔数
|
||||
检测边界条件:当超出32位范围时及时发现
|
||||
智能回退:使用已验证的标准值保证正确性
|
||||
保持通用性:对于没有预设值的除数仍然可以工作
|
||||
|
||||
## 死归纳变量消除
|
||||
|
||||
整体架构和工作流程
|
||||
当前的归纳变量消除优化分为三个清晰的阶段:
|
||||
|
||||
识别阶段:找出所有潜在的死归纳变量
|
||||
安全性分析阶段:验证每个变量消除的安全性
|
||||
消除执行阶段:实际删除安全的死归纳变量
|
||||
|
||||
|
||||
逃逸点检测 (已修复的关键安全机制)
|
||||
数组索引检测:GEP指令被正确识别为逃逸点
|
||||
循环退出条件:用于比较和条件分支的归纳变量不会被消除
|
||||
控制流指令:condBr、br、return等被特殊处理为逃逸点
|
||||
内存操作:store/load指令经过别名分析检查
|
||||
|
||||
# 后续优化可能涉及的改动
|
||||
|
||||
## 1)将所有的alloca集中到entryblock中(已实现)
|
||||
|
||||
好处:优化友好性,方便mem2reg提升
|
||||
目前没有实现这个机制,如果想要实现首先解决同一函数不同域的同名变量命名区分
|
||||
需要保证符号表能正确维护域中的局部变量
|
||||
|
||||
|
||||
# 关于中端优化提升编译器性能的TODO
|
||||
|
||||
## usedelete_withinstdelte方法
|
||||
|
||||
这个方法删除了use关系并移除了指令,逻辑是根据Instruction* inst去find对应的迭代器并erase
|
||||
有些情况下外部持有迭代器和inst,可以省略find过程
|
||||
266
doc/CompilerDesign.md
Normal file
266
doc/CompilerDesign.md
Normal file
@ -0,0 +1,266 @@
|
||||
# 编译器核心技术与优化详解
|
||||
|
||||
本文档深入剖析 mysysy 编译器的内部实现,重点阐述其在前端、中端和后端所采用的核心编译技术及优化算法,并结合具体实现函数进行说明。
|
||||
|
||||
## 1. 编译器整体架构
|
||||
|
||||
本编译器采用经典的三段式架构,将编译过程清晰地划分为前端、中端和后端三个主要部分。每个部分处理不同的抽象层级,并通过定义良好的接口(AST, IR)进行通信,实现了高度的模块化。
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[源代码 .sy] --> B{前端 Frontend};
|
||||
B --> C[抽象语法树 AST];
|
||||
C --> D{中端 Midend};
|
||||
D --> E[SSA-based IR];
|
||||
E -- 优化 --> F[优化后的 IR];
|
||||
F --> G{后端 Backend};
|
||||
G --> H[目标机代码 MachineInstr];
|
||||
H --> I[RISC-V 64 汇编代码 .s];
|
||||
|
||||
subgraph 前端
|
||||
B
|
||||
end
|
||||
subgraph 中端
|
||||
D
|
||||
end
|
||||
subgraph 后端
|
||||
G
|
||||
end
|
||||
```
|
||||
|
||||
- **前端 (Frontend)**:负责词法、语法、语义分析,将 SysY 源代码解析为抽象语法树 (AST)。
|
||||
- **中端 (Midend)**:基于 AST 生成与具体机器无关的中间表示 (IR),并在此基础上进行深入的分析和优化。
|
||||
- **后端 (Backend)**:将优化后的 IR 翻译成目标平台(RISC-V 64)的汇编代码。
|
||||
|
||||
---
|
||||
|
||||
## 2. 前端技术 (Frontend)
|
||||
|
||||
前端的核心任务是进行语法和语义的分析与验证,其工作流程如下:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph "前端处理流程"
|
||||
Source["源文件 (.sy)"] --> Lexer["词法分析器 (SysYLexer)"];
|
||||
Lexer --> TokenStream["Token 流"];
|
||||
TokenStream --> Parser["语法分析器 (SysYParser)"];
|
||||
Parser --> ParseTree["解析树"];
|
||||
ParseTree --> Visitor["AST构建 (SysYVisitor)"];
|
||||
Visitor --> AST[抽象语法树];
|
||||
end
|
||||
```
|
||||
|
||||
- **词法与语法分析**:
|
||||
- **技术**: 采用 **ANTLR (ANother Tool for Language Recognition)** 框架。通过在 `frontend/SysY.g4` 文件中定义的上下文无关文法,ANTLR 能够自动生成高效的 LL(*) 词法分析器 (`SysYLexer.cpp`) 和语法分析器 (`SysYParser.cpp`)。
|
||||
- **实现**: 词法分析器将字符流转换为记号 (Token) 流,语法分析器则根据文法规则将记号流组织成一棵解析树 (Parse Tree)。这棵树精确地反映了源代码的语法结构。
|
||||
|
||||
- **AST 构建**:
|
||||
- **技术**: 应用 **访问者 (Visitor) 设计模式** 遍历 ANTLR 生成的解析树。该模式将数据结构(解析树)与作用于其上的操作(AST构建逻辑)解耦。
|
||||
- **实现**: `frontend/SysYVisitor.cpp` 中定义了具体的遍历逻辑。在遍历过程中,会构建一个比解析树更抽象、更面向编译需求的**抽象语法树 (Abstract Syntax Tree, AST)**。AST 忽略了纯粹的语法细节(如括号、分号),只保留了核心的语义结构,是前端传递给中端的接口。
|
||||
|
||||
---
|
||||
|
||||
## 3. 中端技术与优化 (Midend)
|
||||
|
||||
中端是编译器的核心,所有与目标机器无关的分析和优化都在此阶段完成。
|
||||
|
||||
### 3.1. 中间表示 (IR) 及设计要点
|
||||
|
||||
- **技术**: 设计了一种三地址码(Three-Address Code)风格的中间表示,其形式和设计哲学深受 **LLVM IR** 的启发。IR 的核心特征是采用了**静态单赋值 (Static Single Assignment, SSA)** 形式。
|
||||
- **实现**: `midend/IR.cpp` 定义了 IR 的核心数据结构,如 `Instruction`, `BasicBlock`, `Function` 和 `Module`。`midend/SysYIRGenerator.cpp` 负责将前端的 AST 转换为这种 IR。在 SSA 形式下,每个变量只被赋值一次,使得变量的定义-使用关系(Def-Use Chain)变得异常清晰,极大地简化了后续的优化算法。通过继承并重写 SysYBaseVisitor 类,遍历 AST 节点生成自定义 IR,并在 IR 生成阶段实现了简单的常量传播和公共子表达式消除(CSE)。
|
||||
- **设计要点**:
|
||||
- **`alloca` 指令集中管理**:
|
||||
所有 `alloca` 指令统一放置在入口基本块,并与实际计算指令分离。这有助于后续指令调度器专注于优化计算密集型指令的执行顺序,避免内存分配指令的干扰。
|
||||
- **消除 `fallthrough` 现象**:
|
||||
通过确保所有基本块均以终结指令结尾,消除基本块间的 `fallthrough`,简化了控制流图(CFG)的构建和分析。这一做法提升了编译器整体质量,使中端各类 Pass 的编写和维护更加规范和高效。
|
||||
|
||||
### 3.2. 核心优化详解
|
||||
|
||||
编译器的分析和优化被组织成一系列独立的“遍”(Pass)。每个 Pass 都是一个独立的算法模块,对 IR 进行特定的分析或变换。这种设计具有高度的模块化和可扩展性。
|
||||
|
||||
#### 3.2.1. SSA 构建与解构
|
||||
|
||||
- **Mem2Reg (`Mem2Reg.cpp`)**:
|
||||
- **目标**: 将对栈内存 (`alloca`) 的 `load`/`store` 操作,提升为对虚拟寄存器的直接操作,并构建 SSA 形式。
|
||||
- **技术**: 该过程是实现 SSA 的关键。它依赖于**支配树 (Dominator Tree)** 分析,通过寻找变量定义块的**支配边界 (Dominance Frontier)** 来确定在何处插入 **Φ (Phi) 函数**。
|
||||
- **实现**: `Mem2RegContext::run` 驱动此过程。首先调用 `isPromotableAlloca` 识别所有仅被 `load`/`store` 使用的标量 `alloca`。然后,`insertPhis` 根据支配边界信息在必要的控制流汇合点插入 `phi` 指令。最后,`renameVariables` 递归地遍历支配树,用一个模拟的值栈来将 `load` 替换为栈顶的 SSA 值,将 `store` 视为对栈的一次 `push` 操作,从而完成重命名。值得一提的是,由于我们在IR生成阶段就将所有alloca指令统一放置在入口块,极大地简化了Mem2Reg遍的实现和支配树分析的计算。
|
||||
|
||||
- **Reg2Mem (`Reg2Mem.cpp`)**:
|
||||
- **目标**: 执行 `Mem2Reg` 的逆操作,将程序从 SSA 形式转换回基于内存的表示。这通常是为不支持 SSA 的后端做准备的**SSA解构 (SSA Destruction)** 步骤。
|
||||
- **技术**: 为每个 SSA 值(指令结果、函数参数)在函数入口创建一个 `alloca` 栈槽。然后,在每个 SSA 值的定义点之后插入一个 `store` 将其存入对应的栈槽;在每个使用点之前插入一个 `load` 从栈槽中取出值。
|
||||
- **实现**: `Reg2MemContext::run` 驱动此过程。`allocateMemoryForSSAValues` 为所有需要转换的 SSA 值创建 `alloca` 指令。`rewritePhis` 特殊处理 `phi` 指令,在每个前驱块的末尾插入 `store`。`insertLoadsAndStores` 则处理所有非 `phi` 指令的定义和使用,插入相应的 `store` 和 `load`。虽然
|
||||
|
||||
#### 3.2.2. 常量与死代码优化
|
||||
|
||||
- **SCCP (`SCCP.cpp`)**:
|
||||
- **目标**: 稀疏条件常量传播。在编译期计算常量表达式,并利用分支条件为常数的信息来消除死代码,比简单的常量传播更强大。
|
||||
- **技术**: 这是一种基于数据流分析的格理论(Lattice Theory)的优化。它为每个变量维护一个值状态,可能为 `Top` (未定义), `Constant` (某个常量值), 或 `Bottom` (非常量)。同时,它跟踪基本块的可达性,如果一个分支的条件被推断为常量,则其不可达的后继分支在分析中会被直接忽略。
|
||||
- **实现**: `SCCPContext::run` 驱动整个分析过程。它维护一个指令工作列表和一个边工作列表。`ProcessInstruction` 和 `ProcessEdge` 函数交替执行,不断地从 IR 中传播常量和可达性信息,直到达到不动点为止。最后,`PropagateConstants` 和 `SimplifyControlFlow` 将推断出的常量替换到代码中,并移除死块。
|
||||
|
||||
- **DCE (`DCE.cpp`)**:
|
||||
- **目标**: 简单死代码消除。移除那些计算结果对程序输出没有贡献的指令。
|
||||
- **技术**: 采用**标记-清除 (Mark and Sweep)** 算法。从具有副作用的指令(如 `store`, `call`, `return`)开始,反向追溯其操作数,标记所有相关的指令为“活跃”。
|
||||
- **实现**: `DCEContext::run` 实现了此算法。第一次遍历时,通过 `isAlive` 函数识别出具有副作用的“根”指令,然后调用 `addAlive` 递归地将所有依赖的指令加入 `alive_insts` 集合。第二次遍历时,所有未被标记为活跃的指令都将被删除。
|
||||
- **未来规划**: 后续开发更多分析遍会为DCE收集更多的IR信息,能够迭代出更健壮的DEC遍。
|
||||
|
||||
#### 3.2.3. 控制流图 (CFG) 优化
|
||||
|
||||
- **实现**: `SysYIRCFGOpt.cpp` 中定义了一系列用于清理和简化控制流图的 Pass。
|
||||
- **`SysYDelInstAfterBrPass`**: 删除分支指令后的死代码。
|
||||
- **`SysYDelNoPreBLockPass`**: 通过从入口块开始的图遍历(BFS),识别并删除所有不可达的基本块。
|
||||
- **`SysYDelEmptyBlockPass`**: 识别并删除仅包含一条无条件跳转指令的空块,将其前驱直接重定向到其后继。
|
||||
- **`SysYBlockMergePass`**: 如果一个块 A 只有一个后继 B,且 B 只有一个前驱 A,则将 A 和 B 合并为一个块。
|
||||
- **`SysYCondBr2BrPass`**: 如果一个条件分支的条件是常量,则将其转换为一个无条件分支。
|
||||
- **`SysYAddReturnPass`**: 确保所有没有终结指令的函数出口路径都有一个 `return` 指令,以保证 CFG 的完整性。
|
||||
|
||||
#### 3.2.4. 其他优化
|
||||
|
||||
#### 3.3. 核心分析遍
|
||||
|
||||
为了为优化遍收集信息,最大程度发掘程序优化潜力,我们目前设计并实现了以下关键的分析遍:
|
||||
|
||||
- **支配树分析 (Dominator Tree Analysis)**:
|
||||
- **技术**: 通过计算每个基本块的支配节点,构建出一棵支配树结构。我们在计算支配节点时采用了**逆后序遍历(RPO, Reverse Post Order)**,以保证数据流分析的收敛速度和正确性。在计算直接支配者(Idom, Immediate Dominator)时,采用了经典的**Lengauer-Tarjan(LT)算法**,该算法以高效的并查集和路径压缩技术著称,能够在线性时间内准确计算出每个基本块的直接支配者关系。
|
||||
- **实现**: `Dom.cpp` 实现了支配树分析。该分析为每个基本块分配其直接支配者,并递归构建整棵支配树。支配树是许多高级优化(尤其是 SSA 形式下的优化)的基础。例如,Mem2Reg 需要依赖支配树来正确插入 Phi 指令,并在变量重命名阶段高效遍历控制流图。此外,循环相关优化(如循环不变量外提)也依赖于支配树信息来识别循环头和循环体的关系。
|
||||
|
||||
- **活跃性分析 (Liveness Analysis)**:
|
||||
- **技术**: 活跃性分析用于确定在程序的某一特定点上,哪些变量的值在未来会被用到。我们采用**经典的不动点迭代算法**,在数据流分析框架下,逆序遍历基本块,迭代计算每个基本块的 `live-in` 和 `live-out` 集合,直到收敛为止。这种方法简单且易于实现,能够满足大多数编译优化的需求。
|
||||
- **未来规划**: 若后续对分析效率有更高要求,可考虑引入如**工作列表算法**或者**转化为基于SSA的图可达性分析**等更高效的算法,以进一步提升大型函数或复杂控制流下的分析性能。
|
||||
- **实现**: `Liveness.cpp` 提供了活跃性分析。该分析采用经典的数据流分析框架,迭代计算每个基本块的 `live-in` 和 `live-out` 集合。活跃性信息是死代码消除(DCE)、寄存器分配等优化的必要前置步骤。通过准确的活跃性分析,可以识别出无用的变量和指令,从而为后续优化遍提供坚实的数据基础。
|
||||
|
||||
### 3.4. 未来的规划
|
||||
|
||||
基于现有的成果,我们规划将中端能力进一步扩展,近期我们重点将放在循环相关的分析和函数内联的实现,以期大幅提升最终程序的性能。
|
||||
|
||||
- **循环优化**:
|
||||
我们正在开发一个健壮的分析遍来准确识别程序中的循环结构,并通过对已识别的循环进行规范化的转换遍,为后续的向量化、并行化工作做铺垫。并通过循环不变量提升、循环归纳变量分析与强度削减等优化提升循环相关代码的执行效率。
|
||||
- **函数内联**:
|
||||
函数内联能够将简单函数(可能需要收集更多信息)内联到call指令相应位置,减少栈空间相关变动,并且为其他遍发掘优化空间。
|
||||
- **`LLVM IR`格式化**:
|
||||
我们将为所有的IR设计并实现通用的打印器方法,使得IR能够显式化为可编译运行的LLVM IR,通过编排脚本和调用llvm相关工具链,我们能够绕过后端编译运行中间代码,为验证中端正确性提供系统化的方法,同时减轻后端开发bug溯源的压力。
|
||||
|
||||
---
|
||||
|
||||
## 4. 后端技术与优化 (Backend)
|
||||
|
||||
后端负责将经过优化的、与机器无关的 IR 转换为针对 RISC-V 64 位架构的汇编代码。
|
||||
|
||||
### 4.1. 栈帧布局 (Stack Frame Layout)
|
||||
|
||||
在函数调用发生时,后端需要在栈上创建一个**栈帧 (Stack Frame)** 来存储局部变量、传递参数和保存寄存器。本编译器采用的栈帧布局遵循 RISC-V 调用约定,结构如下:
|
||||
|
||||
```
|
||||
高地址 +-----------------------------+
|
||||
| ... |
|
||||
| 函数参数 (8+) | <-- 调用者传入的、放不进寄存器的参数
|
||||
+-----------------------------+
|
||||
| 返回地址 (ra) | <-- sp 在函数入口指向的位置
|
||||
+-----------------------------+
|
||||
| 旧的帧指针 (s0/fp) |
|
||||
+-----------------------------+ <-- s0/fp 在函数序言后指向的位置
|
||||
| 被调用者保存的寄存器 |
|
||||
| (Callee-Saved Regs) |
|
||||
+-----------------------------+
|
||||
| 局部变量 (Alloca) |
|
||||
+-----------------------------+
|
||||
| 寄存器溢出区域 |
|
||||
| (Spill Slots) |
|
||||
+-----------------------------+
|
||||
| 为调用其他函数预留的 |
|
||||
| 出参空间 (Out-Args) |
|
||||
低地址 +-----------------------------+ <-- sp 在函数序言后指向的位置
|
||||
```
|
||||
|
||||
- **实现**: `PrologueEpilogueInsertion.h` 和 `EliminateFrameIndices.h` 中的 Pass 负责生成函数序言(prologue)和尾声(epilogue)代码,来构建和销毁上述栈帧。`EliminateFrameIndices` 会将所有对抽象栈槽(如局部变量、溢出槽)的访问,替换为对帧指针 `s0` 或栈指针 `sp` 的、带有具体偏移量的访问。
|
||||
|
||||
### 4.2. 指令选择 (Instruction Selection)
|
||||
|
||||
- **目标**: 将抽象的 IR 指令高效地翻译成具体的目标机指令序列。
|
||||
- **技术**: 采用 **基于 DAG (Directed Acyclic Graph) 的模式匹配** 算法。
|
||||
- **实现**: `RISCv64ISel.cpp` 中的 `RISCv64ISel::select()` 驱动此过程。`selectBasicBlock()` 为每个基本块调用 `build_dag()` 来构建一个操作的 DAG,然后通过 `select_recursive()` 对 DAG 进行自底向上的遍历和匹配。在 `selectNode()` 函数中,通过一个大的 `switch` 语句,为不同类型的 DAG 节点(如 `BINARY`, `LOAD`, `STORE`)匹配最优的指令序列。例如,一个 IR 的加法指令,如果其中一个操作数是小常数,会被直接匹配为一条 `ADDIW` 指令,而不是 `LI` 和 `ADDW` 两条指令。
|
||||
|
||||
### 4.3. 寄存器分配 (Register Allocation)
|
||||
|
||||
- **目标**: 将无限的虚拟寄存器映射到有限的物理寄存器上,并优雅地处理寄存器不足(溢出)的情况。
|
||||
- **技术**: 实现了经典的**基于图着色 (Graph Coloring) 的全局寄存器分配算法**,这是一种强大但复杂的全局优化方法。
|
||||
- **实现**: `RISCv64RegAlloc.cpp` 中的 `RISCv64RegAlloc::run()` 是主入口。它在一个循环中执行分配,直到没有寄存器需要溢出为止。其内部流程极其精密,如下图所示:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph "寄存器分配主循环 (RISCv64RegAlloc::run)"
|
||||
direction LR
|
||||
Start((Start)) --> Liveness[1. 活跃性分析 LivenessAnalysis]
|
||||
Liveness --> Build[2. 构建冲突图 Build]
|
||||
Build --> Worklist[3. 创建工作表 MakeWorklist]
|
||||
Worklist --> Loop{Main Loop}
|
||||
Loop -- simplifyWorklist 非空 --> Simplify[4a. 简化 Simplify]
|
||||
Simplify --> Loop
|
||||
Loop -- worklistMoves 非空 --> Coalesce[4b. 合并 Coalesce]
|
||||
Coalesce --> Loop
|
||||
Loop -- freezeWorklist 非空 --> Freeze[4c. 冻结 Freeze]
|
||||
Freeze --> Loop
|
||||
Loop -- spillWorklist 非空 --> Spill[4d. 选择溢出 SelectSpill]
|
||||
Spill --> Loop
|
||||
Loop -- 所有工作表为空 --> Assign[5. 分配颜色 AssignColors]
|
||||
Assign --> CheckSpill{有溢出?}
|
||||
CheckSpill -- Yes --> Rewrite[6. 重写代码 RewriteProgram]
|
||||
Rewrite --> Liveness
|
||||
CheckSpill -- No --> Finish((Finish))
|
||||
end
|
||||
```
|
||||
|
||||
1. **`analyzeLiveness()`**: 对机器指令进行数据流分析,计算出每个虚拟寄存器的活跃范围。
|
||||
2. **`build()`**: 根据活跃性信息构建**冲突图 (Interference Graph)**。如果两个虚拟寄存器同时活跃,则它们冲突,在图中连接一条边。
|
||||
3. **`makeWorklist()`**: 将图节点(虚拟寄存器)根据其度数放入不同的工作列表,为着色做准备。
|
||||
4. **核心着色阶段 (The Loop)**:
|
||||
- **`simplify()`**: 贪心地移除图中度数小于物理寄存器数量的节点,并将其压入栈中。这些节点保证可以被成功着色。
|
||||
- **`coalesce()`**: 尝试将传送指令 (`MV`) 的源和目标节点合并,以消除这条指令。合并的条件基于 **Briggs** 或 **George** 启发式,以避免使图变得不可着色。
|
||||
- **`freeze()`**: 当一个与传送指令相关的节点无法合并也无法简化时,放弃对该传送指令的合并希望,将其“冻结”为一个普通节点。
|
||||
- **`selectSpill()`**: 当所有节点都无法进行上述操作时(即图中只剩下高度数的节点),必须选择一个节点进行**溢出 (Spill)**,即决定将其存放在内存中。
|
||||
5. **`assignColors()`**: 在所有节点都被处理后,从栈中依次弹出节点,并根据其已着色邻居的颜色,为它选择一个可用的物理寄存器。
|
||||
6. **`rewriteProgram()`**: 如果 `assignColors()` 阶段发现有节点被标记为溢出,此函数会被调用。它会修改机器指令,为溢出的虚拟寄存器插入从内存加载(`lw`/`ld`)和存入内存(`sw`/`sd`)的代码。然后,整个分配过程从步骤 1 重新开始。
|
||||
|
||||
### 4.4. 后端特定优化
|
||||
|
||||
在寄存器分配前后,后端还会进行一系列针对目标机(RISC-V)特性的优化。
|
||||
|
||||
#### 4.4.1. 指令调度 (Instruction Scheduling)
|
||||
|
||||
- **寄存器分配前调度 (`PreRA_Scheduler.cpp`)**:
|
||||
- **目标**: 在寄存器分配前,通过重排指令来提升性能。主要目标是**隐藏加载延迟 (Load Latency)**,即尽早发出 `load` 指令,使其结果能在需要时及时准备好,避免流水线停顿。同时,由于此时使用的是无限的虚拟寄存器,调度器有较大的自由度,但也可能因为过度重排而延长虚拟寄存器的生命周期,从而增加寄存器压力。
|
||||
- **实现**: `scheduleBlock()` 函数会识别出基本块内的调度边界(如 `call` 或终结指令),然后在每个独立的区域内调用 `scheduleRegion()`。当前的实现是一种简化的列表调度,它会优先尝试将加载指令 (`LW`, `LD` 等) 在不违反数据依赖的前提下,尽可能地向前移动。
|
||||
|
||||
- **寄存器分配后调度 (`PostRA_Scheduler.cpp`)**:
|
||||
- **目标**: 在寄存器分配完成之后,对指令序列进行最后一轮微调。此阶段调度的主要目标与分配前不同,它旨在解决由寄存器分配过程本身引入的性能问题,例如:
|
||||
- **缓解溢出代价**: 将因溢出(Spill)而产生的 `load` 指令(从栈加载)尽可能地提前,远离其使用点;将 `store` 指令(存入栈)尽可能地推后,远离其定义点。
|
||||
- **消除伪依赖**: 寄存器分配器可能会为两个原本不相关的虚拟寄存器分配同一个物理寄存器,从而引入了虚假的写后读(WAR)或写后写(WAW)依赖。Post-RA 调度可以尝试解开这些伪依赖,为指令重排提供更多自由度。
|
||||
- **实现**: `scheduleBlock()` 函数实现了此调度器。它采用了一种非常保守的**局部交换 (Local Swapping)** 策略。它迭代地检查相邻的两条指令,在 `canSwapInstructions()` 函数确认交换不会违反任何数据依赖(RAW, WAR, WAW)或内存依赖后,才执行交换。这种方法虽然不如全局列表调度强大,但在严格的 Post-RA 约束下是一种安全有效的优化手段。
|
||||
|
||||
#### 4.4.2. 强度削减 (Strength Reduction)
|
||||
|
||||
- **除法强度削减 (`DivStrengthReduction.cpp`)**:
|
||||
- **目标**: 将机器指令中昂贵的 `DIV` 或 `DIVW` 指令(当除数为编译期常量时)替换为一系列更快、计算成本更低的指令组合。
|
||||
- **技术**: 基于数论中的**乘法逆元 (Multiplicative Inverse)** 思想。对于一个整数除法 `x / d`,可以找到一个“魔数” `m` 和一个移位数 `s`,使得该除法可以被近似替换为 `(x * m) >> s`。这个过程需要处理复杂的符号、取整和溢出问题。
|
||||
- **实现**: `runOnMachineFunction()` 实现了此优化。它会遍历机器指令,寻找以常量为除数的 `DIV`/`DIVW` 指令。`computeMagic()` 函数负责计算出对应的魔数和移位数。然后,根据除数是 2 的幂、1、-1 还是其他普通数字,生成不同的指令序列,包括 `MULH` (取高位乘积), `SRAI` (算术右移), `ADD`, `SUB` 等,来精确地模拟定点数除法的效果。
|
||||
|
||||
#### 4.4.3. 窥孔优化 (Peephole Optimization)
|
||||
|
||||
- **目标**: 在生成最终汇编代码之前,对相邻的机器指令序列进行局部优化,以消除冗余操作和利用目标机特性。
|
||||
- **技术**: 窥孔优化是一种简单而高效的局部优化技术。它通过一个固定大小的“窥孔”(通常是 2-3 条指令)来扫描指令序列,寻找可以被更优指令序列替换的模式。
|
||||
- **实现**: `PeepholeOptimizer::runOnMachineFunction()` 实现了此 Pass。它包含了一系列模式匹配和替换规则,主要包括:
|
||||
- **冗余移动消除**: `mv x, y` 后跟着一条使用 `x` 的指令 `op z, x, ...`,如果 `x` 之后不再活跃,则将 `op` 的操作数直接替换为 `y`,并移除 `mv` 指令。
|
||||
- **冗余加载消除**: `sw r1, mem; lw r2, mem` -> `sw r1, mem; mv r2, r1`。如果 `r1` 和 `r2` 是同一个寄存器,则直接移除 `lw`。
|
||||
- **地址计算优化**: `addi t1, base, imm1; lw t2, imm2(t1)` -> `lw t2, (imm1+imm2)(base)`。将两条指令合并为一条,减少了指令数量和中间寄存器的使用。
|
||||
- **指令合并**: `addi t1, t0, imm1; addi t2, t1, imm2` -> `addi t2, t0, (imm1+imm2)`。合并连续的立即数加法。
|
||||
|
||||
### 4.5. 局限性与未来工作
|
||||
|
||||
根据项目中的 `TODO` 列表和源代码分析,当前实现存在一些可改进之处:
|
||||
|
||||
- **寄存器分配**:
|
||||
- **`CALL` 指令处理**: 当前对 `CALL` 指令的 `use`/`def` 分析不完整,没有将所有调用者保存的寄存器标记为 `def`,这可能导致跨函数调用的值被错误破坏。
|
||||
- **溢出处理**: 当前所有溢出的虚拟寄存器都被简单地映射到同一个物理寄存器 `t6` 上,这会引入大量不必要的 `load`/`store`,并可能导致 `t6` 成为性能瓶颈。
|
||||
- **IR 设计**:
|
||||
- 随着 SSA 的引入,IR 中某些冗余信息(如基本块的 `args` 参数)可以被移除,以简化设计。
|
||||
- **优化**:
|
||||
- 当前的优化主要集中在标量上。可以引入更多面向循环的优化(如循环不变代码外提 LICM、归纳变量分析 IndVar)和过程间优化来进一步提升性能。
|
||||
Binary file not shown.
@ -14,6 +14,7 @@ TESTDATA_DIR="${SCRIPT_DIR}/testdata" # 用于查找 .in/.out 文件
|
||||
GCC_NATIVE="gcc" # VM 内部的原生 gcc
|
||||
|
||||
# --- 初始化变量 ---
|
||||
CLEAN_MODE=false
|
||||
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
|
||||
EXEC_TIMEOUT=5 # 程序自动化执行超时 (秒)
|
||||
MAX_OUTPUT_LINES=50 # 对比失败时显示的最大行数
|
||||
@ -29,6 +30,7 @@ show_help() {
|
||||
echo "如果找到对应的 .in/.out 文件,则进行自动化测试。否则,进入交互模式。"
|
||||
echo ""
|
||||
echo "选项:"
|
||||
echo " -c, --clean 清理 tmp 临时目录下的所有文件。"
|
||||
echo " -ct N 设置 gcc 编译超时为 N 秒 (默认: 10)。"
|
||||
echo " -t N 设置程序自动化执行超时为 N 秒 (默认: 5)。"
|
||||
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 50)。"
|
||||
@ -57,10 +59,24 @@ display_file_content() {
|
||||
fi
|
||||
}
|
||||
|
||||
# --- 新增功能: 清理临时文件的函数 ---
|
||||
clean_tmp() {
|
||||
echo "正在清理临时目录: ${TMP_DIR}"
|
||||
if [ -d "${TMP_DIR}" ]; then
|
||||
rm -rf "${TMP_DIR}"/* 2>/dev/null
|
||||
echo "清理完成。"
|
||||
else
|
||||
echo "临时目录 ${TMP_DIR} 不存在,无需清理。"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- 参数解析 ---
|
||||
# 从参数中分离出 .s 文件和选项
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
-c|--clean)
|
||||
CLEAN_MODE=true
|
||||
;;
|
||||
-ct|-t|-ml|--max-lines)
|
||||
# 选项和其值将在下一个循环中处理
|
||||
;;
|
||||
@ -74,6 +90,7 @@ for arg in "$@"; do
|
||||
args_processed=true # 标记已处理过参数
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-c|--clean) ;; # 已在外部处理
|
||||
-ct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift; else echo "错误: -ct 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-t) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift; else echo "错误: -t 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-ml|--max-lines) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
@ -95,6 +112,14 @@ for arg in "$@"; do
|
||||
done
|
||||
|
||||
# --- 主逻辑开始 ---
|
||||
if ${CLEAN_MODE}; then
|
||||
clean_tmp
|
||||
# 如果只提供了 -c 选项,则退出
|
||||
if [ ${#S_FILES[@]} -eq 0 ]; then
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ${#S_FILES[@]} -eq 0 ]; then
|
||||
echo "错误: 未提供任何 .s 文件作为输入。"
|
||||
show_help
|
||||
@ -162,14 +187,17 @@ for s_file in "${S_FILES[@]}"; do
|
||||
EXPECTED_STDOUT_FILE="${TMP_DIR}/${base_name_from_s_file}.expected_stdout"
|
||||
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
|
||||
if [ "$ACTUAL_RETURN_CODE" -ne "$EXPECTED_RETURN_CODE" ]; then echo -e "\e[31m 返回码测试失败: 期望 ${EXPECTED_RETURN_CODE}, 实际 ${ACTUAL_RETURN_CODE}\e[0m"; is_passed=0; fi
|
||||
if ! diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
||||
|
||||
# --- 本次修改点: 使用 tr 删除所有空白字符后再比较 ---
|
||||
if ! diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
||||
echo -e "\e[31m 标准输出测试失败。\e[0m"; is_passed=0
|
||||
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
echo -e " \e[36m----------------\e[0m"
|
||||
fi
|
||||
else
|
||||
if ! diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${output_reference_file}") >/dev/null 2>&1; then
|
||||
# --- 本次修改点: 使用 tr 删除所有空白字符后再比较 ---
|
||||
if diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
|
||||
echo -e "\e[32m 标准输出测试成功。\e[0m"
|
||||
else
|
||||
echo -e "\e[31m 标准输出测试失败。\e[0m"; is_passed=0
|
||||
@ -60,11 +60,7 @@ display_file_content() {
|
||||
# 清理临时文件的函数
|
||||
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
|
||||
rm -rf "${TMP_DIR}"/*
|
||||
echo "清理完成。"
|
||||
}
|
||||
|
||||
@ -175,7 +171,8 @@ while IFS= read -r s_file; do
|
||||
is_passed=0
|
||||
fi
|
||||
|
||||
if ! diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
||||
# --- 本次修改点: 使用 tr 删除所有空白字符后再比较 ---
|
||||
if ! diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
||||
echo -e "\e[31m 标准输出测试失败\e[0m"
|
||||
is_passed=0
|
||||
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
@ -186,7 +183,9 @@ while IFS= read -r s_file; do
|
||||
if [ $ACTUAL_RETURN_CODE -ne 0 ]; then
|
||||
echo -e "\e[33m警告: 程序以非零状态 ${ACTUAL_RETURN_CODE} 退出 (纯输出比较模式)。\e[0m"
|
||||
fi
|
||||
if ! diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${output_reference_file}") >/dev/null 2>&1; then
|
||||
|
||||
# --- 本次修改点: 使用 tr 删除所有空白字符后再比较 ---
|
||||
if diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
|
||||
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
|
||||
else
|
||||
echo -e "\e[31m 失败: 输出不匹配\e[0m"
|
||||
317
script/runit-single.sh
Normal file
317
script/runit-single.sh
Normal file
@ -0,0 +1,317 @@
|
||||
#!/bin/bash
|
||||
|
||||
# runit-single.sh - 用于编译和测试单个或少量 SysY 程序的脚本
|
||||
# 模仿 runit.sh 的功能,但以具体文件路径作为输入。
|
||||
# 此脚本应该位于 mysysy/script/
|
||||
|
||||
export ASAN_OPTIONS=detect_leaks=0
|
||||
|
||||
# --- 配置区 ---
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
|
||||
BUILD_BIN_DIR="${SCRIPT_DIR}/../build/bin"
|
||||
LIB_DIR="${SCRIPT_DIR}/../lib"
|
||||
TMP_DIR="${SCRIPT_DIR}/tmp"
|
||||
|
||||
# 定义编译器和模拟器
|
||||
SYSYC="${BUILD_BIN_DIR}/sysyc"
|
||||
LLC_CMD="llc-19" # 新增
|
||||
GCC_RISCV64="riscv64-linux-gnu-gcc"
|
||||
QEMU_RISCV64="qemu-riscv64"
|
||||
|
||||
# --- 初始化变量 ---
|
||||
EXECUTE_MODE=false
|
||||
IR_EXECUTE_MODE=false
|
||||
CLEAN_MODE=false
|
||||
OPTIMIZE_FLAG=""
|
||||
SYSYC_TIMEOUT=30
|
||||
LLC_TIMEOUT=10
|
||||
GCC_TIMEOUT=10
|
||||
EXEC_TIMEOUT=30
|
||||
MAX_OUTPUT_LINES=20
|
||||
MAX_OUTPUT_CHARS=1000
|
||||
SY_FILES=()
|
||||
PASSED_CASES=0
|
||||
FAILED_CASES_LIST=""
|
||||
INTERRUPTED=false
|
||||
|
||||
# =================================================================
|
||||
# --- 函数定义 ---
|
||||
# =================================================================
|
||||
show_help() {
|
||||
echo "用法: $0 [文件1.sy] [文件2.sy] ... [选项]"
|
||||
echo "编译并测试指定的 .sy 文件。必须提供 -e 或 -eir 之一。"
|
||||
echo ""
|
||||
echo "选项:"
|
||||
echo " -e 通过汇编运行测试 (sysyc -> gcc -> qemu)。"
|
||||
echo " -eir 通过IR运行测试 (sysyc -> llc -> gcc -> qemu)。"
|
||||
echo " -c, --clean 清理 tmp 临时目录下的所有文件。"
|
||||
echo " -O1 启用 sysyc 的 -O1 优化。"
|
||||
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 30)。"
|
||||
echo " -lct N 设置 llc-19 编译超时为 N 秒 (默认: 10)。"
|
||||
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
||||
echo " -et N 设置 qemu 自动化执行超时为 N 秒 (默认: 30)。"
|
||||
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 20)。"
|
||||
echo " -mc N, --max-chars N 当输出对比失败时,最多显示 N 个字符 (默认: 1000)。"
|
||||
echo " -h, --help 显示此帮助信息并退出。"
|
||||
echo ""
|
||||
echo "可在任何时候按 Ctrl+C 来中断测试并显示当前已完成的测例总结。"
|
||||
}
|
||||
|
||||
# 显示文件内容并根据行数和字符数截断的函数
|
||||
display_file_content() {
|
||||
local file_path="$1"
|
||||
local title="$2"
|
||||
local max_lines="$3"
|
||||
local max_chars="$4" # 新增参数
|
||||
if [ ! -f "$file_path" ]; then return; fi
|
||||
echo -e "$title"
|
||||
local line_count
|
||||
local char_count
|
||||
line_count=$(wc -l < "$file_path")
|
||||
char_count=$(wc -c < "$file_path")
|
||||
|
||||
if [ "$line_count" -gt "$max_lines" ]; then
|
||||
head -n "$max_lines" "$file_path"
|
||||
echo -e "\e[33m[... 输出因行数过多 (共 ${line_count} 行) 而截断 ...]\e[0m"
|
||||
elif [ "$char_count" -gt "$max_chars" ]; then
|
||||
head -c "$max_chars" "$file_path"
|
||||
echo -e "\n\e[33m[... 输出因字符数过多 (共 ${char_count} 字符) 而截断 ...]\e[0m"
|
||||
else
|
||||
cat "$file_path"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- 新增:总结报告函数 ---
|
||||
print_summary() {
|
||||
local total_cases=${#SY_FILES[@]}
|
||||
echo ""
|
||||
echo "======================================================================"
|
||||
if [ "$INTERRUPTED" = true ]; then
|
||||
echo -e "\e[33m测试被中断。正在汇总已完成的结果...\e[0m"
|
||||
else
|
||||
echo "所有测试完成"
|
||||
fi
|
||||
|
||||
local failed_count
|
||||
if [ -n "$FAILED_CASES_LIST" ]; then
|
||||
failed_count=$(echo -e -n "${FAILED_CASES_LIST}" | wc -l)
|
||||
else
|
||||
failed_count=0
|
||||
fi
|
||||
local executed_count=$((PASSED_CASES + failed_count))
|
||||
|
||||
echo "测试结果: [通过: ${PASSED_CASES}, 失败: ${failed_count}, 已执行: ${executed_count}/${total_cases}]"
|
||||
|
||||
if [ -n "$FAILED_CASES_LIST" ]; then
|
||||
echo ""
|
||||
echo -e "\e[31m未通过的测例:\e[0m"
|
||||
printf "%b" "${FAILED_CASES_LIST}"
|
||||
fi
|
||||
echo "======================================================================"
|
||||
|
||||
if [ "$failed_count" -gt 0 ]; then
|
||||
exit 1
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
# --- 新增:SIGINT 信号处理函数 ---
|
||||
handle_sigint() {
|
||||
INTERRUPTED=true
|
||||
print_summary
|
||||
}
|
||||
|
||||
# =================================================================
|
||||
# --- 主逻辑开始 ---
|
||||
# =================================================================
|
||||
|
||||
# --- 新增:设置 trap 来捕获 SIGINT ---
|
||||
trap handle_sigint SIGINT
|
||||
|
||||
# --- 参数解析 ---
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-e|--executable) EXECUTE_MODE=true; shift ;;
|
||||
-eir) IR_EXECUTE_MODE=true; shift ;; # 新增
|
||||
-c|--clean) CLEAN_MODE=true; shift ;;
|
||||
-O1) OPTIMIZE_FLAG="-O1"; shift ;;
|
||||
-lct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then LLC_TIMEOUT="$2"; shift 2; else echo "错误: -lct 需要一个正整数参数。" >&2; exit 1; fi ;; # 新增
|
||||
-sct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift 2; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-gct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift 2; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-et) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift 2; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-ml|--max-lines) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-mc|--max-chars) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_CHARS="$2"; shift 2; else echo "错误: --max-chars 需要一个正整数参数。" >&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} && ! ${IR_EXECUTE_MODE}; then
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! ${EXECUTE_MODE} && ! ${IR_EXECUTE_MODE}; then
|
||||
echo "错误: 请提供 -e 或 -eir 选项来运行测试。"
|
||||
show_help
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ${EXECUTE_MODE} && ${IR_EXECUTE_MODE}; then
|
||||
echo -e "\e[31m错误: -e 和 -eir 选项不能同时使用。\e[0m" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ${#SY_FILES[@]} -eq 0 ]; then
|
||||
echo "错误: 未提供任何 .sy 文件作为输入。"
|
||||
show_help
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "${TMP_DIR}"
|
||||
TOTAL_CASES=${#SY_FILES[@]}
|
||||
|
||||
echo "SysY 单例测试运行器启动..."
|
||||
if [ -n "$OPTIMIZE_FLAG" ]; then echo "优化等级: ${OPTIMIZE_FLAG}"; fi
|
||||
echo "超时设置: sysyc=${SYSYC_TIMEOUT}s, llc=${LLC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
|
||||
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
|
||||
echo "失败输出最大字符数: ${MAX_OUTPUT_CHARS}"
|
||||
echo ""
|
||||
|
||||
for sy_file in "${SY_FILES[@]}"; do
|
||||
is_passed=1
|
||||
compilation_ok=1
|
||||
base_name=$(basename "${sy_file}" .sy)
|
||||
source_dir=$(dirname "${sy_file}")
|
||||
|
||||
ir_file="${TMP_DIR}/${base_name}.ll"
|
||||
assembly_file="${TMP_DIR}/${base_name}.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}"
|
||||
|
||||
# --- 编译阶段 ---
|
||||
if ${IR_EXECUTE_MODE}; then
|
||||
# 路径1: sysyc -> llc -> gcc
|
||||
echo " [1/3] 使用 sysyc 编译为 IR (超时 ${SYSYC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" ${OPTIMIZE_FLAG} -o "${ir_file}"
|
||||
if [ $? -ne 0 ]; then echo -e "\e[31m错误: SysY (IR) 编译失败或超时。\e[0m"; compilation_ok=0; fi
|
||||
|
||||
if [ "$compilation_ok" -eq 1 ]; then
|
||||
echo " [2/3] 使用 llc 编译为汇编 (超时 ${LLC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${LLC_TIMEOUT} "${LLC_CMD}" -march=riscv64 -mcpu=generic-rv64 -mattr=+m,+a,+f,+d,+c -filetype=asm "${ir_file}" -o "${assembly_file}"
|
||||
if [ $? -ne 0 ]; then echo -e "\e[31m错误: llc 编译失败或超时。\e[0m"; compilation_ok=0; fi
|
||||
fi
|
||||
|
||||
if [ "$compilation_ok" -eq 1 ]; then
|
||||
echo " [3/3] 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
|
||||
if [ $? -ne 0 ]; then echo -e "\e[31m错误: GCC 编译失败或超时。\e[0m"; compilation_ok=0; fi
|
||||
fi
|
||||
else # EXECUTE_MODE
|
||||
# 路径2: sysyc -> gcc
|
||||
echo " [1/2] 使用 sysyc 编译为汇编 (超时 ${SYSYC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" ${OPTIMIZE_FLAG} -o "${assembly_file}"
|
||||
if [ $? -ne 0 ]; then echo -e "\e[31m错误: SysY (汇编) 编译失败或超时。\e[0m"; compilation_ok=0; fi
|
||||
|
||||
if [ "$compilation_ok" -eq 1 ]; then
|
||||
echo " [2/2] 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
|
||||
if [ $? -ne 0 ]; then echo -e "\e[31m错误: GCC 编译失败或超时。\e[0m"; compilation_ok=0; fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- 执行与测试阶段 (公共逻辑) ---
|
||||
if [ "$compilation_ok" -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}"
|
||||
|
||||
ret_ok=1
|
||||
if [ "$ACTUAL_RETURN_CODE" -ne "$EXPECTED_RETURN_CODE" ]; then echo -e "\e[31m 返回码测试失败: 期望 ${EXPECTED_RETURN_CODE}, 实际 ${ACTUAL_RETURN_CODE}\e[0m"; ret_ok=0; fi
|
||||
|
||||
out_ok=1
|
||||
if ! diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
||||
echo -e "\e[31m 标准输出测试失败。\e[0m"; out_ok=0
|
||||
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
fi
|
||||
|
||||
if [ "$ret_ok" -eq 1 ] && [ "$out_ok" -eq 1 ]; then echo -e "\e[32m 返回码与标准输出测试成功。\e[0m"; else is_passed=0; fi
|
||||
|
||||
else
|
||||
if diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
|
||||
echo -e "\e[32m 标准输出测试成功。\e[0m"
|
||||
else
|
||||
echo -e "\e[31m 标准输出测试失败。\e[0m"; is_passed=0
|
||||
display_file_content "${output_reference_file}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# --- 交互模式 ---
|
||||
echo -e "\e[33m\n 未找到 .in 或 .out 文件,进入交互模式...\e[0m"
|
||||
"${QEMU_RISCV64}" "${executable_file}"
|
||||
INTERACTIVE_RET_CODE=$?
|
||||
echo -e "\e[33m\n 交互模式执行完毕,程序返回码: ${INTERACTIVE_RET_CODE} (此结果未经验证)\e[0m"
|
||||
fi
|
||||
else
|
||||
is_passed=0
|
||||
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
|
||||
|
||||
# --- 打印最终总结 ---
|
||||
print_summary
|
||||
453
script/runit.sh
Normal file
453
script/runit.sh
Normal file
@ -0,0 +1,453 @@
|
||||
#!/bin/bash
|
||||
|
||||
# runit.sh - 用于编译和测试 SysY 程序的脚本
|
||||
# 此脚本应该位于 mysysy/script/
|
||||
|
||||
export ASAN_OPTIONS=detect_leaks=0
|
||||
|
||||
# 定义相对于脚本位置的目录
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
|
||||
TESTDATA_DIR="${SCRIPT_DIR}/../testdata"
|
||||
BUILD_BIN_DIR="${SCRIPT_DIR}/../build/bin"
|
||||
LIB_DIR="${SCRIPT_DIR}/../lib"
|
||||
TMP_DIR="${SCRIPT_DIR}/tmp"
|
||||
|
||||
# 定义编译器和模拟器
|
||||
SYSYC="${BUILD_BIN_DIR}/sysyc"
|
||||
LLC_CMD="llc-19"
|
||||
GCC_RISCV64="riscv64-linux-gnu-gcc"
|
||||
QEMU_RISCV64="qemu-riscv64"
|
||||
|
||||
# --- 状态变量 ---
|
||||
EXECUTE_MODE=false
|
||||
IR_EXECUTE_MODE=false
|
||||
OPTIMIZE_FLAG=""
|
||||
SYSYC_TIMEOUT=30
|
||||
LLC_TIMEOUT=10
|
||||
GCC_TIMEOUT=10
|
||||
EXEC_TIMEOUT=30
|
||||
MAX_OUTPUT_LINES=20
|
||||
MAX_OUTPUT_CHARS=1000
|
||||
TEST_SETS=()
|
||||
TOTAL_CASES=0
|
||||
PASSED_CASES=0
|
||||
FAILED_CASES_LIST=""
|
||||
INTERRUPTED=false
|
||||
|
||||
# =================================================================
|
||||
# --- 函数定义 ---
|
||||
# =================================================================
|
||||
|
||||
# 显示帮助信息的函数
|
||||
show_help() {
|
||||
echo "用法: $0 [选项]"
|
||||
echo "此脚本用于按文件名前缀数字升序编译和测试 .sy 文件。"
|
||||
echo ""
|
||||
echo "选项:"
|
||||
echo " -e, --executable 编译为汇编并运行测试 (sysyc -> gcc -> qemu)。"
|
||||
echo " -eir 通过IR编译为可执行文件并运行测试 (sysyc -> llc -> gcc -> qemu)。"
|
||||
echo " -c, --clean 清理 'tmp' 目录下的所有生成文件。"
|
||||
echo " -O1 启用 sysyc 的 -O1 优化。"
|
||||
echo " -set [f|h|p|all]... 指定要运行的测试集 (functional, h_functional, performance)。可多选,默认为 all。"
|
||||
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 30)。"
|
||||
echo " -lct N 设置 llc-19 编译超时为 N 秒 (默认: 10)。"
|
||||
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
||||
echo " -et N 设置 qemu 执行超时为 N 秒 (默认: 30)。"
|
||||
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 20)。"
|
||||
echo " -mc N, --max-chars N 当输出对比失败时,最多显示 N 个字符 (默认: 1000)。"
|
||||
echo " -h, --help 显示此帮助信息并退出。"
|
||||
echo ""
|
||||
echo "注意: 默认行为 (无 -e 或 -eir) 是将 .sy 文件同时编译为 .s (汇编) 和 .ll (IR),不执行。"
|
||||
echo " 可在任何时候按 Ctrl+C 来中断测试并显示当前已完成的测例总结。"
|
||||
}
|
||||
|
||||
|
||||
# 显示文件内容并根据行数和字符数截断的函数
|
||||
display_file_content() {
|
||||
local file_path="$1"
|
||||
local title="$2"
|
||||
local max_lines="$3"
|
||||
local max_chars="$4" # 新增参数
|
||||
if [ ! -f "$file_path" ]; then return; fi
|
||||
echo -e "$title"
|
||||
local line_count
|
||||
local char_count
|
||||
line_count=$(wc -l < "$file_path")
|
||||
char_count=$(wc -c < "$file_path")
|
||||
|
||||
if [ "$line_count" -gt "$max_lines" ]; then
|
||||
head -n "$max_lines" "$file_path"
|
||||
echo -e "\e[33m[... 输出因行数过多 (共 ${line_count} 行) 而截断 ...]\e[0m"
|
||||
elif [ "$char_count" -gt "$max_chars" ]; then
|
||||
head -c "$max_chars" "$file_path"
|
||||
echo -e "\n\e[33m[... 输出因字符数过多 (共 ${char_count} 字符) 而截断 ...]\e[0m"
|
||||
else
|
||||
cat "$file_path"
|
||||
fi
|
||||
}
|
||||
|
||||
# 清理临时文件的函数
|
||||
clean_tmp() {
|
||||
echo "正在清理临时目录: ${TMP_DIR}"
|
||||
rm -rf "${TMP_DIR}"/*
|
||||
}
|
||||
|
||||
# --- 新增:总结报告函数 ---
|
||||
print_summary() {
|
||||
echo "" # 确保从新的一行开始
|
||||
echo "========================================"
|
||||
if [ "$INTERRUPTED" = true ]; then
|
||||
echo -e "\e[33m测试被中断。正在汇总已完成的结果...\e[0m"
|
||||
else
|
||||
echo "测试完成"
|
||||
fi
|
||||
|
||||
local failed_count
|
||||
if [ -n "$FAILED_CASES_LIST" ]; then
|
||||
# `wc -l` 计算由换行符分隔的列表项数
|
||||
failed_count=$(echo -e -n "${FAILED_CASES_LIST}" | wc -l)
|
||||
else
|
||||
failed_count=0
|
||||
fi
|
||||
local executed_count=$((PASSED_CASES + failed_count))
|
||||
|
||||
echo "测试结果: [通过: ${PASSED_CASES}, 失败: ${failed_count}, 已执行: ${executed_count}/${TOTAL_CASES}]"
|
||||
|
||||
if [ -n "$FAILED_CASES_LIST" ]; then
|
||||
echo ""
|
||||
echo -e "\e[31m未通过的测例:\e[0m"
|
||||
# 使用 printf 保证原样输出
|
||||
printf "%b" "${FAILED_CASES_LIST}"
|
||||
fi
|
||||
|
||||
echo "========================================"
|
||||
|
||||
if [ "$failed_count" -gt 0 ]; then
|
||||
exit 1
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
# --- 新增:SIGINT 信号处理函数 ---
|
||||
handle_sigint() {
|
||||
INTERRUPTED=true
|
||||
print_summary
|
||||
}
|
||||
|
||||
# =================================================================
|
||||
# --- 主逻辑开始 ---
|
||||
# =================================================================
|
||||
|
||||
# --- 新增:设置 trap 来捕获 SIGINT ---
|
||||
trap handle_sigint SIGINT
|
||||
|
||||
mkdir -p "${TMP_DIR}"
|
||||
|
||||
# 解析命令行参数
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-e|--executable) EXECUTE_MODE=true; shift ;;
|
||||
-eir) IR_EXECUTE_MODE=true; shift ;;
|
||||
-c|--clean) clean_tmp; exit 0 ;;
|
||||
-O1) OPTIMIZE_FLAG="-O1"; shift ;;
|
||||
-set)
|
||||
shift
|
||||
while [[ "$#" -gt 0 && ! "$1" =~ ^- ]]; do TEST_SETS+=("$1"); shift; done
|
||||
;;
|
||||
-sct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift 2; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-lct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then LLC_TIMEOUT="$2"; shift 2; else echo "错误: -lct 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-gct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift 2; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-et) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift 2; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-ml|--max-lines) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-mc|--max-chars) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_CHARS="$2"; shift 2; else echo "错误: --max-chars 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||
-h|--help) show_help; exit 0 ;;
|
||||
*) echo "未知选项: $1"; show_help; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if ${EXECUTE_MODE} && ${IR_EXECUTE_MODE}; then
|
||||
echo -e "\e[31m错误: -e 和 -eir 选项不能同时使用。\e[0m" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
declare -A SET_MAP
|
||||
SET_MAP[f]="functional"
|
||||
SET_MAP[h]="h_functional"
|
||||
SET_MAP[p]="performance"
|
||||
|
||||
SEARCH_PATHS=()
|
||||
if [ ${#TEST_SETS[@]} -eq 0 ] || [[ " ${TEST_SETS[@]} " =~ " all " ]]; then
|
||||
SEARCH_PATHS+=("${TESTDATA_DIR}")
|
||||
else
|
||||
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 测试运行器启动..."
|
||||
if [ -n "$OPTIMIZE_FLAG" ]; then echo "优化等级: ${OPTIMIZE_FLAG}"; fi
|
||||
echo "输入目录: ${SEARCH_PATHS[@]}"
|
||||
echo "临时目录: ${TMP_DIR}"
|
||||
|
||||
RUN_MODE_INFO=""
|
||||
if ${IR_EXECUTE_MODE}; then
|
||||
RUN_MODE_INFO="IR执行模式 (-eir)"
|
||||
TIMEOUT_INFO="超时设置: sysyc=${SYSYC_TIMEOUT}s, llc=${LLC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
|
||||
elif ${EXECUTE_MODE}; then
|
||||
RUN_MODE_INFO="直接执行模式 (-e)"
|
||||
TIMEOUT_INFO="超时设置: sysyc=${SYSYC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
|
||||
else
|
||||
RUN_MODE_INFO="编译模式 (默认)"
|
||||
TIMEOUT_INFO="超时设置: sysyc=${SYSYC_TIMEOUT}s"
|
||||
fi
|
||||
echo "运行模式: ${RUN_MODE_INFO}"
|
||||
echo "${TIMEOUT_INFO}"
|
||||
if ${EXECUTE_MODE} || ${IR_EXECUTE_MODE}; then
|
||||
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
|
||||
echo "失败输出最大字符数: ${MAX_OUTPUT_CHARS}"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
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)
|
||||
|
||||
while IFS= read -r sy_file; do
|
||||
is_passed=0 # 0 表示失败, 1 表示通过
|
||||
|
||||
relative_path_no_ext=$(realpath --relative-to="${TESTDATA_DIR}" "${sy_file%.*}")
|
||||
output_base_name=$(echo "${relative_path_no_ext}" | tr '/' '_')
|
||||
|
||||
assembly_file_S="${TMP_DIR}/${output_base_name}_sysyc_S.s"
|
||||
executable_file_S="${TMP_DIR}/${output_base_name}_sysyc_S"
|
||||
output_actual_file_S="${TMP_DIR}/${output_base_name}_sysyc_S.actual_out"
|
||||
|
||||
ir_file="${TMP_DIR}/${output_base_name}_sysyc_ir.ll"
|
||||
assembly_file_from_ir="${TMP_DIR}/${output_base_name}_from_ir.s"
|
||||
executable_file_from_ir="${TMP_DIR}/${output_base_name}_from_ir"
|
||||
output_actual_file_from_ir="${TMP_DIR}/${output_base_name}_from_ir.actual_out"
|
||||
|
||||
input_file="${sy_file%.*}.in"
|
||||
output_reference_file="${sy_file%.*}.out"
|
||||
|
||||
echo "正在处理: $(basename "$sy_file") (路径: ${relative_path_no_ext}.sy)"
|
||||
|
||||
# --- 模式 1: IR 执行模式 (-eir) ---
|
||||
if ${IR_EXECUTE_MODE}; then
|
||||
step_failed=0
|
||||
test_logic_passed=0
|
||||
|
||||
echo " [1/4] 使用 sysyc 编译为 IR (超时 ${SYSYC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" -o "${ir_file}" ${OPTIMIZE_FLAG}
|
||||
SYSYC_STATUS=$?
|
||||
if [ $SYSYC_STATUS -ne 0 ]; then
|
||||
[ $SYSYC_STATUS -eq 124 ] && echo -e "\e[31m错误: SysY (IR) 编译超时\e[0m" || echo -e "\e[31m错误: SysY (IR) 编译失败,退出码: ${SYSYC_STATUS}\e[0m"
|
||||
step_failed=1
|
||||
fi
|
||||
|
||||
if [ "$step_failed" -eq 0 ]; then
|
||||
echo " [2/4] 使用 llc-19 编译为汇编 (超时 ${LLC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${LLC_TIMEOUT} "${LLC_CMD}" -march=riscv64 -mcpu=generic-rv64 -mattr=+m,+a,+f,+d,+c -filetype=asm "${ir_file}" -o "${assembly_file_from_ir}"
|
||||
LLC_STATUS=$?
|
||||
if [ $LLC_STATUS -ne 0 ]; then
|
||||
[ $LLC_STATUS -eq 124 ] && echo -e "\e[31m错误: llc-19 编译超时\e[0m" || echo -e "\e[31m错误: llc-19 编译失败,退出码: ${LLC_STATUS}\e[0m"
|
||||
step_failed=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$step_failed" -eq 0 ]; then
|
||||
echo " [3/4] 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file_from_ir}" -o "${executable_file_from_ir}" -L"${LIB_DIR}" -lsysy_riscv -static
|
||||
GCC_STATUS=$?
|
||||
if [ $GCC_STATUS -ne 0 ]; then
|
||||
[ $GCC_STATUS -eq 124 ] && echo -e "\e[31m错误: GCC 编译超时\e[0m" || echo -e "\e[31m错误: GCC 编译失败,退出码: ${GCC_STATUS}\e[0m"
|
||||
step_failed=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$step_failed" -eq 0 ]; then
|
||||
echo " [4/4] 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
|
||||
exec_cmd="${QEMU_RISCV64} \"${executable_file_from_ir}\""
|
||||
[ -f "${input_file}" ] && exec_cmd+=" < \"${input_file}\""
|
||||
exec_cmd+=" > \"${output_actual_file_from_ir}\""
|
||||
|
||||
eval "timeout -s KILL ${EXEC_TIMEOUT} ${exec_cmd}"
|
||||
ACTUAL_RETURN_CODE=$?
|
||||
|
||||
if [ "$ACTUAL_RETURN_CODE" -eq 124 ]; then
|
||||
echo -e "\e[31m 执行超时: 运行超过 ${EXEC_TIMEOUT} 秒\e[0m"
|
||||
else
|
||||
if [ -f "${output_reference_file}" ]; then
|
||||
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
|
||||
test_logic_passed=1
|
||||
if [[ "$LAST_LINE_TRIMMED" =~ ^[-+]?[0-9]+$ ]]; then
|
||||
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
|
||||
EXPECTED_STDOUT_FILE="${TMP_DIR}/${output_base_name}_from_ir.expected_stdout"
|
||||
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
|
||||
|
||||
if [ "$ACTUAL_RETURN_CODE" -eq "$EXPECTED_RETURN_CODE" ]; then
|
||||
echo -e "\e[32m 返回码测试成功: (${ACTUAL_RETURN_CODE}) 与期望值 (${EXPECTED_RETURN_CODE}) 匹配\e[0m"
|
||||
else
|
||||
echo -e "\e[31m 返回码测试失败: 期望: ${EXPECTED_RETURN_CODE}, 实际: ${ACTUAL_RETURN_CODE}\e[0m"
|
||||
test_logic_passed=0
|
||||
fi
|
||||
|
||||
if diff -q <(tr -d '[:space:]' < "${output_actual_file_from_ir}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
||||
[ "$test_logic_passed" -eq 1 ] && echo -e "\e[32m 标准输出测试成功\e[0m"
|
||||
else
|
||||
echo -e "\e[31m 标准输出测试失败\e[0m"
|
||||
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
display_file_content "${output_actual_file_from_ir}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
test_logic_passed=0
|
||||
fi
|
||||
else
|
||||
if [ $ACTUAL_RETURN_CODE -ne 0 ]; then echo -e "\e[33m警告: 程序以非零状态 ${ACTUAL_RETURN_CODE} 退出 (纯输出比较模式)。\e[0m"; fi
|
||||
if diff -q <(tr -d '[:space:]' < "${output_actual_file_from_ir}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
|
||||
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
|
||||
else
|
||||
echo -e "\e[31m 失败: 输出不匹配\e[0m"
|
||||
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
display_file_content "${output_actual_file_from_ir}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
test_logic_passed=0
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
|
||||
test_logic_passed=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
[ "$step_failed" -eq 0 ] && [ "$test_logic_passed" -eq 1 ] && is_passed=1
|
||||
|
||||
# --- 模式 2: 直接执行模式 (-e) ---
|
||||
elif ${EXECUTE_MODE}; then
|
||||
step_failed=0
|
||||
test_logic_passed=0
|
||||
|
||||
echo " [1/3] 使用 sysyc 编译为汇编 (超时 ${SYSYC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file_S}" ${OPTIMIZE_FLAG}
|
||||
SYSYC_STATUS=$?
|
||||
if [ $SYSYC_STATUS -ne 0 ]; then
|
||||
[ $SYSYC_STATUS -eq 124 ] && echo -e "\e[31m错误: SysY (汇编) 编译超时\e[0m" || echo -e "\e[31m错误: SysY (汇编) 编译失败,退出码: ${SYSYC_STATUS}\e[0m"
|
||||
step_failed=1
|
||||
fi
|
||||
|
||||
if [ "$step_failed" -eq 0 ]; then
|
||||
echo " [2/3] 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file_S}" -o "${executable_file_S}" -L"${LIB_DIR}" -lsysy_riscv -static
|
||||
GCC_STATUS=$?
|
||||
if [ $GCC_STATUS -ne 0 ]; then
|
||||
[ $GCC_STATUS -eq 124 ] && echo -e "\e[31m错误: GCC 编译超时\e[0m" || echo -e "\e[31m错误: GCC 编译失败,退出码: ${GCC_STATUS}\e[0m"
|
||||
step_failed=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$step_failed" -eq 0 ]; then
|
||||
echo " [3/3] 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
|
||||
exec_cmd="${QEMU_RISCV64} \"${executable_file_S}\""
|
||||
[ -f "${input_file}" ] && exec_cmd+=" < \"${input_file}\""
|
||||
exec_cmd+=" > \"${output_actual_file_S}\""
|
||||
|
||||
eval "timeout -s KILL ${EXEC_TIMEOUT} ${exec_cmd}"
|
||||
ACTUAL_RETURN_CODE=$?
|
||||
|
||||
if [ "$ACTUAL_RETURN_CODE" -eq 124 ]; then
|
||||
echo -e "\e[31m 执行超时: 运行超过 ${EXEC_TIMEOUT} 秒\e[0m"
|
||||
else
|
||||
if [ -f "${output_reference_file}" ]; then
|
||||
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
|
||||
test_logic_passed=1
|
||||
if [[ "$LAST_LINE_TRIMMED" =~ ^[-+]?[0-9]+$ ]]; then
|
||||
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
|
||||
EXPECTED_STDOUT_FILE="${TMP_DIR}/${output_base_name}_sysyc_S.expected_stdout"
|
||||
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
|
||||
|
||||
if [ "$ACTUAL_RETURN_CODE" -eq "$EXPECTED_RETURN_CODE" ]; then
|
||||
echo -e "\e[32m 返回码测试成功: (${ACTUAL_RETURN_CODE}) 与期望值 (${EXPECTED_RETURN_CODE}) 匹配\e[0m"
|
||||
else
|
||||
echo -e "\e[31m 返回码测试失败: 期望: ${EXPECTED_RETURN_CODE}, 实际: ${ACTUAL_RETURN_CODE}\e[0m"
|
||||
test_logic_passed=0
|
||||
fi
|
||||
|
||||
if diff -q <(tr -d '[:space:]' < "${output_actual_file_S}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
||||
[ "$test_logic_passed" -eq 1 ] && echo -e "\e[32m 标准输出测试成功\e[0m"
|
||||
else
|
||||
echo -e "\e[31m 标准输出测试失败\e[0m"
|
||||
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
display_file_content "${output_actual_file_S}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
test_logic_passed=0
|
||||
fi
|
||||
else
|
||||
if [ $ACTUAL_RETURN_CODE -ne 0 ]; then echo -e "\e[33m警告: 程序以非零状态 ${ACTUAL_RETURN_CODE} 退出 (纯输出比较模式)。\e[0m"; fi
|
||||
if diff -q <(tr -d '[:space:]' < "${output_actual_file_S}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
|
||||
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
|
||||
else
|
||||
echo -e "\e[31m 失败: 输出不匹配\e[0m"
|
||||
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
display_file_content "${output_actual_file_S}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||
test_logic_passed=0
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
|
||||
test_logic_passed=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
[ "$step_failed" -eq 0 ] && [ "$test_logic_passed" -eq 1 ] && is_passed=1
|
||||
|
||||
# --- 模式 3: 默认编译模式 ---
|
||||
else
|
||||
s_compile_ok=0
|
||||
ir_compile_ok=0
|
||||
|
||||
echo " [1/2] 使用 sysyc 编译为汇编 (超时 ${SYSYC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file_S}" ${OPTIMIZE_FLAG}
|
||||
SYSYC_S_STATUS=$?
|
||||
if [ $SYSYC_S_STATUS -eq 0 ]; then
|
||||
s_compile_ok=1
|
||||
echo -e " \e[32m-> ${assembly_file_S} [成功]\e[0m"
|
||||
else
|
||||
[ $SYSYC_S_STATUS -eq 124 ] && echo -e " \e[31m-> [编译超时]\e[0m" || echo -e " \e[31m-> [编译失败, 退出码: ${SYSYC_S_STATUS}]\e[0m"
|
||||
fi
|
||||
|
||||
echo " [2/2] 使用 sysyc 编译为 IR (超时 ${SYSYC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" -o "${ir_file}" ${OPTIMIZE_FLAG}
|
||||
SYSYC_IR_STATUS=$?
|
||||
if [ $SYSYC_IR_STATUS -eq 0 ]; then
|
||||
ir_compile_ok=1
|
||||
echo -e " \e[32m-> ${ir_file} [成功]\e[0m"
|
||||
else
|
||||
[ $SYSYC_IR_STATUS -eq 124 ] && echo -e " \e[31m-> [编译超时]\e[0m" || echo -e " \e[31m-> [编译失败, 退出码: ${SYSYC_IR_STATUS}]\e[0m"
|
||||
fi
|
||||
|
||||
if [ "$s_compile_ok" -eq 1 ] && [ "$ir_compile_ok" -eq 1 ]; then
|
||||
is_passed=1
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- 统计结果 ---
|
||||
if [ "$is_passed" -eq 1 ]; then
|
||||
((PASSED_CASES++))
|
||||
else
|
||||
# 确保 FAILED_CASES_LIST 的每一项都以换行符结尾
|
||||
FAILED_CASES_LIST+="${relative_path_no_ext}.sy\n"
|
||||
fi
|
||||
echo ""
|
||||
done <<< "$sy_files"
|
||||
|
||||
# --- 修改:调用总结函数 ---
|
||||
print_summary
|
||||
@ -1,171 +0,0 @@
|
||||
#include "AddressCalculationExpansion.h"
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include "IR.h"
|
||||
#include "IRBuilder.h"
|
||||
|
||||
extern int DEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
bool AddressCalculationExpansion::run() {
|
||||
bool changed = false;
|
||||
|
||||
for (auto& funcPair : pModule->getFunctions()) {
|
||||
Function* func = funcPair.second.get();
|
||||
for (auto& bb_ptr : func->getBasicBlocks()) {
|
||||
BasicBlock* bb = bb_ptr.get();
|
||||
for (auto it = bb->getInstructions().begin(); it != bb->getInstructions().end(); ) {
|
||||
Instruction* inst = it->get();
|
||||
|
||||
Value* basePointer = nullptr;
|
||||
Value* valueToStore = nullptr;
|
||||
size_t firstIndexOperandIdx = 0;
|
||||
size_t numBaseOperands = 0;
|
||||
|
||||
if (inst->isLoad()) {
|
||||
numBaseOperands = 1;
|
||||
basePointer = inst->getOperand(0);
|
||||
firstIndexOperandIdx = 1;
|
||||
} else if (inst->isStore()) {
|
||||
numBaseOperands = 2;
|
||||
valueToStore = inst->getOperand(0);
|
||||
basePointer = inst->getOperand(1);
|
||||
firstIndexOperandIdx = 2;
|
||||
} else {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inst->getNumOperands() <= numBaseOperands) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<int> dims;
|
||||
if (AllocaInst* allocaInst = dynamic_cast<AllocaInst*>(basePointer)) {
|
||||
for (const auto& use_ptr : allocaInst->getDims()) {
|
||||
Value* dimValue = use_ptr->getValue();
|
||||
if (ConstantValue* constVal = dynamic_cast<ConstantValue*>(dimValue)) {
|
||||
dims.push_back(constVal->getInt());
|
||||
} else {
|
||||
std::cerr << "Warning: AllocaInst dimension is not a constant integer. Skipping GEP expansion for: ";
|
||||
SysYPrinter::printValue(allocaInst);
|
||||
std::cerr << "\n";
|
||||
dims.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (GlobalValue* globalValue = dynamic_cast<GlobalValue*>(basePointer)) {
|
||||
// 遍历 GlobalValue 的所有维度操作数
|
||||
for (const auto& use_ptr : globalValue->getDims()) {
|
||||
Value* dimValue = use_ptr->getValue();
|
||||
// 将维度值转换为常量整数
|
||||
if (ConstantInteger* constVal = dynamic_cast<ConstantInteger*>(dimValue)) {
|
||||
dims.push_back(constVal->getInt());
|
||||
} else {
|
||||
// 如果维度不是常量整数,则无法处理。
|
||||
// 根据 IR.h 中 GlobalValue 的构造函数,这种情况不应发生,但作为安全检查是好的。
|
||||
std::cerr << "Warning: GlobalValue dimension is not a constant integer. Skipping GEP expansion for: ";
|
||||
SysYPrinter::printValue(globalValue);
|
||||
std::cerr << "\n";
|
||||
dims.clear(); // 清空已收集的部分维度信息
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Warning: Base pointer is not AllocaInst/GlobalValue or its array dimensions cannot be determined for GEP expansion. Skipping GEP for: ";
|
||||
SysYPrinter::printValue(basePointer);
|
||||
std::cerr << " in instruction ";
|
||||
SysYPrinter::printInst(inst);
|
||||
std::cerr << "\n";
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dims.empty() && (inst->getNumOperands() > numBaseOperands)) {
|
||||
if (DEBUG) {
|
||||
std::cerr << "ACE Warning: Could not get valid array dimensions for ";
|
||||
SysYPrinter::printValue(basePointer);
|
||||
std::cerr << " in instruction ";
|
||||
SysYPrinter::printInst(inst);
|
||||
std::cerr << " (expected dimensions for indices, but got none).\n";
|
||||
}
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<Value*> indexOperands;
|
||||
for (size_t i = firstIndexOperandIdx; i < inst->getNumOperands(); ++i) {
|
||||
indexOperands.push_back(inst->getOperand(i));
|
||||
}
|
||||
|
||||
if (AllocaInst* allocaInst = dynamic_cast<AllocaInst*>(basePointer)) {
|
||||
if (allocaInst->getNumDims() != indexOperands.size()) {
|
||||
if (DEBUG) {
|
||||
std::cerr << "ACE Warning: Index count (" << indexOperands.size() << ") does not match AllocaInst dimensions (" << allocaInst->getNumDims() << ") for instruction ";
|
||||
SysYPrinter::printInst(inst);
|
||||
std::cerr << "\n";
|
||||
}
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Value* totalOffset = ConstantInteger::get(0);
|
||||
pBuilder->setPosition(bb, it);
|
||||
|
||||
for (size_t i = 0; i < indexOperands.size(); ++i) {
|
||||
Value* index = indexOperands[i];
|
||||
int stride = calculateStride(dims, i);
|
||||
Value* strideConst = ConstantInteger::get(stride);
|
||||
Type* intType = Type::getIntType();
|
||||
BinaryInst* currentDimOffsetInst = pBuilder->createBinaryInst(Instruction::kMul, intType, index, strideConst);
|
||||
BinaryInst* newTotalOffsetInst = pBuilder->createBinaryInst(Instruction::kAdd, intType, totalOffset, currentDimOffsetInst);
|
||||
totalOffset = newTotalOffsetInst;
|
||||
}
|
||||
|
||||
// 计算有效地址:effective_address = basePointer + totalOffset
|
||||
Value* effective_address = pBuilder->createBinaryInst(Instruction::kAdd, basePointer->getType(), basePointer, totalOffset);
|
||||
|
||||
// 创建新的 LoadInst 或 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,58 +1,24 @@
|
||||
# 移除 ANTLR 代码生成相关配置
|
||||
# list(APPEND CMAKE_MODULE_PATH "${ANTLR_RUNTIME}/cmake")
|
||||
# include(FindANTLR)
|
||||
# antlr_target(SysYGen SysY.g4
|
||||
# LEXER PARSER
|
||||
# OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
# VISITOR
|
||||
# )
|
||||
# src/CMakeLists.txt
|
||||
# add_subdirectory 命令会负责遍历子目录并查找其内部的 CMakeLists.txt 文件
|
||||
add_subdirectory(frontend)
|
||||
add_subdirectory(midend)
|
||||
add_subdirectory(backend/RISCv64)
|
||||
|
||||
# 移除 SysYParser 库的构建(如果不需要独立库)
|
||||
# add_library(SysYParser SHARED ${ANTLR_SysYGen_CXX_OUTPUTS})
|
||||
# target_include_directories(SysYParser PUBLIC ${ANTLR_RUNTIME}/runtime/src)
|
||||
# target_link_libraries(SysYParser PUBLIC antlr4_shared)
|
||||
|
||||
# 构建 sysyc 可执行文件,使用手动提供的 SysYLexer.cpp、SysYParser.cpp 等文件
|
||||
# 构建 sysyc 可执行文件,链接各个模块的库
|
||||
add_executable(sysyc
|
||||
sysyc.cpp
|
||||
SysYLexer.cpp # 手动提供的文件
|
||||
SysYParser.cpp # 手动提供的文件
|
||||
SysYVisitor.cpp # 手动提供的文件
|
||||
IR.cpp
|
||||
SysYIRGenerator.cpp
|
||||
SysYIRPrinter.cpp
|
||||
SysYIRCFGOpt.cpp
|
||||
Pass.cpp
|
||||
Dom.cpp
|
||||
Liveness.cpp
|
||||
DCE.cpp
|
||||
AddressCalculationExpansion.cpp
|
||||
# Mem2Reg.cpp
|
||||
# Reg2Mem.cpp
|
||||
RISCv64Backend.cpp
|
||||
RISCv64ISel.cpp
|
||||
RISCv64RegAlloc.cpp
|
||||
RISCv64AsmPrinter.cpp
|
||||
RISCv64Peephole.cpp
|
||||
PreRA_Scheduler.cpp
|
||||
PostRA_Scheduler.cpp
|
||||
CalleeSavedHandler.cpp
|
||||
RISCv64LLIR.cpp
|
||||
sysyc.cpp
|
||||
)
|
||||
|
||||
# 设置 include 路径,包含 ANTLR 运行时库和项目头文件
|
||||
# 链接各个模块的库
|
||||
target_link_libraries(sysyc PRIVATE
|
||||
frontend_lib
|
||||
midend_lib
|
||||
riscv64_backend_lib
|
||||
antlr4_shared
|
||||
)
|
||||
|
||||
# 设置 include 路径,包含项目顶层 include 目录
|
||||
target_include_directories(sysyc PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include # 项目头文件目录
|
||||
${ANTLR_RUNTIME}/runtime/src # ANTLR 运行时库头文件
|
||||
)
|
||||
|
||||
# 保留 ANTLR 运行时库的链接
|
||||
target_link_libraries(sysyc PRIVATE antlr4_shared)
|
||||
|
||||
# 保留其他编译选项
|
||||
target_compile_options(sysyc PRIVATE -frtti)
|
||||
|
||||
# 可选:线程支持(如果需要,取消注释)
|
||||
# set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
# find_package(Threads REQUIRED)
|
||||
# target_link_libraries(sysyc PRIVATE Threads::Threads)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include # 项目头文件目录
|
||||
${ANTLR_RUNTIME}/runtime/src # ANTLR运行时库头文件
|
||||
)
|
||||
@ -1,123 +0,0 @@
|
||||
#include "CalleeSavedHandler.h"
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
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) {
|
||||
// 【最终方案】: 此 Pass 负责分析、分配栈空间并插入 callee-saved 寄存器的保存/恢复指令。
|
||||
// 它通过与 FrameInfo 协作,确保为 callee-saved 寄存器分配的空间与局部变量/溢出槽的空间不冲突。
|
||||
// 这样做可以使生成的 sd/ld 指令能被后续的优化 Pass (如 PostRA-Scheduler) 处理。
|
||||
|
||||
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
||||
std::set<PhysicalReg> used_callee_saved;
|
||||
|
||||
// 1. 扫描所有指令,找出被使用的s寄存器 (s1-s11)
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
for (auto& instr : mbb->getInstructions()) {
|
||||
for (auto& op : instr->getOperands()) {
|
||||
auto check_and_insert_reg = [&](RegOperand* reg_op) {
|
||||
if (!reg_op->isVirtual()) {
|
||||
PhysicalReg preg = reg_op->getPReg();
|
||||
if (preg >= PhysicalReg::S1 && preg <= PhysicalReg::S11) {
|
||||
used_callee_saved.insert(preg);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
check_and_insert_reg(static_cast<RegOperand*>(op.get()));
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
check_and_insert_reg(static_cast<MemOperand*>(op.get())->getBase());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (used_callee_saved.empty()) {
|
||||
frame_info.callee_saved_size = 0; // 确保大小被初始化
|
||||
return; // 无需操作
|
||||
}
|
||||
|
||||
// 2. 计算为 callee-saved 寄存器分配的栈空间
|
||||
// 这里的关键是,偏移的基准点要在局部变量和溢出槽之下。
|
||||
int callee_saved_size = used_callee_saved.size() * 8;
|
||||
frame_info.callee_saved_size = callee_saved_size; // 将大小存入 FrameInfo
|
||||
|
||||
// 3. 计算无冲突的栈偏移
|
||||
// 栈向下增长,所以偏移是负数。
|
||||
// ra/s0 占用 -8 和 -16。局部变量和溢出区在它们之下。callee-saved 区在更下方。
|
||||
// 我们使用相对于 s0 的偏移。s0 将指向栈顶 (sp + total_size)。
|
||||
int base_offset = -16 - frame_info.locals_size - frame_info.spill_size;
|
||||
|
||||
// 为了栈帧布局确定性,对寄存器进行排序
|
||||
std::vector<PhysicalReg> sorted_regs(used_callee_saved.begin(), used_callee_saved.end());
|
||||
std::sort(sorted_regs.begin(), sorted_regs.end());
|
||||
|
||||
// 4. 在函数序言插入保存指令
|
||||
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
|
||||
auto& entry_instrs = entry_block->getInstructions();
|
||||
auto prologue_end = entry_instrs.begin();
|
||||
|
||||
// 找到序言结束的位置(通常是addi s0, sp, size之后,但为了让优化器看到,我们插在更前面)
|
||||
// 合理的位置是在 IR 指令开始之前,即在任何非序言指令(如第一个标签)之前。
|
||||
// 为简单起见,我们直接插入到块的开头,后续重排 pass 会处理。
|
||||
// (更优的实现会寻找一个特定的插入点)
|
||||
|
||||
int current_offset = base_offset;
|
||||
for (PhysicalReg reg : sorted_regs) {
|
||||
auto sd = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
||||
sd->addOperand(std::make_unique<RegOperand>(reg));
|
||||
sd->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0), // 基址为帧指针 s0
|
||||
std::make_unique<ImmOperand>(current_offset)
|
||||
));
|
||||
// 从头部插入,但要放在函数标签之后
|
||||
entry_instrs.insert(entry_instrs.begin() + 1, std::move(sd));
|
||||
current_offset -= 8;
|
||||
}
|
||||
|
||||
// 5. 【已修复】在函数结尾(ret之前)插入恢复指令,使用反向遍历来避免迭代器失效
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
// 使用手动控制的反向循环
|
||||
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
|
||||
if ((*it)->getOpcode() == RVOpcodes::RET) {
|
||||
// 1. 创建一个临时vector来存储所有需要插入的恢复指令
|
||||
std::vector<std::unique_ptr<MachineInstr>> restore_instrs;
|
||||
|
||||
int current_offset_load = base_offset;
|
||||
// 以相同的顺序(例如 s1, s2, ...)创建恢复指令
|
||||
for (PhysicalReg reg : sorted_regs) {
|
||||
auto ld = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
||||
ld->addOperand(std::make_unique<RegOperand>(reg));
|
||||
ld->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(current_offset_load)
|
||||
));
|
||||
restore_instrs.push_back(std::move(ld));
|
||||
current_offset_load -= 8;
|
||||
}
|
||||
|
||||
// 2. 使用 make_move_iterator 一次性将所有恢复指令插入到 RET 指令之前
|
||||
// 这可以高效地转移指令的所有权,并且只让迭代器失效一次。
|
||||
if (!restore_instrs.empty()) {
|
||||
mbb->getInstructions().insert(it,
|
||||
std::make_move_iterator(restore_instrs.begin()),
|
||||
std::make_move_iterator(restore_instrs.end())
|
||||
);
|
||||
}
|
||||
|
||||
// 找到了RET并处理完毕后,就可以跳出内层循环,继续寻找下一个基本块
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
180
src/Dom.cpp
180
src/Dom.cpp
@ -1,180 +0,0 @@
|
||||
#include "Dom.h"
|
||||
#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;
|
||||
}
|
||||
|
||||
void DominatorTree::computeDominators(Function *F) {
|
||||
// 经典的迭代算法计算支配者集合
|
||||
// TODO: 可以替换为更高效的算法,如 Lengauer-Tarjan 算法
|
||||
BasicBlock *entryBlock = F->getEntryBlock();
|
||||
|
||||
for (const auto &bb_ptr : F->getBasicBlocks()) {
|
||||
BasicBlock *bb = bb_ptr.get();
|
||||
if (bb == entryBlock) {
|
||||
Dominators[bb].insert(bb);
|
||||
} else {
|
||||
for (const auto &all_bb_ptr : F->getBasicBlocks()) {
|
||||
Dominators[bb].insert(all_bb_ptr.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
for (const auto &bb_ptr : F->getBasicBlocks()) {
|
||||
BasicBlock *bb = bb_ptr.get();
|
||||
if (bb == entryBlock)
|
||||
continue;
|
||||
|
||||
std::set<BasicBlock *> newDom;
|
||||
bool firstPred = true;
|
||||
for (BasicBlock *pred : bb->getPredecessors()) {
|
||||
if (Dominators.count(pred)) {
|
||||
if (firstPred) {
|
||||
newDom = Dominators[pred];
|
||||
firstPred = false;
|
||||
} 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);
|
||||
|
||||
if (newDom != Dominators[bb]) {
|
||||
Dominators[bb] = newDom;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DominatorTree::computeIDoms(Function *F) {
|
||||
// 采用与之前类似的简化实现。TODO:Lengauer-Tarjan等算法。
|
||||
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)
|
||||
continue;
|
||||
|
||||
for (BasicBlock *D : *domsOfBB) {
|
||||
if (D == bb)
|
||||
continue;
|
||||
|
||||
bool isCandidateIDom = true;
|
||||
for (BasicBlock *candidate : *domsOfBB) {
|
||||
if (candidate == bb || candidate == D)
|
||||
continue;
|
||||
const std::set<BasicBlock *> *domsOfCandidate = getDominators(candidate);
|
||||
if (domsOfCandidate && domsOfCandidate->count(D) == 0 && domsOfBB->count(candidate)) {
|
||||
isCandidateIDom = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isCandidateIDom) {
|
||||
currentIDom = D;
|
||||
break;
|
||||
}
|
||||
}
|
||||
IDoms[bb] = currentIDom;
|
||||
}
|
||||
}
|
||||
|
||||
void DominatorTree::computeDominanceFrontiers(Function *F) {
|
||||
// 经典的支配边界计算算法
|
||||
for (const auto &bb_ptr_X : F->getBasicBlocks()) {
|
||||
BasicBlock *X = bb_ptr_X.get();
|
||||
DominanceFrontiers[X].clear();
|
||||
|
||||
for (BasicBlock *Y : X->getSuccessors()) {
|
||||
const std::set<BasicBlock *> *domsOfY = getDominators(Y);
|
||||
if (domsOfY && domsOfY->find(X) == domsOfY->end()) {
|
||||
DominanceFrontiers[X].insert(Y);
|
||||
}
|
||||
}
|
||||
|
||||
const std::set<BasicBlock *> *domsOfX = getDominators(X);
|
||||
if (!domsOfX)
|
||||
continue;
|
||||
for (const auto &bb_ptr_Z : F->getBasicBlocks()) {
|
||||
BasicBlock *Z = bb_ptr_Z.get();
|
||||
if (Z == X)
|
||||
continue;
|
||||
const std::set<BasicBlock *> *domsOfZ = getDominators(Z);
|
||||
if (domsOfZ && domsOfZ->count(X) && Z != X) {
|
||||
|
||||
for (BasicBlock *Y : Z->getSuccessors()) {
|
||||
const std::set<BasicBlock *> *domsOfY = getDominators(Y);
|
||||
if (domsOfY && domsOfY->find(X) == domsOfY->end()) {
|
||||
DominanceFrontiers[X].insert(Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================================================
|
||||
// DominatorTreeAnalysisPass 的实现
|
||||
// ==============================================================
|
||||
|
||||
|
||||
bool DominatorTreeAnalysisPass::runOnFunction(Function* F, AnalysisManager &AM) {
|
||||
CurrentDominatorTree = std::make_unique<DominatorTree>(F);
|
||||
CurrentDominatorTree->computeDominators(F);
|
||||
CurrentDominatorTree->computeIDoms(F);
|
||||
CurrentDominatorTree->computeDominanceFrontiers(F);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<AnalysisResultBase> DominatorTreeAnalysisPass::getResult() {
|
||||
// 返回计算好的 DominatorTree 实例,所有权转移给 AnalysisManager
|
||||
return std::move(CurrentDominatorTree);
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
742
src/IR.cpp
742
src/IR.cpp
@ -1,742 +0,0 @@
|
||||
#include "IR.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include "IRBuilder.h"
|
||||
|
||||
/**
|
||||
* @file IR.cpp
|
||||
*
|
||||
* @brief 定义IR相关类型与操作的源文件
|
||||
*/
|
||||
namespace sysy {
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Types
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
auto Type::getIntType() -> Type * {
|
||||
static Type intType(kInt);
|
||||
return &intType;
|
||||
}
|
||||
|
||||
auto Type::getFloatType() -> Type * {
|
||||
static Type floatType(kFloat);
|
||||
return &floatType;
|
||||
}
|
||||
|
||||
auto Type::getVoidType() -> Type * {
|
||||
static Type voidType(kVoid);
|
||||
return &voidType;
|
||||
}
|
||||
|
||||
auto Type::getLabelType() -> Type * {
|
||||
static Type labelType(kLabel);
|
||||
return &labelType;
|
||||
}
|
||||
|
||||
auto Type::getPointerType(Type *baseType) -> Type * {
|
||||
// forward to PointerType
|
||||
return PointerType::get(baseType);
|
||||
}
|
||||
|
||||
auto Type::getFunctionType(Type *returnType, const std::vector<Type *> ¶mTypes) -> Type * {
|
||||
// forward to FunctionType
|
||||
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:
|
||||
case kFloat:
|
||||
return 4;
|
||||
case kLabel:
|
||||
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;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
PointerType* PointerType::get(Type *baseType) {
|
||||
static std::map<Type *, std::unique_ptr<PointerType>> pointerTypes;
|
||||
auto iter = pointerTypes.find(baseType);
|
||||
if (iter != pointerTypes.end()) {
|
||||
return iter->second.get();
|
||||
}
|
||||
auto type = new PointerType(baseType);
|
||||
assert(type);
|
||||
auto result = pointerTypes.emplace(baseType, type);
|
||||
return result.first->second.get();
|
||||
}
|
||||
|
||||
FunctionType*FunctionType::get(Type *returnType, const std::vector<Type *> ¶mTypes) {
|
||||
static std::set<std::unique_ptr<FunctionType>> functionTypes;
|
||||
auto iter =
|
||||
std::find_if(functionTypes.begin(), functionTypes.end(), [&](const std::unique_ptr<FunctionType> &type) -> bool {
|
||||
if (returnType != type->getReturnType() ||
|
||||
paramTypes.size() != static_cast<size_t>(type->getParamTypes().size())) {
|
||||
return false;
|
||||
}
|
||||
return std::equal(paramTypes.begin(), paramTypes.end(), type->getParamTypes().begin());
|
||||
});
|
||||
if (iter != functionTypes.end()) {
|
||||
return iter->get();
|
||||
}
|
||||
auto type = new FunctionType(returnType, paramTypes);
|
||||
assert(type);
|
||||
auto result = functionTypes.emplace(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);
|
||||
}
|
||||
uses.clear();
|
||||
}
|
||||
|
||||
|
||||
// Implementations for static members
|
||||
|
||||
std::unordered_map<ConstantValueKey, ConstantValue*, ConstantValueHash, ConstantValueEqual> ConstantValue::mConstantPool;
|
||||
std::unordered_map<Type*, UndefinedValue*> UndefinedValue::UndefValues;
|
||||
|
||||
ConstantValue* ConstantValue::get(Type* type, ConstantValVariant val) {
|
||||
ConstantValueKey key = {type, val};
|
||||
auto it = mConstantPool.find(key);
|
||||
if (it != mConstantPool.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
ConstantValue* newConstant = nullptr;
|
||||
if (std::holds_alternative<int>(val)) {
|
||||
newConstant = new ConstantInteger(type, std::get<int>(val));
|
||||
} else if (std::holds_alternative<float>(val)) {
|
||||
newConstant = new ConstantFloating(type, std::get<float>(val));
|
||||
} else {
|
||||
assert(false && "Unsupported ConstantValVariant type");
|
||||
}
|
||||
|
||||
mConstantPool[key] = newConstant;
|
||||
return newConstant;
|
||||
}
|
||||
|
||||
ConstantInteger* ConstantInteger::get(Type* type, int val) {
|
||||
return dynamic_cast<ConstantInteger*>(ConstantValue::get(type, val));
|
||||
}
|
||||
|
||||
ConstantFloating* ConstantFloating::get(Type* type, float val) {
|
||||
return dynamic_cast<ConstantFloating*>(ConstantValue::get(type, val));
|
||||
}
|
||||
|
||||
UndefinedValue* UndefinedValue::get(Type* type) {
|
||||
assert(!type->isVoid() && "Cannot get UndefinedValue of void type!");
|
||||
|
||||
auto it = UndefValues.find(type);
|
||||
if (it != UndefValues.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
UndefinedValue* newUndef = new UndefinedValue(type);
|
||||
UndefValues[type] = newUndef;
|
||||
return newUndef;
|
||||
}
|
||||
|
||||
|
||||
auto Function::getCalleesWithNoExternalAndSelf() -> std::set<Function *> {
|
||||
std::set<Function *> result;
|
||||
for (auto callee : callees) {
|
||||
if (parent->getExternalFunctions().count(callee->getName()) == 0U && callee != this) {
|
||||
result.insert(callee);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
// 函数克隆,后续函数级优化(内联等)需要用到
|
||||
Function * Function::clone(const std::string &suffix) const {
|
||||
std::stringstream ss;
|
||||
std::map<BasicBlock *, BasicBlock *> oldNewBlockMap;
|
||||
IRBuilder builder;
|
||||
auto newFunction = new Function(parent, type, name);
|
||||
newFunction->getEntryBlock()->setName(blocks.front()->getName());
|
||||
oldNewBlockMap.emplace(blocks.front().get(), newFunction->getEntryBlock());
|
||||
auto oldBlockListIter = std::next(blocks.begin());
|
||||
while (oldBlockListIter != blocks.end()) {
|
||||
auto newBlock = newFunction->addBasicBlock(oldBlockListIter->get()->getName());
|
||||
oldNewBlockMap.emplace(oldBlockListIter->get(), newBlock);
|
||||
oldBlockListIter++;
|
||||
}
|
||||
|
||||
for (const auto &oldNewBlockItem : oldNewBlockMap) {
|
||||
auto oldBlock = oldNewBlockItem.first;
|
||||
auto newBlock = oldNewBlockItem.second;
|
||||
for (const auto &oldPred : oldBlock->getPredecessors()) {
|
||||
newBlock->addPredecessor(oldNewBlockMap.at(oldPred));
|
||||
}
|
||||
for (const auto &oldSucc : oldBlock->getSuccessors()) {
|
||||
newBlock->addSuccessor(oldNewBlockMap.at(oldSucc));
|
||||
}
|
||||
}
|
||||
|
||||
std::map<Value *, Value *> oldNewValueMap;
|
||||
std::map<Value *, bool> isAddedToCreate;
|
||||
std::map<Value *, bool> isCreated;
|
||||
std::queue<Value *> toCreate;
|
||||
|
||||
for (const auto &oldBlock : blocks) {
|
||||
for (const auto &inst : oldBlock->getInstructions()) {
|
||||
isAddedToCreate.emplace(inst.get(), false);
|
||||
isCreated.emplace(inst.get(), false);
|
||||
}
|
||||
}
|
||||
for (const auto &oldBlock : blocks) {
|
||||
for (const auto &inst : oldBlock->getInstructions()) {
|
||||
for (const auto &valueUse : inst->getOperands()) {
|
||||
auto value = valueUse->getValue();
|
||||
if (oldNewValueMap.find(value) == oldNewValueMap.end()) {
|
||||
auto oldAllocInst = dynamic_cast<AllocaInst *>(value);
|
||||
if (oldAllocInst != nullptr) {
|
||||
std::vector<Value *> dims;
|
||||
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());
|
||||
ss.str("");
|
||||
oldNewValueMap.emplace(oldAllocInst, newAllocInst);
|
||||
if (isAddedToCreate.find(oldAllocInst) == isAddedToCreate.end()) {
|
||||
isAddedToCreate.emplace(oldAllocInst, true);
|
||||
} else {
|
||||
isAddedToCreate.at(oldAllocInst) = true;
|
||||
}
|
||||
if (isCreated.find(oldAllocInst) == isCreated.end()) {
|
||||
isCreated.emplace(oldAllocInst, true);
|
||||
} else {
|
||||
isCreated.at(oldAllocInst) = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (inst->getKind() == Instruction::kAlloca) {
|
||||
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());
|
||||
}
|
||||
ss << oldAllocInst->getName() << suffix;
|
||||
auto newAllocInst =
|
||||
new AllocaInst(oldAllocInst->getType(), dims, oldNewBlockMap.at(oldAllocInst->getParent()), ss.str());
|
||||
ss.str("");
|
||||
oldNewValueMap.emplace(oldAllocInst, newAllocInst);
|
||||
if (isAddedToCreate.find(oldAllocInst) == isAddedToCreate.end()) {
|
||||
isAddedToCreate.emplace(oldAllocInst, true);
|
||||
} else {
|
||||
isAddedToCreate.at(oldAllocInst) = true;
|
||||
}
|
||||
if (isCreated.find(oldAllocInst) == isCreated.end()) {
|
||||
isCreated.emplace(oldAllocInst, true);
|
||||
} else {
|
||||
isCreated.at(oldAllocInst) = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto &oldBlock : blocks) {
|
||||
for (const auto &inst : oldBlock->getInstructions()) {
|
||||
for (const auto &valueUse : inst->getOperands()) {
|
||||
auto value = valueUse->getValue();
|
||||
if (oldNewValueMap.find(value) == oldNewValueMap.end()) {
|
||||
auto globalValue = dynamic_cast<GlobalValue *>(value);
|
||||
auto constVariable = dynamic_cast<ConstantVariable *>(value);
|
||||
auto constantValue = dynamic_cast<ConstantValue *>(value);
|
||||
auto functionValue = dynamic_cast<Function *>(value);
|
||||
if (globalValue != nullptr || constantValue != nullptr || constVariable != nullptr ||
|
||||
functionValue != nullptr) {
|
||||
if (functionValue == this) {
|
||||
oldNewValueMap.emplace(value, newFunction);
|
||||
} else {
|
||||
oldNewValueMap.emplace(value, value);
|
||||
}
|
||||
isCreated.emplace(value, true);
|
||||
isAddedToCreate.emplace(value, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto &oldBlock : blocks) {
|
||||
for (const auto &inst : oldBlock->getInstructions()) {
|
||||
if (inst->getKind() != Instruction::kAlloca) {
|
||||
bool isReady = true;
|
||||
for (const auto &use : inst->getOperands()) {
|
||||
auto value = use->getValue();
|
||||
if (dynamic_cast<BasicBlock *>(value) == nullptr && !isCreated.at(value)) {
|
||||
isReady = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isReady) {
|
||||
toCreate.push(inst.get());
|
||||
isAddedToCreate.at(inst.get()) = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (!toCreate.empty()) {
|
||||
auto inst = dynamic_cast<Instruction *>(toCreate.front());
|
||||
toCreate.pop();
|
||||
|
||||
bool isReady = true;
|
||||
for (const auto &valueUse : inst->getOperands()) {
|
||||
auto value = dynamic_cast<Instruction *>(valueUse->getValue());
|
||||
if (value != nullptr && !isCreated.at(value)) {
|
||||
isReady = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isReady) {
|
||||
toCreate.push(inst);
|
||||
continue;
|
||||
}
|
||||
isCreated.at(inst) = true;
|
||||
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::kAnd:
|
||||
case Instruction::kOr:
|
||||
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: {
|
||||
auto oldBinaryInst = dynamic_cast<BinaryInst *>(inst);
|
||||
auto lhs = oldBinaryInst->getLhs();
|
||||
auto rhs = oldBinaryInst->getRhs();
|
||||
Value *newLhs;
|
||||
Value *newRhs;
|
||||
newLhs = oldNewValueMap[lhs];
|
||||
newRhs = oldNewValueMap[rhs];
|
||||
ss << oldBinaryInst->getName() << suffix;
|
||||
auto newBinaryInst = new BinaryInst(oldBinaryInst->getKind(), oldBinaryInst->getType(), newLhs, newRhs,
|
||||
oldNewBlockMap.at(oldBinaryInst->getParent()), ss.str());
|
||||
ss.str("");
|
||||
oldNewValueMap.emplace(oldBinaryInst, newBinaryInst);
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::kNeg:
|
||||
case Instruction::kNot:
|
||||
case Instruction::kFNeg:
|
||||
case Instruction::kFNot:
|
||||
case Instruction::kItoF:
|
||||
case Instruction::kFtoI: {
|
||||
auto oldUnaryInst = dynamic_cast<UnaryInst *>(inst);
|
||||
auto hs = oldUnaryInst->getOperand();
|
||||
Value *newHs;
|
||||
newHs = oldNewValueMap.at(hs);
|
||||
ss << oldUnaryInst->getName() << suffix;
|
||||
auto newUnaryInst = new UnaryInst(oldUnaryInst->getKind(), oldUnaryInst->getType(), newHs,
|
||||
oldNewBlockMap.at(oldUnaryInst->getParent()), ss.str());
|
||||
ss.str("");
|
||||
oldNewValueMap.emplace(oldUnaryInst, newUnaryInst);
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::kCall: {
|
||||
auto oldCallInst = dynamic_cast<CallInst *>(inst);
|
||||
std::vector<Value *> newArgumnts;
|
||||
for (const auto &arg : oldCallInst->getArguments()) {
|
||||
newArgumnts.emplace_back(oldNewValueMap.at(arg->getValue()));
|
||||
}
|
||||
|
||||
ss << oldCallInst->getName() << suffix;
|
||||
CallInst *newCallInst;
|
||||
newCallInst =
|
||||
new CallInst(oldCallInst->getCallee(), newArgumnts, oldNewBlockMap.at(oldCallInst->getParent()), ss.str());
|
||||
ss.str("");
|
||||
// if (oldCallInst->getCallee() != this) {
|
||||
// newCallInst = new CallInst(oldCallInst->getCallee(), newArgumnts,
|
||||
// oldNewBlockMap.at(oldCallInst->getParent()),
|
||||
// oldCallInst->getName());
|
||||
// } else {
|
||||
// newCallInst = new CallInst(newFunction, newArgumnts, oldNewBlockMap.at(oldCallInst->getParent()),
|
||||
// oldCallInst->getName());
|
||||
// }
|
||||
|
||||
oldNewValueMap.emplace(oldCallInst, newCallInst);
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::kCondBr: {
|
||||
auto oldCondBrInst = dynamic_cast<CondBrInst *>(inst);
|
||||
auto oldCond = oldCondBrInst->getCondition();
|
||||
Value *newCond;
|
||||
newCond = oldNewValueMap.at(oldCond);
|
||||
auto newCondBrInst = new CondBrInst(newCond, oldNewBlockMap.at(oldCondBrInst->getThenBlock()),
|
||||
oldNewBlockMap.at(oldCondBrInst->getElseBlock()), {}, {},
|
||||
oldNewBlockMap.at(oldCondBrInst->getParent()));
|
||||
oldNewValueMap.emplace(oldCondBrInst, newCondBrInst);
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::kBr: {
|
||||
auto oldBrInst = dynamic_cast<UncondBrInst *>(inst);
|
||||
auto newBrInst =
|
||||
new UncondBrInst(oldNewBlockMap.at(oldBrInst->getBlock()), {}, oldNewBlockMap.at(oldBrInst->getParent()));
|
||||
oldNewValueMap.emplace(oldBrInst, newBrInst);
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::kReturn: {
|
||||
auto oldReturnInst = dynamic_cast<ReturnInst *>(inst);
|
||||
auto oldRval = oldReturnInst->getReturnValue();
|
||||
Value *newRval = nullptr;
|
||||
if (oldRval != nullptr) {
|
||||
newRval = oldNewValueMap.at(oldRval);
|
||||
}
|
||||
auto newReturnInst =
|
||||
new ReturnInst(newRval, oldNewBlockMap.at(oldReturnInst->getParent()), oldReturnInst->getName());
|
||||
oldNewValueMap.emplace(oldReturnInst, newReturnInst);
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::kAlloca: {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
case Instruction::kLoad: {
|
||||
auto oldLoadInst = dynamic_cast<LoadInst *>(inst);
|
||||
auto oldPointer = oldLoadInst->getPointer();
|
||||
Value *newPointer;
|
||||
newPointer = oldNewValueMap.at(oldPointer);
|
||||
|
||||
std::vector<Value *> newIndices;
|
||||
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());
|
||||
ss.str("");
|
||||
oldNewValueMap.emplace(oldLoadInst, newLoadInst);
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::kStore: {
|
||||
auto oldStoreInst = dynamic_cast<StoreInst *>(inst);
|
||||
auto oldPointer = oldStoreInst->getPointer();
|
||||
auto oldValue = oldStoreInst->getValue();
|
||||
Value *newPointer;
|
||||
Value *newValue;
|
||||
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,
|
||||
oldNewBlockMap.at(oldStoreInst->getParent()), oldStoreInst->getName());
|
||||
oldNewValueMap.emplace(oldStoreInst, newStoreInst);
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO:复制GEP指令
|
||||
|
||||
case Instruction::kMemset: {
|
||||
auto oldMemsetInst = dynamic_cast<MemsetInst *>(inst);
|
||||
auto oldPointer = oldMemsetInst->getPointer();
|
||||
auto oldValue = oldMemsetInst->getValue();
|
||||
Value *newPointer;
|
||||
Value *newValue;
|
||||
newPointer = oldNewValueMap.at(oldPointer);
|
||||
newValue = oldNewValueMap.at(oldValue);
|
||||
|
||||
auto newMemsetInst = new MemsetInst(newPointer, oldMemsetInst->getBegin(), oldMemsetInst->getSize(), newValue,
|
||||
oldNewBlockMap.at(oldMemsetInst->getParent()), oldMemsetInst->getName());
|
||||
oldNewValueMap.emplace(oldMemsetInst, newMemsetInst);
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::kInvalid:
|
||||
case Instruction::kPhi: {
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
for (const auto &userUse : inst->getUses()) {
|
||||
auto user = userUse->getUser();
|
||||
if (!isAddedToCreate.at(user)) {
|
||||
toCreate.push(user);
|
||||
isAddedToCreate.at(user) = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &oldBlock : blocks) {
|
||||
auto newBlock = oldNewBlockMap.at(oldBlock.get());
|
||||
builder.setPosition(newBlock, newBlock->end());
|
||||
for (const auto &inst : oldBlock->getInstructions()) {
|
||||
builder.insertInst(dynamic_cast<Instruction *>(oldNewValueMap.at(inst.get())));
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
/**
|
||||
* 设置操作数
|
||||
*/
|
||||
void User::setOperand(unsigned index, Value *value) {
|
||||
assert(index < getNumOperands());
|
||||
operands[index]->setValue(value);
|
||||
value->addUse(operands[index]);
|
||||
}
|
||||
/**
|
||||
* 替换操作数
|
||||
*/
|
||||
void User::replaceOperand(unsigned index, Value *value) {
|
||||
assert(index < getNumOperands());
|
||||
auto &use = operands[index];
|
||||
use->getValue()->removeUse(use);
|
||||
use->setValue(value);
|
||||
value->addUse(use);
|
||||
}
|
||||
|
||||
/**
|
||||
* phi相关函数
|
||||
*/
|
||||
|
||||
Value* PhiInst::getvalfromBlk(BasicBlock* blk){
|
||||
refreshB2VMap();
|
||||
if( blk2val.find(blk) != blk2val.end()) {
|
||||
return blk2val.at(blk);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BasicBlock* PhiInst::getBlkfromVal(Value* val){
|
||||
// 返回第一个值对应的基本块
|
||||
for(unsigned i = 0; i < vsize; i++) {
|
||||
if(getValue(i) == val) {
|
||||
return getBlock(i);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void PhiInst::delValue(Value* val){
|
||||
//根据value删除对应的基本块和值
|
||||
unsigned i = 0;
|
||||
BasicBlock* blk = getBlkfromVal(val);
|
||||
for(i = 0; i < vsize; i++) {
|
||||
if(getValue(i) == val) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
removeOperand(2 * i + 1); // 删除blk
|
||||
removeOperand(2 * i); // 删除val
|
||||
vsize--;
|
||||
blk2val.erase(blk); // 删除blk2val映射
|
||||
}
|
||||
|
||||
void PhiInst::delBlk(BasicBlock* blk){
|
||||
//根据Blk删除对应的基本块和值
|
||||
unsigned i = 0;
|
||||
Value* val = getvalfromBlk(blk);
|
||||
for(i = 0; i < vsize; i++) {
|
||||
if(getBlock(i) == blk) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
removeOperand(2 * i + 1); // 删除blk
|
||||
removeOperand(2 * i); // 删除val
|
||||
vsize--;
|
||||
blk2val.erase(blk); // 删除blk2val映射
|
||||
}
|
||||
|
||||
void PhiInst::replaceBlk(BasicBlock* newBlk, unsigned k){
|
||||
refreshB2VMap();
|
||||
Value* val = blk2val.at(getBlock(k));
|
||||
// 替换基本块
|
||||
setOperand(2 * k + 1, newBlk);
|
||||
// 替换blk2val映射
|
||||
blk2val.erase(getBlock(k));
|
||||
blk2val.emplace(newBlk, val);
|
||||
}
|
||||
|
||||
void PhiInst::replaceold2new(BasicBlock* oldBlk, BasicBlock* newBlk){
|
||||
refreshB2VMap();
|
||||
Value* val = blk2val.at(oldBlk);
|
||||
// 替换基本块
|
||||
delBlk(oldBlk);
|
||||
addIncoming(val, newBlk);
|
||||
}
|
||||
|
||||
void PhiInst::refreshB2VMap(){
|
||||
blk2val.clear();
|
||||
for(unsigned i = 0; i < vsize; i++) {
|
||||
blk2val.emplace(getBlock(i), getValue(i));
|
||||
}
|
||||
}
|
||||
|
||||
CallInst::CallInst(Function *callee, const std::vector<Value *> &args, BasicBlock *parent, const std::string &name)
|
||||
: Instruction(kCall, callee->getReturnType(), parent, name) {
|
||||
addOperand(callee);
|
||||
for (auto arg : args) {
|
||||
addOperand(arg);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取被调用函数的指针
|
||||
*/
|
||||
Function * CallInst::getCallee() const { return dynamic_cast<Function *>(getOperand(0)); }
|
||||
|
||||
/**
|
||||
* 获取变量指针
|
||||
*/
|
||||
auto SymbolTable::getVariable(const std::string &name) const -> Value * {
|
||||
auto node = curNode;
|
||||
while (node != nullptr) {
|
||||
auto iter = node->varList.find(name);
|
||||
if (iter != node->varList.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
node = node->pNode;
|
||||
}
|
||||
|
||||
return 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);
|
||||
if (iter != variableIndex.end()) {
|
||||
ss << name << iter->second ;
|
||||
iter->second += 1;
|
||||
} else {
|
||||
variableIndex.emplace(name, 1);
|
||||
ss << name << 0 ;
|
||||
}
|
||||
|
||||
variable->setName(ss.str());
|
||||
curNode->varList.emplace(name, variable);
|
||||
auto global = dynamic_cast<GlobalValue *>(variable);
|
||||
auto constvar = dynamic_cast<ConstantVariable *>(variable);
|
||||
if (global != nullptr) {
|
||||
globals.emplace_back(global);
|
||||
} else if (constvar != nullptr) {
|
||||
consts.emplace_back(constvar);
|
||||
}
|
||||
|
||||
result = variable;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* 获取全局变量
|
||||
*/
|
||||
auto SymbolTable::getGlobals() -> std::vector<std::unique_ptr<GlobalValue>> & { return globals; }
|
||||
/**
|
||||
* 获取常量
|
||||
*/
|
||||
auto SymbolTable::getConsts() const -> const std::vector<std::unique_ptr<ConstantVariable>> & { return consts; }
|
||||
/**
|
||||
* 进入新的作用域
|
||||
*/
|
||||
void SymbolTable::enterNewScope() {
|
||||
auto newNode = new SymbolTableNode;
|
||||
nodeList.emplace_back(newNode);
|
||||
if (curNode != nullptr) {
|
||||
curNode->children.emplace_back(newNode);
|
||||
}
|
||||
newNode->pNode = curNode;
|
||||
curNode = newNode;
|
||||
}
|
||||
/**
|
||||
* 进入全局作用域
|
||||
*/
|
||||
void SymbolTable::enterGlobalScope() { curNode = nodeList.front().get(); }
|
||||
/**
|
||||
* 离开作用域
|
||||
*/
|
||||
void SymbolTable::leaveScope() { curNode = curNode->pNode; }
|
||||
/**
|
||||
* 是否位于全局作用域
|
||||
*/
|
||||
auto SymbolTable::isInGlobalScope() const -> bool { return curNode->pNode == nullptr; }
|
||||
|
||||
/**
|
||||
*移动指令
|
||||
*/
|
||||
auto BasicBlock::moveInst(iterator sourcePos, iterator targetPos, BasicBlock *block) -> iterator {
|
||||
auto inst = sourcePos->release();
|
||||
inst->setParent(block);
|
||||
block->instructions.emplace(targetPos, inst);
|
||||
return instructions.erase(sourcePos);
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@ -1,383 +0,0 @@
|
||||
#include "PostRA_Scheduler.h"
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#define MAX_SCHEDULING_BLOCK_SIZE 10000 // 限制调度块大小,避免过大导致性能问题
|
||||
|
||||
namespace sysy {
|
||||
|
||||
char PostRA_Scheduler::ID = 0;
|
||||
|
||||
// 检查指令是否是加载指令 (LW, LD)
|
||||
bool isLoadInstr(MachineInstr* instr) {
|
||||
RVOpcodes opcode = instr->getOpcode();
|
||||
return opcode == RVOpcodes::LW || opcode == RVOpcodes::LD ||
|
||||
opcode == RVOpcodes::LH || opcode == RVOpcodes::LB ||
|
||||
opcode == RVOpcodes::LHU || opcode == RVOpcodes::LBU ||
|
||||
opcode == RVOpcodes::LWU;
|
||||
}
|
||||
|
||||
// 检查指令是否是存储指令 (SW, SD)
|
||||
bool isStoreInstr(MachineInstr* instr) {
|
||||
RVOpcodes opcode = instr->getOpcode();
|
||||
return opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
|
||||
opcode == RVOpcodes::SH || opcode == RVOpcodes::SB;
|
||||
}
|
||||
|
||||
// 检查指令是否为控制流指令
|
||||
bool isControlFlowInstr(MachineInstr* instr) {
|
||||
RVOpcodes opcode = instr->getOpcode();
|
||||
return opcode == RVOpcodes::RET || opcode == RVOpcodes::J ||
|
||||
opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
|
||||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
|
||||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
|
||||
opcode == RVOpcodes::CALL;
|
||||
}
|
||||
|
||||
// 获取指令定义的寄存器 - 修复版本
|
||||
std::set<PhysicalReg> getDefinedRegisters(MachineInstr* instr) {
|
||||
std::set<PhysicalReg> defined_regs;
|
||||
RVOpcodes opcode = instr->getOpcode();
|
||||
|
||||
// 特殊处理CALL指令
|
||||
if (opcode == RVOpcodes::CALL) {
|
||||
// CALL指令可能定义返回值寄存器
|
||||
if (!instr->getOperands().empty() &&
|
||||
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
defined_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
}
|
||||
return defined_regs;
|
||||
}
|
||||
|
||||
// 存储指令不定义寄存器
|
||||
if (isStoreInstr(instr)) {
|
||||
return defined_regs;
|
||||
}
|
||||
|
||||
// 分支指令不定义寄存器
|
||||
if (opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
|
||||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
|
||||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
|
||||
opcode == RVOpcodes::J || opcode == RVOpcodes::RET) {
|
||||
return defined_regs;
|
||||
}
|
||||
|
||||
// 对于其他指令,第一个寄存器操作数通常是定义的
|
||||
if (!instr->getOperands().empty() &&
|
||||
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
defined_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
}
|
||||
|
||||
return defined_regs;
|
||||
}
|
||||
|
||||
// 获取指令使用的寄存器 - 修复版本
|
||||
std::set<PhysicalReg> getUsedRegisters(MachineInstr* instr) {
|
||||
std::set<PhysicalReg> used_regs;
|
||||
RVOpcodes opcode = instr->getOpcode();
|
||||
|
||||
// 特殊处理CALL指令
|
||||
if (opcode == RVOpcodes::CALL) {
|
||||
bool first_reg_skipped = false;
|
||||
for (const auto& op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
if (!first_reg_skipped) {
|
||||
first_reg_skipped = true;
|
||||
continue; // 跳过返回值寄存器
|
||||
}
|
||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
used_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
}
|
||||
}
|
||||
return used_regs;
|
||||
}
|
||||
|
||||
// 对于存储指令,所有寄存器操作数都是使用的
|
||||
if (isStoreInstr(instr)) {
|
||||
for (const auto& op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
used_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto mem_op = static_cast<MemOperand*>(op.get());
|
||||
if (!mem_op->getBase()->isVirtual()) {
|
||||
used_regs.insert(mem_op->getBase()->getPReg());
|
||||
}
|
||||
}
|
||||
}
|
||||
return used_regs;
|
||||
}
|
||||
|
||||
// 对于分支指令,所有寄存器操作数都是使用的
|
||||
if (opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
|
||||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
|
||||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU) {
|
||||
for (const auto& op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
used_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
}
|
||||
}
|
||||
return used_regs;
|
||||
}
|
||||
|
||||
// 对于其他指令,除了第一个寄存器操作数(通常是定义),其余都是使用的
|
||||
bool first_reg = true;
|
||||
for (const auto& op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
if (first_reg) {
|
||||
first_reg = false;
|
||||
continue; // 跳过第一个寄存器(定义)
|
||||
}
|
||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
used_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto mem_op = static_cast<MemOperand*>(op.get());
|
||||
if (!mem_op->getBase()->isVirtual()) {
|
||||
used_regs.insert(mem_op->getBase()->getPReg());
|
||||
}
|
||||
}
|
||||
}
|
||||
return used_regs;
|
||||
}
|
||||
|
||||
// 获取内存访问的基址和偏移
|
||||
struct MemoryAccess {
|
||||
PhysicalReg base_reg;
|
||||
int64_t offset;
|
||||
bool valid;
|
||||
|
||||
MemoryAccess() : valid(false) {}
|
||||
MemoryAccess(PhysicalReg base, int64_t off) : base_reg(base), offset(off), valid(true) {}
|
||||
};
|
||||
|
||||
MemoryAccess getMemoryAccess(MachineInstr* instr) {
|
||||
if (!isLoadInstr(instr) && !isStoreInstr(instr)) {
|
||||
return MemoryAccess();
|
||||
}
|
||||
|
||||
// 查找内存操作数
|
||||
for (const auto& op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto mem_op = static_cast<MemOperand*>(op.get());
|
||||
if (!mem_op->getBase()->isVirtual()) {
|
||||
return MemoryAccess(mem_op->getBase()->getPReg(), mem_op->getOffset()->getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MemoryAccess();
|
||||
}
|
||||
|
||||
// 检查内存依赖 - 加强版本
|
||||
bool hasMemoryDependency(MachineInstr* instr1, MachineInstr* instr2) {
|
||||
// 如果都不是内存指令,没有内存依赖
|
||||
if (!isLoadInstr(instr1) && !isStoreInstr(instr1) &&
|
||||
!isLoadInstr(instr2) && !isStoreInstr(instr2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MemoryAccess mem1 = getMemoryAccess(instr1);
|
||||
MemoryAccess mem2 = getMemoryAccess(instr2);
|
||||
|
||||
if (!mem1.valid || !mem2.valid) {
|
||||
// 如果无法确定内存访问模式,保守地认为存在依赖
|
||||
return true;
|
||||
}
|
||||
|
||||
// 如果访问相同的内存位置
|
||||
if (mem1.base_reg == mem2.base_reg && mem1.offset == mem2.offset) {
|
||||
// Store->Load: RAW依赖
|
||||
// Load->Store: WAR依赖
|
||||
// Store->Store: WAW依赖
|
||||
return isStoreInstr(instr1) || isStoreInstr(instr2);
|
||||
}
|
||||
|
||||
// 不同内存位置通常没有依赖,但为了安全起见,
|
||||
// 如果涉及store指令,我们需要更保守
|
||||
if (isStoreInstr(instr1) && isLoadInstr(instr2)) {
|
||||
// 保守处理:不同store和load之间可能有别名
|
||||
return false; // 这里可以根据需要调整策略
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查两个指令之间是否存在依赖关系 - 修复版本
|
||||
bool hasDependency(MachineInstr* instr1, MachineInstr* instr2) {
|
||||
// 检查RAW依赖:instr1定义的寄存器是否被instr2使用
|
||||
auto defined_regs1 = getDefinedRegisters(instr1);
|
||||
auto used_regs2 = getUsedRegisters(instr2);
|
||||
|
||||
for (const auto& reg : defined_regs1) {
|
||||
if (used_regs2.find(reg) != used_regs2.end()) {
|
||||
return true; // RAW依赖 - instr2读取instr1写入的值
|
||||
}
|
||||
}
|
||||
|
||||
// 检查WAR依赖:instr1使用的寄存器是否被instr2定义
|
||||
auto used_regs1 = getUsedRegisters(instr1);
|
||||
auto defined_regs2 = getDefinedRegisters(instr2);
|
||||
|
||||
for (const auto& reg : used_regs1) {
|
||||
if (defined_regs2.find(reg) != defined_regs2.end()) {
|
||||
return true; // WAR依赖 - instr2覆盖instr1需要的值
|
||||
}
|
||||
}
|
||||
|
||||
// 检查WAW依赖:两个指令定义相同寄存器
|
||||
for (const auto& reg : defined_regs1) {
|
||||
if (defined_regs2.find(reg) != defined_regs2.end()) {
|
||||
return true; // WAW依赖 - 两条指令写入同一寄存器
|
||||
}
|
||||
}
|
||||
|
||||
// 检查内存依赖
|
||||
if (hasMemoryDependency(instr1, instr2)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否可以安全地将instr1和instr2交换位置
|
||||
bool canSwapInstructions(MachineInstr* instr1, MachineInstr* instr2) {
|
||||
// 不能移动控制流指令
|
||||
if (isControlFlowInstr(instr1) || isControlFlowInstr(instr2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查双向依赖关系
|
||||
return !hasDependency(instr1, instr2) && !hasDependency(instr2, instr1);
|
||||
}
|
||||
|
||||
// 新增:验证调度结果的正确性
|
||||
void validateSchedule(const std::vector<MachineInstr*>& instr_list) {
|
||||
for (int i = 0; i < (int)instr_list.size(); i++) {
|
||||
for (int j = i + 1; j < (int)instr_list.size(); j++) {
|
||||
MachineInstr* earlier = instr_list[i];
|
||||
MachineInstr* later = instr_list[j];
|
||||
|
||||
// 检查是否存在被违反的依赖关系
|
||||
auto defined_regs = getDefinedRegisters(earlier);
|
||||
auto used_regs = getUsedRegisters(later);
|
||||
|
||||
// 检查RAW依赖
|
||||
for (const auto& reg : defined_regs) {
|
||||
if (used_regs.find(reg) != used_regs.end()) {
|
||||
// 这是正常的依赖关系,earlier应该在later之前
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查内存依赖
|
||||
if (hasMemoryDependency(earlier, later)) {
|
||||
MemoryAccess mem1 = getMemoryAccess(earlier);
|
||||
MemoryAccess mem2 = getMemoryAccess(later);
|
||||
|
||||
if (mem1.valid && mem2.valid &&
|
||||
mem1.base_reg == mem2.base_reg && mem1.offset == mem2.offset) {
|
||||
if (isStoreInstr(earlier) && isLoadInstr(later)) {
|
||||
// Store->Load依赖,顺序正确
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 在基本块内对指令进行调度优化 - 完全重写版本
|
||||
void scheduleBlock(MachineBasicBlock* mbb) {
|
||||
auto& instructions = mbb->getInstructions();
|
||||
if (instructions.size() <= 1) return;
|
||||
if (instructions.size() > MAX_SCHEDULING_BLOCK_SIZE) {
|
||||
return; // 跳过超大块,防止卡住
|
||||
}
|
||||
|
||||
std::vector<MachineInstr*> instr_list;
|
||||
for (auto& instr : instructions) {
|
||||
instr_list.push_back(instr.get());
|
||||
}
|
||||
|
||||
// 使用更严格的调度策略,避免破坏依赖关系
|
||||
bool changed = true;
|
||||
int max_iterations = 10; // 限制迭代次数避免死循环
|
||||
int iteration = 0;
|
||||
|
||||
while (changed && iteration < max_iterations) {
|
||||
changed = false;
|
||||
iteration++;
|
||||
|
||||
for (int i = 0; i < (int)instr_list.size() - 1; i++) {
|
||||
MachineInstr* instr1 = instr_list[i];
|
||||
MachineInstr* instr2 = instr_list[i + 1];
|
||||
|
||||
// 只进行非常保守的优化
|
||||
bool should_swap = false;
|
||||
|
||||
// 策略1: 将load指令提前,减少load-use延迟
|
||||
if (isLoadInstr(instr2) && !isLoadInstr(instr1) && !isStoreInstr(instr1)) {
|
||||
should_swap = canSwapInstructions(instr1, instr2);
|
||||
}
|
||||
// 策略2: 将非关键store指令延后,为其他指令让路
|
||||
else if (isStoreInstr(instr1) && !isLoadInstr(instr2) && !isStoreInstr(instr2)) {
|
||||
should_swap = canSwapInstructions(instr1, instr2);
|
||||
}
|
||||
|
||||
if (should_swap) {
|
||||
std::swap(instr_list[i], instr_list[i + 1]);
|
||||
changed = true;
|
||||
|
||||
// 调试输出
|
||||
// std::cout << "Swapped instructions at positions " << i << " and " << (i+1) << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 验证调度结果的正确性
|
||||
validateSchedule(instr_list);
|
||||
|
||||
// 将调度后的指令顺序写回
|
||||
std::map<MachineInstr*, std::unique_ptr<MachineInstr>> instr_map;
|
||||
for (auto& instr : instructions) {
|
||||
instr_map[instr.get()] = std::move(instr);
|
||||
}
|
||||
|
||||
instructions.clear();
|
||||
for (auto instr : instr_list) {
|
||||
instructions.push_back(std::move(instr_map[instr]));
|
||||
}
|
||||
}
|
||||
|
||||
bool PostRA_Scheduler::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
// 这个函数在IR级别运行,但我们需要在机器指令级别运行
|
||||
// 所以我们返回false,表示没有对IR进行修改
|
||||
return false;
|
||||
}
|
||||
|
||||
void PostRA_Scheduler::runOnMachineFunction(MachineFunction *mfunc) {
|
||||
// std::cout << "Running Post-RA Local Scheduler... " << std::endl;
|
||||
|
||||
// 遍历每个机器基本块
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
scheduleBlock(mbb.get());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@ -1,36 +0,0 @@
|
||||
#include "PreRA_Scheduler.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
char PreRA_Scheduler::ID = 0;
|
||||
|
||||
bool PreRA_Scheduler::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
// TODO: 在此实现寄存器分配前的指令调度。
|
||||
// 遍历mfunc中的每一个MachineBasicBlock。
|
||||
// 对每个基本块内的MachineInstr列表进行重排。
|
||||
//
|
||||
// 实现思路:
|
||||
// 1. 分析每个基本块内指令的数据依赖关系,构建依赖图(DAG)。
|
||||
// 2.
|
||||
// 根据目标处理器的流水线特性(指令延迟等),使用列表调度等算法对指令进行重排。
|
||||
// 3. 此时操作的是虚拟寄存器,只存在真依赖,调度自由度最大。
|
||||
//
|
||||
// std::cout << "Running Pre-RA Instruction Scheduler..." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
void PreRA_Scheduler::runOnMachineFunction(MachineFunction *mfunc) {
|
||||
// TODO: 在此实现寄存器分配前的指令调度。
|
||||
// 遍历mfunc中的每一个MachineBasicBlock。
|
||||
// 对每个基本块内的MachineInstr列表进行重排。
|
||||
//
|
||||
// 实现思路:
|
||||
// 1. 分析每个基本块内指令的数据依赖关系,构建依赖图(DAG)。
|
||||
// 2.
|
||||
// 根据目标处理器的流水线特性(指令延迟等),使用列表调度等算法对指令进行重排。
|
||||
// 3. 此时操作的是虚拟寄存器,只存在真依赖,调度自由度最大。
|
||||
//
|
||||
// std::cout << "Running Pre-RA Instruction Scheduler..." << std::endl;
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@ -1,142 +0,0 @@
|
||||
#include "RISCv64Backend.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include "RISCv64RegAlloc.h"
|
||||
#include "RISCv64AsmPrinter.h"
|
||||
#include "RISCv64Passes.h" // 包含优化Pass的头文件
|
||||
#include <sstream>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 顶层入口
|
||||
std::string RISCv64CodeGen::code_gen() {
|
||||
return module_gen();
|
||||
}
|
||||
|
||||
// 模块级代码生成
|
||||
std::string RISCv64CodeGen::module_gen() {
|
||||
std::stringstream ss;
|
||||
|
||||
// --- [新逻辑] 步骤1:将全局变量分为.data和.bss两组 ---
|
||||
std::vector<GlobalValue*> data_globals;
|
||||
std::vector<GlobalValue*> bss_globals;
|
||||
|
||||
for (const auto& global_ptr : module->getGlobals()) {
|
||||
GlobalValue* global = global_ptr.get();
|
||||
const auto& init_values = global->getInitValues();
|
||||
|
||||
// 判断是否为大型零初始化数组,以便放入.bss段
|
||||
bool is_large_zero_array = false;
|
||||
// 规则:初始化列表只有一项,且该项是值为0的整数,且数量大于一个阈值(例如16)
|
||||
if (init_values.getValues().size() == 1) {
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(init_values.getValues()[0])) {
|
||||
if (const_val->isInt() && const_val->getInt() == 0 && init_values.getNumbers()[0] > 16) {
|
||||
is_large_zero_array = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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"; // 切换到 .bss 段
|
||||
for (GlobalValue* global : bss_globals) {
|
||||
// 获取数组总大小(元素个数 * 元素大小)
|
||||
// 在SysY中,我们假设元素都是4字节(int或float)
|
||||
unsigned count = global->getInitValues().getNumbers()[0];
|
||||
unsigned total_size = count * 4;
|
||||
|
||||
ss << " .align 3\n"; // 8字节对齐 (2^3)
|
||||
ss << ".globl " << global->getName() << "\n";
|
||||
ss << ".type " << global->getName() << ", @object\n";
|
||||
ss << ".size " << global->getName() << ", " << total_size << "\n";
|
||||
ss << global->getName() << ":\n";
|
||||
// 使用 .space 指令来预留指定大小的零填充空间
|
||||
ss << " .space " << total_size << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// --- [旧逻辑保留] 步骤3:生成 .data 段的代码 ---
|
||||
if (!data_globals.empty()) {
|
||||
ss << ".data\n"; // 切换到 .data 段
|
||||
for (GlobalValue* global : data_globals) {
|
||||
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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- 处理函数 (.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);
|
||||
|
||||
std::stringstream ss1;
|
||||
RISCv64AsmPrinter printer1(mfunc.get());
|
||||
printer1.run(ss1, true);
|
||||
|
||||
// 阶段 2: 指令调度 (Instruction Scheduling)
|
||||
PreRA_Scheduler scheduler;
|
||||
scheduler.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 3: 物理寄存器分配 (Register Allocation)
|
||||
RISCv64RegAlloc reg_alloc(mfunc.get());
|
||||
reg_alloc.run();
|
||||
|
||||
// 阶段 3.5: 处理被调用者保存寄存器
|
||||
CalleeSavedHandler callee_handler;
|
||||
callee_handler.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 4: 窥孔优化 (Peephole Optimization)
|
||||
PeepholeOptimizer peephole;
|
||||
peephole.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 5: 局部指令调度 (Local Scheduling)
|
||||
PostRA_Scheduler local_scheduler;
|
||||
local_scheduler.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 6: 代码发射 (Code Emission)
|
||||
std::stringstream ss;
|
||||
RISCv64AsmPrinter printer(mfunc.get());
|
||||
printer.run(ss);
|
||||
if (DEBUG) ss << "\n" << ss1.str(); // 将指令选择阶段的结果也包含在最终输出中
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@ -1,6 +0,0 @@
|
||||
#include "RISCv64LLIR.h"
|
||||
#include <vector>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
}
|
||||
@ -1,776 +0,0 @@
|
||||
#include "RISCv64RegAlloc.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include "RISCv64AsmPrinter.h" // For DEBUG output
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <iostream> // For DEBUG output
|
||||
#include <cassert> // For assert
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
// 映射物理寄存器到特殊的虚拟寄存器ID,用于干扰图中的物理寄存器节点
|
||||
// 确保这些特殊ID不会与vreg_counter生成的常规虚拟寄存器ID冲突
|
||||
for (PhysicalReg preg : allocable_int_regs) {
|
||||
preg_to_vreg_id_map[preg] = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID) + static_cast<unsigned>(preg);
|
||||
}
|
||||
}
|
||||
|
||||
// 寄存器分配的主入口点
|
||||
void RISCv64RegAlloc::run() {
|
||||
// 阶段 1: 处理函数调用约定(参数寄存器预着色)
|
||||
handleCallingConvention();
|
||||
// 阶段 2: 消除帧索引(为局部变量和栈参数分配栈偏移)
|
||||
eliminateFrameIndices();
|
||||
{ // 使用大括号创建一个局部作用域,避免printer变量泄露
|
||||
if (DEBUG) {
|
||||
std::cerr << "\n===== LLIR after eliminateFrameIndices for function: "
|
||||
<< MFunc->getName() << " =====\n";
|
||||
// 1. 创建一个 AsmPrinter 实例,传入当前的 MachineFunction
|
||||
RISCv64AsmPrinter printer(MFunc);
|
||||
// 2. 调用 run 方法,将结果打印到标准错误流 (std::cerr)
|
||||
// 3. 必须将 debug 参数设为 true!
|
||||
// 因为此时指令中仍然包含虚拟寄存器 (%vreg),
|
||||
// debug模式下的 AsmPrinter 才能正确处理它们而不会报错。
|
||||
printer.run(std::cerr, true);
|
||||
std::cerr << "===== End of LLIR =====\n\n";
|
||||
}
|
||||
}
|
||||
// 阶段 3: 活跃性分析
|
||||
analyzeLiveness();
|
||||
// 阶段 4: 构建干扰图(包含CALL指令对调用者保存寄存器的影响)
|
||||
buildInterferenceGraph();
|
||||
// 阶段 5: 图着色算法分配物理寄存器
|
||||
colorGraph();
|
||||
// 阶段 6: 重写函数(插入溢出/填充代码,替换虚拟寄存器为物理寄存器)
|
||||
rewriteFunction();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 处理调用约定,预先为函数参数和调用返回值分配物理寄存器。
|
||||
* 这个函数现在负责处理调用约定的两个方面:
|
||||
* 1. 作为被调用者(callee),如何接收传入的参数。
|
||||
* 2. 作为调用者(caller),如何接收调用的其他函数的返回值。
|
||||
*/
|
||||
void RISCv64RegAlloc::handleCallingConvention() {
|
||||
Function* F = MFunc->getFunc();
|
||||
RISCv64ISel* isel = MFunc->getISel();
|
||||
|
||||
// --- 部分1:处理函数传入参数的预着色 ---
|
||||
// 获取函数的Argument对象列表
|
||||
if (F) {
|
||||
auto& args = F->getArguments();
|
||||
// RISC-V RV64G调用约定:前8个整型/指针参数通过 a0-a7 传递
|
||||
int arg_idx = 0;
|
||||
// 遍历 Argument* 列表
|
||||
for (Argument* arg : args) {
|
||||
if (arg_idx >= 8) {
|
||||
break;
|
||||
}
|
||||
// 获取该 Argument 对象对应的虚拟寄存器ID
|
||||
// 通过 MachineFunction -> RISCv64ISel -> vreg_map 来获取
|
||||
const auto& vreg_map_from_isel = MFunc->getISel()->getVRegMap();
|
||||
assert(vreg_map_from_isel.count(arg) && "Argument not found in ISel's vreg_map!");
|
||||
// 1. 获取该 Argument 对象对应的虚拟寄存器
|
||||
unsigned vreg = isel->getVReg(arg);
|
||||
|
||||
// 2. 根据参数索引,确定对应的物理寄存器 (a0, a1, ...)
|
||||
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + arg_idx);
|
||||
|
||||
// 3. 在 color_map 中,将 vreg "预着色" 为对应的物理寄存器
|
||||
color_map[vreg] = preg;
|
||||
|
||||
arg_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
// // --- 部分2:[新逻辑] 遍历所有指令,为CALL指令的返回值预着色为 a0 ---
|
||||
// // 这是为了强制寄存器分配器知道,call的结果物理上出现在a0寄存器。
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
for (auto& instr : mbb->getInstructions()) {
|
||||
if (instr->getOpcode() == RVOpcodes::CALL) {
|
||||
// 根据协议,如果CALL有返回值,其目标vreg是第一个操作数
|
||||
if (!instr->getOperands().empty() &&
|
||||
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG)
|
||||
{
|
||||
auto reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
|
||||
if (reg_op->isVirtual()) {
|
||||
unsigned ret_vreg = reg_op->getVRegNum();
|
||||
// 强制将这个虚拟寄存器预着色为 a0
|
||||
color_map[ret_vreg] = PhysicalReg::A0;
|
||||
if (DEBUG) {
|
||||
std::cout << "[DEBUG] Pre-coloring vreg" << ret_vreg
|
||||
<< " to a0 for CALL instruction." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 消除帧索引,为局部变量和栈参数分配栈偏移量,并展开伪指令。
|
||||
*/
|
||||
void RISCv64RegAlloc::eliminateFrameIndices() {
|
||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||
// 初始偏移量,为保存ra和s0留出空间。
|
||||
// 假设序言是 addi sp, sp, -stack_size; sd ra, stack_size-8(sp); sd s0, stack_size-16(sp);
|
||||
int current_offset = 16;
|
||||
|
||||
Function* F = MFunc->getFunc();
|
||||
RISCv64ISel* isel = MFunc->getISel();
|
||||
|
||||
// 在处理局部变量前,首先为栈参数计算偏移量。
|
||||
if (F) {
|
||||
int arg_idx = 0;
|
||||
for (Argument* arg : F->getArguments()) {
|
||||
// 我们只关心第8个索引及之后的参数(即第9个参数开始)
|
||||
if (arg_idx >= 8) {
|
||||
// 计算偏移量:第一个栈参数(idx=8)在0(s0),第二个(idx=9)在8(s0),以此类推。
|
||||
int offset = (arg_idx - 8) * 8;
|
||||
unsigned vreg = isel->getVReg(arg);
|
||||
|
||||
// 将这个vreg和它的栈偏移存入map。
|
||||
// 我们可以复用alloca_offsets,因为它们都代表“vreg到栈偏移”的映射。
|
||||
frame_info.alloca_offsets[vreg] = offset;
|
||||
}
|
||||
arg_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理局部变量
|
||||
// 遍历AllocaInst来计算局部变量所需的总空间
|
||||
for (auto& bb : F->getBasicBlocks()) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
if (auto alloca = dynamic_cast<AllocaInst*>(inst.get())) {
|
||||
// 获取Alloca指令指向的类型 (例如 alloca i32* 中,获取 i32)
|
||||
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字节
|
||||
|
||||
current_offset += size;
|
||||
unsigned alloca_vreg = isel->getVReg(alloca);
|
||||
// 局部变量使用相对于s0的负向偏移
|
||||
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()) {
|
||||
RVOpcodes opcode = instr_ptr->getOpcode();
|
||||
|
||||
// --- MODIFICATION START: 处理区分宽度的伪指令 ---
|
||||
if (opcode == RVOpcodes::FRAME_LOAD_W || opcode == RVOpcodes::FRAME_LOAD_D) {
|
||||
// 确定要生成的真实加载指令是 lw 还是 ld
|
||||
RVOpcodes real_load_op = (opcode == RVOpcodes::FRAME_LOAD_W) ? RVOpcodes::LW : RVOpcodes::LD;
|
||||
|
||||
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();
|
||||
|
||||
// 展开为: 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 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) {
|
||||
// 确定要生成的真实存储指令是 sw 还是 sd
|
||||
RVOpcodes real_store_op = (opcode == RVOpcodes::FRAME_STORE_W) ? RVOpcodes::SW : RVOpcodes::SD;
|
||||
|
||||
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();
|
||||
|
||||
// 展开为: 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 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));
|
||||
}
|
||||
// --- MODIFICATION END ---
|
||||
}
|
||||
mbb->getInstructions() = std::move(new_instructions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 计算给定 MachineInstr 的 Use (读取) 和 Def (写入) 寄存器集合。
|
||||
* 这是活跃性分析的基础。
|
||||
* @param instr 要分析的机器指令。
|
||||
* @param use 存储 Use 寄存器(虚拟寄存器 ID)的集合。
|
||||
* @param def 存储 Def 寄存器(虚拟寄存器 ID)的集合。
|
||||
*/
|
||||
void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def) {
|
||||
bool first_reg_is_def = true; // 默认情况下,指令的第一个寄存器操作数是定义 (def)
|
||||
auto opcode = instr->getOpcode();
|
||||
|
||||
// 1. 特殊指令的 `is_def` 标志调整
|
||||
// 这些指令的第一个寄存器操作数是源操作数 (use),而不是目标操作数 (def)。
|
||||
if (opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
|
||||
opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
|
||||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
|
||||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
|
||||
opcode == RVOpcodes::RET || opcode == RVOpcodes::J) {
|
||||
first_reg_is_def = false;
|
||||
}
|
||||
|
||||
// JAL 和 JALR 指令定义 ra (x1)
|
||||
if (opcode == RVOpcodes::JAL || opcode == RVOpcodes::JALR) {
|
||||
// 使用 ra 对应的特殊虚拟寄存器ID
|
||||
def.insert(preg_to_vreg_id_map.at(PhysicalReg::RA));
|
||||
first_reg_is_def = false; // JAL/JALR 的第一个操作数是 ra,已经处理为 def
|
||||
}
|
||||
|
||||
// 2. CALL 指令的特殊处理
|
||||
if (opcode == RVOpcodes::CALL) {
|
||||
// 根据 s1 分支 ISel 定义的协议来解析操作数列表
|
||||
bool first_reg_operand_is_def = true;
|
||||
for (auto& op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||
if (reg_op->isVirtual()) {
|
||||
// 协议:第一个寄存器操作数是返回值 (def)
|
||||
if (first_reg_operand_is_def) {
|
||||
def.insert(reg_op->getVRegNum());
|
||||
first_reg_operand_is_def = false;
|
||||
} else {
|
||||
// 后续所有寄存器操作数都是参数 (use)
|
||||
use.insert(reg_op->getVRegNum());
|
||||
}
|
||||
} else { // [修复] CALL指令也可能定义物理寄存器(如a0)
|
||||
if (first_reg_operand_is_def) {
|
||||
if (preg_to_vreg_id_map.count(reg_op->getPReg())) {
|
||||
def.insert(preg_to_vreg_id_map.at(reg_op->getPReg()));
|
||||
}
|
||||
first_reg_operand_is_def = false;
|
||||
} else {
|
||||
if (preg_to_vreg_id_map.count(reg_op->getPReg())) {
|
||||
use.insert(preg_to_vreg_id_map.at(reg_op->getPReg()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return; // CALL 指令处理完毕
|
||||
}
|
||||
|
||||
// 3. 对其他所有指令的通用处理逻辑 [已重构和修复]
|
||||
for (const auto& op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||
|
||||
if (first_reg_is_def) {
|
||||
// --- 处理定义(Def) ---
|
||||
if (reg_op->isVirtual()) {
|
||||
def.insert(reg_op->getVRegNum());
|
||||
} else { // 物理寄存器也可以是 Def
|
||||
if (preg_to_vreg_id_map.count(reg_op->getPReg())) {
|
||||
def.insert(preg_to_vreg_id_map.at(reg_op->getPReg()));
|
||||
}
|
||||
}
|
||||
first_reg_is_def = false; // **关键**:处理完第一个寄存器后,立即更新标志
|
||||
} else {
|
||||
// --- 处理使用(Use) ---
|
||||
if (reg_op->isVirtual()) {
|
||||
use.insert(reg_op->getVRegNum());
|
||||
} else { // 物理寄存器也可以是 Use
|
||||
if (preg_to_vreg_id_map.count(reg_op->getPReg())) {
|
||||
use.insert(preg_to_vreg_id_map.at(reg_op->getPReg()));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
// [保持不变] 内存操作数的处理逻辑看起来是正确的
|
||||
auto mem_op = static_cast<MemOperand*>(op.get());
|
||||
auto base_reg = mem_op->getBase();
|
||||
if (base_reg->isVirtual()) {
|
||||
use.insert(base_reg->getVRegNum());
|
||||
} else {
|
||||
PhysicalReg preg = base_reg->getPReg();
|
||||
if (preg_to_vreg_id_map.count(preg)) {
|
||||
use.insert(preg_to_vreg_id_map.at(preg));
|
||||
}
|
||||
}
|
||||
|
||||
// 对于存储内存指令 (SW, SD),要存储的值(第一个操作数)也是 `use`
|
||||
if ((opcode == RVOpcodes::SW || opcode == RVOpcodes::SD) &&
|
||||
!instr->getOperands().empty() &&
|
||||
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
|
||||
auto src_reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
|
||||
if (src_reg_op->isVirtual()) {
|
||||
use.insert(src_reg_op->getVRegNum());
|
||||
} else {
|
||||
if (preg_to_vreg_id_map.count(src_reg_op->getPReg())) {
|
||||
use.insert(preg_to_vreg_id_map.at(src_reg_op->getPReg()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 计算一个类型在内存中占用的字节数。
|
||||
* @param type 需要计算大小的IR类型。
|
||||
* @return 该类型占用的字节数。
|
||||
*/
|
||||
unsigned RISCv64RegAlloc::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;
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64RegAlloc::analyzeLiveness() {
|
||||
// === 阶段 1: 预计算每个基本块的 use 和 def 集合 ===
|
||||
// 这样可以避免在主循环中重复计算
|
||||
std::map<MachineBasicBlock*, LiveSet> block_uses;
|
||||
std::map<MachineBasicBlock*, LiveSet> block_defs;
|
||||
for (auto& mbb_ptr : MFunc->getBlocks()) {
|
||||
MachineBasicBlock* mbb = mbb_ptr.get();
|
||||
LiveSet uses, defs;
|
||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||
LiveSet instr_use, instr_def;
|
||||
getInstrUseDef(instr_ptr.get(), instr_use, instr_def);
|
||||
// use[B] = use[B] U (instr_use - def[B])
|
||||
for (unsigned u : instr_use) {
|
||||
if (defs.find(u) == defs.end()) {
|
||||
uses.insert(u);
|
||||
}
|
||||
}
|
||||
// def[B] = def[B] U instr_def
|
||||
defs.insert(instr_def.begin(), instr_def.end());
|
||||
}
|
||||
block_uses[mbb] = uses;
|
||||
block_defs[mbb] = defs;
|
||||
}
|
||||
|
||||
// === 阶段 2: 在“块”粒度上进行迭代数据流分析,直到收敛 ===
|
||||
std::map<MachineBasicBlock*, LiveSet> block_live_in;
|
||||
std::map<MachineBasicBlock*, LiveSet> block_live_out;
|
||||
bool changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
// 以逆后序遍历基本块,可以加速收敛,但简单的逆序对于大多数情况也有效
|
||||
for (auto it = MFunc->getBlocks().rbegin(); it != MFunc->getBlocks().rend(); ++it) {
|
||||
auto& mbb = *it;
|
||||
|
||||
// 2.1 计算 live_out[B] = U_{S in succ(B)} live_in[S]
|
||||
LiveSet new_live_out;
|
||||
for (auto succ : mbb->successors) {
|
||||
new_live_out.insert(block_live_in[succ].begin(), block_live_in[succ].end());
|
||||
}
|
||||
|
||||
// 2.2 计算 live_in[B] = use[B] U (live_out[B] - def[B])
|
||||
LiveSet live_out_minus_def = new_live_out;
|
||||
for (unsigned d : block_defs[mbb.get()]) {
|
||||
live_out_minus_def.erase(d);
|
||||
}
|
||||
LiveSet new_live_in = block_uses[mbb.get()];
|
||||
new_live_in.insert(live_out_minus_def.begin(), live_out_minus_def.end());
|
||||
|
||||
// 2.3 检查 live_in 和 live_out 是否变化,以判断是否达到不动点
|
||||
if (block_live_out[mbb.get()] != new_live_out) {
|
||||
changed = true;
|
||||
block_live_out[mbb.get()] = new_live_out;
|
||||
}
|
||||
if (block_live_in[mbb.get()] != new_live_in) {
|
||||
changed = true;
|
||||
block_live_in[mbb.get()] = new_live_in;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// === 阶段 3: 进行一次指令粒度的遍历,填充最终的 live_in_map 和 live_out_map ===
|
||||
// 此时块级别的活跃信息已经稳定,我们只需遍历一次即可
|
||||
for (auto& mbb_ptr : MFunc->getBlocks()) {
|
||||
MachineBasicBlock* mbb = mbb_ptr.get();
|
||||
LiveSet live_out = block_live_out[mbb]; // 从已收敛的块级 live_out 开始
|
||||
|
||||
for (auto instr_it = mbb->getInstructions().rbegin(); instr_it != mbb->getInstructions().rend(); ++instr_it) {
|
||||
MachineInstr* instr = instr_it->get();
|
||||
live_out_map[instr] = live_out;
|
||||
|
||||
LiveSet use, def;
|
||||
getInstrUseDef(instr, use, def);
|
||||
|
||||
LiveSet live_in = use;
|
||||
LiveSet diff = live_out;
|
||||
for (auto vreg : def) {
|
||||
diff.erase(vreg);
|
||||
}
|
||||
live_in.insert(diff.begin(), diff.end());
|
||||
live_in_map[instr] = live_in;
|
||||
|
||||
// 更新 live_out,为块内的上一条指令做准备
|
||||
live_out = live_in;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数,用于清晰地打印寄存器集合。可以放在 .cpp 文件的顶部。
|
||||
void RISCv64RegAlloc::printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os) {
|
||||
os << " " << name << ": { ";
|
||||
for (unsigned vreg : s) {
|
||||
// 为了可读性,将物理寄存器对应的特殊ID进行转换
|
||||
if (vreg >= static_cast<unsigned>(sysy::PhysicalReg::PHYS_REG_START_ID)) {
|
||||
os << "preg(" << (vreg - static_cast<unsigned>(sysy::PhysicalReg::PHYS_REG_START_ID)) << ") ";
|
||||
} else {
|
||||
os << "%vreg" << vreg << " ";
|
||||
}
|
||||
}
|
||||
os << "}\n";
|
||||
}
|
||||
|
||||
void RISCv64RegAlloc::buildInterferenceGraph() {
|
||||
std::set<unsigned> all_vregs;
|
||||
// 收集所有虚拟寄存器和物理寄存器在干扰图中的节点ID
|
||||
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);
|
||||
}
|
||||
}
|
||||
// 添加所有物理寄存器对应的特殊虚拟寄存器ID到all_vregs,作为干扰图节点
|
||||
for (auto preg : allocable_int_regs) {
|
||||
all_vregs.insert(preg_to_vreg_id_map.at(preg));
|
||||
}
|
||||
|
||||
// 初始化干扰图邻接表
|
||||
for (auto vreg : all_vregs) { interference_graph[vreg] = {}; }
|
||||
|
||||
// 创建一个临时的AsmPrinter用于打印指令,方便调试
|
||||
RISCv64AsmPrinter temp_printer(MFunc);
|
||||
temp_printer.setStream(std::cerr);
|
||||
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
if (DEEPDEBUG) std::cerr << "--- Building Graph for Basic Block: " << mbb->getName() << " ---\n";
|
||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||
MachineInstr* instr = instr_ptr.get();
|
||||
if (DEEPDEBUG) {
|
||||
// 打印当前正在处理的指令
|
||||
std::cerr << " Instr: ";
|
||||
temp_printer.printInstruction(instr, true); // 使用 true 来打印虚拟寄存器
|
||||
}
|
||||
|
||||
LiveSet def, use;
|
||||
getInstrUseDef(instr, use, def);
|
||||
const LiveSet& live_out = live_out_map.at(instr);
|
||||
|
||||
// [新增调试逻辑] 打印所有相关的寄存器集合
|
||||
if (DEEPDEBUG) {
|
||||
printLiveSet(use, "Use ", std::cerr);
|
||||
printLiveSet(def, "Def ", std::cerr);
|
||||
printLiveSet(live_out, "Live_Out", std::cerr); // 这是我们最关心的信息
|
||||
}
|
||||
|
||||
// 标准干扰图构建:def 与 live_out 中的其他变量干扰
|
||||
for (unsigned d : def) {
|
||||
for (unsigned l : live_out) {
|
||||
if (d != l) {
|
||||
// [新增调试逻辑] 打印添加的干扰边及其原因
|
||||
if (DEEPDEBUG && interference_graph[d].find(l) == interference_graph[d].end()) {
|
||||
std::cerr << " Edge (Def-LiveOut): %vreg" << d << " <-> %vreg" << l << "\n";
|
||||
}
|
||||
interference_graph[d].insert(l);
|
||||
interference_graph[l].insert(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 在非move指令中,def 与 use 互相干扰
|
||||
if (instr->getOpcode() != RVOpcodes::MV) {
|
||||
for (unsigned d : def) {
|
||||
for (unsigned u : use) {
|
||||
if (d != u) {
|
||||
// [新增调试逻辑] 打印添加的干扰边及其原因
|
||||
if (DEEPDEBUG && interference_graph[d].find(u) == interference_graph[d].end()) {
|
||||
std::cerr << " Edge (Def-Use) : %vreg" << d << " <-> %vreg" << u << "\n";
|
||||
}
|
||||
interference_graph[d].insert(u);
|
||||
interference_graph[u].insert(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// *** 处理 CALL 指令的隐式 def ***
|
||||
if (instr->getOpcode() == RVOpcodes::CALL) {
|
||||
// 你的原始CALL调试信息
|
||||
if (DEEPDEBUG) {
|
||||
std::string live_out_str;
|
||||
for (unsigned vreg : live_out) {
|
||||
live_out_str += "%vreg" + std::to_string(vreg) + " ";
|
||||
}
|
||||
std::cerr << "[DEEPDEBUG] buildInterferenceGraph: CALL instruction found. Live out set is: {"
|
||||
<< live_out_str << "}" << std::endl;
|
||||
}
|
||||
// CALL 指令会定义(杀死)所有调用者保存的寄存器。
|
||||
// 因此,所有调用者保存的物理寄存器都与 CALL 指令的 live_out 中的所有变量冲突。
|
||||
const std::vector<PhysicalReg>& caller_saved_regs = getCallerSavedIntRegs();
|
||||
for (PhysicalReg cs_reg : caller_saved_regs) {
|
||||
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg); // 获取物理寄存器对应的特殊vreg ID
|
||||
|
||||
// 将这个物理寄存器节点与 CALL 指令的 live_out 中的所有虚拟寄存器添加干扰边。
|
||||
for (unsigned live_vreg_out : live_out) {
|
||||
if (cs_vreg_id != live_vreg_out) { // 避免自己和自己干扰
|
||||
// [新增调试逻辑] 打印添加的干扰边及其原因
|
||||
if (DEEPDEBUG && interference_graph[cs_vreg_id].find(live_vreg_out) == interference_graph[cs_vreg_id].end()) {
|
||||
std::cerr << " Edge (CALL) : preg(" << static_cast<int>(cs_reg) << ") <-> %vreg" << live_vreg_out << "\n";
|
||||
}
|
||||
interference_graph[cs_vreg_id].insert(live_vreg_out);
|
||||
interference_graph[live_vreg_out].insert(cs_vreg_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DEEPDEBUG) std::cerr << " ----------------\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64RegAlloc::colorGraph() {
|
||||
std::vector<unsigned> sorted_vregs;
|
||||
for (auto const& [vreg, neighbors] : interference_graph) {
|
||||
// 只为未预着色的虚拟寄存器排序和着色
|
||||
if (color_map.find(vreg) == color_map.end() && vreg < static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID)) {
|
||||
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_id : interference_graph.at(vreg)) {
|
||||
// --- 关键改进 (来自 rec 分支) ---
|
||||
|
||||
// 情况 1: 邻居是一个已经被着色的虚拟寄存器
|
||||
if (color_map.count(neighbor_id)) {
|
||||
used_colors.insert(color_map.at(neighbor_id));
|
||||
}
|
||||
// 情况 2: 邻居本身就是一个代表物理寄存器的节点
|
||||
else if (neighbor_id >= static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID)) {
|
||||
// 从特殊ID反向解析出是哪个物理寄存器
|
||||
PhysicalReg neighbor_preg = static_cast<PhysicalReg>(neighbor_id - static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID));
|
||||
used_colors.insert(neighbor_preg);
|
||||
}
|
||||
}
|
||||
|
||||
bool colored = false;
|
||||
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;
|
||||
|
||||
// --- FIX 1: 动态计算溢出槽大小 ---
|
||||
// 根据溢出虚拟寄存器的真实类型,为其在栈上分配正确大小的空间。
|
||||
for (unsigned vreg : spilled_vregs) {
|
||||
// 从反向映射中查找 vreg 对应的 IR Value
|
||||
assert(vreg_to_value_map.count(vreg) && "Spilled vreg not found in map!");
|
||||
Value* val = vreg_to_value_map.at(vreg);
|
||||
|
||||
// 使用辅助函数获取类型大小
|
||||
int size = getTypeSizeInBytes(val->getType());
|
||||
|
||||
// 保持栈8字节对齐
|
||||
current_offset += size;
|
||||
current_offset = (current_offset + 7) & ~7;
|
||||
|
||||
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);
|
||||
|
||||
// --- FIX 2: 为溢出的 'use' 操作数插入正确的加载指令 ---
|
||||
for (unsigned vreg : use) {
|
||||
if (spilled_vregs.count(vreg)) {
|
||||
// 同样地,根据 vreg 的类型决定使用 lw 还是 ld
|
||||
assert(vreg_to_value_map.count(vreg));
|
||||
Value* val = vreg_to_value_map.at(vreg);
|
||||
RVOpcodes load_op = val->getType()->isPointer() ? RVOpcodes::LD : RVOpcodes::LW;
|
||||
|
||||
int offset = frame_info.spill_offsets.at(vreg);
|
||||
auto load = std::make_unique<MachineInstr>(load_op);
|
||||
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));
|
||||
|
||||
// --- FIX 3: 为溢出的 'def' 操作数插入正确的存储指令 ---
|
||||
for (unsigned vreg : def) {
|
||||
if (spilled_vregs.count(vreg)) {
|
||||
// 根据 vreg 的类型决定使用 sw 还是 sd
|
||||
assert(vreg_to_value_map.count(vreg));
|
||||
Value* val = vreg_to_value_map.at(vreg);
|
||||
RVOpcodes store_op = val->getType()->isPointer() ? RVOpcodes::SD : RVOpcodes::SW;
|
||||
|
||||
int offset = frame_info.spill_offsets.at(vreg);
|
||||
auto store = std::make_unique<MachineInstr>(store_op);
|
||||
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()) {
|
||||
|
||||
// 情况一:操作数本身就是一个寄存器 (例如 add rd, rs1, rs2 中的所有操作数)
|
||||
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)) {
|
||||
PhysicalReg preg = color_map.at(vreg);
|
||||
reg_op->setPReg(preg);
|
||||
} else if (spilled_vregs.count(vreg)) {
|
||||
// 如果vreg被溢出,替换为专用的溢出物理寄存器t6
|
||||
reg_op->setPReg(PhysicalReg::T6);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 情况二:操作数是一个内存地址 (例如 lw rd, offset(rs1) 中的 offset(rs1))
|
||||
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)) {
|
||||
// 如果基址vreg被成功着色,替换
|
||||
PhysicalReg preg = color_map.at(vreg);
|
||||
base_reg_op->setPReg(preg);
|
||||
|
||||
} else if (spilled_vregs.count(vreg)) {
|
||||
// 如果基址vreg被溢出,替换为t6
|
||||
base_reg_op->setPReg(PhysicalReg::T6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@ -1,600 +0,0 @@
|
||||
#include "SysYIRCFGOpt.h"
|
||||
#include "SysYIROptUtils.h"
|
||||
#include <cassert>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <queue> // 引入队列,SysYDelNoPreBLock需要
|
||||
|
||||
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->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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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->end();
|
||||
(--thelastinstinst);
|
||||
if (thelastinstinst->get()->isUnconditional()) {
|
||||
SysYIROptUtils::usedelete(thelastinstinst->get());
|
||||
thelastinstinst = block->getInstructions().erase(thelastinstinst);
|
||||
} else if (thelastinstinst->get()->isConditional()) {
|
||||
// 如果是条件分支,判断条件是否相同,主要优化相同布尔表达式
|
||||
if (thelastinstinst->get()->getOperand(1)->getName() == thelastinstinst->get()->getOperand(1)->getName()) {
|
||||
SysYIROptUtils::usedelete(thelastinstinst->get());
|
||||
thelastinstinst = block->getInstructions().erase(thelastinstinst);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 将后继块的指令移动到当前块
|
||||
// 并将后继块的父指针改为当前块
|
||||
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;
|
||||
|
||||
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 instIter = blockIter->get()->getInstructions().begin();
|
||||
instIter != blockIter->get()->getInstructions().end();) {
|
||||
SysYIROptUtils::usedelete(instIter->get());
|
||||
instIter = blockIter->get()->getInstructions().erase(instIter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (auto blockIter = func->getBasicBlocks().begin(); blockIter != func->getBasicBlocks().end();) {
|
||||
if (!blockIter->get()->getreachable()) {
|
||||
for (auto succblock : blockIter->get()->getSuccessors()) {
|
||||
for (auto &phiinst : succblock->getInstructions()) {
|
||||
if (phiinst->getKind() != Instruction::kPhi) {
|
||||
break;
|
||||
}
|
||||
// 使用 delBlk 方法正确地删除对应于被删除基本块的传入值
|
||||
dynamic_cast<PhiInst *>(phiinst.get())->delBlk(blockIter->get());
|
||||
}
|
||||
}
|
||||
// 删除不可达基本块,注意迭代器不可达问题
|
||||
func->removeBasicBlock((blockIter++)->get());
|
||||
changed = true;
|
||||
} else {
|
||||
blockIter++;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
// 删除空块
|
||||
bool SysYCFGOptUtils::SysYDelEmptyBlock(Function *func, IRBuilder* pBuilder) {
|
||||
bool changed = false;
|
||||
|
||||
// 收集不可达基本块
|
||||
// 这里的不可达基本块是指没有实际指令的基本块
|
||||
// 当一个基本块没有实际指令例如只有phi指令和一个uncondbr指令时,也会被视作不可达
|
||||
auto basicBlocks = func->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 && basicBlock->getNumSuccessors() == 1) // 确保有后继且只有一个
|
||||
EmptyBlocks[basicBlock.get()] = basicBlock->getSuccessors().front();
|
||||
}
|
||||
}
|
||||
// 更新基本块信息,增加必要指令
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
// 把空块转换成只有跳转指令的不可达块 (这段逻辑在优化遍中可能需要调整,这里是原样保留)
|
||||
// 通常,DelEmptyBlock 应该在BlockMerge之后运行,如果存在完全空块,它会尝试填充一个Br指令。
|
||||
// 但是,它主要目的是重定向跳转。
|
||||
if (distance(basicBlock->begin(), basicBlock->end()) == 0) {
|
||||
if (basicBlock->getNumSuccessors() == 0) {
|
||||
continue;
|
||||
}
|
||||
if (basicBlock->getNumSuccessors() > 1) {
|
||||
// 如果一个空块有多个后继,说明CFG结构有问题或者需要特殊处理,这里简单assert
|
||||
assert(false && "Empty block with multiple successors found during SysYDelEmptyBlock");
|
||||
}
|
||||
// 这里的逻辑有点问题,如果一个块是空的,且只有一个后继,应该直接跳转到后继。
|
||||
// 如果这个块最终被删除了,那么其前驱也需要重定向。
|
||||
// 这个循环的目的是重定向现有的跳转指令,而不是创建新的。
|
||||
// 所以下面的逻辑才是核心。
|
||||
// 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.count(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0)))) {
|
||||
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
||||
thelastinst->get()->replaceOperand(0, EmptyBlocks[thelastBlockOld]);
|
||||
}
|
||||
|
||||
// 如果有重定向发生
|
||||
if (thelastBlockOld != nullptr) {
|
||||
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());
|
||||
changed = true; // 标记IR被修改
|
||||
}
|
||||
|
||||
|
||||
if (thelastBlockOld != nullptr) {
|
||||
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getInstructions()) {
|
||||
if (InstInNew->isPhi()) {
|
||||
// 使用 delBlk 方法删除 oldBlock 对应的传入值
|
||||
dynamic_cast<PhiInst *>(InstInNew.get())->delBlk(thelastBlockOld);
|
||||
} 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));
|
||||
bool thenChanged = false;
|
||||
bool elseChanged = false;
|
||||
|
||||
|
||||
BasicBlock *thelastBlockOld = nullptr;
|
||||
while (EmptyBlocks.count(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)))) {
|
||||
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||
thelastinst->get()->replaceOperand(
|
||||
1, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))]);
|
||||
thenChanged = true;
|
||||
}
|
||||
|
||||
if (thenChanged) {
|
||||
basicBlock->removeSuccessor(OldThenBlock);
|
||||
OldThenBlock->removePredecessor(basicBlock.get());
|
||||
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)));
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->addPredecessor(basicBlock.get());
|
||||
changed = true; // 标记IR被修改
|
||||
}
|
||||
|
||||
// 处理 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));
|
||||
SysYIROptUtils::usedelete(thelastinst->get());
|
||||
thelastinst = basicBlock->getInstructions().erase(thelastinst);
|
||||
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||
pBuilder->createUncondBrInst(thebrBlock, {});
|
||||
changed = true; // 标记IR被修改
|
||||
continue;
|
||||
}
|
||||
|
||||
if (thelastBlockOld != nullptr) {
|
||||
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->getInstructions()) {
|
||||
if (InstInNew->isPhi()) {
|
||||
// 使用 delBlk 方法删除 oldBlock 对应的传入值
|
||||
dynamic_cast<PhiInst *>(InstInNew.get())->delBlk(thelastBlockOld);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thelastBlockOld = nullptr;
|
||||
while (EmptyBlocks.count(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2)))) {
|
||||
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2));
|
||||
thelastinst->get()->replaceOperand(
|
||||
2, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))]);
|
||||
elseChanged = true;
|
||||
}
|
||||
|
||||
if (elseChanged) {
|
||||
basicBlock->removeSuccessor(OldElseBlock);
|
||||
OldElseBlock->removePredecessor(basicBlock.get());
|
||||
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2)));
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->addPredecessor(basicBlock.get());
|
||||
changed = true; // 标记IR被修改
|
||||
}
|
||||
|
||||
// 处理 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));
|
||||
SysYIROptUtils::usedelete(thelastinst->get());
|
||||
thelastinst = basicBlock->getInstructions().erase(thelastinst);
|
||||
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||
pBuilder->createUncondBrInst(thebrBlock, {});
|
||||
changed = true; // 标记IR被修改
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// 如果有重定向发生
|
||||
// 需要更新后继块的前驱关系
|
||||
if (thelastBlockOld != nullptr) {
|
||||
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->getInstructions()) {
|
||||
if (InstInNew->isPhi()) {
|
||||
// 使用 delBlk 方法删除 oldBlock 对应的传入值
|
||||
dynamic_cast<PhiInst *>(InstInNew.get())->delBlk(thelastBlockOld);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// 如果不是终止指令,但有后继 (例如,末尾没有显式终止指令的块)
|
||||
// 这段逻辑可能需要更严谨的CFG检查来确保正确性
|
||||
if (basicBlock->getNumSuccessors() == 1) {
|
||||
// 这里的逻辑似乎是想为没有terminator的块添加一个,但通常这应该在CFG构建阶段完成。
|
||||
// 如果这里仍然执行,确保它符合预期。
|
||||
// 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());
|
||||
// changed = true; // 标记IR被修改
|
||||
// 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 = func->getBasicBlocks().begin(); iter != func->getBasicBlocks().end();) {
|
||||
|
||||
if (EmptyBlocks.count(iter->get())) {
|
||||
// EntryBlock跳过
|
||||
if (iter->get() == func->getEntryBlock()) {
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto instIter = iter->get()->getInstructions().begin();
|
||||
instIter != iter->get()->getInstructions().end();) {
|
||||
SysYIROptUtils::usedelete(instIter->get()); // 仅删除 use 关系
|
||||
// 显式地从基本块中删除指令并更新迭代器
|
||||
instIter = iter->get()->getInstructions().erase(instIter);
|
||||
}
|
||||
// 删除不可达基本块的phi指令的操作数
|
||||
for (auto &succ : iter->get()->getSuccessors()) {
|
||||
for (auto &instinsucc : succ->getInstructions()) {
|
||||
if (instinsucc->isPhi()) {
|
||||
// iter->get() 就是当前被删除的空基本块,它作为前驱连接到这里的Phi指令
|
||||
dynamic_cast<PhiInst *>(instinsucc.get())->delBlk(iter->get());
|
||||
} else {
|
||||
// Phi 指令通常在基本块的开头,如果不是 Phi 指令就停止检查
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func->removeBasicBlock((iter++)->get());
|
||||
changed = true;
|
||||
} else {
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
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->getInstructions().end();
|
||||
--thelast;
|
||||
|
||||
if (thelast->get()->isConditional()){
|
||||
ConstantValue *constOperand = dynamic_cast<ConstantValue *>(thelast->get()->getOperand(0));
|
||||
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 *>(thelast->get()->getOperand(1));
|
||||
auto elseBlock = dynamic_cast<BasicBlock *>(thelast->get()->getOperand(2));
|
||||
SysYIROptUtils::usedelete(thelast->get());
|
||||
thelast = basicblock->getInstructions().erase(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())->delBlk(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())->delBlk(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
|
||||
File diff suppressed because it is too large
Load Diff
28
src/backend/RISCv64/CMakeLists.txt
Normal file
28
src/backend/RISCv64/CMakeLists.txt
Normal file
@ -0,0 +1,28 @@
|
||||
# src/backend/RISCv64/CMakeLists.txt
|
||||
add_library(riscv64_backend_lib STATIC
|
||||
RISCv64AsmPrinter.cpp
|
||||
RISCv64Backend.cpp
|
||||
RISCv64ISel.cpp
|
||||
RISCv64LLIR.cpp
|
||||
RISCv64RegAlloc.cpp
|
||||
RISCv64LinearScan.cpp
|
||||
RISCv64SimpleRegAlloc.cpp
|
||||
RISCv64BasicBlockAlloc.cpp
|
||||
Handler/CalleeSavedHandler.cpp
|
||||
Handler/LegalizeImmediates.cpp
|
||||
Handler/PrologueEpilogueInsertion.cpp
|
||||
Handler/EliminateFrameIndices.cpp
|
||||
Optimize/Peephole.cpp
|
||||
Optimize/PostRA_Scheduler.cpp
|
||||
Optimize/PreRA_Scheduler.cpp
|
||||
Optimize/DivStrengthReduction.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
|
||||
235
src/backend/RISCv64/Handler/EliminateFrameIndices.cpp
Normal file
235
src/backend/RISCv64/Handler/EliminateFrameIndices.cpp
Normal file
@ -0,0 +1,235 @@
|
||||
#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();
|
||||
|
||||
// 在这里处理栈传递的参数,以便在寄存器分配前就将数据流显式化,修复溢出逻辑的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);
|
||||
|
||||
// 优化栈帧大小:对于大数组使用4字节对齐,小对象使用8字节对齐
|
||||
if (size >= 256) { // 大数组优化
|
||||
size = (size + 3) & ~3; // 4字节对齐
|
||||
} else {
|
||||
size = (size + 7) & ~7; // 8字节对齐
|
||||
}
|
||||
if (size == 0) size = 4; // 最小4字节
|
||||
|
||||
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;
|
||||
// 记录局部变量区域分配结束的最终偏移量
|
||||
frame_info.locals_end_offset = -local_var_offset;
|
||||
|
||||
// 在函数入口为所有栈传递的参数插入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;
|
||||
|
||||
// 步骤 3.1: 生成所有加载栈参数的指令,暂存起来
|
||||
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++;
|
||||
}
|
||||
|
||||
//仅当有需要加载的栈参数时,才执行插入逻辑
|
||||
if (!arg_load_instrs.empty()) {
|
||||
auto& entry_instrs = entry_block->getInstructions();
|
||||
auto insertion_point = entry_instrs.begin(); // 默认插入点为块的开头
|
||||
auto last_arg_save_it = entry_instrs.end();
|
||||
|
||||
// 步骤 3.2: 寻找一个安全的插入点。
|
||||
// 遍历入口块的指令,找到最后一条保存“寄存器传递参数”的伪指令。
|
||||
// 这样可以确保我们在所有 a0-a7 参数被保存之后,才执行可能覆盖它们的加载指令。
|
||||
for (auto it = entry_instrs.begin(); it != entry_instrs.end(); ++it) {
|
||||
MachineInstr* instr = it->get();
|
||||
// 寻找代表保存参数到栈的伪指令
|
||||
if (instr->getOpcode() == RVOpcodes::FRAME_STORE_W ||
|
||||
instr->getOpcode() == RVOpcodes::FRAME_STORE_D ||
|
||||
instr->getOpcode() == RVOpcodes::FRAME_STORE_F) {
|
||||
|
||||
// 检查被保存的值是否是寄存器参数 (arg_no < 8)
|
||||
auto& operands = instr->getOperands();
|
||||
if (operands.empty() || operands[0]->getKind() != MachineOperand::KIND_REG) continue;
|
||||
|
||||
unsigned src_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
|
||||
Value* ir_value = isel->getVRegValueMap().count(src_vreg) ? isel->getVRegValueMap().at(src_vreg) : nullptr;
|
||||
|
||||
if (auto ir_arg = dynamic_cast<Argument*>(ir_value)) {
|
||||
if (ir_arg->getIndex() < 8) {
|
||||
last_arg_save_it = it; // 找到了一个保存寄存器参数的指令,更新位置
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果找到了这样的保存指令,我们的插入点就在它之后
|
||||
if (last_arg_save_it != entry_instrs.end()) {
|
||||
insertion_point = std::next(last_arg_save_it);
|
||||
}
|
||||
|
||||
// 步骤 3.3: 在计算出的安全位置,一次性插入所有新创建的参数加载指令
|
||||
entry_instrs.insert(insertion_point,
|
||||
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: case RVOpcodes::FLD: case RVOpcodes::FSD: {
|
||||
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
|
||||
182
src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp
Normal file
182
src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp
Normal file
@ -0,0 +1,182 @@
|
||||
#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)
|
||||
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;
|
||||
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.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;
|
||||
|
||||
// 3. 计算最终的栈帧总大小,包含栈溢出保护
|
||||
int total_stack_size = frame_info.locals_size +
|
||||
frame_info.spill_size +
|
||||
frame_info.callee_saved_size +
|
||||
16;
|
||||
|
||||
// 栈溢出保护:增加最大栈帧大小以容纳大型数组
|
||||
const int MAX_STACK_FRAME_SIZE = 8192; // 8KB to handle large arrays like 256*4*2 = 2048 bytes
|
||||
if (total_stack_size > MAX_STACK_FRAME_SIZE) {
|
||||
// 如果仍然超过限制,尝试优化对齐方式
|
||||
std::cerr << "Warning: Stack frame size " << total_stack_size
|
||||
<< " exceeds recommended limit " << MAX_STACK_FRAME_SIZE << " for function "
|
||||
<< mfunc->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 优化:减少对齐开销,使用16字节对齐而非更大的对齐
|
||||
int aligned_stack_size = (total_stack_size + 15) & ~15;
|
||||
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. 分配栈帧
|
||||
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
|
||||
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));
|
||||
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
|
||||
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. 保存所有使用到的被调用者保存寄存器
|
||||
int next_available_offset = -(16 + frame_info.locals_size + frame_info.spill_size);
|
||||
for (const auto& reg : frame_info.callee_saved_regs_to_store) {
|
||||
// 改为“先更新,后使用”逻辑
|
||||
next_available_offset -= 8; // 先为当前寄存器分配下一个可用槽位
|
||||
RVOpcodes store_op = isFPR(reg) ? 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>(next_available_offset) // 使用新计算出的正确偏移
|
||||
));
|
||||
prologue_instrs.push_back(std::move(save_cs_reg));
|
||||
// 不再需要在循环末尾递减
|
||||
}
|
||||
|
||||
// 4.5. 将所有生成的序言指令一次性插入到函数入口
|
||||
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()) {
|
||||
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. 恢复被调用者保存寄存器
|
||||
int next_available_offset_restore = -(16 + frame_info.locals_size + frame_info.spill_size);
|
||||
for (const auto& reg : frame_info.callee_saved_regs_to_store) {
|
||||
next_available_offset_restore -= 8; // 为下一个寄存器准备偏移
|
||||
RVOpcodes load_op = isFPR(reg) ? 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>(next_available_offset_restore) // 使用当前偏移
|
||||
));
|
||||
epilogue_instrs.push_back(std::move(restore_cs_reg));
|
||||
}
|
||||
|
||||
// 5.2. 恢复 ra 和 s0
|
||||
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));
|
||||
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. 释放栈帧
|
||||
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
|
||||
282
src/backend/RISCv64/Optimize/DivStrengthReduction.cpp
Normal file
282
src/backend/RISCv64/Optimize/DivStrengthReduction.cpp
Normal file
@ -0,0 +1,282 @@
|
||||
#include "DivStrengthReduction.h"
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
char DivStrengthReduction::ID = 0;
|
||||
|
||||
bool DivStrengthReduction::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
// This pass works on MachineFunction level, not IR level
|
||||
return false;
|
||||
}
|
||||
|
||||
void DivStrengthReduction::runOnMachineFunction(MachineFunction *mfunc) {
|
||||
if (!mfunc)
|
||||
return;
|
||||
|
||||
bool debug = false; // Set to true for debugging
|
||||
if (debug)
|
||||
std::cout << "Running DivStrengthReduction optimization..." << std::endl;
|
||||
|
||||
int next_temp_reg = 1000;
|
||||
auto createTempReg = [&]() -> int {
|
||||
return next_temp_reg++;
|
||||
};
|
||||
|
||||
struct MagicInfo {
|
||||
int64_t magic;
|
||||
int shift;
|
||||
};
|
||||
|
||||
auto computeMagic = [](int64_t d, bool is_32bit) -> MagicInfo {
|
||||
int word_size = is_32bit ? 32 : 64;
|
||||
uint64_t ad = std::abs(d);
|
||||
|
||||
if (ad == 0) return {0, 0};
|
||||
|
||||
int l = std::floor(std::log2(ad));
|
||||
if ((ad & (ad - 1)) == 0) { // power of 2
|
||||
l = 0; // special case for power of 2, shift will be calculated differently
|
||||
}
|
||||
|
||||
__int128_t one = 1;
|
||||
__int128_t num;
|
||||
int total_shift;
|
||||
|
||||
if (is_32bit) {
|
||||
total_shift = 31 + l;
|
||||
num = one << total_shift;
|
||||
} else {
|
||||
total_shift = 63 + l;
|
||||
num = one << total_shift;
|
||||
}
|
||||
|
||||
__int128_t den = ad;
|
||||
int64_t magic = (num / den) + 1;
|
||||
|
||||
return {magic, total_shift};
|
||||
};
|
||||
|
||||
auto isPowerOfTwo = [](int64_t n) -> bool {
|
||||
return n > 0 && (n & (n - 1)) == 0;
|
||||
};
|
||||
|
||||
auto getPowerOfTwoExponent = [](int64_t n) -> int {
|
||||
if (n <= 0 || (n & (n - 1)) != 0) return -1;
|
||||
int shift = 0;
|
||||
while (n > 1) {
|
||||
n >>= 1;
|
||||
shift++;
|
||||
}
|
||||
return shift;
|
||||
};
|
||||
|
||||
struct InstructionReplacement {
|
||||
size_t index;
|
||||
size_t count_to_erase;
|
||||
std::vector<std::unique_ptr<MachineInstr>> newInstrs;
|
||||
};
|
||||
|
||||
for (auto &mbb_uptr : mfunc->getBlocks()) {
|
||||
auto &mbb = *mbb_uptr;
|
||||
auto &instrs = mbb.getInstructions();
|
||||
std::vector<InstructionReplacement> replacements;
|
||||
|
||||
for (size_t i = 0; i < instrs.size(); ++i) {
|
||||
auto *instr = instrs[i].get();
|
||||
|
||||
bool is_32bit = (instr->getOpcode() == RVOpcodes::DIVW);
|
||||
|
||||
if (instr->getOpcode() != RVOpcodes::DIV && !is_32bit) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (instr->getOperands().size() != 3) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto *dst_op = instr->getOperands()[0].get();
|
||||
auto *src1_op = instr->getOperands()[1].get();
|
||||
auto *src2_op = instr->getOperands()[2].get();
|
||||
|
||||
int64_t divisor = 0;
|
||||
bool const_divisor_found = false;
|
||||
size_t instructions_to_replace = 1;
|
||||
|
||||
if (src2_op->getKind() == MachineOperand::KIND_IMM) {
|
||||
divisor = static_cast<ImmOperand *>(src2_op)->getValue();
|
||||
const_divisor_found = true;
|
||||
} else if (src2_op->getKind() == MachineOperand::KIND_REG) {
|
||||
if (i > 0) {
|
||||
auto *prev_instr = instrs[i - 1].get();
|
||||
if (prev_instr->getOpcode() == RVOpcodes::LI && prev_instr->getOperands().size() == 2) {
|
||||
auto *li_dst_op = prev_instr->getOperands()[0].get();
|
||||
auto *li_imm_op = prev_instr->getOperands()[1].get();
|
||||
if (li_dst_op->getKind() == MachineOperand::KIND_REG && li_imm_op->getKind() == MachineOperand::KIND_IMM) {
|
||||
auto *div_reg_op = static_cast<RegOperand *>(src2_op);
|
||||
auto *li_dst_reg_op = static_cast<RegOperand *>(li_dst_op);
|
||||
if (div_reg_op->isVirtual() && li_dst_reg_op->isVirtual() &&
|
||||
div_reg_op->getVRegNum() == li_dst_reg_op->getVRegNum()) {
|
||||
divisor = static_cast<ImmOperand *>(li_imm_op)->getValue();
|
||||
const_divisor_found = true;
|
||||
instructions_to_replace = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!const_divisor_found) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto *dst_reg = static_cast<RegOperand *>(dst_op);
|
||||
auto *src1_reg = static_cast<RegOperand *>(src1_op);
|
||||
|
||||
if (divisor == 0) continue;
|
||||
|
||||
std::vector<std::unique_ptr<MachineInstr>> newInstrs;
|
||||
|
||||
if (divisor == 1) {
|
||||
auto moveInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::ADDW : RVOpcodes::ADD);
|
||||
moveInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
|
||||
moveInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
|
||||
moveInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||
newInstrs.push_back(std::move(moveInstr));
|
||||
}
|
||||
else if (divisor == -1) {
|
||||
auto negInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SUBW : RVOpcodes::SUB);
|
||||
negInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
|
||||
negInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||
negInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
|
||||
newInstrs.push_back(std::move(negInstr));
|
||||
}
|
||||
else if (isPowerOfTwo(std::abs(divisor))) {
|
||||
int shift = getPowerOfTwoExponent(std::abs(divisor));
|
||||
int temp_reg = createTempReg();
|
||||
|
||||
auto sraSignInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SRAIW : RVOpcodes::SRAI);
|
||||
sraSignInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
sraSignInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
|
||||
sraSignInstr->addOperand(std::make_unique<ImmOperand>(is_32bit ? 31 : 63));
|
||||
newInstrs.push_back(std::move(sraSignInstr));
|
||||
|
||||
auto srlInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SRLIW : RVOpcodes::SRLI);
|
||||
srlInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
srlInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
srlInstr->addOperand(std::make_unique<ImmOperand>((is_32bit ? 32 : 64) - shift));
|
||||
newInstrs.push_back(std::move(srlInstr));
|
||||
|
||||
auto addInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::ADDW : RVOpcodes::ADD);
|
||||
addInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
addInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
|
||||
addInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
newInstrs.push_back(std::move(addInstr));
|
||||
|
||||
auto sraInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SRAIW : RVOpcodes::SRAI);
|
||||
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
sraInstr->addOperand(std::make_unique<ImmOperand>(shift));
|
||||
newInstrs.push_back(std::move(sraInstr));
|
||||
|
||||
if (divisor < 0) {
|
||||
auto negInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SUBW : RVOpcodes::SUB);
|
||||
negInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
|
||||
negInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||
negInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
newInstrs.push_back(std::move(negInstr));
|
||||
} else {
|
||||
auto moveInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::ADDW : RVOpcodes::ADD);
|
||||
moveInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
|
||||
moveInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
moveInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||
newInstrs.push_back(std::move(moveInstr));
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto magic_info = computeMagic(divisor, is_32bit);
|
||||
int magic_reg = createTempReg();
|
||||
int temp_reg = createTempReg();
|
||||
|
||||
auto loadInstr = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
loadInstr->addOperand(std::make_unique<RegOperand>(magic_reg));
|
||||
loadInstr->addOperand(std::make_unique<ImmOperand>(magic_info.magic));
|
||||
newInstrs.push_back(std::move(loadInstr));
|
||||
|
||||
if (is_32bit) {
|
||||
auto mulInstr = std::make_unique<MachineInstr>(RVOpcodes::MUL);
|
||||
mulInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
mulInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
|
||||
mulInstr->addOperand(std::make_unique<RegOperand>(magic_reg));
|
||||
newInstrs.push_back(std::move(mulInstr));
|
||||
|
||||
auto sraInstr = std::make_unique<MachineInstr>(RVOpcodes::SRAI);
|
||||
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
sraInstr->addOperand(std::make_unique<ImmOperand>(magic_info.shift));
|
||||
newInstrs.push_back(std::move(sraInstr));
|
||||
} else {
|
||||
auto mulhInstr = std::make_unique<MachineInstr>(RVOpcodes::MULH);
|
||||
mulhInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
mulhInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
|
||||
mulhInstr->addOperand(std::make_unique<RegOperand>(magic_reg));
|
||||
newInstrs.push_back(std::move(mulhInstr));
|
||||
|
||||
int post_shift = magic_info.shift - 63;
|
||||
if (post_shift > 0) {
|
||||
auto sraInstr = std::make_unique<MachineInstr>(RVOpcodes::SRAI);
|
||||
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
sraInstr->addOperand(std::make_unique<ImmOperand>(post_shift));
|
||||
newInstrs.push_back(std::move(sraInstr));
|
||||
}
|
||||
}
|
||||
|
||||
int sign_reg = createTempReg();
|
||||
auto sraSignInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SRAIW : RVOpcodes::SRAI);
|
||||
sraSignInstr->addOperand(std::make_unique<RegOperand>(sign_reg));
|
||||
sraSignInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
|
||||
sraSignInstr->addOperand(std::make_unique<ImmOperand>(is_32bit ? 31 : 63));
|
||||
newInstrs.push_back(std::move(sraSignInstr));
|
||||
|
||||
auto subInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SUBW : RVOpcodes::SUB);
|
||||
subInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
subInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
subInstr->addOperand(std::make_unique<RegOperand>(sign_reg));
|
||||
newInstrs.push_back(std::move(subInstr));
|
||||
|
||||
if (divisor < 0) {
|
||||
auto negInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SUBW : RVOpcodes::SUB);
|
||||
negInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
|
||||
negInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||
negInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
newInstrs.push_back(std::move(negInstr));
|
||||
} else {
|
||||
auto moveInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::ADDW : RVOpcodes::ADD);
|
||||
moveInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
|
||||
moveInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
moveInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||
newInstrs.push_back(std::move(moveInstr));
|
||||
}
|
||||
}
|
||||
|
||||
if (!newInstrs.empty()) {
|
||||
size_t start_index = i;
|
||||
if (instructions_to_replace == 2) {
|
||||
start_index = i - 1;
|
||||
}
|
||||
replacements.push_back({start_index, instructions_to_replace, std::move(newInstrs)});
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = replacements.rbegin(); it != replacements.rend(); ++it) {
|
||||
instrs.erase(instrs.begin() + it->index, instrs.begin() + it->index + it->count_to_erase);
|
||||
instrs.insert(instrs.begin() + it->index,
|
||||
std::make_move_iterator(it->newInstrs.begin()),
|
||||
std::make_move_iterator(it->newInstrs.end()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@ -1,9 +1,10 @@
|
||||
#include "RISCv64Peephole.h"
|
||||
#include "Peephole.h"
|
||||
#include <functional>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
char PeepholeOptimizer::ID = 0;
|
||||
bool PeepholeOptimizer::fusedMulAddEnabled = true; // 默认启用浮点乘加融合优化
|
||||
|
||||
bool PeepholeOptimizer::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
// This pass works on MachineFunction level, not IR level
|
||||
@ -634,6 +635,99 @@ void PeepholeOptimizer::runOnMachineFunction(MachineFunction *mfunc) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 8. 浮点乘加融合优化
|
||||
// 8.1 fmul.s t1, t2, t3; fadd.s t4, t1, t5 -> fmadd.s t4, t2, t3, t5
|
||||
else if (isFusedMulAddEnabled() &&
|
||||
mi1->getOpcode() == RVOpcodes::FMUL_S &&
|
||||
mi2->getOpcode() == RVOpcodes::FADD_S) {
|
||||
if (mi1->getOperands().size() == 3 && mi2->getOperands().size() == 3) {
|
||||
auto *fmul_dst = static_cast<RegOperand *>(mi1->getOperands()[0].get());
|
||||
auto *fmul_src1 = static_cast<RegOperand *>(mi1->getOperands()[1].get());
|
||||
auto *fmul_src2 = static_cast<RegOperand *>(mi1->getOperands()[2].get());
|
||||
|
||||
auto *fadd_dst = static_cast<RegOperand *>(mi2->getOperands()[0].get());
|
||||
auto *fadd_src1 = static_cast<RegOperand *>(mi2->getOperands()[1].get());
|
||||
auto *fadd_src2 = static_cast<RegOperand *>(mi2->getOperands()[2].get());
|
||||
|
||||
// 检查fmul的目标是否是fadd的第一个源操作数
|
||||
if (areRegsEqual(fmul_dst, fadd_src1)) {
|
||||
// 检查中间寄存器是否在后续还会被使用
|
||||
bool canOptimize = true;
|
||||
for (size_t j = i + 2; j < instrs.size(); ++j) {
|
||||
auto *later_instr = instrs[j].get();
|
||||
|
||||
// 如果中间寄存器被重新定义,则可以优化
|
||||
if (isRegRedefinedAt(later_instr, fmul_dst, areRegsEqual)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 如果中间寄存器被使用,则不能优化
|
||||
if (isRegUsedLater(instrs, fmul_dst, j)) {
|
||||
canOptimize = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (canOptimize) {
|
||||
// 创建新的FMADD_S指令: fmadd.s t4, t2, t3, t5
|
||||
auto newInstr = std::make_unique<MachineInstr>(RVOpcodes::FMADD_S);
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*fadd_dst));
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*fmul_src1));
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*fmul_src2));
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*fadd_src2));
|
||||
instrs[i + 1] = std::move(newInstr);
|
||||
instrs.erase(instrs.begin() + i);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 8.2 fmul.s t1, t2, t3; fadd.s t4, t5, t1 -> fmadd.s t4, t2, t3, t5
|
||||
else if (isFusedMulAddEnabled() &&
|
||||
mi1->getOpcode() == RVOpcodes::FMUL_S &&
|
||||
mi2->getOpcode() == RVOpcodes::FADD_S) {
|
||||
if (mi1->getOperands().size() == 3 && mi2->getOperands().size() == 3) {
|
||||
auto *fmul_dst = static_cast<RegOperand *>(mi1->getOperands()[0].get());
|
||||
auto *fmul_src1 = static_cast<RegOperand *>(mi1->getOperands()[1].get());
|
||||
auto *fmul_src2 = static_cast<RegOperand *>(mi1->getOperands()[2].get());
|
||||
|
||||
auto *fadd_dst = static_cast<RegOperand *>(mi2->getOperands()[0].get());
|
||||
auto *fadd_src1 = static_cast<RegOperand *>(mi2->getOperands()[1].get());
|
||||
auto *fadd_src2 = static_cast<RegOperand *>(mi2->getOperands()[2].get());
|
||||
|
||||
// 检查fmul的目标是否是fadd的第二个源操作数
|
||||
if (areRegsEqual(fmul_dst, fadd_src2)) {
|
||||
// 检查中间寄存器是否在后续还会被使用
|
||||
bool canOptimize = true;
|
||||
for (size_t j = i + 2; j < instrs.size(); ++j) {
|
||||
auto *later_instr = instrs[j].get();
|
||||
|
||||
// 如果中间寄存器被重新定义,则可以优化
|
||||
if (isRegRedefinedAt(later_instr, fmul_dst, areRegsEqual)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 如果中间寄存器被使用,则不能优化
|
||||
if (isRegUsedLater(instrs, fmul_dst, j)) {
|
||||
canOptimize = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (canOptimize) {
|
||||
// 创建新的FMADD_S指令: fmadd.s t4, t2, t3, t5
|
||||
auto newInstr = std::make_unique<MachineInstr>(RVOpcodes::FMADD_S);
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*fadd_dst));
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*fmul_src1));
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*fmul_src2));
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*fadd_src1));
|
||||
instrs[i + 1] = std::move(newInstr);
|
||||
instrs.erase(instrs.begin() + i);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 根据是否发生变化调整遍历索引
|
||||
if (!changed) {
|
||||
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
|
||||
@ -1,20 +1,10 @@
|
||||
#include "RISCv64AsmPrinter.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include <stdexcept>
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
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:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
RISCv64AsmPrinter::RISCv64AsmPrinter(MachineFunction* mfunc) : MFunc(mfunc) {}
|
||||
|
||||
@ -22,52 +12,12 @@ void RISCv64AsmPrinter::run(std::ostream& os, bool debug) {
|
||||
OS = &os;
|
||||
|
||||
*OS << ".globl " << MFunc->getName() << "\n";
|
||||
*OS << MFunc->getName() << ":\n";
|
||||
|
||||
printPrologue();
|
||||
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
printBasicBlock(mbb.get(), debug);
|
||||
}
|
||||
}
|
||||
|
||||
// 在 RISCv64AsmPrinter.cpp 文件中
|
||||
|
||||
void RISCv64AsmPrinter::printPrologue() {
|
||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||
// 计算总栈帧大小。
|
||||
// 包含三部分:局部变量区、寄存器溢出区、以及为被调用者保存(callee-saved)寄存器预留的区域。
|
||||
// 最后再加上为保存 ra 和 s0 固定的16字节。
|
||||
int total_stack_size = frame_info.locals_size +
|
||||
frame_info.spill_size +
|
||||
frame_info.callee_saved_size +
|
||||
16;
|
||||
|
||||
// 保持栈指针16字节对齐
|
||||
int aligned_stack_size = (total_stack_size + 15) & ~15;
|
||||
frame_info.total_size = aligned_stack_size; // 更新最终的栈大小
|
||||
|
||||
// 只有在需要分配栈空间时才生成指令
|
||||
if (aligned_stack_size > 0) {
|
||||
// 1. 一次性分配整个栈帧
|
||||
*OS << " addi sp, sp, -" << aligned_stack_size << "\n";
|
||||
// 2. 在新的栈顶附近保存 ra 和 s0
|
||||
*OS << " sd ra, " << (aligned_stack_size - 8) << "(sp)\n";
|
||||
*OS << " sd s0, " << (aligned_stack_size - 16) << "(sp)\n";
|
||||
// 3. 设置新的帧指针 s0,使其指向栈帧的底部(高地址)
|
||||
*OS << " addi s0, sp, " << aligned_stack_size << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64AsmPrinter::printEpilogue() {
|
||||
int aligned_stack_size = MFunc->getFrameInfo().total_size;
|
||||
if (aligned_stack_size > 0) {
|
||||
*OS << " ld ra, " << (aligned_stack_size - 8) << "(sp)\n";
|
||||
*OS << " ld s0, " << (aligned_stack_size - 16) << "(sp)\n";
|
||||
*OS << " addi sp, sp, " << aligned_stack_size << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64AsmPrinter::printBasicBlock(MachineBasicBlock* mbb, bool debug) {
|
||||
if (!mbb->getName().empty()) {
|
||||
*OS << mbb->getName() << ":\n";
|
||||
@ -79,9 +29,6 @@ void RISCv64AsmPrinter::printBasicBlock(MachineBasicBlock* mbb, bool debug) {
|
||||
|
||||
void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
|
||||
auto opcode = instr->getOpcode();
|
||||
if (opcode == RVOpcodes::RET) {
|
||||
printEpilogue();
|
||||
}
|
||||
|
||||
if (opcode == RVOpcodes::LABEL) {
|
||||
// 标签直接打印,不加缩进
|
||||
@ -97,7 +44,7 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
|
||||
case RVOpcodes::ADD: *OS << "add "; break; case RVOpcodes::ADDI: *OS << "addi "; break;
|
||||
case RVOpcodes::ADDW: *OS << "addw "; break; case RVOpcodes::ADDIW: *OS << "addiw "; break;
|
||||
case RVOpcodes::SUB: *OS << "sub "; break; case RVOpcodes::SUBW: *OS << "subw "; break;
|
||||
case RVOpcodes::MUL: *OS << "mul "; break; case RVOpcodes::MULW: *OS << "mulw "; break;
|
||||
case RVOpcodes::MUL: *OS << "mul "; break; case RVOpcodes::MULW: *OS << "mulw "; break; case RVOpcodes::MULH: *OS << "mulh "; break;
|
||||
case RVOpcodes::DIV: *OS << "div "; break; case RVOpcodes::DIVW: *OS << "divw "; break;
|
||||
case RVOpcodes::REM: *OS << "rem "; break; case RVOpcodes::REMW: *OS << "remw "; break;
|
||||
case RVOpcodes::XOR: *OS << "xor "; break; case RVOpcodes::XORI: *OS << "xori "; break;
|
||||
@ -116,7 +63,9 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
|
||||
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;
|
||||
@ -125,8 +74,24 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
|
||||
case RVOpcodes::LI: *OS << "li "; break; case RVOpcodes::LA: *OS << "la "; break;
|
||||
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: { // [核心修改] 为CALL指令添加特殊处理逻辑
|
||||
case RVOpcodes::SNEZ: *OS << "snez "; 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::FMADD_S: *OS << "fmadd.s "; break;
|
||||
case RVOpcodes::FNEG_S: *OS << "fneg.s "; break;
|
||||
case RVOpcodes::FEQ_S: *OS << "feq.s "; break;
|
||||
case RVOpcodes::FLT_S: *OS << "flt.s "; break;
|
||||
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::FCVT_W_S_RTZ: *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::FSRMI: *OS << "fsrmi "; break;
|
||||
case RVOpcodes::CALL: { // 为CALL指令添加特殊处理逻辑
|
||||
*OS << "call ";
|
||||
// 遍历所有操作数,只寻找并打印函数名标签
|
||||
for (const auto& op : instr->getOperands()) {
|
||||
@ -160,6 +125,15 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
|
||||
// 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");
|
||||
}
|
||||
@ -211,7 +185,7 @@ void RISCv64AsmPrinter::printOperand(MachineOperand* op) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string RISCv64AsmPrinter::regToString(PhysicalReg reg) {
|
||||
std::string RISCv64AsmPrinter::regToString(PhysicalReg reg) const {
|
||||
switch (reg) {
|
||||
case PhysicalReg::ZERO: return "x0"; case PhysicalReg::RA: return "ra";
|
||||
case PhysicalReg::SP: return "sp"; case PhysicalReg::GP: return "gp";
|
||||
@ -249,4 +223,30 @@ std::string RISCv64AsmPrinter::regToString(PhysicalReg reg) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string RISCv64AsmPrinter::formatInstr(const MachineInstr* instr) {
|
||||
if (!instr) return "(null instr)";
|
||||
|
||||
// 使用 stringstream 作为临时的输出目标
|
||||
std::stringstream ss;
|
||||
|
||||
// 关键: 临时将类成员 'OS' 指向我们的 stringstream
|
||||
std::ostream* old_os = this->OS;
|
||||
this->OS = &ss;
|
||||
|
||||
// 修正: 调用正确的内部打印函数 printMachineInstr
|
||||
printInstruction(const_cast<MachineInstr*>(instr), false);
|
||||
|
||||
// 恢复旧的 ostream 指针
|
||||
this->OS = old_os;
|
||||
|
||||
// 获取stringstream的内容并做一些清理
|
||||
std::string result = ss.str();
|
||||
size_t endpos = result.find_last_not_of(" \t\n\r");
|
||||
if (std::string::npos != endpos) {
|
||||
result = result.substr(0, endpos + 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
368
src/backend/RISCv64/RISCv64Backend.cpp
Normal file
368
src/backend/RISCv64/RISCv64Backend.cpp
Normal file
@ -0,0 +1,368 @@
|
||||
#include "RISCv64Backend.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include "RISCv64RegAlloc.h"
|
||||
#include "RISCv64LinearScan.h"
|
||||
#include "RISCv64SimpleRegAlloc.h"
|
||||
#include "RISCv64BasicBlockAlloc.h"
|
||||
#include "RISCv64AsmPrinter.h"
|
||||
#include "RISCv64Passes.h"
|
||||
#include <sstream>
|
||||
#include <future>
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
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";
|
||||
bool is_all_zeros = true;
|
||||
const auto& init_values = global->getInitValues();
|
||||
if (init_values.getValues().empty()) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_all_zeros) {
|
||||
ss << " .zero " << total_size << "\n";
|
||||
} else {
|
||||
// 对于有非零初始值的变量,保持原有的打印逻辑。
|
||||
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) {
|
||||
// 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers)
|
||||
RISCv64ISel isel;
|
||||
std::unique_ptr<MachineFunction> mfunc = isel.runOnFunction(func);
|
||||
// 第一次调试打印输出
|
||||
std::stringstream ss_after_isel;
|
||||
RISCv64AsmPrinter printer_isel(mfunc.get());
|
||||
printer_isel.run(ss_after_isel, true);
|
||||
// DEBUG = 1;
|
||||
if (DEBUG) {
|
||||
std::cerr << "====== Intermediate Representation after Instruction Selection ======\n"
|
||||
<< ss_after_isel.str();
|
||||
}
|
||||
// DEBUG = 0;
|
||||
// 阶段 2: 消除帧索引 (展开伪指令,计算局部变量偏移)
|
||||
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.1: 除法强度削弱优化 (Division Strength Reduction)
|
||||
DivStrengthReduction div_strength_reduction;
|
||||
div_strength_reduction.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// // 阶段 2.2: 指令调度 (Instruction Scheduling)
|
||||
// PreRA_Scheduler scheduler;
|
||||
// scheduler.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 3: 物理寄存器分配 (Register Allocation)
|
||||
bool allocation_succeeded = false;
|
||||
|
||||
// 尝试迭代图着色 (IRC)
|
||||
if (!irc_failed) {
|
||||
if (DEBUG) std::cerr << "Attempting Register Allocation with Iterated Register Coloring (IRC)...\n";
|
||||
RISCv64RegAlloc irc_alloc(mfunc.get());
|
||||
auto stop_flag = std::make_shared<std::atomic<bool>>(false);
|
||||
auto future = std::async(std::launch::async, &RISCv64RegAlloc::run, &irc_alloc, stop_flag);
|
||||
std::future_status status = future.wait_for(std::chrono::seconds(25));
|
||||
bool success_irc = false;
|
||||
if (status == std::future_status::ready) {
|
||||
try {
|
||||
if (future.get()) {
|
||||
success_irc = true;
|
||||
} else {
|
||||
std::cerr << "Warning: IRC explicitly returned failure for function '" << func->getName() << "'.\n";
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Error: IRC allocation threw an exception: " << e.what() << std::endl;
|
||||
}
|
||||
} else if (status == std::future_status::timeout) {
|
||||
std::cerr << "Warning: IRC allocation timed out after 25 seconds. Requesting cancellation...\n";
|
||||
stop_flag->store(true);
|
||||
try {
|
||||
future.get();
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Exception occurred during IRC thread shutdown after timeout: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (success_irc) {
|
||||
allocation_succeeded = true;
|
||||
if (DEBUG) std::cerr << "IRC allocation succeeded.\n";
|
||||
} else {
|
||||
std::cerr << "Info: Blacklisting IRC for subsequent functions and falling back.\n";
|
||||
irc_failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试简单图着色 (SGC)
|
||||
if (!allocation_succeeded) {
|
||||
// 如果是从IRC失败回退过来的,需要重新创建干净的mfunc和ISel
|
||||
RISCv64ISel isel_for_sgc;
|
||||
if (irc_failed) {
|
||||
if (DEBUG) std::cerr << "Info: Resetting MachineFunction for SGC attempt.\n";
|
||||
mfunc = isel_for_sgc.runOnFunction(func);
|
||||
EliminateFrameIndicesPass efi_pass_for_sgc;
|
||||
efi_pass_for_sgc.runOnMachineFunction(mfunc.get());
|
||||
}
|
||||
|
||||
if (DEBUG) std::cerr << "Attempting Register Allocation with Simple Graph Coloring (SGC)...\n";
|
||||
|
||||
bool sgc_completed_in_time = false;
|
||||
{
|
||||
RISCv64SimpleRegAlloc sgc_alloc(mfunc.get());
|
||||
auto future = std::async(std::launch::async, &RISCv64SimpleRegAlloc::run, &sgc_alloc);
|
||||
std::future_status status = future.wait_for(std::chrono::seconds(25));
|
||||
|
||||
if (status == std::future_status::ready) {
|
||||
try {
|
||||
future.get(); // 检查是否有异常
|
||||
sgc_completed_in_time = true;
|
||||
if (DEBUG) std::cerr << "SGC allocation completed successfully within the time limit.\n";
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Error: SGC allocation threw an exception: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sgc_completed_in_time) {
|
||||
allocation_succeeded = true;
|
||||
} else {
|
||||
std::cerr << "Warning: SGC allocation timed out or failed for function '" << func->getName()
|
||||
<< "'. Falling back.\n";
|
||||
}
|
||||
}
|
||||
|
||||
// 如果都失败了,则使用基本块分配器 (BBA)
|
||||
if (!allocation_succeeded) {
|
||||
// 为BBA准备干净的mfunc和ISel
|
||||
std::cerr << "Info: Resetting MachineFunction for BBA fallback.\n";
|
||||
RISCv64ISel isel_for_bba;
|
||||
mfunc = isel_for_bba.runOnFunction(func);
|
||||
EliminateFrameIndicesPass efi_pass_for_bba;
|
||||
efi_pass_for_bba.runOnMachineFunction(mfunc.get());
|
||||
|
||||
std::cerr << "Info: Using Basic Block Allocator as final fallback.\n";
|
||||
RISCv64BasicBlockAlloc bb_alloc(mfunc.get());
|
||||
bb_alloc.run();
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
// 阶段 3.3: 大立即数合法化
|
||||
LegalizeImmediatesPass legalizer;
|
||||
legalizer.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 6: 代码发射 (Code Emission)
|
||||
std::stringstream ss;
|
||||
RISCv64AsmPrinter printer(mfunc.get());
|
||||
printer.run(ss);
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
267
src/backend/RISCv64/RISCv64BasicBlockAlloc.cpp
Normal file
267
src/backend/RISCv64/RISCv64BasicBlockAlloc.cpp
Normal file
@ -0,0 +1,267 @@
|
||||
#include "RISCv64BasicBlockAlloc.h"
|
||||
#include "RISCv64Info.h"
|
||||
#include "RISCv64AsmPrinter.h"
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
// 外部调试级别控制变量
|
||||
extern int DEBUG;
|
||||
extern int DEEPDEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 将 getInstrUseDef 的定义移到这里,因为它是一个全局的辅助函数
|
||||
void getInstrUseDef(const MachineInstr* instr, std::set<unsigned>& use, std::set<unsigned>& def) {
|
||||
auto opcode = instr->getOpcode();
|
||||
const auto& operands = instr->getOperands();
|
||||
|
||||
auto get_vreg_id_if_virtual = [&](const MachineOperand* op, std::set<unsigned>& s) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<const RegOperand*>(op);
|
||||
if (reg_op->isVirtual()) s.insert(reg_op->getVRegNum());
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto mem_op = static_cast<const MemOperand*>(op);
|
||||
auto reg_op = mem_op->getBase();
|
||||
if (reg_op->isVirtual()) s.insert(reg_op->getVRegNum());
|
||||
}
|
||||
};
|
||||
|
||||
if (op_info.count(opcode)) {
|
||||
const auto& info = op_info.at(opcode);
|
||||
for (int idx : info.first) if (idx < operands.size()) get_vreg_id_if_virtual(operands[idx].get(), def);
|
||||
for (int idx : info.second) if (idx < operands.size()) get_vreg_id_if_virtual(operands[idx].get(), use);
|
||||
// 内存操作数的基址寄存器总是use
|
||||
for (const auto& op : operands) if (op->getKind() == MachineOperand::KIND_MEM) get_vreg_id_if_virtual(op.get(), use);
|
||||
} else if (opcode == RVOpcodes::CALL) {
|
||||
if (!operands.empty() && operands[0]->getKind() == MachineOperand::KIND_REG) get_vreg_id_if_virtual(operands[0].get(), def);
|
||||
for (size_t i = 1; i < operands.size(); ++i) if (operands[i]->getKind() == MachineOperand::KIND_REG) get_vreg_id_if_virtual(operands[i].get(), use);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RISCv64BasicBlockAlloc::RISCv64BasicBlockAlloc(MachineFunction* mfunc)
|
||||
: MFunc(mfunc), ISel(mfunc->getISel()) {
|
||||
// 初始化临时寄存器池
|
||||
int_temps = {PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3, PhysicalReg::T6};
|
||||
fp_temps = {PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3, PhysicalReg::F4};
|
||||
int_temp_idx = 0;
|
||||
fp_temp_idx = 0;
|
||||
|
||||
// 构建ABI寄存器映射
|
||||
if (MFunc->getFunc()) {
|
||||
int int_arg_idx = 0;
|
||||
int fp_arg_idx = 0;
|
||||
for (Argument* arg : MFunc->getFunc()->getArguments()) {
|
||||
unsigned arg_vreg = ISel->getVReg(arg);
|
||||
if (arg->getType()->isFloat()) {
|
||||
if (fp_arg_idx < 8) {
|
||||
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + fp_arg_idx++);
|
||||
abi_vreg_map[arg_vreg] = preg;
|
||||
}
|
||||
} else {
|
||||
if (int_arg_idx < 8) {
|
||||
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + int_arg_idx++);
|
||||
abi_vreg_map[arg_vreg] = preg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64BasicBlockAlloc::run() {
|
||||
if (DEBUG) std::cerr << "===== [BB-Alloc] Running Stateful Greedy Allocator for function: " << MFunc->getName() << " =====\n";
|
||||
|
||||
computeLiveness();
|
||||
assignStackSlotsForAllVRegs();
|
||||
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
processBasicBlock(mbb.get());
|
||||
}
|
||||
|
||||
// 将ABI寄存器映射(如函数参数)合并到最终结果中
|
||||
MFunc->getFrameInfo().vreg_to_preg_map.insert(this->abi_vreg_map.begin(), this->abi_vreg_map.end());
|
||||
}
|
||||
|
||||
PhysicalReg RISCv64BasicBlockAlloc::getNextIntTemp() {
|
||||
PhysicalReg reg = int_temps[int_temp_idx];
|
||||
int_temp_idx = (int_temp_idx + 1) % int_temps.size();
|
||||
return reg;
|
||||
}
|
||||
|
||||
PhysicalReg RISCv64BasicBlockAlloc::getNextFpTemp() {
|
||||
PhysicalReg reg = fp_temps[fp_temp_idx];
|
||||
fp_temp_idx = (fp_temp_idx + 1) % fp_temps.size();
|
||||
return reg;
|
||||
}
|
||||
|
||||
void RISCv64BasicBlockAlloc::computeLiveness() {
|
||||
// 这是一个必需的步骤,用于确定在块末尾哪些变量需要被写回栈
|
||||
// 为保持聚焦,此处暂时留空,但请确保您有一个有效的活性分析来填充 live_out 映射
|
||||
}
|
||||
|
||||
void RISCv64BasicBlockAlloc::assignStackSlotsForAllVRegs() {
|
||||
if (DEBUG) std::cerr << "[BB-Alloc] Assigning stack slots for all vregs.\n";
|
||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||
int current_offset = frame_info.locals_end_offset;
|
||||
const auto& vreg_type_map = ISel->getVRegTypeMap();
|
||||
|
||||
for (unsigned vreg = 1; vreg < ISel->getVRegCounter(); ++vreg) {
|
||||
if (this->abi_vreg_map.count(vreg) || frame_info.alloca_offsets.count(vreg) || frame_info.spill_offsets.count(vreg)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Type* type = vreg_type_map.count(vreg) ? vreg_type_map.at(vreg) : Type::getIntType();
|
||||
int size = type->isPointer() ? 8 : 4;
|
||||
|
||||
current_offset -= size;
|
||||
current_offset &= -size; // 按size对齐
|
||||
|
||||
frame_info.spill_offsets[vreg] = current_offset;
|
||||
}
|
||||
frame_info.spill_size = -(current_offset - frame_info.locals_end_offset);
|
||||
}
|
||||
|
||||
void RISCv64BasicBlockAlloc::processBasicBlock(MachineBasicBlock* mbb) {
|
||||
if (DEEPDEBUG) std::cerr << " [BB-Alloc] Processing block " << mbb->getName() << "\n";
|
||||
|
||||
vreg_to_preg.clear();
|
||||
preg_to_vreg.clear();
|
||||
dirty_pregs.clear();
|
||||
|
||||
auto& instrs = mbb->getInstructions();
|
||||
std::vector<std::unique_ptr<MachineInstr>> new_instrs;
|
||||
const auto& vreg_type_map = ISel->getVRegTypeMap();
|
||||
|
||||
for (auto& instr_ptr : instrs) {
|
||||
std::set<unsigned> use_vregs, def_vregs;
|
||||
getInstrUseDef(instr_ptr.get(), use_vregs, def_vregs);
|
||||
|
||||
std::map<unsigned, PhysicalReg> current_instr_map;
|
||||
|
||||
// 1. 确保所有use操作数都在物理寄存器中
|
||||
for (unsigned vreg : use_vregs) {
|
||||
current_instr_map[vreg] = ensureInReg(vreg, new_instrs);
|
||||
}
|
||||
|
||||
// 2. 为所有def操作数分配物理寄存器
|
||||
for (unsigned vreg : def_vregs) {
|
||||
current_instr_map[vreg] = allocReg(vreg, new_instrs);
|
||||
}
|
||||
|
||||
// 3. 重写指令,将vreg替换为preg
|
||||
for (const auto& pair : current_instr_map) {
|
||||
instr_ptr->replaceVRegWithPReg(pair.first, pair.second);
|
||||
}
|
||||
|
||||
new_instrs.push_back(std::move(instr_ptr));
|
||||
}
|
||||
|
||||
// 4. 在块末尾,写回所有被修改过的且在后续块中活跃(live-out)的vreg
|
||||
StackFrameInfo& frame_info = MFunc->getFrameInfo(); // **修正:获取frame_info引用**
|
||||
const auto& lo = live_out[mbb];
|
||||
for(auto const& [preg, vreg] : preg_to_vreg) {
|
||||
// **修正:简化逻辑,在此保底分配器中总是写回脏寄存器**
|
||||
if (dirty_pregs.count(preg)) {
|
||||
if (!frame_info.spill_offsets.count(vreg)) continue;
|
||||
Type* type = vreg_type_map.at(vreg);
|
||||
RVOpcodes store_op = type->isFloat() ? RVOpcodes::FSW : (type->isPointer() ? RVOpcodes::SD : RVOpcodes::SW);
|
||||
auto store = std::make_unique<MachineInstr>(store_op);
|
||||
store->addOperand(std::make_unique<RegOperand>(preg));
|
||||
store->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(vreg))
|
||||
));
|
||||
new_instrs.push_back(std::move(store));
|
||||
}
|
||||
}
|
||||
|
||||
instrs = std::move(new_instrs);
|
||||
}
|
||||
|
||||
PhysicalReg RISCv64BasicBlockAlloc::ensureInReg(unsigned vreg, std::vector<std::unique_ptr<MachineInstr>>& new_instrs) {
|
||||
if (abi_vreg_map.count(vreg)) {
|
||||
return abi_vreg_map.at(vreg);
|
||||
}
|
||||
if (vreg_to_preg.count(vreg)) {
|
||||
return vreg_to_preg.at(vreg);
|
||||
}
|
||||
|
||||
PhysicalReg preg = allocReg(vreg, new_instrs);
|
||||
|
||||
const auto& vreg_type_map = ISel->getVRegTypeMap();
|
||||
Type* type = vreg_type_map.count(vreg) ? vreg_type_map.at(vreg) : Type::getIntType();
|
||||
RVOpcodes load_op = type->isFloat() ? RVOpcodes::FLW : (type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW);
|
||||
|
||||
auto load = std::make_unique<MachineInstr>(load_op);
|
||||
load->addOperand(std::make_unique<RegOperand>(preg));
|
||||
load->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(MFunc->getFrameInfo().spill_offsets.at(vreg))
|
||||
));
|
||||
new_instrs.push_back(std::move(load));
|
||||
|
||||
dirty_pregs.erase(preg);
|
||||
|
||||
return preg;
|
||||
}
|
||||
|
||||
PhysicalReg RISCv64BasicBlockAlloc::allocReg(unsigned vreg, std::vector<std::unique_ptr<MachineInstr>>& new_instrs) {
|
||||
if (abi_vreg_map.count(vreg)) {
|
||||
dirty_pregs.insert(abi_vreg_map.at(vreg)); // 如果参数被重定义,也标记为脏
|
||||
return abi_vreg_map.at(vreg);
|
||||
}
|
||||
|
||||
bool is_fp = ISel->getVRegTypeMap().at(vreg)->isFloat();
|
||||
PhysicalReg preg = findFreeReg(is_fp);
|
||||
if (preg == PhysicalReg::INVALID) {
|
||||
preg = spillReg(is_fp, new_instrs);
|
||||
}
|
||||
|
||||
if (preg_to_vreg.count(preg)) {
|
||||
vreg_to_preg.erase(preg_to_vreg.at(preg));
|
||||
}
|
||||
vreg_to_preg[vreg] = preg;
|
||||
preg_to_vreg[preg] = vreg;
|
||||
dirty_pregs.insert(preg);
|
||||
|
||||
return preg;
|
||||
}
|
||||
|
||||
PhysicalReg RISCv64BasicBlockAlloc::findFreeReg(bool is_fp) {
|
||||
// **修正:使用正确的成员变量名 int_temps 和 fp_temps**
|
||||
const auto& regs = is_fp ? fp_temps : int_temps;
|
||||
for (PhysicalReg preg : regs) {
|
||||
if (!preg_to_vreg.count(preg)) {
|
||||
return preg;
|
||||
}
|
||||
}
|
||||
return PhysicalReg::INVALID;
|
||||
}
|
||||
|
||||
PhysicalReg RISCv64BasicBlockAlloc::spillReg(bool is_fp, std::vector<std::unique_ptr<MachineInstr>>& new_instrs) {
|
||||
// **修正**: 调用成员函数需要使用 this->
|
||||
PhysicalReg preg_to_spill = is_fp ? this->getNextFpTemp() : this->getNextIntTemp();
|
||||
|
||||
if (preg_to_vreg.count(preg_to_spill)) {
|
||||
unsigned victim_vreg = preg_to_vreg.at(preg_to_spill);
|
||||
if (dirty_pregs.count(preg_to_spill)) {
|
||||
const auto& vreg_type_map = ISel->getVRegTypeMap();
|
||||
Type* type = vreg_type_map.count(victim_vreg) ? vreg_type_map.at(victim_vreg) : Type::getIntType();
|
||||
RVOpcodes store_op = type->isFloat() ? RVOpcodes::FSW : (type->isPointer() ? RVOpcodes::SD : RVOpcodes::SW);
|
||||
auto store = std::make_unique<MachineInstr>(store_op);
|
||||
store->addOperand(std::make_unique<RegOperand>(preg_to_spill));
|
||||
store->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(MFunc->getFrameInfo().spill_offsets.at(victim_vreg))
|
||||
));
|
||||
new_instrs.push_back(std::move(store));
|
||||
}
|
||||
vreg_to_preg.erase(victim_vreg);
|
||||
dirty_pregs.erase(preg_to_spill);
|
||||
}
|
||||
|
||||
preg_to_vreg.erase(preg_to_spill);
|
||||
return preg_to_spill;
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
File diff suppressed because it is too large
Load Diff
195
src/backend/RISCv64/RISCv64LLIR.cpp
Normal file
195
src/backend/RISCv64/RISCv64LLIR.cpp
Normal file
@ -0,0 +1,195 @@
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "RISCv64Info.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";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief (为紧急溢出模式添加)将指令中所有对特定虚拟寄存器的引用替换为指定的物理寄存器。
|
||||
*/
|
||||
void MachineInstr::replaceVRegWithPReg(unsigned old_vreg, PhysicalReg preg) {
|
||||
for (auto& op : operands) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||
if (reg_op->isVirtual() && reg_op->getVRegNum() == old_vreg) {
|
||||
// 将虚拟寄存器操作数直接转换为物理寄存器操作数
|
||||
reg_op->setPReg(preg);
|
||||
}
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
// 同时处理内存操作数中的基址寄存器
|
||||
auto mem_op = static_cast<MemOperand*>(op.get());
|
||||
auto base_reg = mem_op->getBase();
|
||||
if (base_reg->isVirtual() && base_reg->getVRegNum() == old_vreg) {
|
||||
base_reg->setPReg(preg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief (为常规溢出模式添加)根据提供的映射表,重映射指令中的虚拟寄存器。
|
||||
* 这个函数的逻辑与 RISCv64LinearScan::getInstrUseDef 非常相似,因为它也需要
|
||||
* 知道哪个操作数是 use,哪个是 def。
|
||||
*/
|
||||
void MachineInstr::remapVRegs(const std::map<unsigned, unsigned>& use_remap, const std::map<unsigned, unsigned>& def_remap) {
|
||||
auto opcode = getOpcode();
|
||||
|
||||
// 辅助lambda,用于替换寄存器操作数
|
||||
auto remap_reg_op = [](RegOperand* reg_op, const std::map<unsigned, unsigned>& remap) {
|
||||
if (reg_op->isVirtual() && remap.count(reg_op->getVRegNum())) {
|
||||
reg_op->setVRegNum(remap.at(reg_op->getVRegNum()));
|
||||
}
|
||||
};
|
||||
|
||||
// 根据指令信息表(op_info)来确定 use 和 def
|
||||
if (op_info.count(opcode)) {
|
||||
const auto& info = op_info.at(opcode);
|
||||
// 替换 def 操作数
|
||||
for (int idx : info.first) {
|
||||
if (idx < operands.size() && operands[idx]->getKind() == MachineOperand::KIND_REG) {
|
||||
remap_reg_op(static_cast<RegOperand*>(operands[idx].get()), def_remap);
|
||||
}
|
||||
}
|
||||
// 替换 use 操作数
|
||||
for (int idx : info.second) {
|
||||
if (idx < operands.size()) {
|
||||
if (operands[idx]->getKind() == MachineOperand::KIND_REG) {
|
||||
remap_reg_op(static_cast<RegOperand*>(operands[idx].get()), use_remap);
|
||||
} else if (operands[idx]->getKind() == MachineOperand::KIND_MEM) {
|
||||
// 内存操作数的基址寄存器总是 use
|
||||
remap_reg_op(static_cast<MemOperand*>(operands[idx].get())->getBase(), use_remap);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (opcode == RVOpcodes::CALL) {
|
||||
// 处理 CALL 指令的特殊情况
|
||||
// 第一个操作数(如果存在且是寄存器)是 def
|
||||
if (!operands.empty() && operands[0]->getKind() == MachineOperand::KIND_REG) {
|
||||
remap_reg_op(static_cast<RegOperand*>(operands[0].get()), def_remap);
|
||||
}
|
||||
// 其余寄存器操作数是 use
|
||||
for (size_t i = 1; i < operands.size(); ++i) {
|
||||
if (operands[i]->getKind() == MachineOperand::KIND_REG) {
|
||||
remap_reg_op(static_cast<RegOperand*>(operands[i].get()), use_remap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
694
src/backend/RISCv64/RISCv64LinearScan.cpp
Normal file
694
src/backend/RISCv64/RISCv64LinearScan.cpp
Normal file
@ -0,0 +1,694 @@
|
||||
#include "RISCv64LinearScan.h"
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include "RISCv64Info.h"
|
||||
#include "RISCv64AsmPrinter.h"
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <functional>
|
||||
|
||||
// 外部调试级别控制变量
|
||||
extern int DEBUG;
|
||||
extern int DEEPDEBUG;
|
||||
extern int DEEPERDEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// --- 调试辅助函数 ---
|
||||
// These helpers are self-contained and only used for logging.
|
||||
static std::string pregToString(PhysicalReg preg) {
|
||||
// This map is a copy from AsmPrinter to avoid dependency issues.
|
||||
static const std::map<PhysicalReg, std::string> preg_names = {
|
||||
{PhysicalReg::ZERO, "zero"}, {PhysicalReg::RA, "ra"}, {PhysicalReg::SP, "sp"}, {PhysicalReg::GP, "gp"}, {PhysicalReg::TP, "tp"},
|
||||
{PhysicalReg::T0, "t0"}, {PhysicalReg::T1, "t1"}, {PhysicalReg::T2, "t2"}, {PhysicalReg::T3, "t3"}, {PhysicalReg::T4, "t4"}, {PhysicalReg::T5, "t5"}, {PhysicalReg::T6, "t6"},
|
||||
{PhysicalReg::S0, "s0"}, {PhysicalReg::S1, "s1"}, {PhysicalReg::S2, "s2"}, {PhysicalReg::S3, "s3"}, {PhysicalReg::S4, "s4"}, {PhysicalReg::S5, "s5"}, {PhysicalReg::S6, "s6"}, {PhysicalReg::S7, "s7"}, {PhysicalReg::S8, "s8"}, {PhysicalReg::S9, "s9"}, {PhysicalReg::S10, "s10"}, {PhysicalReg::S11, "s11"},
|
||||
{PhysicalReg::A0, "a0"}, {PhysicalReg::A1, "a1"}, {PhysicalReg::A2, "a2"}, {PhysicalReg::A3, "a3"}, {PhysicalReg::A4, "a4"}, {PhysicalReg::A5, "a5"}, {PhysicalReg::A6, "a6"}, {PhysicalReg::A7, "a7"},
|
||||
{PhysicalReg::F0, "f0"}, {PhysicalReg::F1, "f1"}, {PhysicalReg::F2, "f2"}, {PhysicalReg::F3, "f3"}, {PhysicalReg::F4, "f4"}, {PhysicalReg::F5, "f5"}, {PhysicalReg::F6, "f6"}, {PhysicalReg::F7, "f7"},
|
||||
{PhysicalReg::F8, "f8"}, {PhysicalReg::F9, "f9"}, {PhysicalReg::F10, "f10"}, {PhysicalReg::F11, "f11"}, {PhysicalReg::F12, "f12"}, {PhysicalReg::F13, "f13"}, {PhysicalReg::F14, "f14"}, {PhysicalReg::F15, "f15"},
|
||||
{PhysicalReg::F16, "f16"}, {PhysicalReg::F17, "f17"}, {PhysicalReg::F18, "f18"}, {PhysicalReg::F19, "f19"}, {PhysicalReg::F20, "f20"}, {PhysicalReg::F21, "f21"}, {PhysicalReg::F22, "f22"}, {PhysicalReg::F23, "f23"},
|
||||
{PhysicalReg::F24, "f24"}, {PhysicalReg::F25, "f25"}, {PhysicalReg::F26, "f26"}, {PhysicalReg::F27, "f27"}, {PhysicalReg::F28, "f28"}, {PhysicalReg::F29, "f29"}, {PhysicalReg::F30, "f30"}, {PhysicalReg::F31, "f31"},
|
||||
{PhysicalReg::INVALID, "INVALID"}
|
||||
};
|
||||
if (preg_names.count(preg)) return preg_names.at(preg);
|
||||
return "UnknownPreg";
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::string setToString(const std::set<T>& s, std::function<std::string(T)> formatter) {
|
||||
std::stringstream ss;
|
||||
ss << "{ ";
|
||||
bool first = true;
|
||||
for (const auto& item : s) {
|
||||
if (!first) ss << ", ";
|
||||
ss << formatter(item);
|
||||
first = false;
|
||||
}
|
||||
ss << " }";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static std::string vregSetToString(const std::set<unsigned>& s) {
|
||||
return setToString<unsigned>(s, [](unsigned v){ return "%v" + std::to_string(v); });
|
||||
}
|
||||
|
||||
static std::string pregSetToString(const std::set<PhysicalReg>& s) {
|
||||
return setToString<PhysicalReg>(s, pregToString);
|
||||
}
|
||||
|
||||
// Helper function to check if a register is callee-saved.
|
||||
// Defined locally to avoid scope issues.
|
||||
static bool isCalleeSaved(PhysicalReg preg) {
|
||||
if (preg >= PhysicalReg::S0 && preg <= PhysicalReg::S11) return true;
|
||||
if (preg >= PhysicalReg::F8 && preg <= PhysicalReg::F9) return true;
|
||||
if (preg >= PhysicalReg::F18 && preg <= PhysicalReg::F27) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
RISCv64LinearScan::RISCv64LinearScan(MachineFunction* mfunc)
|
||||
: MFunc(mfunc),
|
||||
ISel(mfunc->getISel()),
|
||||
vreg_type_map(ISel->getVRegTypeMap()) {
|
||||
|
||||
allocable_int_regs = {
|
||||
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3, PhysicalReg::T6,
|
||||
PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3, PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
|
||||
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
|
||||
};
|
||||
allocable_fp_regs = {
|
||||
PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3, PhysicalReg::F4, PhysicalReg::F5, PhysicalReg::F6, PhysicalReg::F7,
|
||||
PhysicalReg::F10, PhysicalReg::F11, PhysicalReg::F12, PhysicalReg::F13, PhysicalReg::F14, PhysicalReg::F15, PhysicalReg::F16, PhysicalReg::F17,
|
||||
PhysicalReg::F8, PhysicalReg::F9, 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,
|
||||
};
|
||||
if (MFunc->getFunc()) {
|
||||
int int_arg_idx = 0;
|
||||
int fp_arg_idx = 0;
|
||||
for (Argument* arg : MFunc->getFunc()->getArguments()) {
|
||||
unsigned arg_vreg = ISel->getVReg(arg);
|
||||
if (arg->getType()->isFloat()) {
|
||||
if (fp_arg_idx < 8) {
|
||||
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + fp_arg_idx++);
|
||||
abi_vreg_map[arg_vreg] = preg;
|
||||
}
|
||||
} else {
|
||||
if (int_arg_idx < 8) {
|
||||
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + int_arg_idx++);
|
||||
abi_vreg_map[arg_vreg] = preg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RISCv64LinearScan::run() {
|
||||
if (DEBUG) std::cerr << "===== [LSRA] Running for function: " << MFunc->getName() << " =====\n";
|
||||
|
||||
const int MAX_ITERATIONS = 3;
|
||||
|
||||
for (int iteration = 1; ; ++iteration) {
|
||||
if (DEBUG && iteration > 1) {
|
||||
std::cerr << "\n----- [LSRA] Re-running iteration " << iteration << " -----\n";
|
||||
}
|
||||
|
||||
linearizeBlocks();
|
||||
computeLiveIntervals();
|
||||
bool needs_spill = linearScan();
|
||||
|
||||
// 如果当前这轮线性扫描不需要溢出,说明分配成功,直接跳出循环。
|
||||
if (!needs_spill) {
|
||||
break;
|
||||
}
|
||||
|
||||
// --- 检查是否需要启动或已经失败于保底策略 ---
|
||||
if (iteration > MAX_ITERATIONS) {
|
||||
// 如果我们已经在保底模式下运行过,但这一轮 linearScan 仍然返回 true,
|
||||
// 这说明发生了无法解决的错误,此时才真正失败。
|
||||
if (conservative_spill_mode) {
|
||||
std::cerr << "\n!!!!!! [LSRA-FATAL] Allocation failed to converge even in Conservative Spill Mode. Triggering final fallback. !!!!!!\n\n";
|
||||
return false; // 返回失败,而不是exit
|
||||
}
|
||||
// 这是第一次达到最大迭代次数,触发保底策略。
|
||||
std::cerr << "\n!!!!!! [LSRA-WARN] Convergence failed after " << MAX_ITERATIONS
|
||||
<< " iterations. Entering Conservative Spill Mode for the next attempt. !!!!!!\n\n";
|
||||
conservative_spill_mode = true; // 开启保守溢出模式,将在下一次循环生效
|
||||
}
|
||||
|
||||
// 只要需要溢出,就重写程序
|
||||
if (DEBUG) std::cerr << "[LSRA] Spilling detected, will rewrite program.\n";
|
||||
rewriteProgram();
|
||||
}
|
||||
|
||||
if (DEBUG) std::cerr << "[LSRA] Applying final allocation.\n";
|
||||
applyAllocation();
|
||||
MFunc->getFrameInfo().vreg_to_preg_map = this->vreg_to_preg_map;
|
||||
collectUsedCalleeSavedRegs();
|
||||
|
||||
if (DEBUG) std::cerr << "===== [LSRA] Finished for function: " << MFunc->getName() << " =====\n\n";
|
||||
return true; // 分配成功
|
||||
}
|
||||
|
||||
void RISCv64LinearScan::linearizeBlocks() {
|
||||
linear_order_blocks.clear();
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
linear_order_blocks.push_back(mbb.get());
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64LinearScan::computeLiveIntervals() {
|
||||
if (DEBUG) std::cerr << "[LSRA-Live] Starting live interval computation.\n";
|
||||
instr_numbering.clear();
|
||||
live_intervals.clear();
|
||||
unhandled.clear();
|
||||
|
||||
int num = 0;
|
||||
std::set<int> call_locations;
|
||||
for (auto* mbb : linear_order_blocks) {
|
||||
for (auto& instr : mbb->getInstructions()) {
|
||||
instr_numbering[instr.get()] = num;
|
||||
if (instr->getOpcode() == RVOpcodes::CALL) call_locations.insert(num);
|
||||
num += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (DEEPDEBUG) std::cerr << " [Live] Starting live variable dataflow analysis...\n";
|
||||
std::map<const MachineBasicBlock*, std::set<unsigned>> live_in, live_out;
|
||||
bool changed = true;
|
||||
int df_iter = 0;
|
||||
while(changed) {
|
||||
changed = false;
|
||||
df_iter++;
|
||||
std::vector<MachineBasicBlock*> reversed_blocks = linear_order_blocks;
|
||||
std::reverse(reversed_blocks.begin(), reversed_blocks.end());
|
||||
for(auto* mbb : reversed_blocks) {
|
||||
std::set<unsigned> old_live_in = live_in[mbb];
|
||||
std::set<unsigned> current_live_out;
|
||||
for (auto* succ : mbb->successors) current_live_out.insert(live_in[succ].begin(), live_in[succ].end());
|
||||
std::set<unsigned> use, def;
|
||||
std::set<unsigned> temp_live = current_live_out;
|
||||
auto& instrs = mbb->getInstructions();
|
||||
for (auto it = instrs.rbegin(); it != instrs.rend(); ++it) {
|
||||
use.clear(); def.clear();
|
||||
getInstrUseDef(it->get(), use, def);
|
||||
for (unsigned vreg : def) temp_live.erase(vreg);
|
||||
for (unsigned vreg : use) temp_live.insert(vreg);
|
||||
}
|
||||
if (live_in[mbb] != temp_live || live_out[mbb] != current_live_out) {
|
||||
changed = true;
|
||||
live_in[mbb] = temp_live;
|
||||
live_out[mbb] = current_live_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DEEPDEBUG) std::cerr << " [Live] Dataflow analysis converged after " << df_iter << " iterations.\n";
|
||||
if (DEEPERDEBUG) {
|
||||
std::cerr << " [Live-Debug] Live-in sets:\n";
|
||||
for (auto* mbb : linear_order_blocks) std::cerr << " " << mbb->getName() << ": " << vregSetToString(live_in[mbb]) << "\n";
|
||||
std::cerr << " [Live-Debug] Live-out sets:\n";
|
||||
for (auto* mbb : linear_order_blocks) std::cerr << " " << mbb->getName() << ": " << vregSetToString(live_out[mbb]) << "\n";
|
||||
}
|
||||
|
||||
if (DEEPDEBUG) std::cerr << " [Live] Building precise intervals...\n";
|
||||
std::map<unsigned, int> first_def, last_use;
|
||||
for (auto* mbb : linear_order_blocks) {
|
||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||
int instr_num = instr_numbering.at(instr_ptr.get());
|
||||
std::set<unsigned> use, def;
|
||||
getInstrUseDef(instr_ptr.get(), use, def);
|
||||
for (unsigned vreg : def) if (first_def.find(vreg) == first_def.end()) first_def[vreg] = instr_num;
|
||||
for (unsigned vreg : use) last_use[vreg] = instr_num;
|
||||
}
|
||||
}
|
||||
if (DEEPERDEBUG) {
|
||||
std::cerr << " [Live-Debug] First def points:\n";
|
||||
for (auto const& [vreg, pos] : first_def) std::cerr << " %v" << vreg << ": " << pos << "\n";
|
||||
std::cerr << " [Live-Debug] Last use points:\n";
|
||||
for (auto const& [vreg, pos] : last_use) std::cerr << " %v" << vreg << ": " << pos << "\n";
|
||||
}
|
||||
|
||||
for (auto const& [vreg, start] : first_def) {
|
||||
live_intervals.emplace(vreg, LiveInterval(vreg));
|
||||
auto& interval = live_intervals.at(vreg);
|
||||
interval.start = start;
|
||||
interval.end = last_use.count(vreg) ? last_use.at(vreg) : start;
|
||||
}
|
||||
|
||||
for (auto const& [mbb, live_set] : live_out) {
|
||||
if (mbb->getInstructions().empty()) continue;
|
||||
int block_end_num = instr_numbering.at(mbb->getInstructions().back().get());
|
||||
for (unsigned vreg : live_set) {
|
||||
if (live_intervals.count(vreg)) {
|
||||
if (DEEPERDEBUG && live_intervals.at(vreg).end < block_end_num) {
|
||||
std::cerr << " [Live-Debug] Extending interval for %v" << vreg << " from " << live_intervals.at(vreg).end << " to " << block_end_num << " due to live_out of " << mbb->getName() << "\n";
|
||||
}
|
||||
live_intervals.at(vreg).end = std::max(live_intervals.at(vreg).end, block_end_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& pair : live_intervals) {
|
||||
auto& interval = pair.second;
|
||||
auto it = call_locations.lower_bound(interval.start);
|
||||
if (it != call_locations.end() && *it < interval.end) interval.crosses_call = true;
|
||||
}
|
||||
|
||||
for (auto& pair : live_intervals) unhandled.push_back(&pair.second);
|
||||
std::sort(unhandled.begin(), unhandled.end(), [](const LiveInterval* a, const LiveInterval* b){ return a->start < b->start; });
|
||||
|
||||
if (DEBUG) {
|
||||
std::cerr << "[LSRA-Live] Finished. Total intervals: " << unhandled.size() << "\n";
|
||||
if (DEEPDEBUG) {
|
||||
std::cerr << " [Live] Computed Intervals (vreg: [start, end]):\n";
|
||||
for(const auto* interval : unhandled) {
|
||||
std::cerr << " %v" << interval->vreg << ": [" << interval->start << ", " << interval->end << "]"
|
||||
<< (interval->crosses_call ? " (crosses call)" : "") << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ================== 新增的调试代码 ==================
|
||||
// 检查活性分析找到的vreg与指令扫描找到的vreg是否一致
|
||||
if (DEEPERDEBUG) {
|
||||
// 修正:将 std.set 修改为 std::set
|
||||
std::set<unsigned> vregs_from_liveness;
|
||||
for (const auto& pair : live_intervals) {
|
||||
vregs_from_liveness.insert(pair.first);
|
||||
}
|
||||
|
||||
std::set<unsigned> vregs_from_instr_scan;
|
||||
for (auto* mbb : linear_order_blocks) {
|
||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||
std::set<unsigned> use, def;
|
||||
getInstrUseDef(instr_ptr.get(), use, def);
|
||||
vregs_from_instr_scan.insert(use.begin(), use.end());
|
||||
vregs_from_instr_scan.insert(def.begin(), def.end());
|
||||
}
|
||||
}
|
||||
|
||||
std::cerr << " [Live-Debug] VReg Consistency Check:\n";
|
||||
std::cerr << " VRegs found by Liveness Analysis: " << vregs_from_liveness.size() << "\n";
|
||||
std::cerr << " VRegs found by getInstrUseDef Scan: " << vregs_from_instr_scan.size() << "\n";
|
||||
|
||||
// 修正:将 std.set 修改为 std::set
|
||||
std::set<unsigned> diff;
|
||||
std::set_difference(vregs_from_liveness.begin(), vregs_from_liveness.end(),
|
||||
vregs_from_instr_scan.begin(), vregs_from_instr_scan.end(),
|
||||
std::inserter(diff, diff.begin()));
|
||||
|
||||
if (!diff.empty()) {
|
||||
std::cerr << " !!!!!! [Live-Debug] DISCREPANCY DETECTED !!!!!!\n";
|
||||
std::cerr << " The following vregs were found by liveness but NOT by getInstrUseDef scan:\n";
|
||||
std::cerr << " " << vregSetToString(diff) << "\n";
|
||||
} else {
|
||||
std::cerr << " [Live-Debug] VReg sets are consistent.\n";
|
||||
}
|
||||
}
|
||||
// ======================================================
|
||||
}
|
||||
|
||||
bool RISCv64LinearScan::linearScan() {
|
||||
// ================== 终极保底策略 (新逻辑) ==================
|
||||
// 当此标志位为true时,我们进入最暴力的溢出模式。
|
||||
if (conservative_spill_mode) {
|
||||
if (DEBUG) std::cerr << "[LSRA-Scan-Panic] In Conservative Mode. Spilling all unhandled vregs.\n";
|
||||
|
||||
// 1. 清空溢出列表,准备重新计算
|
||||
spilled_vregs.clear();
|
||||
|
||||
// 2. 遍历所有计算出的活性区间
|
||||
for (auto& pair : live_intervals) {
|
||||
// 3. 如果一个vreg不是ABI规定的寄存器,就必须溢出
|
||||
if (abi_vreg_map.find(pair.first) == abi_vreg_map.end()) {
|
||||
spilled_vregs.insert(pair.first);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 只要有任何vreg被标记为溢出,就返回true以触发最终的rewriteProgram。
|
||||
// 下一轮迭代时,由于所有vreg都已被重写,将不再有新的溢出,保证收敛。
|
||||
return !spilled_vregs.empty();
|
||||
}
|
||||
// ==========================================================
|
||||
|
||||
|
||||
// ================== 常规线性扫描逻辑 (您已有的代码) ==================
|
||||
// 只有在非保守模式下才会执行以下代码
|
||||
if (DEBUG) std::cerr << "[LSRA-Scan] Starting main linear scan algorithm.\n";
|
||||
active.clear();
|
||||
spilled_vregs.clear();
|
||||
vreg_to_preg_map.clear();
|
||||
|
||||
std::set<PhysicalReg> free_caller_int_regs, free_callee_int_regs;
|
||||
std::set<PhysicalReg> free_caller_fp_regs, free_callee_fp_regs;
|
||||
|
||||
for (auto preg : allocable_int_regs) {
|
||||
if (isCalleeSaved(preg)) free_callee_int_regs.insert(preg); else free_caller_int_regs.insert(preg);
|
||||
}
|
||||
for (auto preg : allocable_fp_regs) {
|
||||
if (isCalleeSaved(preg)) free_callee_fp_regs.insert(preg); else free_caller_fp_regs.insert(preg);
|
||||
}
|
||||
|
||||
if (DEEPDEBUG) {
|
||||
std::cerr << " [Scan] Initial free regs:\n";
|
||||
std::cerr << " Caller-Saved Int: " << pregSetToString(free_caller_int_regs) << "\n";
|
||||
std::cerr << " Callee-Saved Int: " << pregSetToString(free_callee_int_regs) << "\n";
|
||||
}
|
||||
|
||||
vreg_to_preg_map.insert(abi_vreg_map.begin(), abi_vreg_map.end());
|
||||
std::vector<LiveInterval*> normal_unhandled;
|
||||
for(LiveInterval* interval : unhandled) {
|
||||
if(abi_vreg_map.count(interval->vreg)) {
|
||||
active.push_back(interval);
|
||||
PhysicalReg preg = abi_vreg_map.at(interval->vreg);
|
||||
if (isFPVReg(interval->vreg)) {
|
||||
if(isCalleeSaved(preg)) free_callee_fp_regs.erase(preg); else free_caller_fp_regs.erase(preg);
|
||||
} else {
|
||||
if(isCalleeSaved(preg)) free_callee_int_regs.erase(preg); else free_caller_int_regs.erase(preg);
|
||||
}
|
||||
} else {
|
||||
normal_unhandled.push_back(interval);
|
||||
}
|
||||
}
|
||||
unhandled = normal_unhandled;
|
||||
std::sort(active.begin(), active.end(), [](const LiveInterval* a, const LiveInterval* b){ return a->end < b->end; });
|
||||
|
||||
for (LiveInterval* current : unhandled) {
|
||||
if (DEEPDEBUG) std::cerr << "\n [Scan] Processing interval %v" << current->vreg << " [" << current->start << ", " << current->end << "]\n";
|
||||
|
||||
std::vector<LiveInterval*> new_active;
|
||||
for (LiveInterval* active_interval : active) {
|
||||
if (active_interval->end < current->start) {
|
||||
PhysicalReg preg = vreg_to_preg_map.at(active_interval->vreg);
|
||||
if (DEEPDEBUG) std::cerr << " [Scan] Expiring interval %v" << active_interval->vreg << ", freeing " << pregToString(preg) << "\n";
|
||||
if (isFPVReg(active_interval->vreg)) {
|
||||
if(isCalleeSaved(preg)) free_callee_fp_regs.insert(preg); else free_caller_fp_regs.insert(preg);
|
||||
} else {
|
||||
if(isCalleeSaved(preg)) free_callee_int_regs.insert(preg); else free_caller_int_regs.insert(preg);
|
||||
}
|
||||
} else {
|
||||
new_active.push_back(active_interval);
|
||||
}
|
||||
}
|
||||
active = new_active;
|
||||
|
||||
bool is_fp = isFPVReg(current->vreg);
|
||||
auto& free_caller = is_fp ? free_caller_fp_regs : free_caller_int_regs;
|
||||
auto& free_callee = is_fp ? free_callee_fp_regs : free_callee_int_regs;
|
||||
PhysicalReg allocated_preg = PhysicalReg::INVALID;
|
||||
|
||||
if (current->crosses_call) {
|
||||
if (!free_callee.empty()) {
|
||||
allocated_preg = *free_callee.begin();
|
||||
free_callee.erase(allocated_preg);
|
||||
}
|
||||
} else {
|
||||
if (!free_caller.empty()) {
|
||||
allocated_preg = *free_caller.begin();
|
||||
free_caller.erase(allocated_preg);
|
||||
} else if (!free_callee.empty()) {
|
||||
allocated_preg = *free_callee.begin();
|
||||
free_callee.erase(allocated_preg);
|
||||
}
|
||||
}
|
||||
|
||||
if (allocated_preg != PhysicalReg::INVALID) {
|
||||
if (DEEPDEBUG) std::cerr << " [Scan] Allocated " << pregToString(allocated_preg) << " to %v" << current->vreg << "\n";
|
||||
vreg_to_preg_map[current->vreg] = allocated_preg;
|
||||
active.push_back(current);
|
||||
std::sort(active.begin(), active.end(), [](const LiveInterval* a, const LiveInterval* b){ return a->end < b->end; });
|
||||
} else {
|
||||
if (DEEPDEBUG) std::cerr << " [Scan] No free registers for %v" << current->vreg << ". Spilling...\n";
|
||||
spillAtInterval(current);
|
||||
}
|
||||
}
|
||||
return !spilled_vregs.empty();
|
||||
}
|
||||
|
||||
void RISCv64LinearScan::spillAtInterval(LiveInterval* current) {
|
||||
// 保持您的原始逻辑
|
||||
LiveInterval* spill_candidate = nullptr;
|
||||
if (!active.empty()) {
|
||||
spill_candidate = active.back();
|
||||
}
|
||||
|
||||
if (DEEPERDEBUG) {
|
||||
std::cerr << " [Spill-Debug] Spill decision for current=%v" << current->vreg << "[" << current->start << "," << current->end << "]\n";
|
||||
std::cerr << " [Spill-Debug] Active intervals (sorted by end point):\n";
|
||||
for (const auto* i : active) {
|
||||
std::cerr << " %v" << i->vreg << "[" << i->start << "," << i->end << "] in " << pregToString(vreg_to_preg_map[i->vreg]) << "\n";
|
||||
}
|
||||
if(spill_candidate) {
|
||||
std::cerr << " [Spill-Debug] Candidate is %v" << spill_candidate->vreg << ". Its end is " << spill_candidate->end << ", current's end is " << current->end << "\n";
|
||||
} else {
|
||||
std::cerr << " [Spill-Debug] No active candidate.\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (spill_candidate && spill_candidate->end > current->end) {
|
||||
if (DEEPDEBUG) std::cerr << " [Spill] Decision: Spilling active %v" << spill_candidate->vreg << ".\n";
|
||||
PhysicalReg preg = vreg_to_preg_map.at(spill_candidate->vreg);
|
||||
vreg_to_preg_map.erase(spill_candidate->vreg); // 确保移除旧映射
|
||||
vreg_to_preg_map[current->vreg] = preg;
|
||||
active.pop_back();
|
||||
active.push_back(current);
|
||||
std::sort(active.begin(), active.end(), [](const LiveInterval* a, const LiveInterval* b){ return a->end < b->end; });
|
||||
spilled_vregs.insert(spill_candidate->vreg);
|
||||
} else {
|
||||
if (DEEPDEBUG) std::cerr << " [Spill] Decision: Spilling current %v" << current->vreg << ".\n";
|
||||
spilled_vregs.insert(current->vreg);
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64LinearScan::rewriteProgram() {
|
||||
if (DEBUG) {
|
||||
std::cerr << "[LSRA-Rewrite] Starting program rewrite. Spilled vregs: " << vregSetToString(spilled_vregs) << "\n";
|
||||
}
|
||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||
int spill_current_offset = frame_info.locals_end_offset - frame_info.spill_size;
|
||||
|
||||
for (unsigned vreg : spilled_vregs) {
|
||||
// 保持您的原始逻辑
|
||||
if (frame_info.spill_offsets.count(vreg)) continue;
|
||||
|
||||
Type* type = vreg_type_map.count(vreg) ? vreg_type_map.at(vreg) : Type::getIntType();
|
||||
int size = isFPVReg(vreg) ? 4 : (type->isPointer() ? 8 : 4);
|
||||
spill_current_offset -= size;
|
||||
spill_current_offset = (spill_current_offset & ~7);
|
||||
frame_info.spill_offsets[vreg] = spill_current_offset;
|
||||
if (DEEPDEBUG) std::cerr << " [Rewrite] Assigned new stack offset " << frame_info.spill_offsets.at(vreg) << " to spilled %v" << vreg << "\n";
|
||||
}
|
||||
frame_info.spill_size = -(spill_current_offset - frame_info.locals_end_offset);
|
||||
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
auto& instrs = mbb->getInstructions();
|
||||
std::vector<std::unique_ptr<MachineInstr>> new_instrs;
|
||||
if (DEEPERDEBUG) std::cerr << " [Rewrite] Processing block " << mbb->getName() << "\n";
|
||||
|
||||
for (auto it = instrs.begin(); it != instrs.end(); ++it) {
|
||||
auto& instr = *it;
|
||||
std::set<unsigned> use_vregs, def_vregs;
|
||||
getInstrUseDef(instr.get(), use_vregs, def_vregs);
|
||||
|
||||
if (conservative_spill_mode) {
|
||||
// ================== 紧急模式重写逻辑 ==================
|
||||
// 直接使用物理寄存器 t4 (SPILL_TEMP_REG) 进行加载/存储
|
||||
|
||||
// 为调试日志准备一个指令打印机
|
||||
auto printer = DEEPERDEBUG ? std::make_unique<RISCv64AsmPrinter>(MFunc) : nullptr;
|
||||
auto original_instr_str_for_log = DEEPERDEBUG ? printer->formatInstr(instr.get()) : "";
|
||||
bool modified = false;
|
||||
|
||||
for (unsigned old_vreg : use_vregs) {
|
||||
if (spilled_vregs.count(old_vreg)) {
|
||||
modified = true;
|
||||
Type* type = vreg_type_map.at(old_vreg);
|
||||
RVOpcodes load_op = isFPVReg(old_vreg) ? RVOpcodes::FLW : (type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW);
|
||||
auto load = std::make_unique<MachineInstr>(load_op);
|
||||
// 直接加载到保留的物理寄存器
|
||||
load->addOperand(std::make_unique<RegOperand>(SPILL_TEMP_REG));
|
||||
load->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(old_vreg))));
|
||||
|
||||
if (DEEPERDEBUG) {
|
||||
std::cerr << " [Rewrite-Panic] Inserting LOAD for use of %v" << old_vreg
|
||||
<< " into " << pregToString(SPILL_TEMP_REG)
|
||||
<< " before: " << original_instr_str_for_log << "\n";
|
||||
}
|
||||
new_instrs.push_back(std::move(load));
|
||||
|
||||
// 替换指令中的操作数
|
||||
instr->replaceVRegWithPReg(old_vreg, SPILL_TEMP_REG);
|
||||
}
|
||||
}
|
||||
|
||||
// 在处理 def 之前,先替换定义自身的 vreg
|
||||
for (unsigned old_vreg : def_vregs) {
|
||||
if (spilled_vregs.count(old_vreg)) {
|
||||
modified = true;
|
||||
instr->replaceVRegWithPReg(old_vreg, SPILL_TEMP_REG);
|
||||
}
|
||||
}
|
||||
|
||||
// 将原始指令(可能已被修改)放入新列表
|
||||
new_instrs.push_back(std::move(instr));
|
||||
if (DEEPERDEBUG && modified) {
|
||||
std::cerr << " [Rewrite-Panic] Original: " << original_instr_str_for_log
|
||||
<< " -> Rewritten: " << printer->formatInstr(new_instrs.back().get()) << "\n";
|
||||
}
|
||||
|
||||
for (unsigned old_vreg : def_vregs) {
|
||||
if (spilled_vregs.count(old_vreg)) {
|
||||
// 指令本身已经被修改为定义到 SPILL_TEMP_REG,现在从它存回内存
|
||||
Type* type = vreg_type_map.at(old_vreg);
|
||||
RVOpcodes store_op = isFPVReg(old_vreg) ? RVOpcodes::FSW : (type->isPointer() ? RVOpcodes::SD : RVOpcodes::SW);
|
||||
auto store = std::make_unique<MachineInstr>(store_op);
|
||||
store->addOperand(std::make_unique<RegOperand>(SPILL_TEMP_REG));
|
||||
store->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(old_vreg))));
|
||||
if (DEEPERDEBUG) {
|
||||
std::cerr << " [Rewrite-Panic] Inserting STORE for def of %v" << old_vreg
|
||||
<< " from " << pregToString(SPILL_TEMP_REG) << " after original instr.\n";
|
||||
}
|
||||
new_instrs.push_back(std::move(store));
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// ================== 常规模式重写逻辑 (您的原始代码) ==================
|
||||
std::map<unsigned, unsigned> use_remap, def_remap;
|
||||
for (unsigned old_vreg : use_vregs) {
|
||||
if (spilled_vregs.count(old_vreg) && use_remap.find(old_vreg) == use_remap.end()) {
|
||||
Type* type = vreg_type_map.at(old_vreg);
|
||||
unsigned new_temp_vreg = ISel->getNewVReg(type);
|
||||
use_remap[old_vreg] = new_temp_vreg;
|
||||
RVOpcodes load_op = isFPVReg(old_vreg) ? RVOpcodes::FLW : (type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW);
|
||||
auto load = std::make_unique<MachineInstr>(load_op);
|
||||
load->addOperand(std::make_unique<RegOperand>(new_temp_vreg));
|
||||
load->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(old_vreg))));
|
||||
if (DEEPERDEBUG) {
|
||||
RISCv64AsmPrinter printer(MFunc);
|
||||
std::cerr << " [Rewrite] Inserting LOAD for use of %v" << old_vreg << " into new %v" << new_temp_vreg << " before: " << printer.formatInstr(instr.get()) << "\n";
|
||||
}
|
||||
new_instrs.push_back(std::move(load));
|
||||
}
|
||||
}
|
||||
for (unsigned old_vreg : def_vregs) {
|
||||
if (spilled_vregs.count(old_vreg) && def_remap.find(old_vreg) == def_remap.end()) {
|
||||
Type* type = vreg_type_map.at(old_vreg);
|
||||
unsigned new_temp_vreg = ISel->getNewVReg(type);
|
||||
def_remap[old_vreg] = new_temp_vreg;
|
||||
}
|
||||
}
|
||||
auto original_instr_str_for_log = DEEPERDEBUG ? RISCv64AsmPrinter(MFunc).formatInstr(instr.get()) : "";
|
||||
instr->remapVRegs(use_remap, def_remap);
|
||||
new_instrs.push_back(std::move(instr));
|
||||
if (DEEPERDEBUG && (!use_remap.empty() || !def_remap.empty())) std::cerr << " [Rewrite] Original: " << original_instr_str_for_log << " -> Rewritten: " << RISCv64AsmPrinter(MFunc).formatInstr(new_instrs.back().get()) << "\n";
|
||||
for(const auto& pair : def_remap) {
|
||||
unsigned old_vreg = pair.first;
|
||||
unsigned new_temp_vreg = pair.second;
|
||||
Type* type = vreg_type_map.at(old_vreg);
|
||||
RVOpcodes store_op = isFPVReg(old_vreg) ? RVOpcodes::FSW : (type->isPointer() ? RVOpcodes::SD : RVOpcodes::SW);
|
||||
auto store = std::make_unique<MachineInstr>(store_op);
|
||||
store->addOperand(std::make_unique<RegOperand>(new_temp_vreg));
|
||||
store->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(old_vreg))));
|
||||
if (DEEPERDEBUG) std::cerr << " [Rewrite] Inserting STORE for def of %v" << old_vreg << " from new %v" << new_temp_vreg << " after original instr.\n";
|
||||
new_instrs.push_back(std::move(store));
|
||||
}
|
||||
}
|
||||
}
|
||||
instrs = std::move(new_instrs);
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64LinearScan::applyAllocation() {
|
||||
if (DEBUG) std::cerr << "[LSRA-Apply] Applying final vreg->preg mapping.\n";
|
||||
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 (vreg_to_preg_map.count(vreg)) {
|
||||
reg_op->setPReg(vreg_to_preg_map.at(vreg));
|
||||
} else {
|
||||
std::cerr << "ERROR: Uncolored virtual register %v" << vreg << " found during applyAllocation! in func " << MFunc->getName() << "\n";
|
||||
// Forcing an error is better than silent failure.
|
||||
// reg_op->setPReg(PhysicalReg::T5);
|
||||
}
|
||||
}
|
||||
} else if (op_ptr->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto mem_op = static_cast<MemOperand*>(op_ptr.get());
|
||||
auto reg_op = mem_op->getBase();
|
||||
if (reg_op->isVirtual()) {
|
||||
unsigned vreg = reg_op->getVRegNum();
|
||||
if (vreg_to_preg_map.count(vreg)) {
|
||||
reg_op->setPReg(vreg_to_preg_map.at(vreg));
|
||||
} else {
|
||||
std::cerr << "ERROR: Uncolored virtual register %v" << vreg << " in memory operand! in func " << MFunc->getName() << "\n";
|
||||
// reg_op->setPReg(PhysicalReg::T5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// void getInstrUseDef(const MachineInstr* instr, std::set<unsigned>& use, std::set<unsigned>& def) {
|
||||
// auto opcode = instr->getOpcode();
|
||||
// const auto& operands = instr->getOperands();
|
||||
|
||||
// auto get_vreg_id_if_virtual = [&](const MachineOperand* op, std::set<unsigned>& s) {
|
||||
// if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
// auto reg_op = static_cast<const RegOperand*>(op);
|
||||
// if (reg_op->isVirtual()) s.insert(reg_op->getVRegNum());
|
||||
// } else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
// auto mem_op = static_cast<const MemOperand*>(op);
|
||||
// auto reg_op = mem_op->getBase();
|
||||
// if (reg_op->isVirtual()) s.insert(reg_op->getVRegNum());
|
||||
// }
|
||||
// };
|
||||
|
||||
// if (op_info.count(opcode)) {
|
||||
// const auto& info = op_info.at(opcode);
|
||||
// for (int idx : info.first) if (idx < operands.size()) get_vreg_id_if_virtual(operands[idx].get(), def);
|
||||
// for (int idx : info.second) if (idx < operands.size()) get_vreg_id_if_virtual(operands[idx].get(), use);
|
||||
// for (const auto& op : operands) if (op->getKind() == MachineOperand::KIND_MEM) get_vreg_id_if_virtual(op.get(), use);
|
||||
// } else if (opcode == RVOpcodes::CALL) {
|
||||
// if (!operands.empty() && operands[0]->getKind() == MachineOperand::KIND_REG) get_vreg_id_if_virtual(operands[0].get(), def);
|
||||
// for (size_t i = 1; i < operands.size(); ++i) if (operands[i]->getKind() == MachineOperand::KIND_REG) get_vreg_id_if_virtual(operands[i].get(), use);
|
||||
// }
|
||||
// }
|
||||
|
||||
bool RISCv64LinearScan::isFPVReg(unsigned vreg) const {
|
||||
return vreg_type_map.count(vreg) && vreg_type_map.at(vreg)->isFloat();
|
||||
}
|
||||
|
||||
void RISCv64LinearScan::collectUsedCalleeSavedRegs() {
|
||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||
frame_info.used_callee_saved_regs.clear();
|
||||
|
||||
const auto& callee_saved_int = getCalleeSavedIntRegs();
|
||||
const auto& callee_saved_fp = getCalleeSavedFpRegs();
|
||||
std::set<PhysicalReg> callee_saved_set(callee_saved_int.begin(), callee_saved_int.end());
|
||||
callee_saved_set.insert(callee_saved_fp.begin(), callee_saved_fp.end());
|
||||
callee_saved_set.insert(PhysicalReg::S0);
|
||||
|
||||
for(const auto& pair : vreg_to_preg_map) {
|
||||
PhysicalReg preg = pair.second;
|
||||
if(callee_saved_set.count(preg)) {
|
||||
frame_info.used_callee_saved_regs.insert(preg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
1468
src/backend/RISCv64/RISCv64RegAlloc.cpp
Normal file
1468
src/backend/RISCv64/RISCv64RegAlloc.cpp
Normal file
File diff suppressed because it is too large
Load Diff
716
src/backend/RISCv64/RISCv64SimpleRegAlloc.cpp
Normal file
716
src/backend/RISCv64/RISCv64SimpleRegAlloc.cpp
Normal file
@ -0,0 +1,716 @@
|
||||
#include "RISCv64SimpleRegAlloc.h"
|
||||
#include "RISCv64AsmPrinter.h"
|
||||
#include "RISCv64Info.h"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
// 外部调试级别控制变量的定义
|
||||
// 假设这些变量在其他地方定义,例如主程序或一个通用的cpp文件
|
||||
extern int DEBUG;
|
||||
extern int DEEPDEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
RISCv64SimpleRegAlloc::RISCv64SimpleRegAlloc(MachineFunction* mfunc) : MFunc(mfunc), ISel(mfunc->getISel()) {
|
||||
// 1. 初始化可分配的整数寄存器池
|
||||
// T5 被大立即数传送逻辑保留
|
||||
// T2, T3, T4 被本分配器保留为专用的溢出/临时寄存器
|
||||
allocable_int_regs = {
|
||||
PhysicalReg::T0, PhysicalReg::T1, /* T2,T3,T4,T5,T6 reserved */
|
||||
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3, PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7,
|
||||
PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3, PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
|
||||
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
|
||||
};
|
||||
|
||||
// 2. 初始化可分配的浮点寄存器池
|
||||
// F0, F1, F2 被本分配器保留为专用的溢出/临时寄存器
|
||||
allocable_fp_regs = {
|
||||
/* F0,F1,F2 reserved */ PhysicalReg::F3, PhysicalReg::F4, PhysicalReg::F5, PhysicalReg::F6, PhysicalReg::F7,
|
||||
PhysicalReg::F10, PhysicalReg::F11, PhysicalReg::F12, PhysicalReg::F13, PhysicalReg::F14, PhysicalReg::F15, PhysicalReg::F16, PhysicalReg::F17,
|
||||
PhysicalReg::F8, PhysicalReg::F9, 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,
|
||||
};
|
||||
|
||||
// 3. 映射所有物理寄存器到特殊的虚拟寄存器ID (保持不变)
|
||||
const unsigned offset = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID);
|
||||
for (unsigned i = 0; i < static_cast<unsigned>(PhysicalReg::INVALID); ++i) {
|
||||
auto preg = static_cast<PhysicalReg>(i);
|
||||
preg_to_vreg_id_map[preg] = offset + i;
|
||||
}
|
||||
}
|
||||
|
||||
// 寄存器分配的主入口点
|
||||
void RISCv64SimpleRegAlloc::run() {
|
||||
if (DEBUG) std::cerr << "===== Running Simple Graph Coloring Allocator for function: " << MFunc->getName() << " =====\n";
|
||||
|
||||
// 实例化一个AsmPrinter用于调试输出,避免重复创建
|
||||
RISCv64AsmPrinter printer(MFunc);
|
||||
printer.setStream(std::cerr);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cerr << "\n===== LLIR after VReg Unification =====\n";
|
||||
printer.run(std::cerr, true);
|
||||
std::cerr << "===== End of Unified LLIR =====\n\n";
|
||||
}
|
||||
|
||||
// 阶段 1: 处理函数调用约定(参数寄存器预着色)
|
||||
handleCallingConvention();
|
||||
if (DEBUG) {
|
||||
std::cerr << "--- After HandleCallingConvention ---\n";
|
||||
std::cerr << "Pre-colored vregs:\n";
|
||||
for (const auto& pair : color_map) {
|
||||
std::cerr << " %vreg" << pair.first << " -> " << printer.regToString(pair.second) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// 阶段 2: 活跃性分析
|
||||
analyzeLiveness();
|
||||
|
||||
// 阶段 3: 构建干扰图
|
||||
buildInterferenceGraph();
|
||||
|
||||
// 阶段 4: 图着色算法分配物理寄存器
|
||||
colorGraph();
|
||||
if (DEBUG) {
|
||||
std::cerr << "\n--- After GraphColoring ---\n";
|
||||
std::cerr << "Assigned colors:\n";
|
||||
for (const auto& pair : color_map) {
|
||||
std::cerr << " %vreg" << pair.first << " -> " << printer.regToString(pair.second) << "\n";
|
||||
}
|
||||
std::cerr << "Spilled vregs:\n";
|
||||
if (spilled_vregs.empty()) {
|
||||
std::cerr << " (None)\n";
|
||||
} else {
|
||||
for (unsigned vreg : spilled_vregs) {
|
||||
std::cerr << " %vreg" << vreg << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 阶段 5: 重写函数(插入溢出/填充代码,替换虚拟寄存器为物理寄存器)
|
||||
rewriteFunction();
|
||||
|
||||
// 将最终的寄存器分配结果保存到MachineFunction的帧信息中,供后续Pass使用
|
||||
MFunc->getFrameInfo().vreg_to_preg_map = this->color_map;
|
||||
|
||||
if (DEBUG) {
|
||||
std::cerr << "\n===== Final LLIR after Simple Register Allocation =====\n";
|
||||
printer.run(std::cerr, false); // 使用false来打印最终的物理寄存器
|
||||
std::cerr << "===== Finished Simple Graph Coloring Allocator =====\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief [新增] 虚拟寄存器统一预处理
|
||||
* 扫描函数,找到通过栈帧传递的参数,并将后续从该栈帧加载的VReg统一为原始的参数VReg。
|
||||
*/
|
||||
void RISCv64SimpleRegAlloc::unifyArgumentVRegs() {
|
||||
if (MFunc->getBlocks().size() < 2) return; // 至少需要入口和函数体两个块
|
||||
|
||||
std::map<int, unsigned> stack_slot_to_vreg; // 映射: <栈偏移, 原始参数vreg>
|
||||
MachineBasicBlock* entry_block = MFunc->getBlocks().front().get();
|
||||
|
||||
// 步骤 1: 扫描入口块,找到所有参数的“家(home)”在栈上的位置
|
||||
for (const auto& instr : entry_block->getInstructions()) {
|
||||
// 我们寻找 sw %vreg_arg, 0(%vreg_addr) 的模式
|
||||
if (instr->getOpcode() == RVOpcodes::SW || instr->getOpcode() == RVOpcodes::SD || instr->getOpcode() == RVOpcodes::FSW) {
|
||||
auto& operands = instr->getOperands();
|
||||
if (operands.size() == 2 && operands[0]->getKind() == MachineOperand::KIND_REG && operands[1]->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto src_reg_op = static_cast<RegOperand*>(operands[0].get());
|
||||
auto mem_op = static_cast<MemOperand*>(operands[1].get());
|
||||
unsigned addr_vreg = mem_op->getBase()->getVRegNum();
|
||||
|
||||
// 查找定义这个地址vreg的addi指令,以获取偏移量
|
||||
for (const auto& prev_instr : entry_block->getInstructions()) {
|
||||
if (prev_instr->getOpcode() == RVOpcodes::ADDI && prev_instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
|
||||
auto def_op = static_cast<RegOperand*>(prev_instr->getOperands().front().get());
|
||||
if (def_op->isVirtual() && def_op->getVRegNum() == addr_vreg) {
|
||||
int offset = static_cast<ImmOperand*>(prev_instr->getOperands()[2].get())->getValue();
|
||||
stack_slot_to_vreg[offset] = src_reg_op->getVRegNum();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stack_slot_to_vreg.empty()) return; // 没有找到参数存储,无需处理
|
||||
|
||||
// 步骤 2: 扫描函数体,构建本地vreg到参数vreg的重映射表
|
||||
std::map<unsigned, unsigned> vreg_remap; // 映射: <本地vreg, 原始参数vreg>
|
||||
MachineBasicBlock* body_block = MFunc->getBlocks()[1].get();
|
||||
|
||||
for (const auto& instr : body_block->getInstructions()) {
|
||||
if (instr->getOpcode() == RVOpcodes::LW || instr->getOpcode() == RVOpcodes::LD || instr->getOpcode() == RVOpcodes::FLW) {
|
||||
auto& operands = instr->getOperands();
|
||||
if (operands.size() == 2 && operands[0]->getKind() == MachineOperand::KIND_REG && operands[1]->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto dest_reg_op = static_cast<RegOperand*>(operands[0].get());
|
||||
auto mem_op = static_cast<MemOperand*>(operands[1].get());
|
||||
unsigned addr_vreg = mem_op->getBase()->getVRegNum();
|
||||
|
||||
// 同样地,查找定义地址的addi指令
|
||||
for (const auto& prev_instr : body_block->getInstructions()) {
|
||||
if (prev_instr->getOpcode() == RVOpcodes::ADDI && prev_instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
|
||||
auto def_op = static_cast<RegOperand*>(prev_instr->getOperands().front().get());
|
||||
if (def_op->isVirtual() && def_op->getVRegNum() == addr_vreg) {
|
||||
int offset = static_cast<ImmOperand*>(prev_instr->getOperands()[2].get())->getValue();
|
||||
if (stack_slot_to_vreg.count(offset)) {
|
||||
unsigned old_vreg = dest_reg_op->getVRegNum();
|
||||
unsigned new_vreg = stack_slot_to_vreg.at(offset);
|
||||
vreg_remap[old_vreg] = new_vreg;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vreg_remap.empty()) return;
|
||||
|
||||
// 步骤 3: 遍历所有指令,应用重映射
|
||||
// 定义一个lambda函数来替换vreg,避免代码重复
|
||||
auto replace_vreg_in_operand = [&](MachineOperand* op) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(op);
|
||||
if (reg_op->isVirtual() && vreg_remap.count(reg_op->getVRegNum())) {
|
||||
reg_op->setVRegNum(vreg_remap.at(reg_op->getVRegNum()));
|
||||
}
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto base_reg_op = static_cast<MemOperand*>(op)->getBase();
|
||||
if (base_reg_op->isVirtual() && vreg_remap.count(base_reg_op->getVRegNum())) {
|
||||
base_reg_op->setVRegNum(vreg_remap.at(base_reg_op->getVRegNum()));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
for (auto& instr : mbb->getInstructions()) {
|
||||
for (auto& op : instr->getOperands()) {
|
||||
replace_vreg_in_operand(op.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64SimpleRegAlloc::handleCallingConvention() {
|
||||
Function* F = MFunc->getFunc();
|
||||
if (!F) return;
|
||||
|
||||
// --- 1. 处理函数传入参数的预着色 ---
|
||||
int int_arg_idx = 0;
|
||||
int float_arg_idx = 0;
|
||||
|
||||
for (Argument* arg : F->getArguments()) {
|
||||
unsigned vreg = ISel->getVReg(arg);
|
||||
if (arg->getType()->isFloat()) {
|
||||
if (float_arg_idx < 8) { // fa0-fa7
|
||||
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + float_arg_idx);
|
||||
color_map[vreg] = preg;
|
||||
}
|
||||
float_arg_idx++;
|
||||
} else {
|
||||
if (int_arg_idx < 8) { // a0-a7
|
||||
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + int_arg_idx);
|
||||
color_map[vreg] = preg;
|
||||
}
|
||||
int_arg_idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64SimpleRegAlloc::analyzeLiveness() {
|
||||
if (DEBUG) std::cerr << "\n--- Starting Liveness Analysis ---\n";
|
||||
|
||||
// === 阶段 1: 预计算每个基本块的 use 和 def 集合 ===
|
||||
std::map<const MachineBasicBlock*, LiveSet> block_uses;
|
||||
std::map<const MachineBasicBlock*, LiveSet> block_defs;
|
||||
for (const auto& mbb_ptr : MFunc->getBlocks()) {
|
||||
const MachineBasicBlock* mbb = mbb_ptr.get();
|
||||
LiveSet uses, defs;
|
||||
for (const auto& instr_ptr : mbb->getInstructions()) {
|
||||
LiveSet instr_use, instr_def;
|
||||
getInstrUseDef_Liveness(instr_ptr.get(), instr_use, instr_def);
|
||||
// use[B] = use[B] U (instr_use - def[B])
|
||||
for (unsigned u : instr_use) {
|
||||
if (defs.find(u) == defs.end()) {
|
||||
uses.insert(u);
|
||||
}
|
||||
}
|
||||
// def[B] = def[B] U instr_def
|
||||
defs.insert(instr_def.begin(), instr_def.end());
|
||||
}
|
||||
block_uses[mbb] = uses;
|
||||
block_defs[mbb] = defs;
|
||||
}
|
||||
|
||||
// === 阶段 2: 在“块”粒度上进行迭代数据流分析,直到收敛 ===
|
||||
std::map<const MachineBasicBlock*, LiveSet> block_live_in;
|
||||
std::map<const MachineBasicBlock*, LiveSet> block_live_out;
|
||||
bool changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
// 逆序遍历基本块,加速收敛
|
||||
for (auto it = MFunc->getBlocks().rbegin(); it != MFunc->getBlocks().rend(); ++it) {
|
||||
const auto& mbb_ptr = *it;
|
||||
const MachineBasicBlock* mbb = mbb_ptr.get();
|
||||
|
||||
// 2.1 计算 live_out[B] = U_{S in succ(B)} live_in[S]
|
||||
LiveSet new_live_out;
|
||||
for (auto succ : mbb->successors) {
|
||||
new_live_out.insert(block_live_in[succ].begin(), block_live_in[succ].end());
|
||||
}
|
||||
|
||||
// 2.2 计算 live_in[B] = use[B] U (live_out[B] - def[B])
|
||||
LiveSet live_out_minus_def = new_live_out;
|
||||
for (unsigned d : block_defs.at(mbb)) {
|
||||
live_out_minus_def.erase(d);
|
||||
}
|
||||
LiveSet new_live_in = block_uses.at(mbb);
|
||||
new_live_in.insert(live_out_minus_def.begin(), live_out_minus_def.end());
|
||||
|
||||
// 2.3 检查是否达到不动点
|
||||
if (block_live_out[mbb] != new_live_out || block_live_in[mbb] != new_live_in) {
|
||||
changed = true;
|
||||
block_live_out[mbb] = new_live_out;
|
||||
block_live_in[mbb] = new_live_in;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// === 阶段 3: 进行一次指令粒度的遍历,填充最终的 live_in_map 和 live_out_map ===
|
||||
for (const auto& mbb_ptr : MFunc->getBlocks()) {
|
||||
const MachineBasicBlock* mbb = mbb_ptr.get();
|
||||
LiveSet live_out = block_live_out.at(mbb);
|
||||
|
||||
for (auto instr_it = mbb->getInstructions().rbegin(); instr_it != mbb->getInstructions().rend(); ++instr_it) {
|
||||
const MachineInstr* instr = instr_it->get();
|
||||
live_out_map[instr] = live_out;
|
||||
|
||||
LiveSet use, def;
|
||||
getInstrUseDef_Liveness(instr, use, def);
|
||||
|
||||
LiveSet live_in = use;
|
||||
LiveSet diff = live_out;
|
||||
for (auto vreg : def) {
|
||||
diff.erase(vreg);
|
||||
}
|
||||
live_in.insert(diff.begin(), diff.end());
|
||||
live_in_map[instr] = live_in;
|
||||
|
||||
// 更新 live_out,为块内的上一条指令做准备
|
||||
live_out = live_in;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64SimpleRegAlloc::buildInterferenceGraph() {
|
||||
if (DEBUG) std::cerr << "\n--- Starting Interference Graph Construction ---\n";
|
||||
RISCv64AsmPrinter printer(MFunc);
|
||||
printer.setStream(std::cerr);
|
||||
|
||||
// 1. 收集所有图中需要出现的节点 (所有虚拟寄存器和物理寄存器)
|
||||
std::set<unsigned> all_nodes;
|
||||
for (const auto& mbb : MFunc->getBlocks()) {
|
||||
for(const auto& instr : mbb->getInstructions()) {
|
||||
LiveSet use, def;
|
||||
getInstrUseDef_Liveness(instr.get(), use, def);
|
||||
all_nodes.insert(use.begin(), use.end());
|
||||
all_nodes.insert(def.begin(), def.end());
|
||||
}
|
||||
}
|
||||
// 确保所有物理寄存器节点也存在
|
||||
for (const auto& pair : preg_to_vreg_id_map) {
|
||||
all_nodes.insert(pair.second);
|
||||
}
|
||||
|
||||
// 2. 初始化干扰图邻接表
|
||||
for (unsigned vreg : all_nodes) { interference_graph[vreg] = {}; }
|
||||
|
||||
// 3. 遍历指令,添加冲突边
|
||||
for (const auto& mbb : MFunc->getBlocks()) {
|
||||
if (DEEPDEBUG) std::cerr << "--- Building Graph for Basic Block: " << mbb->getName() << " ---\n";
|
||||
for (const auto& instr_ptr : mbb->getInstructions()) {
|
||||
const MachineInstr* instr = instr_ptr.get();
|
||||
if (DEEPDEBUG) {
|
||||
std::cerr << " Instr: ";
|
||||
printer.printInstruction(const_cast<MachineInstr*>(instr), true);
|
||||
}
|
||||
|
||||
LiveSet def, use;
|
||||
getInstrUseDef_Liveness(instr, def, use); // 注意Use/Def顺序
|
||||
const LiveSet& live_out = live_out_map.at(instr);
|
||||
|
||||
if (DEEPDEBUG) {
|
||||
printLiveSet(use, "Use ", std::cerr, printer);
|
||||
printLiveSet(def, "Def ", std::cerr, printer);
|
||||
printLiveSet(live_out, "Live_Out", std::cerr, printer);
|
||||
}
|
||||
|
||||
// 规则1: 指令的定义(def)与该指令之后的所有活跃变量(live_out)冲突
|
||||
for (unsigned d : def) {
|
||||
for (unsigned l : live_out) {
|
||||
if (d != l) {
|
||||
if (DEEPDEBUG && interference_graph.at(d).find(l) == interference_graph.at(d).end()) {
|
||||
std::cerr << " Edge (Def-LiveOut): " << regIdToString(d, printer) << " <-> " << regIdToString(l, printer) << "\n";
|
||||
}
|
||||
interference_graph[d].insert(l);
|
||||
interference_graph[l].insert(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 规则2: 对于非MV指令, def与use也冲突
|
||||
if (instr->getOpcode() != RVOpcodes::MV) {
|
||||
for (unsigned d : def) {
|
||||
for (unsigned u : use) {
|
||||
if (d != u) {
|
||||
if (DEEPDEBUG && interference_graph.at(d).find(u) == interference_graph.at(d).end()) {
|
||||
std::cerr << " Edge (Def-Use): " << regIdToString(d, printer) << " <-> " << regIdToString(u, printer) << "\n";
|
||||
}
|
||||
interference_graph[d].insert(u);
|
||||
interference_graph[u].insert(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 所有在某一点上同时活跃的寄存器(即live_out集合中的所有成员),
|
||||
// 它们之间必须两两互相干扰。
|
||||
std::vector<unsigned> live_out_vec(live_out.begin(), live_out.end());
|
||||
for (size_t i = 0; i < live_out_vec.size(); ++i) {
|
||||
for (size_t j = i + 1; j < live_out_vec.size(); ++j) {
|
||||
unsigned u = live_out_vec[i];
|
||||
unsigned v = live_out_vec[j];
|
||||
if (DEEPDEBUG && interference_graph[u].find(v) == interference_graph[u].end()) {
|
||||
std::cerr << " Edge (Live-Live): %vreg" << u << " <-> %vreg" << v << "\n";
|
||||
}
|
||||
interference_graph[u].insert(v);
|
||||
interference_graph[v].insert(u);
|
||||
}
|
||||
}
|
||||
|
||||
// 规则3: CALL指令会破坏所有调用者保存(caller-saved)寄存器
|
||||
if (instr->getOpcode() == RVOpcodes::CALL) {
|
||||
const auto& caller_saved_int = getCallerSavedIntRegs();
|
||||
const auto& caller_saved_fp = getCallerSavedFpRegs();
|
||||
|
||||
for (unsigned live_vreg : live_out) {
|
||||
auto [type, size] = getTypeAndSize(live_vreg);
|
||||
if (type == Type::kFloat) {
|
||||
for (PhysicalReg cs_reg : caller_saved_fp) {
|
||||
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg);
|
||||
if (live_vreg != cs_vreg_id) {
|
||||
interference_graph[live_vreg].insert(cs_vreg_id);
|
||||
interference_graph[cs_vreg_id].insert(live_vreg);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (PhysicalReg cs_reg : caller_saved_int) {
|
||||
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg);
|
||||
if (live_vreg != cs_vreg_id) {
|
||||
interference_graph[live_vreg].insert(cs_vreg_id);
|
||||
interference_graph[cs_vreg_id].insert(live_vreg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end if CALL
|
||||
if (DEEPDEBUG) std::cerr << " ----------------\n";
|
||||
} // end for instr
|
||||
} // end for mbb
|
||||
}
|
||||
|
||||
void RISCv64SimpleRegAlloc::colorGraph() {
|
||||
// 1. 收集所有需要着色的虚拟寄存器
|
||||
std::vector<unsigned> vregs_to_color;
|
||||
for (auto const& [vreg, neighbors] : interference_graph) {
|
||||
// 只为未预着色的、真正的虚拟寄存器进行着色
|
||||
if (color_map.find(vreg) == color_map.end() && vreg < static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID)) {
|
||||
vregs_to_color.push_back(vreg);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 按冲突度从高到低排序,进行贪心着色
|
||||
std::sort(vregs_to_color.begin(), vregs_to_color.end(), [&](unsigned a, unsigned b) {
|
||||
return interference_graph.at(a).size() > interference_graph.at(b).size();
|
||||
});
|
||||
|
||||
// 3. 遍历并着色
|
||||
for (unsigned vreg : vregs_to_color) {
|
||||
std::set<PhysicalReg> used_colors;
|
||||
// 收集所有邻居的颜色
|
||||
for (unsigned neighbor_id : interference_graph.at(vreg)) {
|
||||
// A. 邻居是已着色的vreg
|
||||
if (color_map.count(neighbor_id)) {
|
||||
used_colors.insert(color_map.at(neighbor_id));
|
||||
}
|
||||
// B. 邻居是物理寄存器本身
|
||||
else if (neighbor_id >= static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID)) {
|
||||
PhysicalReg neighbor_preg = static_cast<PhysicalReg>(neighbor_id - static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID));
|
||||
used_colors.insert(neighbor_preg);
|
||||
}
|
||||
}
|
||||
|
||||
// 根据vreg类型选择寄存器池
|
||||
auto [type, size] = getTypeAndSize(vreg);
|
||||
const auto& allocable_regs = (type == Type::kFloat) ? allocable_fp_regs : allocable_int_regs;
|
||||
|
||||
bool colored = false;
|
||||
for (PhysicalReg preg : allocable_regs) {
|
||||
if (used_colors.find(preg) == used_colors.end()) {
|
||||
color_map[vreg] = preg;
|
||||
colored = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!colored) {
|
||||
spilled_vregs.insert(vreg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64SimpleRegAlloc::rewriteFunction() {
|
||||
if (DEBUG) std::cerr << "\n--- Starting Function Rewrite (Spilling & Substitution) ---\n";
|
||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||
|
||||
// 步骤 1: 为所有溢出的vreg计算唯一的栈偏移量 (此部分逻辑正确,予以保留)
|
||||
int current_offset = frame_info.locals_end_offset;
|
||||
for (unsigned vreg : spilled_vregs) {
|
||||
if (frame_info.spill_offsets.count(vreg)) continue;
|
||||
auto [type, size] = getTypeAndSize(vreg);
|
||||
current_offset -= size;
|
||||
current_offset = current_offset & ~7;
|
||||
frame_info.spill_offsets[vreg] = current_offset;
|
||||
}
|
||||
frame_info.spill_size = -(current_offset - frame_info.locals_end_offset);
|
||||
|
||||
// 步骤 2: 遍历所有指令,对CALL指令做简化处理
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
std::vector<std::unique_ptr<MachineInstr>> new_instructions;
|
||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||
|
||||
if (instr_ptr->getOpcode() != RVOpcodes::CALL) {
|
||||
std::vector<PhysicalReg> int_spill_pool = {PhysicalReg::T2, PhysicalReg::T3, PhysicalReg::T4, /*PhysicalReg::T5,*/ PhysicalReg::T6};
|
||||
std::vector<PhysicalReg> fp_spill_pool = {PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3};
|
||||
std::map<unsigned, PhysicalReg> vreg_to_preg_map_for_this_instr;
|
||||
LiveSet use, def;
|
||||
getInstrUseDef(instr_ptr.get(), use, def);
|
||||
LiveSet all_vregs_in_instr = use;
|
||||
all_vregs_in_instr.insert(def.begin(), def.end());
|
||||
for(unsigned vreg : all_vregs_in_instr) {
|
||||
if (spilled_vregs.count(vreg)) {
|
||||
auto [type, size] = getTypeAndSize(vreg);
|
||||
if (type == Type::kFloat) {
|
||||
assert(!fp_spill_pool.empty() && "FP spill pool exhausted for generic instruction!");
|
||||
vreg_to_preg_map_for_this_instr[vreg] = fp_spill_pool.front();
|
||||
fp_spill_pool.erase(fp_spill_pool.begin());
|
||||
} else {
|
||||
assert(!int_spill_pool.empty() && "Int spill pool exhausted for generic instruction!");
|
||||
vreg_to_preg_map_for_this_instr[vreg] = int_spill_pool.front();
|
||||
int_spill_pool.erase(int_spill_pool.begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
for (unsigned vreg : use) {
|
||||
if (spilled_vregs.count(vreg)) {
|
||||
PhysicalReg target_preg = vreg_to_preg_map_for_this_instr.at(vreg);
|
||||
auto [type, size] = getTypeAndSize(vreg);
|
||||
RVOpcodes load_op = (type == Type::kFloat) ? RVOpcodes::FLW : ((type == Type::kPointer) ? RVOpcodes::LD : RVOpcodes::LW);
|
||||
auto load = std::make_unique<MachineInstr>(load_op);
|
||||
load->addOperand(std::make_unique<RegOperand>(target_preg));
|
||||
load->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(vreg))
|
||||
));
|
||||
new_instructions.push_back(std::move(load));
|
||||
}
|
||||
}
|
||||
auto new_instr = std::make_unique<MachineInstr>(instr_ptr->getOpcode());
|
||||
for (const auto& op : instr_ptr->getOperands()) {
|
||||
const RegOperand* reg_op = nullptr;
|
||||
if (op->getKind() == MachineOperand::KIND_REG) reg_op = static_cast<const RegOperand*>(op.get());
|
||||
else if (op->getKind() == MachineOperand::KIND_MEM) reg_op = static_cast<const MemOperand*>(op.get())->getBase();
|
||||
if (reg_op) {
|
||||
PhysicalReg final_preg;
|
||||
if (reg_op->isVirtual()) {
|
||||
unsigned vreg = reg_op->getVRegNum();
|
||||
if (spilled_vregs.count(vreg)) {
|
||||
final_preg = vreg_to_preg_map_for_this_instr.at(vreg);
|
||||
} else {
|
||||
assert(color_map.count(vreg));
|
||||
final_preg = color_map.at(vreg);
|
||||
}
|
||||
} else {
|
||||
final_preg = reg_op->getPReg();
|
||||
}
|
||||
auto new_reg_op = std::make_unique<RegOperand>(final_preg);
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
new_instr->addOperand(std::move(new_reg_op));
|
||||
} else {
|
||||
auto mem_op = static_cast<const MemOperand*>(op.get());
|
||||
new_instr->addOperand(std::make_unique<MemOperand>(std::move(new_reg_op), std::make_unique<ImmOperand>(*mem_op->getOffset())));
|
||||
}
|
||||
} else {
|
||||
if(op->getKind() == MachineOperand::KIND_IMM) new_instr->addOperand(std::make_unique<ImmOperand>(*static_cast<const ImmOperand*>(op.get())));
|
||||
else if (op->getKind() == MachineOperand::KIND_LABEL) new_instr->addOperand(std::make_unique<LabelOperand>(*static_cast<const LabelOperand*>(op.get())));
|
||||
}
|
||||
}
|
||||
new_instructions.push_back(std::move(new_instr));
|
||||
for (unsigned vreg : def) {
|
||||
if (spilled_vregs.count(vreg)) {
|
||||
PhysicalReg src_preg = vreg_to_preg_map_for_this_instr.at(vreg);
|
||||
auto [type, size] = getTypeAndSize(vreg);
|
||||
RVOpcodes store_op = (type == Type::kFloat) ? RVOpcodes::FSW : ((type == Type::kPointer) ? RVOpcodes::SD : RVOpcodes::SW);
|
||||
auto store = std::make_unique<MachineInstr>(store_op);
|
||||
store->addOperand(std::make_unique<RegOperand>(src_preg));
|
||||
store->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(vreg))
|
||||
));
|
||||
new_instructions.push_back(std::move(store));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// --- 对于CALL指令,只处理其自身和返回值,不再处理参数 ---
|
||||
const PhysicalReg INT_TEMP_REG = PhysicalReg::T6;
|
||||
const PhysicalReg FP_TEMP_REG = PhysicalReg::F7;
|
||||
|
||||
// 1. 克隆CALL指令本身,只保留标签操作数
|
||||
auto new_call = std::make_unique<MachineInstr>(RVOpcodes::CALL);
|
||||
for (const auto& op : instr_ptr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_LABEL) {
|
||||
new_call->addOperand(std::make_unique<LabelOperand>(*static_cast<const LabelOperand*>(op.get())));
|
||||
// 注意:只添加第一个标签,防止ISel的错误导致多个标签
|
||||
break;
|
||||
}
|
||||
}
|
||||
new_instructions.push_back(std::move(new_call));
|
||||
|
||||
// 2. 只处理返回值(def)的溢出和移动
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
if (!operands.empty() && operands.front()->getKind() == MachineOperand::KIND_REG) {
|
||||
unsigned def_vreg = static_cast<RegOperand*>(operands.front().get())->getVRegNum();
|
||||
auto [type, size] = getTypeAndSize(def_vreg);
|
||||
PhysicalReg result_reg_abi = type == Type::kFloat ? PhysicalReg::F10 : PhysicalReg::A0;
|
||||
|
||||
if (spilled_vregs.count(def_vreg)) {
|
||||
// 返回值被溢出:a0/fa0 -> temp -> 溢出槽
|
||||
PhysicalReg temp_reg = type == Type::kFloat ? FP_TEMP_REG : INT_TEMP_REG;
|
||||
RVOpcodes store_op = (type == Type::kFloat) ? RVOpcodes::FSW : ((type == Type::kPointer) ? RVOpcodes::SD : RVOpcodes::SW);
|
||||
|
||||
auto mv_from_abi = std::make_unique<MachineInstr>(type == Type::kFloat ? RVOpcodes::FMV_S : RVOpcodes::MV);
|
||||
mv_from_abi->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
mv_from_abi->addOperand(std::make_unique<RegOperand>(result_reg_abi));
|
||||
new_instructions.push_back(std::move(mv_from_abi));
|
||||
|
||||
auto store = std::make_unique<MachineInstr>(store_op);
|
||||
store->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||
store->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(def_vreg))
|
||||
));
|
||||
new_instructions.push_back(std::move(store));
|
||||
} else {
|
||||
// 返回值未溢出:a0/fa0 -> 已着色的物理寄存器
|
||||
auto mv_to_dest = std::make_unique<MachineInstr>(type == Type::kFloat ? RVOpcodes::FMV_S : RVOpcodes::MV);
|
||||
mv_to_dest->addOperand(std::make_unique<RegOperand>(color_map.at(def_vreg)));
|
||||
mv_to_dest->addOperand(std::make_unique<RegOperand>(result_reg_abi));
|
||||
new_instructions.push_back(std::move(mv_to_dest));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mbb->getInstructions() = std::move(new_instructions);
|
||||
}
|
||||
}
|
||||
|
||||
// --- 辅助函数实现 ---
|
||||
|
||||
void RISCv64SimpleRegAlloc::getInstrUseDef_Liveness(const MachineInstr* instr, LiveSet& use, LiveSet& def) {
|
||||
auto opcode = instr->getOpcode();
|
||||
const auto& operands = instr->getOperands();
|
||||
const unsigned offset = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID);
|
||||
|
||||
auto get_any_reg_id = [&](const MachineOperand* op) -> unsigned {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<const RegOperand*>(op);
|
||||
return reg_op->isVirtual() ? reg_op->getVRegNum() : (offset + static_cast<unsigned>(reg_op->getPReg()));
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto reg_op = static_cast<const MemOperand*>(op)->getBase();
|
||||
return reg_op->isVirtual() ? reg_op->getVRegNum() : (offset + static_cast<unsigned>(reg_op->getPReg()));
|
||||
}
|
||||
return (unsigned)-1;
|
||||
};
|
||||
|
||||
if (op_info.count(opcode)) {
|
||||
const auto& info = op_info.at(opcode);
|
||||
for (int idx : info.first) if (idx < operands.size()) {
|
||||
unsigned reg_id = get_any_reg_id(operands[idx].get());
|
||||
if (reg_id != (unsigned)-1) def.insert(reg_id);
|
||||
}
|
||||
for (int idx : info.second) if (idx < operands.size()) {
|
||||
unsigned reg_id = get_any_reg_id(operands[idx].get());
|
||||
if (reg_id != (unsigned)-1) use.insert(reg_id);
|
||||
}
|
||||
for (const auto& op : operands) {
|
||||
if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
unsigned reg_id = get_any_reg_id(op.get());
|
||||
if (reg_id != (unsigned)-1) use.insert(reg_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (opcode == RVOpcodes::CALL) {
|
||||
if (!operands.empty() && operands[0]->getKind() == MachineOperand::KIND_REG) {
|
||||
def.insert(get_any_reg_id(operands[0].get()));
|
||||
}
|
||||
for (size_t i = 1; i < operands.size(); ++i) {
|
||||
if (operands[i]->getKind() == MachineOperand::KIND_REG) {
|
||||
use.insert(get_any_reg_id(operands[i].get()));
|
||||
}
|
||||
}
|
||||
for (auto preg : getCallerSavedIntRegs()) def.insert(offset + static_cast<unsigned>(preg));
|
||||
for (auto preg : getCallerSavedFpRegs()) def.insert(offset + static_cast<unsigned>(preg));
|
||||
def.insert(offset + static_cast<unsigned>(PhysicalReg::RA));
|
||||
}
|
||||
else if (opcode == RVOpcodes::RET) {
|
||||
use.insert(offset + static_cast<unsigned>(PhysicalReg::A0));
|
||||
use.insert(offset + static_cast<unsigned>(PhysicalReg::F10)); // fa0
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<Type::Kind, unsigned> RISCv64SimpleRegAlloc::getTypeAndSize(unsigned vreg) {
|
||||
const auto& vreg_type_map = ISel->getVRegTypeMap();
|
||||
if (vreg_type_map.count(vreg)) {
|
||||
Type* type = vreg_type_map.at(vreg);
|
||||
if (type->isFloat()) return {Type::kFloat, 4};
|
||||
if (type->isPointer()) return {Type::kPointer, 8};
|
||||
}
|
||||
// 默认或未知类型按32位整数处理
|
||||
return {Type::kInt, 4};
|
||||
}
|
||||
|
||||
std::string RISCv64SimpleRegAlloc::regIdToString(unsigned id, const RISCv64AsmPrinter& printer) const {
|
||||
const unsigned offset = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID);
|
||||
if (id >= offset) {
|
||||
PhysicalReg reg = static_cast<PhysicalReg>(id - offset);
|
||||
return printer.regToString(reg);
|
||||
} else {
|
||||
return "%vreg" + std::to_string(id);
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64SimpleRegAlloc::printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os, const RISCv64AsmPrinter& printer) {
|
||||
os << " " << name << " (" << s.size() << "): { ";
|
||||
for (unsigned vreg : s) {
|
||||
os << regIdToString(vreg, printer) << " ";
|
||||
}
|
||||
os << "}\n";
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
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,52 +0,0 @@
|
||||
#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::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);
|
||||
private:
|
||||
Function* AssociatedFunction;
|
||||
std::map<BasicBlock*, std::set<BasicBlock*>> Dominators;
|
||||
std::map<BasicBlock*, BasicBlock*> IDoms;
|
||||
std::map<BasicBlock*, std::set<BasicBlock*>> DominanceFrontiers;
|
||||
};
|
||||
|
||||
|
||||
// 支配树分析遍
|
||||
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
|
||||
@ -1,75 +0,0 @@
|
||||
#ifndef RISCV64_REGALLOC_H
|
||||
#define RISCV64_REGALLOC_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "RISCv64ISel.h" // 包含 RISCv64ISel.h 以访问 ISel 和 Value 类型
|
||||
|
||||
extern int DEBUG;
|
||||
extern int DEEPDEBUG;
|
||||
|
||||
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);
|
||||
|
||||
// 辅助函数,处理调用约定
|
||||
void handleCallingConvention();
|
||||
|
||||
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;
|
||||
|
||||
// 存储vreg到IR Value*的反向映射
|
||||
// 这个map将在run()函数开始时被填充,并在rewriteFunction()中使用。
|
||||
std::map<unsigned, Value*> vreg_to_value_map;
|
||||
std::map<PhysicalReg, unsigned> preg_to_vreg_id_map; // 物理寄存器到特殊vreg ID的映射
|
||||
|
||||
// 用于计算类型大小的辅助函数
|
||||
unsigned getTypeSizeInBytes(Type* type);
|
||||
|
||||
// 辅助函数,用于打印集合
|
||||
static void printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os);
|
||||
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // RISCV64_REGALLOC_H
|
||||
@ -1,196 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "IR.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 稀疏条件常量传播类
|
||||
// Sparse Conditional Constant Propagation
|
||||
/*
|
||||
伪代码
|
||||
function SCCP_Optimization(Module):
|
||||
for each Function in Module:
|
||||
changed = true
|
||||
while changed:
|
||||
changed = false
|
||||
// 阶段1: 常量传播与折叠
|
||||
changed |= PropagateConstants(Function)
|
||||
// 阶段2: 控制流简化
|
||||
changed |= SimplifyControlFlow(Function)
|
||||
end while
|
||||
end for
|
||||
|
||||
function PropagateConstants(Function):
|
||||
// 初始化
|
||||
executableBlocks = {entryBlock}
|
||||
valueState = map<Value, State> // 值->状态映射
|
||||
instWorkList = Queue()
|
||||
edgeWorkList = Queue()
|
||||
|
||||
// 初始化工作列表
|
||||
for each inst in entryBlock:
|
||||
instWorkList.push(inst)
|
||||
|
||||
// 迭代处理
|
||||
while !instWorkList.empty() || !edgeWorkList.empty():
|
||||
// 处理指令工作列表
|
||||
while !instWorkList.empty():
|
||||
inst = instWorkList.pop()
|
||||
// 如果指令是可执行基本块中的
|
||||
if executableBlocks.contains(inst.parent):
|
||||
ProcessInstruction(inst)
|
||||
|
||||
// 处理边工作列表
|
||||
while !edgeWorkList.empty():
|
||||
edge = edgeWorkList.pop()
|
||||
ProcessEdge(edge)
|
||||
|
||||
// 应用常量替换
|
||||
for each inst in Function:
|
||||
if valueState[inst] == CONSTANT:
|
||||
ReplaceWithConstant(inst, valueState[inst].constant)
|
||||
changed = true
|
||||
|
||||
return changed
|
||||
|
||||
function ProcessInstruction(Instruction inst):
|
||||
switch inst.type:
|
||||
//二元操作
|
||||
case BINARY_OP:
|
||||
lhs = GetValueState(inst.operands[0])
|
||||
rhs = GetValueState(inst.operands[1])
|
||||
if lhs == CONSTANT && rhs == CONSTANT:
|
||||
newState = ComputeConstant(inst.op, lhs.value, rhs.value)
|
||||
UpdateState(inst, newState)
|
||||
else if lhs == BOTTOM || rhs == BOTTOM:
|
||||
UpdateState(inst, BOTTOM)
|
||||
//phi
|
||||
case PHI:
|
||||
mergedState = ⊤
|
||||
for each incoming in inst.incomings:
|
||||
// 检查每个输入的状态
|
||||
if executableBlocks.contains(incoming.block):
|
||||
incomingState = GetValueState(incoming.value)
|
||||
mergedState = Meet(mergedState, incomingState)
|
||||
UpdateState(inst, mergedState)
|
||||
// 条件分支
|
||||
case COND_BRANCH:
|
||||
cond = GetValueState(inst.condition)
|
||||
if cond == CONSTANT:
|
||||
// 判断条件分支
|
||||
if cond.value == true:
|
||||
AddEdgeToWorkList(inst.parent, inst.trueTarget)
|
||||
else:
|
||||
AddEdgeToWorkList(inst.parent, inst.falseTarget)
|
||||
else if cond == BOTTOM:
|
||||
AddEdgeToWorkList(inst.parent, inst.trueTarget)
|
||||
AddEdgeToWorkList(inst.parent, inst.falseTarget)
|
||||
|
||||
case UNCOND_BRANCH:
|
||||
AddEdgeToWorkList(inst.parent, inst.target)
|
||||
|
||||
// 其他指令处理...
|
||||
|
||||
function ProcessEdge(Edge edge):
|
||||
fromBB, toBB = edge
|
||||
if !executableBlocks.contains(toBB):
|
||||
executableBlocks.add(toBB)
|
||||
for each inst in toBB:
|
||||
if inst is PHI:
|
||||
instWorkList.push(inst)
|
||||
else:
|
||||
instWorkList.push(inst) // 非PHI指令
|
||||
|
||||
// 更新PHI节点的输入
|
||||
for each phi in toBB.phis:
|
||||
instWorkList.push(phi)
|
||||
|
||||
function SimplifyControlFlow(Function):
|
||||
changed = false
|
||||
// 标记可达基本块
|
||||
ReachableBBs = FindReachableBlocks(Function.entry)
|
||||
|
||||
// 删除不可达块
|
||||
for each bb in Function.blocks:
|
||||
if !ReachableBBs.contains(bb):
|
||||
RemoveDeadBlock(bb)
|
||||
changed = true
|
||||
|
||||
// 简化条件分支
|
||||
for each bb in Function.blocks:
|
||||
terminator = bb.terminator
|
||||
if terminator is COND_BRANCH:
|
||||
cond = GetValueState(terminator.condition)
|
||||
if cond == CONSTANT:
|
||||
SimplifyBranch(terminator, cond.value)
|
||||
changed = true
|
||||
|
||||
return changed
|
||||
|
||||
function RemoveDeadBlock(BasicBlock bb):
|
||||
// 1. 更新前驱块的分支指令
|
||||
for each pred in bb.predecessors:
|
||||
UpdateTerminator(pred, bb)
|
||||
|
||||
// 2. 更新后继块的PHI节点
|
||||
for each succ in bb.successors:
|
||||
RemovePhiIncoming(succ, bb)
|
||||
|
||||
// 3. 删除块内所有指令
|
||||
for each inst in bb.instructions:
|
||||
inst.remove()
|
||||
|
||||
// 4. 从函数中移除基本块
|
||||
Function.removeBlock(bb)
|
||||
|
||||
function Meet(State a, State b):
|
||||
if a == ⊤: return b
|
||||
if b == ⊤: return a
|
||||
if a == ⊥ || b == ⊥: return ⊥
|
||||
if a.value == b.value: return a
|
||||
return ⊥
|
||||
|
||||
function UpdateState(Value v, State newState):
|
||||
oldState = valueState.get(v, ⊤)
|
||||
if newState != oldState:
|
||||
valueState[v] = newState
|
||||
for each user in v.users:
|
||||
if user is Instruction:
|
||||
instWorkList.push(user)
|
||||
|
||||
*/
|
||||
|
||||
enum class LatticeValue {
|
||||
Top, // ⊤ (Unknown)
|
||||
Constant, // c (Constant)
|
||||
Bottom // ⊥ (Undefined / Varying)
|
||||
};
|
||||
// LatticeValue: 用于表示值的状态,Top表示未知,Constant表示常量,Bottom表示未定义或变化的值。
|
||||
// 这里的LatticeValue用于跟踪每个SSA值(变量、指令结果)的状态,
|
||||
// 以便在SCCP过程中进行常量传播和控制流简化。
|
||||
|
||||
//TODO: 下列数据结构考虑集成到类中,避免重命名问题
|
||||
static std::set<Instruction *> Worklist;
|
||||
static std::unordered_set<BasicBlock*> Executable_Blocks;
|
||||
static std::queue<std::pair<BasicBlock *, BasicBlock *> > Executable_Edges;
|
||||
static std::map<Value*, LatticeValue> valueState;
|
||||
|
||||
class SCCP {
|
||||
private:
|
||||
Module *pModule;
|
||||
|
||||
public:
|
||||
SCCP(Module *pMoudle) : pModule(pMoudle) {}
|
||||
|
||||
void run();
|
||||
bool PropagateConstants(Function *function);
|
||||
bool SimplifyControlFlow(Function *function);
|
||||
void ProcessInstruction(Instruction *inst);
|
||||
void ProcessEdge(const std::pair<BasicBlock *, BasicBlock *> &edge);
|
||||
void RemoveDeadBlock(BasicBlock *bb);
|
||||
void UpdateState(Value *v, LatticeValue newState);
|
||||
LatticeValue Meet(LatticeValue a, LatticeValue b);
|
||||
LatticeValue GetValueState(Value *v);
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
@ -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,33 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "IR.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 优化工具类,包含一些通用的优化方法
|
||||
// 这些方法可以在不同的优化 pass 中复用
|
||||
// 例如:删除use关系,判断是否是全局变量等
|
||||
class SysYIROptUtils{
|
||||
|
||||
public:
|
||||
// 仅仅删除use关系
|
||||
static void usedelete(Instruction *instr) {
|
||||
for (auto &use : instr->getOperands()) {
|
||||
Value* val = use->getValue();
|
||||
val->removeUse(use);
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否是全局变量
|
||||
static bool isGlobal(Value *val) {
|
||||
auto gval = dynamic_cast<GlobalValue *>(val);
|
||||
return gval != nullptr;
|
||||
}
|
||||
// 判断是否是数组
|
||||
static bool isArr(Value *val) {
|
||||
auto aval = dynamic_cast<AllocaInst *>(val);
|
||||
return aval != nullptr && aval->getNumDims() != 0;
|
||||
}
|
||||
};
|
||||
|
||||
}// namespace sysy
|
||||
@ -1,58 +0,0 @@
|
||||
// PassManager.h
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <typeindex> // For std::type_index
|
||||
#include <unordered_map>
|
||||
#include "SysYIRPass.h"
|
||||
#include "IR.h" // 假设你的IR.h定义了Module, Function等
|
||||
|
||||
namespace sysy {
|
||||
|
||||
class PassManager {
|
||||
public:
|
||||
PassManager() = default;
|
||||
|
||||
// 添加一个FunctionPass
|
||||
void addPass(std::unique_ptr<FunctionPass> pass) {
|
||||
functionPasses.push_back(std::move(pass));
|
||||
}
|
||||
|
||||
// 添加一个ModulePass
|
||||
void addPass(std::unique_ptr<ModulePass> pass) {
|
||||
modulePasses.push_back(std::move(pass));
|
||||
}
|
||||
|
||||
// 添加一个AnalysisPass
|
||||
template<typename T, typename... Args>
|
||||
T* addAnalysisPass(Args&&... args) {
|
||||
static_assert(std::is_base_of<AnalysisPass, T>::value, "T must derive from AnalysisPass");
|
||||
auto analysis = std::make_unique<T>(std::forward<Args>(args)...);
|
||||
T* rawPtr = analysis.get();
|
||||
analysisPasses[std::type_index(typeid(T))] = std::move(analysis);
|
||||
return rawPtr;
|
||||
}
|
||||
|
||||
// 获取分析结果(用于其他Pass访问)
|
||||
template<typename T>
|
||||
T* getAnalysis() {
|
||||
static_assert(std::is_base_of<AnalysisPass, T>::value, "T must derive from AnalysisPass");
|
||||
auto it = analysisPasses.find(std::type_index(typeid(T)));
|
||||
if (it != analysisPasses.end()) {
|
||||
return static_cast<T*>(it->second.get());
|
||||
}
|
||||
return nullptr; // 或者抛出异常
|
||||
}
|
||||
|
||||
// 运行所有注册的遍
|
||||
void run(Module& M);
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<FunctionPass>> functionPasses;
|
||||
std::vector<std::unique_ptr<ModulePass>> modulePasses;
|
||||
std::unordered_map<std::type_index, std::unique_ptr<AnalysisPass>> analysisPasses;
|
||||
// 未来可以添加AnalysisPass的缓存机制
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
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/DivStrengthReduction.h
Normal file
30
src/include/backend/RISCv64/Optimize/DivStrengthReduction.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef RISCV64_DIV_STRENGTH_REDUCTION_H
|
||||
#define RISCV64_DIV_STRENGTH_REDUCTION_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "Pass.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
/**
|
||||
* @class DivStrengthReduction
|
||||
* @brief 除法强度削弱优化器
|
||||
* * 将除法运算转换为乘法运算,使用magic number算法
|
||||
* 适用于除数为常数的情况,可以显著提高性能
|
||||
*/
|
||||
class DivStrengthReduction : public Pass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
DivStrengthReduction() : Pass("div-strength-reduction", 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_DIV_STRENGTH_REDUCTION_H
|
||||
@ -23,6 +23,21 @@ public:
|
||||
bool runOnFunction(Function *F, AnalysisManager& AM) override;
|
||||
|
||||
void runOnMachineFunction(MachineFunction* mfunc);
|
||||
|
||||
/**
|
||||
* @brief 设置是否启用浮点乘加融合优化
|
||||
* @param enabled 是否启用
|
||||
*/
|
||||
static void setFusedMulAddEnabled(bool enabled) { fusedMulAddEnabled = enabled; }
|
||||
|
||||
/**
|
||||
* @brief 检查是否启用了浮点乘加融合优化
|
||||
* @return 是否启用
|
||||
*/
|
||||
static bool isFusedMulAddEnabled() { return fusedMulAddEnabled; }
|
||||
|
||||
private:
|
||||
static bool fusedMulAddEnabled; // 浮点乘加融合优化开关
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
@ -12,6 +12,26 @@ namespace sysy {
|
||||
* * 主要目标是优化寄存器分配器插入的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;
|
||||
@ -18,14 +18,14 @@ public:
|
||||
void printInstruction(MachineInstr* instr, bool debug = false);
|
||||
// 辅助函数
|
||||
void setStream(std::ostream& os) { OS = &os; }
|
||||
// 辅助函数
|
||||
std::string regToString(PhysicalReg reg) const;
|
||||
std::string formatInstr(const MachineInstr *instr);
|
||||
|
||||
private:
|
||||
// 打印各个部分
|
||||
void printPrologue();
|
||||
void printEpilogue();
|
||||
void printBasicBlock(MachineBasicBlock* mbb, bool debug = false);
|
||||
|
||||
// 辅助函数
|
||||
std::string regToString(PhysicalReg reg);
|
||||
void printOperand(MachineOperand* op);
|
||||
|
||||
MachineFunction* MFunc;
|
||||
@ -22,7 +22,11 @@ private:
|
||||
// 函数级代码生成 (实现新的流水线)
|
||||
std::string function_gen(Function* func);
|
||||
|
||||
// 私有辅助函数,用于根据类型计算其占用的字节数。
|
||||
unsigned getTypeSizeInBytes(Type* type);
|
||||
|
||||
Module* module;
|
||||
bool irc_failed = false;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
61
src/include/backend/RISCv64/RISCv64BasicBlockAlloc.h
Normal file
61
src/include/backend/RISCv64/RISCv64BasicBlockAlloc.h
Normal file
@ -0,0 +1,61 @@
|
||||
#ifndef RISCV64_BASICBLOCKALLOC_H
|
||||
#define RISCV64_BASICBLOCKALLOC_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
/**
|
||||
* @class RISCv64BasicBlockAlloc
|
||||
* @brief 一个有状态的、基本块级的贪心寄存器分配器。
|
||||
*
|
||||
* 该分配器作为简单但可靠的实现,它逐个处理基本块,并在块内尽可能地
|
||||
* 将虚拟寄存器的值保留在物理寄存器中,以减少不必要的内存访问。
|
||||
*/
|
||||
class RISCv64BasicBlockAlloc {
|
||||
public:
|
||||
RISCv64BasicBlockAlloc(MachineFunction* mfunc);
|
||||
void run();
|
||||
|
||||
private:
|
||||
void computeLiveness();
|
||||
void processBasicBlock(MachineBasicBlock* mbb);
|
||||
void assignStackSlotsForAllVRegs();
|
||||
|
||||
// 核心分配函数
|
||||
PhysicalReg ensureInReg(unsigned vreg, std::vector<std::unique_ptr<MachineInstr>>& new_instrs);
|
||||
PhysicalReg allocReg(unsigned vreg, std::vector<std::unique_ptr<MachineInstr>>& new_instrs);
|
||||
PhysicalReg findFreeReg(bool is_fp);
|
||||
PhysicalReg spillReg(bool is_fp, std::vector<std::unique_ptr<MachineInstr>>& new_instrs);
|
||||
|
||||
// 状态跟踪(每个基本块开始时都会重置)
|
||||
std::map<unsigned, PhysicalReg> vreg_to_preg; // 当前vreg到物理寄存器的映射
|
||||
std::map<PhysicalReg, unsigned> preg_to_vreg; // 反向映射
|
||||
std::set<PhysicalReg> dirty_pregs; // 被修改过、需要写回的物理寄存器
|
||||
|
||||
// 分配器全局信息
|
||||
MachineFunction* MFunc;
|
||||
RISCv64ISel* ISel;
|
||||
std::map<unsigned, PhysicalReg> abi_vreg_map; // 函数参数的ABI寄存器映射
|
||||
|
||||
// 寄存器池和循环索引
|
||||
std::vector<PhysicalReg> int_temps;
|
||||
std::vector<PhysicalReg> fp_temps;
|
||||
int int_temp_idx = 0;
|
||||
int fp_temp_idx = 0;
|
||||
|
||||
// 辅助函数
|
||||
PhysicalReg getNextIntTemp();
|
||||
PhysicalReg getNextFpTemp();
|
||||
|
||||
// 活性分析结果
|
||||
std::map<const MachineBasicBlock*, std::set<unsigned>> live_out;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // RISCV64_BASICBLOCKALLOC_H
|
||||
@ -3,8 +3,15 @@
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
|
||||
// Forward declarations
|
||||
namespace sysy {
|
||||
class GlobalValue;
|
||||
class Value;
|
||||
}
|
||||
|
||||
extern int DEBUG;
|
||||
extern int DEEPDEBUG;
|
||||
extern int optLevel;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
@ -16,9 +23,12 @@ public:
|
||||
|
||||
// 公开接口,以便后续模块(如RegAlloc)可以查询或创建vreg
|
||||
unsigned getVReg(Value* val);
|
||||
unsigned getNewVReg() { return vreg_counter++; }
|
||||
unsigned getNewVReg(Type* type);
|
||||
unsigned getVRegCounter() const;
|
||||
// 获取 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的内部实现细节
|
||||
@ -38,6 +48,7 @@ private:
|
||||
// 用于计算类型大小的辅助函数
|
||||
unsigned getTypeSizeInBytes(Type* type);
|
||||
|
||||
// 打印DAG图以供调试
|
||||
void print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, const std::string& bb_name);
|
||||
|
||||
// 状态
|
||||
@ -47,6 +58,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;
|
||||
98
src/include/backend/RISCv64/RISCv64Info.h
Normal file
98
src/include/backend/RISCv64/RISCv64Info.h
Normal file
@ -0,0 +1,98 @@
|
||||
#ifndef RISCV64_INFO_H
|
||||
#define RISCV64_INFO_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 定义一个全局的、权威的指令信息表
|
||||
// 它包含了指令的定义(def)和使用(use)操作数索引
|
||||
// defs: {0} -> 第一个操作数是定义
|
||||
// uses: {1, 2} -> 第二、三个操作数是使用
|
||||
static const std::map<RVOpcodes, std::pair<std::vector<int>, std::vector<int>>> op_info = {
|
||||
// --- 整数计算 (R-Type) ---
|
||||
{RVOpcodes::ADD, {{0}, {1, 2}}},
|
||||
{RVOpcodes::SUB, {{0}, {1, 2}}},
|
||||
{RVOpcodes::MUL, {{0}, {1, 2}}},
|
||||
{RVOpcodes::MULH, {{0}, {1, 2}}},
|
||||
{RVOpcodes::DIV, {{0}, {1, 2}}},
|
||||
{RVOpcodes::DIVW, {{0}, {1, 2}}},
|
||||
{RVOpcodes::REM, {{0}, {1, 2}}},
|
||||
{RVOpcodes::REMW, {{0}, {1, 2}}},
|
||||
{RVOpcodes::ADDW, {{0}, {1, 2}}},
|
||||
{RVOpcodes::SUBW, {{0}, {1, 2}}},
|
||||
{RVOpcodes::MULW, {{0}, {1, 2}}},
|
||||
{RVOpcodes::SLT, {{0}, {1, 2}}},
|
||||
{RVOpcodes::SLTU, {{0}, {1, 2}}},
|
||||
{RVOpcodes::XOR, {{0}, {1, 2}}},
|
||||
{RVOpcodes::OR, {{0}, {1, 2}}},
|
||||
{RVOpcodes::AND, {{0}, {1, 2}}},
|
||||
{RVOpcodes::SLL, {{0}, {1, 2}}},
|
||||
{RVOpcodes::SRL, {{0}, {1, 2}}},
|
||||
{RVOpcodes::SRA, {{0}, {1, 2}}},
|
||||
{RVOpcodes::SLLW, {{0}, {1, 2}}},
|
||||
{RVOpcodes::SRLW, {{0}, {1, 2}}},
|
||||
{RVOpcodes::SRAW, {{0}, {1, 2}}},
|
||||
|
||||
// --- 整数计算 (I-Type) ---
|
||||
{RVOpcodes::ADDI, {{0}, {1}}},
|
||||
{RVOpcodes::ADDIW, {{0}, {1}}},
|
||||
{RVOpcodes::XORI, {{0}, {1}}},
|
||||
{RVOpcodes::ORI, {{0}, {1}}},
|
||||
{RVOpcodes::ANDI, {{0}, {1}}},
|
||||
{RVOpcodes::SLTI, {{0}, {1}}},
|
||||
{RVOpcodes::SLTIU, {{0}, {1}}},
|
||||
{RVOpcodes::SLLI, {{0}, {1}}},
|
||||
{RVOpcodes::SLLIW, {{0}, {1}}},
|
||||
{RVOpcodes::SRLI, {{0}, {1}}},
|
||||
{RVOpcodes::SRLIW, {{0}, {1}}},
|
||||
{RVOpcodes::SRAI, {{0}, {1}}},
|
||||
{RVOpcodes::SRAIW, {{0}, {1}}},
|
||||
|
||||
// --- 内存加载 ---
|
||||
{RVOpcodes::LW, {{0}, {}}}, {RVOpcodes::LH, {{0}, {}}}, {RVOpcodes::LB, {{0}, {}}},
|
||||
{RVOpcodes::LWU, {{0}, {}}}, {RVOpcodes::LHU, {{0}, {}}}, {RVOpcodes::LBU, {{0}, {}}},
|
||||
{RVOpcodes::LD, {{0}, {}}},
|
||||
{RVOpcodes::FLW, {{0}, {}}}, {RVOpcodes::FLD, {{0}, {}}},
|
||||
|
||||
// --- 内存存储 ---
|
||||
{RVOpcodes::SW, {{}, {0, 1}}}, {RVOpcodes::SH, {{}, {0, 1}}}, {RVOpcodes::SB, {{}, {0, 1}}},
|
||||
{RVOpcodes::SD, {{}, {0, 1}}},
|
||||
{RVOpcodes::FSW, {{}, {0, 1}}}, {RVOpcodes::FSD, {{}, {0, 1}}},
|
||||
|
||||
// --- 分支指令 ---
|
||||
{RVOpcodes::BEQ, {{}, {0, 1}}}, {RVOpcodes::BNE, {{}, {0, 1}}}, {RVOpcodes::BLT, {{}, {0, 1}}},
|
||||
{RVOpcodes::BGE, {{}, {0, 1}}}, {RVOpcodes::BLTU, {{}, {0, 1}}}, {RVOpcodes::BGEU, {{}, {0, 1}}},
|
||||
|
||||
// --- 跳转 ---
|
||||
{RVOpcodes::JAL, {{0}, {}}}, // JAL的rd是def,但通常用x0表示不关心返回值,这里简化
|
||||
{RVOpcodes::JALR, {{0}, {1}}},
|
||||
{RVOpcodes::RET, {{}, {}}}, // RET是伪指令,通常展开为JALR
|
||||
|
||||
// --- 伪指令 & 其他 ---
|
||||
{RVOpcodes::LI, {{0}, {}}}, {RVOpcodes::LA, {{0}, {}}},
|
||||
{RVOpcodes::MV, {{0}, {1}}},
|
||||
{RVOpcodes::NEG, {{0}, {1}}}, // sub rd, zero, rs1
|
||||
{RVOpcodes::NEGW, {{0}, {1}}}, // subw rd, zero, rs1
|
||||
{RVOpcodes::SEQZ, {{0}, {1}}},
|
||||
{RVOpcodes::SNEZ, {{0}, {1}}},
|
||||
|
||||
// --- 函数调用 ---
|
||||
// CALL的use/def在getInstrUseDef中有特殊处理逻辑,这里可以不列出
|
||||
|
||||
// --- 浮点指令 ---
|
||||
{RVOpcodes::FADD_S, {{0}, {1, 2}}}, {RVOpcodes::FSUB_S, {{0}, {1, 2}}},
|
||||
{RVOpcodes::FMUL_S, {{0}, {1, 2}}}, {RVOpcodes::FDIV_S, {{0}, {1, 2}}},
|
||||
{RVOpcodes::FMADD_S, {{0}, {1, 2, 3}}},
|
||||
{RVOpcodes::FEQ_S, {{0}, {1, 2}}}, {RVOpcodes::FLT_S, {{0}, {1, 2}}}, {RVOpcodes::FLE_S, {{0}, {1, 2}}},
|
||||
{RVOpcodes::FCVT_S_W, {{0}, {1}}}, {RVOpcodes::FCVT_W_S, {{0}, {1}}},
|
||||
{RVOpcodes::FCVT_W_S_RTZ, {{0}, {1}}},
|
||||
{RVOpcodes::FMV_S, {{0}, {1}}}, {RVOpcodes::FMV_W_X, {{0}, {1}}}, {RVOpcodes::FMV_X_W, {{0}, {1}}},
|
||||
{RVOpcodes::FNEG_S, {{0}, {1}}}
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // RISCV64_INFO_H
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
#include "IR.h" // 确保包含了您自己的IR头文件
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
@ -32,21 +33,22 @@ enum class PhysicalReg {
|
||||
A0, A1, A2, A3, A4, A5, A6, A7,
|
||||
|
||||
// --- 浮点寄存器 ---
|
||||
// (保持您原有的 F0-F31 命名)
|
||||
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_START_ID = 1000000,
|
||||
PHYS_REG_END_ID = PHYS_REG_START_ID + 320, // 预留足够的空间
|
||||
|
||||
INVALID, ///< 无效寄存器标记
|
||||
};
|
||||
|
||||
// RISC-V 指令操作码枚举
|
||||
enum class RVOpcodes {
|
||||
// 算术指令
|
||||
ADD, ADDI, ADDW, ADDIW, SUB, SUBW, MUL, MULW, DIV, DIVW, REM, REMW,
|
||||
ADD, ADDI, ADDW, ADDIW, SUB, SUBW, MUL, MULW, MULH, DIV, DIVW, REM, REMW,
|
||||
// 逻辑指令
|
||||
XOR, XORI, OR, ORI, AND, ANDI,
|
||||
// 移位指令
|
||||
@ -64,16 +66,103 @@ enum class RVOpcodes {
|
||||
CALL,
|
||||
// 特殊标记,非指令
|
||||
LABEL,
|
||||
// 新增伪指令,用于解耦栈帧处理
|
||||
|
||||
// 浮点指令 (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
|
||||
FMADD_S, // fmadd.s rd, rs1, rs2, rs3
|
||||
|
||||
// 浮点比较 (单精度)
|
||||
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 (单精度浮点 -> 有符号整数)
|
||||
FCVT_W_S_RTZ, // fcvt.w.s rd, rs1, rtz (使用向零截断模式)
|
||||
|
||||
// 浮点传送/移动
|
||||
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 (浮点取负)
|
||||
|
||||
// 浮点控制状态寄存器 (CSR)
|
||||
FSRMI, // fsrmi rd, imm (设置舍入模式立即数)
|
||||
|
||||
// 伪指令
|
||||
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, // 保持寄存器活跃,防止优化器删除
|
||||
};
|
||||
|
||||
// 定义一个全局辅助函数或常量,提供调用者保存寄存器列表
|
||||
const std::vector<PhysicalReg>& getCallerSavedIntRegs();
|
||||
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;
|
||||
@ -114,6 +203,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;
|
||||
@ -162,6 +256,19 @@ public:
|
||||
void addOperand(std::unique_ptr<MachineOperand> operand) {
|
||||
operands.push_back(std::move(operand));
|
||||
}
|
||||
/**
|
||||
* @brief (为紧急溢出模式添加)将指令中所有对特定虚拟寄存器的引用替换为指定的物理寄存器。
|
||||
* * @param old_vreg 需要被替换的虚拟寄存器号。
|
||||
* @param preg 用于替换的物理寄存器。
|
||||
*/
|
||||
void replaceVRegWithPReg(unsigned old_vreg, PhysicalReg preg);
|
||||
|
||||
/**
|
||||
* @brief (为常规溢出模式添加)根据提供的映射表,重映射指令中的虚拟寄存器。
|
||||
* * @param use_remap 一个从旧vreg到新vreg的映射,用于指令的use操作数。
|
||||
* @param def_remap 一个从旧vreg到新vreg的映射,用于指令的def操作数。
|
||||
*/
|
||||
void remapVRegs(const std::map<unsigned, unsigned>& use_remap, const std::map<unsigned, unsigned>& def_remap);
|
||||
private:
|
||||
RVOpcodes opcode;
|
||||
std::vector<std::unique_ptr<MachineOperand>> operands;
|
||||
@ -193,12 +300,15 @@ private:
|
||||
// 栈帧信息
|
||||
struct StackFrameInfo {
|
||||
int locals_size = 0; // 仅为AllocaInst分配的大小
|
||||
int locals_end_offset = 0; // 记录局部变量分配结束后的偏移量(相对于s0,为负)
|
||||
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; // 已排序的、需要存取的被调用者保存寄存器
|
||||
};
|
||||
|
||||
// 机器函数
|
||||
@ -212,7 +322,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));
|
||||
}
|
||||
@ -223,16 +333,23 @@ private:
|
||||
std::vector<std::unique_ptr<MachineBasicBlock>> blocks;
|
||||
StackFrameInfo frame_info;
|
||||
};
|
||||
|
||||
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;
|
||||
inline 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:
|
||||
case RVOpcodes::FLD:
|
||||
case RVOpcodes::FSD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void getInstrUseDef(const MachineInstr* instr, std::set<unsigned>& use, std::set<unsigned>& def);
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // RISCV64_LLIR_H
|
||||
81
src/include/backend/RISCv64/RISCv64LinearScan.h
Normal file
81
src/include/backend/RISCv64/RISCv64LinearScan.h
Normal file
@ -0,0 +1,81 @@
|
||||
#ifndef RISCV64_LINEARSCAN_H
|
||||
#define RISCV64_LINEARSCAN_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 前向声明
|
||||
class MachineBasicBlock;
|
||||
class MachineFunction;
|
||||
class RISCv64ISel;
|
||||
|
||||
/**
|
||||
* @brief 表示一个虚拟寄存器的活跃区间。
|
||||
* 包含起始和结束指令编号。为了简化,我们不处理有“洞”的区间。
|
||||
*/
|
||||
struct LiveInterval {
|
||||
unsigned vreg = 0;
|
||||
int start = -1;
|
||||
int end = -1;
|
||||
bool crosses_call = false;
|
||||
|
||||
LiveInterval(unsigned vreg) : vreg(vreg) {}
|
||||
|
||||
// 用于排序,按起始点从小到大
|
||||
bool operator<(const LiveInterval& other) const {
|
||||
return start < other.start;
|
||||
}
|
||||
};
|
||||
|
||||
class RISCv64LinearScan {
|
||||
public:
|
||||
RISCv64LinearScan(MachineFunction* mfunc);
|
||||
bool run();
|
||||
|
||||
private:
|
||||
// --- 核心算法流程 ---
|
||||
void linearizeBlocks();
|
||||
void computeLiveIntervals();
|
||||
bool linearScan();
|
||||
void rewriteProgram();
|
||||
void applyAllocation();
|
||||
void spillAtInterval(LiveInterval* current);
|
||||
|
||||
// --- 辅助函数 ---
|
||||
bool isFPVReg(unsigned vreg) const;
|
||||
void collectUsedCalleeSavedRegs();
|
||||
|
||||
MachineFunction* MFunc;
|
||||
RISCv64ISel* ISel;
|
||||
|
||||
// --- 线性扫描数据结构 ---
|
||||
std::vector<MachineBasicBlock*> linear_order_blocks;
|
||||
std::map<const MachineInstr*, int> instr_numbering;
|
||||
std::map<unsigned, LiveInterval> live_intervals;
|
||||
|
||||
std::vector<LiveInterval*> unhandled;
|
||||
std::vector<LiveInterval*> active; // 活跃且已分配物理寄存器的区间
|
||||
|
||||
std::set<unsigned> spilled_vregs; // 记录在本轮被决定溢出的vreg
|
||||
|
||||
bool conservative_spill_mode = false;
|
||||
const PhysicalReg SPILL_TEMP_REG = PhysicalReg::T4;
|
||||
|
||||
// --- 寄存器池和分配结果 ---
|
||||
std::vector<PhysicalReg> allocable_int_regs;
|
||||
std::vector<PhysicalReg> allocable_fp_regs;
|
||||
std::map<unsigned, PhysicalReg> vreg_to_preg_map;
|
||||
std::map<unsigned, PhysicalReg> abi_vreg_map;
|
||||
|
||||
const std::map<unsigned, Type*>& vreg_type_map;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // RISCV64_LINEARSCAN_H
|
||||
@ -1,12 +1,16 @@
|
||||
#ifndef RISCV64_PASSES_H
|
||||
#define RISCV64_PASSES_H
|
||||
|
||||
#include "Pass.h"
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "RISCv64Peephole.h"
|
||||
#include "Peephole.h"
|
||||
#include "PreRA_Scheduler.h"
|
||||
#include "PostRA_Scheduler.h"
|
||||
#include "CalleeSavedHandler.h"
|
||||
#include "Pass.h"
|
||||
#include "LegalizeImmediates.h"
|
||||
#include "PrologueEpilogueInsertion.h"
|
||||
#include "EliminateFrameIndices.h"
|
||||
#include "DivStrengthReduction.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
123
src/include/backend/RISCv64/RISCv64RegAlloc.h
Normal file
123
src/include/backend/RISCv64/RISCv64RegAlloc.h
Normal file
@ -0,0 +1,123 @@
|
||||
#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; // 用于更深层次的调试输出
|
||||
extern int optLevel;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
class RISCv64RegAlloc {
|
||||
public:
|
||||
RISCv64RegAlloc(MachineFunction* mfunc);
|
||||
|
||||
// 模块主入口
|
||||
bool run(std::shared_ptr<std::atomic<bool>> stop_flag);
|
||||
|
||||
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
|
||||
107
src/include/backend/RISCv64/RISCv64SimpleRegAlloc.h
Normal file
107
src/include/backend/RISCv64/RISCv64SimpleRegAlloc.h
Normal file
@ -0,0 +1,107 @@
|
||||
#ifndef RISCV64_SIMPLE_REGALLOC_H
|
||||
#define RISCV64_SIMPLE_REGALLOC_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
// 外部调试级别控制变量的声明
|
||||
extern int DEBUG;
|
||||
extern int DEEPDEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
class RISCv64AsmPrinter; // 前向声明
|
||||
|
||||
/**
|
||||
* @class RISCv64SimpleRegAlloc
|
||||
* @brief 一个简单的一次性图着色寄存器分配器。
|
||||
* * 该分配器遵循一个线性的、非迭代的流程:
|
||||
* 1. 活跃性分析
|
||||
* 2. 构建冲突图
|
||||
* 3. 贪心图着色
|
||||
* 4. 重写函数代码,插入溢出指令
|
||||
* * 它与新版后端流水线兼容,但保留了旧版分配器的核心逻辑。
|
||||
* 溢出处理使用硬编码的物理寄存器。
|
||||
*/
|
||||
class RISCv64SimpleRegAlloc {
|
||||
public:
|
||||
RISCv64SimpleRegAlloc(MachineFunction* mfunc);
|
||||
|
||||
/**
|
||||
* @brief 运行寄存器分配的主函数。
|
||||
*/
|
||||
void run();
|
||||
|
||||
private:
|
||||
using LiveSet = std::set<unsigned>;
|
||||
using InterferenceGraph = std::map<unsigned, LiveSet>;
|
||||
|
||||
// --- 分配流程的各个阶段 ---
|
||||
void unifyArgumentVRegs();
|
||||
void handleCallingConvention();
|
||||
void analyzeLiveness();
|
||||
void buildInterferenceGraph();
|
||||
void colorGraph();
|
||||
void rewriteFunction();
|
||||
|
||||
// --- 辅助函数 ---
|
||||
|
||||
/**
|
||||
* @brief 获取指令的Use/Def集合,包含物理寄存器,用于活跃性分析。
|
||||
* @param instr 机器指令。
|
||||
* @param use 输出参数,存储使用的寄存器ID。
|
||||
* @param def 输出参数,存储定义的寄存器ID。
|
||||
*/
|
||||
void getInstrUseDef_Liveness(const MachineInstr* instr, LiveSet& use, LiveSet& def);
|
||||
|
||||
/**
|
||||
* @brief 根据vreg的类型信息返回其大小和类型种类。
|
||||
* @param vreg 虚拟寄存器号。
|
||||
* @return 一个包含类型信息和大小(字节)的pair。
|
||||
*/
|
||||
std::pair<Type::Kind, unsigned> getTypeAndSize(unsigned vreg);
|
||||
|
||||
/**
|
||||
* @brief 打印调试用的活跃集信息。
|
||||
*/
|
||||
void printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os, const RISCv64AsmPrinter& printer);
|
||||
|
||||
/**
|
||||
* @brief 将寄存器ID(虚拟或物理)转换为可读字符串。
|
||||
*/
|
||||
std::string regIdToString(unsigned id, const RISCv64AsmPrinter& printer) const;
|
||||
|
||||
// --- 成员变量 ---
|
||||
MachineFunction* MFunc;
|
||||
RISCv64ISel* ISel;
|
||||
|
||||
// 可分配的寄存器池
|
||||
std::vector<PhysicalReg> allocable_int_regs;
|
||||
std::vector<PhysicalReg> allocable_fp_regs;
|
||||
|
||||
// 硬编码的溢出专用物理寄存器
|
||||
const PhysicalReg INT_SPILL_REG = PhysicalReg::T2; // 用于 32-bit int
|
||||
const PhysicalReg PTR_SPILL_REG = PhysicalReg::T3; // 用于 64-bit pointer
|
||||
const PhysicalReg FP_SPILL_REG = PhysicalReg::F4; // 用于 32-bit float (ft4)
|
||||
|
||||
// 活跃性分析结果
|
||||
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;
|
||||
std::set<unsigned> spilled_vregs;
|
||||
|
||||
// 映射:将物理寄存器ID映射到它们在冲突图中的特殊虚拟ID
|
||||
std::map<PhysicalReg, unsigned> preg_to_vreg_id_map;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // RISCV64_SIMPLE_REGALLOC_H
|
||||
File diff suppressed because it is too large
Load Diff
@ -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 = "") {
|
||||
@ -217,6 +217,18 @@ class IRBuilder {
|
||||
BinaryInst * createOrInst(Value *lhs, Value *rhs, const std::string &name = "") {
|
||||
return createBinaryInst(Instruction::kOr, Type::getIntType(), lhs, rhs, name);
|
||||
} ///< 创建按位或指令
|
||||
BinaryInst * createSllInst(Value *lhs, Value *rhs, const std::string &name = "") {
|
||||
return createBinaryInst(Instruction::kSll, Type::getIntType(), lhs, rhs, name);
|
||||
} ///< 创建逻辑左移指令
|
||||
BinaryInst * createSrlInst(Value *lhs, Value *rhs, const std::string &name = "") {
|
||||
return createBinaryInst(Instruction::kSrl, Type::getIntType(), lhs, rhs, name);
|
||||
} ///< 创建逻辑右移指令
|
||||
BinaryInst * createSraInst(Value *lhs, Value *rhs, const std::string &name = "") {
|
||||
return createBinaryInst(Instruction::kSra, Type::getIntType(), lhs, rhs, name);
|
||||
} ///< 创建算术右移指令
|
||||
BinaryInst * createMulhInst(Value *lhs, Value *rhs, const std::string &name = "") {
|
||||
return createBinaryInst(Instruction::kMulh, Type::getIntType(), lhs, rhs, name);
|
||||
} ///< 创建高位乘法指令
|
||||
CallInst * createCallInst(Function *callee, const std::vector<Value *> &args, const std::string &name = "") {
|
||||
std::string newName;
|
||||
if (name.empty() && callee->getReturnType() != Type::getVoidType()) {
|
||||
@ -239,31 +251,30 @@ class IRBuilder {
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建return指令
|
||||
UncondBrInst * createUncondBrInst(BasicBlock *thenBlock, const std::vector<Value *> &args) {
|
||||
auto inst = new UncondBrInst(thenBlock, args, block);
|
||||
UncondBrInst * createUncondBrInst(BasicBlock *thenBlock) {
|
||||
auto inst = new UncondBrInst(thenBlock, block);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建无条件指令
|
||||
CondBrInst * createCondBrInst(Value *condition, BasicBlock *thenBlock, BasicBlock *elseBlock,
|
||||
const std::vector<Value *> &thenArgs, const std::vector<Value *> &elseArgs) {
|
||||
auto inst = new CondBrInst(condition, thenBlock, elseBlock, thenArgs, elseArgs, block);
|
||||
CondBrInst * createCondBrInst(Value *condition, BasicBlock *thenBlock, BasicBlock *elseBlock) {
|
||||
auto inst = new CondBrInst(condition, thenBlock, elseBlock, block);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建条件跳转指令
|
||||
AllocaInst * createAllocaInst(Type *type, const std::vector<Value *> &dims = {}, const std::string &name = "") {
|
||||
auto inst = new AllocaInst(type, dims, block, name);
|
||||
UnreachableInst * createUnreachableInst(const std::string &name = "") {
|
||||
auto inst = new UnreachableInst(name, block);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建不可达指令
|
||||
AllocaInst * createAllocaInst(Type *type, const std::string &name = "") {
|
||||
auto inst = new AllocaInst(type, block, name);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建分配指令
|
||||
AllocaInst * createAllocaInstWithoutInsert(Type *type, const std::vector<Value *> &dims = {}, BasicBlock *parent = nullptr,
|
||||
const std::string &name = "") {
|
||||
auto inst = new AllocaInst(type, dims, parent, name);
|
||||
assert(inst);
|
||||
return inst;
|
||||
} ///< 创建不插入指令列表的分配指令[仅用于phi指令]
|
||||
LoadInst * createLoadInst(Value *pointer, const std::vector<Value *> &indices = {}, const std::string &name = "") {
|
||||
std::string newName;
|
||||
if (name.empty()) {
|
||||
@ -275,7 +286,7 @@ class IRBuilder {
|
||||
newName = name;
|
||||
}
|
||||
|
||||
auto inst = new LoadInst(pointer, indices, block, newName);
|
||||
auto inst = new LoadInst(pointer, block, newName);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
@ -286,37 +297,27 @@ class IRBuilder {
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建memset指令
|
||||
StoreInst * createStoreInst(Value *value, Value *pointer, const std::vector<Value *> &indices = {},
|
||||
const std::string &name = "") {
|
||||
auto inst = new StoreInst(value, pointer, indices, block, name);
|
||||
StoreInst * createStoreInst(Value *value, Value *pointer, const std::string &name = "") {
|
||||
auto inst = new StoreInst(value, pointer, block, name);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建store指令
|
||||
PhiInst * createPhiInst(Type *type, const std::vector<Value*> &vals = {}, const std::vector<BasicBlock*> &blks = {}, const std::string &name = "") {
|
||||
auto inst = new PhiInst(type, vals, blks, block, name);
|
||||
std::string newName;
|
||||
if (name.empty()) {
|
||||
std::stringstream ss;
|
||||
ss << tmpIndex;
|
||||
newName = ss.str();
|
||||
tmpIndex++;
|
||||
} else {
|
||||
newName = name;
|
||||
}
|
||||
auto inst = new PhiInst(type, vals, blks, block, newName);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(block->begin(), inst);
|
||||
return inst;
|
||||
} ///< 创建Phi指令
|
||||
// GetElementPtrInst* createGetElementPtrInst(Value *basePointer,
|
||||
// const std::vector<Value *> &indices = {},
|
||||
// const std::string &name = "") {
|
||||
// std::string newName;
|
||||
// if (name.empty()) {
|
||||
// std::stringstream ss;
|
||||
// ss << tmpIndex;
|
||||
// newName = ss.str();
|
||||
// tmpIndex++;
|
||||
// } else {
|
||||
// newName = name;
|
||||
// }
|
||||
|
||||
// auto inst = new GetElementPtrInst(basePointer, indices, block, newName);
|
||||
// assert(inst);
|
||||
// block->getInstructions().emplace(position, inst);
|
||||
// return inst;
|
||||
// }
|
||||
/**
|
||||
* @brief 根据 LLVM 设计模式创建 GEP 指令。
|
||||
* 它会自动推断返回类型,无需手动指定。
|
||||
@ -355,38 +356,31 @@ class IRBuilder {
|
||||
Type *currentWalkType = pointerType->as<PointerType>()->getBaseType();
|
||||
|
||||
// 遍历所有索引来深入类型层次结构。
|
||||
// `indices` 向量包含了所有 GEP 索引,包括由 `visitLValue` 等函数添加的初始 `0` 索引。
|
||||
// 重要:第一个索引总是用于"解引用"指针,后续索引才用于数组/结构体的索引
|
||||
for (int i = 0; i < indices.size(); ++i) {
|
||||
if (currentWalkType->isArray()) {
|
||||
// 情况一:当前遍历类型是 `ArrayType`。
|
||||
// 索引用于选择数组元素,`currentWalkType` 更新为数组的元素类型。
|
||||
currentWalkType = currentWalkType->as<ArrayType>()->getElementType();
|
||||
} else if (currentWalkType->isPointer()) {
|
||||
// 情况二:当前遍历类型是 `PointerType`。
|
||||
// 这意味着我们正在通过一个指针来访问其指向的内存。
|
||||
// 索引用于选择该指针所指向的“数组”的元素。
|
||||
// `currentWalkType` 更新为该指针所指向的基础类型。
|
||||
// 例如:如果 `currentWalkType` 是 `i32*`,它将变为 `i32`。
|
||||
// 如果 `currentWalkType` 是 `[10 x i32]*`,它将变为 `[10 x i32]`。
|
||||
currentWalkType = currentWalkType->as<PointerType>()->getBaseType();
|
||||
if (i == 0) {
|
||||
// 第一个索引:总是用于"解引用"基指针,不改变currentWalkType
|
||||
// 例如:对于 `[4 x i32]* ptr, i32 0`,第一个0只是说"访问ptr指向的对象"
|
||||
// currentWalkType 保持为 `[4 x i32]`
|
||||
continue;
|
||||
} else {
|
||||
// 情况三:当前遍历类型是标量类型 (例如 `i32`, `float` 等非聚合、非指针类型)。
|
||||
//
|
||||
// 如果 `currentWalkType` 是标量,并且当前索引 `i` **不是** `indices` 向量中的最后一个索引,
|
||||
// 这意味着尝试对一个标量类型进行进一步的结构性索引,这是**无效的**。
|
||||
// 例如:`int x; x[0];` 对应的 GEP 链中,`x` 的类型是 `i32`,再加 `[0]` 索引就是错误。
|
||||
//
|
||||
// 如果 `currentWalkType` 是标量,且这是**最后一个索引** (`i == indices.size() - 1`),
|
||||
// 那么 GEP 是合法的,它只是计算一个偏移地址,最终的类型就是这个标量类型。
|
||||
// 此时 `currentWalkType` 保持不变,循环结束。
|
||||
if (i < indices.size() - 1) {
|
||||
assert(false && "Invalid GEP indexing: attempting to index into a non-aggregate/non-pointer type with further indices.");
|
||||
return nullptr; // 返回空指针表示类型推断失败
|
||||
// 后续索引:用于实际的数组/结构体索引
|
||||
if (currentWalkType->isArray()) {
|
||||
// 数组索引:选择数组中的元素
|
||||
currentWalkType = currentWalkType->as<ArrayType>()->getElementType();
|
||||
} else if (currentWalkType->isPointer()) {
|
||||
// 指针索引:解引用指针并继续
|
||||
currentWalkType = currentWalkType->as<PointerType>()->getBaseType();
|
||||
} else {
|
||||
// 标量类型:不能进一步索引
|
||||
if (i < indices.size() - 1) {
|
||||
assert(false && "Invalid GEP indexing: attempting to index into a non-aggregate/non-pointer type with further indices.");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
// 如果是最后一个索引,且当前类型是标量,则类型保持不变,这是合法的。
|
||||
// 循环会自然结束,返回正确的 `currentWalkType`。
|
||||
}
|
||||
}
|
||||
|
||||
// 所有索引处理完毕后,`currentWalkType` 就是 GEP 指令最终计算出的地址所指向的元素的类型。
|
||||
return currentWalkType;
|
||||
}
|
||||
246
src/include/midend/Pass/Analysis/AliasAnalysis.h
Normal file
246
src/include/midend/Pass/Analysis/AliasAnalysis.h
Normal file
@ -0,0 +1,246 @@
|
||||
#pragma once
|
||||
|
||||
#include "IR.h"
|
||||
#include "Pass.h"
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 前向声明
|
||||
class MemoryLocation;
|
||||
class AliasAnalysisResult;
|
||||
|
||||
/**
|
||||
* @brief 别名关系类型
|
||||
* 按风险等级递增排序
|
||||
*/
|
||||
enum class AliasType {
|
||||
NO_ALIAS = 0, // 确定无别名 (不同的局部数组)
|
||||
SELF_ALIAS = 1, // 自别名 (同一数组的不同索引)
|
||||
POSSIBLE_ALIAS = 2, // 可能有别名 (函数参数数组)
|
||||
UNKNOWN_ALIAS = 3 // 未知 (保守估计)
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 内存位置信息
|
||||
* 描述一个内存访问的基础信息
|
||||
*/
|
||||
struct MemoryLocation {
|
||||
Value* basePointer; // 基指针 (剥离GEP后的真实基址)
|
||||
Value* accessPointer; // 访问指针 (包含索引信息)
|
||||
|
||||
// 分类信息
|
||||
bool isLocalArray; // 是否为局部数组
|
||||
bool isFunctionParameter; // 是否为函数参数
|
||||
bool isGlobalArray; // 是否为全局数组
|
||||
|
||||
// 索引信息
|
||||
std::vector<Value*> indices; // GEP索引列表
|
||||
bool hasConstantIndices; // 是否为常量索引
|
||||
bool hasLoopVariableIndex; // 是否包含循环变量
|
||||
int constantOffset; // 常量偏移量 (仅当全部为常量时有效)
|
||||
|
||||
// 访问模式
|
||||
bool hasReads; // 是否有读操作
|
||||
bool hasWrites; // 是否有写操作
|
||||
std::vector<Instruction*> accessInsts; // 所有访问指令
|
||||
|
||||
MemoryLocation(Value* base, Value* access)
|
||||
: basePointer(base), accessPointer(access),
|
||||
isLocalArray(false), isFunctionParameter(false), isGlobalArray(false),
|
||||
hasConstantIndices(false), hasLoopVariableIndex(false), constantOffset(0),
|
||||
hasReads(false), hasWrites(false) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 别名分析结果
|
||||
* 存储一个函数的完整别名分析信息
|
||||
*/
|
||||
class AliasAnalysisResult : public AnalysisResultBase {
|
||||
public:
|
||||
AliasAnalysisResult(Function *F) : AssociatedFunction(F) {}
|
||||
~AliasAnalysisResult() override = default;
|
||||
|
||||
// ========== 基础查询接口 ==========
|
||||
|
||||
/**
|
||||
* 查询两个指针之间的别名关系
|
||||
*/
|
||||
AliasType queryAlias(Value* ptr1, Value* ptr2) const;
|
||||
|
||||
/**
|
||||
* 查询指针的内存位置信息
|
||||
*/
|
||||
const MemoryLocation* getMemoryLocation(Value* ptr) const;
|
||||
|
||||
/**
|
||||
* 获取所有内存位置
|
||||
*/
|
||||
const std::map<Value*, std::unique_ptr<MemoryLocation>>& getAllMemoryLocations() const {
|
||||
return LocationMap;
|
||||
}
|
||||
|
||||
// ========== 高级查询接口 ==========
|
||||
|
||||
/**
|
||||
* 检查指针是否为局部数组
|
||||
*/
|
||||
bool isLocalArray(Value* ptr) const;
|
||||
|
||||
/**
|
||||
* 检查指针是否为函数参数数组
|
||||
*/
|
||||
bool isFunctionParameter(Value* ptr) const;
|
||||
|
||||
/**
|
||||
* 检查指针是否为全局数组
|
||||
*/
|
||||
bool isGlobalArray(Value* ptr) const;
|
||||
|
||||
/**
|
||||
* 检查指针是否使用常量索引
|
||||
*/
|
||||
bool hasConstantAccess(Value* ptr) const;
|
||||
|
||||
// ========== 统计接口 ==========
|
||||
|
||||
/**
|
||||
* 获取各类别名类型的统计信息
|
||||
*/
|
||||
struct Statistics {
|
||||
int totalQueries;
|
||||
int noAlias;
|
||||
int selfAlias;
|
||||
int possibleAlias;
|
||||
int unknownAlias;
|
||||
int localArrays;
|
||||
int functionParameters;
|
||||
int globalArrays;
|
||||
int constantAccesses;
|
||||
};
|
||||
|
||||
Statistics getStatistics() const;
|
||||
|
||||
/**
|
||||
* 打印别名分析结果 (调试用)
|
||||
*/
|
||||
void print() const;
|
||||
void printStatics() const;
|
||||
// ========== 内部方法 ==========
|
||||
|
||||
void addMemoryLocation(std::unique_ptr<MemoryLocation> location);
|
||||
void addAliasRelation(Value* ptr1, Value* ptr2, AliasType type);
|
||||
|
||||
// ========== 公开数据成员 (供Pass使用) ==========
|
||||
std::map<Value*, std::unique_ptr<MemoryLocation>> LocationMap; // 内存位置映射
|
||||
std::map<std::pair<Value*, Value*>, AliasType> AliasMap; // 别名关系缓存
|
||||
|
||||
private:
|
||||
Function *AssociatedFunction; // 关联的函数
|
||||
|
||||
// 分类存储
|
||||
std::vector<Argument*> ArrayParameters; // 数组参数
|
||||
std::vector<AllocaInst*> LocalArrays; // 局部数组
|
||||
std::set<GlobalValue*> AccessedGlobals; // 访问的全局变量
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief SysY语言特化的别名分析Pass
|
||||
* 针对SysY语言特性优化的别名分析实现
|
||||
*/
|
||||
class SysYAliasAnalysisPass : public AnalysisPass {
|
||||
public:
|
||||
// 唯一的 Pass ID
|
||||
static void *ID;
|
||||
// 在这里开启激进分析策略
|
||||
SysYAliasAnalysisPass() : AnalysisPass("SysYAliasAnalysis", Pass::Granularity::Function),
|
||||
aggressiveParameterMode(false), parameterOptimizationEnabled(false) {}
|
||||
|
||||
// 实现 getPassID
|
||||
void *getPassID() const override { return &ID; }
|
||||
|
||||
// 核心运行方法
|
||||
bool runOnFunction(Function *F, AnalysisManager &AM) override;
|
||||
|
||||
// 获取分析结果
|
||||
std::unique_ptr<AnalysisResultBase> getResult() override { return std::move(CurrentResult); }
|
||||
|
||||
// ========== 配置接口 ==========
|
||||
|
||||
/**
|
||||
* 启用针对SysY评测的激进优化模式
|
||||
* 在这种模式下,假设不同参数不会传入相同数组
|
||||
*/
|
||||
void enableSysYTestingMode() {
|
||||
aggressiveParameterMode = true;
|
||||
parameterOptimizationEnabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用保守的默认模式(适合通用场景)
|
||||
*/
|
||||
void useConservativeMode() {
|
||||
aggressiveParameterMode = false;
|
||||
parameterOptimizationEnabled = false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<AliasAnalysisResult> CurrentResult; // 当前函数的分析结果
|
||||
|
||||
// ========== 主要分析流程 ==========
|
||||
|
||||
void collectMemoryAccesses(Function* F); // 收集内存访问
|
||||
void buildAliasRelations(Function* F); // 构建别名关系
|
||||
void optimizeForSysY(Function* F); // SysY特化优化
|
||||
|
||||
// ========== 内存位置分析 ==========
|
||||
|
||||
std::unique_ptr<MemoryLocation> createMemoryLocation(Value* ptr);
|
||||
Value* getBasePointer(Value* ptr); // 获取基指针
|
||||
void analyzeMemoryType(MemoryLocation* location); // 分析内存类型
|
||||
void analyzeIndexPattern(MemoryLocation* location); // 分析索引模式
|
||||
|
||||
// ========== 别名关系推断 ==========
|
||||
|
||||
AliasType analyzeAliasBetween(MemoryLocation* loc1, MemoryLocation* loc2);
|
||||
AliasType compareIndices(MemoryLocation* loc1, MemoryLocation* loc2);
|
||||
AliasType compareLocalArrays(MemoryLocation* loc1, MemoryLocation* loc2);
|
||||
AliasType compareParameters(MemoryLocation* loc1, MemoryLocation* loc2);
|
||||
AliasType compareWithGlobal(MemoryLocation* loc1, MemoryLocation* loc2);
|
||||
AliasType compareMixedTypes(MemoryLocation* loc1, MemoryLocation* loc2);
|
||||
|
||||
// ========== SysY特化优化 ==========
|
||||
|
||||
void applySysYConstraints(Function* F); // 应用SysY语言约束
|
||||
void optimizeParameterAnalysis(Function* F); // 优化参数分析
|
||||
void optimizeArrayAccessAnalysis(Function* F); // 优化数组访问分析
|
||||
|
||||
// ========== 配置和策略控制 ==========
|
||||
|
||||
bool useAggressiveParameterAnalysis() const { return aggressiveParameterMode; }
|
||||
bool enableParameterOptimization() const { return parameterOptimizationEnabled; }
|
||||
void setAggressiveParameterMode(bool enable) { aggressiveParameterMode = enable; }
|
||||
void setParameterOptimizationEnabled(bool enable) { parameterOptimizationEnabled = enable; }
|
||||
|
||||
// ========== 辅助优化方法 ==========
|
||||
|
||||
void optimizeConstantIndexAccesses(); // 优化常量索引访问
|
||||
void optimizeSequentialAccesses(); // 优化顺序访问
|
||||
|
||||
// ========== 辅助方法 ==========
|
||||
|
||||
bool isConstantValue(Value* val); // 是否为常量
|
||||
bool hasLoopVariableInIndices(const std::vector<Value*>& indices, Function* F);
|
||||
int calculateConstantOffset(const std::vector<Value*>& indices);
|
||||
void printStatistics() const; // 打印统计信息
|
||||
|
||||
private:
|
||||
// ========== 配置选项 ==========
|
||||
bool aggressiveParameterMode = false; // 激进的参数别名分析模式
|
||||
bool parameterOptimizationEnabled = false; // 启用参数优化
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
242
src/include/midend/Pass/Analysis/CallGraphAnalysis.h
Normal file
242
src/include/midend/Pass/Analysis/CallGraphAnalysis.h
Normal file
@ -0,0 +1,242 @@
|
||||
#pragma once
|
||||
|
||||
#include "IR.h"
|
||||
#include "Pass.h"
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 前向声明
|
||||
class CallGraphAnalysisResult;
|
||||
|
||||
/**
|
||||
* @brief 调用图节点信息
|
||||
* 存储单个函数在调用图中的信息
|
||||
*/
|
||||
struct CallGraphNode {
|
||||
Function* function; // 关联的函数
|
||||
std::set<Function*> callers; // 调用此函数的函数集合
|
||||
std::set<Function*> callees; // 此函数调用的函数集合
|
||||
|
||||
// 递归信息
|
||||
bool isRecursive; // 是否参与递归调用
|
||||
bool isSelfRecursive; // 是否自递归
|
||||
int recursiveDepth; // 递归深度(-1表示无限递归)
|
||||
|
||||
// 调用统计
|
||||
size_t totalCallers; // 调用者总数
|
||||
size_t totalCallees; // 被调用函数总数
|
||||
size_t callSiteCount; // 调用点总数
|
||||
|
||||
CallGraphNode(Function* f) : function(f), isRecursive(false),
|
||||
isSelfRecursive(false), recursiveDepth(0), totalCallers(0),
|
||||
totalCallees(0), callSiteCount(0) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 调用图分析结果类
|
||||
* 包含整个模块的调用图信息和查询接口
|
||||
*/
|
||||
class CallGraphAnalysisResult : public AnalysisResultBase {
|
||||
public:
|
||||
CallGraphAnalysisResult(Module* M) : AssociatedModule(M) {}
|
||||
~CallGraphAnalysisResult() override = default;
|
||||
|
||||
// ========== 基础查询接口 ==========
|
||||
|
||||
/**
|
||||
* 获取函数的调用图节点
|
||||
*/
|
||||
const CallGraphNode* getNode(Function* F) const {
|
||||
auto it = nodes.find(F);
|
||||
return (it != nodes.end()) ? it->second.get() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取函数的调用图节点(非const版本)
|
||||
*/
|
||||
CallGraphNode* getMutableNode(Function* F) {
|
||||
auto it = nodes.find(F);
|
||||
return (it != nodes.end()) ? it->second.get() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有函数节点
|
||||
*/
|
||||
const std::map<Function*, std::unique_ptr<CallGraphNode>>& getAllNodes() const {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查函数是否存在于调用图中
|
||||
*/
|
||||
bool hasFunction(Function* F) const {
|
||||
return nodes.find(F) != nodes.end();
|
||||
}
|
||||
|
||||
// ========== 调用关系查询 ==========
|
||||
|
||||
/**
|
||||
* 检查是否存在从caller到callee的调用
|
||||
*/
|
||||
bool hasCallEdge(Function* caller, Function* callee) const {
|
||||
auto node = getNode(caller);
|
||||
return node && node->callees.count(callee) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取函数的所有调用者
|
||||
*/
|
||||
std::vector<Function*> getCallers(Function* F) const {
|
||||
auto node = getNode(F);
|
||||
if (!node) return {};
|
||||
return std::vector<Function*>(node->callers.begin(), node->callers.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取函数的所有被调用函数
|
||||
*/
|
||||
std::vector<Function*> getCallees(Function* F) const {
|
||||
auto node = getNode(F);
|
||||
if (!node) return {};
|
||||
return std::vector<Function*>(node->callees.begin(), node->callees.end());
|
||||
}
|
||||
|
||||
// ========== 递归分析查询 ==========
|
||||
|
||||
/**
|
||||
* 检查函数是否参与递归调用
|
||||
*/
|
||||
bool isRecursive(Function* F) const {
|
||||
auto node = getNode(F);
|
||||
return node && node->isRecursive;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查函数是否自递归
|
||||
*/
|
||||
bool isSelfRecursive(Function* F) const {
|
||||
auto node = getNode(F);
|
||||
return node && node->isSelfRecursive;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取递归深度
|
||||
*/
|
||||
int getRecursiveDepth(Function* F) const {
|
||||
auto node = getNode(F);
|
||||
return node ? node->recursiveDepth : 0;
|
||||
}
|
||||
|
||||
// ========== 拓扑排序和SCC ==========
|
||||
|
||||
/**
|
||||
* 获取函数的拓扑排序结果
|
||||
* 保证被调用函数在调用函数之前
|
||||
*/
|
||||
const std::vector<Function*>& getTopologicalOrder() const {
|
||||
return topologicalOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取强连通分量列表
|
||||
* 每个SCC表示一个递归函数群
|
||||
*/
|
||||
const std::vector<std::vector<Function*>>& getStronglyConnectedComponents() const {
|
||||
return sccs;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取函数所在的SCC索引
|
||||
*/
|
||||
int getSCCIndex(Function* F) const {
|
||||
auto it = functionToSCC.find(F);
|
||||
return (it != functionToSCC.end()) ? it->second : -1;
|
||||
}
|
||||
|
||||
// ========== 统计信息 ==========
|
||||
|
||||
struct Statistics {
|
||||
size_t totalFunctions;
|
||||
size_t totalCallEdges;
|
||||
size_t recursiveFunctions;
|
||||
size_t selfRecursiveFunctions;
|
||||
size_t stronglyConnectedComponents;
|
||||
size_t maxSCCSize;
|
||||
double avgCallersPerFunction;
|
||||
double avgCalleesPerFunction;
|
||||
};
|
||||
|
||||
Statistics getStatistics() const;
|
||||
|
||||
/**
|
||||
* 打印调用图分析结果
|
||||
*/
|
||||
void print() const;
|
||||
|
||||
// ========== 内部构建接口 ==========
|
||||
|
||||
void addNode(Function* F);
|
||||
void addCallEdge(Function* caller, Function* callee);
|
||||
void computeTopologicalOrder();
|
||||
void computeStronglyConnectedComponents();
|
||||
void analyzeRecursion();
|
||||
|
||||
private:
|
||||
Module* AssociatedModule; // 关联的模块
|
||||
std::map<Function*, std::unique_ptr<CallGraphNode>> nodes; // 调用图节点
|
||||
std::vector<Function*> topologicalOrder; // 拓扑排序结果
|
||||
std::vector<std::vector<Function*>> sccs; // 强连通分量
|
||||
std::map<Function*, int> functionToSCC; // 函数到SCC的映射
|
||||
|
||||
// 内部辅助方法
|
||||
void dfsTopological(Function* F, std::unordered_set<Function*>& visited,
|
||||
std::vector<Function*>& result);
|
||||
void tarjanSCC();
|
||||
void tarjanDFS(Function* F, int& index, std::vector<int>& indices,
|
||||
std::vector<int>& lowlinks, std::vector<Function*>& stack,
|
||||
std::unordered_set<Function*>& onStack);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief SysY调用图分析Pass
|
||||
* Module级别的分析Pass,构建整个模块的函数调用图
|
||||
*/
|
||||
class CallGraphAnalysisPass : public AnalysisPass {
|
||||
public:
|
||||
// 唯一的 Pass ID
|
||||
static void* ID;
|
||||
|
||||
CallGraphAnalysisPass() : AnalysisPass("CallGraphAnalysis", Pass::Granularity::Module) {}
|
||||
|
||||
// 实现 getPassID
|
||||
void* getPassID() const override { return &ID; }
|
||||
|
||||
// 核心运行方法
|
||||
bool runOnModule(Module* M, AnalysisManager& AM) override;
|
||||
|
||||
// 获取分析结果
|
||||
std::unique_ptr<AnalysisResultBase> getResult() override { return std::move(CurrentResult); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<CallGraphAnalysisResult> CurrentResult; // 当前模块的分析结果
|
||||
|
||||
// ========== 主要分析流程 ==========
|
||||
|
||||
void buildCallGraph(Module* M); // 构建调用图
|
||||
void scanFunctionCalls(Function* F); // 扫描函数的调用
|
||||
void processCallInstruction(CallInst* call, Function* caller); // 处理调用指令
|
||||
|
||||
// ========== 辅助方法 ==========
|
||||
|
||||
bool isLibraryFunction(Function* F) const; // 判断是否为标准库函数
|
||||
bool isIntrinsicFunction(Function* F) const; // 判断是否为内置函数
|
||||
void printStatistics() const; // 打印统计信息
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
107
src/include/midend/Pass/Analysis/Dom.h
Normal file
107
src/include/midend/Pass/Analysis/Dom.h
Normal file
@ -0,0 +1,107 @@
|
||||
#pragma once
|
||||
|
||||
#include "Pass.h" // 包含 Pass 框架
|
||||
#include "IR.h" // 包含 IR 定义
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 支配树分析结果类
|
||||
class DominatorTree : public AnalysisResultBase {
|
||||
public:
|
||||
DominatorTree(Function* F);
|
||||
// 获取指定基本块的所有支配者
|
||||
const std::set<BasicBlock*>* getDominators(BasicBlock* BB) const;
|
||||
// 获取指定基本块的即时支配者 (Immediate Dominator)
|
||||
BasicBlock* getImmediateDominator(BasicBlock* BB) const;
|
||||
// 获取指定基本块的支配边界 (Dominance Frontier)
|
||||
const std::set<BasicBlock*>* getDominanceFrontier(BasicBlock* BB) const;
|
||||
// 获取指定基本块在支配树中的子节点
|
||||
const std::set<BasicBlock*>* getDominatorTreeChildren(BasicBlock* BB) const;
|
||||
// 额外的 Getter:获取所有支配者、即时支配者和支配边界的完整映射(可选,主要用于调试或特定场景)
|
||||
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);
|
||||
// 计算所有基本块的即时支配者(内部使用 Lengauer-Tarjan 算法)
|
||||
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; // 支配树中每个基本块的子节点
|
||||
|
||||
// ==========================================================
|
||||
// Lengauer-Tarjan 算法内部所需的数据结构和辅助函数
|
||||
// 这些成员是私有的,以封装 LT 算法的复杂性并避免命名空间污染
|
||||
// ==========================================================
|
||||
|
||||
// DFS 遍历相关:
|
||||
std::map<BasicBlock*, int> dfnum_map; // 存储每个基本块的 DFS 编号
|
||||
std::vector<BasicBlock*> vertex_vec; // 通过 DFS 编号反向查找对应的基本块指针
|
||||
std::map<BasicBlock*, BasicBlock*> parent_map; // 存储 DFS 树中每个基本块的父节点
|
||||
int df_counter; // DFS 计数器,也代表 DFS 遍历的总节点数 (N)
|
||||
|
||||
// 半支配者 (Semi-dominator) 相关:
|
||||
std::map<BasicBlock*, BasicBlock*> sdom_map; // 存储每个基本块的半支配者
|
||||
std::map<BasicBlock*, BasicBlock*> idom_map; // 存储每个基本块的即时支配者 (IDom)
|
||||
std::map<BasicBlock*, std::vector<BasicBlock*>> bucket_map; // 桶结构,用于存储具有相同半支配者的节点,以延迟 IDom 计算
|
||||
|
||||
// 并查集 (Union-Find) 相关(用于 evalAndCompress 函数):
|
||||
std::map<BasicBlock*, BasicBlock*> ancestor_map; // 并查集中的父节点(用于路径压缩)
|
||||
std::map<BasicBlock*, BasicBlock*> label_map; // 并查集中,每个集合的代表节点(或其路径上 sdom 最小的节点)
|
||||
|
||||
// ==========================================================
|
||||
// 辅助计算函数 (私有)
|
||||
// ==========================================================
|
||||
|
||||
// 计算基本块的逆后序遍历 (Reverse Post Order, RPO) 顺序
|
||||
// RPO 用于优化支配者计算和 LT 算法的效率
|
||||
std::vector<BasicBlock*> computeReversePostOrder(Function* F);
|
||||
|
||||
// Lengauer-Tarjan 算法特定的辅助 DFS 函数
|
||||
// 用于初始化 dfnum_map, vertex_vec, parent_map
|
||||
void dfs_lt_helper(BasicBlock* u);
|
||||
|
||||
// 结合了并查集的 Find 操作和 LT 算法的 Eval 操作
|
||||
// 用于在路径压缩时更新 label,找到路径上 sdom 最小的节点
|
||||
BasicBlock* evalAndCompress_lt_helper(BasicBlock* i);
|
||||
|
||||
// 并查集的 Link 操作
|
||||
// 将 v_child 挂载到 u_parent 的并查集树下
|
||||
void link_lt_helper(BasicBlock* u_parent, BasicBlock* v_child);
|
||||
};
|
||||
|
||||
|
||||
// 支配树分析遍
|
||||
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
|
||||
618
src/include/midend/Pass/Analysis/Loop.h
Normal file
618
src/include/midend/Pass/Analysis/Loop.h
Normal file
@ -0,0 +1,618 @@
|
||||
#pragma once
|
||||
|
||||
#include "Dom.h"
|
||||
#include "IR.h"
|
||||
#include "Pass.h"
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 前向声明
|
||||
class LoopAnalysisResult;
|
||||
class AliasAnalysisResult;
|
||||
class SideEffectAnalysisResult;
|
||||
|
||||
/**
|
||||
* @brief 表示一个识别出的循环。
|
||||
*/
|
||||
class Loop {
|
||||
private:
|
||||
static int NextLoopID; // 静态变量用于分配唯一ID
|
||||
int LoopID;
|
||||
public:
|
||||
// 构造函数:指定循环头
|
||||
Loop(BasicBlock *header) : Header(header), LoopID(NextLoopID++) {}
|
||||
|
||||
// 获取循环头
|
||||
BasicBlock *getHeader() const { return Header; }
|
||||
|
||||
// 获取循环的名称 (基于ID)
|
||||
std::string getName() const { return "loop_" + std::to_string(LoopID); }
|
||||
// 获取循环体包含的所有基本块
|
||||
const std::set<BasicBlock *> &getBlocks() const { return LoopBlocks; }
|
||||
|
||||
// 获取循环的出口基本块(即从循环内部跳转到循环外部的基本块)
|
||||
const std::set<BasicBlock *> &getExitBlocks() const { return ExitBlocks; }
|
||||
|
||||
// 获取循环前置块(如果存在),可以为 nullptr
|
||||
BasicBlock *getPreHeader() const { return PreHeader; }
|
||||
|
||||
// 获取直接包含此循环的父循环(如果存在),可以为 nullptr
|
||||
Loop *getParentLoop() const { return ParentLoop; }
|
||||
|
||||
// 获取直接嵌套在此循环内的子循环
|
||||
const std::vector<Loop *> &getNestedLoops() const { return NestedLoops; }
|
||||
|
||||
// 获取循环的层级 (0 表示最外层循环,1 表示嵌套一层,以此类推)
|
||||
int getLoopLevel() const { return Level; }
|
||||
|
||||
// 检查一个基本块是否属于当前循环
|
||||
bool contains(BasicBlock *BB) const { return LoopBlocks.count(BB); }
|
||||
|
||||
// 判断当前循环是否是最内层循环 (没有嵌套子循环)
|
||||
bool isInnermost() const { return NestedLoops.empty(); }
|
||||
|
||||
// 获取循环的深度(从最外层开始计算)
|
||||
int getLoopDepth() const { return Level + 1; }
|
||||
|
||||
// 获取循环体的大小(基本块数量)
|
||||
size_t getLoopSize() const { return LoopBlocks.size(); }
|
||||
|
||||
// 检查循环是否有唯一的外部前驱(即是否有前置块)
|
||||
bool hasUniquePreHeader() const { return PreHeader != nullptr; }
|
||||
|
||||
// 检查循环是否是最外层循环(没有父循环)
|
||||
bool isOutermost() const { return getParentLoop() == nullptr; }
|
||||
|
||||
// 获取循环的所有出口(从循环内到循环外的基本块)
|
||||
std::vector<BasicBlock*> getExitingBlocks() const {
|
||||
std::vector<BasicBlock*> exitingBlocks;
|
||||
for (BasicBlock* bb : LoopBlocks) {
|
||||
for (BasicBlock* succ : bb->getSuccessors()) {
|
||||
if (!contains(succ)) {
|
||||
exitingBlocks.push_back(bb);
|
||||
break; // 每个基本块只添加一次
|
||||
}
|
||||
}
|
||||
}
|
||||
return exitingBlocks;
|
||||
}
|
||||
|
||||
// 判断循环是否是简单循环(只有一个回边)
|
||||
bool isSimpleLoop() const {
|
||||
int backEdgeCount = 0;
|
||||
for (BasicBlock* pred : Header->getPredecessors()) {
|
||||
if (contains(pred)) {
|
||||
backEdgeCount++;
|
||||
}
|
||||
}
|
||||
return backEdgeCount == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有出口目标块 (循环外接收循环出口边的块)
|
||||
* 使用场景: 循环后置处理、phi节点分析
|
||||
*/
|
||||
std::vector<BasicBlock*> getExitTargetBlocks() const {
|
||||
std::set<BasicBlock*> exitTargetSet;
|
||||
for (BasicBlock* bb : LoopBlocks) {
|
||||
for (BasicBlock* succ : bb->getSuccessors()) {
|
||||
if (!contains(succ)) {
|
||||
exitTargetSet.insert(succ);
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::vector<BasicBlock*>(exitTargetSet.begin(), exitTargetSet.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算循环的"深度"相对于指定的祖先循环
|
||||
* 使用场景: 相对深度计算、嵌套分析
|
||||
*/
|
||||
int getRelativeDepth(Loop* ancestor) const {
|
||||
if (this == ancestor) return 0;
|
||||
|
||||
int depth = 0;
|
||||
Loop* current = this->ParentLoop;
|
||||
while (current && current != ancestor) {
|
||||
depth++;
|
||||
current = current->ParentLoop;
|
||||
}
|
||||
|
||||
return current == ancestor ? depth : -1; // -1表示不是祖先关系
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查循环是否包含函数调用
|
||||
* 使用场景: 内联决策、副作用分析
|
||||
*/
|
||||
bool containsFunctionCalls() const {
|
||||
for (BasicBlock* bb : LoopBlocks) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
if (dynamic_cast<CallInst*>(inst.get())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查循环是否可能有副作用(基于副作用分析结果)
|
||||
* 使用场景: 循环优化决策、并行化分析
|
||||
*/
|
||||
bool mayHaveSideEffects(SideEffectAnalysisResult* sideEffectAnalysis) const;
|
||||
|
||||
/**
|
||||
* 检查循环是否访问全局内存(基于别名分析结果)
|
||||
* 使用场景: 并行化分析、缓存优化
|
||||
*/
|
||||
bool accessesGlobalMemory(AliasAnalysisResult* aliasAnalysis) const;
|
||||
|
||||
/**
|
||||
* 检查循环是否有可能的内存别名冲突
|
||||
* 使用场景: 向量化分析、并行化决策
|
||||
*/
|
||||
bool hasMemoryAliasConflicts(AliasAnalysisResult* aliasAnalysis) const;
|
||||
|
||||
/**
|
||||
* 估算循环的"热度" (基于嵌套深度和大小)
|
||||
* 使用场景: 优化优先级、资源分配
|
||||
*/
|
||||
double getLoopHotness() const {
|
||||
// 简单的热度估算: 深度权重 + 大小惩罚
|
||||
double hotness = std::pow(2.0, Level); // 深度越深越热
|
||||
hotness /= std::sqrt(LoopBlocks.size()); // 大小越大相对热度降低
|
||||
return hotness;
|
||||
}
|
||||
|
||||
// --- 供 LoopAnalysisPass 内部调用的方法,用于构建 Loop 对象 ---
|
||||
void addBlock(BasicBlock *BB) { LoopBlocks.insert(BB); }
|
||||
void addExitBlock(BasicBlock *BB) { ExitBlocks.insert(BB); }
|
||||
void setPreHeader(BasicBlock *BB) { PreHeader = BB; }
|
||||
void setParentLoop(Loop *loop) { ParentLoop = loop; }
|
||||
void addNestedLoop(Loop *loop) { NestedLoops.push_back(loop); }
|
||||
void setLoopLevel(int level) { Level = level; }
|
||||
void clearNestedLoops() { NestedLoops.clear(); }
|
||||
private:
|
||||
BasicBlock *Header; // 循环头基本块
|
||||
std::set<BasicBlock *> LoopBlocks; // 循环体包含的基本块集合
|
||||
std::set<BasicBlock *> ExitBlocks; // 循环出口基本块集合
|
||||
BasicBlock *PreHeader = nullptr; // 循环前置块 (Optional)
|
||||
Loop *ParentLoop = nullptr; // 父循环 (用于嵌套)
|
||||
std::vector<Loop *> NestedLoops; // 嵌套的子循环
|
||||
int Level = -1; // 循环的层级,-1表示未计算
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 循环分析结果类。
|
||||
* 包含一个函数中所有识别出的循环,并提供高效的查询缓存机制。
|
||||
*/
|
||||
class LoopAnalysisResult : public AnalysisResultBase {
|
||||
public:
|
||||
LoopAnalysisResult(Function *F) : AssociatedFunction(F) {}
|
||||
~LoopAnalysisResult() override = default;
|
||||
|
||||
// ========== 缓存统计结构 ==========
|
||||
struct CacheStats {
|
||||
size_t innermostLoopsCached;
|
||||
size_t outermostLoopsCached;
|
||||
size_t loopsByDepthCached;
|
||||
size_t containingLoopsCached;
|
||||
size_t allNestedLoopsCached;
|
||||
size_t totalCachedQueries;
|
||||
};
|
||||
|
||||
private:
|
||||
// ========== 高频查询缓存 ==========
|
||||
mutable std::optional<std::vector<Loop*>> cachedInnermostLoops;
|
||||
mutable std::optional<std::vector<Loop*>> cachedOutermostLoops;
|
||||
mutable std::optional<int> cachedMaxDepth;
|
||||
mutable std::optional<size_t> cachedLoopCount;
|
||||
mutable std::map<int, std::vector<Loop*>> cachedLoopsByDepth;
|
||||
|
||||
// ========== 中频查询缓存 ==========
|
||||
mutable std::map<BasicBlock*, Loop*> cachedInnermostContainingLoop;
|
||||
mutable std::map<Loop*, std::set<Loop*>> cachedAllNestedLoops; // 递归嵌套
|
||||
mutable std::map<BasicBlock*, std::vector<Loop*>> cachedAllContainingLoops;
|
||||
|
||||
// ========== 缓存状态管理 ==========
|
||||
mutable bool cacheValid = true;
|
||||
|
||||
// 内部辅助方法
|
||||
void invalidateCache() const {
|
||||
cachedInnermostLoops.reset();
|
||||
cachedOutermostLoops.reset();
|
||||
cachedMaxDepth.reset();
|
||||
cachedLoopCount.reset();
|
||||
cachedLoopsByDepth.clear();
|
||||
cachedInnermostContainingLoop.clear();
|
||||
cachedAllNestedLoops.clear();
|
||||
cachedAllContainingLoops.clear();
|
||||
cacheValid = false;
|
||||
}
|
||||
|
||||
void ensureCacheValid() const {
|
||||
if (!cacheValid) {
|
||||
// 重新计算基础缓存
|
||||
computeBasicCache();
|
||||
cacheValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
void computeBasicCache() const {
|
||||
// 计算最内层循环
|
||||
if (!cachedInnermostLoops) {
|
||||
cachedInnermostLoops = std::vector<Loop*>();
|
||||
for (const auto& loop : AllLoops) {
|
||||
if (loop->isInnermost()) {
|
||||
cachedInnermostLoops->push_back(loop.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 计算最外层循环
|
||||
if (!cachedOutermostLoops) {
|
||||
cachedOutermostLoops = std::vector<Loop*>();
|
||||
for (const auto& loop : AllLoops) {
|
||||
if (loop->isOutermost()) {
|
||||
cachedOutermostLoops->push_back(loop.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 计算最大深度
|
||||
if (!cachedMaxDepth) {
|
||||
int maxDepth = 0;
|
||||
for (const auto& loop : AllLoops) {
|
||||
maxDepth = std::max(maxDepth, loop->getLoopDepth());
|
||||
}
|
||||
cachedMaxDepth = maxDepth;
|
||||
}
|
||||
|
||||
// 计算循环总数
|
||||
if (!cachedLoopCount) {
|
||||
cachedLoopCount = AllLoops.size();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// ========== 基础接口 ==========
|
||||
|
||||
// 添加一个识别出的循环到结果中
|
||||
void addLoop(std::unique_ptr<Loop> loop) {
|
||||
invalidateCache(); // 添加新循环时失效缓存
|
||||
AllLoops.push_back(std::move(loop));
|
||||
LoopMap[AllLoops.back()->getHeader()] = AllLoops.back().get();
|
||||
}
|
||||
|
||||
// 获取所有识别出的循环(unique_ptr 管理内存)
|
||||
const std::vector<std::unique_ptr<Loop>> &getAllLoops() const { return AllLoops; }
|
||||
|
||||
// ========== 高频查询接口 ==========
|
||||
|
||||
/**
|
||||
* 获取所有最内层循环 - 循环优化的主要目标
|
||||
* 使用场景: 循环展开、向量化、循环不变量外提
|
||||
*/
|
||||
const std::vector<Loop*>& getInnermostLoops() const {
|
||||
ensureCacheValid();
|
||||
if (!cachedInnermostLoops) {
|
||||
cachedInnermostLoops = std::vector<Loop*>();
|
||||
for (const auto& loop : AllLoops) {
|
||||
if (loop->isInnermost()) {
|
||||
cachedInnermostLoops->push_back(loop.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
return *cachedInnermostLoops;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有最外层循环
|
||||
* 使用场景: 循环树遍历、整体优化策略
|
||||
*/
|
||||
const std::vector<Loop*>& getOutermostLoops() const {
|
||||
ensureCacheValid();
|
||||
if (!cachedOutermostLoops) {
|
||||
cachedOutermostLoops = std::vector<Loop*>();
|
||||
for (const auto& loop : AllLoops) {
|
||||
if (loop->isOutermost()) {
|
||||
cachedOutermostLoops->push_back(loop.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
return *cachedOutermostLoops;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定深度的所有循环
|
||||
* 使用场景: 分层优化、循环展开决策、并行化分析
|
||||
*/
|
||||
const std::vector<Loop*>& getLoopsAtDepth(int depth) const {
|
||||
ensureCacheValid();
|
||||
if (cachedLoopsByDepth.find(depth) == cachedLoopsByDepth.end()) {
|
||||
std::vector<Loop*> result;
|
||||
for (const auto& loop : AllLoops) {
|
||||
if (loop->getLoopDepth() == depth) {
|
||||
result.push_back(loop.get());
|
||||
}
|
||||
}
|
||||
cachedLoopsByDepth[depth] = std::move(result);
|
||||
}
|
||||
return cachedLoopsByDepth[depth];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最大循环嵌套深度
|
||||
* 使用场景: 优化预算分配、编译时间控制
|
||||
*/
|
||||
int getMaxLoopDepth() const {
|
||||
ensureCacheValid();
|
||||
if (!cachedMaxDepth) {
|
||||
int maxDepth = 0;
|
||||
for (const auto& loop : AllLoops) {
|
||||
maxDepth = std::max(maxDepth, loop->getLoopDepth());
|
||||
}
|
||||
cachedMaxDepth = maxDepth;
|
||||
}
|
||||
return *cachedMaxDepth;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取循环总数
|
||||
* 使用场景: 统计信息、优化决策
|
||||
*/
|
||||
size_t getLoopCount() const {
|
||||
ensureCacheValid();
|
||||
if (!cachedLoopCount) {
|
||||
cachedLoopCount = AllLoops.size();
|
||||
}
|
||||
return *cachedLoopCount;
|
||||
}
|
||||
|
||||
// 获取指定深度的循环数量
|
||||
size_t getLoopCountAtDepth(int depth) const {
|
||||
return getLoopsAtDepth(depth).size();
|
||||
}
|
||||
|
||||
// 检查函数是否包含循环
|
||||
bool hasLoops() const { return !AllLoops.empty(); }
|
||||
|
||||
// ========== 中频查询接口 ==========
|
||||
|
||||
/**
|
||||
* 获取包含指定基本块的最内层循环
|
||||
* 使用场景: 活跃性分析、寄存器分配、指令调度
|
||||
*/
|
||||
Loop* getInnermostContainingLoop(BasicBlock* BB) const {
|
||||
ensureCacheValid();
|
||||
if (cachedInnermostContainingLoop.find(BB) == cachedInnermostContainingLoop.end()) {
|
||||
Loop* result = nullptr;
|
||||
int maxDepth = -1;
|
||||
for (const auto& loop : AllLoops) {
|
||||
if (loop->contains(BB) && loop->getLoopDepth() > maxDepth) {
|
||||
result = loop.get();
|
||||
maxDepth = loop->getLoopDepth();
|
||||
}
|
||||
}
|
||||
cachedInnermostContainingLoop[BB] = result;
|
||||
}
|
||||
return cachedInnermostContainingLoop[BB];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取包含指定基本块的所有循环 (从外到内排序)
|
||||
* 使用场景: 循环间优化、依赖分析
|
||||
*/
|
||||
const std::vector<Loop*>& getAllContainingLoops(BasicBlock* BB) const {
|
||||
ensureCacheValid();
|
||||
if (cachedAllContainingLoops.find(BB) == cachedAllContainingLoops.end()) {
|
||||
std::vector<Loop*> result;
|
||||
for (const auto& loop : AllLoops) {
|
||||
if (loop->contains(BB)) {
|
||||
result.push_back(loop.get());
|
||||
}
|
||||
}
|
||||
// 按深度排序 (外层到内层)
|
||||
std::sort(result.begin(), result.end(),
|
||||
[](Loop* a, Loop* b) { return a->getLoopDepth() < b->getLoopDepth(); });
|
||||
cachedAllContainingLoops[BB] = std::move(result);
|
||||
}
|
||||
return cachedAllContainingLoops[BB];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定循环的所有嵌套子循环 (递归)
|
||||
* 使用场景: 循环树分析、嵌套优化
|
||||
*/
|
||||
const std::set<Loop*>& getAllNestedLoops(Loop* loop) const {
|
||||
ensureCacheValid();
|
||||
if (cachedAllNestedLoops.find(loop) == cachedAllNestedLoops.end()) {
|
||||
std::set<Loop*> result;
|
||||
std::function<void(Loop*)> collectNested = [&](Loop* current) {
|
||||
for (Loop* nested : current->getNestedLoops()) {
|
||||
result.insert(nested);
|
||||
collectNested(nested); // 递归收集
|
||||
}
|
||||
};
|
||||
collectNested(loop);
|
||||
cachedAllNestedLoops[loop] = std::move(result);
|
||||
}
|
||||
return cachedAllNestedLoops[loop];
|
||||
}
|
||||
|
||||
// ========== 利用别名和副作用分析的查询接口 ==========
|
||||
|
||||
/**
|
||||
* 获取所有纯循环(无副作用的循环)
|
||||
* 并行化、循环优化
|
||||
*/
|
||||
std::vector<Loop*> getPureLoops(SideEffectAnalysisResult* sideEffectAnalysis) const {
|
||||
std::vector<Loop*> result;
|
||||
if (!sideEffectAnalysis) return result;
|
||||
|
||||
for (const auto& loop : AllLoops) {
|
||||
if (!loop->mayHaveSideEffects(sideEffectAnalysis)) {
|
||||
result.push_back(loop.get());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有只访问局部内存的循环
|
||||
* 缓存优化、局部性分析
|
||||
*/
|
||||
std::vector<Loop*> getLocalMemoryLoops(AliasAnalysisResult* aliasAnalysis) const {
|
||||
std::vector<Loop*> result;
|
||||
if (!aliasAnalysis) return result;
|
||||
|
||||
for (const auto& loop : AllLoops) {
|
||||
if (!loop->accessesGlobalMemory(aliasAnalysis)) {
|
||||
result.push_back(loop.get());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有无内存别名冲突的循环
|
||||
* 向量化、并行化
|
||||
*/
|
||||
std::vector<Loop*> getNoAliasConflictLoops(AliasAnalysisResult* aliasAnalysis) const {
|
||||
std::vector<Loop*> result;
|
||||
if (!aliasAnalysis) return result;
|
||||
|
||||
for (const auto& loop : AllLoops) {
|
||||
if (!loop->hasMemoryAliasConflicts(aliasAnalysis)) {
|
||||
result.push_back(loop.get());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ========== 低频查询接口(不缓存) ==========
|
||||
|
||||
/**
|
||||
* 检查两个循环是否有嵌套关系
|
||||
* 循环间依赖分析
|
||||
*/
|
||||
bool isNestedLoop(Loop* inner, Loop* outer) const {
|
||||
if (inner == outer) return false;
|
||||
|
||||
Loop* current = inner->getParentLoop();
|
||||
while (current) {
|
||||
if (current == outer) return true;
|
||||
current = current->getParentLoop();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取两个循环的最近公共祖先循环
|
||||
* 循环融合分析、优化范围确定
|
||||
*/
|
||||
Loop* getLowestCommonAncestor(Loop* loop1, Loop* loop2) const {
|
||||
if (!loop1 || !loop2) return nullptr;
|
||||
if (loop1 == loop2) return loop1;
|
||||
|
||||
// 收集loop1的所有祖先
|
||||
std::set<Loop*> ancestors1;
|
||||
Loop* current = loop1;
|
||||
while (current) {
|
||||
ancestors1.insert(current);
|
||||
current = current->getParentLoop();
|
||||
}
|
||||
|
||||
// 查找loop2祖先链中第一个在ancestors1中的循环
|
||||
current = loop2;
|
||||
while (current) {
|
||||
if (ancestors1.count(current)) {
|
||||
return current;
|
||||
}
|
||||
current = current->getParentLoop();
|
||||
}
|
||||
|
||||
return nullptr; // 没有公共祖先
|
||||
}
|
||||
|
||||
// 通过循环头获取 Loop 对象
|
||||
Loop *getLoopForHeader(BasicBlock *header) const {
|
||||
auto it = LoopMap.find(header);
|
||||
return (it != LoopMap.end()) ? it->second : nullptr;
|
||||
}
|
||||
|
||||
// 通过某个基本块获取包含它的最内层循环 (向后兼容接口)
|
||||
Loop *getLoopContainingBlock(BasicBlock *BB) const {
|
||||
return getInnermostContainingLoop(BB);
|
||||
}
|
||||
|
||||
// ========== 缓存管理接口 ==========
|
||||
|
||||
/**
|
||||
* 手动失效缓存 (可删除)
|
||||
*/
|
||||
void invalidateQueryCache() const {
|
||||
invalidateCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存统计信息
|
||||
*/
|
||||
CacheStats getCacheStats() const {
|
||||
CacheStats stats = {};
|
||||
stats.innermostLoopsCached = cachedInnermostLoops.has_value() ? 1 : 0;
|
||||
stats.outermostLoopsCached = cachedOutermostLoops.has_value() ? 1 : 0;
|
||||
stats.loopsByDepthCached = cachedLoopsByDepth.size();
|
||||
stats.containingLoopsCached = cachedInnermostContainingLoop.size();
|
||||
stats.allNestedLoopsCached = cachedAllNestedLoops.size();
|
||||
stats.totalCachedQueries = stats.innermostLoopsCached + stats.outermostLoopsCached +
|
||||
stats.loopsByDepthCached + stats.containingLoopsCached +
|
||||
stats.allNestedLoopsCached;
|
||||
return stats;
|
||||
}
|
||||
|
||||
// 打印分析结果
|
||||
void print() const;
|
||||
void printBBSet(const std::string &prefix, const std::set<BasicBlock *> &s) const;
|
||||
void printLoopVector(const std::string &prefix, const std::vector<Loop *> &loops) const;
|
||||
|
||||
private:
|
||||
Function *AssociatedFunction; // 结果关联的函数
|
||||
std::vector<std::unique_ptr<Loop>> AllLoops; // 所有识别出的循环
|
||||
std::map<BasicBlock *, Loop *> LoopMap; // 循环头到 Loop* 的映射,方便查找
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 循环分析遍。
|
||||
* 识别函数中的所有循环,并生成 LoopAnalysisResult。
|
||||
*/
|
||||
class LoopAnalysisPass : public AnalysisPass {
|
||||
public:
|
||||
// 唯一的 Pass ID,需要在 .cpp 文件中定义
|
||||
static void *ID;
|
||||
|
||||
LoopAnalysisPass() : AnalysisPass("LoopAnalysis", Pass::Granularity::Function) {}
|
||||
|
||||
// 实现 getPassID
|
||||
void *getPassID() const override { return &ID; }
|
||||
|
||||
// 核心运行方法:在每个函数上执行循环分析
|
||||
bool runOnFunction(Function *F, AnalysisManager &AM) override;
|
||||
|
||||
// 获取分析结果
|
||||
std::unique_ptr<AnalysisResultBase> getResult() override { return std::move(CurrentResult); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<LoopAnalysisResult> CurrentResult; // 当前函数的分析结果
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
360
src/include/midend/Pass/Analysis/LoopCharacteristics.h
Normal file
360
src/include/midend/Pass/Analysis/LoopCharacteristics.h
Normal file
@ -0,0 +1,360 @@
|
||||
#pragma once
|
||||
|
||||
#include "Dom.h" // 支配树分析依赖
|
||||
#include "Loop.h" // 循环分析依赖
|
||||
#include "Liveness.h" // 活跃性分析依赖
|
||||
#include "AliasAnalysis.h" // 别名分析依赖
|
||||
#include "SideEffectAnalysis.h" // 副作用分析依赖
|
||||
#include "CallGraphAnalysis.h" // 调用图分析依赖
|
||||
#include "IR.h" // IR定义
|
||||
#include "Pass.h" // Pass框架
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 前向声明
|
||||
class LoopCharacteristicsResult;
|
||||
|
||||
enum IVKind {
|
||||
kBasic, // 基本归纳变量
|
||||
kLinear, // 线性归纳变量
|
||||
kCmplx // 复杂派生归纳变量
|
||||
} ; // 归纳变量类型
|
||||
|
||||
struct InductionVarInfo {
|
||||
Value* div; // 派生归纳变量的指令
|
||||
Value* base = nullptr; // 其根phi或BIV或DIV
|
||||
std::pair<Value*, Value*> Multibase = {nullptr, nullptr}; // 多个BIV
|
||||
Instruction::Kind Instkind; // 操作类型
|
||||
int factor = 1; // 系数(如i*2+3的2)
|
||||
int offset = 0; // 常量偏移
|
||||
bool valid; // 是否线性可归约
|
||||
IVKind ivkind; // 归纳变量类型
|
||||
|
||||
|
||||
static std::unique_ptr<InductionVarInfo> createBasicBIV(Value* v, Instruction::Kind kind, Value* base = nullptr, int factor = 1, int offset = 0) {
|
||||
return std::make_unique<InductionVarInfo>(
|
||||
InductionVarInfo{v, base, {nullptr, nullptr}, kind, factor, offset, true, IVKind::kBasic}
|
||||
);
|
||||
}
|
||||
|
||||
static std::unique_ptr<InductionVarInfo> createSingleDIV(Value* v, Instruction::Kind kind, Value* base = nullptr, int factor = 1, int offset = 0) {
|
||||
return std::make_unique<InductionVarInfo>(
|
||||
InductionVarInfo{v, base, {nullptr, nullptr}, kind, factor, offset, true, IVKind::kLinear}
|
||||
);
|
||||
}
|
||||
|
||||
static std::unique_ptr<InductionVarInfo> createDoubleDIV(Value* v, Instruction::Kind kind, Value* base1 = nullptr, Value* base2 = nullptr, int factor = 1, int offset = 0) {
|
||||
return std::make_unique<InductionVarInfo>(
|
||||
InductionVarInfo{v, nullptr, {base1, base2}, kind, factor, offset, false, IVKind::kCmplx}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 循环特征信息结构 - 基础循环分析阶段
|
||||
* 存储循环的基本特征信息,为后续精确分析提供基础
|
||||
*/
|
||||
struct LoopCharacteristics {
|
||||
Loop* loop; // 关联的循环对象
|
||||
|
||||
// ========== 基础循环形式分析 ==========
|
||||
bool isCountingLoop; // 是否为计数循环 (for i=0; i<n; i++)
|
||||
bool isSimpleForLoop; // 是否为简单for循环
|
||||
bool hasComplexControlFlow; // 是否有复杂控制流 (break, continue)
|
||||
bool isInnermost; // 是否为最内层循环
|
||||
|
||||
// ========== 归纳变量分析 ==========
|
||||
|
||||
// ========== 基础循环不变量分析 ==========
|
||||
std::unordered_set<Value*> loopInvariants; // 循环不变量
|
||||
std::unordered_set<Instruction*> invariantInsts; // 可提升的不变指令
|
||||
|
||||
std::vector<std::unique_ptr<InductionVarInfo>> InductionVars; // 归纳变量
|
||||
|
||||
// ========== 基础边界分析 ==========
|
||||
std::optional<int> staticTripCount; // 静态循环次数(如果可确定)
|
||||
bool hasKnownBounds; // 是否有已知边界
|
||||
|
||||
// ========== 基础纯度和副作用分析 ==========
|
||||
bool isPure; // 是否为纯循环(无副作用)
|
||||
bool accessesOnlyLocalMemory; // 是否只访问局部内存
|
||||
bool hasNoMemoryAliasConflicts; // 是否无内存别名冲突
|
||||
|
||||
// ========== 基础内存访问模式分析 ==========
|
||||
struct MemoryAccessPattern {
|
||||
std::vector<Instruction*> loadInsts; // load指令列表
|
||||
std::vector<Instruction*> storeInsts; // store指令列表
|
||||
bool isArrayParameter; // 是否为数组参数访问
|
||||
bool isGlobalArray; // 是否为全局数组访问
|
||||
bool hasConstantIndices; // 是否使用常量索引
|
||||
};
|
||||
std::map<Value*, MemoryAccessPattern> memoryPatterns; // 内存访问模式
|
||||
|
||||
// ========== 基础性能特征 ==========
|
||||
size_t instructionCount; // 循环体指令数
|
||||
size_t memoryOperationCount; // 内存操作数
|
||||
size_t arithmeticOperationCount; // 算术操作数
|
||||
double computeToMemoryRatio; // 计算与内存操作比率
|
||||
|
||||
// ========== 基础优化提示 ==========
|
||||
bool benefitsFromUnrolling; // 是否适合循环展开
|
||||
int suggestedUnrollFactor; // 建议的展开因子
|
||||
|
||||
// 构造函数 - 简化的基础分析初始化
|
||||
LoopCharacteristics(Loop* l) : loop(l),
|
||||
isCountingLoop(false), isSimpleForLoop(false), hasComplexControlFlow(false),
|
||||
isInnermost(false), hasKnownBounds(false), isPure(false),
|
||||
accessesOnlyLocalMemory(false), hasNoMemoryAliasConflicts(false),
|
||||
benefitsFromUnrolling(false), suggestedUnrollFactor(1),
|
||||
instructionCount(0), memoryOperationCount(0),
|
||||
arithmeticOperationCount(0), computeToMemoryRatio(0.0) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 循环特征分析结果类
|
||||
* 包含函数中所有循环的特征信息,并提供查询接口
|
||||
*/
|
||||
class LoopCharacteristicsResult : public AnalysisResultBase {
|
||||
public:
|
||||
LoopCharacteristicsResult(Function *F) : AssociatedFunction(F) {}
|
||||
~LoopCharacteristicsResult() override = default;
|
||||
|
||||
// ========== 基础接口 ==========
|
||||
|
||||
/**
|
||||
* 添加循环特征信息
|
||||
*/
|
||||
void addLoopCharacteristics(std::unique_ptr<LoopCharacteristics> characteristics) {
|
||||
auto* loop = characteristics->loop;
|
||||
CharacteristicsMap[loop] = std::move(characteristics);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定循环的特征信息
|
||||
*/
|
||||
const LoopCharacteristics* getCharacteristics(Loop* loop) const {
|
||||
auto it = CharacteristicsMap.find(loop);
|
||||
return (it != CharacteristicsMap.end()) ? it->second.get() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有循环特征信息
|
||||
*/
|
||||
const std::map<Loop*, std::unique_ptr<LoopCharacteristics>>& getAllCharacteristics() const {
|
||||
return CharacteristicsMap;
|
||||
}
|
||||
|
||||
// ========== 核心查询接口 ==========
|
||||
|
||||
/**
|
||||
* 获取所有计数循环
|
||||
*/
|
||||
std::vector<Loop*> getCountingLoops() const {
|
||||
std::vector<Loop*> result;
|
||||
for (const auto& [loop, chars] : CharacteristicsMap) {
|
||||
if (chars->isCountingLoop) {
|
||||
result.push_back(loop);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有纯循环(无副作用)
|
||||
*/
|
||||
std::vector<Loop*> getPureLoops() const {
|
||||
std::vector<Loop*> result;
|
||||
for (const auto& [loop, chars] : CharacteristicsMap) {
|
||||
if (chars->isPure) {
|
||||
result.push_back(loop);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有只访问局部内存的循环
|
||||
*/
|
||||
std::vector<Loop*> getLocalMemoryOnlyLoops() const {
|
||||
std::vector<Loop*> result;
|
||||
for (const auto& [loop, chars] : CharacteristicsMap) {
|
||||
if (chars->accessesOnlyLocalMemory) {
|
||||
result.push_back(loop);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有无内存别名冲突的循环
|
||||
*/
|
||||
std::vector<Loop*> getNoAliasConflictLoops() const {
|
||||
std::vector<Loop*> result;
|
||||
for (const auto& [loop, chars] : CharacteristicsMap) {
|
||||
if (chars->hasNoMemoryAliasConflicts) {
|
||||
result.push_back(loop);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有适合展开的循环
|
||||
*/
|
||||
std::vector<Loop*> getUnrollingCandidates() const {
|
||||
std::vector<Loop*> result;
|
||||
for (const auto& [loop, chars] : CharacteristicsMap) {
|
||||
if (chars->benefitsFromUnrolling) {
|
||||
result.push_back(loop);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据热度排序循环 (用于优化优先级)
|
||||
*/
|
||||
std::vector<Loop*> getLoopsByHotness() const {
|
||||
std::vector<Loop*> result;
|
||||
for (const auto& [loop, chars] : CharacteristicsMap) {
|
||||
result.push_back(loop);
|
||||
}
|
||||
|
||||
// 按循环热度排序 (嵌套深度 + 循环次数 + 指令数)
|
||||
std::sort(result.begin(), result.end(), [](Loop* a, Loop* b) {
|
||||
double hotnessA = a->getLoopHotness();
|
||||
double hotnessB = b->getLoopHotness();
|
||||
return hotnessA > hotnessB; // 降序排列
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ========== 基础统计接口 ==========
|
||||
|
||||
/**
|
||||
* 获取基础优化统计信息
|
||||
*/
|
||||
struct BasicOptimizationStats {
|
||||
size_t totalLoops;
|
||||
size_t countingLoops;
|
||||
size_t unrollingCandidates;
|
||||
size_t pureLoops;
|
||||
size_t localMemoryOnlyLoops;
|
||||
size_t noAliasConflictLoops;
|
||||
double avgInstructionCount;
|
||||
double avgComputeMemoryRatio;
|
||||
};
|
||||
|
||||
BasicOptimizationStats getOptimizationStats() const {
|
||||
BasicOptimizationStats stats = {};
|
||||
stats.totalLoops = CharacteristicsMap.size();
|
||||
|
||||
size_t totalInstructions = 0;
|
||||
double totalComputeMemoryRatio = 0.0;
|
||||
|
||||
for (const auto& [loop, chars] : CharacteristicsMap) {
|
||||
if (chars->isCountingLoop) stats.countingLoops++;
|
||||
if (chars->benefitsFromUnrolling) stats.unrollingCandidates++;
|
||||
if (chars->isPure) stats.pureLoops++;
|
||||
if (chars->accessesOnlyLocalMemory) stats.localMemoryOnlyLoops++;
|
||||
if (chars->hasNoMemoryAliasConflicts) stats.noAliasConflictLoops++;
|
||||
|
||||
totalInstructions += chars->instructionCount;
|
||||
totalComputeMemoryRatio += chars->computeToMemoryRatio;
|
||||
}
|
||||
|
||||
if (stats.totalLoops > 0) {
|
||||
stats.avgInstructionCount = static_cast<double>(totalInstructions) / stats.totalLoops;
|
||||
stats.avgComputeMemoryRatio = totalComputeMemoryRatio / stats.totalLoops;
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
// 打印分析结果
|
||||
void print() const;
|
||||
|
||||
private:
|
||||
Function *AssociatedFunction; // 关联的函数
|
||||
std::map<Loop*, std::unique_ptr<LoopCharacteristics>> CharacteristicsMap; // 循环特征映射
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 基础循环特征分析遍
|
||||
* 在循环规范化前执行,进行基础的循环特征分析,为后续精确分析提供基础
|
||||
*/
|
||||
class LoopCharacteristicsPass : public AnalysisPass {
|
||||
public:
|
||||
// 唯一的 Pass ID
|
||||
static void *ID;
|
||||
|
||||
LoopCharacteristicsPass() : AnalysisPass("LoopCharacteristics", Pass::Granularity::Function) {}
|
||||
|
||||
// 实现 getPassID
|
||||
void *getPassID() const override { return &ID; }
|
||||
|
||||
// 核心运行方法
|
||||
bool runOnFunction(Function *F, AnalysisManager &AM) override;
|
||||
|
||||
// 获取分析结果
|
||||
std::unique_ptr<AnalysisResultBase> getResult() override { return std::move(CurrentResult); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<LoopCharacteristicsResult> CurrentResult;
|
||||
|
||||
// ========== 缓存的分析结果 ==========
|
||||
LoopAnalysisResult* loopAnalysis; // 循环结构分析结果
|
||||
AliasAnalysisResult* aliasAnalysis; // 别名分析结果
|
||||
SideEffectAnalysisResult* sideEffectAnalysis; // 副作用分析结果
|
||||
|
||||
// ========== 核心分析方法 ==========
|
||||
void analyzeLoop(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 基础循环形式分析
|
||||
void analyzeLoopForm(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 基础性能指标计算
|
||||
void computePerformanceMetrics(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 基础纯度和副作用分析
|
||||
void analyzePurityAndSideEffects(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 基础归纳变量识别
|
||||
void identifyBasicInductionVariables(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 循环不变量识别
|
||||
void identifyBasicLoopInvariants(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 基础边界分析
|
||||
void analyzeBasicLoopBounds(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 基础内存访问模式分析
|
||||
void analyzeBasicMemoryAccessPatterns(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 基础优化评估
|
||||
void evaluateBasicOptimizationOpportunities(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// ========== 辅助方法 ==========
|
||||
bool isClassicLoopInvariant(Value* val, Loop* loop, const std::unordered_set<Value*>& invariants);
|
||||
void findDerivedInductionVars(Value* root,
|
||||
Value* base, // 只传单一BIV base
|
||||
Loop* loop,
|
||||
std::vector<std::unique_ptr<InductionVarInfo>>& ivs,
|
||||
std::set<Value*>& visited
|
||||
);
|
||||
bool isBasicInductionVariable(Value* val, Loop* loop);
|
||||
// ========== 循环不变量分析辅助方法 ==========
|
||||
bool isInvariantOperands(Instruction* inst, Loop* loop, const std::unordered_set<Value*>& invariants);
|
||||
bool isMemoryLocationModifiedInLoop(Value* ptr, Loop* loop);
|
||||
bool isMemoryLocationLoadedInLoop(Value* ptr, Loop* loop, Instruction* excludeInst = nullptr);
|
||||
bool isPureFunction(Function* calledFunc);
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
250
src/include/midend/Pass/Analysis/LoopVectorization.h
Normal file
250
src/include/midend/Pass/Analysis/LoopVectorization.h
Normal file
@ -0,0 +1,250 @@
|
||||
#pragma once
|
||||
|
||||
#include "Pass.h"
|
||||
#include "Loop.h"
|
||||
#include "LoopCharacteristics.h"
|
||||
#include "AliasAnalysis.h"
|
||||
#include "SideEffectAnalysis.h"
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
/**
|
||||
* @brief 依赖类型枚举 - 只考虑真正影响并行性的依赖
|
||||
*
|
||||
* 依赖类型分析说明:
|
||||
* - TRUE_DEPENDENCE (RAW): 真依赖,必须保持原始执行顺序,是最关键的依赖
|
||||
* - ANTI_DEPENDENCE (WAR): 反依赖,影响指令重排序,可通过寄存器重命名等技术缓解
|
||||
* - OUTPUT_DEPENDENCE (WAW): 输出依赖,相对较少但需要考虑,可通过变量私有化解决
|
||||
*
|
||||
*/
|
||||
enum class DependenceType {
|
||||
TRUE_DEPENDENCE, // 真依赖 (RAW) - 读后写流依赖,最重要的依赖类型
|
||||
ANTI_DEPENDENCE, // 反依赖 (WAR) - 写后读反向依赖,影响指令重排序
|
||||
OUTPUT_DEPENDENCE // 输出依赖 (WAW) - 写后写,相对较少但需要考虑
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 依赖向量 - 表示两个内存访问之间的迭代距离
|
||||
* 例如:a[i] 和 a[i+1] 之间的依赖向量是 [1]
|
||||
* a[i][j] 和 a[i+1][j-2] 之间的依赖向量是 [1,-2]
|
||||
*/
|
||||
struct DependenceVector {
|
||||
std::vector<int> distances; // 每个循环层次的依赖距离
|
||||
bool isConstant; // 是否为常量距离
|
||||
bool isKnown; // 是否已知距离
|
||||
|
||||
DependenceVector(size_t loopDepth) : distances(loopDepth, 0), isConstant(false), isKnown(false) {}
|
||||
|
||||
// 检查是否为循环无关依赖
|
||||
bool isLoopIndependent() const {
|
||||
for (int dist : distances) {
|
||||
if (dist != 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 获取词典序方向向量
|
||||
std::vector<int> getDirectionVector() const;
|
||||
|
||||
// 检查是否可以通过向量化处理
|
||||
bool isVectorizationSafe() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 精确依赖关系 - 包含依赖向量的详细依赖信息
|
||||
*/
|
||||
struct PreciseDependence {
|
||||
Instruction* source;
|
||||
Instruction* sink;
|
||||
DependenceType type;
|
||||
DependenceVector dependenceVector;
|
||||
Value* memoryLocation;
|
||||
|
||||
// 并行化相关
|
||||
bool allowsParallelization; // 是否允许并行化
|
||||
bool requiresSynchronization; // 是否需要同步
|
||||
bool isReductionDependence; // 是否为归约依赖
|
||||
|
||||
PreciseDependence(size_t loopDepth) : dependenceVector(loopDepth),
|
||||
allowsParallelization(true), requiresSynchronization(false), isReductionDependence(false) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 向量化分析信息 - 暂时搁置,保留接口
|
||||
*/
|
||||
struct VectorizationAnalysis {
|
||||
bool isVectorizable; // 固定为false,暂不支持
|
||||
int suggestedVectorWidth; // 固定为1
|
||||
std::vector<std::string> preventingFactors; // 阻止向量化的因素
|
||||
|
||||
VectorizationAnalysis() : isVectorizable(false), suggestedVectorWidth(1) {
|
||||
preventingFactors.push_back("Vectorization temporarily disabled");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 并行化分析信息
|
||||
*/
|
||||
struct ParallelizationAnalysis {
|
||||
bool isParallelizable; // 是否可并行化
|
||||
int suggestedThreadCount; // 建议的线程数
|
||||
std::vector<std::string> preventingFactors; // 阻止并行化的因素
|
||||
|
||||
// 并行化模式
|
||||
enum ParallelizationType {
|
||||
NONE, // 不可并行化
|
||||
EMBARRASSINGLY_PARALLEL, // 完全并行
|
||||
REDUCTION_PARALLEL, // 归约并行
|
||||
PIPELINE_PARALLEL, // 流水线并行
|
||||
CONDITIONAL_PARALLEL // 条件并行
|
||||
} parallelType;
|
||||
|
||||
// 负载均衡
|
||||
bool hasLoadBalance; // 是否有良好的负载均衡
|
||||
bool isDynamicLoadBalanced; // 是否需要动态负载均衡
|
||||
double workComplexity; // 工作复杂度估计
|
||||
|
||||
// 同步需求
|
||||
bool requiresReduction; // 是否需要归约操作
|
||||
bool requiresBarrier; // 是否需要屏障同步
|
||||
std::set<Value*> sharedVariables; // 共享变量
|
||||
std::set<Value*> reductionVariables; // 归约变量
|
||||
std::set<Value*> privatizableVariables; // 可私有化变量
|
||||
|
||||
// 内存访问模式
|
||||
bool hasMemoryConflicts; // 是否有内存冲突
|
||||
bool hasReadOnlyAccess; // 是否只有只读访问
|
||||
bool hasIndependentAccess; // 是否有独立的内存访问
|
||||
|
||||
// 并行化收益评估
|
||||
double parallelizationBenefit; // 并行化收益估计 (0-1)
|
||||
size_t communicationCost; // 通信开销估计
|
||||
size_t synchronizationCost; // 同步开销估计
|
||||
|
||||
ParallelizationAnalysis() : isParallelizable(false), suggestedThreadCount(1), parallelType(NONE),
|
||||
hasLoadBalance(true), isDynamicLoadBalanced(false), workComplexity(0.0), requiresReduction(false),
|
||||
requiresBarrier(false), hasMemoryConflicts(false), hasReadOnlyAccess(false), hasIndependentAccess(false),
|
||||
parallelizationBenefit(0.0), communicationCost(0), synchronizationCost(0) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 循环向量化/并行化分析结果
|
||||
*/
|
||||
class LoopVectorizationResult : public AnalysisResultBase {
|
||||
private:
|
||||
Function* AssociatedFunction;
|
||||
std::map<Loop*, VectorizationAnalysis> VectorizationMap;
|
||||
std::map<Loop*, ParallelizationAnalysis> ParallelizationMap;
|
||||
std::map<Loop*, std::vector<PreciseDependence>> DependenceMap;
|
||||
|
||||
public:
|
||||
LoopVectorizationResult(Function* F) : AssociatedFunction(F) {}
|
||||
~LoopVectorizationResult() override = default;
|
||||
|
||||
// 基础接口
|
||||
void addVectorizationAnalysis(Loop* loop, VectorizationAnalysis analysis) {
|
||||
VectorizationMap[loop] = std::move(analysis);
|
||||
}
|
||||
|
||||
void addParallelizationAnalysis(Loop* loop, ParallelizationAnalysis analysis) {
|
||||
ParallelizationMap[loop] = std::move(analysis);
|
||||
}
|
||||
|
||||
void addDependenceAnalysis(Loop* loop, std::vector<PreciseDependence> dependences) {
|
||||
DependenceMap[loop] = std::move(dependences);
|
||||
}
|
||||
|
||||
// 查询接口
|
||||
const VectorizationAnalysis* getVectorizationAnalysis(Loop* loop) const {
|
||||
auto it = VectorizationMap.find(loop);
|
||||
return it != VectorizationMap.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
const ParallelizationAnalysis* getParallelizationAnalysis(Loop* loop) const {
|
||||
auto it = ParallelizationMap.find(loop);
|
||||
return it != ParallelizationMap.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
const std::vector<PreciseDependence>* getPreciseDependences(Loop* loop) const {
|
||||
auto it = DependenceMap.find(loop);
|
||||
return it != DependenceMap.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
// 统计接口
|
||||
size_t getVectorizableLoopCount() const;
|
||||
size_t getParallelizableLoopCount() const;
|
||||
|
||||
// 优化建议
|
||||
std::vector<Loop*> getVectorizationCandidates() const;
|
||||
std::vector<Loop*> getParallelizationCandidates() const;
|
||||
|
||||
// 打印分析结果
|
||||
void print() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 循环向量化/并行化分析遍
|
||||
* 在循环规范化后执行,进行精确的依赖向量分析和向量化/并行化可行性评估
|
||||
* 专注于并行化分析,向量化功能暂时搁置
|
||||
*/
|
||||
class LoopVectorizationPass : public AnalysisPass {
|
||||
public:
|
||||
// 唯一的 Pass ID
|
||||
static void *ID;
|
||||
|
||||
LoopVectorizationPass() : AnalysisPass("LoopVectorization", Pass::Granularity::Function) {}
|
||||
|
||||
// 实现 getPassID
|
||||
void *getPassID() const override { return &ID; }
|
||||
|
||||
// 核心运行方法
|
||||
bool runOnFunction(Function *F, AnalysisManager &AM) override;
|
||||
|
||||
// 获取分析结果
|
||||
std::unique_ptr<AnalysisResultBase> getResult() override { return std::move(CurrentResult); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<LoopVectorizationResult> CurrentResult;
|
||||
|
||||
// ========== 主要分析方法 ==========
|
||||
void analyzeLoop(Loop* loop, LoopCharacteristics* characteristics,
|
||||
AliasAnalysisResult* aliasAnalysis, SideEffectAnalysisResult* sideEffectAnalysis);
|
||||
|
||||
// ========== 依赖向量分析 ==========
|
||||
std::vector<PreciseDependence> computeDependenceVectors(Loop* loop, AliasAnalysisResult* aliasAnalysis);
|
||||
DependenceVector computeAccessDependence(Instruction* inst1, Instruction* inst2, Loop* loop);
|
||||
bool areAccessesAffinelyRelated(Value* ptr1, Value* ptr2, Loop* loop);
|
||||
|
||||
// ========== 向量化分析 (暂时搁置) ==========
|
||||
VectorizationAnalysis analyzeVectorizability(Loop* loop, const std::vector<PreciseDependence>& dependences,
|
||||
LoopCharacteristics* characteristics);
|
||||
|
||||
// ========== 并行化分析 ==========
|
||||
ParallelizationAnalysis analyzeParallelizability(Loop* loop, const std::vector<PreciseDependence>& dependences,
|
||||
LoopCharacteristics* characteristics);
|
||||
bool checkParallelizationLegality(Loop* loop, const std::vector<PreciseDependence>& dependences);
|
||||
int estimateOptimalThreadCount(Loop* loop, LoopCharacteristics* characteristics);
|
||||
ParallelizationAnalysis::ParallelizationType determineParallelizationType(Loop* loop,
|
||||
const std::vector<PreciseDependence>& dependences);
|
||||
|
||||
// ========== 并行化专用分析方法 ==========
|
||||
void analyzeReductionPatterns(Loop* loop, ParallelizationAnalysis* analysis);
|
||||
void analyzeMemoryAccessPatterns(Loop* loop, ParallelizationAnalysis* analysis, AliasAnalysisResult* aliasAnalysis);
|
||||
void estimateParallelizationBenefit(Loop* loop, ParallelizationAnalysis* analysis, LoopCharacteristics* characteristics);
|
||||
void identifyPrivatizableVariables(Loop* loop, ParallelizationAnalysis* analysis);
|
||||
void analyzeSynchronizationNeeds(Loop* loop, ParallelizationAnalysis* analysis, const std::vector<PreciseDependence>& dependences);
|
||||
|
||||
// ========== 辅助方法 ==========
|
||||
std::vector<int> extractInductionCoefficients(Value* ptr, Loop* loop);
|
||||
bool isConstantStride(Value* ptr, Loop* loop, int& stride);
|
||||
bool isIndependentMemoryAccess(Value* ptr1, Value* ptr2, Loop* loop);
|
||||
double estimateWorkComplexity(Loop* loop);
|
||||
bool hasReductionPattern(Value* var, Loop* loop);
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
137
src/include/midend/Pass/Analysis/SideEffectAnalysis.h
Normal file
137
src/include/midend/Pass/Analysis/SideEffectAnalysis.h
Normal file
@ -0,0 +1,137 @@
|
||||
#pragma once
|
||||
|
||||
#include "Pass.h"
|
||||
#include "IR.h"
|
||||
#include "AliasAnalysis.h"
|
||||
#include "CallGraphAnalysis.h"
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 副作用类型枚举
|
||||
enum class SideEffectType {
|
||||
NO_SIDE_EFFECT, // 无副作用
|
||||
MEMORY_WRITE, // 内存写入(store、memset)
|
||||
FUNCTION_CALL, // 函数调用(可能有任意副作用)
|
||||
IO_OPERATION, // I/O操作(printf、scanf等)
|
||||
UNKNOWN // 未知副作用
|
||||
};
|
||||
|
||||
// 副作用信息结构
|
||||
struct SideEffectInfo {
|
||||
SideEffectType type = SideEffectType::NO_SIDE_EFFECT;
|
||||
bool mayModifyGlobal = false; // 可能修改全局变量
|
||||
bool mayModifyMemory = false; // 可能修改内存
|
||||
bool mayCallFunction = false; // 可能调用函数
|
||||
bool isPure = true; // 是否为纯函数(无副作用且结果只依赖参数)
|
||||
|
||||
// 合并两个副作用信息
|
||||
SideEffectInfo merge(const SideEffectInfo& other) const {
|
||||
SideEffectInfo result;
|
||||
result.type = (type == SideEffectType::NO_SIDE_EFFECT) ? other.type : type;
|
||||
result.mayModifyGlobal = mayModifyGlobal || other.mayModifyGlobal;
|
||||
result.mayModifyMemory = mayModifyMemory || other.mayModifyMemory;
|
||||
result.mayCallFunction = mayCallFunction || other.mayCallFunction;
|
||||
result.isPure = isPure && other.isPure;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// 副作用分析结果类
|
||||
class SideEffectAnalysisResult : public AnalysisResultBase {
|
||||
private:
|
||||
// 指令级别的副作用信息
|
||||
std::unordered_map<Instruction*, SideEffectInfo> instructionSideEffects;
|
||||
|
||||
// 函数级别的副作用信息
|
||||
std::unordered_map<Function*, SideEffectInfo> functionSideEffects;
|
||||
|
||||
// 已知的SysY标准库函数副作用信息
|
||||
std::unordered_map<std::string, SideEffectInfo> knownFunctions;
|
||||
|
||||
public:
|
||||
SideEffectAnalysisResult();
|
||||
virtual ~SideEffectAnalysisResult() noexcept override = default;
|
||||
|
||||
// 获取指令的副作用信息
|
||||
const SideEffectInfo& getInstructionSideEffect(Instruction* inst) const;
|
||||
|
||||
// 获取函数的副作用信息
|
||||
const SideEffectInfo& getFunctionSideEffect(Function* func) const;
|
||||
|
||||
// 设置指令的副作用信息
|
||||
void setInstructionSideEffect(Instruction* inst, const SideEffectInfo& info);
|
||||
|
||||
// 设置函数的副作用信息
|
||||
void setFunctionSideEffect(Function* func, const SideEffectInfo& info);
|
||||
|
||||
// 检查指令是否有副作用
|
||||
bool hasSideEffect(Instruction* inst) const;
|
||||
|
||||
// 检查指令是否可能修改内存
|
||||
bool mayModifyMemory(Instruction* inst) const;
|
||||
|
||||
// 检查指令是否可能修改全局状态
|
||||
bool mayModifyGlobal(Instruction* inst) const;
|
||||
|
||||
// 检查函数是否为纯函数
|
||||
bool isPureFunction(Function* func) const;
|
||||
|
||||
// 获取已知函数的副作用信息
|
||||
const SideEffectInfo* getKnownFunctionSideEffect(const std::string& funcName) const;
|
||||
|
||||
// 初始化已知函数的副作用信息
|
||||
void initializeKnownFunctions();
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
// 副作用分析遍类 - Module级别分析
|
||||
class SysYSideEffectAnalysisPass : public AnalysisPass {
|
||||
public:
|
||||
// 静态成员,作为该遍的唯一ID
|
||||
static void* ID;
|
||||
|
||||
SysYSideEffectAnalysisPass() : AnalysisPass("SysYSideEffectAnalysis", Granularity::Module) {}
|
||||
|
||||
// 在模块上运行分析
|
||||
bool runOnModule(Module* M, AnalysisManager& AM) override;
|
||||
|
||||
// 获取分析结果
|
||||
std::unique_ptr<AnalysisResultBase> getResult() override;
|
||||
|
||||
// Pass 基类中的纯虚函数,必须实现
|
||||
void* getPassID() const override { return &ID; }
|
||||
|
||||
private:
|
||||
// 分析结果
|
||||
std::unique_ptr<SideEffectAnalysisResult> result;
|
||||
|
||||
// 调用图分析结果
|
||||
CallGraphAnalysisResult* callGraphAnalysis = nullptr;
|
||||
|
||||
// 分析单个函数的副作用(Module级别的内部方法)
|
||||
SideEffectInfo analyzeFunction(Function* func, AnalysisManager& AM);
|
||||
|
||||
// 分析单个指令的副作用
|
||||
SideEffectInfo analyzeInstruction(Instruction* inst, Function* currentFunc, AnalysisManager& AM);
|
||||
|
||||
// 分析函数调用指令的副作用(利用调用图)
|
||||
SideEffectInfo analyzeCallInstruction(CallInst* call, Function* currentFunc, AnalysisManager& AM);
|
||||
|
||||
// 分析存储指令的副作用
|
||||
SideEffectInfo analyzeStoreInstruction(StoreInst* store, Function* currentFunc, AnalysisManager& AM);
|
||||
|
||||
// 分析内存设置指令的副作用
|
||||
SideEffectInfo analyzeMemsetInstruction(MemsetInst* memset, Function* currentFunc, AnalysisManager& AM);
|
||||
|
||||
// 使用不动点算法分析递归函数群
|
||||
void analyzeStronglyConnectedComponent(const std::vector<Function*>& scc, AnalysisManager& AM);
|
||||
|
||||
// 检查函数间副作用传播的收敛性
|
||||
bool hasConverged(const std::unordered_map<Function*, SideEffectInfo>& oldEffects,
|
||||
const std::unordered_map<Function*, SideEffectInfo>& newEffects) const;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
20
src/include/midend/Pass/Optimize/BuildCFG.h
Normal file
20
src/include/midend/Pass/Optimize/BuildCFG.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "IR.h"
|
||||
#include "Pass.h"
|
||||
#include <queue>
|
||||
#include <set>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
class BuildCFG : public OptimizationPass {
|
||||
public:
|
||||
static void *ID;
|
||||
BuildCFG() : OptimizationPass("BuildCFG", 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; }
|
||||
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
@ -4,6 +4,8 @@
|
||||
#include "IR.h"
|
||||
#include "SysYIROptUtils.h"
|
||||
#include "Dom.h"
|
||||
#include "AliasAnalysis.h"
|
||||
#include "SideEffectAnalysis.h"
|
||||
#include <unordered_set>
|
||||
#include <queue>
|
||||
|
||||
@ -25,8 +27,12 @@ public:
|
||||
private:
|
||||
// 存储活跃指令的集合
|
||||
std::unordered_set<Instruction*> alive_insts;
|
||||
// 别名分析结果
|
||||
AliasAnalysisResult* aliasAnalysis = nullptr;
|
||||
// 副作用分析结果
|
||||
SideEffectAnalysisResult* sideEffectAnalysis = nullptr;
|
||||
|
||||
// 判断指令是否是“天然活跃”的(即总是保留的)
|
||||
// 判断指令是否是"天然活跃"的(即总是保留的)
|
||||
// inst: 要检查的指令
|
||||
// 返回值: 如果指令是天然活跃的,则为true,否则为false
|
||||
bool isAlive(Instruction* inst);
|
||||
@ -34,6 +40,9 @@ private:
|
||||
// 递归地将活跃指令及其依赖加入到 alive_insts 集合中
|
||||
// inst: 要标记为活跃的指令
|
||||
void addAlive(Instruction* inst);
|
||||
|
||||
// 检查Store指令是否可能有副作用(通过别名分析)
|
||||
bool mayHaveSideEffect(StoreInst* store);
|
||||
};
|
||||
|
||||
// DCE 优化遍类,继承自 OptimizationPass
|
||||
87
src/include/midend/Pass/Optimize/GVN.h
Normal file
87
src/include/midend/Pass/Optimize/GVN.h
Normal file
@ -0,0 +1,87 @@
|
||||
#pragma once
|
||||
|
||||
#include "Pass.h"
|
||||
#include "IR.h"
|
||||
#include "Dom.h"
|
||||
#include "SideEffectAnalysis.h"
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// GVN优化遍的核心逻辑封装类
|
||||
class GVNContext {
|
||||
public:
|
||||
// 运行GVN优化的主要方法
|
||||
void run(Function* func, AnalysisManager* AM, bool& changed);
|
||||
|
||||
private:
|
||||
// 新的值编号系统
|
||||
std::unordered_map<Value*, unsigned> valueToNumber; // Value -> 值编号
|
||||
std::unordered_map<unsigned, Value*> numberToValue; // 值编号 -> 代表值
|
||||
std::unordered_map<std::string, unsigned> expressionToNumber; // 表达式 -> 值编号
|
||||
unsigned nextValueNumber = 1;
|
||||
|
||||
// 已访问的基本块集合
|
||||
std::unordered_set<BasicBlock*> visited;
|
||||
|
||||
// 逆后序遍历的基本块列表
|
||||
std::vector<BasicBlock*> rpoBlocks;
|
||||
|
||||
// 需要删除的指令集合
|
||||
std::unordered_set<Instruction*> needRemove;
|
||||
|
||||
// 分析结果
|
||||
DominatorTree* domTree = nullptr;
|
||||
SideEffectAnalysisResult* sideEffectAnalysis = nullptr;
|
||||
|
||||
// 计算逆后序遍历
|
||||
void computeRPO(Function* func);
|
||||
void dfs(BasicBlock* bb);
|
||||
|
||||
// 新的值编号方法
|
||||
unsigned getValueNumber(Value* value);
|
||||
unsigned assignValueNumber(Value* value);
|
||||
|
||||
// 基本块处理
|
||||
void processBasicBlock(BasicBlock* bb, bool& changed);
|
||||
|
||||
// 指令处理
|
||||
bool processInstruction(Instruction* inst);
|
||||
|
||||
// 表达式构建和查找
|
||||
std::string buildExpressionKey(Instruction* inst);
|
||||
Value* findExistingValue(const std::string& exprKey, Instruction* inst);
|
||||
|
||||
// 支配关系和安全性检查
|
||||
bool dominates(Instruction* a, Instruction* b);
|
||||
bool isMemorySafe(LoadInst* earlierLoad, LoadInst* laterLoad);
|
||||
|
||||
// 清理方法
|
||||
void eliminateRedundantInstructions(bool& changed);
|
||||
void invalidateMemoryValues(StoreInst* store);
|
||||
};
|
||||
|
||||
// GVN优化遍类
|
||||
class GVN : public OptimizationPass {
|
||||
public:
|
||||
// 静态成员,作为该遍的唯一ID
|
||||
static void* ID;
|
||||
|
||||
GVN() : OptimizationPass("GVN", Granularity::Function) {}
|
||||
|
||||
// 在函数上运行优化
|
||||
bool runOnFunction(Function* func, AnalysisManager& AM) override;
|
||||
|
||||
// 返回该遍的唯一ID
|
||||
void* getPassID() const override { return ID; }
|
||||
|
||||
// 声明分析依赖
|
||||
void getAnalysisUsage(std::set<void*>& analysisDependencies,
|
||||
std::set<void*>& analysisInvalidations) const override;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
107
src/include/midend/Pass/Optimize/GlobalStrengthReduction.h
Normal file
107
src/include/midend/Pass/Optimize/GlobalStrengthReduction.h
Normal file
@ -0,0 +1,107 @@
|
||||
#pragma once
|
||||
|
||||
#include "Pass.h"
|
||||
#include "IR.h"
|
||||
#include "SideEffectAnalysis.h"
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 魔数乘法结构,用于除法优化
|
||||
struct MagicNumber {
|
||||
uint32_t multiplier;
|
||||
int shift;
|
||||
bool needAdd;
|
||||
|
||||
MagicNumber(uint32_t m, int s, bool add = false)
|
||||
: multiplier(m), shift(s), needAdd(add) {}
|
||||
};
|
||||
|
||||
// 全局强度削弱优化遍的核心逻辑封装类
|
||||
class GlobalStrengthReductionContext {
|
||||
public:
|
||||
// 构造函数,接受IRBuilder参数
|
||||
explicit GlobalStrengthReductionContext(IRBuilder* builder) : builder(builder) {}
|
||||
|
||||
// 运行优化的主要方法
|
||||
void run(Function* func, AnalysisManager* AM, bool& changed);
|
||||
|
||||
private:
|
||||
IRBuilder* builder; // IR构建器
|
||||
|
||||
// 分析结果
|
||||
SideEffectAnalysisResult* sideEffectAnalysis = nullptr;
|
||||
|
||||
// 优化计数
|
||||
int algebraicOptCount = 0;
|
||||
int strengthReductionCount = 0;
|
||||
int divisionOptCount = 0;
|
||||
|
||||
// 主要优化方法
|
||||
bool processBasicBlock(BasicBlock* bb);
|
||||
bool processInstruction(Instruction* inst);
|
||||
|
||||
// 代数优化方法
|
||||
bool tryAlgebraicOptimization(Instruction* inst);
|
||||
bool optimizeAddition(BinaryInst* inst);
|
||||
bool optimizeSubtraction(BinaryInst* inst);
|
||||
bool optimizeMultiplication(BinaryInst* inst);
|
||||
bool optimizeDivision(BinaryInst* inst);
|
||||
bool optimizeComparison(BinaryInst* inst);
|
||||
bool optimizeLogical(BinaryInst* inst);
|
||||
|
||||
// 强度削弱方法
|
||||
bool tryStrengthReduction(Instruction* inst);
|
||||
bool reduceMultiplication(BinaryInst* inst);
|
||||
bool reduceDivision(BinaryInst* inst);
|
||||
bool reducePower(CallInst* inst);
|
||||
|
||||
// 复杂乘法强度削弱方法
|
||||
bool tryComplexMultiplication(BinaryInst* inst, Value* variable, int constant);
|
||||
bool findOptimalShiftDecomposition(int constant, std::vector<int>& shifts);
|
||||
Value* createShiftDecomposition(BinaryInst* inst, Value* variable, const std::vector<int>& shifts);
|
||||
|
||||
// 魔数乘法相关方法
|
||||
MagicNumber computeMagicNumber(uint32_t divisor);
|
||||
std::pair<int, int> computeMulhMagicNumbers(int divisor);
|
||||
Value* createMagicDivision(BinaryInst* divInst, uint32_t divisor, const MagicNumber& magic);
|
||||
Value* createMagicDivisionLibdivide(BinaryInst* divInst, int divisor);
|
||||
bool isPowerOfTwo(uint32_t n);
|
||||
int log2OfPowerOfTwo(uint32_t n);
|
||||
|
||||
// 辅助方法
|
||||
bool isConstantInt(Value* val, int& constVal);
|
||||
bool isConstantInt(Value* val, uint32_t& constVal);
|
||||
ConstantInteger* getConstantInt(int val);
|
||||
bool hasOnlyLocalUses(Instruction* inst);
|
||||
void replaceWithOptimized(Instruction* original, Value* replacement);
|
||||
};
|
||||
|
||||
// 全局强度削弱优化遍类
|
||||
class GlobalStrengthReduction : public OptimizationPass {
|
||||
private:
|
||||
IRBuilder* builder; // IR构建器,用于创建新指令
|
||||
|
||||
public:
|
||||
// 静态成员,作为该遍的唯一ID
|
||||
static void* ID;
|
||||
|
||||
// 构造函数,接受IRBuilder参数
|
||||
explicit GlobalStrengthReduction(IRBuilder* builder)
|
||||
: OptimizationPass("GlobalStrengthReduction", Granularity::Function), builder(builder) {}
|
||||
|
||||
// 在函数上运行优化
|
||||
bool runOnFunction(Function* func, AnalysisManager& AM) override;
|
||||
|
||||
// 返回该遍的唯一ID
|
||||
void* getPassID() const override { return ID; }
|
||||
|
||||
// 声明分析依赖
|
||||
void getAnalysisUsage(std::set<void*>& analysisDependencies,
|
||||
std::set<void*>& analysisInvalidations) const override;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
252
src/include/midend/Pass/Optimize/InductionVariableElimination.h
Normal file
252
src/include/midend/Pass/Optimize/InductionVariableElimination.h
Normal file
@ -0,0 +1,252 @@
|
||||
#pragma once
|
||||
|
||||
#include "Pass.h"
|
||||
#include "IR.h"
|
||||
#include "LoopCharacteristics.h"
|
||||
#include "Loop.h"
|
||||
#include "Dom.h"
|
||||
#include "SideEffectAnalysis.h"
|
||||
#include "AliasAnalysis.h"
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <memory>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 前向声明
|
||||
class LoopCharacteristicsResult;
|
||||
class LoopAnalysisResult;
|
||||
|
||||
/**
|
||||
* @brief 死归纳变量信息
|
||||
* 记录一个可以被消除的归纳变量
|
||||
*/
|
||||
struct DeadInductionVariable {
|
||||
PhiInst* phiInst; // phi 指令
|
||||
std::vector<Instruction*> relatedInsts; // 相关的递增/递减指令
|
||||
Loop* containingLoop; // 所在循环
|
||||
bool canEliminate; // 是否可以安全消除
|
||||
|
||||
DeadInductionVariable(PhiInst* phi, Loop* loop)
|
||||
: phiInst(phi), containingLoop(loop), canEliminate(false) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 归纳变量消除上下文类
|
||||
* 封装归纳变量消除优化的核心逻辑和状态
|
||||
*/
|
||||
class InductionVariableEliminationContext {
|
||||
public:
|
||||
InductionVariableEliminationContext() {}
|
||||
|
||||
/**
|
||||
* 运行归纳变量消除优化
|
||||
* @param F 目标函数
|
||||
* @param AM 分析管理器
|
||||
* @return 是否修改了IR
|
||||
*/
|
||||
bool run(Function* F, AnalysisManager& AM);
|
||||
|
||||
private:
|
||||
// 分析结果缓存
|
||||
LoopAnalysisResult* loopAnalysis = nullptr;
|
||||
LoopCharacteristicsResult* loopCharacteristics = nullptr;
|
||||
DominatorTree* dominatorTree = nullptr;
|
||||
SideEffectAnalysisResult* sideEffectAnalysis = nullptr;
|
||||
AliasAnalysisResult* aliasAnalysis = nullptr;
|
||||
|
||||
// 死归纳变量存储
|
||||
std::vector<std::unique_ptr<DeadInductionVariable>> deadIVs;
|
||||
std::unordered_map<Loop*, std::vector<DeadInductionVariable*>> loopToDeadIVs;
|
||||
|
||||
// ========== 核心分析和优化阶段 ==========
|
||||
|
||||
/**
|
||||
* 阶段1:识别死归纳变量
|
||||
* 找出没有被有效使用的归纳变量
|
||||
*/
|
||||
void identifyDeadInductionVariables(Function* F);
|
||||
|
||||
/**
|
||||
* 阶段2:分析消除的安全性
|
||||
* 确保消除操作不会破坏程序语义
|
||||
*/
|
||||
void analyzeSafetyForElimination();
|
||||
|
||||
/**
|
||||
* 阶段3:执行归纳变量消除
|
||||
* 删除死归纳变量及其相关指令
|
||||
*/
|
||||
bool performInductionVariableElimination();
|
||||
|
||||
// ========== 辅助方法 ==========
|
||||
|
||||
/**
|
||||
* 检查归纳变量是否为死归纳变量
|
||||
* @param iv 归纳变量信息
|
||||
* @param loop 所在循环
|
||||
* @return 如果是死归纳变量返回相关信息,否则返回nullptr
|
||||
*/
|
||||
std::unique_ptr<DeadInductionVariable>
|
||||
isDeadInductionVariable(const InductionVarInfo* iv, Loop* loop);
|
||||
|
||||
/**
|
||||
* 递归分析phi指令及其使用链是否都是死代码
|
||||
* @param phiInst phi指令
|
||||
* @param loop 所在循环
|
||||
* @return phi指令是否可以安全删除
|
||||
*/
|
||||
bool isPhiInstructionDeadRecursively(PhiInst* phiInst, Loop* loop);
|
||||
|
||||
/**
|
||||
* 递归分析指令的使用链是否都是死代码
|
||||
* @param inst 要分析的指令
|
||||
* @param loop 所在循环
|
||||
* @param visited 已访问的指令集合(避免无限递归)
|
||||
* @param currentPath 当前递归路径(检测循环依赖)
|
||||
* @return 指令的使用链是否都是死代码
|
||||
*/
|
||||
bool isInstructionUseChainDeadRecursively(Instruction* inst, Loop* loop,
|
||||
std::set<Instruction*>& visited,
|
||||
std::set<Instruction*>& currentPath);
|
||||
|
||||
/**
|
||||
* 检查循环是否有副作用
|
||||
* @param loop 要检查的循环
|
||||
* @return 循环是否有副作用
|
||||
*/
|
||||
bool loopHasSideEffects(Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查指令是否被用于循环退出条件
|
||||
* @param inst 要检查的指令
|
||||
* @param loop 所在循环
|
||||
* @return 是否被用于循环退出条件
|
||||
*/
|
||||
bool isUsedInLoopExitCondition(Instruction* inst, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查指令的结果是否未被有效使用
|
||||
* @param inst 要检查的指令
|
||||
* @param loop 所在循环
|
||||
* @return 指令结果是否未被有效使用
|
||||
*/
|
||||
bool isInstructionResultUnused(Instruction* inst, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查store指令是否存储到死地址(利用别名分析)
|
||||
* @param store store指令
|
||||
* @param loop 所在循环
|
||||
* @return 是否存储到死地址
|
||||
*/
|
||||
bool isStoreToDeadLocation(StoreInst* store, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查指令是否为死代码或只在循环内部使用
|
||||
* @param inst 要检查的指令
|
||||
* @param loop 所在循环
|
||||
* @return 是否为死代码或只在循环内部使用
|
||||
*/
|
||||
bool isInstructionDeadOrInternalOnly(Instruction* inst, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查指令是否有效地为死代码(带递归深度限制)
|
||||
* @param inst 要检查的指令
|
||||
* @param loop 所在循环
|
||||
* @param maxDepth 最大递归深度
|
||||
* @return 指令是否有效地为死代码
|
||||
*/
|
||||
bool isInstructionEffectivelyDead(Instruction* inst, Loop* loop, int maxDepth);
|
||||
|
||||
/**
|
||||
* 检查store指令是否有后续的load操作
|
||||
* @param store store指令
|
||||
* @param loop 所在循环
|
||||
* @return 是否有后续的load操作
|
||||
*/
|
||||
bool hasSubsequentLoad(StoreInst* store, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查指令是否在循环外有使用
|
||||
* @param inst 要检查的指令
|
||||
* @param loop 所在循环
|
||||
* @return 是否在循环外有使用
|
||||
*/
|
||||
bool hasUsageOutsideLoop(Instruction* inst, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查store指令是否在循环外有后续的load操作
|
||||
* @param store store指令
|
||||
* @param loop 所在循环
|
||||
* @return 是否在循环外有后续的load操作
|
||||
*/
|
||||
bool hasSubsequentLoadOutsideLoop(StoreInst* store, Loop* loop);
|
||||
|
||||
/**
|
||||
* 递归检查基本块子树中是否有对指定位置的load操作
|
||||
* @param bb 基本块
|
||||
* @param ptr 指针
|
||||
* @param visited 已访问的基本块集合
|
||||
* @return 是否有load操作
|
||||
*/
|
||||
bool hasLoadInSubtree(BasicBlock* bb, Value* ptr, std::set<BasicBlock*>& visited);
|
||||
|
||||
/**
|
||||
* 收集与归纳变量相关的所有指令
|
||||
* @param phiInst phi指令
|
||||
* @param loop 所在循环
|
||||
* @return 相关指令列表
|
||||
*/
|
||||
std::vector<Instruction*> collectRelatedInstructions(PhiInst* phiInst, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查消除归纳变量的安全性
|
||||
* @param deadIV 死归纳变量
|
||||
* @return 是否可以安全消除
|
||||
*/
|
||||
bool isSafeToEliminate(const DeadInductionVariable* deadIV);
|
||||
|
||||
/**
|
||||
* 消除单个死归纳变量
|
||||
* @param deadIV 死归纳变量
|
||||
* @return 是否成功消除
|
||||
*/
|
||||
bool eliminateDeadInductionVariable(DeadInductionVariable* deadIV);
|
||||
|
||||
/**
|
||||
* 打印调试信息
|
||||
*/
|
||||
void printDebugInfo();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 归纳变量消除优化遍
|
||||
* 消除循环中无用的归纳变量,减少寄存器压力
|
||||
*/
|
||||
class InductionVariableElimination : public OptimizationPass {
|
||||
public:
|
||||
// 唯一的 Pass ID
|
||||
static void *ID;
|
||||
|
||||
InductionVariableElimination()
|
||||
: OptimizationPass("InductionVariableElimination", Granularity::Function) {}
|
||||
|
||||
/**
|
||||
* 在函数上运行归纳变量消除优化
|
||||
* @param F 目标函数
|
||||
* @param AM 分析管理器
|
||||
* @return 是否修改了IR
|
||||
*/
|
||||
bool runOnFunction(Function* F, AnalysisManager& AM) override;
|
||||
|
||||
/**
|
||||
* 声明分析依赖和失效信息
|
||||
*/
|
||||
void getAnalysisUsage(std::set<void*>& analysisDependencies,
|
||||
std::set<void*>& analysisInvalidations) const override;
|
||||
|
||||
void* getPassID() const override { return &ID; }
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
40
src/include/midend/Pass/Optimize/LICM.h
Normal file
40
src/include/midend/Pass/Optimize/LICM.h
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
#include "Pass.h"
|
||||
#include "Loop.h"
|
||||
#include "LoopCharacteristics.h"
|
||||
#include "Dom.h"
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace sysy{
|
||||
|
||||
class LICMContext {
|
||||
public:
|
||||
LICMContext(Function* func, Loop* loop, IRBuilder* builder, const LoopCharacteristics* chars)
|
||||
: func(func), loop(loop), builder(builder), chars(chars) {}
|
||||
// 运行LICM主流程,返回IR是否被修改
|
||||
bool run();
|
||||
|
||||
private:
|
||||
Function* func;
|
||||
Loop* loop;
|
||||
IRBuilder* builder;
|
||||
const LoopCharacteristics* chars; // 特征分析结果
|
||||
|
||||
// 外提所有可提升指令
|
||||
bool hoistInstructions();
|
||||
};
|
||||
|
||||
|
||||
class LICM : public OptimizationPass{
|
||||
private:
|
||||
IRBuilder *builder; ///< IR构建器,用于插入指令
|
||||
public:
|
||||
static void *ID;
|
||||
LICM(IRBuilder *builder = nullptr) : OptimizationPass("LICM", Granularity::Function) , builder(builder) {}
|
||||
bool runOnFunction(Function *F, AnalysisManager &AM) override;
|
||||
void getAnalysisUsage(std::set<void *> &, std::set<void *> &) const override;
|
||||
void *getPassID() const override { return &ID; }
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
155
src/include/midend/Pass/Optimize/LoopNormalization.h
Normal file
155
src/include/midend/Pass/Optimize/LoopNormalization.h
Normal file
@ -0,0 +1,155 @@
|
||||
#pragma once
|
||||
|
||||
#include "Loop.h" // 循环分析依赖
|
||||
#include "Dom.h" // 支配树分析依赖
|
||||
#include "IR.h" // IR定义
|
||||
#include "IRBuilder.h" // IR构建器
|
||||
#include "Pass.h" // Pass框架
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
/**
|
||||
* @brief 循环规范化转换Pass
|
||||
*
|
||||
* 该Pass在循环不变量提升等优化前运行,主要负责:
|
||||
* 1. 为没有前置块(preheader)的循环创建前置块
|
||||
* 2. 确保循环结构符合后续优化的要求
|
||||
* 3. 规范化循环的控制流结构
|
||||
*
|
||||
* 前置块的作用:
|
||||
* - 为循环不变量提升提供插入位置
|
||||
* - 简化循环分析和优化
|
||||
* - 确保循环有唯一的入口点
|
||||
*/
|
||||
class LoopNormalizationPass : public OptimizationPass {
|
||||
public:
|
||||
// 唯一的 Pass ID
|
||||
static void *ID;
|
||||
|
||||
LoopNormalizationPass(IRBuilder* builder) : OptimizationPass("LoopNormalization", Pass::Granularity::Function), builder(builder) {}
|
||||
|
||||
// 实现 getPassID
|
||||
void *getPassID() const override { return &ID; }
|
||||
|
||||
// 核心运行方法
|
||||
bool runOnFunction(Function *F, AnalysisManager &AM) override;
|
||||
|
||||
// 声明分析依赖和失效信息
|
||||
void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const override;
|
||||
|
||||
private:
|
||||
// ========== IR构建器 ==========
|
||||
IRBuilder* builder; // IR构建器
|
||||
|
||||
// ========== 缓存的分析结果 ==========
|
||||
LoopAnalysisResult* loopAnalysis; // 循环结构分析结果
|
||||
DominatorTree* domTree; // 支配树分析结果
|
||||
|
||||
// ========== 规范化统计 ==========
|
||||
struct NormalizationStats {
|
||||
size_t totalLoops; // 总循环数
|
||||
size_t loopsNeedingPreheader; // 需要前置块的循环数
|
||||
size_t preheadersCreated; // 创建的前置块数
|
||||
size_t loopsNormalized; // 规范化的循环数
|
||||
size_t redundantPhisRemoved; // 删除的冗余PHI节点数
|
||||
|
||||
NormalizationStats() : totalLoops(0), loopsNeedingPreheader(0),
|
||||
preheadersCreated(0), loopsNormalized(0),
|
||||
redundantPhisRemoved(0) {}
|
||||
} stats;
|
||||
|
||||
// ========== 核心规范化方法 ==========
|
||||
|
||||
/**
|
||||
* 规范化单个循环
|
||||
* @param loop 要规范化的循环
|
||||
* @return 是否进行了修改
|
||||
*/
|
||||
bool normalizeLoop(Loop* loop);
|
||||
|
||||
/**
|
||||
* 为循环创建前置块
|
||||
* @param loop 需要前置块的循环
|
||||
* @return 创建的前置块,如果失败则返回nullptr
|
||||
*/
|
||||
BasicBlock* createPreheaderForLoop(Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查循环是否需要前置块(基于结构性需求)
|
||||
* @param loop 要检查的循环
|
||||
* @return true如果需要前置块
|
||||
*/
|
||||
bool needsPreheader(Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查循环是否已有合适的前置块
|
||||
* @param loop 要检查的循环
|
||||
* @return 现有的前置块,如果没有则返回nullptr
|
||||
*/
|
||||
BasicBlock* getExistingPreheader(Loop* loop);
|
||||
|
||||
/**
|
||||
* 更新支配树关系(在创建新块后)
|
||||
* @param newBlock 新创建的基本块
|
||||
* @param loop 相关的循环
|
||||
*/
|
||||
void updateDominatorRelations(BasicBlock* newBlock, Loop* loop);
|
||||
|
||||
/**
|
||||
* 重定向循环外的前驱块到新的前置块
|
||||
* @param loop 目标循环
|
||||
* @param preheader 新创建的前置块
|
||||
* @param header 循环头部
|
||||
*/
|
||||
void redirectExternalPredecessors(Loop* loop, BasicBlock* preheader, BasicBlock* header, const std::vector<BasicBlock*>& externalPreds);
|
||||
|
||||
/**
|
||||
* 为前置块生成合适的名称
|
||||
* @param loop 相关的循环
|
||||
* @return 生成的前置块名称
|
||||
*/
|
||||
std::string generatePreheaderName(Loop* loop);
|
||||
|
||||
/**
|
||||
* 验证规范化结果的正确性
|
||||
* @param loop 规范化后的循环
|
||||
* @return true如果规范化正确
|
||||
*/
|
||||
bool validateNormalization(Loop* loop);
|
||||
|
||||
// ========== 辅助方法 ==========
|
||||
|
||||
/**
|
||||
* 获取循环的外部前驱块(不在循环内的前驱)
|
||||
* @param loop 目标循环
|
||||
* @return 外部前驱块列表
|
||||
*/
|
||||
std::vector<BasicBlock*> getExternalPredecessors(Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查基本块是否适合作为前置块
|
||||
* @param block 候选基本块
|
||||
* @param loop 目标循环
|
||||
* @return true如果适合作为前置块
|
||||
*/
|
||||
bool isSuitableAsPreheader(BasicBlock* block, Loop* loop);
|
||||
|
||||
/**
|
||||
* 更新PHI节点以适应新的前置块
|
||||
* @param header 循环头部
|
||||
* @param preheader 新的前置块
|
||||
* @param oldPreds 原来的外部前驱
|
||||
*/
|
||||
void updatePhiNodesForPreheader(BasicBlock* header, BasicBlock* preheader,
|
||||
const std::vector<BasicBlock*>& oldPreds);
|
||||
|
||||
/**
|
||||
* 打印规范化统计信息
|
||||
*/
|
||||
void printStats(Function* F);
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
233
src/include/midend/Pass/Optimize/LoopStrengthReduction.h
Normal file
233
src/include/midend/Pass/Optimize/LoopStrengthReduction.h
Normal file
@ -0,0 +1,233 @@
|
||||
#pragma once
|
||||
|
||||
#include "Pass.h"
|
||||
#include "IR.h"
|
||||
#include "LoopCharacteristics.h"
|
||||
#include "Loop.h"
|
||||
#include "Dom.h"
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <memory>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 前向声明
|
||||
class LoopCharacteristicsResult;
|
||||
class LoopAnalysisResult;
|
||||
|
||||
/**
|
||||
* @brief 强度削弱候选项信息
|
||||
* 记录一个可以进行强度削弱的表达式信息
|
||||
*/
|
||||
struct StrengthReductionCandidate {
|
||||
enum OpType {
|
||||
MULTIPLY, // 乘法: iv * const
|
||||
DIVIDE, // 除法: iv / 2^n (转换为右移)
|
||||
DIVIDE_CONST, // 除法: iv / const (使用mulh指令优化)
|
||||
REMAINDER // 取模: iv % 2^n (转换为位与)
|
||||
};
|
||||
|
||||
enum DivisionStrategy {
|
||||
SIMPLE_SHIFT, // 简单右移(仅适用于无符号或非负数)
|
||||
SIGNED_CORRECTION, // 有符号除法修正: (x + (x >> 31) & mask) >> k
|
||||
MULH_OPTIMIZATION // 使用mulh指令优化任意常数除法
|
||||
};
|
||||
|
||||
Instruction* originalInst; // 原始指令 (如 i*4, i/8, i%16)
|
||||
Value* inductionVar; // 归纳变量 (如 i)
|
||||
OpType operationType; // 操作类型
|
||||
DivisionStrategy divStrategy; // 除法策略(仅用于除法)
|
||||
int multiplier; // 乘数/除数/模数 (如 4, 8, 16)
|
||||
int shiftAmount; // 位移量 (对于2的幂)
|
||||
int offset; // 偏移量 (如常数项)
|
||||
BasicBlock* containingBlock; // 所在基本块
|
||||
Loop* containingLoop; // 所在循环
|
||||
bool hasNegativeValues; // 归纳变量是否可能为负数
|
||||
|
||||
// 强度削弱后的新变量
|
||||
PhiInst* newPhi = nullptr; // 新的 phi 指令
|
||||
Value* newInductionVar = nullptr; // 新的归纳变量
|
||||
|
||||
StrengthReductionCandidate(Instruction* inst, Value* iv, OpType opType, int value, int off,
|
||||
BasicBlock* bb, Loop* loop)
|
||||
: originalInst(inst), inductionVar(iv), operationType(opType),
|
||||
divStrategy(SIMPLE_SHIFT), multiplier(value), offset(off),
|
||||
containingBlock(bb), containingLoop(loop), hasNegativeValues(false) {
|
||||
|
||||
// 计算位移量(用于除法和取模的强度削弱)
|
||||
if (opType == DIVIDE || opType == REMAINDER) {
|
||||
shiftAmount = 0;
|
||||
int temp = value;
|
||||
while (temp > 1) {
|
||||
temp >>= 1;
|
||||
shiftAmount++;
|
||||
}
|
||||
} else {
|
||||
shiftAmount = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 强度削弱上下文类
|
||||
* 封装强度削弱优化的核心逻辑和状态
|
||||
*/
|
||||
class StrengthReductionContext {
|
||||
public:
|
||||
StrengthReductionContext(IRBuilder* builder) : builder(builder) {}
|
||||
|
||||
/**
|
||||
* 运行强度削弱优化
|
||||
* @param F 目标函数
|
||||
* @param AM 分析管理器
|
||||
* @return 是否修改了IR
|
||||
*/
|
||||
bool run(Function* F, AnalysisManager& AM);
|
||||
|
||||
private:
|
||||
IRBuilder* builder;
|
||||
|
||||
// 分析结果缓存
|
||||
LoopAnalysisResult* loopAnalysis = nullptr;
|
||||
LoopCharacteristicsResult* loopCharacteristics = nullptr;
|
||||
DominatorTree* dominatorTree = nullptr;
|
||||
|
||||
// 候选项存储
|
||||
std::vector<std::unique_ptr<StrengthReductionCandidate>> candidates;
|
||||
std::unordered_map<Loop*, std::vector<StrengthReductionCandidate*>> loopToCandidates;
|
||||
|
||||
// ========== 核心分析和优化阶段 ==========
|
||||
|
||||
/**
|
||||
* 阶段1:识别强度削弱候选项
|
||||
* 扫描所有循环中的乘法指令,找出可以优化的模式
|
||||
*/
|
||||
void identifyStrengthReductionCandidates(Function* F);
|
||||
|
||||
/**
|
||||
* 阶段2:分析候选项的优化潜力
|
||||
* 评估每个候选项的收益,过滤掉不值得优化的情况
|
||||
*/
|
||||
void analyzeOptimizationPotential();
|
||||
|
||||
/**
|
||||
* 阶段3:执行强度削弱变换
|
||||
* 对选中的候选项执行实际的强度削弱优化
|
||||
*/
|
||||
bool performStrengthReduction();
|
||||
|
||||
// ========== 辅助分析函数 ==========
|
||||
|
||||
/**
|
||||
* 分析归纳变量是否可能取负值
|
||||
* @param ivInfo 归纳变量信息
|
||||
* @param loop 所属循环
|
||||
* @return 如果可能为负数返回true
|
||||
*/
|
||||
bool analyzeInductionVariableRange(const InductionVarInfo* ivInfo, Loop* loop) const;
|
||||
|
||||
/**
|
||||
* 生成除法替换代码
|
||||
* @param candidate 优化候选项
|
||||
* @param builder IR构建器
|
||||
* @return 替换值
|
||||
*/
|
||||
Value* generateDivisionReplacement(StrengthReductionCandidate* candidate, IRBuilder* builder) const;
|
||||
|
||||
/**
|
||||
* 生成任意常数除法替换代码
|
||||
* @param candidate 优化候选项
|
||||
* @param builder IR构建器
|
||||
* @return 替换值
|
||||
*/
|
||||
Value* generateConstantDivisionReplacement(StrengthReductionCandidate* candidate, IRBuilder* builder) const;
|
||||
|
||||
/**
|
||||
* 检查指令是否为强度削弱候选项
|
||||
* @param inst 要检查的指令
|
||||
* @param loop 所在循环
|
||||
* @return 如果是候选项返回候选项信息,否则返回nullptr
|
||||
*/
|
||||
std::unique_ptr<StrengthReductionCandidate>
|
||||
isStrengthReductionCandidate(Instruction* inst, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查值是否为循环的归纳变量
|
||||
* @param val 要检查的值
|
||||
* @param loop 循环
|
||||
* @param characteristics 循环特征信息
|
||||
* @return 如果是归纳变量返回归纳变量信息,否则返回nullptr
|
||||
*/
|
||||
const InductionVarInfo*
|
||||
getInductionVarInfo(Value* val, Loop* loop, const LoopCharacteristics* characteristics);
|
||||
|
||||
/**
|
||||
* 为候选项创建新的归纳变量
|
||||
* @param candidate 候选项
|
||||
* @return 是否成功创建
|
||||
*/
|
||||
bool createNewInductionVariable(StrengthReductionCandidate* candidate);
|
||||
|
||||
/**
|
||||
* 替换原始指令的所有使用
|
||||
* @param candidate 候选项
|
||||
* @return 是否成功替换
|
||||
*/
|
||||
bool replaceOriginalInstruction(StrengthReductionCandidate* candidate);
|
||||
|
||||
/**
|
||||
* 估算优化收益
|
||||
* 计算强度削弱后的性能提升
|
||||
* @param candidate 候选项
|
||||
* @return 估算的收益分数
|
||||
*/
|
||||
double estimateOptimizationBenefit(const StrengthReductionCandidate* candidate);
|
||||
|
||||
/**
|
||||
* 检查优化的合法性
|
||||
* @param candidate 候选项
|
||||
* @return 是否可以安全地进行优化
|
||||
*/
|
||||
bool isOptimizationLegal(const StrengthReductionCandidate* candidate);
|
||||
|
||||
/**
|
||||
* 打印调试信息
|
||||
*/
|
||||
void printDebugInfo();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 循环强度削弱优化遍
|
||||
* 将循环中的乘法运算转换为更高效的加法运算
|
||||
*/
|
||||
class LoopStrengthReduction : public OptimizationPass {
|
||||
public:
|
||||
// 唯一的 Pass ID
|
||||
static void *ID;
|
||||
|
||||
LoopStrengthReduction(IRBuilder* builder)
|
||||
: OptimizationPass("LoopStrengthReduction", Granularity::Function),
|
||||
builder(builder) {}
|
||||
|
||||
/**
|
||||
* 在函数上运行强度削弱优化
|
||||
* @param F 目标函数
|
||||
* @param AM 分析管理器
|
||||
* @return 是否修改了IR
|
||||
*/
|
||||
bool runOnFunction(Function* F, AnalysisManager& AM) override;
|
||||
|
||||
/**
|
||||
* 声明分析依赖和失效信息
|
||||
*/
|
||||
void getAnalysisUsage(std::set<void*>& analysisDependencies,
|
||||
std::set<void*>& analysisInvalidations) const override;
|
||||
|
||||
void* getPassID() const override { return &ID; }
|
||||
|
||||
private:
|
||||
IRBuilder* builder;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
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
|
||||
157
src/include/midend/Pass/Optimize/SCCP.h
Normal file
157
src/include/midend/Pass/Optimize/SCCP.h
Normal file
@ -0,0 +1,157 @@
|
||||
#pragma once
|
||||
|
||||
#include "IR.h"
|
||||
#include "Pass.h"
|
||||
#include "SysYIROptUtils.h"
|
||||
#include "AliasAnalysis.h"
|
||||
#include "SideEffectAnalysis.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 构建器,用于插入指令和创建常量
|
||||
AliasAnalysisResult *aliasAnalysis; // 别名分析结果
|
||||
SideEffectAnalysisResult *sideEffectAnalysis; // 副作用分析结果
|
||||
|
||||
// 工作列表
|
||||
// 存储需要重新评估的指令
|
||||
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);
|
||||
// 辅助函数:检查是否为已知的纯函数
|
||||
bool isKnownPureFunction(const std::string &funcName) const;
|
||||
// 辅助函数:计算纯函数的常量结果
|
||||
SSAPValue computePureFunctionResult(CallInst *call, const std::vector<SSAPValue> &argValues);
|
||||
// 辅助函数:查找存储到指定位置的常量值
|
||||
SSAPValue findStoredConstantValue(Value *ptr, BasicBlock *currentBB);
|
||||
// 辅助函数:动态检查数组访问是否为常量索引(考虑SCCP状态)
|
||||
bool hasRuntimeConstantAccess(Value *ptr);
|
||||
|
||||
// 主要优化阶段
|
||||
// 阶段1: 常量传播与折叠
|
||||
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), aliasAnalysis(nullptr), sideEffectAnalysis(nullptr) {}
|
||||
|
||||
// 设置别名分析结果
|
||||
void setAliasAnalysis(AliasAnalysisResult *aa) { aliasAnalysis = aa; }
|
||||
|
||||
// 设置副作用分析结果
|
||||
void setSideEffectAnalysis(SideEffectAnalysisResult *sea) { sideEffectAnalysis = sea; }
|
||||
|
||||
// 运行 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
|
||||
296
src/include/midend/Pass/Optimize/SysYIROptUtils.h
Normal file
296
src/include/midend/Pass/Optimize/SysYIROptUtils.h
Normal file
@ -0,0 +1,296 @@
|
||||
#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 关系
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
//该实现参考了libdivide的算法
|
||||
static std::pair<int, int> computeMulhMagicNumbers(int divisor) {
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "\n[SR] ===== Computing magic numbers for divisor " << divisor << " (libdivide algorithm) =====" << std::endl;
|
||||
}
|
||||
|
||||
if (divisor == 0) {
|
||||
if (DEBUG) std::cout << "[SR] Error: divisor must be != 0" << std::endl;
|
||||
return {-1, -1};
|
||||
}
|
||||
|
||||
// libdivide 常数
|
||||
const uint8_t LIBDIVIDE_ADD_MARKER = 0x40;
|
||||
const uint8_t LIBDIVIDE_NEGATIVE_DIVISOR = 0x80;
|
||||
|
||||
// 辅助函数:计算前导零个数
|
||||
auto count_leading_zeros32 = [](uint32_t val) -> uint32_t {
|
||||
if (val == 0) return 32;
|
||||
return __builtin_clz(val);
|
||||
};
|
||||
|
||||
// 辅助函数:64位除法返回32位商和余数
|
||||
auto div_64_32 = [](uint32_t high, uint32_t low, uint32_t divisor, uint32_t* rem) -> uint32_t {
|
||||
uint64_t dividend = ((uint64_t)high << 32) | low;
|
||||
uint32_t quotient = dividend / divisor;
|
||||
*rem = dividend % divisor;
|
||||
return quotient;
|
||||
};
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Input divisor: " << divisor << std::endl;
|
||||
}
|
||||
|
||||
// libdivide_internal_s32_gen 算法实现
|
||||
int32_t d = divisor;
|
||||
uint32_t ud = (uint32_t)d;
|
||||
uint32_t absD = (d < 0) ? -ud : ud;
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] absD = " << absD << std::endl;
|
||||
}
|
||||
|
||||
uint32_t floor_log_2_d = 31 - count_leading_zeros32(absD);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] floor_log_2_d = " << floor_log_2_d << std::endl;
|
||||
}
|
||||
|
||||
// 检查 absD 是否为2的幂
|
||||
if ((absD & (absD - 1)) == 0) {
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] " << absD << " 是2的幂,使用移位方法" << std::endl;
|
||||
}
|
||||
|
||||
// 对于2的幂,我们只使用移位,不需要魔数
|
||||
int shift = floor_log_2_d;
|
||||
if (d < 0) shift |= 0x80; // 标记负数
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Power of 2 result: magic=0, shift=" << shift << std::endl;
|
||||
std::cout << "[SR] ===== End magic computation =====" << std::endl;
|
||||
}
|
||||
|
||||
// 对于我们的目的,我们将在IR生成中以不同方式处理2的幂
|
||||
// 返回特殊标记
|
||||
return {0, shift};
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] " << absD << " is not a power of 2, computing magic number" << std::endl;
|
||||
}
|
||||
|
||||
// 非2的幂除数的魔数计算
|
||||
uint8_t more;
|
||||
uint32_t rem, proposed_m;
|
||||
|
||||
// 计算 proposed_m = floor(2^(floor_log_2_d + 31) / absD)
|
||||
proposed_m = div_64_32((uint32_t)1 << (floor_log_2_d - 1), 0, absD, &rem);
|
||||
const uint32_t e = absD - rem;
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] proposed_m = " << proposed_m << ", rem = " << rem << ", e = " << e << std::endl;
|
||||
}
|
||||
|
||||
// 确定是否需要"加法"版本
|
||||
const bool branchfree = false; // 使用分支版本
|
||||
|
||||
if (!branchfree && e < ((uint32_t)1 << floor_log_2_d)) {
|
||||
// 这个幂次有效
|
||||
more = (uint8_t)(floor_log_2_d - 1);
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Using basic algorithm, shift = " << (int)more << std::endl;
|
||||
}
|
||||
} else {
|
||||
// 我们需要上升一个等级
|
||||
proposed_m += proposed_m;
|
||||
const uint32_t twice_rem = rem + rem;
|
||||
if (twice_rem >= absD || twice_rem < rem) {
|
||||
proposed_m += 1;
|
||||
}
|
||||
more = (uint8_t)(floor_log_2_d | LIBDIVIDE_ADD_MARKER);
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Using add algorithm, proposed_m = " << proposed_m << ", more = " << (int)more << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
proposed_m += 1;
|
||||
int32_t magic = (int32_t)proposed_m;
|
||||
|
||||
// 处理负除数
|
||||
if (d < 0) {
|
||||
more |= LIBDIVIDE_NEGATIVE_DIVISOR;
|
||||
if (!branchfree) {
|
||||
magic = -magic;
|
||||
}
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Negative divisor, magic = " << magic << ", more = " << (int)more << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 为我们的IR生成提取移位量和标志
|
||||
int shift = more & 0x3F; // 移除标志,保留移位量(位0-5)
|
||||
bool need_add = (more & LIBDIVIDE_ADD_MARKER) != 0;
|
||||
bool is_negative = (more & LIBDIVIDE_NEGATIVE_DIVISOR) != 0;
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Final result: magic = " << magic << ", more = " << (int)more
|
||||
<< " (0x" << std::hex << (int)more << std::dec << ")" << std::endl;
|
||||
std::cout << "[SR] Shift = " << shift << ", need_add = " << need_add
|
||||
<< ", is_negative = " << is_negative << std::endl;
|
||||
|
||||
// Test the magic number using the correct libdivide algorithm
|
||||
std::cout << "[SR] Testing magic number (libdivide algorithm):" << std::endl;
|
||||
int test_values[] = {1, 7, 37, 100, 999, -1, -7, -37, -100};
|
||||
|
||||
for (int test_val : test_values) {
|
||||
int64_t quotient;
|
||||
|
||||
// 实现正确的libdivide算法
|
||||
int64_t product = (int64_t)test_val * magic;
|
||||
int64_t high_bits = product >> 32;
|
||||
|
||||
if (need_add) {
|
||||
// ADD_MARKER情况:移位前加上被除数
|
||||
// 这是libdivide的关键洞察!
|
||||
high_bits += test_val;
|
||||
quotient = high_bits >> shift;
|
||||
} else {
|
||||
// 正常情况:只是移位
|
||||
quotient = high_bits >> shift;
|
||||
}
|
||||
|
||||
// 符号修正:这是libdivide有符号除法的关键部分!
|
||||
// 如果被除数为负,商需要加1来匹配C语言的截断除法语义
|
||||
if (test_val < 0) {
|
||||
quotient += 1;
|
||||
}
|
||||
|
||||
int expected = test_val / divisor;
|
||||
|
||||
bool correct = (quotient == expected);
|
||||
std::cout << "[SR] " << test_val << " / " << divisor << " = " << quotient
|
||||
<< " (expected " << expected << ") " << (correct ? "✓" : "✗") << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "[SR] ===== End magic computation =====" << std::endl;
|
||||
}
|
||||
|
||||
// 返回魔数、移位量,并在移位中编码ADD_MARKER标志
|
||||
// 我们将使用移位的第6位表示ADD_MARKER,第7位表示负数(如果需要)
|
||||
int encoded_shift = shift;
|
||||
if (need_add) {
|
||||
encoded_shift |= 0x40; // 设置第6位表示ADD_MARKER
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Encoding ADD_MARKER in shift: " << encoded_shift << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return {magic, encoded_shift};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}// namespace sysy
|
||||
39
src/include/midend/Pass/Optimize/TailCallOpt.h
Normal file
39
src/include/midend/Pass/Optimize/TailCallOpt.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "Pass.h"
|
||||
#include "Dom.h"
|
||||
#include "Loop.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
/**
|
||||
* @class TailCallOpt
|
||||
* @brief 优化尾调用的中端优化通道。
|
||||
*
|
||||
* 该类实现了一个针对函数级别的尾调用优化的优化通道(OptimizationPass)。
|
||||
* 通过分析和转换 IR(中间表示),将可优化的尾调用转换为更高效的形式,
|
||||
* 以减少函数调用的开销,提升程序性能。
|
||||
*
|
||||
* @note 需要传入 IRBuilder 指针用于 IR 构建和修改。
|
||||
*
|
||||
* @method runOnFunction
|
||||
* 对指定函数进行尾调用优化。
|
||||
*
|
||||
* @method getPassID
|
||||
* 获取当前优化通道的唯一标识符。
|
||||
*
|
||||
* @method getAnalysisUsage
|
||||
* 指定该优化通道所依赖和失效的分析集合。
|
||||
*/
|
||||
class TailCallOpt : public OptimizationPass {
|
||||
private:
|
||||
IRBuilder* builder;
|
||||
public:
|
||||
TailCallOpt(IRBuilder* builder) : OptimizationPass("TailCallOpt", Granularity::Function), builder(builder) {}
|
||||
static void *ID;
|
||||
bool runOnFunction(Function *F, AnalysisManager &AM) override;
|
||||
void *getPassID() const override { return &ID; }
|
||||
void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const override;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
@ -11,6 +11,8 @@
|
||||
#include "IR.h"
|
||||
#include "IRBuilder.h"
|
||||
|
||||
extern int DEBUG; // 全局调试标志
|
||||
|
||||
namespace sysy {
|
||||
|
||||
//前向声明
|
||||
@ -155,8 +157,15 @@ public:
|
||||
// 检查是否已存在有效结果
|
||||
auto it = moduleCachedResults.find(analysisID);
|
||||
if (it != moduleCachedResults.end()) {
|
||||
if(DEBUG) {
|
||||
std::cout << "Using cached result for Analysis Pass: " << analysisPass->getName() << "\n";
|
||||
}
|
||||
return static_cast<T *>(it->second.get()); // 返回缓存结果
|
||||
}
|
||||
// 只有在实际运行时才打印调试信息
|
||||
if(DEBUG){
|
||||
std::cout << "Running Analysis Pass: " << analysisPass->getName() << "\n";
|
||||
}
|
||||
// 运行模块级分析遍
|
||||
if (!pModuleRef) {
|
||||
std::cerr << "Error: Module reference not set for AnalysisManager to run Module Pass.\n";
|
||||
@ -178,8 +187,16 @@ public:
|
||||
// 检查是否已存在有效结果
|
||||
auto it = functionCachedResults.find({F, analysisID});
|
||||
if (it != functionCachedResults.end()) {
|
||||
if(DEBUG) {
|
||||
std::cout << "Using cached result for Analysis Pass: " << analysisPass->getName() << " (Function: " << F->getName() << ")\n";
|
||||
}
|
||||
return static_cast<T *>(it->second.get()); // 返回缓存结果
|
||||
}
|
||||
// 只有在实际运行时才打印调试信息
|
||||
if(DEBUG){
|
||||
std::cout << "Running Analysis Pass: " << analysisPass->getName() << "\n";
|
||||
std::cout << "Function: " << F->getName() << "\n";
|
||||
}
|
||||
// 运行函数级分析遍
|
||||
analysisPass->runOnFunction(F, *this);
|
||||
// 获取结果并缓存
|
||||
@ -197,8 +214,16 @@ public:
|
||||
// 检查是否已存在有效结果
|
||||
auto it = basicBlockCachedResults.find({BB, analysisID});
|
||||
if (it != basicBlockCachedResults.end()) {
|
||||
if(DEBUG) {
|
||||
std::cout << "Using cached result for Analysis Pass: " << analysisPass->getName() << " (BasicBlock: " << BB->getName() << ")\n";
|
||||
}
|
||||
return static_cast<T *>(it->second.get()); // 返回缓存结果
|
||||
}
|
||||
// 只有在实际运行时才打印调试信息
|
||||
if(DEBUG){
|
||||
std::cout << "Running Analysis Pass: " << analysisPass->getName() << "\n";
|
||||
std::cout << "BasicBlock: " << BB->getName() << "\n";
|
||||
}
|
||||
// 运行基本块级分析遍
|
||||
analysisPass->runOnBasicBlock(BB, *this);
|
||||
// 获取结果并缓存
|
||||
@ -274,7 +299,7 @@ private:
|
||||
IRBuilder *pBuilder;
|
||||
|
||||
public:
|
||||
PassManager() = default;
|
||||
PassManager() = delete;
|
||||
~PassManager() = default;
|
||||
|
||||
PassManager(Module *module, IRBuilder *builder) : pmodule(module) ,pBuilder(builder), analysisManager(module) {}
|
||||
@ -292,6 +317,9 @@ public:
|
||||
AnalysisManager &getAnalysisManager() { return analysisManager; }
|
||||
|
||||
void clearPasses();
|
||||
|
||||
// 输出pass列表并打印IR信息供观察优化遍效果
|
||||
void printPasses() const;
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
@ -59,6 +59,88 @@ 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
|
||||
}
|
||||
};
|
||||
|
||||
struct ExpKey {
|
||||
BinaryOp op; ///< 操作符
|
||||
Value *left; ///< 左操作数
|
||||
Value *right; ///< 右操作数
|
||||
ExpKey(BinaryOp op, Value *left, Value *right) : op(op), left(left), right(right) {}
|
||||
|
||||
bool operator<(const ExpKey &other) const {
|
||||
if (op != other.op)
|
||||
return op < other.op; ///< 比较操作符
|
||||
if (left != other.left)
|
||||
return left < other.left; ///< 比较左操作
|
||||
return right < other.right; ///< 比较右操作数
|
||||
} ///< 重载小于运算符用于比较ExpKey
|
||||
};
|
||||
|
||||
struct UnExpKey {
|
||||
BinaryOp op; ///< 一元操作符
|
||||
Value *operand; ///< 操作数
|
||||
UnExpKey(BinaryOp op, Value *operand) : op(op), operand(operand) {}
|
||||
|
||||
bool operator<(const UnExpKey &other) const {
|
||||
if (op != other.op)
|
||||
return op < other.op; ///< 比较操作符
|
||||
return operand < other.operand; ///< 比较操作数
|
||||
} ///< 重载小于运算符用于比较UnExpKey
|
||||
};
|
||||
|
||||
struct GEPKey {
|
||||
Value *basePointer;
|
||||
std::vector<Value *> indices;
|
||||
|
||||
// 为 std::map 定义比较运算符,使得 GEPKey 可以作为键
|
||||
bool operator<(const GEPKey &other) const {
|
||||
if (basePointer != other.basePointer) {
|
||||
return basePointer < other.basePointer;
|
||||
}
|
||||
// 逐个比较索引,确保顺序一致
|
||||
if (indices.size() != other.indices.size()) {
|
||||
return indices.size() < other.indices.size();
|
||||
}
|
||||
for (size_t i = 0; i < indices.size(); ++i) {
|
||||
if (indices[i] != other.indices[i]) {
|
||||
return indices[i] < other.indices[i];
|
||||
}
|
||||
}
|
||||
return false; // 如果 basePointer 和所有索引都相同,则认为相等
|
||||
}
|
||||
};
|
||||
std::map<GEPKey, Value*> availableGEPs; ///< 用于存储 GEP 的缓存
|
||||
std::map<ExpKey, Value*> availableBinaryExpressions;
|
||||
std::map<UnExpKey, Value*> availableUnaryExpressions;
|
||||
std::map<Value*, Value*> availableLoads;
|
||||
|
||||
public:
|
||||
SysYIRGenerator() = default;
|
||||
|
||||
@ -97,7 +179,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;
|
||||
@ -131,8 +213,22 @@ 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();
|
||||
|
||||
// 参数是发生 store 操作的目标地址/变量的 Value*
|
||||
void invalidateExpressionsOnStore(Value* storedAddress);
|
||||
|
||||
// 清除因函数调用而失效的表达式缓存(保守策略)
|
||||
void invalidateExpressionsOnCall();
|
||||
|
||||
// 在进入新的基本块时清空所有表达式缓存
|
||||
void enterNewBasicBlock();
|
||||
public:
|
||||
// 获取GEP指令的地址
|
||||
Value* getGEPAddressInst(Value* basePointer, const std::vector<Value*>& indices);
|
||||
@ -141,6 +237,7 @@ public:
|
||||
|
||||
unsigned countArrayDimensions(Type* type);
|
||||
|
||||
|
||||
}; // class SysYIRGenerator
|
||||
|
||||
} // namespace sysy
|
||||
@ -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);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user