Compare commits
1 Commits
backend-fm
...
deploy-202
| Author | SHA1 | Date | |
|---|---|---|---|
| ef4bdfc8eb |
5
.gitignore
vendored
5
.gitignore
vendored
@ -23,6 +23,7 @@
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
@ -36,7 +37,6 @@ doxygen
|
||||
|
||||
!/testdata/functional/*.out
|
||||
!/testdata/h_functional/*.out
|
||||
!/testdata/performance/*.out
|
||||
build/
|
||||
.antlr
|
||||
.vscode/
|
||||
@ -53,5 +53,4 @@ __init__.py
|
||||
|
||||
.DS_*
|
||||
|
||||
antlr/
|
||||
.clang-format
|
||||
antlr/
|
||||
429
Pass_ID_List.md
429
Pass_ID_List.md
@ -1,429 +0,0 @@
|
||||
# 记录中端遍的开发进度
|
||||
|
||||
| 名称 | 优化级别 | 开发进度 |
|
||||
| ------------ | ------------ | ---------- |
|
||||
| CFG优化 | 函数级 | 已完成 |
|
||||
| DCE | 函数级 | 待正确性测试 |
|
||||
| Mem2Reg | 函数级 | 待正确性测试 |
|
||||
| Reg2Mem | 函数级 | 待正确性测试 |
|
||||
|
||||
|
||||
# 部分优化遍的说明
|
||||
|
||||
## Mem2Reg
|
||||
|
||||
Mem2Reg 遍的主要目标是将那些不必要的、只用于局部标量变量的内存分配 (alloca 指令) 消除,并将这些变量的值转换为 SSA 形式。这有助于减少内存访问,提高代码效率,并为后续的优化创造更好的条件。
|
||||
|
||||
通过Mem2Reg理解删除指令时对use关系的维护:
|
||||
|
||||
在 `Mem2Reg` 优化遍中,当 `load` 和 `store` 指令被删除时,其 `use` 关系(即它们作为操作数与其他 `Value` 对象之间的连接)的正确消除是一个关键问题,尤其涉及到 `AllocaInst`。
|
||||
|
||||
结合您提供的 `Mem2RegContext::renameVariables` 代码和我们之前讨论的 `usedelete` 逻辑,下面是 `use` 关系如何被正确消除的详细过程:
|
||||
|
||||
### 问题回顾:`Use` 关系的双向性
|
||||
|
||||
在您的 IR 设计中,`Use` 对象扮演着连接 `User`(使用者,如 `LoadInst`)和 `Value`(被使用者,如 `AllocaInst`)的双向角色:
|
||||
|
||||
* 一个 `User` 持有对其操作数 `Value` 的 `Use` 对象(通过 `User::operands` 列表)。
|
||||
* 一个 `Value` 持有所有使用它的 `User` 的 `Use` 对象(通过 `Value::uses` 列表)。
|
||||
|
||||
原始问题是:当一个 `LoadInst` 或 `StoreInst` 被删除时,如果不对其作为操作数与 `AllocaInst` 之间的 `Use` 关系进行明确清理,`AllocaInst` 的 `uses` 列表中就会留下指向已删除 `LoadInst` / `StoreInst` 的 `Use` 对象,导致内部的 `User*` 指针悬空,在后续访问时引发 `segmentation fault`。
|
||||
|
||||
### `Mem2Reg` 中 `load`/`store` 指令的删除行为
|
||||
|
||||
在 `Mem2RegContext::renameVariables` 函数中,`load` 和 `store` 指令被处理时,其行为如下:
|
||||
|
||||
1. **处理 `LoadInst`:**
|
||||
当找到一个指向可提升 `AllocaInst` 的 `LoadInst` 时,其用途会被 `replaceAllUsesWith(allocaToValueStackMap[alloca].top())` 替换。这意味着任何原本使用 `LoadInst` 本身计算结果的指令,现在都直接使用 SSA 值栈顶部的 `Value`。
|
||||
**重点:** 这一步处理的是 `LoadInst` 作为**被使用的值 (Value)** 时,其 `uses` 列表的清理。即,将 `LoadInst` 的所有使用者重定向到新的 SSA 值,并把这些 `Use` 对象从 `LoadInst` 的 `uses` 列表中移除。
|
||||
|
||||
2. **处理 `StoreInst`:**
|
||||
当找到一个指向可提升 `AllocaInst` 的 `StoreInst` 时,`StoreInst` 存储的值会被压入值栈。`StoreInst` 本身并不产生可被其他指令直接使用的值(其类型是 `void`),所以它没有 `uses` 列表需要替换。
|
||||
**重点:** `StoreInst` 的主要作用是更新内存状态,在 SSA 形式下,它被移除后需要清理它作为**使用者 (User)** 时的操作数关系。
|
||||
|
||||
在这两种情况下,一旦 `load` 或 `store` 指令的 SSA 转换完成,它们都会通过 `instIter = SysYIROptUtils::usedelete(instIter)` 被显式删除。
|
||||
|
||||
### `SysYIROptUtils::usedelete` 如何正确消除 `Use` 关系
|
||||
|
||||
关键在于对 `SysYIROptUtils::usedelete` 函数的修改,使其在删除指令时,同时处理该指令作为 `User` 和 `Value` 的两种 `Use` 关系:
|
||||
|
||||
1. **清理指令作为 `Value` 时的 `uses` 列表 (由 `replaceAllUsesWith` 完成):**
|
||||
在 `usedelete` 函数中,`inst->replaceAllUsesWith(UndefinedValue::get(inst->getType()))` 的调用至关重要。这确保了:
|
||||
* 如果被删除的 `Instruction`(例如 `LoadInst`)产生了结果值并被其他指令使用,所有这些使用者都会被重定向到 `UndefinedValue`(或者 `Mem2Reg` 中具体的 SSA 值)。
|
||||
* 这个过程会遍历 `LoadInst` 的 `uses` 列表,并将这些 `Use` 对象从 `LoadInst` 的 `uses` 列表中移除。这意味着 `LoadInst` 自己不再被任何其他指令使用。
|
||||
|
||||
2. **清理指令作为 `User` 时其操作数的 `uses` 列表 (由 `RemoveUserOperandUses` 完成):**
|
||||
这是您提出的、并已集成到 `usedelete` 中的关键改进点。对于一个被删除的 `Instruction`(它同时也是 `User`),我们需要清理它**自己使用的操作数**所维护的 `use` 关系。
|
||||
* 例如,`LoadInst %op1` 使用了 `%op1`(一个 `AllocaInst`)。当 `LoadInst` 被删除时,`AllocaInst` 的 `uses` 列表中有一个 `Use` 对象指向这个 `LoadInst`。
|
||||
* `RemoveUserOperandUses` 函数会遍历被删除 `User`(即 `LoadInst` 或 `StoreInst`)的 `operands` 列表。
|
||||
* 对于 `operands` 列表中的每个 `std::shared_ptr<Use> use_ptr`,它会获取 `Use` 对象内部指向的 `Value`(例如 `AllocaInst*`),然后调用 `value->removeUse(use_ptr)`。
|
||||
* 这个 `removeUse` 调用会负责将 `use_ptr` 从 `AllocaInst` 的 `uses` 列表中删除。
|
||||
|
||||
### 总结
|
||||
|
||||
通过在 `SysYIROptUtils::usedelete` 中同时执行这两个步骤:
|
||||
|
||||
* `replaceAllUsesWith`:处理被删除指令**作为结果被使用**时的 `use` 关系。
|
||||
* `RemoveUserOperandUses`:处理被删除指令**作为使用者(User)时,其操作数**的 `use` 关系。
|
||||
|
||||
这就确保了当 `Mem2Reg` 遍历并删除 `load` 和 `store` 指令时,无论是它们作为 `Value` 的使用者,还是它们作为 `User` 的操作数,所有相关的 `Use` 对象都能被正确地从 `Value` 的 `uses` 列表中移除,从而避免了悬空指针和后续的 `segmentation fault`。
|
||||
|
||||
最后,当所有指向某个 `AllocaInst` 的 `load` 和 `store` 指令都被移除后,`AllocaInst` 的 `uses` 列表将变得干净(只包含 Phi 指令,如果它们在 SSA 转换中需要保留 Alloca 作为操作数),这时在 `Mem2RegContext::cleanup()` 阶段,`SysYIROptUtils::usedelete(alloca)` 就可以安全地删除 `AllocaInst` 本身了。
|
||||
|
||||
## Reg2Mem
|
||||
|
||||
我们的Reg2Mem 遍的主要目标是作为 Mem2Reg 的一种逆操作,但更具体是解决后端无法识别 PhiInst 指令的问题。主要的速录是将函数参数和 PhiInst 指令的结果从 SSA 形式转换回内存形式,通过插入 alloca、load 和 store 指令来实现。其他非 Phi 的指令结果将保持 SSA 形式。
|
||||
|
||||
## SCCP
|
||||
|
||||
SCCP(稀疏条件常量传播)是一种编译器优化技术,它结合了常量传播和死代码消除。其核心思想是在程序执行过程中,尝试识别并替换那些在编译时就能确定其值的变量(常量),同时移除那些永远不会被执行到的代码块(不可达代码)。
|
||||
|
||||
以下是 SCCP 的实现思路:
|
||||
|
||||
1. 核心数据结构与工作列表:
|
||||
|
||||
Lattice 值(Lattice Value): SCCP 使用三值格(Three-Valued Lattice)来表示变量的状态:
|
||||
|
||||
Top (T): 初始状态,表示变量的值未知,但可能是一个常量。
|
||||
|
||||
Constant (C): 表示变量的值已经确定为一个具体的常量。
|
||||
|
||||
Bottom (⊥): 表示变量的值不确定或不是一个常量(例如,它可能在运行时有多个不同的值,或者从内存中加载)。一旦变量状态变为 Bottom,它就不能再变回 Constant 或 Top。
|
||||
|
||||
SSAPValue: 封装了 Lattice 值和常量具体值(如果状态是 Constant)。
|
||||
|
||||
*valState (map<Value, SSAPValue>):** 存储程序中每个 Value(变量、指令结果等)的当前 SCCP Lattice 状态。
|
||||
|
||||
*ExecutableBlocks (set<BasicBlock>):** 存储在分析过程中被确定为可执行的基本块。
|
||||
|
||||
工作列表 (Worklists):
|
||||
|
||||
cfgWorkList (queue<pair<BasicBlock, BasicBlock>>):** 存储待处理的控制流图(CFG)边。当一个块被标记为可执行时,它的后继边会被添加到这个列表。
|
||||
|
||||
*ssaWorkList (queue<Instruction>):** 存储待处理的 SSA (Static Single Assignment) 指令。当一个指令的任何操作数的状态发生变化时,该指令就会被添加到这个列表,需要重新评估。
|
||||
|
||||
2. 初始化:
|
||||
|
||||
所有 Value 的状态都被初始化为 Top。
|
||||
|
||||
所有基本块都被初始化为不可执行。
|
||||
|
||||
函数的入口基本块被标记为可执行,并且该块中的所有指令被添加到 ssaWorkList。
|
||||
|
||||
3. 迭代过程 (Fixed-Point Iteration):
|
||||
|
||||
SCCP 的核心是一个迭代过程,它交替处理 CFG 工作列表和 SSA 工作列表,直到达到一个不动点(即没有更多的状态变化)。
|
||||
|
||||
处理 cfgWorkList:
|
||||
|
||||
从 cfgWorkList 中取出一个边 (prev, next)。
|
||||
|
||||
如果 next 块之前是不可执行的,现在通过 prev 块可达,则将其标记为可执行 (markBlockExecutable)。
|
||||
|
||||
一旦 next 块变为可执行,其内部的所有指令(特别是 Phi 指令)都需要被重新评估,因此将它们添加到 ssaWorkList。
|
||||
|
||||
处理 ssaWorkList:
|
||||
|
||||
从 ssaWorkList 中取出一个指令 inst。
|
||||
|
||||
重要: 只有当 inst 所在的块是可执行的,才处理该指令。不可执行块中的指令不参与常量传播。
|
||||
|
||||
计算新的 Lattice 值 (computeLatticeValue): 根据指令类型和其操作数的当前 Lattice 状态,计算 inst 的新的 Lattice 状态。
|
||||
|
||||
常量折叠: 如果所有操作数都是常量,则可以直接执行运算并得到一个新的常量结果。
|
||||
|
||||
Bottom 传播: 如果任何操作数是 Bottom,或者运算规则导致不确定(例如除以零),则结果为 Bottom。
|
||||
|
||||
Phi 指令的特殊处理: Phi 指令的值取决于其所有可执行的前驱块传入的值。
|
||||
|
||||
如果所有可执行前驱都提供了相同的常量 C,则 Phi 结果为 C。
|
||||
|
||||
如果有任何可执行前驱提供了 Bottom,或者不同的可执行前驱提供了不同的常量,则 Phi 结果为 Bottom。
|
||||
|
||||
如果所有可执行前驱都提供了 Top,则 Phi 结果仍为 Top。
|
||||
|
||||
更新状态: 如果 inst 的新计算出的 Lattice 值与它当前存储的值不同,则更新 valState[inst]。
|
||||
|
||||
传播变化: 如果 inst 的状态发生变化,那么所有使用 inst 作为操作数的指令都可能受到影响,需要重新评估。因此,将 inst 的所有使用者添加到 ssaWorkList。
|
||||
|
||||
处理终结符指令 (BranchInst, ReturnInst):
|
||||
|
||||
对于条件分支 BranchInst,如果其条件操作数变为常量:
|
||||
|
||||
如果条件为真,则只有真分支的目标块是可达的,将该边添加到 cfgWorkList。
|
||||
|
||||
如果条件为假,则只有假分支的目标块是可达的,将该边添加到 cfgWorkList。
|
||||
|
||||
如果条件不是常量(Top 或 Bottom),则两个分支都可能被执行,将两边的边都添加到 cfgWorkList。
|
||||
|
||||
这会影响 CFG 的可达性分析,可能导致新的块被标记为可执行。
|
||||
|
||||
4. 应用优化 (Transformation):
|
||||
|
||||
当两个工作列表都为空,达到不动点后,程序代码开始进行实际的修改:
|
||||
|
||||
常量替换:
|
||||
|
||||
遍历所有指令。如果指令的 valState 为 Constant,则用相应的 ConstantValue 替换该指令的所有用途 (replaceAllUsesWith)。
|
||||
|
||||
将该指令标记为待删除。
|
||||
|
||||
对于指令的操作数,如果其 valState 为 Constant,则直接将操作数替换为对应的 ConstantValue(常量折叠)。
|
||||
|
||||
删除死指令: 遍历所有标记为待删除的指令,并从其父基本块中删除它们。
|
||||
|
||||
删除不可达基本块: 遍历函数中的所有基本块。如果一个基本块没有被标记为可执行 (ExecutableBlocks 中不存在),则将其从函数中删除。但入口块不能删除。
|
||||
|
||||
简化分支指令:
|
||||
|
||||
遍历所有可执行的基本块的终结符指令。
|
||||
|
||||
对于条件分支 BranchInst,如果其条件操作数在 valState 中是 Constant:
|
||||
|
||||
如果条件为真,则将该条件分支替换为一个无条件跳转到真分支目标块的指令。
|
||||
|
||||
如果条件为假,则将该条件分支替换为一个无条件跳转到假分支目标块的指令。
|
||||
|
||||
更新 CFG,移除不可达的分支边和其前驱信息。
|
||||
|
||||
computeLatticeValue 的具体逻辑:
|
||||
|
||||
这个函数是 SCCP 的核心逻辑,它定义了如何根据指令类型和操作数的当前 Lattice 状态来计算指令结果的 Lattice 状态。
|
||||
|
||||
二元运算 (Add, Sub, Mul, Div, Rem, ICmp, And, Or):
|
||||
|
||||
如果任何一个操作数是 Bottom,结果就是 Bottom。
|
||||
|
||||
如果任何一个操作数是 Top,结果就是 Top。
|
||||
|
||||
如果两个操作数都是 Constant,执行实际的常量运算,结果是一个新的 Constant。
|
||||
|
||||
一元运算 (Neg, Not):
|
||||
|
||||
如果操作数是 Bottom,结果就是 Bottom。
|
||||
|
||||
如果操作数是 Top,结果就是 Top。
|
||||
|
||||
如果操作数是 Constant,执行实际的常量运算,结果是一个新的 Constant。
|
||||
|
||||
Load 指令: 通常情况下,Load 的结果会被标记为 Bottom,因为内存内容通常在编译时无法确定。但如果加载的是已知的全局常量,可能可以确定。在提供的代码中,它通常返回 Bottom。
|
||||
|
||||
Store 指令: Store 不产生值,所以其 SSAPValue 保持 Top 或不关心。
|
||||
|
||||
Call 指令: 大多数 Call 指令(尤其是对外部或有副作用的函数)的结果都是 Bottom。对于纯函数,如果所有参数都是常量,理论上可以折叠,但这需要额外的分析。
|
||||
|
||||
GetElementPtr (GEP) 指令: GEP 计算内存地址。如果所有索引都是常量,地址本身是常量。但 SCCP 关注的是数据值,因此这里通常返回 Bottom,除非有特定的指针常量跟踪。
|
||||
|
||||
Phi 指令: 如上所述,基于所有可执行前驱的传入值进行聚合。
|
||||
|
||||
Alloc 指令: Alloc 分配内存,返回一个指针。其内容通常是 Bottom。
|
||||
|
||||
Branch 和 Return 指令: 这些是终结符指令,不产生一个可用于其他指令的值,通常 SSAPValue 保持 Top 或不关心。
|
||||
|
||||
类型转换 (ZExt, SExt, Trunc, FtoI, ItoF): 如果操作数是 Constant,则执行相应的类型转换,结果仍为 Constant。对于浮点数转换,由于 SSAPValue 的 constantVal 为 int 类型,所以对浮点数的操作会保守地返回 Bottom。
|
||||
|
||||
未处理的指令: 默认情况下,任何未明确处理的指令都被保守地假定为产生 Bottom 值。
|
||||
|
||||
浮点数处理的注意事项:
|
||||
|
||||
在提供的代码中,SSAPValue 的 constantVal 是 int 类型。这使得浮点数常量传播变得复杂。对于浮点数相关的指令(kFAdd, kFMul, kFCmp, kFNeg, kFNot, kItoF, kFtoI 等),如果不能将浮点值准确地存储在 int 中,或者不能可靠地执行浮点运算,那么通常会保守地将结果设置为 Bottom。一个更完善的 SCCP 实现会使用 std::variant<int, float> 或独立的浮点常量存储来处理浮点数。
|
||||
|
||||
## 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过程
|
||||
36
README.md
36
README.md
@ -37,38 +37,4 @@ mysysy/ $ bash setup.sh
|
||||
```
|
||||
|
||||
### 配套脚本
|
||||
(TODO: 需要完善)
|
||||
|
||||
|
||||
### TODO_list:
|
||||
|
||||
除开注释中的TODO后续时间充足可以考虑的TODO:
|
||||
|
||||
- store load指令由于gep指令的引入, 维度信息的记录是非必须的, 考虑删除
|
||||
|
||||
- use def关系经过mem2reg和phi函数明确转换为ssa形式, 以及函数参数通过value数组明确定义, 使得基本块的args参数信息记录非必须, 考虑删除
|
||||
|
||||
---
|
||||
|
||||
## 编译器后端 TODO 列表
|
||||
|
||||
### 1. `CALL` 指令处理不完善 (高优先级)
|
||||
|
||||
* **问题描述**:当前 `RISCv64RegAlloc::getInstrUseDef()` 方法中,对 `CALL` 指令的 `use`/`def` 分析不完整。它正确识别了返回值为 `def` 和参数为 `use`,但**没有将所有调用者保存 (Caller-saved) 的物理寄存器(`T0-T6`, `A0-A7`)标记为隐式 `def` (即 `CALL` 会破坏它们)**。
|
||||
* **潜在后果**:
|
||||
* **活跃性分析错误**:寄存器分配器可能会错误地认为某个跨函数调用活跃的虚拟寄存器是安全的,并将其分配给 `T` 或 `A` 寄存器。
|
||||
* **值被破坏**:在 `CALL` 指令执行后,这些 `T` 或 `A` 寄存器中本应保留的值会被被调用的函数破坏,导致程序行为异常。
|
||||
* **参考文件**:`RISCv64RegAlloc.cpp` (在 `getInstrUseDef` 函数中对 `RVOpcodes::CALL` 的处理)。
|
||||
|
||||
### 2. `T6` 寄存器作为溢出寄存器的问题 (中等优先级)
|
||||
|
||||
* **问题描述**:`RISCv64RegAlloc::rewriteFunction()` 方法中,所有未能成功着色并被溢出 (spilled) 的虚拟寄存器,都被统一替换为物理寄存器 `T6`。
|
||||
* **问题 2.1:`T6` 是调用者保存寄存器,但未被调用者保存**:
|
||||
* `T6` 属于调用者保存寄存器 (`T0-T6` 范围)。
|
||||
* 标准 ABI 要求,如果一个调用者保存寄存器在函数调用前后都活跃(例如,它存储了一个被溢出的变量,而这个变量在 `CALL` 指令之后还需要用到),那么**调用者**有责任在 `CALL` 前保存该寄存器,并在 `CALL` 后恢复它。
|
||||
* 目前的 `rewriteFunction` 没有为 `T6` 插入这种保存/恢复逻辑。
|
||||
* **潜在后果**:如果一个溢出变量被分配到 `T6`,并且它跨函数调用活跃,那么 `putint` 或其他任何被调用的函数可能会随意使用 `T6`,从而破坏该溢出变量的值。
|
||||
* **问题 2.2:所有溢出变量共用一个 `T6`**:
|
||||
* 将所有溢出变量映射到同一个物理寄存器 `T6` 是一种简化的溢出策略。
|
||||
* **潜在后果**:这意味着,每当需要使用一个溢出变量时,其值必须从栈中加载到 `T6`;每当一个溢出变量被定义时,其值必须从 `T6` 存储回栈。这会引入大量的 `load`/`store` 指令,并导致 `T6` 本身成为一个高度冲突的寄存器,严重降低代码效率。
|
||||
* **参考文件**:`RISCv64RegAlloc.cpp` (在 `rewriteFunction` 函数中处理 `spilled_vregs` 的部分)。
|
||||
(TODO: 需要完善)
|
||||
@ -1,272 +0,0 @@
|
||||
# 编译器核心技术与优化详解
|
||||
|
||||
本文档深入剖析 mysysy 编译器的内部实现,重点阐述其在前端、中端和后端所采用的核心编译技术及优化算法,并结合具体实现函数进行说明。
|
||||
|
||||
## 1. 编译器整体架构
|
||||
|
||||
本编译器采用经典的三段式架构,将编译过程清晰地划分为前端、中端和后端三个主要部分。每个部分处理不同的抽象层级,并通过定义良好的接口(AST, IR)进行通信,实现了高度的模块化。
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[源代码 .sy] --> B{前端 Frontend};
|
||||
B --> C[抽象语法树 AST];
|
||||
C --> D{中端 Midend};
|
||||
D --> E[SSA-based IR];
|
||||
E -- 优化 --> F[优化后的 IR];
|
||||
F --> G{后端 Backend};
|
||||
G --> H[目标机代码 MachineInstr];
|
||||
H --> I[RISC-V 64 汇编代码 .s];
|
||||
|
||||
subgraph 前端
|
||||
B
|
||||
end
|
||||
subgraph 中端
|
||||
D
|
||||
end
|
||||
subgraph 后端
|
||||
G
|
||||
end
|
||||
```
|
||||
|
||||
- **前端 (Frontend)**:负责词法、语法、语义分析,将 SysY 源代码解析为抽象语法树 (AST)。
|
||||
- **中端 (Midend)**:基于 AST 生成与具体机器无关的中间表示 (IR),并在此基础上进行深入的分析和优化。
|
||||
- **后端 (Backend)**:将优化后的 IR 翻译成目标平台(RISC-V 64)的汇编代码。
|
||||
|
||||
---
|
||||
|
||||
## 2. 前端技术 (Frontend)
|
||||
|
||||
前端的核心任务是进行语法和语义的分析与验证,其工作流程如下:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph "前端处理流程"
|
||||
Source["源文件 (.sy)"] --> Lexer["词法分析器 (SysYLexer)"];
|
||||
Lexer --> TokenStream["Token 流"];
|
||||
TokenStream --> Parser["语法分析器 (SysYParser)"];
|
||||
Parser --> ParseTree["解析树"];
|
||||
ParseTree --> Visitor["AST构建 (SysYVisitor)"];
|
||||
Visitor --> AST[抽象语法树];
|
||||
end
|
||||
```
|
||||
|
||||
- **词法与语法分析**:
|
||||
- **技术**: 采用 **ANTLR (ANother Tool for Language Recognition)** 框架。通过在 `frontend/SysY.g4` 文件中定义的上下文无关文法,ANTLR 能够自动生成高效的 LL(*) 词法分析器 (`SysYLexer.cpp`) 和语法分析器 (`SysYParser.cpp`)。
|
||||
- **实现**: 词法分析器将字符流转换为记号 (Token) 流,语法分析器则根据文法规则将记号流组织成一棵解析树 (Parse Tree)。这棵树精确地反映了源代码的语法结构。
|
||||
|
||||
- **AST 构建**:
|
||||
- **技术**: 应用 **访问者 (Visitor) 设计模式** 遍历 ANTLR 生成的解析树。该模式将数据结构(解析树)与作用于其上的操作(AST构建逻辑)解耦。
|
||||
- **实现**: `frontend/SysYVisitor.cpp` 中定义了具体的遍历逻辑。在遍历过程中,会构建一个比解析树更抽象、更面向编译需求的**抽象语法树 (Abstract Syntax Tree, AST)**。AST 忽略了纯粹的语法细节(如括号、分号),只保留了核心的语义结构,是前端传递给中端的接口。
|
||||
|
||||
---
|
||||
|
||||
## 3. 中端技术与优化 (Midend)
|
||||
|
||||
中端是编译器的核心,所有与目标机器无关的分析和优化都在此阶段完成。
|
||||
|
||||
### 3.1. 中间表示 (IR) 及设计要点
|
||||
|
||||
- **技术**: 设计了一种三地址码(Three-Address Code)风格的中间表示,其形式和设计哲学深受 **LLVM IR** 的启发。IR 的核心特征是采用了**静态单赋值 (Static Single Assignment, SSA)** 形式。
|
||||
- **实现**: `midend/IR.cpp` 定义了 IR 的核心数据结构,如 `Instruction`, `BasicBlock`, `Function` 和 `Module`。`midend/SysYIRGenerator.cpp` 负责将前端的 AST 转换为这种 IR。在 SSA 形式下,每个变量只被赋值一次,使得变量的定义-使用关系(Def-Use Chain)变得异常清晰,极大地简化了后续的优化算法。通过继承并重写 SysYBaseVisitor 类,遍历 AST 节点生成自定义 IR,并在 IR 生成阶段实现了简单的常量传播和公共子表达式消除(CSE)。
|
||||
- **设计要点**:
|
||||
- **`alloca` 指令集中管理**:
|
||||
所有 `alloca` 指令统一放置在入口基本块,并与实际计算指令分离。这有助于后续指令调度器专注于优化计算密集型指令的执行顺序,避免内存分配指令的干扰。
|
||||
- **消除 `fallthrough` 现象**:
|
||||
通过确保所有基本块均以终结指令结尾,消除基本块间的 `fallthrough`,简化了控制流图(CFG)的构建和分析。这一做法提升了编译器整体质量,使中端各类 Pass 的编写和维护更加规范和高效。
|
||||
|
||||
|
||||
### 3.2. 核心优化详解
|
||||
|
||||
编译器的分析和优化被组织成一系列独立的“遍”(Pass)。每个 Pass 都是一个独立的算法模块,对 IR 进行特定的分析或变换。这种设计具有高度的模块化和可扩展性。
|
||||
|
||||
#### 3.2.1. SSA 构建与解构
|
||||
|
||||
- **Mem2Reg (`Mem2Reg.cpp`)**:
|
||||
- **目标**: 将对栈内存 (`alloca`) 的 `load`/`store` 操作,提升为对虚拟寄存器的直接操作,并构建 SSA 形式。
|
||||
- **技术**: 该过程是实现 SSA 的关键。它依赖于**支配树 (Dominator Tree)** 分析,通过寻找变量定义块的**支配边界 (Dominance Frontier)** 来确定在何处插入 **Φ (Phi) 函数**。
|
||||
- **实现**: `Mem2RegContext::run` 驱动此过程。首先调用 `isPromotableAlloca` 识别所有仅被 `load`/`store` 使用的标量 `alloca`。然后,`insertPhis` 根据支配边界信息在必要的控制流汇合点插入 `phi` 指令。最后,`renameVariables` 递归地遍历支配树,用一个模拟的值栈来将 `load` 替换为栈顶的 SSA 值,将 `store` 视为对栈的一次 `push` 操作,从而完成重命名。值得一提的是,由于我们在IR生成阶段就将所有alloca指令统一放置在入口块,极大地简化了Mem2Reg遍的实现和支配树分析的计算。
|
||||
|
||||
- **Reg2Mem (`Reg2Mem.cpp`)**:
|
||||
- **目标**: 执行 `Mem2Reg` 的逆操作,将程序从 SSA 形式转换回基于内存的表示。这通常是为不支持 SSA 的后端做准备的**SSA解构 (SSA Destruction)** 步骤。
|
||||
- **技术**: 为每个 SSA 值(指令结果、函数参数)在函数入口创建一个 `alloca` 栈槽。然后,在每个 SSA 值的定义点之后插入一个 `store` 将其存入对应的栈槽;在每个使用点之前插入一个 `load` 从栈槽中取出值。
|
||||
- **实现**: `Reg2MemContext::run` 驱动此过程。`allocateMemoryForSSAValues` 为所有需要转换的 SSA 值创建 `alloca` 指令。`rewritePhis` 特殊处理 `phi` 指令,在每个前驱块的末尾插入 `store`。`insertLoadsAndStores` 则处理所有非 `phi` 指令的定义和使用,插入相应的 `store` 和 `load`。虽然
|
||||
|
||||
#### 3.2.2. 常量与死代码优化
|
||||
|
||||
- **SCCP (`SCCP.cpp`)**:
|
||||
- **目标**: 稀疏条件常量传播。在编译期计算常量表达式,并利用分支条件为常数的信息来消除死代码,比简单的常量传播更强大。
|
||||
- **技术**: 这是一种基于数据流分析的格理论(Lattice Theory)的优化。它为每个变量维护一个值状态,可能为 `Top` (未定义), `Constant` (某个常量值), 或 `Bottom` (非常量)。同时,它跟踪基本块的可达性,如果一个分支的条件被推断为常量,则其不可达的后继分支在分析中会被直接忽略。
|
||||
- **实现**: `SCCPContext::run` 驱动整个分析过程。它维护一个指令工作列表和一个边工作列表。`ProcessInstruction` 和 `ProcessEdge` 函数交替执行,不断地从 IR 中传播常量和可达性信息,直到达到不动点为止。最后,`PropagateConstants` 和 `SimplifyControlFlow` 将推断出的常量替换到代码中,并移除死块。
|
||||
|
||||
- **DCE (`DCE.cpp`)**:
|
||||
- **目标**: 简单死代码消除。移除那些计算结果对程序输出没有贡献的指令。
|
||||
- **技术**: 采用**标记-清除 (Mark and Sweep)** 算法。从具有副作用的指令(如 `store`, `call`, `return`)开始,反向追溯其操作数,标记所有相关的指令为“活跃”。
|
||||
- **实现**: `DCEContext::run` 实现了此算法。第一次遍历时,通过 `isAlive` 函数识别出具有副作用的“根”指令,然后调用 `addAlive` 递归地将所有依赖的指令加入 `alive_insts` 集合。第二次遍历时,所有未被标记为活跃的指令都将被删除。
|
||||
- **未来规划**: 后续开发更多分析遍会为DCE收集更多的IR信息,能够迭代出更健壮的DEC遍。
|
||||
|
||||
#### 3.2.3. 控制流图 (CFG) 优化
|
||||
|
||||
- **实现**: `SysYIRCFGOpt.cpp` 中定义了一系列用于清理和简化控制流图的 Pass。
|
||||
- **`SysYDelInstAfterBrPass`**: 删除分支指令后的死代码。
|
||||
- **`SysYDelNoPreBLockPass`**: 通过从入口块开始的图遍历(BFS),识别并删除所有不可达的基本块。
|
||||
- **`SysYDelEmptyBlockPass`**: 识别并删除仅包含一条无条件跳转指令的空块,将其前驱直接重定向到其后继。
|
||||
- **`SysYBlockMergePass`**: 如果一个块 A 只有一个后继 B,且 B 只有一个前驱 A,则将 A 和 B 合并为一个块。
|
||||
- **`SysYCondBr2BrPass`**: 如果一个条件分支的条件是常量,则将其转换为一个无条件分支。
|
||||
- **`SysYAddReturnPass`**: 确保所有没有终结指令的函数出口路径都有一个 `return` 指令,以保证 CFG 的完整性。
|
||||
|
||||
#### 3.2.4. 其他优化
|
||||
|
||||
- **LargeArrayToGlobal (`LargeArrayToGlobal.cpp`)**:
|
||||
- **目标**: 防止因大型局部数组导致的栈溢出,并可能改善数据局部性。
|
||||
- **技术**: 遍历函数中的 `alloca` 指令,如果通过 `calculateTypeSize` 计算出其分配的内存大小超过一个阈值(如 1024 字节),则将其转换为一个全局变量。
|
||||
- **实现**: `convertAllocaToGlobal` 函数负责创建一个新的 `GlobalValue`,并调用 `replaceAllUsesWith` 将原 `alloca` 的所有使用者重定向到新的全局变量,最后删除原 `alloca` 指令。
|
||||
|
||||
#### 3.3. 核心分析遍
|
||||
|
||||
为了为优化遍收集信息,最大程度发掘程序优化潜力,我们目前设计并实现了以下关键的分析遍:
|
||||
|
||||
- **支配树分析 (Dominator Tree Analysis)**:
|
||||
- **技术**: 通过计算每个基本块的支配节点,构建出一棵支配树结构。我们在计算支配节点时采用了**逆后序遍历(RPO, Reverse Post Order)**,以保证数据流分析的收敛速度和正确性。在计算直接支配者(Idom, Immediate Dominator)时,采用了经典的**Lengauer-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.
Binary file not shown.
@ -1,304 +0,0 @@
|
||||
#!/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
|
||||
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 " -h, --help 显示此帮助信息并退出。"
|
||||
echo ""
|
||||
echo "可在任何时候按 Ctrl+C 来中断测试并显示当前已完成的测例总结。"
|
||||
}
|
||||
|
||||
display_file_content() {
|
||||
local file_path="$1"
|
||||
local title="$2"
|
||||
local max_lines="$3"
|
||||
if [ ! -f "$file_path" ]; then return; fi
|
||||
echo -e "$title"
|
||||
local line_count
|
||||
line_count=$(wc -l < "$file_path")
|
||||
if [ "$line_count" -gt "$max_lines" ]; then
|
||||
head -n "$max_lines" "$file_path"
|
||||
echo -e "\e[33m[... 输出已截断,共 ${line_count} 行 ...]\e[0m"
|
||||
else
|
||||
cat "$file_path"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- 新增:总结报告函数 ---
|
||||
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 ;;
|
||||
-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 ""
|
||||
|
||||
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}"
|
||||
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
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}"
|
||||
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
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
|
||||
442
script/runit.sh
442
script/runit.sh
@ -1,442 +0,0 @@
|
||||
#!/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
|
||||
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 " -h, --help 显示此帮助信息并退出。"
|
||||
echo ""
|
||||
echo "注意: 默认行为 (无 -e 或 -eir) 是将 .sy 文件同时编译为 .s (汇编) 和 .ll (IR),不执行。"
|
||||
echo " 可在任何时候按 Ctrl+C 来中断测试并显示当前已完成的测例总结。"
|
||||
}
|
||||
|
||||
|
||||
# 显示文件内容并根据行数截断的函数
|
||||
display_file_content() {
|
||||
local file_path="$1"
|
||||
local title="$2"
|
||||
local max_lines="$3"
|
||||
if [ ! -f "$file_path" ]; then return; fi
|
||||
echo -e "$title"
|
||||
local line_count
|
||||
line_count=$(wc -l < "$file_path")
|
||||
if [ "$line_count" -gt "$max_lines" ]; then
|
||||
head -n "$max_lines" "$file_path"
|
||||
echo -e "\e[33m[... 输出已截断,共 ${line_count} 行 ...]\e[0m"
|
||||
else
|
||||
cat "$file_path"
|
||||
fi
|
||||
}
|
||||
|
||||
# 清理临时文件的函数
|
||||
clean_tmp() {
|
||||
echo "正在清理临时目录: ${TMP_DIR}"
|
||||
rm -rf "${TMP_DIR}"/*
|
||||
}
|
||||
|
||||
# --- 新增:总结报告函数 ---
|
||||
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 ;;
|
||||
-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}"
|
||||
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}"
|
||||
display_file_content "${output_actual_file_from_ir}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
test_logic_passed=0
|
||||
fi
|
||||
else
|
||||
if [ $ACTUAL_RETURN_CODE -ne 0 ]; then echo -e "\e[33m警告: 程序以非零状态 ${ACTUAL_RETURN_CODE} 退出 (纯输出比较模式)。\e[0m"; fi
|
||||
if diff -q <(tr -d '[:space:]' < "${output_actual_file_from_ir}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
|
||||
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
|
||||
else
|
||||
echo -e "\e[31m 失败: 输出不匹配\e[0m"
|
||||
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
display_file_content "${output_actual_file_from_ir}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
test_logic_passed=0
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
|
||||
test_logic_passed=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
[ "$step_failed" -eq 0 ] && [ "$test_logic_passed" -eq 1 ] && is_passed=1
|
||||
|
||||
# --- 模式 2: 直接执行模式 (-e) ---
|
||||
elif ${EXECUTE_MODE}; then
|
||||
step_failed=0
|
||||
test_logic_passed=0
|
||||
|
||||
echo " [1/3] 使用 sysyc 编译为汇编 (超时 ${SYSYC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file_S}" ${OPTIMIZE_FLAG}
|
||||
SYSYC_STATUS=$?
|
||||
if [ $SYSYC_STATUS -ne 0 ]; then
|
||||
[ $SYSYC_STATUS -eq 124 ] && echo -e "\e[31m错误: SysY (汇编) 编译超时\e[0m" || echo -e "\e[31m错误: SysY (汇编) 编译失败,退出码: ${SYSYC_STATUS}\e[0m"
|
||||
step_failed=1
|
||||
fi
|
||||
|
||||
if [ "$step_failed" -eq 0 ]; then
|
||||
echo " [2/3] 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file_S}" -o "${executable_file_S}" -L"${LIB_DIR}" -lsysy_riscv -static
|
||||
GCC_STATUS=$?
|
||||
if [ $GCC_STATUS -ne 0 ]; then
|
||||
[ $GCC_STATUS -eq 124 ] && echo -e "\e[31m错误: GCC 编译超时\e[0m" || echo -e "\e[31m错误: GCC 编译失败,退出码: ${GCC_STATUS}\e[0m"
|
||||
step_failed=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$step_failed" -eq 0 ]; then
|
||||
echo " [3/3] 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
|
||||
exec_cmd="${QEMU_RISCV64} \"${executable_file_S}\""
|
||||
[ -f "${input_file}" ] && exec_cmd+=" < \"${input_file}\""
|
||||
exec_cmd+=" > \"${output_actual_file_S}\""
|
||||
|
||||
eval "timeout -s KILL ${EXEC_TIMEOUT} ${exec_cmd}"
|
||||
ACTUAL_RETURN_CODE=$?
|
||||
|
||||
if [ "$ACTUAL_RETURN_CODE" -eq 124 ]; then
|
||||
echo -e "\e[31m 执行超时: 运行超过 ${EXEC_TIMEOUT} 秒\e[0m"
|
||||
else
|
||||
if [ -f "${output_reference_file}" ]; then
|
||||
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
|
||||
test_logic_passed=1
|
||||
if [[ "$LAST_LINE_TRIMMED" =~ ^[-+]?[0-9]+$ ]]; then
|
||||
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
|
||||
EXPECTED_STDOUT_FILE="${TMP_DIR}/${output_base_name}_sysyc_S.expected_stdout"
|
||||
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
|
||||
|
||||
if [ "$ACTUAL_RETURN_CODE" -eq "$EXPECTED_RETURN_CODE" ]; then
|
||||
echo -e "\e[32m 返回码测试成功: (${ACTUAL_RETURN_CODE}) 与期望值 (${EXPECTED_RETURN_CODE}) 匹配\e[0m"
|
||||
else
|
||||
echo -e "\e[31m 返回码测试失败: 期望: ${EXPECTED_RETURN_CODE}, 实际: ${ACTUAL_RETURN_CODE}\e[0m"
|
||||
test_logic_passed=0
|
||||
fi
|
||||
|
||||
if diff -q <(tr -d '[:space:]' < "${output_actual_file_S}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
||||
[ "$test_logic_passed" -eq 1 ] && echo -e "\e[32m 标准输出测试成功\e[0m"
|
||||
else
|
||||
echo -e "\e[31m 标准输出测试失败\e[0m"
|
||||
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
display_file_content "${output_actual_file_S}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
test_logic_passed=0
|
||||
fi
|
||||
else
|
||||
if [ $ACTUAL_RETURN_CODE -ne 0 ]; then echo -e "\e[33m警告: 程序以非零状态 ${ACTUAL_RETURN_CODE} 退出 (纯输出比较模式)。\e[0m"; fi
|
||||
if diff -q <(tr -d '[:space:]' < "${output_actual_file_S}") <(tr -d '[:space:]' < "${output_reference_file}") >/dev/null 2>&1; then
|
||||
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
|
||||
else
|
||||
echo -e "\e[31m 失败: 输出不匹配\e[0m"
|
||||
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
display_file_content "${output_actual_file_S}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
||||
test_logic_passed=0
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo " 无参考输出文件。程序返回码: ${ACTUAL_RETURN_CODE}"
|
||||
test_logic_passed=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
[ "$step_failed" -eq 0 ] && [ "$test_logic_passed" -eq 1 ] && is_passed=1
|
||||
|
||||
# --- 模式 3: 默认编译模式 ---
|
||||
else
|
||||
s_compile_ok=0
|
||||
ir_compile_ok=0
|
||||
|
||||
echo " [1/2] 使用 sysyc 编译为汇编 (超时 ${SYSYC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file_S}" ${OPTIMIZE_FLAG}
|
||||
SYSYC_S_STATUS=$?
|
||||
if [ $SYSYC_S_STATUS -eq 0 ]; then
|
||||
s_compile_ok=1
|
||||
echo -e " \e[32m-> ${assembly_file_S} [成功]\e[0m"
|
||||
else
|
||||
[ $SYSYC_S_STATUS -eq 124 ] && echo -e " \e[31m-> [编译超时]\e[0m" || echo -e " \e[31m-> [编译失败, 退出码: ${SYSYC_S_STATUS}]\e[0m"
|
||||
fi
|
||||
|
||||
echo " [2/2] 使用 sysyc 编译为 IR (超时 ${SYSYC_TIMEOUT}s)..."
|
||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" -o "${ir_file}" ${OPTIMIZE_FLAG}
|
||||
SYSYC_IR_STATUS=$?
|
||||
if [ $SYSYC_IR_STATUS -eq 0 ]; then
|
||||
ir_compile_ok=1
|
||||
echo -e " \e[32m-> ${ir_file} [成功]\e[0m"
|
||||
else
|
||||
[ $SYSYC_IR_STATUS -eq 124 ] && echo -e " \e[31m-> [编译超时]\e[0m" || echo -e " \e[31m-> [编译失败, 退出码: ${SYSYC_IR_STATUS}]\e[0m"
|
||||
fi
|
||||
|
||||
if [ "$s_compile_ok" -eq 1 ] && [ "$ir_compile_ok" -eq 1 ]; then
|
||||
is_passed=1
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- 统计结果 ---
|
||||
if [ "$is_passed" -eq 1 ]; then
|
||||
((PASSED_CASES++))
|
||||
else
|
||||
# 确保 FAILED_CASES_LIST 的每一项都以换行符结尾
|
||||
FAILED_CASES_LIST+="${relative_path_no_ext}.sy\n"
|
||||
fi
|
||||
echo ""
|
||||
done <<< "$sy_files"
|
||||
|
||||
# --- 修改:调用总结函数 ---
|
||||
print_summary
|
||||
171
src/AddressCalculationExpansion.cpp
Normal file
171
src/AddressCalculationExpansion.cpp
Normal file
@ -0,0 +1,171 @@
|
||||
#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,24 +1,52 @@
|
||||
# src/CMakeLists.txt
|
||||
# add_subdirectory 命令会负责遍历子目录并查找其内部的 CMakeLists.txt 文件
|
||||
add_subdirectory(frontend)
|
||||
add_subdirectory(midend)
|
||||
add_subdirectory(backend/RISCv64)
|
||||
# 移除 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
|
||||
# )
|
||||
|
||||
# 构建 sysyc 可执行文件,链接各个模块的库
|
||||
# 移除 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 等文件
|
||||
add_executable(sysyc
|
||||
sysyc.cpp
|
||||
sysyc.cpp
|
||||
SysYLexer.cpp # 手动提供的文件
|
||||
SysYParser.cpp # 手动提供的文件
|
||||
SysYVisitor.cpp # 手动提供的文件
|
||||
IR.cpp
|
||||
SysYIRGenerator.cpp
|
||||
SysYIRPrinter.cpp
|
||||
SysYIROptPre.cpp
|
||||
SysYIRAnalyser.cpp
|
||||
# DeadCodeElimination.cpp
|
||||
AddressCalculationExpansion.cpp
|
||||
# Mem2Reg.cpp
|
||||
# Reg2Mem.cpp
|
||||
RISCv64Backend.cpp
|
||||
RISCv64ISel.cpp
|
||||
RISCv64RegAlloc.cpp
|
||||
RISCv64AsmPrinter.cpp
|
||||
RISCv64Passes.cpp
|
||||
)
|
||||
|
||||
# 链接各个模块的库
|
||||
target_link_libraries(sysyc PRIVATE
|
||||
frontend_lib
|
||||
midend_lib
|
||||
riscv64_backend_lib
|
||||
antlr4_shared
|
||||
)
|
||||
|
||||
# 设置 include 路径,包含项目顶层 include 目录
|
||||
# 设置 include 路径,包含 ANTLR 运行时库和项目头文件
|
||||
target_include_directories(sysyc PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include # 项目头文件目录
|
||||
${ANTLR_RUNTIME}/runtime/src # ANTLR运行时库头文件
|
||||
)
|
||||
${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)
|
||||
750
src/IR.cpp
Normal file
750
src/IR.cpp
Normal file
@ -0,0 +1,750 @@
|
||||
#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::getSize() const -> unsigned {
|
||||
switch (kind) {
|
||||
case kInt:
|
||||
case kFloat:
|
||||
return 4;
|
||||
case kLabel:
|
||||
case kPointer:
|
||||
case kFunction:
|
||||
return 8;
|
||||
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();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
case Instruction::kLa: {
|
||||
auto oldLaInst = dynamic_cast<LaInst *>(inst);
|
||||
auto oldPointer = oldLaInst->getPointer();
|
||||
Value *newPointer;
|
||||
std::vector<Value *> newIndices;
|
||||
newPointer = oldNewValueMap.at(oldPointer);
|
||||
|
||||
for (const auto &index : oldLaInst->getIndices()) {
|
||||
newIndices.emplace_back(oldNewValueMap.at(index->getValue()));
|
||||
}
|
||||
ss << oldLaInst->getName() << suffix;
|
||||
auto newLaInst = new LaInst(newPointer, newIndices, oldNewBlockMap.at(oldLaInst->getParent()), ss.str());
|
||||
ss.str("");
|
||||
oldNewValueMap.emplace(oldLaInst, newLaInst);
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::kGetSubArray: {
|
||||
auto oldGetSubArrayInst = dynamic_cast<GetSubArrayInst *>(inst);
|
||||
auto oldFather = oldGetSubArrayInst->getFatherArray();
|
||||
auto oldChild = oldGetSubArrayInst->getChildArray();
|
||||
Value *newFather;
|
||||
Value *newChild;
|
||||
std::vector<Value *> newIndices;
|
||||
newFather = oldNewValueMap.at(oldFather);
|
||||
newChild = oldNewValueMap.at(oldChild);
|
||||
|
||||
for (const auto &index : oldGetSubArrayInst->getIndices()) {
|
||||
newIndices.emplace_back(oldNewValueMap.at(index->getValue()));
|
||||
}
|
||||
ss << oldGetSubArrayInst->getName() << suffix;
|
||||
auto newGetSubArrayInst =
|
||||
new GetSubArrayInst(dynamic_cast<LVal *>(newFather), dynamic_cast<LVal *>(newChild), newIndices,
|
||||
oldNewBlockMap.at(oldGetSubArrayInst->getParent()), ss.str());
|
||||
ss.str("");
|
||||
oldNewValueMap.emplace(oldGetSubArrayInst, newGetSubArrayInst);
|
||||
break;
|
||||
}
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
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 -> User * {
|
||||
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, User *variable) -> User * {
|
||||
User *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,10 +1,20 @@
|
||||
#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) {}
|
||||
|
||||
@ -12,12 +22,57 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64AsmPrinter::printPrologue() {
|
||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||
// 序言需要为保存ra和s0预留16字节
|
||||
int total_stack_size = frame_info.locals_size + frame_info.spill_size + 16;
|
||||
int aligned_stack_size = (total_stack_size + 15) & ~15;
|
||||
frame_info.total_size = aligned_stack_size;
|
||||
|
||||
if (aligned_stack_size > 0) {
|
||||
*OS << " addi sp, sp, -" << aligned_stack_size << "\n";
|
||||
*OS << " sd ra, " << (aligned_stack_size - 8) << "(sp)\n";
|
||||
*OS << " sd s0, " << (aligned_stack_size - 16) << "(sp)\n";
|
||||
*OS << " addi s0, sp, " << aligned_stack_size << "\n";
|
||||
}
|
||||
|
||||
// 忠实还原保存函数入口参数的逻辑
|
||||
Function* F = MFunc->getFunc();
|
||||
if (F && F->getEntryBlock()) {
|
||||
int arg_idx = 0;
|
||||
RISCv64ISel* isel = MFunc->getISel();
|
||||
for (AllocaInst* alloca_for_param : F->getEntryBlock()->getArguments()) {
|
||||
if (arg_idx >= 8) break;
|
||||
|
||||
unsigned vreg = isel->getVReg(alloca_for_param);
|
||||
if (frame_info.alloca_offsets.count(vreg)) {
|
||||
int offset = frame_info.alloca_offsets.at(vreg);
|
||||
auto arg_reg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + arg_idx);
|
||||
*OS << " sw " << regToString(arg_reg) << ", " << offset << "(s0)\n";
|
||||
}
|
||||
arg_idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64AsmPrinter::printEpilogue() {
|
||||
int aligned_stack_size = MFunc->getFrameInfo().total_size;
|
||||
if (aligned_stack_size > 0) {
|
||||
*OS << " ld ra, " << (aligned_stack_size - 8) << "(sp)\n";
|
||||
*OS << " ld s0, " << (aligned_stack_size - 16) << "(sp)\n";
|
||||
*OS << " addi sp, sp, " << aligned_stack_size << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64AsmPrinter::printBasicBlock(MachineBasicBlock* mbb, bool debug) {
|
||||
if (!mbb->getName().empty()) {
|
||||
*OS << mbb->getName() << ":\n";
|
||||
@ -29,6 +84,9 @@ 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) {
|
||||
// 标签直接打印,不加缩进
|
||||
@ -44,7 +102,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::MULH: *OS << "mulh "; break;
|
||||
case RVOpcodes::MUL: *OS << "mul "; break; case RVOpcodes::MULW: *OS << "mulw "; 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;
|
||||
@ -63,9 +121,7 @@ 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::FLW: *OS << "flw "; break;
|
||||
case RVOpcodes::FSW: *OS << "fsw "; break; case RVOpcodes::FLD: *OS << "fld "; break;
|
||||
case RVOpcodes::FSD: *OS << "fsd "; break;
|
||||
case RVOpcodes::SD: *OS << "sd "; 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;
|
||||
@ -74,66 +130,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::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()) {
|
||||
if (op->getKind() == MachineOperand::KIND_LABEL) {
|
||||
printOperand(op.get());
|
||||
break; // 找到标签后即可退出
|
||||
}
|
||||
}
|
||||
*OS << "\n";
|
||||
return; // 处理完毕,直接返回,不再执行后续的通用操作数打印
|
||||
}
|
||||
case RVOpcodes::SNEZ: *OS << "snez "; break;
|
||||
case RVOpcodes::CALL: *OS << "call "; break;
|
||||
case RVOpcodes::LABEL:
|
||||
// printOperand(instr->getOperands()[0].get());
|
||||
// *OS << ":";
|
||||
break;
|
||||
case RVOpcodes::FRAME_LOAD_W:
|
||||
case RVOpcodes::FRAME_LOAD:
|
||||
// It should have been eliminated by RegAlloc
|
||||
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
|
||||
*OS << "frame_load_w "; break;
|
||||
case RVOpcodes::FRAME_LOAD_D:
|
||||
*OS << "frame_load "; break;
|
||||
case RVOpcodes::FRAME_STORE:
|
||||
// It should have been eliminated by RegAlloc
|
||||
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
|
||||
*OS << "frame_load_d "; break;
|
||||
case RVOpcodes::FRAME_STORE_W:
|
||||
// It should have been eliminated by RegAlloc
|
||||
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
|
||||
*OS << "frame_store_w "; break;
|
||||
case RVOpcodes::FRAME_STORE_D:
|
||||
// It should have been eliminated by RegAlloc
|
||||
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
|
||||
*OS << "frame_store_d "; break;
|
||||
*OS << "frame_store "; break;
|
||||
case RVOpcodes::FRAME_ADDR:
|
||||
// It should have been eliminated by RegAlloc
|
||||
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
|
||||
*OS << "frame_addr "; break;
|
||||
case RVOpcodes::FRAME_LOAD_F:
|
||||
if (!debug) throw std::runtime_error("FRAME_LOAD_F not eliminated before AsmPrinter");
|
||||
*OS << "frame_load_f "; break;
|
||||
case RVOpcodes::FRAME_STORE_F:
|
||||
if (!debug) throw std::runtime_error("FRAME_STORE_F not eliminated before AsmPrinter");
|
||||
*OS << "frame_store_f "; break;
|
||||
case RVOpcodes::PSEUDO_KEEPALIVE:
|
||||
if (!debug) throw std::runtime_error("PSEUDO_KEEPALIVE not eliminated before AsmPrinter");
|
||||
*OS << "keepalive "; break;
|
||||
default:
|
||||
throw std::runtime_error("Unknown opcode in AsmPrinter");
|
||||
}
|
||||
@ -223,30 +237,4 @@ 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
|
||||
92
src/RISCv64Backend.cpp
Normal file
92
src/RISCv64Backend.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
#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段)
|
||||
if (!module->getGlobals().empty()) {
|
||||
ss << ".data\n";
|
||||
for (const auto& global : module->getGlobals()) {
|
||||
ss << ".globl " << global->getName() << "\n";
|
||||
ss << global->getName() << ":\n";
|
||||
const auto& init_values = global->getInitValues();
|
||||
for (size_t i = 0; i < init_values.getValues().size(); ++i) {
|
||||
auto val = init_values.getValues()[i];
|
||||
auto count = init_values.getNumbers()[i];
|
||||
if (auto constant = dynamic_cast<ConstantValue*>(val)) {
|
||||
for (unsigned j = 0; j < count; ++j) {
|
||||
if (constant->isInt()) {
|
||||
ss << " .word " << constant->getInt() << "\n";
|
||||
} else {
|
||||
float f = constant->getFloat();
|
||||
uint32_t float_bits = *(uint32_t*)&f;
|
||||
ss << " .word " << float_bits << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 处理函数 (.text段)
|
||||
if (!module->getFunctions().empty()) {
|
||||
ss << ".text\n";
|
||||
for (const auto& func_pair : module->getFunctions()) {
|
||||
if (func_pair.second.get()) {
|
||||
ss << function_gen(func_pair.second.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
// function_gen 现在是包含具体优化名称的、完整的处理流水线
|
||||
std::string RISCv64CodeGen::function_gen(Function* func) {
|
||||
// === 完整的后端处理流水线 ===
|
||||
|
||||
// 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers)
|
||||
RISCv64ISel isel;
|
||||
std::unique_ptr<MachineFunction> mfunc = isel.runOnFunction(func);
|
||||
|
||||
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();
|
||||
|
||||
// 阶段 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 << ss1.str(); // 将指令选择阶段的结果也包含在最终输出中
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
989
src/RISCv64ISel.cpp
Normal file
989
src/RISCv64ISel.cpp
Normal file
@ -0,0 +1,989 @@
|
||||
#include "RISCv64ISel.h"
|
||||
#include <stdexcept>
|
||||
#include <set>
|
||||
#include <functional>
|
||||
#include <cmath> // For std::fabs
|
||||
#include <limits> // For std::numeric_limits
|
||||
#include <iostream>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// DAG节点定义 (内部实现)
|
||||
struct RISCv64ISel::DAGNode {
|
||||
enum NodeKind { CONSTANT, LOAD, STORE, BINARY, CALL, RETURN, BRANCH, ALLOCA_ADDR, UNARY, MEMSET };
|
||||
NodeKind kind;
|
||||
Value* value = nullptr;
|
||||
std::vector<DAGNode*> operands;
|
||||
std::vector<DAGNode*> users;
|
||||
DAGNode(NodeKind k) : kind(k) {}
|
||||
};
|
||||
|
||||
RISCv64ISel::RISCv64ISel() : vreg_counter(0), local_label_counter(0) {}
|
||||
|
||||
// 为一个IR Value获取或分配一个新的虚拟寄存器
|
||||
unsigned RISCv64ISel::getVReg(Value* val) {
|
||||
if (!val) {
|
||||
throw std::runtime_error("Cannot get vreg for a null Value.");
|
||||
}
|
||||
if (vreg_map.find(val) == vreg_map.end()) {
|
||||
if (vreg_counter == 0) {
|
||||
vreg_counter = 1; // vreg 0 保留
|
||||
}
|
||||
vreg_map[val] = vreg_counter++;
|
||||
}
|
||||
return vreg_map.at(val);
|
||||
}
|
||||
|
||||
// 主入口函数
|
||||
std::unique_ptr<MachineFunction> RISCv64ISel::runOnFunction(Function* func) {
|
||||
F = func;
|
||||
if (!F) return nullptr;
|
||||
MFunc = std::make_unique<MachineFunction>(F, this);
|
||||
vreg_map.clear();
|
||||
bb_map.clear();
|
||||
vreg_counter = 0;
|
||||
local_label_counter = 0;
|
||||
|
||||
select();
|
||||
|
||||
return std::move(MFunc);
|
||||
}
|
||||
|
||||
// 指令选择主流程
|
||||
void RISCv64ISel::select() {
|
||||
for (const auto& bb_ptr : F->getBasicBlocks()) {
|
||||
auto mbb = std::make_unique<MachineBasicBlock>(bb_ptr->getName(), MFunc.get());
|
||||
bb_map[bb_ptr.get()] = mbb.get();
|
||||
MFunc->addBlock(std::move(mbb));
|
||||
}
|
||||
|
||||
if (F->getEntryBlock()) {
|
||||
for (auto* arg_alloca : F->getEntryBlock()->getArguments()) {
|
||||
getVReg(arg_alloca);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& bb_ptr : F->getBasicBlocks()) {
|
||||
selectBasicBlock(bb_ptr.get());
|
||||
}
|
||||
|
||||
for (const auto& bb_ptr : F->getBasicBlocks()) {
|
||||
CurMBB = bb_map.at(bb_ptr.get());
|
||||
for (auto succ : bb_ptr->getSuccessors()) {
|
||||
CurMBB->successors.push_back(bb_map.at(succ));
|
||||
}
|
||||
for (auto pred : bb_ptr->getPredecessors()) {
|
||||
CurMBB->predecessors.push_back(bb_map.at(pred));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理单个基本块
|
||||
void RISCv64ISel::selectBasicBlock(BasicBlock* bb) {
|
||||
CurMBB = bb_map.at(bb);
|
||||
auto dag = build_dag(bb);
|
||||
|
||||
if (DEBUG) { // 使用 DEBUG 宏或变量来控制是否打印
|
||||
print_dag(dag, bb->getName());
|
||||
}
|
||||
|
||||
std::map<Value*, DAGNode*> value_to_node;
|
||||
for(const auto& node : dag) {
|
||||
if (node->value) {
|
||||
value_to_node[node->value] = node.get();
|
||||
}
|
||||
}
|
||||
|
||||
std::set<DAGNode*> selected_nodes;
|
||||
std::function<void(DAGNode*)> select_recursive =
|
||||
[&](DAGNode* node) {
|
||||
if (DEEPDEBUG) {
|
||||
std::cout << "[DEEPDEBUG] select_recursive: Visiting node with kind: " << node->kind
|
||||
<< " (Value: " << (node->value ? node->value->getName() : "null") << ")" << std::endl;
|
||||
}
|
||||
if (!node || selected_nodes.count(node)) return;
|
||||
for (auto operand : node->operands) {
|
||||
select_recursive(operand);
|
||||
}
|
||||
selectNode(node);
|
||||
selected_nodes.insert(node);
|
||||
};
|
||||
|
||||
for (const auto& inst_ptr : bb->getInstructions()) {
|
||||
DAGNode* node_to_select = nullptr;
|
||||
if (value_to_node.count(inst_ptr.get())) {
|
||||
node_to_select = value_to_node.at(inst_ptr.get());
|
||||
} else {
|
||||
for(const auto& node : dag) {
|
||||
if(node->value == inst_ptr.get()) {
|
||||
node_to_select = node.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(node_to_select) {
|
||||
select_recursive(node_to_select);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 核心函数:为DAG节点选择并生成MachineInstr (已修复和增强的完整版本)
|
||||
void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
// 调用者(select_recursive)已经保证了操作数节点会先于当前节点被选择。
|
||||
// 因此,这里我们只处理当前节点。
|
||||
|
||||
switch (node->kind) {
|
||||
// [V2优点] 采纳“延迟物化”(Late Materialization)思想。
|
||||
// 这两个节点仅作为标记,不直接生成指令。它们的目的是在DAG中保留类型信息。
|
||||
// 加载其值的责任,被转移给了使用它们的父节点(如STORE, BINARY等)。
|
||||
// 这修复了之前版本中“使用未初始化虚拟寄存器”的根本性bug。
|
||||
case DAGNode::CONSTANT:
|
||||
case DAGNode::ALLOCA_ADDR:
|
||||
if (node->value) {
|
||||
// 确保它有一个关联的虚拟寄存器即可,不生成代码。
|
||||
getVReg(node->value);
|
||||
}
|
||||
break;
|
||||
|
||||
case DAGNode::LOAD: {
|
||||
auto dest_vreg = getVReg(node->value);
|
||||
Value* ptr_val = node->operands[0]->value;
|
||||
|
||||
// [V1设计保留] 对于从栈变量加载,继续使用伪指令 FRAME_LOAD。
|
||||
// 这种设计将栈帧布局的具体计算推迟到后续的 `eliminateFrameIndices` 阶段,保持了模块化。
|
||||
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_LOAD);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(getVReg(alloca)));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_val)) {
|
||||
// 对于全局变量,先用 la 加载其地址,再用 lw 加载其值。
|
||||
auto addr_vreg = getNewVReg();
|
||||
auto la = std::make_unique<MachineInstr>(RVOpcodes::LA);
|
||||
la->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
||||
la->addOperand(std::make_unique<LabelOperand>(global->getName()));
|
||||
CurMBB->addInstruction(std::move(la));
|
||||
|
||||
auto lw = std::make_unique<MachineInstr>(RVOpcodes::LW);
|
||||
lw->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
lw->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(addr_vreg),
|
||||
std::make_unique<ImmOperand>(0)
|
||||
));
|
||||
CurMBB->addInstruction(std::move(lw));
|
||||
} else {
|
||||
// 对于已经在虚拟寄存器中的指针地址,直接通过该地址加载。
|
||||
auto ptr_vreg = getVReg(ptr_val);
|
||||
auto lw = std::make_unique<MachineInstr>(RVOpcodes::LW);
|
||||
lw->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
lw->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(ptr_vreg),
|
||||
std::make_unique<ImmOperand>(0)
|
||||
));
|
||||
CurMBB->addInstruction(std::move(lw));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::STORE: {
|
||||
Value* val_to_store = node->operands[0]->value;
|
||||
Value* ptr_val = node->operands[1]->value;
|
||||
|
||||
// [V2优点] 在STORE节点内部负责加载作为源的常量。
|
||||
// 如果要存储的值是一个常量,就在这里生成 `li` 指令加载它。
|
||||
if (auto val_const = dynamic_cast<ConstantValue*>(val_to_store)) {
|
||||
if (DEBUG) {
|
||||
std::cout << "[DEBUG] selectNode-BINARY: Found constant operand with value " << val_const->getInt()
|
||||
<< ". Generating LI instruction." << std::endl;
|
||||
}
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(getVReg(val_const)));
|
||||
li->addOperand(std::make_unique<ImmOperand>(val_const->getInt()));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
}
|
||||
auto val_vreg = getVReg(val_to_store);
|
||||
|
||||
// [V1设计保留] 同样,对于向栈变量的存储,使用 FRAME_STORE 伪指令。
|
||||
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_STORE);
|
||||
instr->addOperand(std::make_unique<RegOperand>(val_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(getVReg(alloca)));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_val)) {
|
||||
// 向全局变量存储。
|
||||
auto addr_vreg = getNewVReg();
|
||||
auto la = std::make_unique<MachineInstr>(RVOpcodes::LA);
|
||||
la->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
||||
la->addOperand(std::make_unique<LabelOperand>(global->getName()));
|
||||
CurMBB->addInstruction(std::move(la));
|
||||
|
||||
auto sw = std::make_unique<MachineInstr>(RVOpcodes::SW);
|
||||
sw->addOperand(std::make_unique<RegOperand>(val_vreg));
|
||||
sw->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(addr_vreg),
|
||||
std::make_unique<ImmOperand>(0)
|
||||
));
|
||||
CurMBB->addInstruction(std::move(sw));
|
||||
} else {
|
||||
// 向一个指针(存储在虚拟寄存器中)指向的地址存储。
|
||||
auto ptr_vreg = getVReg(ptr_val);
|
||||
auto sw = std::make_unique<MachineInstr>(RVOpcodes::SW);
|
||||
sw->addOperand(std::make_unique<RegOperand>(val_vreg));
|
||||
sw->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(ptr_vreg),
|
||||
std::make_unique<ImmOperand>(0)
|
||||
));
|
||||
CurMBB->addInstruction(std::move(sw));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::BINARY: {
|
||||
auto bin = dynamic_cast<BinaryInst*>(node->value);
|
||||
Value* lhs = bin->getLhs();
|
||||
Value* rhs = bin->getRhs();
|
||||
|
||||
if (bin->getKind() == BinaryInst::kAdd) {
|
||||
Value* base = nullptr;
|
||||
Value* offset = nullptr;
|
||||
|
||||
// [修改] 扩展基地址的判断,使其可以识别 AllocaInst 或 GlobalValue
|
||||
if (dynamic_cast<AllocaInst*>(lhs) || dynamic_cast<GlobalValue*>(lhs)) {
|
||||
base = lhs;
|
||||
offset = rhs;
|
||||
} else if (dynamic_cast<AllocaInst*>(rhs) || dynamic_cast<GlobalValue*>(rhs)) {
|
||||
base = rhs;
|
||||
offset = lhs;
|
||||
}
|
||||
|
||||
// 如果成功匹配到地址计算模式
|
||||
if (base) {
|
||||
// 1. 先为偏移量加载常量(如果它是常量的话)
|
||||
if (auto const_offset = dynamic_cast<ConstantValue*>(offset)) {
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(getVReg(const_offset)));
|
||||
li->addOperand(std::make_unique<ImmOperand>(const_offset->getInt()));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
}
|
||||
|
||||
// 2. [修改] 根据基地址的类型,生成不同的指令来获取基地址
|
||||
auto base_addr_vreg = getNewVReg(); // 创建一个新的临时vreg来存放基地址
|
||||
|
||||
// 情况一:基地址是局部栈变量
|
||||
if (auto alloca_base = dynamic_cast<AllocaInst*>(base)) {
|
||||
auto frame_addr_instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_ADDR);
|
||||
frame_addr_instr->addOperand(std::make_unique<RegOperand>(base_addr_vreg));
|
||||
frame_addr_instr->addOperand(std::make_unique<RegOperand>(getVReg(alloca_base)));
|
||||
CurMBB->addInstruction(std::move(frame_addr_instr));
|
||||
}
|
||||
// 情况二:基地址是全局变量
|
||||
else if (auto global_base = dynamic_cast<GlobalValue*>(base)) {
|
||||
auto la_instr = std::make_unique<MachineInstr>(RVOpcodes::LA);
|
||||
la_instr->addOperand(std::make_unique<RegOperand>(base_addr_vreg));
|
||||
la_instr->addOperand(std::make_unique<LabelOperand>(global_base->getName()));
|
||||
CurMBB->addInstruction(std::move(la_instr));
|
||||
}
|
||||
|
||||
// 3. 生成真正的add指令,计算最终地址(这部分逻辑保持不变)
|
||||
auto final_addr_vreg = getVReg(bin); // 这是整个二元运算的结果vreg
|
||||
auto offset_vreg = getVReg(offset);
|
||||
auto add_instr = std::make_unique<MachineInstr>(RVOpcodes::ADD); // 指针运算是64位
|
||||
add_instr->addOperand(std::make_unique<RegOperand>(final_addr_vreg));
|
||||
add_instr->addOperand(std::make_unique<RegOperand>(base_addr_vreg));
|
||||
add_instr->addOperand(std::make_unique<RegOperand>(offset_vreg));
|
||||
CurMBB->addInstruction(std::move(add_instr));
|
||||
|
||||
return; // 地址计算处理完毕,直接返回
|
||||
}
|
||||
}
|
||||
|
||||
// [V2优点] 在BINARY节点内部按需加载常量操作数。
|
||||
auto load_val_if_const = [&](Value* val) {
|
||||
if (auto c = dynamic_cast<ConstantValue*>(val)) {
|
||||
if (DEBUG) {
|
||||
std::cout << "[DEBUG] selectNode-BINARY: Found constant operand with value " << c->getInt()
|
||||
<< ". Generating LI instruction." << std::endl;
|
||||
}
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(getVReg(c)));
|
||||
li->addOperand(std::make_unique<ImmOperand>(c->getInt()));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
}
|
||||
};
|
||||
|
||||
// 检查是否能应用立即数优化。
|
||||
bool rhs_is_imm_opt = false;
|
||||
if (auto rhs_const = dynamic_cast<ConstantValue*>(rhs)) {
|
||||
if (bin->getKind() == BinaryInst::kAdd && rhs_const->getInt() >= -2048 && rhs_const->getInt() < 2048) {
|
||||
rhs_is_imm_opt = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 仅在不能作为立即数操作数时才需要提前加载。
|
||||
load_val_if_const(lhs);
|
||||
if (!rhs_is_imm_opt) {
|
||||
load_val_if_const(rhs);
|
||||
}
|
||||
|
||||
auto dest_vreg = getVReg(bin);
|
||||
auto lhs_vreg = getVReg(lhs);
|
||||
|
||||
// [V2优点] 融合 ADDIW 优化。
|
||||
if (rhs_is_imm_opt) {
|
||||
auto rhs_const = dynamic_cast<ConstantValue*>(rhs);
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::ADDIW);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<ImmOperand>(rhs_const->getInt()));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
return; // 指令已生成,直接返回。
|
||||
}
|
||||
|
||||
auto rhs_vreg = getVReg(rhs);
|
||||
|
||||
switch (bin->getKind()) {
|
||||
case BinaryInst::kAdd: {
|
||||
// 区分指针运算(64位)和整数运算(32位)。
|
||||
RVOpcodes opcode = (lhs->getType()->isPointer() || rhs->getType()->isPointer()) ? RVOpcodes::ADD : RVOpcodes::ADDW;
|
||||
auto instr = std::make_unique<MachineInstr>(opcode);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case BinaryInst::kSub: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case BinaryInst::kMul: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::MULW);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kDiv: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::DIVW);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kRem: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::REMW);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case BinaryInst::kICmpEQ: { // 等于 (a == b) -> (subw; seqz)
|
||||
auto sub = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
|
||||
sub->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
sub->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
sub->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(sub));
|
||||
|
||||
auto seqz = std::make_unique<MachineInstr>(RVOpcodes::SEQZ);
|
||||
seqz->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
seqz->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
CurMBB->addInstruction(std::move(seqz));
|
||||
break;
|
||||
}
|
||||
case BinaryInst::kICmpNE: { // 不等于 (a != b) -> (subw; snez)
|
||||
auto sub = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
|
||||
sub->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
sub->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
sub->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(sub));
|
||||
|
||||
auto snez = std::make_unique<MachineInstr>(RVOpcodes::SNEZ);
|
||||
snez->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
snez->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
CurMBB->addInstruction(std::move(snez));
|
||||
break;
|
||||
}
|
||||
case BinaryInst::kICmpLT: { // 小于 (a < b) -> slt
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SLT);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case BinaryInst::kICmpGT: { // 大于 (a > b) -> (b < a) -> slt
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SLT);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case BinaryInst::kICmpLE: { // 小于等于 (a <= b) -> !(b < a) -> (slt; xori)
|
||||
auto slt = std::make_unique<MachineInstr>(RVOpcodes::SLT);
|
||||
slt->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
slt->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
slt->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
CurMBB->addInstruction(std::move(slt));
|
||||
|
||||
auto xori = std::make_unique<MachineInstr>(RVOpcodes::XORI);
|
||||
xori->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
xori->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
xori->addOperand(std::make_unique<ImmOperand>(1));
|
||||
CurMBB->addInstruction(std::move(xori));
|
||||
break;
|
||||
}
|
||||
case BinaryInst::kICmpGE: { // 大于等于 (a >= b) -> !(a < b) -> (slt; xori)
|
||||
auto slt = std::make_unique<MachineInstr>(RVOpcodes::SLT);
|
||||
slt->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
slt->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
slt->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(slt));
|
||||
|
||||
auto xori = std::make_unique<MachineInstr>(RVOpcodes::XORI);
|
||||
xori->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
xori->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
xori->addOperand(std::make_unique<ImmOperand>(1));
|
||||
CurMBB->addInstruction(std::move(xori));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("Unsupported binary instruction in ISel");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::UNARY: {
|
||||
auto unary = dynamic_cast<UnaryInst*>(node->value);
|
||||
auto dest_vreg = getVReg(unary);
|
||||
auto src_vreg = getVReg(unary->getOperand());
|
||||
|
||||
switch (unary->getKind()) {
|
||||
case UnaryInst::kNeg: { // 取负: 0 - src
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||
instr->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case UnaryInst::kNot: { // 逻辑非: src == 0 ? 1 : 0
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SEQZ);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("Unsupported unary instruction in ISel");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::CALL: {
|
||||
auto call = dynamic_cast<CallInst*>(node->value);
|
||||
// 处理函数参数,放入a0-a7物理寄存器
|
||||
size_t num_operands = node->operands.size();
|
||||
size_t reg_arg_count = std::min(num_operands, (size_t)8);
|
||||
for (size_t i = 0; i < reg_arg_count; ++i) {
|
||||
DAGNode* arg_node = node->operands[i];
|
||||
auto arg_preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + i);
|
||||
|
||||
if (arg_node->kind == DAGNode::CONSTANT) {
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(arg_node->value)) {
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(arg_preg));
|
||||
li->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
}
|
||||
} else {
|
||||
auto src_vreg = getVReg(arg_node->value);
|
||||
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
mv->addOperand(std::make_unique<RegOperand>(arg_preg));
|
||||
mv->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
CurMBB->addInstruction(std::move(mv));
|
||||
}
|
||||
}
|
||||
if (num_operands > 8) {
|
||||
size_t stack_arg_count = num_operands - 8;
|
||||
int stack_space = stack_arg_count * 8; // RV64中每个参数槽位8字节
|
||||
|
||||
// 2a. 在栈上分配空间
|
||||
auto alloc_instr = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
alloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
alloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
alloc_instr->addOperand(std::make_unique<ImmOperand>(-stack_space));
|
||||
CurMBB->addInstruction(std::move(alloc_instr));
|
||||
|
||||
// 2b. 存储每个栈参数
|
||||
for (size_t i = 8; i < num_operands; ++i) {
|
||||
DAGNode* arg_node = node->operands[i];
|
||||
unsigned src_vreg;
|
||||
|
||||
// 准备源寄存器
|
||||
if (arg_node->kind == DAGNode::CONSTANT) {
|
||||
// 如果是常量,先加载到临时寄存器
|
||||
src_vreg = getNewVReg();
|
||||
auto const_val = dynamic_cast<ConstantValue*>(arg_node->value);
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
li->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
} else {
|
||||
src_vreg = getVReg(arg_node->value);
|
||||
}
|
||||
|
||||
// 计算在栈上的偏移量
|
||||
int offset = (i - 8) * 8;
|
||||
|
||||
// 生成 sd 指令
|
||||
auto sd_instr = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
||||
sd_instr->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
sd_instr->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::SP),
|
||||
std::make_unique<ImmOperand>(offset)
|
||||
));
|
||||
CurMBB->addInstruction(std::move(sd_instr));
|
||||
}
|
||||
}
|
||||
|
||||
auto call_instr = std::make_unique<MachineInstr>(RVOpcodes::CALL);
|
||||
call_instr->addOperand(std::make_unique<LabelOperand>(call->getCallee()->getName()));
|
||||
CurMBB->addInstruction(std::move(call_instr));
|
||||
|
||||
if (num_operands > 8) {
|
||||
size_t stack_arg_count = num_operands - 8;
|
||||
int stack_space = stack_arg_count * 8;
|
||||
|
||||
auto dealloc_instr = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
dealloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
dealloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
dealloc_instr->addOperand(std::make_unique<ImmOperand>(stack_space));
|
||||
CurMBB->addInstruction(std::move(dealloc_instr));
|
||||
}
|
||||
// 处理返回值,从a0移动到目标虚拟寄存器
|
||||
if (!call->getType()->isVoid()) {
|
||||
auto mv_instr = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
mv_instr->addOperand(std::make_unique<RegOperand>(getVReg(call)));
|
||||
mv_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
|
||||
CurMBB->addInstruction(std::move(mv_instr));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::RETURN: {
|
||||
auto ret_inst_ir = dynamic_cast<ReturnInst*>(node->value);
|
||||
if (ret_inst_ir && ret_inst_ir->hasReturnValue()) {
|
||||
Value* ret_val = ret_inst_ir->getReturnValue();
|
||||
// [V2优点] 在RETURN节点内加载常量返回值
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(ret_val)) {
|
||||
auto li_instr = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
|
||||
li_instr->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
|
||||
CurMBB->addInstruction(std::move(li_instr));
|
||||
} else {
|
||||
auto mv_instr = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
mv_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
|
||||
mv_instr->addOperand(std::make_unique<RegOperand>(getVReg(ret_val)));
|
||||
CurMBB->addInstruction(std::move(mv_instr));
|
||||
}
|
||||
}
|
||||
// [V1设计保留] 函数尾声(epilogue)不由RETURN节点生成,
|
||||
// 而是由后续的AsmPrinter或其它Pass统一处理,这是一种常见且有效的模块化设计。
|
||||
auto ret_mi = std::make_unique<MachineInstr>(RVOpcodes::RET);
|
||||
CurMBB->addInstruction(std::move(ret_mi));
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::BRANCH: {
|
||||
// 处理条件分支
|
||||
if (auto cond_br = dynamic_cast<CondBrInst*>(node->value)) {
|
||||
Value* condition = cond_br->getCondition();
|
||||
auto then_bb_name = cond_br->getThenBlock()->getName();
|
||||
auto else_bb_name = cond_br->getElseBlock()->getName();
|
||||
|
||||
// [优化] 检查分支条件是否为编译期常量
|
||||
if (auto const_cond = dynamic_cast<ConstantValue*>(condition)) {
|
||||
// 如果条件是常量,直接生成一个无条件跳转J,而不是BNE
|
||||
if (const_cond->getInt() != 0) { // 条件为 true
|
||||
auto j_instr = std::make_unique<MachineInstr>(RVOpcodes::J);
|
||||
j_instr->addOperand(std::make_unique<LabelOperand>(then_bb_name));
|
||||
CurMBB->addInstruction(std::move(j_instr));
|
||||
} else { // 条件为 false
|
||||
auto j_instr = std::make_unique<MachineInstr>(RVOpcodes::J);
|
||||
j_instr->addOperand(std::make_unique<LabelOperand>(else_bb_name));
|
||||
CurMBB->addInstruction(std::move(j_instr));
|
||||
}
|
||||
}
|
||||
// 如果条件不是常量,则执行标准流程
|
||||
else {
|
||||
// [修复] 为条件变量生成加载指令(如果它是常量的话,尽管上面已经处理了)
|
||||
// 这一步是为了逻辑完整,以防有其他类型的常量没有被捕获
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(condition)) {
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(getVReg(const_val)));
|
||||
li->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
}
|
||||
|
||||
auto cond_vreg = getVReg(condition);
|
||||
|
||||
// 生成 bne cond, zero, then_label (如果cond不为0,则跳转到then)
|
||||
auto br_instr = std::make_unique<MachineInstr>(RVOpcodes::BNE);
|
||||
br_instr->addOperand(std::make_unique<RegOperand>(cond_vreg));
|
||||
br_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||
br_instr->addOperand(std::make_unique<LabelOperand>(then_bb_name));
|
||||
CurMBB->addInstruction(std::move(br_instr));
|
||||
|
||||
// 为else分支生成无条件跳转 (后续Pass可以优化掉不必要的跳转)
|
||||
auto j_instr = std::make_unique<MachineInstr>(RVOpcodes::J);
|
||||
j_instr->addOperand(std::make_unique<LabelOperand>(else_bb_name));
|
||||
CurMBB->addInstruction(std::move(j_instr));
|
||||
}
|
||||
}
|
||||
// 处理无条件分支
|
||||
else if (auto uncond_br = dynamic_cast<UncondBrInst*>(node->value)) {
|
||||
auto j_instr = std::make_unique<MachineInstr>(RVOpcodes::J);
|
||||
j_instr->addOperand(std::make_unique<LabelOperand>(uncond_br->getBlock()->getName()));
|
||||
CurMBB->addInstruction(std::move(j_instr));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::MEMSET: {
|
||||
// [V1设计保留] Memset的核心展开逻辑在虚拟寄存器层面是正确的,无需修改。
|
||||
// 之前的bug是由于其输入(地址、值、大小)的虚拟寄存器未被正确初始化。
|
||||
// 在修复了CONSTANT/ALLOCA_ADDR的加载问题后,此处的逻辑现在可以正常工作。
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "[DEBUG] selectNode-MEMSET: Processing MEMSET node." << std::endl;
|
||||
}
|
||||
auto memset = dynamic_cast<MemsetInst*>(node->value);
|
||||
Value* val_to_set = memset->getValue();
|
||||
Value* size_to_set = memset->getSize();
|
||||
Value* ptr_val = memset->getPointer();
|
||||
auto dest_addr_vreg = getVReg(ptr_val);
|
||||
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(val_to_set)) {
|
||||
if (DEBUG) {
|
||||
std::cout << "[DEBUG] selectNode-MEMSET: Found constant 'value' operand (" << const_val->getInt() << "). Generating LI." << std::endl;
|
||||
}
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(getVReg(const_val)));
|
||||
li->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
}
|
||||
if (auto const_size = dynamic_cast<ConstantValue*>(size_to_set)) {
|
||||
if (DEBUG) {
|
||||
std::cout << "[DEBUG] selectNode-MEMSET: Found constant 'size' operand (" << const_size->getInt() << "). Generating LI." << std::endl;
|
||||
}
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(getVReg(const_size)));
|
||||
li->addOperand(std::make_unique<ImmOperand>(const_size->getInt()));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
}
|
||||
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
|
||||
if (DEBUG) {
|
||||
std::cout << "[DEBUG] selectNode-MEMSET: Found 'pointer' operand is an AllocaInst. Generating FRAME_ADDR." << std::endl;
|
||||
}
|
||||
// 生成新的伪指令来获取栈地址
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_ADDR);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_addr_vreg)); // 目标虚拟寄存器
|
||||
instr->addOperand(std::make_unique<RegOperand>(getVReg(alloca))); // 源AllocaInst
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
}
|
||||
auto r_dest_addr = getVReg(memset->getPointer());
|
||||
auto r_num_bytes = getVReg(memset->getSize());
|
||||
auto r_value_byte = getVReg(memset->getValue());
|
||||
|
||||
// 为memset内部逻辑创建新的临时虚拟寄存器
|
||||
auto r_counter = getNewVReg();
|
||||
auto r_end_addr = getNewVReg();
|
||||
auto r_current_addr = getNewVReg();
|
||||
auto r_temp_val = getNewVReg();
|
||||
|
||||
// 定义一系列lambda表达式来简化指令创建
|
||||
auto add_instr = [&](RVOpcodes op, unsigned rd, unsigned rs1, unsigned rs2) {
|
||||
auto i = std::make_unique<MachineInstr>(op);
|
||||
i->addOperand(std::make_unique<RegOperand>(rd));
|
||||
i->addOperand(std::make_unique<RegOperand>(rs1));
|
||||
i->addOperand(std::make_unique<RegOperand>(rs2));
|
||||
CurMBB->addInstruction(std::move(i));
|
||||
};
|
||||
auto addi_instr = [&](RVOpcodes op, unsigned rd, unsigned rs1, int64_t imm) {
|
||||
auto i = std::make_unique<MachineInstr>(op);
|
||||
i->addOperand(std::make_unique<RegOperand>(rd));
|
||||
i->addOperand(std::make_unique<RegOperand>(rs1));
|
||||
i->addOperand(std::make_unique<ImmOperand>(imm));
|
||||
CurMBB->addInstruction(std::move(i));
|
||||
};
|
||||
auto store_instr = [&](RVOpcodes op, unsigned src, unsigned base, int64_t off) {
|
||||
auto i = std::make_unique<MachineInstr>(op);
|
||||
i->addOperand(std::make_unique<RegOperand>(src));
|
||||
i->addOperand(std::make_unique<MemOperand>(std::make_unique<RegOperand>(base), std::make_unique<ImmOperand>(off)));
|
||||
CurMBB->addInstruction(std::move(i));
|
||||
};
|
||||
auto branch_instr = [&](RVOpcodes op, unsigned rs1, unsigned rs2, const std::string& label) {
|
||||
auto i = std::make_unique<MachineInstr>(op);
|
||||
i->addOperand(std::make_unique<RegOperand>(rs1));
|
||||
i->addOperand(std::make_unique<RegOperand>(rs2));
|
||||
i->addOperand(std::make_unique<LabelOperand>(label));
|
||||
CurMBB->addInstruction(std::move(i));
|
||||
};
|
||||
auto jump_instr = [&](const std::string& label) {
|
||||
auto i = std::make_unique<MachineInstr>(RVOpcodes::J);
|
||||
i->addOperand(std::make_unique<LabelOperand>(label));
|
||||
CurMBB->addInstruction(std::move(i));
|
||||
};
|
||||
auto label_instr = [&](const std::string& name) {
|
||||
auto i = std::make_unique<MachineInstr>(RVOpcodes::LABEL);
|
||||
i->addOperand(std::make_unique<LabelOperand>(name));
|
||||
CurMBB->addInstruction(std::move(i));
|
||||
};
|
||||
|
||||
// 生成唯一的循环标签
|
||||
int unique_id = this->local_label_counter++;
|
||||
std::string loop_start_label = MFunc->getName() + "_memset_loop_start_" + std::to_string(unique_id);
|
||||
std::string loop_end_label = MFunc->getName() + "_memset_loop_end_" + std::to_string(unique_id);
|
||||
std::string remainder_label = MFunc->getName() + "_memset_remainder_" + std::to_string(unique_id);
|
||||
std::string done_label = MFunc->getName() + "_memset_done_" + std::to_string(unique_id);
|
||||
|
||||
// 构造64位的填充值
|
||||
addi_instr(RVOpcodes::ANDI, r_temp_val, r_value_byte, 255);
|
||||
addi_instr(RVOpcodes::SLLI, r_value_byte, r_temp_val, 8);
|
||||
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte);
|
||||
addi_instr(RVOpcodes::SLLI, r_value_byte, r_temp_val, 16);
|
||||
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte);
|
||||
addi_instr(RVOpcodes::SLLI, r_value_byte, r_temp_val, 32);
|
||||
add_instr(RVOpcodes::OR, r_temp_val, r_temp_val, r_value_byte);
|
||||
|
||||
// 计算循环边界
|
||||
add_instr(RVOpcodes::ADD, r_end_addr, r_dest_addr, r_num_bytes);
|
||||
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
mv->addOperand(std::make_unique<RegOperand>(r_current_addr));
|
||||
mv->addOperand(std::make_unique<RegOperand>(r_dest_addr));
|
||||
CurMBB->addInstruction(std::move(mv));
|
||||
addi_instr(RVOpcodes::ANDI, r_counter, r_num_bytes, -8);
|
||||
add_instr(RVOpcodes::ADD, r_counter, r_dest_addr, r_counter);
|
||||
|
||||
// 8字节主循环
|
||||
label_instr(loop_start_label);
|
||||
branch_instr(RVOpcodes::BGEU, r_current_addr, r_counter, loop_end_label);
|
||||
store_instr(RVOpcodes::SD, r_temp_val, r_current_addr, 0);
|
||||
addi_instr(RVOpcodes::ADDI, r_current_addr, r_current_addr, 8);
|
||||
jump_instr(loop_start_label);
|
||||
|
||||
// 1字节收尾循环
|
||||
label_instr(loop_end_label);
|
||||
label_instr(remainder_label);
|
||||
branch_instr(RVOpcodes::BGEU, r_current_addr, r_end_addr, done_label);
|
||||
store_instr(RVOpcodes::SB, r_temp_val, r_current_addr, 0);
|
||||
addi_instr(RVOpcodes::ADDI, r_current_addr, r_current_addr, 1);
|
||||
jump_instr(remainder_label);
|
||||
|
||||
label_instr(done_label);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw std::runtime_error("Unsupported DAGNode kind in ISel");
|
||||
}
|
||||
}
|
||||
|
||||
// 以下是忠实移植的DAG构建函数
|
||||
RISCv64ISel::DAGNode* RISCv64ISel::create_node(int kind_int, Value* val, std::map<Value*, DAGNode*>& value_to_node, std::vector<std::unique_ptr<DAGNode>>& nodes_storage) {
|
||||
auto kind = static_cast<DAGNode::NodeKind>(kind_int);
|
||||
if (val && value_to_node.count(val) && kind != DAGNode::STORE && kind != DAGNode::RETURN && kind != DAGNode::BRANCH && kind != DAGNode::MEMSET) {
|
||||
return value_to_node[val];
|
||||
}
|
||||
auto node = std::make_unique<DAGNode>(kind);
|
||||
node->value = val;
|
||||
DAGNode* raw_node_ptr = node.get();
|
||||
nodes_storage.push_back(std::move(node));
|
||||
if (val && !val->getType()->isVoid() && (dynamic_cast<Instruction*>(val) || dynamic_cast<GlobalValue*>(val))) {
|
||||
value_to_node[val] = raw_node_ptr;
|
||||
}
|
||||
return raw_node_ptr;
|
||||
}
|
||||
|
||||
RISCv64ISel::DAGNode* RISCv64ISel::get_operand_node(Value* val_ir, std::map<Value*, DAGNode*>& value_to_node, std::vector<std::unique_ptr<DAGNode>>& nodes_storage) {
|
||||
if (value_to_node.count(val_ir)) {
|
||||
return value_to_node[val_ir];
|
||||
} else if (dynamic_cast<ConstantValue*>(val_ir)) {
|
||||
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
|
||||
} else if (dynamic_cast<GlobalValue*>(val_ir)) {
|
||||
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
|
||||
} else if (dynamic_cast<AllocaInst*>(val_ir)) {
|
||||
return create_node(DAGNode::ALLOCA_ADDR, val_ir, value_to_node, nodes_storage);
|
||||
}
|
||||
return create_node(DAGNode::LOAD, val_ir, value_to_node, nodes_storage);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicBlock* bb) {
|
||||
std::vector<std::unique_ptr<DAGNode>> nodes_storage;
|
||||
std::map<Value*, DAGNode*> value_to_node;
|
||||
|
||||
for (const auto& inst_ptr : bb->getInstructions()) {
|
||||
Instruction* inst = inst_ptr.get();
|
||||
if (auto alloca = dynamic_cast<AllocaInst*>(inst)) {
|
||||
create_node(DAGNode::ALLOCA_ADDR, alloca, value_to_node, nodes_storage);
|
||||
} else if (auto store = dynamic_cast<StoreInst*>(inst)) {
|
||||
auto store_node = create_node(DAGNode::STORE, store, value_to_node, nodes_storage);
|
||||
store_node->operands.push_back(get_operand_node(store->getValue(), value_to_node, nodes_storage));
|
||||
store_node->operands.push_back(get_operand_node(store->getPointer(), value_to_node, nodes_storage));
|
||||
} else if (auto memset = dynamic_cast<MemsetInst*>(inst)) {
|
||||
auto memset_node = create_node(DAGNode::MEMSET, memset, value_to_node, nodes_storage);
|
||||
memset_node->operands.push_back(get_operand_node(memset->getPointer(), value_to_node, nodes_storage));
|
||||
memset_node->operands.push_back(get_operand_node(memset->getBegin(), value_to_node, nodes_storage));
|
||||
memset_node->operands.push_back(get_operand_node(memset->getSize(), value_to_node, nodes_storage));
|
||||
memset_node->operands.push_back(get_operand_node(memset->getValue(), value_to_node, nodes_storage));
|
||||
if (DEBUG) {
|
||||
std::cout << "[DEBUG] build_dag: Created MEMSET node for: " << memset->getName() << std::endl;
|
||||
for (size_t i = 0; i < memset_node->operands.size(); ++i) {
|
||||
std::cout << " -> Operand " << i << " has kind: " << memset_node->operands[i]->kind << std::endl;
|
||||
}
|
||||
}
|
||||
} else if (auto load = dynamic_cast<LoadInst*>(inst)) {
|
||||
auto load_node = create_node(DAGNode::LOAD, load, value_to_node, nodes_storage);
|
||||
load_node->operands.push_back(get_operand_node(load->getPointer(), value_to_node, nodes_storage));
|
||||
} else if (auto bin = dynamic_cast<BinaryInst*>(inst)) {
|
||||
if(value_to_node.count(bin)) continue;
|
||||
if (bin->getKind() == BinaryInst::kSub) {
|
||||
if (auto const_lhs = dynamic_cast<ConstantValue*>(bin->getLhs())) {
|
||||
if (const_lhs->getInt() == 0) {
|
||||
auto unary_node = create_node(DAGNode::UNARY, bin, value_to_node, nodes_storage);
|
||||
unary_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto bin_node = create_node(DAGNode::BINARY, bin, value_to_node, nodes_storage);
|
||||
bin_node->operands.push_back(get_operand_node(bin->getLhs(), value_to_node, nodes_storage));
|
||||
bin_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
|
||||
} else if (auto un = dynamic_cast<UnaryInst*>(inst)) {
|
||||
if(value_to_node.count(un)) continue;
|
||||
auto unary_node = create_node(DAGNode::UNARY, un, value_to_node, nodes_storage);
|
||||
unary_node->operands.push_back(get_operand_node(un->getOperand(), value_to_node, nodes_storage));
|
||||
} else if (auto call = dynamic_cast<CallInst*>(inst)) {
|
||||
if(value_to_node.count(call)) continue;
|
||||
auto call_node = create_node(DAGNode::CALL, call, value_to_node, nodes_storage);
|
||||
for (auto arg : call->getArguments()) {
|
||||
call_node->operands.push_back(get_operand_node(arg->getValue(), value_to_node, nodes_storage));
|
||||
}
|
||||
} else if (auto ret = dynamic_cast<ReturnInst*>(inst)) {
|
||||
auto ret_node = create_node(DAGNode::RETURN, ret, value_to_node, nodes_storage);
|
||||
if (ret->hasReturnValue()) {
|
||||
ret_node->operands.push_back(get_operand_node(ret->getReturnValue(), value_to_node, nodes_storage));
|
||||
}
|
||||
} else if (auto cond_br = dynamic_cast<CondBrInst*>(inst)) {
|
||||
auto br_node = create_node(DAGNode::BRANCH, cond_br, value_to_node, nodes_storage);
|
||||
br_node->operands.push_back(get_operand_node(cond_br->getCondition(), value_to_node, nodes_storage));
|
||||
} else if (auto uncond_br = dynamic_cast<UncondBrInst*>(inst)) {
|
||||
create_node(DAGNode::BRANCH, uncond_br, value_to_node, nodes_storage);
|
||||
}
|
||||
}
|
||||
return nodes_storage;
|
||||
}
|
||||
|
||||
// [新] 打印DAG图以供调试的辅助函数
|
||||
void RISCv64ISel::print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, const std::string& bb_name) {
|
||||
// 检查是否有DEBUG宏或者全局变量,避免在非调试模式下打印
|
||||
// if (!DEBUG) return;
|
||||
|
||||
std::cerr << "=== DAG for Basic Block: " << bb_name << " ===\n";
|
||||
std::set<DAGNode*> visited;
|
||||
|
||||
// 为节点分配临时ID,方便阅读
|
||||
std::map<DAGNode*, int> node_to_id;
|
||||
int current_id = 0;
|
||||
for (const auto& node_ptr : dag) {
|
||||
node_to_id[node_ptr.get()] = current_id++;
|
||||
}
|
||||
|
||||
// 将NodeKind枚举转换为字符串的辅助函数
|
||||
auto get_kind_string = [](DAGNode::NodeKind kind) {
|
||||
switch (kind) {
|
||||
case DAGNode::CONSTANT: return "CONSTANT";
|
||||
case DAGNode::LOAD: return "LOAD";
|
||||
case DAGNode::STORE: return "STORE";
|
||||
case DAGNode::BINARY: return "BINARY";
|
||||
case DAGNode::CALL: return "CALL";
|
||||
case DAGNode::RETURN: return "RETURN";
|
||||
case DAGNode::BRANCH: return "BRANCH";
|
||||
case DAGNode::ALLOCA_ADDR: return "ALLOCA_ADDR";
|
||||
case DAGNode::UNARY: return "UNARY";
|
||||
case DAGNode::MEMSET: return "MEMSET";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
};
|
||||
|
||||
// 递归打印节点的lambda表达式
|
||||
std::function<void(DAGNode*, int)> print_node =
|
||||
[&](DAGNode* node, int indent) {
|
||||
if (!node) return;
|
||||
|
||||
std::string current_indent(indent, ' ');
|
||||
int node_id = node_to_id.count(node) ? node_to_id[node] : -1;
|
||||
|
||||
std::cerr << current_indent << "Node#" << node_id << ": " << get_kind_string(node->kind);
|
||||
|
||||
// 尝试打印关联的虚拟寄存器
|
||||
if (node->value && vreg_map.count(node->value)) {
|
||||
std::cerr << " (vreg: %vreg" << vreg_map.at(node->value) << ")";
|
||||
}
|
||||
|
||||
// 打印关联的IR Value信息
|
||||
if (node->value) {
|
||||
std::cerr << " [";
|
||||
if (auto inst = dynamic_cast<Instruction*>(node->value)) {
|
||||
std::cerr << inst->getKindString();
|
||||
if (!inst->getName().empty()) {
|
||||
std::cerr << "(" << inst->getName() << ")";
|
||||
}
|
||||
} else if (auto constant = dynamic_cast<ConstantValue*>(node->value)) {
|
||||
std::cerr << "Const(" << constant->getInt() << ")";
|
||||
} else if (auto global = dynamic_cast<GlobalValue*>(node->value)) {
|
||||
std::cerr << "Global(" << global->getName() << ")";
|
||||
} else if (auto alloca = dynamic_cast<AllocaInst*>(node->value)) {
|
||||
std::cerr << "Alloca(" << alloca->getName() << ")";
|
||||
}
|
||||
std::cerr << "]";
|
||||
}
|
||||
std::cerr << "\n";
|
||||
|
||||
if (visited.count(node)) {
|
||||
std::cerr << current_indent << " (已打印过子节点)\n";
|
||||
return;
|
||||
}
|
||||
visited.insert(node);
|
||||
|
||||
if (!node->operands.empty()) {
|
||||
std::cerr << current_indent << " Operands:\n";
|
||||
for (auto operand : node->operands) {
|
||||
print_node(operand, indent + 4);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 从根节点(没有用户的节点,或有副作用的节点)开始打印
|
||||
for (const auto& node_ptr : dag) {
|
||||
if (node_ptr->users.empty() ||
|
||||
node_ptr->kind == DAGNode::STORE ||
|
||||
node_ptr->kind == DAGNode::RETURN ||
|
||||
node_ptr->kind == DAGNode::BRANCH ||
|
||||
node_ptr->kind == DAGNode::MEMSET)
|
||||
{
|
||||
print_node(node_ptr.get(), 0);
|
||||
}
|
||||
}
|
||||
std::cerr << "======================================\n\n";
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
54
src/RISCv64Passes.cpp
Normal file
54
src/RISCv64Passes.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include "RISCv64Passes.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// --- 寄存器分配前优化 ---
|
||||
|
||||
void PreRA_Scheduler::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
// TODO: 在此实现寄存器分配前的指令调度。
|
||||
// 遍历mfunc中的每一个MachineBasicBlock。
|
||||
// 对每个基本块内的MachineInstr列表进行重排。
|
||||
//
|
||||
// 实现思路:
|
||||
// 1. 分析每个基本块内指令的数据依赖关系,构建依赖图(DAG)。
|
||||
// 2. 根据目标处理器的流水线特性(指令延迟等),使用列表调度等算法对指令进行重排。
|
||||
// 3. 此时操作的是虚拟寄存器,只存在真依赖,调度自由度最大。
|
||||
//
|
||||
// std::cout << "Running Pre-RA Instruction Scheduler..." << std::endl;
|
||||
}
|
||||
|
||||
|
||||
// --- 寄存器分配后优化 ---
|
||||
|
||||
void PeepholeOptimizer::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
// TODO: 在此实现窥孔优化。
|
||||
// 遍历mfunc中的每一个MachineBasicBlock。
|
||||
// 对每个基本块内的MachineInstr列表进行扫描和替换。
|
||||
//
|
||||
// 实现思路:
|
||||
// 1. 维护一个大小固定(例如3-5条指令)的滑动窗口。
|
||||
// 2. 识别特定的冗余模式,例如:
|
||||
// - `mv a0, a1` 后紧跟 `mv a1, a0` (可消除的交换)
|
||||
// - `sw t0, 12(s0)` 后紧跟 `lw t1, 12(s0)` (冗余加载)
|
||||
// - 强度削减: `mul x, x, 2` -> `slli x, x, 1`
|
||||
// 3. 识别后,直接修改MachineInstr列表(删除、替换或插入指令)。
|
||||
//
|
||||
// std::cout << "Running Post-RA Peephole Optimizer..." << std::endl;
|
||||
}
|
||||
|
||||
void PostRA_Scheduler::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
// TODO: 在此实现寄存器分配后的局部指令调度。
|
||||
// 遍历mfunc中的每一个MachineBasicBlock。
|
||||
// 重点关注由寄存器分配器插入的spill/fill代码。
|
||||
//
|
||||
// 实现思路:
|
||||
// 1. 识别出用于spill/fill的lw/sw指令。
|
||||
// 2. 在不违反数据依赖(包括物理寄存器引入的伪依赖)的前提下,
|
||||
// 尝试将lw指令向上移动,使其与使用它的指令之间有足够的距离,以隐藏访存延迟。
|
||||
// 3. 同样,可以尝试将sw指令向下移动。
|
||||
//
|
||||
// std::cout << "Running Post-RA Local Scheduler..." << std::endl;
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
335
src/RISCv64RegAlloc.cpp
Normal file
335
src/RISCv64RegAlloc.cpp
Normal file
@ -0,0 +1,335 @@
|
||||
#include "RISCv64RegAlloc.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) : MFunc(mfunc) {
|
||||
allocable_int_regs = {
|
||||
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3,
|
||||
PhysicalReg::T4, PhysicalReg::T5, PhysicalReg::T6,
|
||||
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3,
|
||||
PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7,
|
||||
PhysicalReg::S0, PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3,
|
||||
PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
|
||||
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
|
||||
};
|
||||
}
|
||||
|
||||
void RISCv64RegAlloc::run() {
|
||||
eliminateFrameIndices();
|
||||
analyzeLiveness();
|
||||
buildInterferenceGraph();
|
||||
colorGraph();
|
||||
rewriteFunction();
|
||||
}
|
||||
|
||||
void RISCv64RegAlloc::eliminateFrameIndices() {
|
||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||
int current_offset = 20; // 这里写20是为了在$s0和第一个变量之间留出20字节的安全区,
|
||||
// 以防止一些函数调用方面的恶性bug。
|
||||
Function* F = MFunc->getFunc();
|
||||
RISCv64ISel* isel = MFunc->getISel();
|
||||
|
||||
for (auto& bb : F->getBasicBlocks()) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
if (auto alloca = dynamic_cast<AllocaInst*>(inst.get())) {
|
||||
int size = 4;
|
||||
if (!alloca->getDims().empty()) {
|
||||
int num_elements = 1;
|
||||
for (const auto& dim_use : alloca->getDims()) {
|
||||
if (auto const_dim = dynamic_cast<ConstantValue*>(dim_use->getValue())) {
|
||||
num_elements *= const_dim->getInt();
|
||||
}
|
||||
}
|
||||
size *= num_elements;
|
||||
}
|
||||
current_offset += size;
|
||||
unsigned alloca_vreg = isel->getVReg(alloca);
|
||||
frame_info.alloca_offsets[alloca_vreg] = -current_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
frame_info.locals_size = current_offset;
|
||||
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
std::vector<std::unique_ptr<MachineInstr>> new_instructions;
|
||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||
if (instr_ptr->getOpcode() == RVOpcodes::FRAME_LOAD) {
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
unsigned dest_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
|
||||
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
|
||||
int offset = frame_info.alloca_offsets.at(alloca_vreg);
|
||||
auto addr_vreg = isel->getNewVReg();
|
||||
|
||||
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
addi->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
||||
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
addi->addOperand(std::make_unique<ImmOperand>(offset));
|
||||
new_instructions.push_back(std::move(addi));
|
||||
|
||||
auto lw = std::make_unique<MachineInstr>(RVOpcodes::LW);
|
||||
lw->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
lw->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(addr_vreg),
|
||||
std::make_unique<ImmOperand>(0)));
|
||||
new_instructions.push_back(std::move(lw));
|
||||
|
||||
} else if (instr_ptr->getOpcode() == RVOpcodes::FRAME_STORE) {
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
unsigned src_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
|
||||
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
|
||||
int offset = frame_info.alloca_offsets.at(alloca_vreg);
|
||||
auto addr_vreg = isel->getNewVReg();
|
||||
|
||||
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
addi->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
||||
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
addi->addOperand(std::make_unique<ImmOperand>(offset));
|
||||
new_instructions.push_back(std::move(addi));
|
||||
|
||||
auto sw = std::make_unique<MachineInstr>(RVOpcodes::SW);
|
||||
sw->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
sw->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(addr_vreg),
|
||||
std::make_unique<ImmOperand>(0)));
|
||||
new_instructions.push_back(std::move(sw));
|
||||
} else if (instr_ptr->getOpcode() == RVOpcodes::FRAME_ADDR) { // [新] 处理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)); // 基地址是帧指针 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);
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def) {
|
||||
bool is_def = true;
|
||||
auto opcode = instr->getOpcode();
|
||||
|
||||
// 预定义def和use规则
|
||||
if (opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
|
||||
opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
|
||||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
|
||||
opcode == RVOpcodes::RET || opcode == RVOpcodes::J) {
|
||||
is_def = false;
|
||||
}
|
||||
if (opcode == RVOpcodes::CALL) {
|
||||
// CALL会杀死所有调用者保存寄存器,这是一个简化处理
|
||||
// 同时也使用了传入a0-a7的参数
|
||||
}
|
||||
|
||||
for (const auto& op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||
if (reg_op->isVirtual()) {
|
||||
if (is_def) {
|
||||
def.insert(reg_op->getVRegNum());
|
||||
is_def = false;
|
||||
} else {
|
||||
use.insert(reg_op->getVRegNum());
|
||||
}
|
||||
}
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto mem_op = static_cast<MemOperand*>(op.get());
|
||||
if (mem_op->getBase()->isVirtual()) {
|
||||
use.insert(mem_op->getBase()->getVRegNum());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64RegAlloc::analyzeLiveness() {
|
||||
bool changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
for (auto it = MFunc->getBlocks().rbegin(); it != MFunc->getBlocks().rend(); ++it) {
|
||||
auto& mbb = *it;
|
||||
LiveSet live_out;
|
||||
for (auto succ : mbb->successors) {
|
||||
if (!succ->getInstructions().empty()) {
|
||||
auto first_instr = succ->getInstructions().front().get();
|
||||
if (live_in_map.count(first_instr)) {
|
||||
live_out.insert(live_in_map.at(first_instr).begin(), live_in_map.at(first_instr).end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto instr_it = mbb->getInstructions().rbegin(); instr_it != mbb->getInstructions().rend(); ++instr_it) {
|
||||
MachineInstr* instr = instr_it->get();
|
||||
LiveSet old_live_in = live_in_map[instr];
|
||||
live_out_map[instr] = live_out;
|
||||
|
||||
LiveSet use, def;
|
||||
getInstrUseDef(instr, use, def);
|
||||
|
||||
LiveSet live_in = use;
|
||||
LiveSet diff = live_out;
|
||||
for (auto vreg : def) {
|
||||
diff.erase(vreg);
|
||||
}
|
||||
live_in.insert(diff.begin(), diff.end());
|
||||
live_in_map[instr] = live_in;
|
||||
|
||||
live_out = live_in;
|
||||
|
||||
if (live_in_map[instr] != old_live_in) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64RegAlloc::buildInterferenceGraph() {
|
||||
std::set<unsigned> all_vregs;
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
for(auto& instr : mbb->getInstructions()) {
|
||||
LiveSet use, def;
|
||||
getInstrUseDef(instr.get(), use, def);
|
||||
for(auto u : use) all_vregs.insert(u);
|
||||
for(auto d : def) all_vregs.insert(d);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto vreg : all_vregs) { interference_graph[vreg] = {}; }
|
||||
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
for (auto& instr : mbb->getInstructions()) {
|
||||
LiveSet def, use;
|
||||
getInstrUseDef(instr.get(), use, def);
|
||||
const LiveSet& live_out = live_out_map.at(instr.get());
|
||||
|
||||
for (unsigned d : def) {
|
||||
for (unsigned l : live_out) {
|
||||
if (d != l) {
|
||||
interference_graph[d].insert(l);
|
||||
interference_graph[l].insert(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64RegAlloc::colorGraph() {
|
||||
std::vector<unsigned> sorted_vregs;
|
||||
for (auto const& [vreg, neighbors] : interference_graph) {
|
||||
sorted_vregs.push_back(vreg);
|
||||
}
|
||||
|
||||
std::sort(sorted_vregs.begin(), sorted_vregs.end(), [&](unsigned a, unsigned b) {
|
||||
return interference_graph[a].size() > interference_graph[b].size();
|
||||
});
|
||||
|
||||
for (unsigned vreg : sorted_vregs) {
|
||||
std::set<PhysicalReg> used_colors;
|
||||
for (unsigned neighbor : interference_graph.at(vreg)) {
|
||||
if (color_map.count(neighbor)) {
|
||||
used_colors.insert(color_map.at(neighbor));
|
||||
}
|
||||
}
|
||||
|
||||
bool colored = false;
|
||||
for (PhysicalReg preg : allocable_int_regs) {
|
||||
if (used_colors.find(preg) == used_colors.end()) {
|
||||
color_map[vreg] = preg;
|
||||
colored = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!colored) {
|
||||
spilled_vregs.insert(vreg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64RegAlloc::rewriteFunction() {
|
||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||
int current_offset = frame_info.locals_size;
|
||||
for (unsigned vreg : spilled_vregs) {
|
||||
current_offset += 4;
|
||||
frame_info.spill_offsets[vreg] = -current_offset;
|
||||
}
|
||||
frame_info.spill_size = current_offset - frame_info.locals_size;
|
||||
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
std::vector<std::unique_ptr<MachineInstr>> new_instructions;
|
||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||
LiveSet use, def;
|
||||
getInstrUseDef(instr_ptr.get(), use, def);
|
||||
|
||||
for (unsigned vreg : use) {
|
||||
if (spilled_vregs.count(vreg)) {
|
||||
int offset = frame_info.spill_offsets.at(vreg);
|
||||
auto load = std::make_unique<MachineInstr>(RVOpcodes::LW);
|
||||
load->addOperand(std::make_unique<RegOperand>(vreg));
|
||||
load->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(offset)
|
||||
));
|
||||
new_instructions.push_back(std::move(load));
|
||||
}
|
||||
}
|
||||
|
||||
new_instructions.push_back(std::move(instr_ptr));
|
||||
|
||||
for (unsigned vreg : def) {
|
||||
if (spilled_vregs.count(vreg)) {
|
||||
int offset = frame_info.spill_offsets.at(vreg);
|
||||
auto store = std::make_unique<MachineInstr>(RVOpcodes::SW);
|
||||
store->addOperand(std::make_unique<RegOperand>(vreg));
|
||||
store->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(offset)
|
||||
));
|
||||
new_instructions.push_back(std::move(store));
|
||||
}
|
||||
}
|
||||
}
|
||||
mbb->getInstructions() = std::move(new_instructions);
|
||||
}
|
||||
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||
for (auto& op_ptr : instr_ptr->getOperands()) {
|
||||
if(op_ptr->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(op_ptr.get());
|
||||
if (reg_op->isVirtual()) {
|
||||
unsigned vreg = reg_op->getVRegNum();
|
||||
if (color_map.count(vreg)) {
|
||||
reg_op->setPReg(color_map.at(vreg));
|
||||
} else if (spilled_vregs.count(vreg)) {
|
||||
reg_op->setPReg(PhysicalReg::T6); // 溢出统一用t6
|
||||
}
|
||||
}
|
||||
} else if (op_ptr->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto mem_op = static_cast<MemOperand*>(op_ptr.get());
|
||||
auto base_reg_op = mem_op->getBase();
|
||||
if(base_reg_op->isVirtual()){
|
||||
unsigned vreg = base_reg_op->getVRegNum();
|
||||
if(color_map.count(vreg)) {
|
||||
base_reg_op->setPReg(color_map.at(vreg));
|
||||
} else if (spilled_vregs.count(vreg)) {
|
||||
base_reg_op->setPReg(PhysicalReg::T6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
532
src/SysYIRAnalyser.cpp
Normal file
532
src/SysYIRAnalyser.cpp
Normal file
@ -0,0 +1,532 @@
|
||||
#include "SysYIRAnalyser.h"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
namespace sysy {
|
||||
|
||||
|
||||
void ControlFlowAnalysis::init() {
|
||||
// 初始化分析器
|
||||
auto &functions = pModule->getFunctions();
|
||||
for (const auto &function : functions) {
|
||||
auto func = function.second.get();
|
||||
auto basicBlocks = func->getBasicBlocks();
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
blockAnalysisInfo[basicBlock.get()] = new BlockAnalysisInfo();
|
||||
blockAnalysisInfo[basicBlock.get()]->clear();
|
||||
}
|
||||
functionAnalysisInfo[func] = new FunctionAnalysisInfo();
|
||||
functionAnalysisInfo[func]->clear();
|
||||
}
|
||||
}
|
||||
|
||||
void ControlFlowAnalysis::runControlFlowAnalysis() {
|
||||
// 运行控制流分析
|
||||
clear(); // 清空之前的分析结果
|
||||
init(); // 初始化分析器
|
||||
computeDomNode();
|
||||
computeDomTree();
|
||||
computeDomFrontierAllBlk();
|
||||
}
|
||||
|
||||
void ControlFlowAnalysis::intersectOP4Dom(std::unordered_set<BasicBlock *> &dom, const std::unordered_set<BasicBlock *> &other) {
|
||||
// 计算交集
|
||||
for (auto it = dom.begin(); it != dom.end();) {
|
||||
if (other.find(*it) == other.end()) {
|
||||
// 如果other中没有这个基本块,则从dom中删除
|
||||
it = dom.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto ControlFlowAnalysis::findCommonDominator(BasicBlock *a, BasicBlock *b) -> BasicBlock * {
|
||||
// 查找两个基本块的共同支配结点
|
||||
while (a != b) {
|
||||
BlockAnalysisInfo* infoA = blockAnalysisInfo[a];
|
||||
BlockAnalysisInfo* infoB = blockAnalysisInfo[b];
|
||||
// 如果深度不同,则向上移动到直接支配结点
|
||||
// TODO:空间换时间倍增优化,优先级较低
|
||||
while (infoA->getDomDepth() > infoB->getDomDepth()) {
|
||||
a = const_cast<BasicBlock*>(infoA->getIdom());
|
||||
infoA = blockAnalysisInfo[a];
|
||||
}
|
||||
while (infoB->getDomDepth() > infoA->getDomDepth()) {
|
||||
b = const_cast<BasicBlock*>(infoB->getIdom());
|
||||
infoB = blockAnalysisInfo[b];
|
||||
}
|
||||
if (a == b) break;
|
||||
a = const_cast<BasicBlock*>(infoA->getIdom());
|
||||
b = const_cast<BasicBlock*>(infoB->getIdom());
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
void ControlFlowAnalysis::computeDomNode(){
|
||||
auto &functions = pModule->getFunctions();
|
||||
// 分析每个函数内的基本块
|
||||
for (const auto &function : functions) {
|
||||
auto func = function.second.get();
|
||||
auto basicBlocks = func->getBasicBlocks();
|
||||
std::unordered_set<BasicBlock *> domSetTmp;
|
||||
// 一开始把domSetTmp置为所有block
|
||||
auto entry_block = func->getEntryBlock();
|
||||
entry_block->setName("Entry");
|
||||
blockAnalysisInfo[entry_block]->addDominants(entry_block);
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
domSetTmp.emplace(basicBlock.get());
|
||||
}
|
||||
// 初始化
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
if (basicBlock.get() != entry_block) {
|
||||
blockAnalysisInfo[basicBlock.get()]->setDominants(domSetTmp);
|
||||
// 先把所有block的必经结点都设为N
|
||||
}
|
||||
}
|
||||
|
||||
// 支配节点计算公式
|
||||
//DOM[B]={B}∪ {⋂P∈pred(B) DOM[P]}
|
||||
// 其中pred(B)是B的所有前驱结点
|
||||
// 迭代计算支配结点,直到不再变化
|
||||
// 这里使用迭代法,直到支配结点不再变化
|
||||
// TODO:Lengauer-Tarjan 算法可以更高效地计算支配结点
|
||||
// 或者按照CFG拓扑序遍历效率更高
|
||||
bool changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
// 循环非start结点
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
if (basicBlock.get() != entry_block) {
|
||||
auto olddom =
|
||||
blockAnalysisInfo[basicBlock.get()]->getDominants();
|
||||
|
||||
std::unordered_set<BasicBlock *> dom =
|
||||
blockAnalysisInfo[basicBlock->getPredecessors().front()]->getDominants();
|
||||
|
||||
// 对于每个基本块,计算其支配结点
|
||||
// 取其前驱结点的支配结点的交集和自己
|
||||
for (auto pred : basicBlock->getPredecessors()) {
|
||||
intersectOP4Dom(dom, blockAnalysisInfo[pred]->getDominants());
|
||||
}
|
||||
dom.emplace(basicBlock.get());
|
||||
blockAnalysisInfo[basicBlock.get()]->setDominants(dom);
|
||||
|
||||
if (dom != olddom) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: SEMI-NCA算法改进
|
||||
void ControlFlowAnalysis::computeDomTree() {
|
||||
// 构造支配树
|
||||
auto &functions = pModule->getFunctions();
|
||||
for (const auto &function : functions) {
|
||||
auto func = function.second.get();
|
||||
auto basicBlocks = func->getBasicBlocks();
|
||||
auto entry_block = func->getEntryBlock();
|
||||
|
||||
blockAnalysisInfo[entry_block]->setIdom(entry_block);
|
||||
blockAnalysisInfo[entry_block]->setDomDepth(0); // 入口块深度为0
|
||||
|
||||
bool changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
if (basicBlock.get() == entry_block) continue;
|
||||
|
||||
BasicBlock *new_idom = nullptr;
|
||||
for (auto pred : basicBlock->getPredecessors()) {
|
||||
// 跳过未处理的前驱
|
||||
if (blockAnalysisInfo[pred]->getIdom() == nullptr) continue;
|
||||
// new_idom = (new_idom == nullptr) ? pred : findCommonDominator(new_idom, pred);
|
||||
if (new_idom == nullptr)
|
||||
new_idom = pred;
|
||||
else
|
||||
new_idom = findCommonDominator(new_idom, pred);
|
||||
}
|
||||
// 更新直接支配节点
|
||||
if (new_idom && new_idom != blockAnalysisInfo[basicBlock.get()]->getIdom()) {
|
||||
// 移除旧的支配关系
|
||||
if (blockAnalysisInfo[basicBlock.get()]->getIdom()) {
|
||||
blockAnalysisInfo[const_cast<BasicBlock*>(blockAnalysisInfo[basicBlock.get()]->getIdom())]->removeSdoms(basicBlock.get());
|
||||
}
|
||||
// 设置新的支配关系
|
||||
|
||||
// std::cout << "Block: " << basicBlock->getName()
|
||||
// << " New Idom: " << new_idom->getName() << std::endl;
|
||||
|
||||
blockAnalysisInfo[basicBlock.get()]->setIdom(new_idom);
|
||||
blockAnalysisInfo[new_idom]->addSdoms(basicBlock.get());
|
||||
// 更新深度 = 直接支配节点深度 + 1
|
||||
blockAnalysisInfo[basicBlock.get()]->setDomDepth(
|
||||
blockAnalysisInfo[new_idom]->getDomDepth() + 1);
|
||||
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// for (auto &basicBlock : basicBlocks) {
|
||||
// if (basicBlock.get() != func->getEntryBlock()) {
|
||||
// auto dominats =
|
||||
// blockAnalysisInfo[basicBlock.get()]->getDominants();
|
||||
// bool found = false;
|
||||
// // 从前驱结点开始寻找直接支配结点
|
||||
// std::queue<BasicBlock *> q;
|
||||
// for (auto pred : basicBlock->getPredecessors()) {
|
||||
// q.push(pred);
|
||||
// }
|
||||
// // BFS遍历前驱结点,直到找到直接支配结点
|
||||
// while (!found && !q.empty()) {
|
||||
// auto curr = q.front();
|
||||
// q.pop();
|
||||
// if (curr == basicBlock.get())
|
||||
// continue;
|
||||
// if (dominats.count(curr) != 0U) {
|
||||
// blockAnalysisInfo[basicBlock.get()]->setIdom(curr);
|
||||
// blockAnalysisInfo[curr]->addSdoms(basicBlock.get());
|
||||
// found = true;
|
||||
// } else {
|
||||
// for (auto pred : curr->getPredecessors()) {
|
||||
// q.push(pred);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// std::unordered_set<BasicBlock *> ControlFlowAnalysis::computeDomFrontier(BasicBlock *block) {
|
||||
// std::unordered_set<BasicBlock *> ret_list;
|
||||
// // 计算 localDF
|
||||
// for (auto local_successor : block->getSuccessors()) {
|
||||
// if (local_successor->getIdom() != block) {
|
||||
// ret_list.emplace(local_successor);
|
||||
// }
|
||||
// }
|
||||
// // 计算 upDF
|
||||
// for (auto up_successor : block->getSdoms()) {
|
||||
// auto childrenDF = computeDF(up_successor);
|
||||
// for (auto w : childrenDF) {
|
||||
// if (block != w->getIdom() || block == w) {
|
||||
// ret_list.emplace(w);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// return ret_list;
|
||||
// }
|
||||
|
||||
void ControlFlowAnalysis::computeDomFrontierAllBlk() {
|
||||
auto &functions = pModule->getFunctions();
|
||||
for (const auto &function : functions) {
|
||||
auto func = function.second.get();
|
||||
auto basicBlocks = func->getBasicBlocks();
|
||||
|
||||
// 按支配树深度排序(从深到浅)
|
||||
std::vector<BasicBlock *> orderedBlocks;
|
||||
for (auto &bb : basicBlocks) {
|
||||
orderedBlocks.push_back(bb.get());
|
||||
}
|
||||
std::sort(orderedBlocks.begin(), orderedBlocks.end(),
|
||||
[this](BasicBlock *a, BasicBlock *b) {
|
||||
return blockAnalysisInfo[a]->getDomDepth() > blockAnalysisInfo[b]->getDomDepth();
|
||||
});
|
||||
|
||||
// 计算支配边界
|
||||
for (auto block : orderedBlocks) {
|
||||
std::unordered_set<BasicBlock *> df;
|
||||
|
||||
// Local DF: 直接后继中不被当前块支配的
|
||||
for (auto succ : block->getSuccessors()) {
|
||||
// 当前块不支配该后继(即不是其直接支配节点)
|
||||
if (blockAnalysisInfo[succ]->getIdom() != block) {
|
||||
df.insert(succ);
|
||||
}
|
||||
}
|
||||
|
||||
// Up DF: 从支配子树中继承
|
||||
for (auto child : blockAnalysisInfo[block]->getSdoms()) {
|
||||
for (auto w : blockAnalysisInfo[child]->getDomFrontiers()) {
|
||||
// 如果w不被当前块支配
|
||||
if (block != blockAnalysisInfo[w]->getIdom()) {
|
||||
df.insert(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
blockAnalysisInfo[block]->setDomFrontiers(df);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================
|
||||
// dataflow analysis utils
|
||||
// ==========================
|
||||
|
||||
// 先引用学长的代码
|
||||
// TODO: Worklist 增加逆后序遍历机制
|
||||
void DataFlowAnalysisUtils::forwardAnalyze(Module *pModule){
|
||||
std::map<DataFlowAnalysis *, bool> workAnalysis;
|
||||
for (auto &dataflow : forwardAnalysisList) {
|
||||
dataflow->init(pModule);
|
||||
}
|
||||
|
||||
for (const auto &function : pModule->getFunctions()) {
|
||||
for (auto &dataflow : forwardAnalysisList) {
|
||||
workAnalysis.emplace(dataflow, false);
|
||||
}
|
||||
while (!workAnalysis.empty()) {
|
||||
for (const auto &block : function.second->getBasicBlocks()) {
|
||||
for (auto &elem : workAnalysis) {
|
||||
if (elem.first->analyze(pModule, block.get())) {
|
||||
elem.second = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::map<DataFlowAnalysis *, bool> tmp;
|
||||
std::remove_copy_if(workAnalysis.begin(), workAnalysis.end(), std::inserter(tmp, tmp.end()),
|
||||
[](const std::pair<DataFlowAnalysis *, bool> &elem) -> bool { return !elem.second; });
|
||||
workAnalysis.swap(tmp);
|
||||
|
||||
for (auto &elem : workAnalysis) {
|
||||
elem.second = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DataFlowAnalysisUtils::backwardAnalyze(Module *pModule) {
|
||||
std::map<DataFlowAnalysis *, bool> workAnalysis;
|
||||
for (auto &dataflow : backwardAnalysisList) {
|
||||
dataflow->init(pModule);
|
||||
}
|
||||
|
||||
for (const auto &function : pModule->getFunctions()) {
|
||||
for (auto &dataflow : backwardAnalysisList) {
|
||||
workAnalysis.emplace(dataflow, false);
|
||||
}
|
||||
while (!workAnalysis.empty()) {
|
||||
for (const auto &block : function.second->getBasicBlocks()) {
|
||||
for (auto &elem : workAnalysis) {
|
||||
if (elem.first->analyze(pModule, block.get())) {
|
||||
elem.second = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::map<DataFlowAnalysis *, bool> tmp;
|
||||
std::remove_copy_if(workAnalysis.begin(), workAnalysis.end(), std::inserter(tmp, tmp.end()),
|
||||
[](const std::pair<DataFlowAnalysis *, bool> &elem) -> bool { return !elem.second; });
|
||||
workAnalysis.swap(tmp);
|
||||
|
||||
for (auto &elem : workAnalysis) {
|
||||
elem.second = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::set<User *> ActiveVarAnalysis::getUsedSet(Instruction *inst) {
|
||||
using Kind = Instruction::Kind;
|
||||
std::vector<User *> operands;
|
||||
for (const auto &operand : inst->getOperands()) {
|
||||
operands.emplace_back(dynamic_cast<User *>(operand->getValue()));
|
||||
}
|
||||
std::set<User *> result;
|
||||
switch (inst->getKind()) {
|
||||
// phi op
|
||||
case Kind::kPhi:
|
||||
case Kind::kCall:
|
||||
result.insert(std::next(operands.begin()), operands.end());
|
||||
break;
|
||||
case Kind::kCondBr:
|
||||
result.insert(operands[0]);
|
||||
break;
|
||||
case Kind::kBr:
|
||||
case Kind::kAlloca:
|
||||
break;
|
||||
// mem op
|
||||
case Kind::kStore:
|
||||
// StoreInst 的第一个操作数是被存储的值,第二个操作数是存储的变量
|
||||
// 后续的是可能的数组维度
|
||||
result.insert(operands[0]);
|
||||
result.insert(operands.begin() + 2, operands.end());
|
||||
break;
|
||||
case Kind::kLoad:
|
||||
case Kind::kLa: {
|
||||
auto variable = dynamic_cast<AllocaInst *>(operands[0]);
|
||||
auto global = dynamic_cast<GlobalValue *>(operands[0]);
|
||||
auto constArray = dynamic_cast<ConstantVariable *>(operands[0]);
|
||||
if ((variable != nullptr && variable->getNumDims() == 0) || (global != nullptr && global->getNumDims() == 0) ||
|
||||
(constArray != nullptr && constArray->getNumDims() == 0)) {
|
||||
result.insert(operands[0]);
|
||||
}
|
||||
result.insert(std::next(operands.begin()), operands.end());
|
||||
break;
|
||||
}
|
||||
case Kind::kGetSubArray: {
|
||||
for (unsigned i = 2; i < operands.size(); i++) {
|
||||
// 数组的维度信息
|
||||
result.insert(operands[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Kind::kMemset: {
|
||||
result.insert(std::next(operands.begin()), operands.end());
|
||||
break;
|
||||
}
|
||||
case Kind::kInvalid:
|
||||
// Binary
|
||||
case Kind::kAdd:
|
||||
case Kind::kSub:
|
||||
case Kind::kMul:
|
||||
case Kind::kDiv:
|
||||
case Kind::kRem:
|
||||
case Kind::kICmpEQ:
|
||||
case Kind::kICmpNE:
|
||||
case Kind::kICmpLT:
|
||||
case Kind::kICmpLE:
|
||||
case Kind::kICmpGT:
|
||||
case Kind::kICmpGE:
|
||||
case Kind::kFAdd:
|
||||
case Kind::kFSub:
|
||||
case Kind::kFMul:
|
||||
case Kind::kFDiv:
|
||||
case Kind::kFCmpEQ:
|
||||
case Kind::kFCmpNE:
|
||||
case Kind::kFCmpLT:
|
||||
case Kind::kFCmpLE:
|
||||
case Kind::kFCmpGT:
|
||||
case Kind::kFCmpGE:
|
||||
case Kind::kAnd:
|
||||
case Kind::kOr:
|
||||
// Unary
|
||||
case Kind::kNeg:
|
||||
case Kind::kNot:
|
||||
case Kind::kFNot:
|
||||
case Kind::kFNeg:
|
||||
case Kind::kFtoI:
|
||||
case Kind::kItoF:
|
||||
// terminator
|
||||
case Kind::kReturn:
|
||||
result.insert(operands.begin(), operands.end());
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
result.erase(nullptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
User * ActiveVarAnalysis::getDefine(Instruction *inst) {
|
||||
User *result = nullptr;
|
||||
if (inst->isStore()) {
|
||||
StoreInst* store = dynamic_cast<StoreInst *>(inst);
|
||||
auto operand = store->getPointer();
|
||||
AllocaInst* variable = dynamic_cast<AllocaInst *>(operand);
|
||||
GlobalValue* global = dynamic_cast<GlobalValue *>(operand);
|
||||
if ((variable != nullptr && variable->getNumDims() != 0) || (global != nullptr && global->getNumDims() != 0)) {
|
||||
// 如果是数组变量或者全局变量,则不返回定义
|
||||
// TODO:兼容数组变量
|
||||
result = nullptr;
|
||||
} else {
|
||||
result = dynamic_cast<User *>(operand);
|
||||
}
|
||||
} else if (inst->isPhi()) {
|
||||
result = dynamic_cast<User *>(inst->getOperand(0));
|
||||
} else if (inst->isBinary() || inst->isUnary() || inst->isCall() ||
|
||||
inst->isLoad() || inst->isLa()) {
|
||||
result = dynamic_cast<User *>(inst);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ActiveVarAnalysis::init(Module *pModule) {
|
||||
for (const auto &function : pModule->getFunctions()) {
|
||||
for (const auto &block : function.second->getBasicBlocks()) {
|
||||
activeTable.emplace(block.get(), std::vector<std::set<User *>>{});
|
||||
for (unsigned i = 0; i < block->getNumInstructions() + 1; i++)
|
||||
activeTable.at(block.get()).emplace_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 活跃变量分析公式 每个块内的分析动作供分析器调用
|
||||
bool ActiveVarAnalysis::analyze(Module *pModule, BasicBlock *block) {
|
||||
bool changed = false; // 标记数据流结果是否有变化
|
||||
std::set<User *> activeSet{}; // 当前计算的活跃变量集合
|
||||
|
||||
// 步骤1: 计算基本块出口的活跃变量集 (OUT[B])
|
||||
// 公式: OUT[B] = ∪_{S ∈ succ(B)} IN[S]
|
||||
for (const auto &succ : block->getSuccessors()) {
|
||||
// 获取后继块入口的活跃变量集 (IN[S])
|
||||
auto succActiveSet = activeTable.at(succ).front();
|
||||
// 合并所有后继块的入口活跃变量
|
||||
activeSet.insert(succActiveSet.begin(), succActiveSet.end());
|
||||
}
|
||||
|
||||
// 步骤2: 处理基本块出口处的活跃变量集
|
||||
const auto &instructions = block->getInstructions();
|
||||
const auto numInstructions = instructions.size();
|
||||
|
||||
// 获取旧的出口活跃变量集 (block出口对应索引numInstructions)
|
||||
const auto &oldEndActiveSet = activeTable.at(block)[numInstructions];
|
||||
|
||||
// 检查出口活跃变量集是否有变化
|
||||
if (!std::equal(activeSet.begin(), activeSet.end(),
|
||||
oldEndActiveSet.begin(), oldEndActiveSet.end()))
|
||||
{
|
||||
changed = true; // 标记变化
|
||||
activeTable.at(block)[numInstructions] = activeSet; // 更新出口活跃变量集
|
||||
}
|
||||
|
||||
// 步骤3: 逆序遍历基本块中的指令
|
||||
// 从最后一条指令开始向前计算每个程序点的活跃变量
|
||||
auto instructionIter = instructions.end();
|
||||
instructionIter--; // 指向最后一条指令
|
||||
|
||||
// 从出口向入口遍历 (索引从numInstructions递减到1)
|
||||
for (unsigned i = numInstructions; i > 0; i--) {
|
||||
auto inst = instructionIter->get(); // 当前指令
|
||||
|
||||
auto used = getUsedSet(inst);
|
||||
User *defined = getDefine(inst);
|
||||
|
||||
// 步骤3.3: 计算指令入口的活跃变量 (IN[i])
|
||||
// 公式: IN[i] = use_i ∪ (OUT[i] - def_i)
|
||||
activeSet.erase(defined); // 移除被定义的变量 (OUT[i] - def_i)
|
||||
activeSet.insert(used.begin(), used.end()); // 添加使用的变量
|
||||
|
||||
// 获取旧的入口活跃变量集 (位置i-1对应当前指令的入口)
|
||||
const auto &oldActiveSet = activeTable.at(block)[i - 1];
|
||||
|
||||
// 检查活跃变量集是否有变化
|
||||
if (!std::equal(activeSet.begin(), activeSet.end(),
|
||||
oldActiveSet.begin(), oldActiveSet.end()))
|
||||
{
|
||||
changed = true; // 标记变化
|
||||
activeTable.at(block)[i - 1] = activeSet; // 更新入口活跃变量集
|
||||
}
|
||||
|
||||
instructionIter--; // 移动到前一条指令
|
||||
}
|
||||
|
||||
return changed; // 返回数据流结果是否变化
|
||||
}
|
||||
|
||||
|
||||
auto ActiveVarAnalysis::getActiveTable() const -> const std::map<BasicBlock *, std::vector<std::set<User *>>> & {
|
||||
return activeTable;
|
||||
}
|
||||
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
1278
src/SysYIRGenerator.cpp
Normal file
1278
src/SysYIRGenerator.cpp
Normal file
File diff suppressed because it is too large
Load Diff
484
src/SysYIROptPre.cpp
Normal file
484
src/SysYIROptPre.cpp
Normal file
@ -0,0 +1,484 @@
|
||||
#include "SysYIROptPre.h"
|
||||
#include <cassert>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include "IR.h"
|
||||
#include "IRBuilder.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
/**
|
||||
* use删除operand,以免扰乱后续分析
|
||||
* instr: 要删除的指令
|
||||
*/
|
||||
void SysYOptPre::usedelete(Instruction *instr) {
|
||||
for (auto &use : instr->getOperands()) {
|
||||
Value* val = use->getValue();
|
||||
// std::cout << delete << val->getName() << std::endl;
|
||||
val->removeUse(use);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 删除br后的无用指令
|
||||
void SysYOptPre::SysYDelInstAfterBr() {
|
||||
auto &functions = pModule->getFunctions();
|
||||
for (auto &function : functions) {
|
||||
auto basicBlocks = function.second->getBasicBlocks();
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
bool Branch = false;
|
||||
auto &instructions = basicBlock->getInstructions();
|
||||
auto Branchiter = instructions.end();
|
||||
for (auto iter = instructions.begin(); iter != instructions.end(); ++iter) {
|
||||
if (Branch)
|
||||
usedelete(iter->get());
|
||||
else if ((*iter)->isTerminator()){
|
||||
Branch = true;
|
||||
Branchiter = iter;
|
||||
}
|
||||
}
|
||||
if (Branchiter != instructions.end()) ++Branchiter;
|
||||
while (Branchiter != instructions.end())
|
||||
Branchiter = instructions.erase(Branchiter);
|
||||
|
||||
if (Branch) { // 更新前驱后继关系
|
||||
auto thelastinstinst = basicBlock->getInstructions().end();
|
||||
--thelastinstinst;
|
||||
auto &Successors = basicBlock->getSuccessors();
|
||||
for (auto iterSucc = Successors.begin(); iterSucc != Successors.end();) {
|
||||
(*iterSucc)->removePredecessor(basicBlock.get());
|
||||
basicBlock->removeSuccessor(*iterSucc);
|
||||
}
|
||||
if (thelastinstinst->get()->isUnconditional()) {
|
||||
BasicBlock* branchBlock = dynamic_cast<BasicBlock *>(thelastinstinst->get()->getOperand(0));
|
||||
basicBlock->addSuccessor(branchBlock);
|
||||
branchBlock->addPredecessor(basicBlock.get());
|
||||
} else if (thelastinstinst->get()->isConditional()) {
|
||||
BasicBlock* thenBlock = dynamic_cast<BasicBlock *>(thelastinstinst->get()->getOperand(1));
|
||||
BasicBlock* elseBlock = dynamic_cast<BasicBlock *>(thelastinstinst->get()->getOperand(2));
|
||||
basicBlock->addSuccessor(thenBlock);
|
||||
basicBlock->addSuccessor(elseBlock);
|
||||
thenBlock->addPredecessor(basicBlock.get());
|
||||
elseBlock->addPredecessor(basicBlock.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SysYOptPre::SysYBlockMerge() {
|
||||
auto &functions = pModule->getFunctions(); //std::map<std::string, std::unique_ptr<Function>>
|
||||
for (auto &function : functions) {
|
||||
// auto basicBlocks = function.second->getBasicBlocks();
|
||||
auto &func = function.second;
|
||||
for (auto blockiter = func->getBasicBlocks().begin();
|
||||
blockiter != func->getBasicBlocks().end();) {
|
||||
if (blockiter->get()->getNumSuccessors() == 1) {
|
||||
// 如果当前块只有一个后继块
|
||||
// 且后继块只有一个前驱块
|
||||
// 则将当前块和后继块合并
|
||||
if (((blockiter->get())->getSuccessors()[0])->getNumPredecessors() == 1) {
|
||||
// std::cout << "merge block: " << blockiter->get()->getName() << std::endl;
|
||||
BasicBlock* block = blockiter->get();
|
||||
BasicBlock* nextBlock = blockiter->get()->getSuccessors()[0];
|
||||
auto nextarguments = nextBlock->getArguments();
|
||||
// 删除br指令
|
||||
if (block->getNumInstructions() != 0) {
|
||||
auto thelastinstinst = block->end();
|
||||
(--thelastinstinst);
|
||||
if (thelastinstinst->get()->isUnconditional()) {
|
||||
usedelete(thelastinstinst->get());
|
||||
block->getInstructions().erase(thelastinstinst);
|
||||
} else if (thelastinstinst->get()->isConditional()) {
|
||||
// 如果是条件分支,判断条件是否相同,主要优化相同布尔表达式
|
||||
if (thelastinstinst->get()->getOperand(1)->getName() == thelastinstinst->get()->getOperand(1)->getName()) {
|
||||
usedelete(thelastinstinst->get());
|
||||
block->getInstructions().erase(thelastinstinst);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 将后继块的指令移动到当前块
|
||||
// 并将后继块的父指针改为当前块
|
||||
for (auto institer = nextBlock->begin(); institer != nextBlock->end();) {
|
||||
institer->get()->setParent(block);
|
||||
block->getInstructions().emplace_back(institer->release());
|
||||
institer = nextBlock->getInstructions().erase(institer);
|
||||
}
|
||||
// 合并参数
|
||||
// TODO:是否需要去重?
|
||||
for (auto &argm : nextarguments) {
|
||||
argm->setParent(block);
|
||||
block->insertArgument(argm);
|
||||
}
|
||||
// 更新前驱后继关系,类似树节点操作
|
||||
block->removeSuccessor(nextBlock);
|
||||
nextBlock->removePredecessor(block);
|
||||
std::list<BasicBlock *> succshoulddel;
|
||||
for (auto &succ : nextBlock->getSuccessors()) {
|
||||
block->addSuccessor(succ);
|
||||
succ->replacePredecessor(nextBlock, block);
|
||||
succshoulddel.push_back(succ);
|
||||
}
|
||||
for (auto del : succshoulddel) {
|
||||
nextBlock->removeSuccessor(del);
|
||||
}
|
||||
|
||||
func->removeBasicBlock(nextBlock);
|
||||
|
||||
} else {
|
||||
blockiter++;
|
||||
}
|
||||
} else {
|
||||
blockiter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除无前驱块,兼容SSA后的处理
|
||||
void SysYOptPre::SysYDelNoPreBLock() {
|
||||
|
||||
auto &functions = pModule->getFunctions(); // std::map<std::string, std::unique_ptr<sysy::Function>>
|
||||
for (auto &function : functions) {
|
||||
auto &func = function.second;
|
||||
|
||||
for (auto &block : func->getBasicBlocks()) {
|
||||
block->setreachableFalse();
|
||||
}
|
||||
// 对函数基本块做一个拓扑排序,排查不可达基本块
|
||||
auto entryBlock = func->getEntryBlock();
|
||||
entryBlock->setreachableTrue();
|
||||
std::queue<BasicBlock *> blockqueue;
|
||||
blockqueue.push(entryBlock);
|
||||
while (!blockqueue.empty()) {
|
||||
auto block = blockqueue.front();
|
||||
blockqueue.pop();
|
||||
for (auto &succ : block->getSuccessors()) {
|
||||
if (!succ->getreachable()) {
|
||||
succ->setreachableTrue();
|
||||
blockqueue.push(succ);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除不可达基本块指令
|
||||
for (auto blockIter = func->getBasicBlocks().begin(); blockIter != func->getBasicBlocks().end();blockIter++) {
|
||||
|
||||
if (!blockIter->get()->getreachable())
|
||||
for (auto &iterInst : blockIter->get()->getInstructions())
|
||||
usedelete(iterInst.get());
|
||||
|
||||
}
|
||||
|
||||
|
||||
for (auto blockIter = func->getBasicBlocks().begin(); blockIter != func->getBasicBlocks().end();) {
|
||||
if (!blockIter->get()->getreachable()) {
|
||||
for (auto succblock : blockIter->get()->getSuccessors()) {
|
||||
int indexphi = 1;
|
||||
for (auto pred : succblock->getPredecessors()) {
|
||||
if (pred == blockIter->get()) {
|
||||
break;
|
||||
}
|
||||
indexphi++;
|
||||
}
|
||||
for (auto &phiinst : succblock->getInstructions()) {
|
||||
if (phiinst->getKind() != Instruction::kPhi) {
|
||||
break;
|
||||
}
|
||||
phiinst->removeOperand(indexphi);
|
||||
}
|
||||
}
|
||||
// 删除不可达基本块,注意迭代器不可达问题
|
||||
func->removeBasicBlock((blockIter++)->get());
|
||||
} else {
|
||||
blockIter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SysYOptPre::SysYDelEmptyBlock() {
|
||||
auto &functions = pModule->getFunctions();
|
||||
for (auto &function : functions) {
|
||||
// 收集不可达基本块
|
||||
// 这里的不可达基本块是指没有实际指令的基本块
|
||||
// 当一个基本块没有实际指令例如只有phi指令和一个uncondbr指令时,也会被视作不可达
|
||||
auto basicBlocks = function.second->getBasicBlocks();
|
||||
std::map<sysy::BasicBlock *, BasicBlock *> EmptyBlocks;
|
||||
// 空块儿和后继的基本块的映射
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
if (basicBlock->getNumInstructions() == 0) {
|
||||
if (basicBlock->getNumSuccessors() == 1) {
|
||||
EmptyBlocks[basicBlock.get()] = basicBlock->getSuccessors().front();
|
||||
}
|
||||
}
|
||||
else{
|
||||
// 如果只有phi指令和一个uncondbr。(phi)*(uncondbr)?
|
||||
// 判断除了最后一个指令之外是不是只有phi指令
|
||||
bool onlyPhi = true;
|
||||
for (auto &inst : basicBlock->getInstructions()) {
|
||||
if (!inst->isPhi() && !inst->isUnconditional()) {
|
||||
onlyPhi = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(onlyPhi)
|
||||
EmptyBlocks[basicBlock.get()] = basicBlock->getSuccessors().front();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
// 更新基本块信息,增加必要指令
|
||||
for (auto &basicBlock : basicBlocks) {
|
||||
// 把空块转换成只有跳转指令的不可达块
|
||||
if (distance(basicBlock->begin(), basicBlock->end()) == 0) {
|
||||
if (basicBlock->getNumSuccessors() == 0) {
|
||||
continue;
|
||||
}
|
||||
if (basicBlock->getNumSuccessors() > 1) {
|
||||
assert("");
|
||||
}
|
||||
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||
pBuilder->createUncondBrInst(basicBlock->getSuccessors()[0], {});
|
||||
continue;
|
||||
}
|
||||
|
||||
auto thelastinst = basicBlock->getInstructions().end();
|
||||
--thelastinst;
|
||||
|
||||
// 根据br指令传递的后继块信息,跳过空块链
|
||||
if (thelastinst->get()->isUnconditional()) {
|
||||
BasicBlock* OldBrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
||||
BasicBlock *thelastBlockOld = nullptr;
|
||||
// 如果空块链表为多个块
|
||||
while (EmptyBlocks.find(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))) !=
|
||||
EmptyBlocks.end()) {
|
||||
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
||||
thelastinst->get()->replaceOperand(0, EmptyBlocks[thelastBlockOld]);
|
||||
}
|
||||
|
||||
basicBlock->removeSuccessor(OldBrBlock);
|
||||
OldBrBlock->removePredecessor(basicBlock.get());
|
||||
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0)));
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->addPredecessor(basicBlock.get());
|
||||
|
||||
if (thelastBlockOld != nullptr) {
|
||||
int indexphi = 0;
|
||||
for (auto &pred : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getPredecessors()) {
|
||||
if (pred == thelastBlockOld) {
|
||||
break;
|
||||
}
|
||||
indexphi++;
|
||||
}
|
||||
|
||||
// 更新phi指令的操作数
|
||||
// 移除thelastBlockOld对应的phi操作数
|
||||
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getInstructions()) {
|
||||
if (InstInNew->isPhi()) {
|
||||
dynamic_cast<PhiInst *>(InstInNew.get())->removeOperand(indexphi + 1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (thelastinst->get()->getKind() == Instruction::kCondBr) {
|
||||
auto OldThenBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||
auto OldElseBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2));
|
||||
|
||||
BasicBlock *thelastBlockOld = nullptr;
|
||||
while (EmptyBlocks.find(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))) !=
|
||||
EmptyBlocks.end()) {
|
||||
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||
thelastinst->get()->replaceOperand(
|
||||
1, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))]);
|
||||
}
|
||||
basicBlock->removeSuccessor(OldThenBlock);
|
||||
OldThenBlock->removePredecessor(basicBlock.get());
|
||||
// 处理 then 和 else 分支合并的情况
|
||||
if (dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)) ==
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) {
|
||||
auto thebrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||
usedelete(thelastinst->get());
|
||||
thelastinst = basicBlock->getInstructions().erase(thelastinst);
|
||||
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||
pBuilder->createUncondBrInst(thebrBlock, {});
|
||||
continue;
|
||||
}
|
||||
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)));
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->addPredecessor(basicBlock.get());
|
||||
// auto indexInNew = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getPredecessors().
|
||||
|
||||
if (thelastBlockOld != nullptr) {
|
||||
int indexphi = 0;
|
||||
for (auto &pred : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->getPredecessors()) {
|
||||
if (pred == thelastBlockOld) {
|
||||
break;
|
||||
}
|
||||
indexphi++;
|
||||
}
|
||||
|
||||
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1))->getInstructions()) {
|
||||
if (InstInNew->isPhi()) {
|
||||
dynamic_cast<PhiInst *>(InstInNew.get())->removeOperand(indexphi + 1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thelastBlockOld = nullptr;
|
||||
while (EmptyBlocks.find(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) !=
|
||||
EmptyBlocks.end()) {
|
||||
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2));
|
||||
thelastinst->get()->replaceOperand(
|
||||
2, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))]);
|
||||
}
|
||||
basicBlock->removeSuccessor(OldElseBlock);
|
||||
OldElseBlock->removePredecessor(basicBlock.get());
|
||||
// 处理 then 和 else 分支合并的情况
|
||||
if (dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)) ==
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) {
|
||||
auto thebrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||
usedelete(thelastinst->get());
|
||||
thelastinst = basicBlock->getInstructions().erase(thelastinst);
|
||||
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||
pBuilder->createUncondBrInst(thebrBlock, {});
|
||||
continue;
|
||||
}
|
||||
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2)));
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->addPredecessor(basicBlock.get());
|
||||
|
||||
if (thelastBlockOld != nullptr) {
|
||||
int indexphi = 0;
|
||||
for (auto &pred : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->getPredecessors()) {
|
||||
if (pred == thelastBlockOld) {
|
||||
break;
|
||||
}
|
||||
indexphi++;
|
||||
}
|
||||
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))->getInstructions()) {
|
||||
if (InstInNew->isPhi()) {
|
||||
dynamic_cast<PhiInst *>(InstInNew.get())->removeOperand(indexphi + 1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (basicBlock->getNumSuccessors() == 1) {
|
||||
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||
pBuilder->createUncondBrInst(basicBlock->getSuccessors()[0], {});
|
||||
auto thelastinst = basicBlock->getInstructions().end();
|
||||
(--thelastinst);
|
||||
auto OldBrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
||||
sysy::BasicBlock *thelastBlockOld = nullptr;
|
||||
while (EmptyBlocks.find(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))) !=
|
||||
EmptyBlocks.end()) {
|
||||
thelastBlockOld = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0));
|
||||
|
||||
thelastinst->get()->replaceOperand(
|
||||
0, EmptyBlocks[dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))]);
|
||||
}
|
||||
|
||||
basicBlock->removeSuccessor(OldBrBlock);
|
||||
OldBrBlock->removePredecessor(basicBlock.get());
|
||||
basicBlock->addSuccessor(dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0)));
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->addPredecessor(basicBlock.get());
|
||||
if (thelastBlockOld != nullptr) {
|
||||
int indexphi = 0;
|
||||
for (auto &pred : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getPredecessors()) {
|
||||
if (pred == thelastBlockOld) {
|
||||
break;
|
||||
}
|
||||
indexphi++;
|
||||
}
|
||||
|
||||
for (auto &InstInNew : dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(0))->getInstructions()) {
|
||||
if (InstInNew->isPhi()) {
|
||||
dynamic_cast<PhiInst *>(InstInNew.get())->removeOperand(indexphi + 1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto iter = function.second->getBasicBlocks().begin(); iter != function.second->getBasicBlocks().end();) {
|
||||
|
||||
if (EmptyBlocks.find(iter->get()) != EmptyBlocks.end()) {
|
||||
// EntryBlock跳过
|
||||
if (iter->get() == function.second->getEntryBlock()) {
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto &iterInst : iter->get()->getInstructions())
|
||||
usedelete(iterInst.get());
|
||||
// 删除不可达基本块的phi指令的操作数
|
||||
for (auto &succ : iter->get()->getSuccessors()) {
|
||||
int index = 0;
|
||||
for (auto &pred : succ->getPredecessors()) {
|
||||
if (pred == iter->get()) {
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
for (auto &instinsucc : succ->getInstructions()) {
|
||||
if (instinsucc->isPhi()) {
|
||||
dynamic_cast<PhiInst *>(instinsucc.get())->removeOperand(index);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function.second->removeBasicBlock((iter++)->get());
|
||||
} else {
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果函数没有返回指令,则添加一个默认返回指令(主要解决void函数没有返回指令的问题)
|
||||
void SysYOptPre::SysYAddReturn() {
|
||||
auto &functions = pModule->getFunctions();
|
||||
for (auto &function : functions) {
|
||||
auto &func = function.second;
|
||||
auto basicBlocks = func->getBasicBlocks();
|
||||
for (auto &block : basicBlocks) {
|
||||
if (block->getNumSuccessors() == 0) {
|
||||
// 如果基本块没有后继块,则添加一个返回指令
|
||||
if (block->getNumInstructions() == 0) {
|
||||
pBuilder->setPosition(block.get(), block->end());
|
||||
pBuilder->createReturnInst();
|
||||
}
|
||||
auto thelastinst = block->getInstructions().end();
|
||||
--thelastinst;
|
||||
if (thelastinst->get()->getKind() != Instruction::kReturn) {
|
||||
// std::cout << "Warning: Function " << func->getName() << " has no return instruction, adding default return." << std::endl;
|
||||
|
||||
pBuilder->setPosition(block.get(), block->end());
|
||||
// TODO: 如果int float函数缺少返回值是否需要报错
|
||||
if (func->getReturnType()->isInt()) {
|
||||
pBuilder->createReturnInst(ConstantInteger::get(0));
|
||||
} else if (func->getReturnType()->isFloat()) {
|
||||
pBuilder->createReturnInst(ConstantFloating::get(0.0F));
|
||||
} else {
|
||||
pBuilder->createReturnInst();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
483
src/SysYIRPrinter.cpp
Normal file
483
src/SysYIRPrinter.cpp
Normal file
@ -0,0 +1,483 @@
|
||||
#include "SysYIRPrinter.h"
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "IR.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
void SysYPrinter::printIR() {
|
||||
|
||||
const auto &functions = pModule->getFunctions();
|
||||
|
||||
//TODO: Print target datalayout and triple (minimal required by LLVM)
|
||||
|
||||
printGlobalVariable();
|
||||
|
||||
for (const auto &iter : functions) {
|
||||
if (iter.second->getName() == "main") {
|
||||
printFunction(iter.second.get());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &iter : functions) {
|
||||
if (iter.second->getName() != "main") {
|
||||
printFunction(iter.second.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string SysYPrinter::getTypeString(Type *type) {
|
||||
if (type->isVoid()) {
|
||||
return "void";
|
||||
} else if (type->isInt()) {
|
||||
return "i32";
|
||||
} else if (type->isFloat()) {
|
||||
return "float";
|
||||
|
||||
} else if (auto ptrType = dynamic_cast<PointerType*>(type)) {
|
||||
return getTypeString(ptrType->getBaseType()) + "*";
|
||||
} else if (auto ptrType = dynamic_cast<FunctionType*>(type)) {
|
||||
return getTypeString(ptrType->getReturnType());
|
||||
}
|
||||
assert(false && "Unsupported type");
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string SysYPrinter::getValueName(Value *value) {
|
||||
if (auto global = dynamic_cast<GlobalValue*>(value)) {
|
||||
return "@" + global->getName();
|
||||
} else if (auto inst = dynamic_cast<Instruction*>(value)) {
|
||||
return "%" + inst->getName();
|
||||
} else if (auto constVal = dynamic_cast<ConstantValue*>(value)) {
|
||||
if (constVal->isFloat()) {
|
||||
return std::to_string(constVal->getFloat());
|
||||
}
|
||||
return std::to_string(constVal->getInt());
|
||||
} else if (auto constVar = dynamic_cast<ConstantVariable*>(value)) {
|
||||
return constVar->getName();
|
||||
}
|
||||
assert(false && "Unknown value type");
|
||||
return "";
|
||||
}
|
||||
|
||||
void SysYPrinter::printType(Type *type) {
|
||||
std::cout << getTypeString(type);
|
||||
}
|
||||
|
||||
void SysYPrinter::printValue(Value *value) {
|
||||
std::cout << getValueName(value);
|
||||
}
|
||||
|
||||
void SysYPrinter::printGlobalVariable() {
|
||||
auto &globals = pModule->getGlobals();
|
||||
|
||||
for (const auto &global : globals) {
|
||||
std::cout << "@" << global->getName() << " = global ";
|
||||
|
||||
auto baseType = dynamic_cast<PointerType *>(global->getType())->getBaseType();
|
||||
printType(baseType);
|
||||
|
||||
if (global->getNumDims() > 0) {
|
||||
// Array type
|
||||
std::cout << " [";
|
||||
for (unsigned i = 0; i < global->getNumDims(); i++) {
|
||||
if (i > 0) std::cout << " x ";
|
||||
std::cout << getValueName(global->getDim(i));
|
||||
}
|
||||
std::cout << "]";
|
||||
}
|
||||
|
||||
std::cout << " ";
|
||||
|
||||
if (global->getNumDims() > 0) {
|
||||
// Array initializer
|
||||
std::cout << "[";
|
||||
auto values = global->getInitValues();
|
||||
auto counterValues = values.getValues();
|
||||
auto counterNumbers = values.getNumbers();
|
||||
|
||||
for (size_t i = 0; i < counterNumbers.size(); i++) {
|
||||
if (i > 0) std::cout << ", ";
|
||||
if (baseType->isFloat()) {
|
||||
std::cout << "float " << dynamic_cast<ConstantValue*>(counterValues[i])->getFloat();
|
||||
} else {
|
||||
std::cout << "i32 " << dynamic_cast<ConstantValue*>(counterValues[i])->getInt();
|
||||
}
|
||||
}
|
||||
std::cout << "]";
|
||||
} else {
|
||||
// Scalar initializer
|
||||
if (baseType->isFloat()) {
|
||||
std::cout << "float " << dynamic_cast<ConstantValue*>(global->getByIndex(0))->getFloat();
|
||||
} else {
|
||||
std::cout << "i32 " << dynamic_cast<ConstantValue*>(global->getByIndex(0))->getInt();
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << ", align 4" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void SysYPrinter::printFunction(Function *function) {
|
||||
// Function signature
|
||||
std::cout << "define ";
|
||||
printType(function->getReturnType());
|
||||
std::cout << " @" << function->getName() << "(";
|
||||
|
||||
auto entryBlock = function->getEntryBlock();
|
||||
const auto &args_types = function->getParamTypes();
|
||||
auto &args = entryBlock->getArguments();
|
||||
|
||||
int i = 0;
|
||||
for (const auto &args_type : args_types) {
|
||||
if (i > 0) std::cout << ", ";
|
||||
printType(args_type);
|
||||
std::cout << " %" << args[i]->getName();
|
||||
i++;
|
||||
}
|
||||
|
||||
std::cout << ") {" << std::endl;
|
||||
|
||||
// Function body
|
||||
for (const auto &blockIter : function->getBasicBlocks()) {
|
||||
// Basic block label
|
||||
BasicBlock* blockPtr = blockIter.get();
|
||||
if (blockPtr == function->getEntryBlock()) {
|
||||
std::cout << "entry:" << std::endl;
|
||||
} else if (!blockPtr->getName().empty()) {
|
||||
std::cout << blockPtr->getName() << ":" << std::endl;
|
||||
}
|
||||
|
||||
// Instructions
|
||||
for (const auto &instIter : blockIter->getInstructions()) {
|
||||
auto inst = instIter.get();
|
||||
std::cout << " ";
|
||||
printInst(inst);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "}" << std::endl << std::endl;
|
||||
}
|
||||
|
||||
void SysYPrinter::printInst(Instruction *pInst) {
|
||||
using Kind = Instruction::Kind;
|
||||
|
||||
switch (pInst->getKind()) {
|
||||
case Kind::kAdd:
|
||||
case Kind::kSub:
|
||||
case Kind::kMul:
|
||||
case Kind::kDiv:
|
||||
case Kind::kRem:
|
||||
case Kind::kFAdd:
|
||||
case Kind::kFSub:
|
||||
case Kind::kFMul:
|
||||
case Kind::kFDiv:
|
||||
case Kind::kICmpEQ:
|
||||
case Kind::kICmpNE:
|
||||
case Kind::kICmpLT:
|
||||
case Kind::kICmpGT:
|
||||
case Kind::kICmpLE:
|
||||
case Kind::kICmpGE:
|
||||
case Kind::kFCmpEQ:
|
||||
case Kind::kFCmpNE:
|
||||
case Kind::kFCmpLT:
|
||||
case Kind::kFCmpGT:
|
||||
case Kind::kFCmpLE:
|
||||
case Kind::kFCmpGE:
|
||||
case Kind::kAnd:
|
||||
case Kind::kOr: {
|
||||
auto binInst = dynamic_cast<BinaryInst *>(pInst);
|
||||
|
||||
// Print result variable if exists
|
||||
if (!binInst->getName().empty()) {
|
||||
std::cout << "%" << binInst->getName() << " = ";
|
||||
}
|
||||
|
||||
// Operation name
|
||||
switch (pInst->getKind()) {
|
||||
case Kind::kAdd: std::cout << "add"; break;
|
||||
case Kind::kSub: std::cout << "sub"; break;
|
||||
case Kind::kMul: std::cout << "mul"; break;
|
||||
case Kind::kDiv: std::cout << "sdiv"; break;
|
||||
case Kind::kRem: std::cout << "srem"; break;
|
||||
case Kind::kFAdd: std::cout << "fadd"; break;
|
||||
case Kind::kFSub: std::cout << "fsub"; break;
|
||||
case Kind::kFMul: std::cout << "fmul"; break;
|
||||
case Kind::kFDiv: std::cout << "fdiv"; break;
|
||||
case Kind::kICmpEQ: std::cout << "icmp eq"; break;
|
||||
case Kind::kICmpNE: std::cout << "icmp ne"; break;
|
||||
case Kind::kICmpLT: std::cout << "icmp slt"; break;
|
||||
case Kind::kICmpGT: std::cout << "icmp sgt"; break;
|
||||
case Kind::kICmpLE: std::cout << "icmp sle"; break;
|
||||
case Kind::kICmpGE: std::cout << "icmp sge"; break;
|
||||
case Kind::kFCmpEQ: std::cout << "fcmp oeq"; break;
|
||||
case Kind::kFCmpNE: std::cout << "fcmp one"; break;
|
||||
case Kind::kFCmpLT: std::cout << "fcmp olt"; break;
|
||||
case Kind::kFCmpGT: std::cout << "fcmp ogt"; break;
|
||||
case Kind::kFCmpLE: std::cout << "fcmp ole"; break;
|
||||
case Kind::kFCmpGE: std::cout << "fcmp oge"; break;
|
||||
case Kind::kAnd: std::cout << "and"; break;
|
||||
case Kind::kOr: std::cout << "or"; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
// Types and operands
|
||||
std::cout << " ";
|
||||
printType(binInst->getType());
|
||||
std::cout << " ";
|
||||
printValue(binInst->getLhs());
|
||||
std::cout << ", ";
|
||||
printValue(binInst->getRhs());
|
||||
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kNeg:
|
||||
case Kind::kNot:
|
||||
case Kind::kFNeg:
|
||||
case Kind::kFNot:
|
||||
case Kind::kFtoI:
|
||||
case Kind::kBitFtoI:
|
||||
case Kind::kItoF:
|
||||
case Kind::kBitItoF: {
|
||||
auto unyInst = dynamic_cast<UnaryInst *>(pInst);
|
||||
|
||||
if (!unyInst->getName().empty()) {
|
||||
std::cout << "%" << unyInst->getName() << " = ";
|
||||
}
|
||||
|
||||
switch (pInst->getKind()) {
|
||||
case Kind::kNeg: std::cout << "sub "; break;
|
||||
case Kind::kNot: std::cout << "not "; break;
|
||||
case Kind::kFNeg: std::cout << "fneg "; break;
|
||||
case Kind::kFNot: std::cout << "fneg "; break; // FNot not standard, map to fneg
|
||||
case Kind::kFtoI: std::cout << "fptosi "; break;
|
||||
case Kind::kBitFtoI: std::cout << "bitcast "; break;
|
||||
case Kind::kItoF: std::cout << "sitofp "; break;
|
||||
case Kind::kBitItoF: std::cout << "bitcast "; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
printType(unyInst->getType());
|
||||
std::cout << " ";
|
||||
|
||||
// Special handling for negation
|
||||
if (pInst->getKind() == Kind::kNeg || pInst->getKind() == Kind::kNot) {
|
||||
std::cout << "i32 0, ";
|
||||
}
|
||||
|
||||
printValue(pInst->getOperand(0));
|
||||
|
||||
// For bitcast, need to specify destination type
|
||||
if (pInst->getKind() == Kind::kBitFtoI || pInst->getKind() == Kind::kBitItoF) {
|
||||
std::cout << " to ";
|
||||
printType(unyInst->getType());
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kCall: {
|
||||
auto callInst = dynamic_cast<CallInst *>(pInst);
|
||||
auto function = callInst->getCallee();
|
||||
|
||||
if (!callInst->getName().empty()) {
|
||||
std::cout << "%" << callInst->getName() << " = ";
|
||||
}
|
||||
|
||||
std::cout << "call ";
|
||||
printType(callInst->getType());
|
||||
std::cout << " @" << function->getName() << "(";
|
||||
|
||||
auto params = callInst->getArguments();
|
||||
bool first = true;
|
||||
for (auto ¶m : params) {
|
||||
if (!first) std::cout << ", ";
|
||||
first = false;
|
||||
printType(param->getValue()->getType());
|
||||
std::cout << " ";
|
||||
printValue(param->getValue());
|
||||
}
|
||||
|
||||
std::cout << ")" << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kCondBr: {
|
||||
auto condBrInst = dynamic_cast<CondBrInst *>(pInst);
|
||||
std::cout << "br i1 ";
|
||||
printValue(condBrInst->getCondition());
|
||||
std::cout << ", label %" << condBrInst->getThenBlock()->getName();
|
||||
std::cout << ", label %" << condBrInst->getElseBlock()->getName();
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kBr: {
|
||||
auto brInst = dynamic_cast<UncondBrInst *>(pInst);
|
||||
std::cout << "br label %" << brInst->getBlock()->getName();
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kReturn: {
|
||||
auto retInst = dynamic_cast<ReturnInst *>(pInst);
|
||||
std::cout << "ret ";
|
||||
if (retInst->getNumOperands() != 0) {
|
||||
printType(retInst->getOperand(0)->getType());
|
||||
std::cout << " ";
|
||||
printValue(retInst->getOperand(0));
|
||||
} else {
|
||||
std::cout << "void";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kAlloca: {
|
||||
auto allocaInst = dynamic_cast<AllocaInst *>(pInst);
|
||||
std::cout << "%" << allocaInst->getName() << " = alloca ";
|
||||
|
||||
auto baseType = dynamic_cast<PointerType *>(allocaInst->getType())->getBaseType();
|
||||
printType(baseType);
|
||||
|
||||
if (allocaInst->getNumDims() > 0) {
|
||||
std::cout << ", ";
|
||||
for (size_t i = 0; i < allocaInst->getNumDims(); i++) {
|
||||
if (i > 0) std::cout << ", ";
|
||||
printType(Type::getIntType());
|
||||
std::cout << " ";
|
||||
printValue(allocaInst->getDim(i));
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << ", align 4" << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kLoad: {
|
||||
auto loadInst = dynamic_cast<LoadInst *>(pInst);
|
||||
std::cout << "%" << loadInst->getName() << " = load ";
|
||||
printType(loadInst->getType());
|
||||
std::cout << ", ";
|
||||
printType(loadInst->getPointer()->getType());
|
||||
std::cout << " ";
|
||||
printValue(loadInst->getPointer());
|
||||
|
||||
if (loadInst->getNumIndices() > 0) {
|
||||
std::cout << ", ";
|
||||
for (size_t i = 0; i < loadInst->getNumIndices(); i++) {
|
||||
if (i > 0) std::cout << ", ";
|
||||
printType(Type::getIntType());
|
||||
std::cout << " ";
|
||||
printValue(loadInst->getIndex(i));
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << ", align 4" << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kLa: {
|
||||
auto laInst = dynamic_cast<LaInst *>(pInst);
|
||||
std::cout << "%" << laInst->getName() << " = getelementptr inbounds ";
|
||||
|
||||
auto ptrType = dynamic_cast<PointerType*>(laInst->getPointer()->getType());
|
||||
printType(ptrType->getBaseType());
|
||||
std::cout << ", ";
|
||||
printType(laInst->getPointer()->getType());
|
||||
std::cout << " ";
|
||||
printValue(laInst->getPointer());
|
||||
std::cout << ", ";
|
||||
|
||||
for (size_t i = 0; i < laInst->getNumIndices(); i++) {
|
||||
if (i > 0) std::cout << ", ";
|
||||
printType(Type::getIntType());
|
||||
std::cout << " ";
|
||||
printValue(laInst->getIndex(i));
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kStore: {
|
||||
auto storeInst = dynamic_cast<StoreInst *>(pInst);
|
||||
std::cout << "store ";
|
||||
printType(storeInst->getValue()->getType());
|
||||
std::cout << " ";
|
||||
printValue(storeInst->getValue());
|
||||
std::cout << ", ";
|
||||
printType(storeInst->getPointer()->getType());
|
||||
std::cout << " ";
|
||||
printValue(storeInst->getPointer());
|
||||
|
||||
if (storeInst->getNumIndices() > 0) {
|
||||
std::cout << ", ";
|
||||
for (size_t i = 0; i < storeInst->getNumIndices(); i++) {
|
||||
if (i > 0) std::cout << ", ";
|
||||
printType(Type::getIntType());
|
||||
std::cout << " ";
|
||||
printValue(storeInst->getIndex(i));
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << ", align 4" << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kMemset: {
|
||||
auto memsetInst = dynamic_cast<MemsetInst *>(pInst);
|
||||
std::cout << "call void @llvm.memset.p0.";
|
||||
printType(memsetInst->getPointer()->getType());
|
||||
std::cout << "(";
|
||||
printType(memsetInst->getPointer()->getType());
|
||||
std::cout << " ";
|
||||
printValue(memsetInst->getPointer());
|
||||
std::cout << ", i8 ";
|
||||
printValue(memsetInst->getValue());
|
||||
std::cout << ", i32 ";
|
||||
printValue(memsetInst->getSize());
|
||||
std::cout << ", i1 false)" << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kPhi: {
|
||||
auto phiInst = dynamic_cast<PhiInst *>(pInst);
|
||||
printValue(phiInst->getOperand(0));
|
||||
std::cout << " = phi ";
|
||||
printType(phiInst->getType());
|
||||
|
||||
for (unsigned i = 1; i < phiInst->getNumOperands(); i++) {
|
||||
if (i > 0) std::cout << ", ";
|
||||
std::cout << "[ ";
|
||||
printValue(phiInst->getOperand(i));
|
||||
std::cout << " ]";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
case Kind::kGetSubArray: {
|
||||
auto getSubArrayInst = dynamic_cast<GetSubArrayInst *>(pInst);
|
||||
std::cout << "%" << getSubArrayInst->getName() << " = getelementptr inbounds ";
|
||||
|
||||
auto ptrType = dynamic_cast<PointerType*>(getSubArrayInst->getFatherArray()->getType());
|
||||
printType(ptrType->getBaseType());
|
||||
std::cout << ", ";
|
||||
printType(getSubArrayInst->getFatherArray()->getType());
|
||||
std::cout << " ";
|
||||
printValue(getSubArrayInst->getFatherArray());
|
||||
std::cout << ", ";
|
||||
bool firstIndex = true;
|
||||
for (auto &index : getSubArrayInst->getIndices()) {
|
||||
if (!firstIndex) std::cout << ", ";
|
||||
firstIndex = false;
|
||||
printType(Type::getIntType());
|
||||
std::cout << " ";
|
||||
printValue(index->getValue());
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
default:
|
||||
assert(false && "Unsupported instruction kind");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@ -1,27 +0,0 @@
|
||||
# src/backend/RISCv64/CMakeLists.txt
|
||||
add_library(riscv64_backend_lib STATIC
|
||||
RISCv64AsmPrinter.cpp
|
||||
RISCv64Backend.cpp
|
||||
RISCv64ISel.cpp
|
||||
RISCv64LLIR.cpp
|
||||
RISCv64RegAlloc.cpp
|
||||
RISCv64LinearScan.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 头文件路径 (已存在)
|
||||
)
|
||||
@ -1,51 +0,0 @@
|
||||
#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
|
||||
@ -1,235 +0,0 @@
|
||||
#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
|
||||
@ -1,171 +0,0 @@
|
||||
#include "LegalizeImmediates.h"
|
||||
#include "RISCv64ISel.h" // 需要包含它以调用 getNewVReg()
|
||||
#include "RISCv64AsmPrinter.h"
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
// 声明外部调试控制变量
|
||||
extern int DEBUG;
|
||||
extern int DEEPDEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
char LegalizeImmediatesPass::ID = 0;
|
||||
|
||||
// 辅助函数:检查一个立即数是否在RISC-V的12位有符号范围内
|
||||
static bool isLegalImmediate(int64_t imm) {
|
||||
return imm >= -2048 && imm <= 2047;
|
||||
}
|
||||
|
||||
void LegalizeImmediatesPass::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
if (DEBUG) {
|
||||
std::cerr << "===== Running Legalize Immediates Pass on function: " << mfunc->getName() << " =====\n";
|
||||
}
|
||||
|
||||
// 定义我们保留的、用于暂存的物理寄存器
|
||||
const PhysicalReg TEMP_REG = PhysicalReg::T5;
|
||||
|
||||
// 创建一个临时的AsmPrinter用于打印指令,方便调试
|
||||
RISCv64AsmPrinter temp_printer(mfunc);
|
||||
if (DEEPDEBUG) {
|
||||
temp_printer.setStream(std::cerr);
|
||||
}
|
||||
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
if (DEEPDEBUG) {
|
||||
std::cerr << "--- Processing Basic Block: " << mbb->getName() << " ---\n";
|
||||
}
|
||||
// 创建一个新的指令列表,用于存放合法化后的指令
|
||||
std::vector<std::unique_ptr<MachineInstr>> new_instructions;
|
||||
|
||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||
if (DEEPDEBUG) {
|
||||
std::cerr << " Checking: ";
|
||||
// 打印指令时末尾会带换行符,所以这里不用 std::endl
|
||||
temp_printer.printInstruction(instr_ptr.get(), true);
|
||||
}
|
||||
|
||||
bool legalized = false; // 标记当前指令是否已被展开处理
|
||||
|
||||
switch (instr_ptr->getOpcode()) {
|
||||
case RVOpcodes::ADDI:
|
||||
case RVOpcodes::ADDIW: {
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
// 确保操作数足够多,以防万一
|
||||
if (operands.size() < 3) break;
|
||||
auto imm_op = static_cast<ImmOperand*>(operands.back().get());
|
||||
|
||||
if (!isLegalImmediate(imm_op->getValue())) {
|
||||
if (DEEPDEBUG) {
|
||||
std::cerr << " >> ILLEGAL immediate (" << imm_op->getValue() << "). Expanding...\n";
|
||||
}
|
||||
// 立即数超出范围,需要展开
|
||||
auto rd_op = std::make_unique<RegOperand>(*static_cast<RegOperand*>(operands[0].get()));
|
||||
auto rs1_op = std::make_unique<RegOperand>(*static_cast<RegOperand*>(operands[1].get()));
|
||||
|
||||
// 1. li t5, immediate
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(TEMP_REG));
|
||||
li->addOperand(std::make_unique<ImmOperand>(imm_op->getValue()));
|
||||
|
||||
// 2. add/addw rd, rs1, t5
|
||||
auto new_op = (instr_ptr->getOpcode() == RVOpcodes::ADDI) ? RVOpcodes::ADD : RVOpcodes::ADDW;
|
||||
auto add = std::make_unique<MachineInstr>(new_op);
|
||||
add->addOperand(std::move(rd_op));
|
||||
add->addOperand(std::move(rs1_op));
|
||||
add->addOperand(std::make_unique<RegOperand>(TEMP_REG));
|
||||
|
||||
if (DEEPDEBUG) {
|
||||
std::cerr << " New sequence:\n ";
|
||||
temp_printer.printInstruction(li.get(), true);
|
||||
std::cerr << " ";
|
||||
temp_printer.printInstruction(add.get(), true);
|
||||
}
|
||||
|
||||
new_instructions.push_back(std::move(li));
|
||||
new_instructions.push_back(std::move(add));
|
||||
|
||||
legalized = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// 处理所有内存加载/存储指令
|
||||
case RVOpcodes::LB: case RVOpcodes::LH: case RVOpcodes::LW: case RVOpcodes::LD:
|
||||
case RVOpcodes::LBU: case RVOpcodes::LHU: case RVOpcodes::LWU:
|
||||
case RVOpcodes::SB: case RVOpcodes::SH: case RVOpcodes::SW: case RVOpcodes::SD:
|
||||
case RVOpcodes::FLW: case RVOpcodes::FSW: {
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
auto mem_op = static_cast<MemOperand*>(operands.back().get());
|
||||
auto offset_op = mem_op->getOffset();
|
||||
|
||||
if (!isLegalImmediate(offset_op->getValue())) {
|
||||
if (DEEPDEBUG) {
|
||||
std::cerr << " >> ILLEGAL immediate offset (" << offset_op->getValue() << "). Expanding...\n";
|
||||
}
|
||||
// 偏移量超出范围,需要展开
|
||||
auto data_reg_op = std::make_unique<RegOperand>(*static_cast<RegOperand*>(operands[0].get()));
|
||||
auto base_reg_op = std::make_unique<RegOperand>(*mem_op->getBase());
|
||||
|
||||
// 1. li t5, offset
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(TEMP_REG));
|
||||
li->addOperand(std::make_unique<ImmOperand>(offset_op->getValue()));
|
||||
|
||||
// 2. add t5, base_reg, t5 (计算最终地址,结果也放在t5)
|
||||
auto add = std::make_unique<MachineInstr>(RVOpcodes::ADD);
|
||||
add->addOperand(std::make_unique<RegOperand>(TEMP_REG));
|
||||
add->addOperand(std::move(base_reg_op));
|
||||
add->addOperand(std::make_unique<RegOperand>(TEMP_REG));
|
||||
|
||||
// 3. lw/sw data_reg, 0(t5)
|
||||
auto mem_instr = std::make_unique<MachineInstr>(instr_ptr->getOpcode());
|
||||
mem_instr->addOperand(std::move(data_reg_op));
|
||||
mem_instr->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(TEMP_REG),
|
||||
std::make_unique<ImmOperand>(0)
|
||||
));
|
||||
|
||||
if (DEEPDEBUG) {
|
||||
std::cerr << " New sequence:\n ";
|
||||
temp_printer.printInstruction(li.get(), true);
|
||||
std::cerr << " ";
|
||||
temp_printer.printInstruction(add.get(), true);
|
||||
std::cerr << " ";
|
||||
temp_printer.printInstruction(mem_instr.get(), true);
|
||||
}
|
||||
|
||||
new_instructions.push_back(std::move(li));
|
||||
new_instructions.push_back(std::move(add));
|
||||
new_instructions.push_back(std::move(mem_instr));
|
||||
|
||||
legalized = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// 其他指令不需要处理
|
||||
break;
|
||||
}
|
||||
|
||||
if (!legalized) {
|
||||
if (DEEPDEBUG) {
|
||||
std::cerr << " -- Immediate is legal. Skipping.\n";
|
||||
}
|
||||
// 如果当前指令不需要合法化,直接将其移动到新列表中
|
||||
new_instructions.push_back(std::move(instr_ptr));
|
||||
}
|
||||
}
|
||||
|
||||
// 用新的、已合法化的指令列表替换旧的列表
|
||||
mbb->getInstructions() = std::move(new_instructions);
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cerr << "===== Finished Legalize Immediates Pass =====\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@ -1,182 +0,0 @@
|
||||
#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
|
||||
@ -1,282 +0,0 @@
|
||||
#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,746 +0,0 @@
|
||||
#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
|
||||
return false;
|
||||
}
|
||||
|
||||
void PeepholeOptimizer::runOnMachineFunction(MachineFunction *mfunc) {
|
||||
if (!mfunc)
|
||||
return;
|
||||
using namespace sysy;
|
||||
|
||||
// areRegsEqual: 检查两个寄存器操作数是否相等(考虑虚拟和物理寄存器)。
|
||||
auto areRegsEqual = [](RegOperand *r1, RegOperand *r2) {
|
||||
if (!r1 || !r2 || r1->isVirtual() != r2->isVirtual()) {
|
||||
return false;
|
||||
}
|
||||
if (r1->isVirtual()) {
|
||||
return r1->getVRegNum() == r2->getVRegNum();
|
||||
} else {
|
||||
return r1->getPReg() == r2->getPReg();
|
||||
}
|
||||
};
|
||||
|
||||
// 改进的 isRegUsedLater 函数 - 更完整和准确的实现
|
||||
auto isRegUsedLater =
|
||||
[&](const std::vector<std::unique_ptr<MachineInstr>> &instrs,
|
||||
RegOperand *reg, size_t start_idx) -> bool {
|
||||
for (size_t j = start_idx; j < instrs.size(); ++j) {
|
||||
auto *instr = instrs[j].get();
|
||||
auto opcode = instr->getOpcode();
|
||||
|
||||
// 检查所有操作数
|
||||
for (size_t k = 0; k < instr->getOperands().size(); ++k) {
|
||||
bool isDefOperand = false;
|
||||
|
||||
// 更完整的定义操作数判断逻辑
|
||||
if (k == 0) { // 第一个操作数通常是目标寄存器
|
||||
switch (opcode) {
|
||||
// 算术和逻辑指令 - 第一个操作数是定义
|
||||
case RVOpcodes::MV:
|
||||
case RVOpcodes::ADDI:
|
||||
case RVOpcodes::SLLI:
|
||||
case RVOpcodes::SRLI:
|
||||
case RVOpcodes::SRAI:
|
||||
case RVOpcodes::SLTI:
|
||||
case RVOpcodes::SLTIU:
|
||||
case RVOpcodes::XORI:
|
||||
case RVOpcodes::ORI:
|
||||
case RVOpcodes::ANDI:
|
||||
case RVOpcodes::ADD:
|
||||
case RVOpcodes::SUB:
|
||||
case RVOpcodes::SLL:
|
||||
case RVOpcodes::SLT:
|
||||
case RVOpcodes::SLTU:
|
||||
case RVOpcodes::XOR:
|
||||
case RVOpcodes::SRL:
|
||||
case RVOpcodes::SRA:
|
||||
case RVOpcodes::OR:
|
||||
case RVOpcodes::AND:
|
||||
case RVOpcodes::MUL:
|
||||
case RVOpcodes::DIV:
|
||||
case RVOpcodes::REM:
|
||||
case RVOpcodes::LW:
|
||||
case RVOpcodes::LH:
|
||||
case RVOpcodes::LB:
|
||||
case RVOpcodes::LHU:
|
||||
case RVOpcodes::LBU:
|
||||
|
||||
// 存储指令 - 第一个操作数是使用(要存储的值)
|
||||
case RVOpcodes::SW:
|
||||
case RVOpcodes::SH:
|
||||
case RVOpcodes::SB:
|
||||
// 分支指令 - 第一个操作数是使用
|
||||
case RVOpcodes::BEQ:
|
||||
case RVOpcodes::BNE:
|
||||
case RVOpcodes::BLT:
|
||||
case RVOpcodes::BGE:
|
||||
case RVOpcodes::BLTU:
|
||||
case RVOpcodes::BGEU:
|
||||
// 跳转指令 - 可能使用寄存器
|
||||
case RVOpcodes::JALR:
|
||||
isDefOperand = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
// 对于未知指令,保守地假设第一个操作数可能是使用
|
||||
isDefOperand = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果不是定义操作数,检查是否使用了目标寄存器
|
||||
if (!isDefOperand) {
|
||||
if (instr->getOperands()[k]->getKind() == MachineOperand::KIND_REG) {
|
||||
auto *use_reg =
|
||||
static_cast<RegOperand *>(instr->getOperands()[k].get());
|
||||
if (areRegsEqual(reg, use_reg))
|
||||
return true;
|
||||
}
|
||||
// 检查内存操作数中的基址寄存器
|
||||
if (instr->getOperands()[k]->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto *mem =
|
||||
static_cast<MemOperand *>(instr->getOperands()[k].get());
|
||||
if (areRegsEqual(reg, mem->getBase()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// 检查寄存器是否在指令中被重新定义(用于更精确的分析)
|
||||
auto isRegRedefinedAt =
|
||||
[](MachineInstr *instr, RegOperand *reg,
|
||||
const std::function<bool(RegOperand *, RegOperand *)> &areRegsEqual)
|
||||
-> bool {
|
||||
if (instr->getOperands().empty())
|
||||
return false;
|
||||
|
||||
auto opcode = instr->getOpcode();
|
||||
// 只有当第一个操作数是定义操作数时才检查
|
||||
switch (opcode) {
|
||||
case RVOpcodes::MV:
|
||||
case RVOpcodes::ADDI:
|
||||
case RVOpcodes::ADD:
|
||||
case RVOpcodes::SUB:
|
||||
case RVOpcodes::MUL:
|
||||
case RVOpcodes::LW:
|
||||
// ... 其他定义指令
|
||||
if (instr->getOperands()[0]->getKind() == MachineOperand::KIND_REG) {
|
||||
auto *def_reg =
|
||||
static_cast<RegOperand *>(instr->getOperands()[0].get());
|
||||
return areRegsEqual(reg, def_reg);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// 检查是否为存储-加载模式,支持不同大小的访问
|
||||
auto isStoreLoadPattern = [](MachineInstr *store_instr,
|
||||
MachineInstr *load_instr) -> bool {
|
||||
auto store_op = store_instr->getOpcode();
|
||||
auto load_op = load_instr->getOpcode();
|
||||
|
||||
// 检查存储-加载对应关系
|
||||
return (store_op == RVOpcodes::SW && load_op == RVOpcodes::LW) || // 32位
|
||||
(store_op == RVOpcodes::SH &&
|
||||
load_op == RVOpcodes::LH) || // 16位有符号
|
||||
(store_op == RVOpcodes::SH &&
|
||||
load_op == RVOpcodes::LHU) || // 16位无符号
|
||||
(store_op == RVOpcodes::SB &&
|
||||
load_op == RVOpcodes::LB) || // 8位有符号
|
||||
(store_op == RVOpcodes::SB &&
|
||||
load_op == RVOpcodes::LBU) || // 8位无符号
|
||||
(store_op == RVOpcodes::SD && load_op == RVOpcodes::LD); // 64位
|
||||
};
|
||||
|
||||
// 检查两个内存访问是否访问相同的内存位置
|
||||
auto areMemoryAccessesEqual =
|
||||
[&areRegsEqual](MachineInstr *store_instr, MemOperand *store_mem,
|
||||
MachineInstr *load_instr, MemOperand *load_mem) -> bool {
|
||||
// 基址寄存器必须相同
|
||||
if (!areRegsEqual(store_mem->getBase(), load_mem->getBase())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 偏移量必须相同
|
||||
if (store_mem->getOffset()->getValue() !=
|
||||
load_mem->getOffset()->getValue()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查访问大小是否兼容
|
||||
auto store_op = store_instr->getOpcode();
|
||||
auto load_op = load_instr->getOpcode();
|
||||
|
||||
// 获取访问大小(字节数)
|
||||
auto getAccessSize = [](RVOpcodes opcode) -> int {
|
||||
switch (opcode) {
|
||||
case RVOpcodes::LB:
|
||||
case RVOpcodes::LBU:
|
||||
case RVOpcodes::SB:
|
||||
return 1; // 8位
|
||||
case RVOpcodes::LH:
|
||||
case RVOpcodes::LHU:
|
||||
case RVOpcodes::SH:
|
||||
return 2; // 16位
|
||||
case RVOpcodes::LW:
|
||||
case RVOpcodes::SW:
|
||||
return 4; // 32位
|
||||
case RVOpcodes::LD:
|
||||
case RVOpcodes::SD:
|
||||
return 8; // 64位
|
||||
default:
|
||||
return -1; // 未知
|
||||
}
|
||||
};
|
||||
|
||||
int store_size = getAccessSize(store_op);
|
||||
int load_size = getAccessSize(load_op);
|
||||
|
||||
// 只有访问大小完全匹配时才能进行优化
|
||||
// 这避免了部分重叠访问的复杂情况
|
||||
return store_size > 0 && store_size == load_size;
|
||||
};
|
||||
|
||||
// 简单的内存别名分析:检查两个内存访问之间是否可能有冲突的内存操作
|
||||
auto isMemoryAccessSafe =
|
||||
[&](const std::vector<std::unique_ptr<MachineInstr>> &instrs,
|
||||
size_t store_idx, size_t load_idx, MemOperand *mem) -> bool {
|
||||
// 检查存储和加载之间是否有可能影响内存的指令
|
||||
for (size_t j = store_idx + 1; j < load_idx; ++j) {
|
||||
auto *between_instr = instrs[j].get();
|
||||
auto between_op = between_instr->getOpcode();
|
||||
|
||||
// 检查是否有其他内存写入操作
|
||||
switch (between_op) {
|
||||
case RVOpcodes::SW:
|
||||
case RVOpcodes::SH:
|
||||
case RVOpcodes::SB:
|
||||
case RVOpcodes::SD: {
|
||||
// 如果有其他存储操作,需要检查是否可能访问相同的内存
|
||||
if (between_instr->getOperands().size() >= 2 &&
|
||||
between_instr->getOperands()[1]->getKind() ==
|
||||
MachineOperand::KIND_MEM) {
|
||||
|
||||
auto *other_mem =
|
||||
static_cast<MemOperand *>(between_instr->getOperands()[1].get());
|
||||
|
||||
// 保守的别名分析:如果使用不同的基址寄存器,假设可能别名
|
||||
if (!areRegsEqual(mem->getBase(), other_mem->getBase())) {
|
||||
return false; // 可能的别名,不安全
|
||||
}
|
||||
|
||||
// 如果基址相同但偏移量不同,检查是否重叠
|
||||
int64_t offset1 = mem->getOffset()->getValue();
|
||||
int64_t offset2 = other_mem->getOffset()->getValue();
|
||||
|
||||
// 获取访问大小来检查重叠
|
||||
auto getAccessSize = [](RVOpcodes opcode) -> int {
|
||||
switch (opcode) {
|
||||
case RVOpcodes::SB:
|
||||
return 1;
|
||||
case RVOpcodes::SH:
|
||||
return 2;
|
||||
case RVOpcodes::SW:
|
||||
return 4;
|
||||
case RVOpcodes::SD:
|
||||
return 8;
|
||||
default:
|
||||
return 4; // 默认假设4字节
|
||||
}
|
||||
};
|
||||
|
||||
int size1 = getAccessSize(RVOpcodes::SW); // 从原存储指令推断
|
||||
int size2 = getAccessSize(between_op);
|
||||
|
||||
// 检查内存区域是否重叠
|
||||
bool overlaps =
|
||||
!(offset1 + size1 <= offset2 || offset2 + size2 <= offset1);
|
||||
if (overlaps) {
|
||||
return false; // 内存重叠,不安全
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// 函数调用可能有副作用
|
||||
case RVOpcodes::JAL:
|
||||
case RVOpcodes::JALR:
|
||||
return false; // 函数调用可能修改内存,不安全
|
||||
|
||||
// 原子操作或其他可能修改内存的指令
|
||||
// 根据具体的RISC-V扩展添加更多指令
|
||||
default:
|
||||
// 对于未知指令,采用保守策略
|
||||
// 可以根据具体需求调整
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true; // 没有发现潜在的内存冲突
|
||||
};
|
||||
|
||||
// isPowerOfTwo: 检查数值是否为2的幂次,并返回其指数。
|
||||
auto isPowerOfTwo = [](int64_t n) -> int {
|
||||
if (n <= 0 || (n & (n - 1)) != 0)
|
||||
return -1;
|
||||
int shift = 0;
|
||||
while (n > 1) {
|
||||
n >>= 1;
|
||||
shift++;
|
||||
}
|
||||
return shift;
|
||||
};
|
||||
|
||||
for (auto &mbb_uptr : mfunc->getBlocks()) {
|
||||
auto &mbb = *mbb_uptr;
|
||||
auto &instrs = mbb.getInstructions();
|
||||
if (instrs.size() < 2)
|
||||
continue; // 基本块至少需要两条指令进行窥孔
|
||||
|
||||
// 遍历指令序列进行窥孔优化
|
||||
for (size_t i = 0; i + 1 < instrs.size();) {
|
||||
auto *mi1 = instrs[i].get();
|
||||
auto *mi2 = instrs[i + 1].get();
|
||||
bool changed = false;
|
||||
|
||||
// 1. 消除冗余交换移动: mv a, b; mv b, a -> mv a, b
|
||||
if (mi1->getOpcode() == RVOpcodes::MV &&
|
||||
mi2->getOpcode() == RVOpcodes::MV) {
|
||||
if (mi1->getOperands().size() == 2 && mi2->getOperands().size() == 2) {
|
||||
if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
|
||||
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG &&
|
||||
mi2->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
|
||||
mi2->getOperands()[1]->getKind() == MachineOperand::KIND_REG) {
|
||||
auto *dst1 = static_cast<RegOperand *>(mi1->getOperands()[0].get());
|
||||
auto *src1 = static_cast<RegOperand *>(mi1->getOperands()[1].get());
|
||||
auto *dst2 = static_cast<RegOperand *>(mi2->getOperands()[0].get());
|
||||
auto *src2 = static_cast<RegOperand *>(mi2->getOperands()[1].get());
|
||||
if (areRegsEqual(dst1, src2) && areRegsEqual(src1, dst2)) {
|
||||
instrs.erase(instrs.begin() + i + 1); // 移除第二条指令
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 2. 冗余加载消除: sw t0, offset(base); lw t1, offset(base) -> 替换或消除
|
||||
// lw 添加ld sd支持
|
||||
else if (isStoreLoadPattern(mi1, mi2)) {
|
||||
if (mi1->getOperands().size() == 2 && mi2->getOperands().size() == 2) {
|
||||
if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
|
||||
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_MEM &&
|
||||
mi2->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
|
||||
mi2->getOperands()[1]->getKind() == MachineOperand::KIND_MEM) {
|
||||
|
||||
auto *store_val =
|
||||
static_cast<RegOperand *>(mi1->getOperands()[0].get());
|
||||
auto *store_mem =
|
||||
static_cast<MemOperand *>(mi1->getOperands()[1].get());
|
||||
auto *load_val =
|
||||
static_cast<RegOperand *>(mi2->getOperands()[0].get());
|
||||
auto *load_mem =
|
||||
static_cast<MemOperand *>(mi2->getOperands()[1].get());
|
||||
|
||||
// 检查内存访问是否匹配(基址、偏移量和访问大小)
|
||||
if (areMemoryAccessesEqual(mi1, store_mem, mi2, load_mem)) {
|
||||
// 进行简单的内存别名分析
|
||||
if (isMemoryAccessSafe(instrs, i, i + 1, store_mem)) {
|
||||
if (areRegsEqual(store_val, load_val)) {
|
||||
// sw r1, mem; lw r1, mem -> 消除冗余的lw
|
||||
instrs.erase(instrs.begin() + i + 1);
|
||||
changed = true;
|
||||
} else {
|
||||
// sw r1, mem; lw r2, mem -> 替换lw为mv r2, r1
|
||||
auto newInstr = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*load_val));
|
||||
newInstr->addOperand(
|
||||
std::make_unique<RegOperand>(*store_val));
|
||||
instrs[i + 1] = std::move(newInstr);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 3. 强度削减: mul y, x, 2^n -> slli y, x, n
|
||||
else if (mi1->getOpcode() == RVOpcodes::MUL &&
|
||||
mi1->getOperands().size() == 3) {
|
||||
auto *dst_op = mi1->getOperands()[0].get();
|
||||
auto *src1_op = mi1->getOperands()[1].get();
|
||||
auto *src2_op = mi1->getOperands()[2].get();
|
||||
|
||||
if (dst_op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto *dst_reg = static_cast<RegOperand *>(dst_op);
|
||||
RegOperand *src_reg = nullptr;
|
||||
int shift = -1;
|
||||
|
||||
if (src1_op->getKind() == MachineOperand::KIND_REG &&
|
||||
src2_op->getKind() == MachineOperand::KIND_IMM) {
|
||||
shift =
|
||||
isPowerOfTwo(static_cast<ImmOperand *>(src2_op)->getValue());
|
||||
if (shift >= 0)
|
||||
src_reg = static_cast<RegOperand *>(src1_op);
|
||||
} else if (src1_op->getKind() == MachineOperand::KIND_IMM &&
|
||||
src2_op->getKind() == MachineOperand::KIND_REG) {
|
||||
shift =
|
||||
isPowerOfTwo(static_cast<ImmOperand *>(src1_op)->getValue());
|
||||
if (shift >= 0)
|
||||
src_reg = static_cast<RegOperand *>(src2_op);
|
||||
}
|
||||
|
||||
if (src_reg && shift >= 0 &&
|
||||
shift <= 31) { // RISC-V 移位量限制 (0-31)
|
||||
auto newInstr = std::make_unique<MachineInstr>(RVOpcodes::SLLI);
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*src_reg));
|
||||
newInstr->addOperand(std::make_unique<ImmOperand>(shift));
|
||||
instrs[i] = std::move(newInstr);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 4. 地址计算优化: addi dst, base, imm1; lw/sw val, imm2(dst) -> lw/sw
|
||||
// val, (imm1+imm2)(base)
|
||||
else if (mi1->getOpcode() == RVOpcodes::ADDI &&
|
||||
mi1->getOperands().size() == 3) {
|
||||
auto opcode2 = mi2->getOpcode();
|
||||
if (opcode2 == RVOpcodes::LW || opcode2 == RVOpcodes::SW) {
|
||||
if (mi2->getOperands().size() == 2 &&
|
||||
mi2->getOperands()[1]->getKind() == MachineOperand::KIND_MEM &&
|
||||
mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
|
||||
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG &&
|
||||
mi1->getOperands()[2]->getKind() == MachineOperand::KIND_IMM) {
|
||||
|
||||
auto *addi_dst =
|
||||
static_cast<RegOperand *>(mi1->getOperands()[0].get());
|
||||
auto *addi_base =
|
||||
static_cast<RegOperand *>(mi1->getOperands()[1].get());
|
||||
auto *addi_imm =
|
||||
static_cast<ImmOperand *>(mi1->getOperands()[2].get());
|
||||
|
||||
auto *mem_op =
|
||||
static_cast<MemOperand *>(mi2->getOperands()[1].get());
|
||||
auto *mem_base = mem_op->getBase();
|
||||
auto *mem_imm = mem_op->getOffset();
|
||||
|
||||
// 检查 ADDI 的目标寄存器是否是内存操作的基址
|
||||
if (areRegsEqual(addi_dst, mem_base)) {
|
||||
// 改进的使用检查:考虑寄存器可能在后续被重新定义的情况
|
||||
bool canOptimize = true;
|
||||
|
||||
// 检查从 i+2 开始的指令
|
||||
for (size_t j = i + 2; j < instrs.size(); ++j) {
|
||||
auto *later_instr = instrs[j].get();
|
||||
|
||||
// 如果寄存器被重新定义,那么它后面的使用就不相关了
|
||||
if (isRegRedefinedAt(later_instr, addi_dst, areRegsEqual)) {
|
||||
break; // 寄存器被重新定义,可以安全优化
|
||||
}
|
||||
|
||||
// 如果寄存器被使用,则不能优化
|
||||
if (isRegUsedLater(instrs, addi_dst, j)) {
|
||||
canOptimize = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (canOptimize) {
|
||||
int64_t new_offset = addi_imm->getValue() + mem_imm->getValue();
|
||||
// 检查新偏移量是否符合 RISC-V 12位有符号立即数范围
|
||||
if (new_offset >= -2048 && new_offset <= 2047) {
|
||||
auto new_mem_op = std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(*addi_base),
|
||||
std::make_unique<ImmOperand>(new_offset));
|
||||
mi2->getOperands()[1] = std::move(new_mem_op);
|
||||
instrs.erase(instrs.begin() + i);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 5. 冗余移动指令消除: mv x, y; op z, x, ... -> op z, y, ... (如果 x
|
||||
// 之后不再使用)
|
||||
else if (mi1->getOpcode() == RVOpcodes::MV &&
|
||||
mi1->getOperands().size() == 2) {
|
||||
if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
|
||||
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG) {
|
||||
|
||||
auto *mv_dst = static_cast<RegOperand *>(mi1->getOperands()[0].get());
|
||||
auto *mv_src = static_cast<RegOperand *>(mi1->getOperands()[1].get());
|
||||
|
||||
// 检查第二条指令是否使用了 mv 的目标寄存器
|
||||
std::vector<size_t> use_positions;
|
||||
for (size_t k = 1; k < mi2->getOperands().size(); ++k) {
|
||||
if (mi2->getOperands()[k]->getKind() == MachineOperand::KIND_REG) {
|
||||
auto *use_reg =
|
||||
static_cast<RegOperand *>(mi2->getOperands()[k].get());
|
||||
if (areRegsEqual(mv_dst, use_reg)) {
|
||||
use_positions.push_back(k);
|
||||
}
|
||||
}
|
||||
// 也检查内存操作数中的基址寄存器
|
||||
else if (mi2->getOperands()[k]->getKind() ==
|
||||
MachineOperand::KIND_MEM) {
|
||||
auto *mem =
|
||||
static_cast<MemOperand *>(mi2->getOperands()[k].get());
|
||||
if (areRegsEqual(mv_dst, mem->getBase())) {
|
||||
// 对于内存操作数,我们需要创建新的MemOperand
|
||||
auto new_mem = std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(*mv_src),
|
||||
std::make_unique<ImmOperand>(mem->getOffset()->getValue()));
|
||||
mi2->getOperands()[k] = std::move(new_mem);
|
||||
use_positions.push_back(k); // 标记已处理
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!use_positions.empty()) {
|
||||
// 改进的后续使用检查
|
||||
bool canOptimize = true;
|
||||
for (size_t j = i + 2; j < instrs.size(); ++j) {
|
||||
auto *later_instr = instrs[j].get();
|
||||
|
||||
// 如果寄存器被重新定义,后续使用就不相关了
|
||||
if (isRegRedefinedAt(later_instr, mv_dst, areRegsEqual)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 检查是否还有其他使用
|
||||
if (isRegUsedLater(instrs, mv_dst, j)) {
|
||||
canOptimize = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (canOptimize) {
|
||||
// 替换所有寄存器使用(内存操作数已在上面处理)
|
||||
for (size_t pos : use_positions) {
|
||||
if (mi2->getOperands()[pos]->getKind() ==
|
||||
MachineOperand::KIND_REG) {
|
||||
mi2->getOperands()[pos] =
|
||||
std::make_unique<RegOperand>(*mv_src);
|
||||
}
|
||||
}
|
||||
instrs.erase(instrs.begin() + i);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 6. 连续加法指令合并: addi t1, t0, imm1; addi t2, t1, imm2 -> addi t2,
|
||||
// t0, (imm1+imm2)
|
||||
else if (mi1->getOpcode() == RVOpcodes::ADDI &&
|
||||
mi2->getOpcode() == RVOpcodes::ADDI) {
|
||||
if (mi1->getOperands().size() == 3 && mi2->getOperands().size() == 3) {
|
||||
if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
|
||||
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG &&
|
||||
mi1->getOperands()[2]->getKind() == MachineOperand::KIND_IMM &&
|
||||
mi2->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
|
||||
mi2->getOperands()[1]->getKind() == MachineOperand::KIND_REG &&
|
||||
mi2->getOperands()[2]->getKind() == MachineOperand::KIND_IMM) {
|
||||
|
||||
auto *addi1_dst =
|
||||
static_cast<RegOperand *>(mi1->getOperands()[0].get());
|
||||
auto *addi1_src =
|
||||
static_cast<RegOperand *>(mi1->getOperands()[1].get());
|
||||
auto *addi1_imm =
|
||||
static_cast<ImmOperand *>(mi1->getOperands()[2].get());
|
||||
|
||||
auto *addi2_dst =
|
||||
static_cast<RegOperand *>(mi2->getOperands()[0].get());
|
||||
auto *addi2_src =
|
||||
static_cast<RegOperand *>(mi2->getOperands()[1].get());
|
||||
auto *addi2_imm =
|
||||
static_cast<ImmOperand *>(mi2->getOperands()[2].get());
|
||||
|
||||
// 检查第一个ADDI的目标是否是第二个ADDI的源
|
||||
if (areRegsEqual(addi1_dst, addi2_src)) {
|
||||
// 改进的中间寄存器使用检查
|
||||
bool canOptimize = true;
|
||||
for (size_t j = i + 2; j < instrs.size(); ++j) {
|
||||
auto *later_instr = instrs[j].get();
|
||||
|
||||
// 如果中间寄存器被重新定义,后续使用不相关
|
||||
if (isRegRedefinedAt(later_instr, addi1_dst, areRegsEqual)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 检查是否有其他使用
|
||||
if (isRegUsedLater(instrs, addi1_dst, j)) {
|
||||
canOptimize = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (canOptimize) {
|
||||
int64_t new_imm = addi1_imm->getValue() + addi2_imm->getValue();
|
||||
// 检查新立即数范围
|
||||
if (new_imm >= -2048 && new_imm <= 2047) {
|
||||
auto newInstr =
|
||||
std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
newInstr->addOperand(
|
||||
std::make_unique<RegOperand>(*addi2_dst));
|
||||
newInstr->addOperand(
|
||||
std::make_unique<RegOperand>(*addi1_src));
|
||||
newInstr->addOperand(std::make_unique<ImmOperand>(new_imm));
|
||||
instrs[i + 1] = std::move(newInstr);
|
||||
instrs.erase(instrs.begin() + i);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 7. ADD with zero optimization: add r1, r2, zero -> mv r1, r2
|
||||
else if (mi1->getOpcode() == RVOpcodes::ADD &&
|
||||
mi1->getOperands().size() == 3) {
|
||||
if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
|
||||
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG &&
|
||||
mi1->getOperands()[2]->getKind() == MachineOperand::KIND_REG) {
|
||||
|
||||
auto *add_dst =
|
||||
static_cast<RegOperand *>(mi1->getOperands()[0].get());
|
||||
auto *add_src1 =
|
||||
static_cast<RegOperand *>(mi1->getOperands()[1].get());
|
||||
auto *add_src2 =
|
||||
static_cast<RegOperand *>(mi1->getOperands()[2].get());
|
||||
|
||||
// 检查第二个源操作数是否为ZERO寄存器
|
||||
if (!add_src2->isVirtual() &&
|
||||
add_src2->getPReg() == PhysicalReg::ZERO) {
|
||||
// 创建新的 MV 指令
|
||||
auto newInstr = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*add_dst));
|
||||
newInstr->addOperand(std::make_unique<RegOperand>(*add_src1));
|
||||
instrs[i] = std::move(newInstr);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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) {
|
||||
++i; // 没有优化,继续检查下一对指令
|
||||
} else {
|
||||
// 发生变化,适当回退以捕获新的优化机会。
|
||||
// 这是一种安全的回退策略,可以触发连锁优化,且不会导致无限循环。
|
||||
if (i > 0) {
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@ -1,416 +0,0 @@
|
||||
#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
|
||||
@ -1,466 +0,0 @@
|
||||
#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,340 +0,0 @@
|
||||
#include "RISCv64Backend.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include "RISCv64RegAlloc.h"
|
||||
#include "RISCv64LinearScan.h"
|
||||
#include "RISCv64BasicBlockAlloc.h"
|
||||
#include "RISCv64AsmPrinter.h"
|
||||
#include "RISCv64Passes.h"
|
||||
#include <sstream>
|
||||
#include <future>
|
||||
#include <chrono>
|
||||
#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);
|
||||
|
||||
if (DEBUG) {
|
||||
std::cerr << "====== Intermediate Representation after Instruction Selection ======\n"
|
||||
<< ss_after_isel.str();
|
||||
}
|
||||
|
||||
// 阶段 2: 消除帧索引 (展开伪指令,计算局部变量偏移)
|
||||
// 这个Pass必须在寄存器分配之前运行
|
||||
EliminateFrameIndicesPass efi_pass;
|
||||
efi_pass.runOnMachineFunction(mfunc.get());
|
||||
|
||||
if (DEBUG) {
|
||||
std::cerr << "====== stack info after eliminate frame indices ======\n";
|
||||
mfunc->dumpStackFrameInfo(std::cerr);
|
||||
std::stringstream ss_after_eli;
|
||||
printer_isel.run(ss_after_eli, true);
|
||||
std::cerr << "====== LLIR after eliminate frame indices ======\n"
|
||||
<< ss_after_eli.str();
|
||||
}
|
||||
|
||||
// // 阶段 2: 除法强度削弱优化 (Division Strength Reduction)
|
||||
// DivStrengthReduction div_strength_reduction;
|
||||
// div_strength_reduction.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// // 阶段 2.1: 指令调度 (Instruction Scheduling)
|
||||
// PreRA_Scheduler scheduler;
|
||||
// scheduler.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 3: 物理寄存器分配 (Register Allocation)
|
||||
|
||||
// 首先尝试图着色分配器
|
||||
if (DEBUG) std::cerr << "Attempting Register Allocation with Graph Coloring...\n";
|
||||
if (!gc_failed) {
|
||||
RISCv64RegAlloc gc_alloc(mfunc.get());
|
||||
|
||||
bool success_gc = gc_alloc.run();
|
||||
|
||||
if (!success_gc) {
|
||||
gc_failed = 1; // 后续不再尝试图着色分配器
|
||||
std::cerr << "Warning: Graph coloring register allocation failed function '"
|
||||
<< func->getName()
|
||||
<< "'. Switching to Linear Scan allocator."
|
||||
<< std::endl;
|
||||
|
||||
RISCv64ISel isel_gc_fallback;
|
||||
mfunc = isel_gc_fallback.runOnFunction(func);
|
||||
EliminateFrameIndicesPass efi_pass_gc_fallback;
|
||||
efi_pass_gc_fallback.runOnMachineFunction(mfunc.get());
|
||||
RISCv64LinearScan ls_alloc(mfunc.get());
|
||||
bool success = ls_alloc.run();
|
||||
if (!success) {
|
||||
// 如果线性扫描最终失败,则调用基本块分配器作为终极后备
|
||||
std::cerr << "Info: Linear Scan failed. Switching to Basic Block Allocator as final fallback.\n";
|
||||
|
||||
// 注意:我们需要在一个“干净”的MachineFunction上运行。
|
||||
// 最安全的方式是重新运行指令选择。
|
||||
RISCv64ISel isel_fallback;
|
||||
mfunc = isel_fallback.runOnFunction(func);
|
||||
EliminateFrameIndicesPass efi_pass_fallback;
|
||||
efi_pass_fallback.runOnMachineFunction(mfunc.get());
|
||||
if (DEBUG) {
|
||||
std::cerr << "====== stack info after reg alloc ======\n";
|
||||
}
|
||||
RISCv64BasicBlockAlloc bb_alloc(mfunc.get());
|
||||
bb_alloc.run();
|
||||
}
|
||||
} else {
|
||||
// 图着色成功完成
|
||||
if (DEBUG) std::cerr << "Graph Coloring allocation completed successfully.\n";
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Info: Graph Coloring allocation failed in last function. Switching to Linear Scan allocator...\n";
|
||||
RISCv64LinearScan ls_alloc(mfunc.get());
|
||||
bool success = ls_alloc.run();
|
||||
if (!success) {
|
||||
// 如果线性扫描最终失败,则调用基本块分配器作为终极后备
|
||||
std::cerr << "Info: Linear Scan failed. Switching to Basic Block Allocator as final fallback.\n";
|
||||
|
||||
// 注意:我们需要在一个“干净”的MachineFunction上运行。
|
||||
// 最安全的方式是重新运行指令选择。
|
||||
RISCv64ISel isel_fallback;
|
||||
mfunc = isel_fallback.runOnFunction(func);
|
||||
EliminateFrameIndicesPass efi_pass_fallback;
|
||||
efi_pass_fallback.runOnMachineFunction(mfunc.get());
|
||||
if (DEBUG) {
|
||||
std::cerr << "====== stack info after reg alloc ======\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
|
||||
@ -1,267 +0,0 @@
|
||||
#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
@ -1,195 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,694 +0,0 @@
|
||||
#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
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,17 +0,0 @@
|
||||
# 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)
|
||||
59
src/include/AddressCalculationExpansion.h
Normal file
59
src/include/AddressCalculationExpansion.h
Normal file
@ -0,0 +1,59 @@
|
||||
#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
|
||||
39
src/include/DeadCodeElimination.h
Normal file
39
src/include/DeadCodeElimination.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "IR.h"
|
||||
#include "SysYIRAnalyser.h"
|
||||
#include "SysYIRPrinter.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
class DeadCodeElimination {
|
||||
private:
|
||||
Module *pModule;
|
||||
ControlFlowAnalysis *pCFA; // 控制流分析指针
|
||||
ActiveVarAnalysis *pAVA; // 活跃变量分析指针
|
||||
DataFlowAnalysisUtils dataFlowAnalysisUtils; // 数据流分析工具类
|
||||
|
||||
public:
|
||||
explicit DeadCodeElimination(Module *pMoudle,
|
||||
ControlFlowAnalysis *pCFA = nullptr,
|
||||
ActiveVarAnalysis *pAVA = nullptr)
|
||||
: pModule(pMoudle), pCFA(pCFA), pAVA(pAVA), dataFlowAnalysisUtils() {} // 构造函数
|
||||
|
||||
// TODO:根据参数传入的passes来运行不同的死代码删除流程
|
||||
// void runDCEPipeline(const std::vector<std::string>& passes = {
|
||||
// "dead-store", "redundant-load-store", "dead-load", "dead-alloca", "dead-global"
|
||||
// });
|
||||
void runDCEPipeline(); // 运行死代码删除
|
||||
|
||||
void eliminateDeadStores(Function* func, bool& changed); // 消除无用存储
|
||||
void eliminateDeadLoads(Function* func, bool& changed); // 消除无用加载
|
||||
void eliminateDeadAllocas(Function* func, bool& changed); // 消除无用内存分配
|
||||
void eliminateDeadGlobals(bool& changed); // 消除无用全局变量
|
||||
void eliminateDeadIndirectiveAllocas(Function* func, bool& changed); // 消除无用间接内存分配(phi节点)
|
||||
void eliminateDeadRedundantLoadStore(Function* func, bool& changed); // 消除冗余加载和存储
|
||||
bool isGlobal(Value *val);
|
||||
bool isArr(Value *val);
|
||||
void usedelete(Instruction *instr);
|
||||
|
||||
};
|
||||
} // namespace sysy
|
||||
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,18 +217,6 @@ 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()) {
|
||||
@ -251,30 +239,31 @@ class IRBuilder {
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建return指令
|
||||
UncondBrInst * createUncondBrInst(BasicBlock *thenBlock) {
|
||||
auto inst = new UncondBrInst(thenBlock, block);
|
||||
UncondBrInst * createUncondBrInst(BasicBlock *thenBlock, const std::vector<Value *> &args) {
|
||||
auto inst = new UncondBrInst(thenBlock, args, block);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建无条件指令
|
||||
CondBrInst * createCondBrInst(Value *condition, BasicBlock *thenBlock, BasicBlock *elseBlock) {
|
||||
auto inst = new CondBrInst(condition, thenBlock, elseBlock, block);
|
||||
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);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建条件跳转指令
|
||||
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);
|
||||
AllocaInst * createAllocaInst(Type *type, const std::vector<Value *> &dims = {}, const std::string &name = "") {
|
||||
auto inst = new AllocaInst(type, dims, 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()) {
|
||||
@ -286,104 +275,71 @@ class IRBuilder {
|
||||
newName = name;
|
||||
}
|
||||
|
||||
auto inst = new LoadInst(pointer, block, newName);
|
||||
auto inst = new LoadInst(pointer, indices, block, newName);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建load指令
|
||||
LaInst * createLaInst(Value *pointer, const std::vector<Value *> &indices = {}, const std::string &name = "") {
|
||||
std::string newName;
|
||||
if (name.empty()) {
|
||||
std::stringstream ss;
|
||||
ss << tmpIndex;
|
||||
newName = ss.str();
|
||||
tmpIndex++;
|
||||
} else {
|
||||
newName = name;
|
||||
}
|
||||
|
||||
auto inst = new LaInst(pointer, indices, block, newName);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建la指令
|
||||
GetSubArrayInst * createGetSubArray(LVal *fatherArray, const std::vector<Value *> &indices, const std::string &name = "") {
|
||||
assert(fatherArray->getLValNumDims() > indices.size());
|
||||
std::vector<Value *> subDims;
|
||||
auto dims = fatherArray->getLValDims();
|
||||
auto iter = std::next(dims.begin(), indices.size());
|
||||
while (iter != dims.end()) {
|
||||
subDims.emplace_back(*iter);
|
||||
iter++;
|
||||
}
|
||||
|
||||
std::string childArrayName;
|
||||
std::stringstream ss;
|
||||
ss << "A"
|
||||
<< "%" << tmpIndex;
|
||||
childArrayName = ss.str();
|
||||
tmpIndex++;
|
||||
|
||||
auto fatherArrayValue = dynamic_cast<Value *>(fatherArray);
|
||||
auto childArray = new AllocaInst(fatherArrayValue->getType(), subDims, block, childArrayName);
|
||||
auto inst = new GetSubArrayInst(fatherArray, childArray, indices, block, childArrayName);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建获取部分数组指令
|
||||
MemsetInst * createMemsetInst(Value *pointer, Value *begin, Value *size, Value *value, const std::string &name = "") {
|
||||
auto inst = new MemsetInst(pointer, begin, size, value, block, name);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建memset指令
|
||||
StoreInst * createStoreInst(Value *value, Value *pointer, const std::string &name = "") {
|
||||
auto inst = new StoreInst(value, pointer, block, name);
|
||||
StoreInst * createStoreInst(Value *value, Value *pointer, const std::vector<Value *> &indices = {},
|
||||
const std::string &name = "") {
|
||||
auto inst = new StoreInst(value, pointer, indices, block, name);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建store指令
|
||||
PhiInst * createPhiInst(Type *type, const std::vector<Value*> &vals = {}, const std::vector<BasicBlock*> &blks = {}, const std::string &name = "") {
|
||||
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);
|
||||
auto predNum = block->getNumPredecessors();
|
||||
auto inst = new PhiInst(type, vals, blks, block, name);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(block->begin(), inst);
|
||||
return inst;
|
||||
} ///< 创建Phi指令
|
||||
/**
|
||||
* @brief 根据 LLVM 设计模式创建 GEP 指令。
|
||||
* 它会自动推断返回类型,无需手动指定。
|
||||
*/
|
||||
GetElementPtrInst *createGetElementPtrInst(Value *basePointer, const std::vector<Value *> &indices,
|
||||
const std::string &name = "") {
|
||||
Type *ResultElementType = getIndexedType(basePointer->getType(), indices);
|
||||
if (!ResultElementType) {
|
||||
assert(false && "Invalid GEP indexing!");
|
||||
return nullptr;
|
||||
}
|
||||
Type *ResultType = PointerType::get(ResultElementType);
|
||||
std::string newName;
|
||||
if (name.empty()) {
|
||||
std::stringstream ss;
|
||||
ss << tmpIndex;
|
||||
newName = ss.str();
|
||||
tmpIndex++;
|
||||
} else {
|
||||
newName = name;
|
||||
}
|
||||
|
||||
auto inst = new GetElementPtrInst(ResultType, basePointer, indices, block, newName);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
}
|
||||
|
||||
static Type *getIndexedType(Type *pointerType, const std::vector<Value *> &indices) {
|
||||
assert(pointerType->isPointer() && "base must be a pointer type!");
|
||||
// GEP 的类型推断从基指针所指向的类型开始。
|
||||
// 例如:
|
||||
// - 如果 pointerType 是 `[20 x [10 x i32]]*`,`currentWalkType` 初始为 `[20 x [10 x i32]]`。
|
||||
// - 如果 pointerType 是 `i32*`,`currentWalkType` 初始为 `i32`。
|
||||
// - 如果 pointerType 是 `i32**`,`currentWalkType` 初始为 `i32*`。
|
||||
Type *currentWalkType = pointerType->as<PointerType>()->getBaseType();
|
||||
|
||||
// 遍历所有索引来深入类型层次结构。
|
||||
// 重要:第一个索引总是用于"解引用"指针,后续索引才用于数组/结构体的索引
|
||||
for (int i = 0; i < indices.size(); ++i) {
|
||||
if (i == 0) {
|
||||
// 第一个索引:总是用于"解引用"基指针,不改变currentWalkType
|
||||
// 例如:对于 `[4 x i32]* ptr, i32 0`,第一个0只是说"访问ptr指向的对象"
|
||||
// currentWalkType 保持为 `[4 x i32]`
|
||||
continue;
|
||||
} else {
|
||||
// 后续索引:用于实际的数组/结构体索引
|
||||
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` 就是 GEP 指令最终计算出的地址所指向的元素的类型。
|
||||
return currentWalkType;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
59
src/include/Mem2Reg.h
Normal file
59
src/include/Mem2Reg.h
Normal file
@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include "IR.h"
|
||||
#include "IRBuilder.h"
|
||||
#include "SysYIRAnalyser.h"
|
||||
|
||||
namespace sysy {
|
||||
/**
|
||||
* 实现静态单变量赋值核心类 mem2reg
|
||||
*/
|
||||
class Mem2Reg {
|
||||
private:
|
||||
Module *pModule;
|
||||
IRBuilder *pBuilder;
|
||||
ControlFlowAnalysis *controlFlowAnalysis; // 控制流分析
|
||||
ActiveVarAnalysis *activeVarAnalysis; // 活跃变量分析
|
||||
DataFlowAnalysisUtils dataFlowAnalysisUtils;
|
||||
|
||||
public:
|
||||
Mem2Reg(Module *pMoudle, IRBuilder *pBuilder,
|
||||
ControlFlowAnalysis *pCFA = nullptr, ActiveVarAnalysis *pAVA = nullptr) :
|
||||
pModule(pMoudle), pBuilder(pBuilder), controlFlowAnalysis(pCFA), activeVarAnalysis(pAVA), dataFlowAnalysisUtils()
|
||||
{} // 初始化函数
|
||||
|
||||
void mem2regPipeline(); ///< mem2reg
|
||||
|
||||
private:
|
||||
|
||||
// phi节点的插入需要计算IDF
|
||||
std::unordered_set<BasicBlock *> computeIterDf(const std::unordered_set<BasicBlock *> &blocks); ///< 计算定义块集合的迭代支配边界
|
||||
|
||||
auto computeValue2Blocks() -> void; ///< 计算value2block的映射(不包括数组和global)
|
||||
|
||||
auto preOptimize1() -> void; ///< llvm memtoreg预优化1: 删除不含load的alloc和store
|
||||
auto preOptimize2() -> void; ///< llvm memtoreg预优化2: 针对某个变量的Defblocks只有一个块的情况
|
||||
auto preOptimize3() -> void; ///< llvm memtoreg预优化3: 针对某个变量的所有读写都在同一个块中的情况
|
||||
|
||||
auto insertPhi() -> void; ///< 为所有变量的迭代支配边界插入phi结点
|
||||
|
||||
auto rename(BasicBlock *block, std::unordered_map<Value *, int> &count,
|
||||
std::unordered_map<Value *, std::stack<Instruction *>> &stacks) -> void; ///< 单个块的重命名
|
||||
auto renameAll() -> void; ///< 重命名所有块
|
||||
|
||||
// private helper function.
|
||||
private:
|
||||
auto getPredIndex(BasicBlock *n, BasicBlock *s) -> int; ///< 获取前驱索引
|
||||
auto cascade(Instruction *instr, bool &changed, Function *func, BasicBlock *block,
|
||||
std::list<std::unique_ptr<Instruction>> &instrs) -> void; ///< 消除级联关系
|
||||
auto isGlobal(Value *val) -> bool; ///< 判断是否是全局变量
|
||||
auto isArr(Value *val) -> bool; ///< 判断是否是数组
|
||||
auto usedelete(Instruction *instr) -> void; ///< 删除指令相关的value-use-user关系
|
||||
|
||||
};
|
||||
} // namespace sysy
|
||||
@ -12,25 +12,22 @@ namespace sysy {
|
||||
class RISCv64AsmPrinter {
|
||||
public:
|
||||
RISCv64AsmPrinter(MachineFunction* mfunc);
|
||||
|
||||
// 主入口
|
||||
void run(std::ostream& os, bool debug = false);
|
||||
void printInstruction(MachineInstr* instr, bool debug = false);
|
||||
// 辅助函数
|
||||
void setStream(std::ostream& os) { OS = &os; }
|
||||
// 辅助函数
|
||||
std::string regToString(PhysicalReg reg);
|
||||
std::string formatInstr(const MachineInstr *instr);
|
||||
|
||||
private:
|
||||
// 打印各个部分
|
||||
void printPrologue();
|
||||
void printEpilogue();
|
||||
void printBasicBlock(MachineBasicBlock* mbb, bool debug = false);
|
||||
void printInstruction(MachineInstr* instr, bool debug = false);
|
||||
|
||||
// 辅助函数
|
||||
std::string regToString(PhysicalReg reg);
|
||||
void printOperand(MachineOperand* op);
|
||||
|
||||
MachineFunction* MFunc;
|
||||
std::ostream* OS = nullptr;
|
||||
|
||||
std::ostream* OS;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
@ -22,11 +22,7 @@ private:
|
||||
// 函数级代码生成 (实现新的流水线)
|
||||
std::string function_gen(Function* func);
|
||||
|
||||
// 私有辅助函数,用于根据类型计算其占用的字节数。
|
||||
unsigned getTypeSizeInBytes(Type* type);
|
||||
|
||||
Module* module;
|
||||
bool gc_failed = false;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
@ -3,12 +3,6 @@
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
|
||||
// Forward declarations
|
||||
namespace sysy {
|
||||
class GlobalValue;
|
||||
class Value;
|
||||
}
|
||||
|
||||
extern int DEBUG;
|
||||
extern int DEEPDEBUG;
|
||||
|
||||
@ -22,12 +16,7 @@ public:
|
||||
|
||||
// 公开接口,以便后续模块(如RegAlloc)可以查询或创建vreg
|
||||
unsigned getVReg(Value* val);
|
||||
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; }
|
||||
unsigned getNewVReg() { return vreg_counter++; }
|
||||
|
||||
private:
|
||||
// DAG节点定义,作为ISel的内部实现细节
|
||||
@ -44,10 +33,7 @@ private:
|
||||
std::vector<std::unique_ptr<DAGNode>> build_dag(BasicBlock* bb);
|
||||
DAGNode* get_operand_node(Value* val_ir, std::map<Value*, DAGNode*>&, std::vector<std::unique_ptr<DAGNode>>&);
|
||||
DAGNode* create_node(int kind, Value* val, std::map<Value*, DAGNode*>&, std::vector<std::unique_ptr<DAGNode>>&);
|
||||
// 用于计算类型大小的辅助函数
|
||||
unsigned getTypeSizeInBytes(Type* type);
|
||||
|
||||
// 打印DAG图以供调试
|
||||
void print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, const std::string& bb_name);
|
||||
|
||||
// 状态
|
||||
@ -57,8 +43,6 @@ 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;
|
||||
201
src/include/RISCv64LLIR.h
Normal file
201
src/include/RISCv64LLIR.h
Normal file
@ -0,0 +1,201 @@
|
||||
#ifndef RISCV64_LLIR_H
|
||||
#define RISCV64_LLIR_H
|
||||
|
||||
#include "IR.h" // 确保包含了您自己的IR头文件
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
|
||||
// 前向声明,避免循环引用
|
||||
namespace sysy {
|
||||
class Function;
|
||||
class RISCv64ISel;
|
||||
}
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 物理寄存器定义
|
||||
enum class PhysicalReg {
|
||||
ZERO, RA, SP, GP, TP, T0, T1, T2, S0, S1, A0, A1, A2, A3, A4, A5, A6, A7, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, T3, T4, T5, T6,
|
||||
F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15,F16, F17, F18, F19, F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, F31
|
||||
};
|
||||
|
||||
// RISC-V 指令操作码枚举
|
||||
enum class RVOpcodes {
|
||||
// 算术指令
|
||||
ADD, ADDI, ADDW, ADDIW, SUB, SUBW, MUL, MULW, DIV, DIVW, REM, REMW,
|
||||
// 逻辑指令
|
||||
XOR, XORI, OR, ORI, AND, ANDI,
|
||||
// 移位指令
|
||||
SLL, SLLI, SLLW, SLLIW, SRL, SRLI, SRLW, SRLIW, SRA, SRAI, SRAW, SRAIW,
|
||||
// 比较指令
|
||||
SLT, SLTI, SLTU, SLTIU,
|
||||
// 内存访问指令
|
||||
LW, LH, LB, LWU, LHU, LBU, SW, SH, SB, LD, SD,
|
||||
// 控制流指令
|
||||
J, JAL, JALR, RET,
|
||||
BEQ, BNE, BLT, BGE, BLTU, BGEU,
|
||||
// 伪指令
|
||||
LI, LA, MV, NEG, NEGW, SEQZ, SNEZ,
|
||||
// 函数调用
|
||||
CALL,
|
||||
// 特殊标记,非指令
|
||||
LABEL,
|
||||
// 新增伪指令,用于解耦栈帧处理
|
||||
FRAME_LOAD, // 从栈帧加载 (AllocaInst)
|
||||
FRAME_STORE, // 保存到栈帧 (AllocaInst)
|
||||
FRAME_ADDR, // [新] 获取栈帧变量的地址
|
||||
};
|
||||
|
||||
class MachineOperand;
|
||||
class RegOperand;
|
||||
class ImmOperand;
|
||||
class LabelOperand;
|
||||
class MemOperand;
|
||||
class MachineInstr;
|
||||
class MachineBasicBlock;
|
||||
class MachineFunction;
|
||||
|
||||
// 操作数基类
|
||||
class MachineOperand {
|
||||
public:
|
||||
enum OperandKind { KIND_REG, KIND_IMM, KIND_LABEL, KIND_MEM };
|
||||
MachineOperand(OperandKind kind) : kind(kind) {}
|
||||
virtual ~MachineOperand() = default;
|
||||
OperandKind getKind() const { return kind; }
|
||||
private:
|
||||
OperandKind kind;
|
||||
};
|
||||
|
||||
// 寄存器操作数
|
||||
class RegOperand : public MachineOperand {
|
||||
public:
|
||||
// 构造虚拟寄存器
|
||||
RegOperand(unsigned vreg_num)
|
||||
: MachineOperand(KIND_REG), vreg_num(vreg_num), is_virtual(true) {}
|
||||
|
||||
// 构造物理寄存器
|
||||
RegOperand(PhysicalReg preg)
|
||||
: MachineOperand(KIND_REG), preg(preg), is_virtual(false) {}
|
||||
|
||||
bool isVirtual() const { return is_virtual; }
|
||||
unsigned getVRegNum() const { return vreg_num; }
|
||||
PhysicalReg getPReg() const { return preg; }
|
||||
|
||||
void setPReg(PhysicalReg new_preg) {
|
||||
preg = new_preg;
|
||||
is_virtual = false;
|
||||
}
|
||||
private:
|
||||
unsigned vreg_num = 0;
|
||||
PhysicalReg preg = PhysicalReg::ZERO;
|
||||
bool is_virtual;
|
||||
};
|
||||
|
||||
// 立即数操作数
|
||||
class ImmOperand : public MachineOperand {
|
||||
public:
|
||||
ImmOperand(int64_t value) : MachineOperand(KIND_IMM), value(value) {}
|
||||
int64_t getValue() const { return value; }
|
||||
private:
|
||||
int64_t value;
|
||||
};
|
||||
|
||||
// 标签操作数
|
||||
class LabelOperand : public MachineOperand {
|
||||
public:
|
||||
LabelOperand(const std::string& name) : MachineOperand(KIND_LABEL), name(name) {}
|
||||
const std::string& getName() const { return name; }
|
||||
private:
|
||||
std::string name;
|
||||
};
|
||||
|
||||
// 内存操作数, 表示 offset(base_reg)
|
||||
class MemOperand : public MachineOperand {
|
||||
public:
|
||||
MemOperand(std::unique_ptr<RegOperand> base, std::unique_ptr<ImmOperand> offset)
|
||||
: MachineOperand(KIND_MEM), base(std::move(base)), offset(std::move(offset)) {}
|
||||
RegOperand* getBase() const { return base.get(); }
|
||||
ImmOperand* getOffset() const { return offset.get(); }
|
||||
private:
|
||||
std::unique_ptr<RegOperand> base;
|
||||
std::unique_ptr<ImmOperand> offset;
|
||||
};
|
||||
|
||||
// 机器指令
|
||||
class MachineInstr {
|
||||
public:
|
||||
MachineInstr(RVOpcodes opcode) : opcode(opcode) {}
|
||||
|
||||
RVOpcodes getOpcode() const { return opcode; }
|
||||
const std::vector<std::unique_ptr<MachineOperand>>& getOperands() const { return operands; }
|
||||
std::vector<std::unique_ptr<MachineOperand>>& getOperands() { return operands; }
|
||||
|
||||
void addOperand(std::unique_ptr<MachineOperand> operand) {
|
||||
operands.push_back(std::move(operand));
|
||||
}
|
||||
private:
|
||||
RVOpcodes opcode;
|
||||
std::vector<std::unique_ptr<MachineOperand>> operands;
|
||||
};
|
||||
|
||||
// 机器基本块
|
||||
class MachineBasicBlock {
|
||||
public:
|
||||
MachineBasicBlock(const std::string& name, MachineFunction* parent)
|
||||
: name(name), parent(parent) {}
|
||||
|
||||
const std::string& getName() const { return name; }
|
||||
MachineFunction* getParent() const { return parent; }
|
||||
const std::vector<std::unique_ptr<MachineInstr>>& getInstructions() const { return instructions; }
|
||||
std::vector<std::unique_ptr<MachineInstr>>& getInstructions() { return instructions; }
|
||||
|
||||
void addInstruction(std::unique_ptr<MachineInstr> instr) {
|
||||
instructions.push_back(std::move(instr));
|
||||
}
|
||||
|
||||
std::vector<MachineBasicBlock*> successors;
|
||||
std::vector<MachineBasicBlock*> predecessors;
|
||||
private:
|
||||
std::string name;
|
||||
std::vector<std::unique_ptr<MachineInstr>> instructions;
|
||||
MachineFunction* parent;
|
||||
};
|
||||
|
||||
// 栈帧信息
|
||||
struct StackFrameInfo {
|
||||
int locals_size = 0; // 仅为AllocaInst分配的大小
|
||||
int spill_size = 0; // 仅为溢出分配的大小
|
||||
int total_size = 0; // 总大小
|
||||
std::map<unsigned, int> alloca_offsets; // <AllocaInst的vreg, 栈偏移>
|
||||
std::map<unsigned, int> spill_offsets; // <溢出vreg, 栈偏移>
|
||||
};
|
||||
|
||||
// 机器函数
|
||||
class MachineFunction {
|
||||
public:
|
||||
MachineFunction(Function* func, RISCv64ISel* isel) : F(func), name(func->getName()), isel(isel) {}
|
||||
|
||||
Function* getFunc() const { return F; }
|
||||
RISCv64ISel* getISel() const { return isel; }
|
||||
const std::string& getName() const { return name; }
|
||||
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 addBlock(std::unique_ptr<MachineBasicBlock> block) {
|
||||
blocks.push_back(std::move(block));
|
||||
}
|
||||
private:
|
||||
Function* F;
|
||||
RISCv64ISel* isel; // 指向创建它的ISel,用于获取vreg映射等信息
|
||||
std::string name;
|
||||
std::vector<std::unique_ptr<MachineBasicBlock>> blocks;
|
||||
StackFrameInfo frame_info;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // RISCV64_LLIR_H
|
||||
61
src/include/RISCv64Passes.h
Normal file
61
src/include/RISCv64Passes.h
Normal file
@ -0,0 +1,61 @@
|
||||
#ifndef RISCV64_PASSES_H
|
||||
#define RISCV64_PASSES_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
/**
|
||||
* @class Pass
|
||||
* @brief 所有优化Pass的抽象基类 (可选,但推荐)
|
||||
* * 定义一个通用的接口,所有优化都应该实现它。
|
||||
*/
|
||||
class Pass {
|
||||
public:
|
||||
virtual ~Pass() = default;
|
||||
virtual void runOnMachineFunction(MachineFunction* mfunc) = 0;
|
||||
};
|
||||
|
||||
|
||||
// --- 寄存器分配前优化 ---
|
||||
|
||||
/**
|
||||
* @class PreRA_Scheduler
|
||||
* @brief 寄存器分配前的指令调度器
|
||||
* * 在虚拟寄存器上进行操作,此时调度自由度最大,
|
||||
* 主要目标是隐藏指令延迟,提高流水线效率。
|
||||
*/
|
||||
class PreRA_Scheduler : public Pass {
|
||||
public:
|
||||
void runOnMachineFunction(MachineFunction* mfunc) override;
|
||||
};
|
||||
|
||||
|
||||
// --- 寄存器分配后优化 ---
|
||||
|
||||
/**
|
||||
* @class PeepholeOptimizer
|
||||
* @brief 窥孔优化器
|
||||
* * 在已分配物理寄存器的指令流上,通过一个小的滑动窗口来查找
|
||||
* 并替换掉一些冗余或低效的指令模式。
|
||||
*/
|
||||
class PeepholeOptimizer : public Pass {
|
||||
public:
|
||||
void runOnMachineFunction(MachineFunction* mfunc) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* @class PostRA_Scheduler
|
||||
* @brief 寄存器分配后的局部指令调度器
|
||||
* * 主要目标是优化寄存器分配器插入的spill/fill代码(lw/sw),
|
||||
* 尝试将加载指令提前,以隐藏其访存延迟。
|
||||
*/
|
||||
class PostRA_Scheduler : public Pass {
|
||||
public:
|
||||
void runOnMachineFunction(MachineFunction* mfunc) override;
|
||||
};
|
||||
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // RISCV64_PASSES_H
|
||||
56
src/include/RISCv64RegAlloc.h
Normal file
56
src/include/RISCv64RegAlloc.h
Normal file
@ -0,0 +1,56 @@
|
||||
#ifndef RISCV64_REGALLOC_H
|
||||
#define RISCV64_REGALLOC_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
class RISCv64RegAlloc {
|
||||
public:
|
||||
RISCv64RegAlloc(MachineFunction* mfunc);
|
||||
|
||||
// 模块主入口
|
||||
void run();
|
||||
|
||||
private:
|
||||
using LiveSet = std::set<unsigned>; // 活跃虚拟寄存器集合
|
||||
using InterferenceGraph = std::map<unsigned, std::set<unsigned>>;
|
||||
|
||||
// 栈帧管理
|
||||
void eliminateFrameIndices();
|
||||
|
||||
// 活跃性分析
|
||||
void analyzeLiveness();
|
||||
|
||||
// 构建干扰图
|
||||
void buildInterferenceGraph();
|
||||
|
||||
// 图着色分配寄存器
|
||||
void colorGraph();
|
||||
|
||||
// 重写函数,替换vreg并插入溢出代码
|
||||
void rewriteFunction();
|
||||
|
||||
// 辅助函数,获取指令的Use/Def集合
|
||||
void getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def);
|
||||
|
||||
MachineFunction* MFunc;
|
||||
|
||||
// 活跃性分析结果
|
||||
std::map<const MachineInstr*, LiveSet> live_in_map;
|
||||
std::map<const MachineInstr*, LiveSet> live_out_map;
|
||||
|
||||
// 干扰图
|
||||
InterferenceGraph interference_graph;
|
||||
|
||||
// 图着色结果
|
||||
std::map<unsigned, PhysicalReg> color_map; // vreg -> preg
|
||||
std::set<unsigned> spilled_vregs; // 被溢出的vreg集合
|
||||
|
||||
// 可用的物理寄存器池
|
||||
std::vector<PhysicalReg> allocable_int_regs;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // RISCV64_REGALLOC_H
|
||||
23
src/include/Reg2Mem.h
Normal file
23
src/include/Reg2Mem.h
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "IR.h"
|
||||
#include "IRBuilder.h"
|
||||
|
||||
namespace sysy {
|
||||
/**
|
||||
* Reg2Mem(后端未做phi指令翻译)
|
||||
*/
|
||||
class Reg2Mem {
|
||||
private:
|
||||
Module *pModule;
|
||||
IRBuilder *pBuilder;
|
||||
|
||||
public:
|
||||
Reg2Mem(Module *pMoudle, IRBuilder *pBuilder) : pModule(pMoudle), pBuilder(pBuilder) {}
|
||||
|
||||
void DeletePhiInst();
|
||||
// 删除UD关系, 因为删除了phi指令会修改ud关系
|
||||
void usedelete(Instruction *instr);
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
340
src/include/SysYFormatter.h
Normal file
340
src/include/SysYFormatter.h
Normal file
@ -0,0 +1,340 @@
|
||||
#pragma once
|
||||
|
||||
#include "SysYBaseVisitor.h"
|
||||
#include "SysYParser.h"
|
||||
#include <ostream>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
class SysYFormatter : public SysYBaseVisitor {
|
||||
protected:
|
||||
std::ostream &os;
|
||||
int indent = 0;
|
||||
|
||||
public:
|
||||
SysYFormatter(std::ostream &os) : os(os), indent(0) {}
|
||||
|
||||
protected:
|
||||
struct Indentor {
|
||||
static constexpr int TabSize = 2;
|
||||
int &indent;
|
||||
Indentor(int &indent) : indent(indent) { indent += TabSize; }
|
||||
~Indentor() { indent -= TabSize; }
|
||||
};
|
||||
std::ostream &space() { return os << std::string(indent, ' '); }
|
||||
template <typename T>
|
||||
std::ostream &interleave(const T &container, const std::string sep = ", ") {
|
||||
auto b = container.begin(), e = container.end();
|
||||
(*b)->accept(this);
|
||||
for (b = std::next(b); b != e; b = std::next(b)) {
|
||||
os << sep;
|
||||
(*b)->accept(this);
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
public:
|
||||
// virtual std::any visitModule(SysYParser::ModuleContext *ctx) override {
|
||||
// return visitChildren(ctx);
|
||||
// }
|
||||
|
||||
virtual std::any visitBtype(SysYParser::BtypeContext *ctx) override {
|
||||
os << ctx->getText();
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitDecl(SysYParser::DeclContext *ctx) override {
|
||||
space();
|
||||
if (ctx->CONST())
|
||||
os << ctx->CONST()->getText() << ' ';
|
||||
ctx->btype()->accept(this);
|
||||
os << ' ';
|
||||
interleave(ctx->varDef(), ", ") << ';' << '\n';
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitVarDef(SysYParser::VarDefContext *ctx) override {
|
||||
ctx->lValue()->accept(this);
|
||||
if (ctx->initValue()) {
|
||||
os << ' ' << '=' << ' ';
|
||||
ctx->initValue()->accept(this);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitInitValue(SysYParser::InitValueContext *ctx) override {
|
||||
if (not ctx->exp()) {
|
||||
os << '{';
|
||||
auto values = ctx->initValue();
|
||||
if (values.size())
|
||||
interleave(values, ", ");
|
||||
os << '}';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitFunc(SysYParser::FuncContext *ctx) override {
|
||||
ctx->funcType()->accept(this);
|
||||
os << ' ' << ctx->ID()->getText() << '(';
|
||||
if (ctx->funcFParams())
|
||||
ctx->funcFParams()->accept(this);
|
||||
os << ')' << ' ';
|
||||
ctx->blockStmt()->accept(this);
|
||||
os << '\n';
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitFuncType(SysYParser::FuncTypeContext *ctx) override {
|
||||
os << ctx->getText();
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any
|
||||
visitFuncFParams(SysYParser::FuncFParamsContext *ctx) override {
|
||||
interleave(ctx->funcFParam(), ", ");
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any
|
||||
visitFuncFParam(SysYParser::FuncFParamContext *ctx) override {
|
||||
ctx->btype()->accept(this);
|
||||
os << ' ' << ctx->ID()->getText();
|
||||
if (not ctx->LBRACKET().empty()) {
|
||||
os << '[';
|
||||
auto exp = ctx->exp();
|
||||
if (not exp.empty()) {
|
||||
os << '[';
|
||||
interleave(exp, "][") << ']';
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitBlockStmt(SysYParser::BlockStmtContext *ctx) override {
|
||||
os << '{' << '\n';
|
||||
{
|
||||
Indentor indentor(indent);
|
||||
auto items = ctx->blockItem();
|
||||
if (not items.empty())
|
||||
interleave(items, "");
|
||||
}
|
||||
space() << ctx->RBRACE()->getText() << '\n';
|
||||
return 0;
|
||||
}
|
||||
|
||||
// virtual std::any visitBlockItem(SysYParser::BlockItemContext *ctx)
|
||||
// override {
|
||||
// return visitChildren(ctx);
|
||||
// }
|
||||
|
||||
// virtual std::any visitStmt(SysYParser::StmtContext *ctx) override {
|
||||
// return visitChildren(ctx);
|
||||
// }
|
||||
|
||||
virtual std::any
|
||||
visitAssignStmt(SysYParser::AssignStmtContext *ctx) override {
|
||||
space();
|
||||
ctx->lValue()->accept(this);
|
||||
os << " = ";
|
||||
ctx->exp()->accept(this);
|
||||
os << ';' << '\n';
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitExpStmt(SysYParser::ExpStmtContext *ctx) override {
|
||||
space();
|
||||
ctx->exp()->accept(this);
|
||||
os << ';' << '\n';
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wrapBlock(SysYParser::StmtContext *stmt) {
|
||||
bool isBlock = stmt->blockStmt();
|
||||
if (isBlock) {
|
||||
stmt->accept(this);
|
||||
} else {
|
||||
os << "{\n";
|
||||
{
|
||||
Indentor indentor(indent);
|
||||
stmt->accept(this);
|
||||
}
|
||||
space() << "}\n";
|
||||
}
|
||||
};
|
||||
virtual std::any visitIfStmt(SysYParser::IfStmtContext *ctx) override {
|
||||
space();
|
||||
os << ctx->IF()->getText() << " (";
|
||||
ctx->exp()->accept(this);
|
||||
os << ") ";
|
||||
auto stmt = ctx->stmt();
|
||||
auto ifStmt = stmt[0];
|
||||
wrapBlock(ifStmt);
|
||||
if (stmt.size() == 2) {
|
||||
auto elseStmt = stmt[1];
|
||||
wrapBlock(elseStmt);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitWhileStmt(SysYParser::WhileStmtContext *ctx) override {
|
||||
space();
|
||||
os << ctx->WHILE()->getText() << " (";
|
||||
ctx->exp()->accept(this);
|
||||
os << ") ";
|
||||
wrapBlock(ctx->stmt());
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitBreakStmt(SysYParser::BreakStmtContext *ctx) override {
|
||||
space() << ctx->BREAK()->getText() << ';' << '\n';
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any
|
||||
visitContinueStmt(SysYParser::ContinueStmtContext *ctx) override {
|
||||
space() << ctx->CONTINUE()->getText() << ';' << '\n';
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any
|
||||
visitReturnStmt(SysYParser::ReturnStmtContext *ctx) override {
|
||||
space() << ctx->RETURN()->getText();
|
||||
if (ctx->exp()) {
|
||||
os << ' ';
|
||||
ctx->exp()->accept(this);
|
||||
}
|
||||
os << ';' << '\n';
|
||||
return 0;
|
||||
}
|
||||
|
||||
// virtual std::any visitEmptyStmt(SysYParser::EmptyStmtContext *ctx)
|
||||
// override {
|
||||
// return visitChildren(ctx);
|
||||
// }
|
||||
|
||||
virtual std::any
|
||||
visitRelationExp(SysYParser::RelationExpContext *ctx) override {
|
||||
auto lhs = ctx->exp(0);
|
||||
auto rhs = ctx->exp(1);
|
||||
std::string op =
|
||||
ctx->LT() ? "<" : (ctx->LE() ? "<=" : (ctx->GT() ? ">" : ">="));
|
||||
lhs->accept(this);
|
||||
os << ' ' << op << ' ';
|
||||
rhs->accept(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any
|
||||
visitMultiplicativeExp(SysYParser::MultiplicativeExpContext *ctx) override {
|
||||
auto lhs = ctx->exp(0);
|
||||
auto rhs = ctx->exp(1);
|
||||
std::string op = ctx->MUL() ? "*" : (ctx->DIV() ? "/" : "%");
|
||||
lhs->accept(this);
|
||||
os << ' ' << op << ' ';
|
||||
rhs->accept(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// virtual std::any visitLValueExp(SysYParser::LValueExpContext *ctx)
|
||||
// override {
|
||||
// return visitChildren(ctx);
|
||||
// }
|
||||
|
||||
// virtual std::any visitNumberExp(SysYParser::NumberExpContext *ctx)
|
||||
// override {
|
||||
// return visitChildren(ctx);
|
||||
// }
|
||||
|
||||
virtual std::any visitAndExp(SysYParser::AndExpContext *ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
os << " && ";
|
||||
ctx->exp(1)->accept(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitUnaryExp(SysYParser::UnaryExpContext *ctx) override {
|
||||
std::string op = ctx->ADD() ? "+" : (ctx->SUB() ? "-" : "!");
|
||||
os << op;
|
||||
ctx->exp()->accept(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitParenExp(SysYParser::ParenExpContext *ctx) override {
|
||||
os << '(';
|
||||
ctx->exp()->accept(this);
|
||||
os << ')';
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitStringExp(SysYParser::StringExpContext *ctx) override {
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
virtual std::any visitOrExp(SysYParser::OrExpContext *ctx) override {
|
||||
ctx->exp(0)->accept(this);
|
||||
os << " || ";
|
||||
ctx->exp(1)->accept(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// virtual std::any visitCallExp(SysYParser::CallExpContext *ctx) override {
|
||||
// return visitChildren(ctx);
|
||||
// }
|
||||
|
||||
virtual std::any
|
||||
visitAdditiveExp(SysYParser::AdditiveExpContext *ctx) override {
|
||||
auto lhs = ctx->exp(0);
|
||||
auto rhs = ctx->exp(1);
|
||||
std::string op = ctx->ADD() ? "+" : "-";
|
||||
lhs->accept(this);
|
||||
os << ' ' << op << ' ';
|
||||
rhs->accept(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitEqualExp(SysYParser::EqualExpContext *ctx) override {
|
||||
auto lhs = ctx->exp(0);
|
||||
auto rhs = ctx->exp(1);
|
||||
std::string op = ctx->EQ() ? "==" : "!=";
|
||||
lhs->accept(this);
|
||||
os << ' ' << op << ' ';
|
||||
rhs->accept(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitCall(SysYParser::CallContext *ctx) override {
|
||||
os << ctx->ID()->getText() << '(';
|
||||
if (ctx->funcRParams())
|
||||
ctx->funcRParams()->accept(this);
|
||||
os << ')';
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitLValue(SysYParser::LValueContext *ctx) override {
|
||||
os << ctx->ID()->getText();
|
||||
auto exp = ctx->exp();
|
||||
if (not exp.empty()) {
|
||||
os << '[';
|
||||
interleave(exp, "][") << ']';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitNumber(SysYParser::NumberContext *ctx) override {
|
||||
os << ctx->getText();
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any visitString(SysYParser::StringContext *ctx) override {
|
||||
os << ctx->getText();
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual std::any
|
||||
visitFuncRParams(SysYParser::FuncRParamsContext *ctx) override {
|
||||
interleave(ctx->exp(), ", ");
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
465
src/include/SysYIRAnalyser.h
Normal file
465
src/include/SysYIRAnalyser.h
Normal file
@ -0,0 +1,465 @@
|
||||
#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
|
||||
@ -59,96 +59,15 @@ 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;
|
||||
|
||||
bool HasReturnInst;
|
||||
|
||||
public:
|
||||
Module *get() const { return module.get(); }
|
||||
IRBuilder *getBuilder(){ return &builder; }
|
||||
public:
|
||||
|
||||
std::any visitCompUnit(SysYParser::CompUnitContext *ctx) override;
|
||||
|
||||
std::any visitGlobalConstDecl(SysYParser::GlobalConstDeclContext *ctx) override;
|
||||
@ -179,7 +98,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;
|
||||
@ -213,29 +132,7 @@ public:
|
||||
std::any visitLAndExp(SysYParser::LAndExpContext *ctx) override;
|
||||
std::any visitLOrExp(SysYParser::LOrExpContext *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);
|
||||
// 构建数组类型
|
||||
Type* buildArrayType(Type* baseType, const std::vector<Value*>& dims);
|
||||
|
||||
unsigned countArrayDimensions(Type* type);
|
||||
// std::any visitConstExp(SysYParser::ConstExpContext *ctx) override;
|
||||
|
||||
|
||||
}; // class SysYIRGenerator
|
||||
37
src/include/SysYIROptPre.h
Normal file
37
src/include/SysYIROptPre.h
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "IR.h"
|
||||
#include "IRBuilder.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 优化前对SysY IR的预处理,也可以视作部分CFG优化
|
||||
// 主要包括删除无用指令、合并基本块、删除空块等
|
||||
// 这些操作可以在SysY IR生成时就完成,但为了简化IR生成过程,
|
||||
// 这里将其放在SysY IR生成后进行预处理
|
||||
// 同时兼容phi节点的处理,可以再mem2reg后再次调用优化
|
||||
class SysYOptPre {
|
||||
private:
|
||||
Module *pModule;
|
||||
IRBuilder *pBuilder;
|
||||
|
||||
public:
|
||||
SysYOptPre(Module *pMoudle, IRBuilder *pBuilder) : pModule(pMoudle), pBuilder(pBuilder) {}
|
||||
|
||||
void SysYOptimizateAfterIR(){
|
||||
SysYDelInstAfterBr();
|
||||
SysYBlockMerge();
|
||||
SysYDelNoPreBLock();
|
||||
SysYDelEmptyBlock();
|
||||
SysYAddReturn();
|
||||
}
|
||||
void SysYDelInstAfterBr(); // 删除br后面的指令
|
||||
void SysYDelEmptyBlock(); // 空块删除
|
||||
void SysYDelNoPreBLock(); // 删除无前驱块
|
||||
void SysYBlockMerge(); // 合并基本块(主要针对嵌套if while的exit块,
|
||||
// 也可以修改IR生成实现回填机制
|
||||
void SysYAddReturn(); // 添加return指令(主要针对Void函数)
|
||||
void usedelete(Instruction *instr); // use删除
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
@ -15,7 +15,6 @@ public:
|
||||
public:
|
||||
void printIR();
|
||||
void printGlobalVariable();
|
||||
void printGlobalConstant();
|
||||
|
||||
|
||||
public:
|
||||
@ -23,8 +22,6 @@ 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);
|
||||
@ -1,33 +0,0 @@
|
||||
#ifndef CALLEE_SAVED_HANDLER_H
|
||||
#define CALLEE_SAVED_HANDLER_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "Pass.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
/**
|
||||
* @class CalleeSavedHandler
|
||||
* @brief 处理被调用者保存寄存器(Callee-Saved Registers)的Pass。
|
||||
* * 这个Pass在寄存器分配之后运行。它的主要职责是:
|
||||
* 1. 扫描整个函数,找出所有被使用的 `s` 系列寄存器。
|
||||
* 2. 在函数序言中插入 `sd` 指令来保存这些寄存器。
|
||||
* 3. 在函数结尾(ret指令前)插入 `ld` 指令来恢复这些寄存器。
|
||||
* 4. 正确计算因保存这些寄存器而需要的额外栈空间,并更新StackFrameInfo。
|
||||
*/
|
||||
class CalleeSavedHandler : public Pass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
CalleeSavedHandler() : Pass("callee-saved-handler", Granularity::Function, PassKind::Optimization) {}
|
||||
|
||||
void *getPassID() const override { return &ID; }
|
||||
|
||||
bool runOnFunction(Function *F, AnalysisManager& AM) override;
|
||||
|
||||
void runOnMachineFunction(MachineFunction* mfunc);
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // CALLEE_SAVED_HANDLER_H
|
||||
@ -1,20 +0,0 @@
|
||||
#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
|
||||
@ -1,36 +0,0 @@
|
||||
#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
|
||||
@ -1,35 +0,0 @@
|
||||
#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
|
||||
@ -1,30 +0,0 @@
|
||||
#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
|
||||
@ -1,45 +0,0 @@
|
||||
#ifndef RISCV64_PEEPHOLE_H
|
||||
#define RISCV64_PEEPHOLE_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "Pass.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
/**
|
||||
* @class PeepholeOptimizer
|
||||
* @brief 窥孔优化器
|
||||
* * 在已分配物理寄存器的指令流上,通过一个小的滑动窗口来查找
|
||||
* 并替换掉一些冗余或低效的指令模式。
|
||||
*/
|
||||
class PeepholeOptimizer : public Pass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
PeepholeOptimizer() : Pass("peephole-optimizer", Granularity::Function, PassKind::Optimization) {}
|
||||
|
||||
void *getPassID() const override { return &ID; }
|
||||
|
||||
bool runOnFunction(Function *F, AnalysisManager& AM) override;
|
||||
|
||||
void runOnMachineFunction(MachineFunction* mfunc);
|
||||
|
||||
/**
|
||||
* @brief 设置是否启用浮点乘加融合优化
|
||||
* @param enabled 是否启用
|
||||
*/
|
||||
static void setFusedMulAddEnabled(bool enabled) { fusedMulAddEnabled = enabled; }
|
||||
|
||||
/**
|
||||
* @brief 检查是否启用了浮点乘加融合优化
|
||||
* @return 是否启用
|
||||
*/
|
||||
static bool isFusedMulAddEnabled() { return fusedMulAddEnabled; }
|
||||
|
||||
private:
|
||||
static bool fusedMulAddEnabled; // 浮点乘加融合优化开关
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // RISCV64_PEEPHOLE_H
|
||||
@ -1,50 +0,0 @@
|
||||
#ifndef POST_RA_SCHEDULER_H
|
||||
#define POST_RA_SCHEDULER_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "Pass.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
/**
|
||||
* @class PostRA_Scheduler
|
||||
* @brief 寄存器分配后的局部指令调度器
|
||||
* * 主要目标是优化寄存器分配器插入的spill/fill代码(lw/sw),
|
||||
* 尝试将加载指令提前,以隐藏其访存延迟。
|
||||
*/
|
||||
struct MemoryAccess {
|
||||
PhysicalReg base_reg;
|
||||
int64_t offset;
|
||||
bool valid;
|
||||
|
||||
MemoryAccess() : valid(false) {}
|
||||
MemoryAccess(PhysicalReg base, int64_t off) : base_reg(base), offset(off), valid(true) {}
|
||||
};
|
||||
|
||||
struct InstrRegInfo {
|
||||
std::unordered_set<PhysicalReg> defined_regs;
|
||||
std::unordered_set<PhysicalReg> used_regs;
|
||||
bool is_load;
|
||||
bool is_store;
|
||||
bool is_control_flow;
|
||||
MemoryAccess mem_access;
|
||||
|
||||
InstrRegInfo() : is_load(false), is_store(false), is_control_flow(false) {}
|
||||
};
|
||||
|
||||
class PostRA_Scheduler : public Pass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
PostRA_Scheduler() : Pass("post-ra-scheduler", Granularity::Function, PassKind::Optimization) {}
|
||||
|
||||
void *getPassID() const override { return &ID; }
|
||||
|
||||
bool runOnFunction(Function *F, AnalysisManager& AM) override;
|
||||
|
||||
void runOnMachineFunction(MachineFunction* mfunc);
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // POST_RA_SCHEDULER_H
|
||||
@ -1,30 +0,0 @@
|
||||
#ifndef PRE_RA_SCHEDULER_H
|
||||
#define PRE_RA_SCHEDULER_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "Pass.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
/**
|
||||
* @class PreRA_Scheduler
|
||||
* @brief 寄存器分配前的指令调度器
|
||||
* * 在虚拟寄存器上进行操作,此时调度自由度最大,
|
||||
* 主要目标是隐藏指令延迟,提高流水线效率。
|
||||
*/
|
||||
class PreRA_Scheduler : public Pass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
PreRA_Scheduler() : Pass("pre-ra-scheduler", Granularity::Function, PassKind::Optimization) {}
|
||||
|
||||
void *getPassID() const override { return &ID; }
|
||||
|
||||
bool runOnFunction(Function *F, AnalysisManager& AM) override;
|
||||
|
||||
void runOnMachineFunction(MachineFunction* mfunc);
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // PRE_RA_SCHEDULER_H
|
||||
@ -1,61 +0,0 @@
|
||||
#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
|
||||
@ -1,98 +0,0 @@
|
||||
#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
|
||||
@ -1,355 +0,0 @@
|
||||
#ifndef RISCV64_LLIR_H
|
||||
#define RISCV64_LLIR_H
|
||||
|
||||
#include "IR.h" // 确保包含了您自己的IR头文件
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
|
||||
// 前向声明,避免循环引用
|
||||
namespace sysy {
|
||||
class Function;
|
||||
class RISCv64ISel;
|
||||
}
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 物理寄存器定义
|
||||
enum class PhysicalReg {
|
||||
// --- 特殊功能寄存器 ---
|
||||
ZERO, RA, SP, GP, TP,
|
||||
|
||||
// --- 整数寄存器 (按调用约定分组) ---
|
||||
// 临时寄存器 (调用者保存)
|
||||
T0, T1, T2, T3, T4, T5, T6,
|
||||
|
||||
// 保存寄存器 (被调用者保存)
|
||||
S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11,
|
||||
|
||||
// 参数/返回值寄存器 (调用者保存)
|
||||
A0, A1, A2, A3, A4, A5, A6, A7,
|
||||
|
||||
// --- 浮点寄存器 ---
|
||||
F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11,
|
||||
F12, F13, F14, F15, F16, F17, F18, F19, F20, F21,
|
||||
F22, F23, F24, F25, F26, F27, F28, F29, F30, F31,
|
||||
|
||||
// 用于内部表示物理寄存器在干扰图中的节点ID(一个简单的特殊ID,确保不与vreg_counter冲突)
|
||||
// 假设 vreg_counter 不会达到这么大的值
|
||||
PHYS_REG_START_ID = 1000000,
|
||||
PHYS_REG_END_ID = PHYS_REG_START_ID + 320, // 预留足够的空间
|
||||
|
||||
INVALID, ///< 无效寄存器标记
|
||||
};
|
||||
|
||||
// RISC-V 指令操作码枚举
|
||||
enum class RVOpcodes {
|
||||
// 算术指令
|
||||
ADD, ADDI, ADDW, ADDIW, SUB, SUBW, MUL, MULW, MULH, DIV, DIVW, REM, REMW,
|
||||
// 逻辑指令
|
||||
XOR, XORI, OR, ORI, AND, ANDI,
|
||||
// 移位指令
|
||||
SLL, SLLI, SLLW, SLLIW, SRL, SRLI, SRLW, SRLIW, SRA, SRAI, SRAW, SRAIW,
|
||||
// 比较指令
|
||||
SLT, SLTI, SLTU, SLTIU,
|
||||
// 内存访问指令
|
||||
LW, LH, LB, LWU, LHU, LBU, SW, SH, SB, LD, SD,
|
||||
// 控制流指令
|
||||
J, JAL, JALR, RET,
|
||||
BEQ, BNE, BLT, BGE, BLTU, BGEU,
|
||||
// 伪指令
|
||||
LI, LA, MV, NEG, NEGW, SEQZ, SNEZ,
|
||||
// 函数调用
|
||||
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, // 保持寄存器活跃,防止优化器删除
|
||||
};
|
||||
|
||||
inline bool isGPR(PhysicalReg reg) {
|
||||
return reg >= PhysicalReg::ZERO && reg <= PhysicalReg::T6;
|
||||
}
|
||||
|
||||
// 判断一个物理寄存器是否是浮点寄存器 (FPR)
|
||||
inline bool isFPR(PhysicalReg reg) {
|
||||
return reg >= PhysicalReg::F0 && reg <= PhysicalReg::F31;
|
||||
}
|
||||
|
||||
// 获取所有调用者保存的整数寄存器 (t0-t6, a0-a7)
|
||||
inline const std::vector<PhysicalReg>& getCallerSavedIntRegs() {
|
||||
static const std::vector<PhysicalReg> regs = {
|
||||
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3,
|
||||
PhysicalReg::T4, PhysicalReg::T5, PhysicalReg::T6,
|
||||
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3,
|
||||
PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7
|
||||
};
|
||||
return regs;
|
||||
}
|
||||
|
||||
// 获取所有被调用者保存的整数寄存器 (s0-s11)
|
||||
inline const std::vector<PhysicalReg>& getCalleeSavedIntRegs() {
|
||||
static const std::vector<PhysicalReg> regs = {
|
||||
PhysicalReg::S0, PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3,
|
||||
PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
|
||||
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11
|
||||
};
|
||||
return regs;
|
||||
}
|
||||
|
||||
// 获取所有调用者保存的浮点寄存器 (ft0-ft11, fa0-fa7)
|
||||
inline const std::vector<PhysicalReg>& getCallerSavedFpRegs() {
|
||||
static const std::vector<PhysicalReg> regs = {
|
||||
PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3,
|
||||
PhysicalReg::F4, PhysicalReg::F5, PhysicalReg::F6, PhysicalReg::F7,
|
||||
PhysicalReg::F8, PhysicalReg::F9, PhysicalReg::F10, PhysicalReg::F11, // ft0-ft11 和 fa0-fa7 在标准ABI中重叠
|
||||
PhysicalReg::F12, PhysicalReg::F13, PhysicalReg::F14, PhysicalReg::F15,
|
||||
PhysicalReg::F16, PhysicalReg::F17
|
||||
};
|
||||
return regs;
|
||||
}
|
||||
|
||||
// 获取所有被调用者保存的浮点寄存器 (fs0-fs11)
|
||||
inline const std::vector<PhysicalReg>& getCalleeSavedFpRegs() {
|
||||
static const std::vector<PhysicalReg> regs = {
|
||||
PhysicalReg::F18, PhysicalReg::F19, PhysicalReg::F20, PhysicalReg::F21,
|
||||
PhysicalReg::F22, PhysicalReg::F23, PhysicalReg::F24, PhysicalReg::F25,
|
||||
PhysicalReg::F26, PhysicalReg::F27, PhysicalReg::F28, PhysicalReg::F29,
|
||||
PhysicalReg::F30, PhysicalReg::F31
|
||||
};
|
||||
return regs;
|
||||
}
|
||||
|
||||
class MachineOperand;
|
||||
class RegOperand;
|
||||
class ImmOperand;
|
||||
class LabelOperand;
|
||||
class MemOperand;
|
||||
class MachineInstr;
|
||||
class MachineBasicBlock;
|
||||
class MachineFunction;
|
||||
|
||||
// 操作数基类
|
||||
class MachineOperand {
|
||||
public:
|
||||
enum OperandKind { KIND_REG, KIND_IMM, KIND_LABEL, KIND_MEM };
|
||||
MachineOperand(OperandKind kind) : kind(kind) {}
|
||||
virtual ~MachineOperand() = default;
|
||||
OperandKind getKind() const { return kind; }
|
||||
private:
|
||||
OperandKind kind;
|
||||
};
|
||||
|
||||
// 寄存器操作数
|
||||
class RegOperand : public MachineOperand {
|
||||
public:
|
||||
// 构造虚拟寄存器
|
||||
RegOperand(unsigned vreg_num)
|
||||
: MachineOperand(KIND_REG), vreg_num(vreg_num), is_virtual(true) {}
|
||||
|
||||
// 构造物理寄存器
|
||||
RegOperand(PhysicalReg preg)
|
||||
: MachineOperand(KIND_REG), preg(preg), is_virtual(false) {}
|
||||
|
||||
bool isVirtual() const { return is_virtual; }
|
||||
unsigned getVRegNum() const { return vreg_num; }
|
||||
PhysicalReg getPReg() const { return preg; }
|
||||
|
||||
void setPReg(PhysicalReg new_preg) {
|
||||
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;
|
||||
bool is_virtual;
|
||||
};
|
||||
|
||||
// 立即数操作数
|
||||
class ImmOperand : public MachineOperand {
|
||||
public:
|
||||
ImmOperand(int64_t value) : MachineOperand(KIND_IMM), value(value) {}
|
||||
int64_t getValue() const { return value; }
|
||||
private:
|
||||
int64_t value;
|
||||
};
|
||||
|
||||
// 标签操作数
|
||||
class LabelOperand : public MachineOperand {
|
||||
public:
|
||||
LabelOperand(const std::string& name) : MachineOperand(KIND_LABEL), name(name) {}
|
||||
const std::string& getName() const { return name; }
|
||||
private:
|
||||
std::string name;
|
||||
};
|
||||
|
||||
// 内存操作数, 表示 offset(base_reg)
|
||||
class MemOperand : public MachineOperand {
|
||||
public:
|
||||
MemOperand(std::unique_ptr<RegOperand> base, std::unique_ptr<ImmOperand> offset)
|
||||
: MachineOperand(KIND_MEM), base(std::move(base)), offset(std::move(offset)) {}
|
||||
RegOperand* getBase() const { return base.get(); }
|
||||
ImmOperand* getOffset() const { return offset.get(); }
|
||||
private:
|
||||
std::unique_ptr<RegOperand> base;
|
||||
std::unique_ptr<ImmOperand> offset;
|
||||
};
|
||||
|
||||
// 机器指令
|
||||
class MachineInstr {
|
||||
public:
|
||||
MachineInstr(RVOpcodes opcode) : opcode(opcode) {}
|
||||
|
||||
RVOpcodes getOpcode() const { return opcode; }
|
||||
const std::vector<std::unique_ptr<MachineOperand>>& getOperands() const { return operands; }
|
||||
std::vector<std::unique_ptr<MachineOperand>>& getOperands() { return operands; }
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
// 机器基本块
|
||||
class MachineBasicBlock {
|
||||
public:
|
||||
MachineBasicBlock(const std::string& name, MachineFunction* parent)
|
||||
: name(name), parent(parent) {}
|
||||
|
||||
const std::string& getName() const { return name; }
|
||||
MachineFunction* getParent() const { return parent; }
|
||||
const std::vector<std::unique_ptr<MachineInstr>>& getInstructions() const { return instructions; }
|
||||
std::vector<std::unique_ptr<MachineInstr>>& getInstructions() { return instructions; }
|
||||
|
||||
void addInstruction(std::unique_ptr<MachineInstr> instr) {
|
||||
instructions.push_back(std::move(instr));
|
||||
}
|
||||
|
||||
std::vector<MachineBasicBlock*> successors;
|
||||
std::vector<MachineBasicBlock*> predecessors;
|
||||
private:
|
||||
std::string name;
|
||||
std::vector<std::unique_ptr<MachineInstr>> instructions;
|
||||
MachineFunction* parent;
|
||||
};
|
||||
|
||||
// 栈帧信息
|
||||
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; // 已排序的、需要存取的被调用者保存寄存器
|
||||
};
|
||||
|
||||
// 机器函数
|
||||
class MachineFunction {
|
||||
public:
|
||||
MachineFunction(Function* func, RISCv64ISel* isel) : F(func), name(func->getName()), isel(isel) {}
|
||||
|
||||
Function* getFunc() const { return F; }
|
||||
RISCv64ISel* getISel() const { return isel; }
|
||||
const std::string& getName() const { return name; }
|
||||
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));
|
||||
}
|
||||
private:
|
||||
Function* F;
|
||||
RISCv64ISel* isel; // 指向创建它的ISel,用于获取vreg映射等信息
|
||||
std::string name;
|
||||
std::vector<std::unique_ptr<MachineBasicBlock>> blocks;
|
||||
StackFrameInfo frame_info;
|
||||
};
|
||||
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
|
||||
@ -1,81 +0,0 @@
|
||||
#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,19 +0,0 @@
|
||||
#ifndef RISCV64_PASSES_H
|
||||
#define RISCV64_PASSES_H
|
||||
|
||||
#include "Pass.h"
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "Peephole.h"
|
||||
#include "PreRA_Scheduler.h"
|
||||
#include "PostRA_Scheduler.h"
|
||||
#include "CalleeSavedHandler.h"
|
||||
#include "LegalizeImmediates.h"
|
||||
#include "PrologueEpilogueInsertion.h"
|
||||
#include "EliminateFrameIndices.h"
|
||||
#include "DivStrengthReduction.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // RISCV64_PASSES_H
|
||||
@ -1,122 +0,0 @@
|
||||
#ifndef RISCV64_REGALLOC_H
|
||||
#define RISCV64_REGALLOC_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "RISCv64ISel.h" // 包含 RISCv64ISel.h 以访问 ISel 和 Value 类型
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <stack>
|
||||
|
||||
extern int DEBUG;
|
||||
extern int DEEPDEBUG;
|
||||
extern int DEBUGLENGTH; // 用于限制调试输出的长度
|
||||
extern int DEEPERDEBUG; // 用于更深层次的调试输出
|
||||
|
||||
namespace sysy {
|
||||
|
||||
class RISCv64RegAlloc {
|
||||
public:
|
||||
RISCv64RegAlloc(MachineFunction* mfunc);
|
||||
|
||||
// 模块主入口
|
||||
bool run();
|
||||
|
||||
private:
|
||||
// 类型定义,与Python版本对应
|
||||
using VRegSet = std::set<unsigned>;
|
||||
using InterferenceGraph = std::map<unsigned, VRegSet>;
|
||||
using VRegStack = std::vector<unsigned>; // 使用vector模拟栈,方便遍历
|
||||
using MoveList = std::map<unsigned, std::set<const MachineInstr*>>;
|
||||
using AliasMap = std::map<unsigned, unsigned>;
|
||||
using ColorMap = std::map<unsigned, PhysicalReg>;
|
||||
using VRegMoveSet = std::set<const MachineInstr*>;
|
||||
|
||||
// --- 核心算法流程 ---
|
||||
void initialize();
|
||||
void build();
|
||||
void makeWorklist();
|
||||
void simplify();
|
||||
void coalesce();
|
||||
void freeze();
|
||||
void selectSpill();
|
||||
void assignColors();
|
||||
void rewriteProgram();
|
||||
bool doAllocation();
|
||||
void applyColoring();
|
||||
|
||||
void dumpState(const std::string &stage);
|
||||
|
||||
void precolorByCallingConvention();
|
||||
|
||||
// --- 辅助函数 ---
|
||||
void getInstrUseDef(const MachineInstr* instr, VRegSet& use, VRegSet& def);
|
||||
void getInstrUseDef_Liveness(const MachineInstr *instr, VRegSet &use, VRegSet &def);
|
||||
void addEdge(unsigned u, unsigned v);
|
||||
VRegSet adjacent(unsigned n);
|
||||
VRegMoveSet nodeMoves(unsigned n);
|
||||
bool moveRelated(unsigned n);
|
||||
void decrementDegree(unsigned m);
|
||||
void enableMoves(const VRegSet& nodes);
|
||||
unsigned getAlias(unsigned n);
|
||||
void addWorklist(unsigned u);
|
||||
bool briggsHeuristic(unsigned u, unsigned v);
|
||||
bool georgeHeuristic(unsigned u, unsigned v);
|
||||
void combine(unsigned u, unsigned v);
|
||||
void freezeMoves(unsigned u);
|
||||
void collectUsedCalleeSavedRegs();
|
||||
bool isFPVReg(unsigned vreg) const;
|
||||
std::string regToString(PhysicalReg reg);
|
||||
std::string regIdToString(unsigned id);
|
||||
|
||||
// --- 活跃性分析 ---
|
||||
void analyzeLiveness();
|
||||
|
||||
MachineFunction* MFunc;
|
||||
RISCv64ISel* ISel;
|
||||
|
||||
// --- 算法数据结构 ---
|
||||
// 寄存器池
|
||||
std::vector<PhysicalReg> allocable_int_regs;
|
||||
std::vector<PhysicalReg> allocable_fp_regs;
|
||||
int K_int; // 整数寄存器数量
|
||||
int K_fp; // 浮点寄存器数量
|
||||
|
||||
// 节点集合
|
||||
VRegSet precolored; // 预着色的节点 (物理寄存器)
|
||||
VRegSet initial; // 初始的、所有待处理的虚拟寄存器节点
|
||||
VRegSet simplifyWorklist;
|
||||
VRegSet freezeWorklist;
|
||||
VRegSet spillWorklist;
|
||||
VRegSet spilledNodes;
|
||||
VRegSet coalescedNodes;
|
||||
VRegSet coloredNodes;
|
||||
VRegStack selectStack;
|
||||
|
||||
// Move指令相关
|
||||
std::set<const MachineInstr*> coalescedMoves;
|
||||
std::set<const MachineInstr*> constrainedMoves;
|
||||
std::set<const MachineInstr*> frozenMoves;
|
||||
std::set<const MachineInstr*> worklistMoves;
|
||||
std::set<const MachineInstr*> activeMoves;
|
||||
|
||||
// 数据结构
|
||||
InterferenceGraph adjSet;
|
||||
std::map<unsigned, VRegSet> adjList; // 邻接表
|
||||
std::map<unsigned, int> degree;
|
||||
MoveList moveList;
|
||||
AliasMap alias;
|
||||
ColorMap color_map;
|
||||
|
||||
// 活跃性分析结果
|
||||
std::map<const MachineInstr*, VRegSet> live_in_map;
|
||||
std::map<const MachineInstr*, VRegSet> live_out_map;
|
||||
|
||||
// VReg -> Value* 和 VReg -> Type* 的映射
|
||||
const std::map<unsigned, Value*>& vreg_to_value_map;
|
||||
const std::map<unsigned, Type*>& vreg_type_map;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // RISCV64_REGALLOC_H
|
||||
@ -1,246 +0,0 @@
|
||||
#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
|
||||
@ -1,242 +0,0 @@
|
||||
#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
|
||||
@ -1,107 +0,0 @@
|
||||
#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
|
||||
@ -1,72 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "IR.h" // 包含 IR 定义
|
||||
#include "Pass.h" // 包含 Pass 框架
|
||||
#include <algorithm> // for std::set_union, std::set_difference
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 前向声明
|
||||
class Function;
|
||||
class BasicBlock;
|
||||
class Value;
|
||||
class Instruction;
|
||||
|
||||
// 活跃变量分析结果类
|
||||
// 它将包含 LiveIn 和 LiveOut 集合
|
||||
class LivenessAnalysisResult : public AnalysisResultBase {
|
||||
public:
|
||||
LivenessAnalysisResult(Function *F) : AssociatedFunction(F) {}
|
||||
|
||||
// 获取给定基本块的 LiveIn 集合
|
||||
const std::set<Value *> *getLiveIn(BasicBlock *BB) const;
|
||||
|
||||
// 获取给定基本块的 LiveOut 集合
|
||||
const std::set<Value *> *getLiveOut(BasicBlock *BB) const;
|
||||
|
||||
// 暴露内部数据结构,如果需要更直接的访问
|
||||
const std::map<BasicBlock *, std::set<Value *>> &getLiveInSets() const { return liveInSets; }
|
||||
const std::map<BasicBlock *, std::set<Value *>> &getLiveOutSets() const { return liveOutSets; }
|
||||
|
||||
// 核心计算方法,由 LivenessAnalysisPass 调用
|
||||
void computeLiveness(Function *F);
|
||||
|
||||
private:
|
||||
Function *AssociatedFunction; // 这个活跃变量分析是为哪个函数计算的
|
||||
std::map<BasicBlock *, std::set<Value *>> liveInSets;
|
||||
std::map<BasicBlock *, std::set<Value *>> liveOutSets;
|
||||
|
||||
// 辅助函数:计算基本块的 Def 和 Use 集合
|
||||
// Def: 块内定义,且定义在所有使用之前的值
|
||||
// Use: 块内使用,且使用在所有定义之前的值
|
||||
void computeDefUse(BasicBlock *BB, std::set<Value *> &def, std::set<Value *> &use);
|
||||
};
|
||||
|
||||
// 活跃变量分析遍
|
||||
class LivenessAnalysisPass : public AnalysisPass {
|
||||
public:
|
||||
// 唯一的 Pass ID
|
||||
static void *ID; // LLVM 风格的唯一 ID
|
||||
|
||||
LivenessAnalysisPass() : AnalysisPass("LivenessAnalysis", Pass::Granularity::Function) {}
|
||||
|
||||
// 实现 getPassID
|
||||
void *getPassID() const override { return &ID; }
|
||||
|
||||
// 运行分析并返回结果。现在接受 AnalysisManager& AM 参数
|
||||
bool runOnFunction(Function *F, AnalysisManager &AM) override;
|
||||
|
||||
// 获取分析结果的指针。
|
||||
// 注意:AnalysisManager 将会调用此方法来获取结果并进行缓存。
|
||||
std::unique_ptr<AnalysisResultBase> getResult() override;
|
||||
|
||||
private:
|
||||
// 存储当前分析计算出的 LivenessAnalysisResult 实例
|
||||
// runOnFunction 每次调用都会创建新的 LivenessAnalysisResult 对象
|
||||
std::unique_ptr<LivenessAnalysisResult> CurrentLivenessResult;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
@ -1,618 +0,0 @@
|
||||
#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
|
||||
@ -1,356 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Dom.h" // 支配树分析依赖
|
||||
#include "Loop.h" // 循环分析依赖
|
||||
#include "Liveness.h" // 活跃性分析依赖
|
||||
#include "AliasAnalysis.h" // 别名分析依赖
|
||||
#include "SideEffectAnalysis.h" // 副作用分析依赖
|
||||
#include "CallGraphAnalysis.h" // 调用图分析依赖
|
||||
#include "IR.h" // IR定义
|
||||
#include "Pass.h" // Pass框架
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 前向声明
|
||||
class LoopCharacteristicsResult;
|
||||
|
||||
enum IVKind {
|
||||
kBasic, // 基本归纳变量
|
||||
kLinear, // 线性归纳变量
|
||||
kCmplx // 复杂派生归纳变量
|
||||
} ; // 归纳变量类型
|
||||
|
||||
struct InductionVarInfo {
|
||||
Value* div; // 派生归纳变量的指令
|
||||
Value* base = nullptr; // 其根phi或BIV或DIV
|
||||
std::pair<Value*, Value*> Multibase = {nullptr, nullptr}; // 多个BIV
|
||||
Instruction::Kind Instkind; // 操作类型
|
||||
int factor = 1; // 系数(如i*2+3的2)
|
||||
int offset = 0; // 常量偏移
|
||||
bool valid; // 是否线性可归约
|
||||
IVKind ivkind; // 归纳变量类型
|
||||
|
||||
|
||||
static std::unique_ptr<InductionVarInfo> createBasicBIV(Value* v, Instruction::Kind kind, Value* base = nullptr, int factor = 1, int offset = 0) {
|
||||
return std::make_unique<InductionVarInfo>(
|
||||
InductionVarInfo{v, base, {nullptr, nullptr}, kind, factor, offset, true, IVKind::kBasic}
|
||||
);
|
||||
}
|
||||
|
||||
static std::unique_ptr<InductionVarInfo> createSingleDIV(Value* v, Instruction::Kind kind, Value* base = nullptr, int factor = 1, int offset = 0) {
|
||||
return std::make_unique<InductionVarInfo>(
|
||||
InductionVarInfo{v, base, {nullptr, nullptr}, kind, factor, offset, true, IVKind::kLinear}
|
||||
);
|
||||
}
|
||||
|
||||
static std::unique_ptr<InductionVarInfo> createDoubleDIV(Value* v, Instruction::Kind kind, Value* base1 = nullptr, Value* base2 = nullptr, int factor = 1, int offset = 0) {
|
||||
return std::make_unique<InductionVarInfo>(
|
||||
InductionVarInfo{v, nullptr, {base1, base2}, kind, factor, offset, false, IVKind::kCmplx}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 循环特征信息结构 - 基础循环分析阶段
|
||||
* 存储循环的基本特征信息,为后续精确分析提供基础
|
||||
*/
|
||||
struct LoopCharacteristics {
|
||||
Loop* loop; // 关联的循环对象
|
||||
|
||||
// ========== 基础循环形式分析 ==========
|
||||
bool isCountingLoop; // 是否为计数循环 (for i=0; i<n; i++)
|
||||
bool isSimpleForLoop; // 是否为简单for循环
|
||||
bool hasComplexControlFlow; // 是否有复杂控制流 (break, continue)
|
||||
bool isInnermost; // 是否为最内层循环
|
||||
|
||||
// ========== 归纳变量分析 ==========
|
||||
|
||||
// ========== 基础循环不变量分析 ==========
|
||||
std::unordered_set<Value*> loopInvariants; // 循环不变量
|
||||
std::unordered_set<Instruction*> invariantInsts; // 可提升的不变指令
|
||||
|
||||
std::vector<std::unique_ptr<InductionVarInfo>> InductionVars; // 归纳变量
|
||||
|
||||
// ========== 基础边界分析 ==========
|
||||
std::optional<int> staticTripCount; // 静态循环次数(如果可确定)
|
||||
bool hasKnownBounds; // 是否有已知边界
|
||||
|
||||
// ========== 基础纯度和副作用分析 ==========
|
||||
bool isPure; // 是否为纯循环(无副作用)
|
||||
bool accessesOnlyLocalMemory; // 是否只访问局部内存
|
||||
bool hasNoMemoryAliasConflicts; // 是否无内存别名冲突
|
||||
|
||||
// ========== 基础内存访问模式分析 ==========
|
||||
struct MemoryAccessPattern {
|
||||
std::vector<Instruction*> loadInsts; // load指令列表
|
||||
std::vector<Instruction*> storeInsts; // store指令列表
|
||||
bool isArrayParameter; // 是否为数组参数访问
|
||||
bool isGlobalArray; // 是否为全局数组访问
|
||||
bool hasConstantIndices; // 是否使用常量索引
|
||||
};
|
||||
std::map<Value*, MemoryAccessPattern> memoryPatterns; // 内存访问模式
|
||||
|
||||
// ========== 基础性能特征 ==========
|
||||
size_t instructionCount; // 循环体指令数
|
||||
size_t memoryOperationCount; // 内存操作数
|
||||
size_t arithmeticOperationCount; // 算术操作数
|
||||
double computeToMemoryRatio; // 计算与内存操作比率
|
||||
|
||||
// ========== 基础优化提示 ==========
|
||||
bool benefitsFromUnrolling; // 是否适合循环展开
|
||||
int suggestedUnrollFactor; // 建议的展开因子
|
||||
|
||||
// 构造函数 - 简化的基础分析初始化
|
||||
LoopCharacteristics(Loop* l) : loop(l),
|
||||
isCountingLoop(false), isSimpleForLoop(false), hasComplexControlFlow(false),
|
||||
isInnermost(false), hasKnownBounds(false), isPure(false),
|
||||
accessesOnlyLocalMemory(false), hasNoMemoryAliasConflicts(false),
|
||||
benefitsFromUnrolling(false), suggestedUnrollFactor(1),
|
||||
instructionCount(0), memoryOperationCount(0),
|
||||
arithmeticOperationCount(0), computeToMemoryRatio(0.0) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 循环特征分析结果类
|
||||
* 包含函数中所有循环的特征信息,并提供查询接口
|
||||
*/
|
||||
class LoopCharacteristicsResult : public AnalysisResultBase {
|
||||
public:
|
||||
LoopCharacteristicsResult(Function *F) : AssociatedFunction(F) {}
|
||||
~LoopCharacteristicsResult() override = default;
|
||||
|
||||
// ========== 基础接口 ==========
|
||||
|
||||
/**
|
||||
* 添加循环特征信息
|
||||
*/
|
||||
void addLoopCharacteristics(std::unique_ptr<LoopCharacteristics> characteristics) {
|
||||
auto* loop = characteristics->loop;
|
||||
CharacteristicsMap[loop] = std::move(characteristics);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定循环的特征信息
|
||||
*/
|
||||
const LoopCharacteristics* getCharacteristics(Loop* loop) const {
|
||||
auto it = CharacteristicsMap.find(loop);
|
||||
return (it != CharacteristicsMap.end()) ? it->second.get() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有循环特征信息
|
||||
*/
|
||||
const std::map<Loop*, std::unique_ptr<LoopCharacteristics>>& getAllCharacteristics() const {
|
||||
return CharacteristicsMap;
|
||||
}
|
||||
|
||||
// ========== 核心查询接口 ==========
|
||||
|
||||
/**
|
||||
* 获取所有计数循环
|
||||
*/
|
||||
std::vector<Loop*> getCountingLoops() const {
|
||||
std::vector<Loop*> result;
|
||||
for (const auto& [loop, chars] : CharacteristicsMap) {
|
||||
if (chars->isCountingLoop) {
|
||||
result.push_back(loop);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有纯循环(无副作用)
|
||||
*/
|
||||
std::vector<Loop*> getPureLoops() const {
|
||||
std::vector<Loop*> result;
|
||||
for (const auto& [loop, chars] : CharacteristicsMap) {
|
||||
if (chars->isPure) {
|
||||
result.push_back(loop);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有只访问局部内存的循环
|
||||
*/
|
||||
std::vector<Loop*> getLocalMemoryOnlyLoops() const {
|
||||
std::vector<Loop*> result;
|
||||
for (const auto& [loop, chars] : CharacteristicsMap) {
|
||||
if (chars->accessesOnlyLocalMemory) {
|
||||
result.push_back(loop);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有无内存别名冲突的循环
|
||||
*/
|
||||
std::vector<Loop*> getNoAliasConflictLoops() const {
|
||||
std::vector<Loop*> result;
|
||||
for (const auto& [loop, chars] : CharacteristicsMap) {
|
||||
if (chars->hasNoMemoryAliasConflicts) {
|
||||
result.push_back(loop);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有适合展开的循环
|
||||
*/
|
||||
std::vector<Loop*> getUnrollingCandidates() const {
|
||||
std::vector<Loop*> result;
|
||||
for (const auto& [loop, chars] : CharacteristicsMap) {
|
||||
if (chars->benefitsFromUnrolling) {
|
||||
result.push_back(loop);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据热度排序循环 (用于优化优先级)
|
||||
*/
|
||||
std::vector<Loop*> getLoopsByHotness() const {
|
||||
std::vector<Loop*> result;
|
||||
for (const auto& [loop, chars] : CharacteristicsMap) {
|
||||
result.push_back(loop);
|
||||
}
|
||||
|
||||
// 按循环热度排序 (嵌套深度 + 循环次数 + 指令数)
|
||||
std::sort(result.begin(), result.end(), [](Loop* a, Loop* b) {
|
||||
double hotnessA = a->getLoopHotness();
|
||||
double hotnessB = b->getLoopHotness();
|
||||
return hotnessA > hotnessB; // 降序排列
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ========== 基础统计接口 ==========
|
||||
|
||||
/**
|
||||
* 获取基础优化统计信息
|
||||
*/
|
||||
struct BasicOptimizationStats {
|
||||
size_t totalLoops;
|
||||
size_t countingLoops;
|
||||
size_t unrollingCandidates;
|
||||
size_t pureLoops;
|
||||
size_t localMemoryOnlyLoops;
|
||||
size_t noAliasConflictLoops;
|
||||
double avgInstructionCount;
|
||||
double avgComputeMemoryRatio;
|
||||
};
|
||||
|
||||
BasicOptimizationStats getOptimizationStats() const {
|
||||
BasicOptimizationStats stats = {};
|
||||
stats.totalLoops = CharacteristicsMap.size();
|
||||
|
||||
size_t totalInstructions = 0;
|
||||
double totalComputeMemoryRatio = 0.0;
|
||||
|
||||
for (const auto& [loop, chars] : CharacteristicsMap) {
|
||||
if (chars->isCountingLoop) stats.countingLoops++;
|
||||
if (chars->benefitsFromUnrolling) stats.unrollingCandidates++;
|
||||
if (chars->isPure) stats.pureLoops++;
|
||||
if (chars->accessesOnlyLocalMemory) stats.localMemoryOnlyLoops++;
|
||||
if (chars->hasNoMemoryAliasConflicts) stats.noAliasConflictLoops++;
|
||||
|
||||
totalInstructions += chars->instructionCount;
|
||||
totalComputeMemoryRatio += chars->computeToMemoryRatio;
|
||||
}
|
||||
|
||||
if (stats.totalLoops > 0) {
|
||||
stats.avgInstructionCount = static_cast<double>(totalInstructions) / stats.totalLoops;
|
||||
stats.avgComputeMemoryRatio = totalComputeMemoryRatio / stats.totalLoops;
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
// 打印分析结果
|
||||
void print() const;
|
||||
|
||||
private:
|
||||
Function *AssociatedFunction; // 关联的函数
|
||||
std::map<Loop*, std::unique_ptr<LoopCharacteristics>> CharacteristicsMap; // 循环特征映射
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 基础循环特征分析遍
|
||||
* 在循环规范化前执行,进行基础的循环特征分析,为后续精确分析提供基础
|
||||
*/
|
||||
class LoopCharacteristicsPass : public AnalysisPass {
|
||||
public:
|
||||
// 唯一的 Pass ID
|
||||
static void *ID;
|
||||
|
||||
LoopCharacteristicsPass() : AnalysisPass("LoopCharacteristics", Pass::Granularity::Function) {}
|
||||
|
||||
// 实现 getPassID
|
||||
void *getPassID() const override { return &ID; }
|
||||
|
||||
// 核心运行方法
|
||||
bool runOnFunction(Function *F, AnalysisManager &AM) override;
|
||||
|
||||
// 获取分析结果
|
||||
std::unique_ptr<AnalysisResultBase> getResult() override { return std::move(CurrentResult); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<LoopCharacteristicsResult> CurrentResult;
|
||||
|
||||
// ========== 缓存的分析结果 ==========
|
||||
LoopAnalysisResult* loopAnalysis; // 循环结构分析结果
|
||||
AliasAnalysisResult* aliasAnalysis; // 别名分析结果
|
||||
SideEffectAnalysisResult* sideEffectAnalysis; // 副作用分析结果
|
||||
|
||||
// ========== 核心分析方法 ==========
|
||||
void analyzeLoop(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 基础循环形式分析
|
||||
void analyzeLoopForm(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 基础性能指标计算
|
||||
void computePerformanceMetrics(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 基础纯度和副作用分析
|
||||
void analyzePurityAndSideEffects(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 基础归纳变量识别
|
||||
void identifyBasicInductionVariables(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 循环不变量识别
|
||||
void identifyBasicLoopInvariants(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 基础边界分析
|
||||
void analyzeBasicLoopBounds(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 基础内存访问模式分析
|
||||
void analyzeBasicMemoryAccessPatterns(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// 基础优化评估
|
||||
void evaluateBasicOptimizationOpportunities(Loop* loop, LoopCharacteristics* characteristics);
|
||||
|
||||
// ========== 辅助方法 ==========
|
||||
bool isClassicLoopInvariant(Value* val, Loop* loop, const std::unordered_set<Value*>& invariants);
|
||||
void findDerivedInductionVars(Value* root,
|
||||
Value* base, // 只传单一BIV base
|
||||
Loop* loop,
|
||||
std::vector<std::unique_ptr<InductionVarInfo>>& ivs,
|
||||
std::set<Value*>& visited
|
||||
);
|
||||
bool isBasicInductionVariable(Value* val, Loop* loop);
|
||||
bool hasSimpleMemoryPattern(Loop* loop); // 简单的内存模式检查
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
@ -1,250 +0,0 @@
|
||||
#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
|
||||
@ -1,137 +0,0 @@
|
||||
#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
|
||||
@ -1,20 +0,0 @@
|
||||
#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
|
||||
@ -1,72 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Pass.h"
|
||||
#include "IR.h"
|
||||
#include "SysYIROptUtils.h"
|
||||
#include "Dom.h"
|
||||
#include "AliasAnalysis.h"
|
||||
#include "SideEffectAnalysis.h"
|
||||
#include <unordered_set>
|
||||
#include <queue>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 前向声明分析结果类,确保在需要时可以引用
|
||||
// class DominatorTreeAnalysisResult; // Pass.h 中已包含,这里不再需要
|
||||
class SideEffectInfoAnalysisResult; // 假设有副作用分析结果类
|
||||
|
||||
// DCEContext 类,用于封装DCE的内部逻辑和状态
|
||||
// 这样可以避免静态变量在多线程或多次运行时的冲突,并保持代码的模块化
|
||||
class DCEContext {
|
||||
public:
|
||||
// 运行DCE的主要方法
|
||||
// func: 当前要优化的函数
|
||||
// tp: 分析管理器,用于获取其他分析结果(如果需要)
|
||||
void run(Function* func, AnalysisManager* AM, bool &changed);
|
||||
|
||||
private:
|
||||
// 存储活跃指令的集合
|
||||
std::unordered_set<Instruction*> alive_insts;
|
||||
// 别名分析结果
|
||||
AliasAnalysisResult* aliasAnalysis = nullptr;
|
||||
// 副作用分析结果
|
||||
SideEffectAnalysisResult* sideEffectAnalysis = nullptr;
|
||||
|
||||
// 判断指令是否是"天然活跃"的(即总是保留的)
|
||||
// inst: 要检查的指令
|
||||
// 返回值: 如果指令是天然活跃的,则为true,否则为false
|
||||
bool isAlive(Instruction* inst);
|
||||
|
||||
// 递归地将活跃指令及其依赖加入到 alive_insts 集合中
|
||||
// inst: 要标记为活跃的指令
|
||||
void addAlive(Instruction* inst);
|
||||
|
||||
// 检查Store指令是否可能有副作用(通过别名分析)
|
||||
bool mayHaveSideEffect(StoreInst* store);
|
||||
};
|
||||
|
||||
// DCE 优化遍类,继承自 OptimizationPass
|
||||
class DCE : public OptimizationPass {
|
||||
public:
|
||||
// 构造函数
|
||||
DCE() : OptimizationPass("DCE", Granularity::Function) {}
|
||||
|
||||
// 静态成员,作为该遍的唯一ID
|
||||
static void *ID;
|
||||
|
||||
// 运行在函数上的优化逻辑
|
||||
// F: 当前要优化的函数
|
||||
// AM: 分析管理器,用于获取或使分析结果失效
|
||||
// 返回值: 如果IR被修改,则为true,否则为false
|
||||
bool runOnFunction(Function *F, AnalysisManager& AM) override;
|
||||
|
||||
// 声明该遍的分析依赖和失效信息
|
||||
// analysisDependencies: 该遍运行前需要哪些分析结果
|
||||
// analysisInvalidations: 该遍运行后会使哪些分析结果失效
|
||||
void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const override;
|
||||
|
||||
// Pass 基类中的纯虚函数,必须实现
|
||||
void *getPassID() const override { return &ID; }
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
@ -1,252 +0,0 @@
|
||||
#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
|
||||
@ -1,40 +0,0 @@
|
||||
#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
|
||||
@ -1,24 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Pass.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
class LargeArrayToGlobalPass : public OptimizationPass {
|
||||
public:
|
||||
static void *ID;
|
||||
|
||||
LargeArrayToGlobalPass() : OptimizationPass("LargeArrayToGlobal", Granularity::Module) {}
|
||||
|
||||
bool runOnModule(Module *M, AnalysisManager &AM) override;
|
||||
void *getPassID() const override {
|
||||
return &ID;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned calculateTypeSize(Type *type);
|
||||
void convertAllocaToGlobal(AllocaInst *alloca, Function *F, Module *M);
|
||||
std::string generateUniqueGlobalName(AllocaInst *alloca, Function *F);
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
@ -1,155 +0,0 @@
|
||||
#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
|
||||
@ -1,240 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Pass.h"
|
||||
#include "IR.h"
|
||||
#include "LoopCharacteristics.h"
|
||||
#include "Loop.h"
|
||||
#include "Dom.h"
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <memory>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 前向声明
|
||||
class LoopCharacteristicsResult;
|
||||
class LoopAnalysisResult;
|
||||
|
||||
/**
|
||||
* @brief 强度削弱候选项信息
|
||||
* 记录一个可以进行强度削弱的表达式信息
|
||||
*/
|
||||
struct StrengthReductionCandidate {
|
||||
enum OpType {
|
||||
MULTIPLY, // 乘法: iv * const
|
||||
DIVIDE, // 除法: iv / 2^n (转换为右移)
|
||||
DIVIDE_CONST, // 除法: iv / const (使用mulh指令优化)
|
||||
REMAINDER // 取模: iv % 2^n (转换为位与)
|
||||
};
|
||||
|
||||
enum DivisionStrategy {
|
||||
SIMPLE_SHIFT, // 简单右移(仅适用于无符号或非负数)
|
||||
SIGNED_CORRECTION, // 有符号除法修正: (x + (x >> 31) & mask) >> k
|
||||
MULH_OPTIMIZATION // 使用mulh指令优化任意常数除法
|
||||
};
|
||||
|
||||
Instruction* originalInst; // 原始指令 (如 i*4, i/8, i%16)
|
||||
Value* inductionVar; // 归纳变量 (如 i)
|
||||
OpType operationType; // 操作类型
|
||||
DivisionStrategy divStrategy; // 除法策略(仅用于除法)
|
||||
int multiplier; // 乘数/除数/模数 (如 4, 8, 16)
|
||||
int shiftAmount; // 位移量 (对于2的幂)
|
||||
int offset; // 偏移量 (如常数项)
|
||||
BasicBlock* containingBlock; // 所在基本块
|
||||
Loop* containingLoop; // 所在循环
|
||||
bool hasNegativeValues; // 归纳变量是否可能为负数
|
||||
|
||||
// 强度削弱后的新变量
|
||||
PhiInst* newPhi = nullptr; // 新的 phi 指令
|
||||
Value* newInductionVar = nullptr; // 新的归纳变量
|
||||
|
||||
StrengthReductionCandidate(Instruction* inst, Value* iv, OpType opType, int value, int off,
|
||||
BasicBlock* bb, Loop* loop)
|
||||
: originalInst(inst), inductionVar(iv), operationType(opType),
|
||||
divStrategy(SIMPLE_SHIFT), multiplier(value), offset(off),
|
||||
containingBlock(bb), containingLoop(loop), hasNegativeValues(false) {
|
||||
|
||||
// 计算位移量(用于除法和取模的强度削弱)
|
||||
if (opType == DIVIDE || opType == REMAINDER) {
|
||||
shiftAmount = 0;
|
||||
int temp = value;
|
||||
while (temp > 1) {
|
||||
temp >>= 1;
|
||||
shiftAmount++;
|
||||
}
|
||||
} else {
|
||||
shiftAmount = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 强度削弱上下文类
|
||||
* 封装强度削弱优化的核心逻辑和状态
|
||||
*/
|
||||
class StrengthReductionContext {
|
||||
public:
|
||||
StrengthReductionContext(IRBuilder* builder) : builder(builder) {}
|
||||
|
||||
/**
|
||||
* 运行强度削弱优化
|
||||
* @param F 目标函数
|
||||
* @param AM 分析管理器
|
||||
* @return 是否修改了IR
|
||||
*/
|
||||
bool run(Function* F, AnalysisManager& AM);
|
||||
|
||||
private:
|
||||
IRBuilder* builder;
|
||||
|
||||
// 分析结果缓存
|
||||
LoopAnalysisResult* loopAnalysis = nullptr;
|
||||
LoopCharacteristicsResult* loopCharacteristics = nullptr;
|
||||
DominatorTree* dominatorTree = nullptr;
|
||||
|
||||
// 候选项存储
|
||||
std::vector<std::unique_ptr<StrengthReductionCandidate>> candidates;
|
||||
std::unordered_map<Loop*, std::vector<StrengthReductionCandidate*>> loopToCandidates;
|
||||
|
||||
// ========== 核心分析和优化阶段 ==========
|
||||
|
||||
/**
|
||||
* 阶段1:识别强度削弱候选项
|
||||
* 扫描所有循环中的乘法指令,找出可以优化的模式
|
||||
*/
|
||||
void identifyStrengthReductionCandidates(Function* F);
|
||||
|
||||
/**
|
||||
* 阶段2:分析候选项的优化潜力
|
||||
* 评估每个候选项的收益,过滤掉不值得优化的情况
|
||||
*/
|
||||
void analyzeOptimizationPotential();
|
||||
|
||||
/**
|
||||
* 阶段3:执行强度削弱变换
|
||||
* 对选中的候选项执行实际的强度削弱优化
|
||||
*/
|
||||
bool performStrengthReduction();
|
||||
|
||||
// ========== 辅助分析函数 ==========
|
||||
|
||||
/**
|
||||
* 分析归纳变量是否可能取负值
|
||||
* @param ivInfo 归纳变量信息
|
||||
* @param loop 所属循环
|
||||
* @return 如果可能为负数返回true
|
||||
*/
|
||||
bool analyzeInductionVariableRange(const InductionVarInfo* ivInfo, Loop* loop) const;
|
||||
|
||||
/**
|
||||
* 计算用于除法优化的魔数和移位量
|
||||
* @param divisor 除数
|
||||
* @return {魔数, 移位量}
|
||||
*/
|
||||
std::pair<int, int> computeMulhMagicNumbers(int divisor) const;
|
||||
|
||||
/**
|
||||
* 生成除法替换代码
|
||||
* @param candidate 优化候选项
|
||||
* @param builder IR构建器
|
||||
* @return 替换值
|
||||
*/
|
||||
Value* generateDivisionReplacement(StrengthReductionCandidate* candidate, IRBuilder* builder) const;
|
||||
|
||||
/**
|
||||
* 生成任意常数除法替换代码
|
||||
* @param candidate 优化候选项
|
||||
* @param builder IR构建器
|
||||
* @return 替换值
|
||||
*/
|
||||
Value* generateConstantDivisionReplacement(StrengthReductionCandidate* candidate, IRBuilder* builder) const;
|
||||
|
||||
/**
|
||||
* 检查指令是否为强度削弱候选项
|
||||
* @param inst 要检查的指令
|
||||
* @param loop 所在循环
|
||||
* @return 如果是候选项返回候选项信息,否则返回nullptr
|
||||
*/
|
||||
std::unique_ptr<StrengthReductionCandidate>
|
||||
isStrengthReductionCandidate(Instruction* inst, Loop* loop);
|
||||
|
||||
/**
|
||||
* 检查值是否为循环的归纳变量
|
||||
* @param val 要检查的值
|
||||
* @param loop 循环
|
||||
* @param characteristics 循环特征信息
|
||||
* @return 如果是归纳变量返回归纳变量信息,否则返回nullptr
|
||||
*/
|
||||
const InductionVarInfo*
|
||||
getInductionVarInfo(Value* val, Loop* loop, const LoopCharacteristics* characteristics);
|
||||
|
||||
/**
|
||||
* 为候选项创建新的归纳变量
|
||||
* @param candidate 候选项
|
||||
* @return 是否成功创建
|
||||
*/
|
||||
bool createNewInductionVariable(StrengthReductionCandidate* candidate);
|
||||
|
||||
/**
|
||||
* 替换原始指令的所有使用
|
||||
* @param candidate 候选项
|
||||
* @return 是否成功替换
|
||||
*/
|
||||
bool replaceOriginalInstruction(StrengthReductionCandidate* candidate);
|
||||
|
||||
/**
|
||||
* 估算优化收益
|
||||
* 计算强度削弱后的性能提升
|
||||
* @param candidate 候选项
|
||||
* @return 估算的收益分数
|
||||
*/
|
||||
double estimateOptimizationBenefit(const StrengthReductionCandidate* candidate);
|
||||
|
||||
/**
|
||||
* 检查优化的合法性
|
||||
* @param candidate 候选项
|
||||
* @return 是否可以安全地进行优化
|
||||
*/
|
||||
bool isOptimizationLegal(const StrengthReductionCandidate* candidate);
|
||||
|
||||
/**
|
||||
* 打印调试信息
|
||||
*/
|
||||
void printDebugInfo();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 循环强度削弱优化遍
|
||||
* 将循环中的乘法运算转换为更高效的加法运算
|
||||
*/
|
||||
class LoopStrengthReduction : public OptimizationPass {
|
||||
public:
|
||||
// 唯一的 Pass ID
|
||||
static void *ID;
|
||||
|
||||
LoopStrengthReduction(IRBuilder* builder)
|
||||
: OptimizationPass("LoopStrengthReduction", Granularity::Function),
|
||||
builder(builder) {}
|
||||
|
||||
/**
|
||||
* 在函数上运行强度削弱优化
|
||||
* @param F 目标函数
|
||||
* @param AM 分析管理器
|
||||
* @return 是否修改了IR
|
||||
*/
|
||||
bool runOnFunction(Function* F, AnalysisManager& AM) override;
|
||||
|
||||
/**
|
||||
* 声明分析依赖和失效信息
|
||||
*/
|
||||
void getAnalysisUsage(std::set<void*>& analysisDependencies,
|
||||
std::set<void*>& analysisInvalidations) const override;
|
||||
|
||||
void* getPassID() const override { return &ID; }
|
||||
|
||||
private:
|
||||
IRBuilder* builder;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
@ -1,114 +0,0 @@
|
||||
#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
|
||||
@ -1,59 +0,0 @@
|
||||
#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
|
||||
@ -1,157 +0,0 @@
|
||||
#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
|
||||
@ -1,101 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "IR.h"
|
||||
#include "IRBuilder.h"
|
||||
#include "Pass.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 优化前对SysY IR的预处理,也可以视作部分CFG优化
|
||||
// 主要包括删除无用指令、合并基本块、删除空块等
|
||||
// 这些操作可以在SysY IR生成时就完成,但为了简化IR生成过程,
|
||||
// 这里将其放在SysY IR生成后进行预处理
|
||||
// 同时兼容phi节点的处理,可以再mem2reg后再次调用优化
|
||||
|
||||
//TODO: 可增加的CFG优化和方法
|
||||
// - 检查基本块跳转关系正确性
|
||||
// - 简化条件分支(Branch Simplification),如条件恒真/恒假转为直接跳转
|
||||
// - 合并连续的跳转指令(Jump Threading)在合并不可达块中似乎已经实现了
|
||||
// - 基本块重排序(Block Reordering),提升局部性
|
||||
|
||||
// 辅助工具类,包含实际的CFG优化逻辑
|
||||
// 这些方法可以被独立的Pass调用
|
||||
class SysYCFGOptUtils {
|
||||
public:
|
||||
static bool SysYDelInstAfterBr(Function *func); // 删除br后面的指令
|
||||
static bool SysYDelEmptyBlock(Function *func, IRBuilder* pBuilder); // 空块删除
|
||||
static bool SysYDelNoPreBLock(Function *func); // 删除无前驱块(不可达块)
|
||||
static bool SysYBlockMerge(Function *func); // 合并基本块
|
||||
static bool SysYAddReturn(Function *func, IRBuilder* pBuilder); // 添加return指令
|
||||
static bool SysYCondBr2Br(Function *func, IRBuilder* pBuilder); // 条件分支转换为无条件分支
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
// 独立的CFG优化遍
|
||||
// ======================================================================
|
||||
|
||||
class SysYDelInstAfterBrPass : public OptimizationPass {
|
||||
public:
|
||||
static void *ID; // 唯一ID
|
||||
SysYDelInstAfterBrPass() : OptimizationPass("SysYDelInstAfterBrPass", Granularity::Function) {}
|
||||
bool runOnFunction(Function *F, AnalysisManager& AM) override;
|
||||
void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const override {
|
||||
// 这个优化可能改变CFG结构,使一些CFG相关的分析失效
|
||||
// 可以在这里指定哪些分析会失效,例如支配树、活跃变量等
|
||||
// analysisInvalidations.insert(DominatorTreeAnalysisPass::ID); // 示例
|
||||
}
|
||||
void *getPassID() const override { return &ID; }
|
||||
};
|
||||
|
||||
class SysYDelEmptyBlockPass : public OptimizationPass {
|
||||
private:
|
||||
IRBuilder *pBuilder;
|
||||
public:
|
||||
static void *ID;
|
||||
SysYDelEmptyBlockPass(IRBuilder *builder) : OptimizationPass("SysYDelEmptyBlockPass", Granularity::Function), pBuilder(builder) {}
|
||||
bool runOnFunction(Function *F, AnalysisManager& AM) override;
|
||||
void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const override {};
|
||||
void *getPassID() const override { return &ID; }
|
||||
};
|
||||
|
||||
class SysYDelNoPreBLockPass : public OptimizationPass {
|
||||
public:
|
||||
static void *ID;
|
||||
SysYDelNoPreBLockPass() : OptimizationPass("SysYDelNoPreBLockPass", Granularity::Function) {}
|
||||
bool runOnFunction(Function *F, AnalysisManager& AM) override;
|
||||
void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const override {};
|
||||
void *getPassID() const override { return &ID; }
|
||||
};
|
||||
|
||||
class SysYBlockMergePass : public OptimizationPass {
|
||||
public:
|
||||
static void *ID;
|
||||
SysYBlockMergePass() : OptimizationPass("SysYBlockMergePass", Granularity::Function) {}
|
||||
bool runOnFunction(Function *F, AnalysisManager& AM) override;
|
||||
void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const override {};
|
||||
void *getPassID() const override { return &ID; }
|
||||
};
|
||||
|
||||
class SysYAddReturnPass : public OptimizationPass {
|
||||
private:
|
||||
IRBuilder *pBuilder;
|
||||
public:
|
||||
static void *ID;
|
||||
SysYAddReturnPass(IRBuilder *builder) : OptimizationPass("SysYAddReturnPass", Granularity::Function), pBuilder(builder) {}
|
||||
bool runOnFunction(Function *F, AnalysisManager& AM) override;
|
||||
void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const override {};
|
||||
void *getPassID() const override { return &ID; }
|
||||
};
|
||||
|
||||
class SysYCondBr2BrPass : public OptimizationPass {
|
||||
private:
|
||||
IRBuilder *pBuilder;
|
||||
public:
|
||||
static void *ID;
|
||||
SysYCondBr2BrPass(IRBuilder *builder) : OptimizationPass("SysYCondBr2BrPass", Granularity::Function), pBuilder(builder) {}
|
||||
bool runOnFunction(Function *F, AnalysisManager& AM) override;
|
||||
void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const override {};
|
||||
void *getPassID() const override { return &ID; }
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
@ -1,112 +0,0 @@
|
||||
#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());
|
||||
}
|
||||
};
|
||||
|
||||
}// namespace sysy
|
||||
@ -1,344 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional> // For std::function
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <typeindex> // For std::type_index (although void* ID is more common in LLVM)
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
#include "IR.h"
|
||||
#include "IRBuilder.h"
|
||||
|
||||
extern int DEBUG; // 全局调试标志
|
||||
|
||||
namespace sysy {
|
||||
|
||||
//前向声明
|
||||
class PassManager;
|
||||
class AnalysisManager;
|
||||
|
||||
// 抽象基类:分析结果
|
||||
class AnalysisResultBase {
|
||||
public:
|
||||
virtual ~AnalysisResultBase() = default;
|
||||
};
|
||||
|
||||
// 抽象基类:Pass
|
||||
class Pass {
|
||||
public:
|
||||
enum class Granularity { Module, Function, BasicBlock };
|
||||
|
||||
enum class PassKind { Analysis, Optimization };
|
||||
|
||||
Pass(const std::string &name, Granularity g, PassKind k) : Name(name), G(g), K(k) {}
|
||||
virtual ~Pass() = default;
|
||||
|
||||
const std::string &getName() const { return Name; }
|
||||
Granularity getGranularity() const { return G; }
|
||||
PassKind getPassKind() const { return K; }
|
||||
|
||||
virtual bool runOnModule(Module *M, AnalysisManager& AM) { return false; }
|
||||
virtual bool runOnFunction(Function *F, AnalysisManager& AM) { return false; }
|
||||
virtual bool runOnBasicBlock(BasicBlock *BB, AnalysisManager& AM) { return false; }
|
||||
|
||||
// 所有 Pass 都必须提供一个唯一的 ID
|
||||
// 这通常是一个静态成员,并在 Pass 类外部定义
|
||||
virtual void *getPassID() const = 0;
|
||||
|
||||
protected:
|
||||
std::string Name;
|
||||
Granularity G;
|
||||
PassKind K;
|
||||
};
|
||||
|
||||
// 抽象基类:分析遍
|
||||
class AnalysisPass : public Pass {
|
||||
public:
|
||||
AnalysisPass(const std::string &name, Granularity g) : Pass(name, g, PassKind::Analysis) {}
|
||||
|
||||
virtual std::unique_ptr<AnalysisResultBase> getResult() = 0;
|
||||
};
|
||||
|
||||
// 抽象基类:优化遍
|
||||
class OptimizationPass : public Pass {
|
||||
public:
|
||||
OptimizationPass(const std::string &name, Granularity g) : Pass(name, g, PassKind::Optimization) {}
|
||||
|
||||
virtual void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
|
||||
// 默认不依赖也不修改任何分析
|
||||
}
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
// PassRegistry: 全局 Pass 注册表 (单例)
|
||||
// ======================================================================
|
||||
class PassRegistry {
|
||||
public:
|
||||
// Pass 工厂函数类型:返回 Pass 的唯一指针
|
||||
using PassFactory = std::function<std::unique_ptr<Pass>()>;
|
||||
|
||||
// 获取 PassRegistry 实例 (单例模式)
|
||||
static PassRegistry &getPassRegistry() {
|
||||
static PassRegistry instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
// 注册一个 Pass
|
||||
// passID 是 Pass 类的唯一静态 ID (例如 MyPass::ID 的地址)
|
||||
// factory 是一个 lambda 或函数指针,用于创建该 Pass 的实例
|
||||
void registerPass(void *passID, PassFactory factory) {
|
||||
if (factories.count(passID)) {
|
||||
// Error: Pass with this ID already registered
|
||||
// You might want to throw an exception or log an error
|
||||
return;
|
||||
}
|
||||
factories[passID] = std::move(factory);
|
||||
}
|
||||
|
||||
// 通过 Pass ID 创建一个 Pass 实例
|
||||
std::unique_ptr<Pass> createPass(void *passID) {
|
||||
auto it = factories.find(passID);
|
||||
if (it == factories.end()) {
|
||||
// Error: Pass with this ID not registered
|
||||
return nullptr;
|
||||
}
|
||||
return it->second(); // 调用工厂函数创建实例
|
||||
}
|
||||
|
||||
private:
|
||||
PassRegistry() = default; // 私有构造函数,实现单例
|
||||
~PassRegistry() = default;
|
||||
PassRegistry(const PassRegistry &) = delete; // 禁用拷贝构造
|
||||
PassRegistry &operator=(const PassRegistry &) = delete; // 禁用赋值操作
|
||||
|
||||
std::map<void *, PassFactory> factories;
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
// AnalysisManager: 负责管理和提供分析结果
|
||||
// ======================================================================
|
||||
class AnalysisManager {
|
||||
private:
|
||||
Module *pModuleRef; // 指向被分析的Module
|
||||
|
||||
// 缓存不同粒度的分析结果
|
||||
std::map<void *, std::unique_ptr<AnalysisResultBase>> moduleCachedResults;
|
||||
std::map<std::pair<Function *, void *>, std::unique_ptr<AnalysisResultBase>> functionCachedResults;
|
||||
std::map<std::pair<BasicBlock *, void *>, std::unique_ptr<AnalysisResultBase>> basicBlockCachedResults;
|
||||
|
||||
|
||||
public:
|
||||
// 构造函数接收 Module 指针
|
||||
AnalysisManager(Module *M) : pModuleRef(M) {}
|
||||
AnalysisManager() = delete; // 禁止无参构造
|
||||
|
||||
~AnalysisManager() = default;
|
||||
|
||||
// 获取分析结果的通用模板函数
|
||||
// T 是 AnalysisResult 的具体类型,E 是 AnalysisPass 的具体类型
|
||||
// F 和 BB 参数用于提供上下文,根据分析遍的粒度来使用
|
||||
template <typename T, typename E> T *getAnalysisResult(Function *F = nullptr, BasicBlock *BB = nullptr) {
|
||||
void *analysisID = E::ID; // 获取分析遍的唯一 ID
|
||||
|
||||
// 尝试从注册表创建分析遍实例
|
||||
std::unique_ptr<Pass> basePass = PassRegistry::getPassRegistry().createPass(analysisID);
|
||||
if (!basePass) {
|
||||
// Error: Analysis pass not registered
|
||||
std::cerr << "Error: Analysis pass with ID " << analysisID << " not registered.\n";
|
||||
return nullptr;
|
||||
}
|
||||
AnalysisPass *analysisPass = static_cast<AnalysisPass *>(basePass.get());
|
||||
|
||||
// 根据分析遍的粒度处理
|
||||
switch (analysisPass->getGranularity()) {
|
||||
case Pass::Granularity::Module: {
|
||||
// 检查是否已存在有效结果
|
||||
auto it = moduleCachedResults.find(analysisID);
|
||||
if (it != moduleCachedResults.end()) {
|
||||
if(DEBUG) {
|
||||
std::cout << "Using cached result for Analysis Pass: " << analysisPass->getName() << "\n";
|
||||
}
|
||||
return static_cast<T *>(it->second.get()); // 返回缓存结果
|
||||
}
|
||||
// 只有在实际运行时才打印调试信息
|
||||
if(DEBUG){
|
||||
std::cout << "Running Analysis Pass: " << analysisPass->getName() << "\n";
|
||||
}
|
||||
// 运行模块级分析遍
|
||||
if (!pModuleRef) {
|
||||
std::cerr << "Error: Module reference not set for AnalysisManager to run Module Pass.\n";
|
||||
return nullptr;
|
||||
}
|
||||
analysisPass->runOnModule(pModuleRef, *this);
|
||||
// 获取结果并缓存
|
||||
std::unique_ptr<AnalysisResultBase> result = analysisPass->getResult();
|
||||
T *specificResult = static_cast<T *>(result.get());
|
||||
moduleCachedResults[analysisID] = std::move(result); // 缓存结果
|
||||
return specificResult;
|
||||
}
|
||||
case Pass::Granularity::Function: {
|
||||
// 检查请求的上下文是否正确
|
||||
if (!F) {
|
||||
std::cerr << "Error: Function context required for Function-level Analysis Pass.\n";
|
||||
return nullptr;
|
||||
}
|
||||
// 检查是否已存在有效结果
|
||||
auto it = functionCachedResults.find({F, analysisID});
|
||||
if (it != functionCachedResults.end()) {
|
||||
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);
|
||||
// 获取结果并缓存
|
||||
std::unique_ptr<AnalysisResultBase> result = analysisPass->getResult();
|
||||
T *specificResult = static_cast<T *>(result.get());
|
||||
functionCachedResults[{F, analysisID}] = std::move(result); // 缓存结果
|
||||
return specificResult;
|
||||
}
|
||||
case Pass::Granularity::BasicBlock: {
|
||||
// 检查请求的上下文是否正确
|
||||
if (!BB) {
|
||||
std::cerr << "Error: BasicBlock context required for BasicBlock-level Analysis Pass.\n";
|
||||
return nullptr;
|
||||
}
|
||||
// 检查是否已存在有效结果
|
||||
auto it = basicBlockCachedResults.find({BB, analysisID});
|
||||
if (it != basicBlockCachedResults.end()) {
|
||||
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);
|
||||
// 获取结果并缓存
|
||||
std::unique_ptr<AnalysisResultBase> result = analysisPass->getResult();
|
||||
T *specificResult = static_cast<T *>(result.get());
|
||||
basicBlockCachedResults[{BB, analysisID}] = std::move(result); // 缓存结果
|
||||
return specificResult;
|
||||
}
|
||||
}
|
||||
return nullptr; // 不会到达这里
|
||||
}
|
||||
|
||||
// 使所有分析结果失效 (当 IR 被修改时调用)
|
||||
void invalidateAllAnalyses() {
|
||||
moduleCachedResults.clear();
|
||||
functionCachedResults.clear();
|
||||
basicBlockCachedResults.clear();
|
||||
}
|
||||
|
||||
// 使特定分析结果失效
|
||||
// void *analysisID: 要失效的分析的ID
|
||||
// Function *F: 如果是函数级分析,指定函数;如果是模块级或基本块级,则为nullptr (取决于调用方式)
|
||||
// BasicBlock *BB: 如果是基本块级分析,指定基本块;否则为nullptr
|
||||
void invalidateAnalysis(void *analysisID, Function *F = nullptr, BasicBlock *BB = nullptr) {
|
||||
if (BB) {
|
||||
// 使特定基本块的特定分析结果失效
|
||||
basicBlockCachedResults.erase({BB, analysisID});
|
||||
} else if (F) {
|
||||
// 使特定函数的特定分析结果失效 (也可能包含聚合的BasicBlock结果)
|
||||
functionCachedResults.erase({F, analysisID});
|
||||
// 遍历所有属于F的基本块,使其BasicBlockCache失效 (如果该分析是BasicBlock粒度的)
|
||||
// 这需要遍历F的所有基本块,效率较低,更推荐在BasicBlockPass的invalidateAnalysisUsage中精确指定
|
||||
// 或者在Function级别的invalidate时,清空该Function的所有BasicBlock分析
|
||||
// 这里的实现简单地清空该Function下所有该ID的BasicBlock缓存
|
||||
for (auto it = basicBlockCachedResults.begin(); it != basicBlockCachedResults.end(); ) {
|
||||
// 假设BasicBlock::getParent()方法存在,可以获取所属Function
|
||||
if (it->first.second == analysisID /* && it->first.first->getParent() == F */) { // 需要BasicBlock能获取其父函数
|
||||
it = basicBlockCachedResults.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// 使所有函数的特定分析结果失效 (Module级和所有Function/BasicBlock级)
|
||||
moduleCachedResults.erase(analysisID);
|
||||
for (auto it = functionCachedResults.begin(); it != functionCachedResults.end(); ) {
|
||||
if (it->first.second == analysisID) {
|
||||
it = functionCachedResults.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
for (auto it = basicBlockCachedResults.begin(); it != basicBlockCachedResults.end(); ) {
|
||||
if (it->first.second == analysisID) {
|
||||
it = basicBlockCachedResults.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
// PassManager:遍管理器
|
||||
// ======================================================================
|
||||
class PassManager {
|
||||
private:
|
||||
std::vector<std::unique_ptr<Pass>> passes;
|
||||
AnalysisManager analysisManager;
|
||||
Module *pmodule;
|
||||
IRBuilder *pBuilder;
|
||||
|
||||
public:
|
||||
PassManager() = delete;
|
||||
~PassManager() = default;
|
||||
|
||||
PassManager(Module *module, IRBuilder *builder) : pmodule(module) ,pBuilder(builder), analysisManager(module) {}
|
||||
|
||||
// 运行所有注册的遍
|
||||
bool run();
|
||||
|
||||
// 运行优化管道主要负责注册和运行优化遍
|
||||
// 这里可以根据 optLevel 和 DEBUG 控制不同的优化遍
|
||||
void runOptimizationPipeline(Module* moduleIR, IRBuilder* builder, int optLevel);
|
||||
|
||||
// 添加遍:现在接受 Pass 的 ID,而不是直接的 unique_ptr
|
||||
void addPass(void *passID);
|
||||
|
||||
AnalysisManager &getAnalysisManager() { return analysisManager; }
|
||||
|
||||
void clearPasses();
|
||||
|
||||
// 输出pass列表并打印IR信息供观察优化遍效果
|
||||
void printPasses() const;
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
// 辅助宏或函数,用于简化 Pass 的注册
|
||||
// ======================================================================
|
||||
|
||||
// 用于分析遍的注册
|
||||
template <typename AnalysisPassType> void registerAnalysisPass();
|
||||
|
||||
// (1) 针对需要 IRBuilder 参数的优化遍的重载
|
||||
// 这个模板只在 OptimizationPassType 可以通过 IRBuilder* 构造时才有效
|
||||
template <typename OptimizationPassType, typename std::enable_if<
|
||||
std::is_constructible<OptimizationPassType, IRBuilder*>::value, int>::type = 0>
|
||||
void registerOptimizationPass(IRBuilder* builder);
|
||||
|
||||
// (2) 针对不需要 IRBuilder 参数的所有其他优化遍的重载
|
||||
// 这个模板只在 OptimizationPassType 不能通过 IRBuilder* 构造时才有效
|
||||
template <typename OptimizationPassType, typename std::enable_if<
|
||||
!std::is_constructible<OptimizationPassType, IRBuilder*>::value, int>::type = 0>
|
||||
void registerOptimizationPass();
|
||||
|
||||
} // namespace sysy
|
||||
@ -1,36 +0,0 @@
|
||||
# src/midend/CMakeLists.txt
|
||||
add_library(midend_lib STATIC
|
||||
IR.cpp
|
||||
SysYIRGenerator.cpp
|
||||
SysYIRPrinter.cpp
|
||||
Pass/Pass.cpp
|
||||
Pass/Analysis/Dom.cpp
|
||||
Pass/Analysis/Liveness.cpp
|
||||
Pass/Analysis/Loop.cpp
|
||||
Pass/Analysis/LoopCharacteristics.cpp
|
||||
Pass/Analysis/LoopVectorization.cpp
|
||||
Pass/Analysis/AliasAnalysis.cpp
|
||||
Pass/Analysis/SideEffectAnalysis.cpp
|
||||
Pass/Analysis/CallGraphAnalysis.cpp
|
||||
Pass/Optimize/DCE.cpp
|
||||
Pass/Optimize/Mem2Reg.cpp
|
||||
Pass/Optimize/Reg2Mem.cpp
|
||||
Pass/Optimize/SysYIRCFGOpt.cpp
|
||||
Pass/Optimize/SCCP.cpp
|
||||
Pass/Optimize/LoopNormalization.cpp
|
||||
Pass/Optimize/LICM.cpp
|
||||
Pass/Optimize/LoopStrengthReduction.cpp
|
||||
Pass/Optimize/InductionVariableElimination.cpp
|
||||
Pass/Optimize/BuildCFG.cpp
|
||||
Pass/Optimize/LargeArrayToGlobal.cpp
|
||||
)
|
||||
|
||||
# 包含中端模块所需的头文件路径
|
||||
target_include_directories(midend_lib PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../include/midend # 中端顶层头文件
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../include/midend/Pass # 增加 Pass 头文件路径
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../include/midend/Pass/Analysis # 增加 Pass/Analysis 头文件路径
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../include/midend/Pass/Optimize # 增加 Pass/Optimize 头文件路径
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../include/frontend # 增加 frontend 头文件路径 (已存在)
|
||||
${ANTLR_RUNTIME}/runtime/src # ANTLR运行时库头文件
|
||||
)
|
||||
1443
src/midend/IR.cpp
1443
src/midend/IR.cpp
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user