Compare commits
14 Commits
backend-fl
...
midend-SCC
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c268191826 | ||
|
|
0f1fcc835d | ||
|
|
c5af4f1c49 | ||
|
|
9a53e1b917 | ||
|
|
ef09bc70d4 | ||
|
|
aed4577490 | ||
|
|
35b421b60b | ||
|
|
f3f603a032 | ||
|
|
de0f8422e9 | ||
|
|
35691ab7bc | ||
|
|
61768fa180 | ||
|
|
520ebd96f0 | ||
|
|
6868f638d7 | ||
|
|
206a0af424 |
220
Pass_ID_List.md
220
Pass_ID_List.md
@@ -14,10 +14,220 @@
|
||||
|
||||
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> 或独立的浮点常量存储来处理浮点数。
|
||||
|
||||
|
||||
# 后续优化可能涉及的改动
|
||||
|
||||
@@ -25,4 +235,12 @@ Mem2Reg 遍的主要目标是将那些不必要的、只用于局部标量变量
|
||||
|
||||
好处:优化友好性,方便mem2reg提升
|
||||
目前没有实现这个机制,如果想要实现首先解决同一函数不同域的同名变量命名区分
|
||||
需要保证符号表能正确维护域中的局部变量
|
||||
需要保证符号表能正确维护域中的局部变量
|
||||
|
||||
|
||||
# 关于中端优化提升编译器性能的TODO
|
||||
|
||||
## usedelete_withinstdelte方法
|
||||
|
||||
这个方法删除了use关系并移除了指令,逻辑是根据Instruction* inst去find对应的迭代器并erase
|
||||
有些情况下外部持有迭代器和inst,可以省略find过程
|
||||
@@ -1,8 +1,6 @@
|
||||
#include "CalleeSavedHandler.h"
|
||||
#include <set>
|
||||
#include <vector> //
|
||||
#include <algorithm>
|
||||
#include <iterator> //
|
||||
|
||||
namespace sysy {
|
||||
|
||||
@@ -16,34 +14,23 @@ bool CalleeSavedHandler::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
// 此 Pass 负责分析、分配栈空间并插入 callee-saved 寄存器的保存/恢复指令。
|
||||
// 它通过与 FrameInfo 协作,确保为 callee-saved 寄存器分配的空间与局部变量/溢出槽的空间不冲突。
|
||||
|
||||
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
||||
|
||||
// [修改] 分别记录被使用的整数和浮点被调用者保存寄存器
|
||||
std::set<PhysicalReg> used_int_callee_saved;
|
||||
std::set<PhysicalReg> used_fp_callee_saved;
|
||||
// 这样做可以使生成的 sd/ld 指令能被后续的优化 Pass (如 PostRA-Scheduler) 处理。
|
||||
|
||||
// 1. 扫描所有指令,找出被使用的s寄存器 (s1-s11) 和 fs寄存器 (fs0-fs11)
|
||||
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
||||
std::set<PhysicalReg> used_callee_saved;
|
||||
|
||||
// 1. 扫描所有指令,找出被使用的s寄存器 (s1-s11)
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
for (auto& instr : mbb->getInstructions()) {
|
||||
for (auto& op : instr->getOperands()) {
|
||||
|
||||
auto check_and_insert_reg = [&](RegOperand* reg_op) {
|
||||
if (!reg_op->isVirtual()) {
|
||||
PhysicalReg preg = reg_op->getPReg();
|
||||
|
||||
// [修改] 区分整数和浮点被调用者保存寄存器
|
||||
// s0 由序言/尾声处理器专门处理,这里不计入
|
||||
if (preg >= PhysicalReg::S1 && preg <= PhysicalReg::S11) {
|
||||
used_int_callee_saved.insert(preg);
|
||||
}
|
||||
// fs0-fs11 在我们的枚举中对应 f8,f9,f18-f27
|
||||
else if ((preg >= PhysicalReg::F8 && preg <= PhysicalReg::F9) || (preg >= PhysicalReg::F18 && preg <= PhysicalReg::F27)) {
|
||||
used_fp_callee_saved.insert(preg);
|
||||
used_callee_saved.insert(preg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
check_and_insert_reg(static_cast<RegOperand*>(op.get()));
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
@@ -53,109 +40,83 @@ void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有使用任何需要处理的 callee-saved 寄存器,则直接返回
|
||||
if (used_int_callee_saved.empty() && used_fp_callee_saved.empty()) {
|
||||
if (used_callee_saved.empty()) {
|
||||
frame_info.callee_saved_size = 0; // 确保大小被初始化
|
||||
return;
|
||||
return; // 无需操作
|
||||
}
|
||||
|
||||
// 2. 计算为 callee-saved 寄存器分配的栈空间大小
|
||||
// 每个寄存器在RV64中都占用8字节
|
||||
int callee_saved_size = (used_int_callee_saved.size() + used_fp_callee_saved.size()) * 8;
|
||||
frame_info.callee_saved_size = callee_saved_size;
|
||||
// 2. 计算为 callee-saved 寄存器分配的栈空间
|
||||
// 这里的关键是,偏移的基准点要在局部变量和溢出槽之下。
|
||||
int callee_saved_size = used_callee_saved.size() * 8;
|
||||
frame_info.callee_saved_size = callee_saved_size; // 将大小存入 FrameInfo
|
||||
|
||||
// 3. 在函数序言中插入保存指令
|
||||
// 3. 计算无冲突的栈偏移
|
||||
// 栈向下增长,所以偏移是负数。
|
||||
// ra/s0 占用 -8 和 -16。局部变量和溢出区在它们之下。callee-saved 区在更下方。
|
||||
// 我们使用相对于 s0 的偏移。s0 将指向栈顶 (sp + total_size)。
|
||||
int base_offset = -16 - frame_info.locals_size - frame_info.spill_size;
|
||||
|
||||
// 为了栈帧布局确定性,对寄存器进行排序
|
||||
std::vector<PhysicalReg> sorted_regs(used_callee_saved.begin(), used_callee_saved.end());
|
||||
std::sort(sorted_regs.begin(), sorted_regs.end());
|
||||
|
||||
// 4. 在函数序言插入保存指令
|
||||
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
|
||||
auto& entry_instrs = entry_block->getInstructions();
|
||||
// 插入点通常在函数入口标签之后
|
||||
auto insert_pos = entry_instrs.begin();
|
||||
if (!entry_instrs.empty() && entry_instrs.front()->getOpcode() == RVOpcodes::LABEL) {
|
||||
insert_pos = std::next(insert_pos);
|
||||
}
|
||||
auto prologue_end = entry_instrs.begin();
|
||||
|
||||
// 为了布局确定性,对寄存器进行排序并按序保存
|
||||
std::vector<PhysicalReg> sorted_int_regs(used_int_callee_saved.begin(), used_int_callee_saved.end());
|
||||
std::vector<PhysicalReg> sorted_fp_regs(used_fp_callee_saved.begin(), used_fp_callee_saved.end());
|
||||
std::sort(sorted_int_regs.begin(), sorted_int_regs.end());
|
||||
std::sort(sorted_fp_regs.begin(), sorted_fp_regs.end());
|
||||
|
||||
std::vector<std::unique_ptr<MachineInstr>> save_instrs;
|
||||
int current_offset = -16; // ra和s0已占用-8和-16,从-24开始分配
|
||||
// 找到序言结束的位置(通常是addi s0, sp, size之后,但为了让优化器看到,我们插在更前面)
|
||||
// 合理的位置是在 IR 指令开始之前,即在任何非序言指令(如第一个标签)之前。
|
||||
// 为简单起见,我们直接插入到块的开头,后续重排 pass 会处理。
|
||||
// (更优的实现会寻找一个特定的插入点)
|
||||
|
||||
// 准备整数保存指令 (sd)
|
||||
for (PhysicalReg reg : sorted_int_regs) {
|
||||
current_offset -= 8;
|
||||
int current_offset = base_offset;
|
||||
for (PhysicalReg reg : sorted_regs) {
|
||||
auto sd = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
||||
sd->addOperand(std::make_unique<RegOperand>(reg));
|
||||
sd->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0), // 基址为帧指针 s0
|
||||
std::make_unique<ImmOperand>(current_offset)
|
||||
));
|
||||
save_instrs.push_back(std::move(sd));
|
||||
}
|
||||
|
||||
// 准备浮点保存指令 (fsd)
|
||||
for (PhysicalReg reg : sorted_fp_regs) {
|
||||
// 从头部插入,但要放在函数标签之后
|
||||
entry_instrs.insert(entry_instrs.begin() + 1, std::move(sd));
|
||||
current_offset -= 8;
|
||||
auto fsd = std::make_unique<MachineInstr>(RVOpcodes::FSD); // 使用浮点保存指令
|
||||
fsd->addOperand(std::make_unique<RegOperand>(reg));
|
||||
fsd->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(current_offset)
|
||||
));
|
||||
save_instrs.push_back(std::move(fsd));
|
||||
}
|
||||
|
||||
// 一次性插入所有保存指令
|
||||
if (!save_instrs.empty()) {
|
||||
entry_instrs.insert(insert_pos,
|
||||
std::make_move_iterator(save_instrs.begin()),
|
||||
std::make_move_iterator(save_instrs.end()));
|
||||
}
|
||||
|
||||
// 4. 在函数结尾(ret之前)插入恢复指令
|
||||
// 5. 在函数结尾(ret之前)插入恢复指令,使用反向遍历来避免迭代器失效
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
// 使用手动控制的反向循环
|
||||
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
|
||||
if ((*it)->getOpcode() == RVOpcodes::RET) {
|
||||
// 1. 创建一个临时vector来存储所有需要插入的恢复指令
|
||||
std::vector<std::unique_ptr<MachineInstr>> restore_instrs;
|
||||
current_offset = -16; // 重置偏移量用于恢复
|
||||
|
||||
// 准备恢复整数寄存器 (ld) - 以与保存时相同的顺序
|
||||
for (PhysicalReg reg : sorted_int_regs) {
|
||||
current_offset -= 8;
|
||||
int current_offset_load = base_offset;
|
||||
// 以相同的顺序(例如 s1, s2, ...)创建恢复指令
|
||||
for (PhysicalReg reg : sorted_regs) {
|
||||
auto ld = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
||||
ld->addOperand(std::make_unique<RegOperand>(reg));
|
||||
ld->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(current_offset)
|
||||
std::make_unique<ImmOperand>(current_offset_load)
|
||||
));
|
||||
restore_instrs.push_back(std::move(ld));
|
||||
current_offset_load -= 8;
|
||||
}
|
||||
|
||||
// 准备恢复浮点寄存器 (fld)
|
||||
for (PhysicalReg reg : sorted_fp_regs) {
|
||||
current_offset -= 8;
|
||||
auto fld = std::make_unique<MachineInstr>(RVOpcodes::FLD); // 使用浮点加载指令
|
||||
fld->addOperand(std::make_unique<RegOperand>(reg));
|
||||
fld->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(current_offset)
|
||||
));
|
||||
restore_instrs.push_back(std::move(fld));
|
||||
}
|
||||
|
||||
// 一次性插入所有恢复指令
|
||||
// 2. 使用 make_move_iterator 一次性将所有恢复指令插入到 RET 指令之前
|
||||
// 这可以高效地转移指令的所有权,并且只让迭代器失效一次。
|
||||
if (!restore_instrs.empty()) {
|
||||
mbb->getInstructions().insert(it,
|
||||
std::make_move_iterator(restore_instrs.begin()),
|
||||
std::make_move_iterator(restore_instrs.end()));
|
||||
mbb->getInstructions().insert(it,
|
||||
std::make_move_iterator(restore_instrs.begin()),
|
||||
std::make_move_iterator(restore_instrs.end())
|
||||
);
|
||||
}
|
||||
|
||||
// 处理完一个基本块的RET后,迭代器已失效,需跳出当前块的循环
|
||||
goto next_block_label;
|
||||
|
||||
// 找到了RET并处理完毕后,就可以跳出内层循环,继续寻找下一个基本块
|
||||
break;
|
||||
}
|
||||
}
|
||||
next_block_label:;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,8 +52,6 @@ void LegalizeImmediatesPass::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
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())) {
|
||||
@@ -75,7 +73,7 @@ void LegalizeImmediatesPass::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
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);
|
||||
@@ -94,8 +92,7 @@ void LegalizeImmediatesPass::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
// 处理所有内存加载/存储指令
|
||||
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::SB: case RVOpcodes::SH: case RVOpcodes::SW: case RVOpcodes::SD: {
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
auto mem_op = static_cast<MemOperand*>(operands.back().get());
|
||||
auto offset_op = mem_op->getOffset();
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include "PrologueEpilogueInsertion.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include "RISCv64RegAlloc.h" // 需要访问RegAlloc的结果
|
||||
|
||||
namespace sysy {
|
||||
|
||||
@@ -8,13 +6,7 @@ char PrologueEpilogueInsertionPass::ID = 0;
|
||||
|
||||
void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
||||
Function* F = mfunc->getFunc();
|
||||
RISCv64ISel* isel = mfunc->getISel();
|
||||
|
||||
// [关键] 获取寄存器分配的结果 (vreg -> preg 的映射)
|
||||
// RegAlloc Pass 必须已经运行过
|
||||
auto& vreg_to_preg_map = frame_info.vreg_to_preg_map;
|
||||
|
||||
// 完全遵循 AsmPrinter 中的计算逻辑
|
||||
int total_stack_size = frame_info.locals_size +
|
||||
frame_info.spill_size +
|
||||
@@ -32,6 +24,7 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
|
||||
|
||||
std::vector<std::unique_ptr<MachineInstr>> prologue_instrs;
|
||||
|
||||
// 严格按照 AsmPrinter 的打印顺序来创建和组织指令
|
||||
// 1. addi sp, sp, -aligned_stack_size
|
||||
auto alloc_stack = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
alloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
@@ -64,63 +57,10 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
|
||||
set_fp->addOperand(std::make_unique<ImmOperand>(aligned_stack_size));
|
||||
prologue_instrs.push_back(std::move(set_fp));
|
||||
|
||||
// --- [正确逻辑] 在s0设置完毕后,使用物理寄存器加载栈参数 ---
|
||||
if (F && isel) {
|
||||
// 定义暂存寄存器
|
||||
const PhysicalReg INT_SCRATCH_REG = PhysicalReg::T5;
|
||||
const PhysicalReg FP_SCRATCH_REG = PhysicalReg::F7;
|
||||
|
||||
int arg_idx = 0;
|
||||
for (Argument* arg : F->getArguments()) {
|
||||
if (arg_idx >= 8) {
|
||||
unsigned vreg = isel->getVReg(arg);
|
||||
|
||||
// 确认RegAlloc已经为这个vreg计算了偏移量,并且分配了物理寄存器
|
||||
if (frame_info.alloca_offsets.count(vreg) && vreg_to_preg_map.count(vreg)) {
|
||||
int offset = frame_info.alloca_offsets.at(vreg);
|
||||
PhysicalReg dest_preg = vreg_to_preg_map.at(vreg);
|
||||
Type* arg_type = arg->getType();
|
||||
|
||||
// 根据类型执行不同的加载序列
|
||||
if (arg_type->isFloat()) {
|
||||
// 1. flw ft7, offset(s0)
|
||||
auto load_arg = std::make_unique<MachineInstr>(RVOpcodes::FLW);
|
||||
load_arg->addOperand(std::make_unique<RegOperand>(FP_SCRATCH_REG));
|
||||
load_arg->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(offset)
|
||||
));
|
||||
prologue_instrs.push_back(std::move(load_arg));
|
||||
// 2. fmv.s dest_preg, ft7
|
||||
auto move_arg = std::make_unique<MachineInstr>(RVOpcodes::FMV_S);
|
||||
move_arg->addOperand(std::make_unique<RegOperand>(dest_preg));
|
||||
move_arg->addOperand(std::make_unique<RegOperand>(FP_SCRATCH_REG));
|
||||
prologue_instrs.push_back(std::move(move_arg));
|
||||
} else {
|
||||
// 确定是加载32位(lw)还是64位(ld)
|
||||
RVOpcodes load_op = arg_type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW;
|
||||
// 1. lw/ld t5, offset(s0)
|
||||
auto load_arg = std::make_unique<MachineInstr>(load_op);
|
||||
load_arg->addOperand(std::make_unique<RegOperand>(INT_SCRATCH_REG));
|
||||
load_arg->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(offset)
|
||||
));
|
||||
prologue_instrs.push_back(std::move(load_arg));
|
||||
// 2. mv dest_preg, t5
|
||||
auto move_arg = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
move_arg->addOperand(std::make_unique<RegOperand>(dest_preg));
|
||||
move_arg->addOperand(std::make_unique<RegOperand>(INT_SCRATCH_REG));
|
||||
prologue_instrs.push_back(std::move(move_arg));
|
||||
}
|
||||
}
|
||||
}
|
||||
arg_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
// 确定插入点
|
||||
// 确定插入点(在函数名标签之后)
|
||||
auto insert_pos = entry_instrs.begin();
|
||||
// [重要] 这里我们不再需要跳过LABEL,因为AsmPrinter将不再打印函数名标签
|
||||
// 第一个基本块的标签就是函数入口
|
||||
|
||||
// 一次性将所有序言指令插入
|
||||
if (!prologue_instrs.empty()) {
|
||||
@@ -129,13 +69,14 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
|
||||
std::make_move_iterator(prologue_instrs.end()));
|
||||
}
|
||||
|
||||
// --- 2. 插入尾声 (此部分逻辑保持不变) ---
|
||||
// --- 2. 插入尾声 ---
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
|
||||
if ((*it)->getOpcode() == RVOpcodes::RET) {
|
||||
std::vector<std::unique_ptr<MachineInstr>> epilogue_instrs;
|
||||
|
||||
// 1. ld ra
|
||||
// 同样严格按照 AsmPrinter 的打印顺序
|
||||
// 1. ld ra, (aligned_stack_size - 8)(sp)
|
||||
auto restore_ra = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
||||
restore_ra->addOperand(std::make_unique<RegOperand>(PhysicalReg::RA));
|
||||
restore_ra->addOperand(std::make_unique<MemOperand>(
|
||||
@@ -144,7 +85,7 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
|
||||
));
|
||||
epilogue_instrs.push_back(std::move(restore_ra));
|
||||
|
||||
// 2. ld s0
|
||||
// 2. ld s0, (aligned_stack_size - 16)(sp)
|
||||
auto restore_fp = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
||||
restore_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
restore_fp->addOperand(std::make_unique<MemOperand>(
|
||||
@@ -165,6 +106,7 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
|
||||
std::make_move_iterator(epilogue_instrs.begin()),
|
||||
std::make_move_iterator(epilogue_instrs.end()));
|
||||
}
|
||||
// 处理完一个基本块中的RET后,迭代器已失效,需跳出
|
||||
goto next_block;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "PostRA_Scheduler.h"
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#define MAX_SCHEDULING_BLOCK_SIZE 10000 // 限制调度块大小,避免过大导致性能问题
|
||||
|
||||
namespace sysy {
|
||||
@@ -10,407 +10,374 @@ 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;
|
||||
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 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;
|
||||
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() &&
|
||||
// 获取指令定义的寄存器 - 修复版本
|
||||
std::set<PhysicalReg> getDefinedRegisters(MachineInstr* instr) {
|
||||
std::set<PhysicalReg> defined_regs;
|
||||
RVOpcodes opcode = instr->getOpcode();
|
||||
|
||||
// 特殊处理CALL指令
|
||||
if (opcode == RVOpcodes::CALL) {
|
||||
// CALL指令可能定义返回值寄存器
|
||||
if (!instr->getOperands().empty() &&
|
||||
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
defined_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
}
|
||||
return defined_regs;
|
||||
}
|
||||
|
||||
// 存储指令不定义寄存器
|
||||
if (isStoreInstr(instr)) {
|
||||
return defined_regs;
|
||||
}
|
||||
|
||||
// 分支指令不定义寄存器
|
||||
if (opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
|
||||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
|
||||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
|
||||
opcode == RVOpcodes::J || opcode == RVOpcodes::RET) {
|
||||
return defined_regs;
|
||||
}
|
||||
|
||||
// 对于其他指令,第一个寄存器操作数通常是定义的
|
||||
if (!instr->getOperands().empty() &&
|
||||
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op =
|
||||
static_cast<RegOperand *>(instr->getOperands().front().get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
defined_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
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; // 跳过返回值寄存器
|
||||
// 获取指令使用的寄存器 - 修复版本
|
||||
std::set<PhysicalReg> getUsedRegisters(MachineInstr* instr) {
|
||||
std::set<PhysicalReg> used_regs;
|
||||
RVOpcodes opcode = instr->getOpcode();
|
||||
|
||||
// 特殊处理CALL指令
|
||||
if (opcode == RVOpcodes::CALL) {
|
||||
bool first_reg_skipped = false;
|
||||
for (const auto& op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
if (!first_reg_skipped) {
|
||||
first_reg_skipped = true;
|
||||
continue; // 跳过返回值寄存器
|
||||
}
|
||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
used_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// 对于存储指令,所有寄存器操作数都是使用的
|
||||
if (isStoreInstr(instr)) {
|
||||
for (const auto &op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand *>(op.get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
used_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto mem_op = static_cast<MemOperand *>(op.get());
|
||||
if (!mem_op->getBase()->isVirtual()) {
|
||||
used_regs.insert(mem_op->getBase()->getPReg());
|
||||
}
|
||||
}
|
||||
}
|
||||
return used_regs;
|
||||
}
|
||||
|
||||
// 对于分支指令,所有寄存器操作数都是使用的
|
||||
if (opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
|
||||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
|
||||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU) {
|
||||
for (const auto &op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand *>(op.get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
used_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
}
|
||||
}
|
||||
return used_regs;
|
||||
}
|
||||
|
||||
// 对于其他指令,除了第一个寄存器操作数(通常是定义),其余都是使用的
|
||||
bool first_reg = true;
|
||||
for (const auto &op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
if (first_reg) {
|
||||
first_reg = false;
|
||||
continue; // 跳过第一个寄存器(定义)
|
||||
}
|
||||
auto reg_op = static_cast<RegOperand *>(op.get());
|
||||
if (!reg_op->isVirtual()) {
|
||||
used_regs.insert(reg_op->getPReg());
|
||||
}
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto mem_op = static_cast<MemOperand *>(op.get());
|
||||
if (!mem_op->getBase()->isVirtual()) {
|
||||
used_regs.insert(mem_op->getBase()->getPReg());
|
||||
}
|
||||
}
|
||||
}
|
||||
return used_regs;
|
||||
}
|
||||
|
||||
// 获取内存访问的基址和偏移
|
||||
struct MemoryAccess {
|
||||
PhysicalReg base_reg;
|
||||
int64_t offset;
|
||||
bool valid;
|
||||
|
||||
MemoryAccess() : valid(false) {}
|
||||
MemoryAccess(PhysicalReg base, int64_t off) : base_reg(base), offset(off), valid(true) {}
|
||||
};
|
||||
|
||||
MemoryAccess getMemoryAccess(MachineInstr *instr) {
|
||||
if (!isLoadInstr(instr) && !isStoreInstr(instr)) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
// 查找内存操作数
|
||||
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());
|
||||
}
|
||||
// 检查内存依赖 - 加强版本
|
||||
bool hasMemoryDependency(MachineInstr* instr1, MachineInstr* instr2) {
|
||||
// 如果都不是内存指令,没有内存依赖
|
||||
if (!isLoadInstr(instr1) && !isStoreInstr(instr1) &&
|
||||
!isLoadInstr(instr2) && !isStoreInstr(instr2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
MemoryAccess mem1 = getMemoryAccess(instr1);
|
||||
MemoryAccess mem2 = getMemoryAccess(instr2);
|
||||
|
||||
if (!mem1.valid || !mem2.valid) {
|
||||
// 如果无法确定内存访问模式,保守地认为存在依赖
|
||||
return true;
|
||||
}
|
||||
|
||||
// 如果访问相同的内存位置
|
||||
if (mem1.base_reg == mem2.base_reg && mem1.offset == mem2.offset) {
|
||||
// Store->Load: RAW依赖
|
||||
// Load->Store: WAR依赖
|
||||
// Store->Store: WAW依赖
|
||||
return isStoreInstr(instr1) || isStoreInstr(instr2);
|
||||
}
|
||||
|
||||
// 不同内存位置通常没有依赖,但为了安全起见,
|
||||
// 如果涉及store指令,我们需要更保守
|
||||
if (isStoreInstr(instr1) && isLoadInstr(instr2)) {
|
||||
// 保守处理:不同store和load之间可能有别名
|
||||
return false; // 这里可以根据需要调整策略
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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写入的值
|
||||
// 检查两个指令之间是否存在依赖关系 - 修复版本
|
||||
bool hasDependency(MachineInstr* instr1, MachineInstr* instr2) {
|
||||
// 检查RAW依赖:instr1定义的寄存器是否被instr2使用
|
||||
auto defined_regs1 = getDefinedRegisters(instr1);
|
||||
auto used_regs2 = getUsedRegisters(instr2);
|
||||
|
||||
for (const auto& reg : defined_regs1) {
|
||||
if (used_regs2.find(reg) != used_regs2.end()) {
|
||||
return true; // RAW依赖 - instr2读取instr1写入的值
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查WAR依赖:instr1使用的寄存器是否被instr2定义
|
||||
for (const auto ® : info1.used_regs) {
|
||||
if (info2.defined_regs.find(reg) != info2.defined_regs.end()) {
|
||||
return true; // WAR依赖 - instr2覆盖instr1需要的值
|
||||
|
||||
// 检查WAR依赖:instr1使用的寄存器是否被instr2定义
|
||||
auto used_regs1 = getUsedRegisters(instr1);
|
||||
auto defined_regs2 = getDefinedRegisters(instr2);
|
||||
|
||||
for (const auto& reg : used_regs1) {
|
||||
if (defined_regs2.find(reg) != defined_regs2.end()) {
|
||||
return true; // WAR依赖 - instr2覆盖instr1需要的值
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查WAW依赖:两个指令定义相同寄存器
|
||||
for (const auto ® : info1.defined_regs) {
|
||||
if (info2.defined_regs.find(reg) != info2.defined_regs.end()) {
|
||||
return true; // WAW依赖 - 两条指令写入同一寄存器
|
||||
|
||||
// 检查WAW依赖:两个指令定义相同寄存器
|
||||
for (const auto& reg : defined_regs1) {
|
||||
if (defined_regs2.find(reg) != defined_regs2.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) {
|
||||
|
||||
// 检查内存依赖
|
||||
if (hasMemoryDependency(instr1, instr2)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 检查是否可以安全地将instr1和instr2交换位置
|
||||
bool canSwapInstructions(MachineInstr* instr1, MachineInstr* instr2) {
|
||||
// 不能移动控制流指令
|
||||
if (isControlFlowInstr(instr1) || isControlFlowInstr(instr2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查双向依赖关系
|
||||
return !hasDependency(instr1, instr2) && !hasDependency(instr2, instr1);
|
||||
}
|
||||
|
||||
// 在基本块内对指令进行调度优化 - 优化版本
|
||||
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;
|
||||
}
|
||||
// 新增:验证调度结果的正确性
|
||||
void validateSchedule(const std::vector<MachineInstr*>& instr_list) {
|
||||
for (int i = 0; i < (int)instr_list.size(); i++) {
|
||||
for (int j = i + 1; j < (int)instr_list.size(); j++) {
|
||||
MachineInstr* earlier = instr_list[i];
|
||||
MachineInstr* later = instr_list[j];
|
||||
|
||||
// 检查是否存在被违反的依赖关系
|
||||
auto defined_regs = getDefinedRegisters(earlier);
|
||||
auto used_regs = getUsedRegisters(later);
|
||||
|
||||
// 检查RAW依赖
|
||||
for (const auto& reg : defined_regs) {
|
||||
if (used_regs.find(reg) != used_regs.end()) {
|
||||
// 这是正常的依赖关系,earlier应该在later之前
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查内存依赖
|
||||
if (hasMemoryDependency(earlier, later)) {
|
||||
MemoryAccess mem1 = getMemoryAccess(earlier);
|
||||
MemoryAccess mem2 = getMemoryAccess(later);
|
||||
|
||||
if (mem1.valid && mem2.valid &&
|
||||
mem1.base_reg == mem2.base_reg && mem1.offset == mem2.offset) {
|
||||
if (isStoreInstr(earlier) && isLoadInstr(later)) {
|
||||
// Store->Load依赖,顺序正确
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 验证调度结果的正确性
|
||||
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 scheduleBlock(MachineBasicBlock* mbb) {
|
||||
auto& instructions = mbb->getInstructions();
|
||||
if (instructions.size() <= 1) return;
|
||||
if (instructions.size() > MAX_SCHEDULING_BLOCK_SIZE) {
|
||||
return; // 跳过超大块,防止卡住
|
||||
}
|
||||
|
||||
std::vector<MachineInstr*> instr_list;
|
||||
for (auto& instr : instructions) {
|
||||
instr_list.push_back(instr.get());
|
||||
}
|
||||
|
||||
// 使用更严格的调度策略,避免破坏依赖关系
|
||||
bool changed = true;
|
||||
int max_iterations = 10; // 限制迭代次数避免死循环
|
||||
int iteration = 0;
|
||||
|
||||
while (changed && iteration < max_iterations) {
|
||||
changed = false;
|
||||
iteration++;
|
||||
|
||||
for (int i = 0; i < (int)instr_list.size() - 1; i++) {
|
||||
MachineInstr* instr1 = instr_list[i];
|
||||
MachineInstr* instr2 = instr_list[i + 1];
|
||||
|
||||
// 只进行非常保守的优化
|
||||
bool should_swap = false;
|
||||
|
||||
// 策略1: 将load指令提前,减少load-use延迟
|
||||
if (isLoadInstr(instr2) && !isLoadInstr(instr1) && !isStoreInstr(instr1)) {
|
||||
should_swap = canSwapInstructions(instr1, instr2);
|
||||
}
|
||||
// 策略2: 将非关键store指令延后,为其他指令让路
|
||||
else if (isStoreInstr(instr1) && !isLoadInstr(instr2) && !isStoreInstr(instr2)) {
|
||||
should_swap = canSwapInstructions(instr1, instr2);
|
||||
}
|
||||
|
||||
if (should_swap) {
|
||||
std::swap(instr_list[i], instr_list[i + 1]);
|
||||
changed = true;
|
||||
|
||||
// 调试输出
|
||||
// std::cout << "Swapped instructions at positions " << i << " and " << (i+1) << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 验证调度结果的正确性
|
||||
validateSchedule(instr_list);
|
||||
|
||||
// 将调度后的指令顺序写回
|
||||
std::map<MachineInstr*, std::unique_ptr<MachineInstr>> instr_map;
|
||||
for (auto& instr : instructions) {
|
||||
instr_map[instr.get()] = std::move(instr);
|
||||
}
|
||||
|
||||
instructions.clear();
|
||||
for (auto instr : instr_list) {
|
||||
instructions.push_back(std::move(instr_map[instr]));
|
||||
}
|
||||
}
|
||||
|
||||
bool PostRA_Scheduler::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
// 这个函数在IR级别运行,但我们需要在机器指令级别运行
|
||||
// 所以我们返回false,表示没有对IR进行修改
|
||||
return false;
|
||||
}
|
||||
|
||||
void PostRA_Scheduler::runOnMachineFunction(MachineFunction *mfunc) {
|
||||
// std::cout << "Running Post-RA Local Scheduler... " << std::endl;
|
||||
|
||||
// 遍历每个机器基本块
|
||||
for (auto &mbb : mfunc->getBlocks()) {
|
||||
scheduleBlock(mbb.get());
|
||||
}
|
||||
|
||||
// 清理全局缓存
|
||||
instr_info_cache.clear();
|
||||
// std::cout << "Running Post-RA Local Scheduler... " << std::endl;
|
||||
|
||||
// 遍历每个机器基本块
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
scheduleBlock(mbb.get());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "PreRA_Scheduler.h"
|
||||
#include "RISCv64LLIR.h"
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#define MAX_SCHEDULING_BLOCK_SIZE 1000 // 严格限制调度块大小
|
||||
@@ -66,44 +66,9 @@ 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;
|
||||
// 获取指令定义的虚拟寄存器
|
||||
static std::set<unsigned> getDefinedVirtualRegisters(MachineInstr *instr) {
|
||||
std::set<unsigned> defined_regs;
|
||||
RVOpcodes opcode = instr->getOpcode();
|
||||
|
||||
// CALL指令可能定义返回值寄存器
|
||||
@@ -136,9 +101,9 @@ static std::unordered_set<unsigned> getDefinedVirtualRegisters(MachineInstr *ins
|
||||
return defined_regs;
|
||||
}
|
||||
|
||||
// 获取指令使用的虚拟寄存器 - 优化版本
|
||||
static std::unordered_set<unsigned> getUsedVirtualRegisters(MachineInstr *instr) {
|
||||
std::unordered_set<unsigned> used_regs;
|
||||
// 获取指令使用的虚拟寄存器
|
||||
static std::set<unsigned> getUsedVirtualRegisters(MachineInstr *instr) {
|
||||
std::set<unsigned> used_regs;
|
||||
RVOpcodes opcode = instr->getOpcode();
|
||||
|
||||
// CALL指令:跳过第一个操作数(返回值),其余为参数
|
||||
@@ -199,6 +164,22 @@ static std::unordered_set<unsigned> getUsedVirtualRegisters(MachineInstr *instr)
|
||||
return used_regs;
|
||||
}
|
||||
|
||||
// 获取内存访问位置信息
|
||||
struct MemoryLocation {
|
||||
unsigned base_reg;
|
||||
int64_t offset;
|
||||
bool is_valid;
|
||||
|
||||
MemoryLocation() : base_reg(0), offset(0), is_valid(false) {}
|
||||
MemoryLocation(unsigned base, int64_t off)
|
||||
: base_reg(base), offset(off), is_valid(true) {}
|
||||
|
||||
bool operator==(const MemoryLocation &other) const {
|
||||
return is_valid && other.is_valid && base_reg == other.base_reg &&
|
||||
offset == other.offset;
|
||||
}
|
||||
};
|
||||
|
||||
// 获取内存访问位置
|
||||
static MemoryLocation getMemoryLocation(MachineInstr *instr) {
|
||||
if (!isLoadInstr(instr) && !isStoreInstr(instr)) {
|
||||
@@ -218,27 +199,6 @@ static MemoryLocation getMemoryLocation(MachineInstr *instr) {
|
||||
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) {
|
||||
@@ -254,28 +214,30 @@ static bool mayAlias(const MemoryLocation &loc1, const MemoryLocation &loc2) {
|
||||
return loc1.offset == loc2.offset;
|
||||
}
|
||||
|
||||
// 检查两个指令之间是否存在数据依赖 - 优化版本
|
||||
// 检查两个指令之间是否存在数据依赖
|
||||
static bool hasDataDependency(MachineInstr *first, MachineInstr *second) {
|
||||
const InstrInfo& info_first = getInstrInfo(first);
|
||||
const InstrInfo& info_second = getInstrInfo(second);
|
||||
auto defined_regs_first = getDefinedVirtualRegisters(first);
|
||||
auto used_regs_first = getUsedVirtualRegisters(first);
|
||||
auto defined_regs_second = getDefinedVirtualRegisters(second);
|
||||
auto used_regs_second = getUsedVirtualRegisters(second);
|
||||
|
||||
// RAW依赖: second读取first写入的寄存器
|
||||
for (const auto ® : info_first.defined_regs) {
|
||||
if (info_second.used_regs.find(reg) != info_second.used_regs.end()) {
|
||||
for (const auto ® : defined_regs_first) {
|
||||
if (used_regs_second.count(reg)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// WAR依赖: second写入first读取的寄存器
|
||||
for (const auto ® : info_first.used_regs) {
|
||||
if (info_second.defined_regs.find(reg) != info_second.defined_regs.end()) {
|
||||
for (const auto ® : used_regs_first) {
|
||||
if (defined_regs_second.count(reg)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// WAW依赖: 两个指令写入同一寄存器
|
||||
for (const auto ® : info_first.defined_regs) {
|
||||
if (info_second.defined_regs.find(reg) != info_second.defined_regs.end()) {
|
||||
for (const auto ® : defined_regs_first) {
|
||||
if (defined_regs_second.count(reg)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -283,41 +245,40 @@ static bool hasDataDependency(MachineInstr *first, MachineInstr *second) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查两个指令之间是否存在内存依赖 - 优化版本
|
||||
// 检查两个指令之间是否存在内存依赖
|
||||
static bool hasMemoryDependency(MachineInstr *first, MachineInstr *second) {
|
||||
const InstrInfo& info_first = getInstrInfo(first);
|
||||
const InstrInfo& info_second = getInstrInfo(second);
|
||||
bool first_accesses_memory = isLoadInstr(first) || isStoreInstr(first);
|
||||
bool second_accesses_memory = isLoadInstr(second) || isStoreInstr(second);
|
||||
|
||||
if (!info_first.has_memory_access || !info_second.has_memory_access) {
|
||||
if (!first_accesses_memory || !second_accesses_memory) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 如果至少有一个是存储指令,需要检查别名
|
||||
if (info_first.is_store || info_second.is_store) {
|
||||
return mayAlias(info_first.mem_location, info_second.mem_location);
|
||||
if (isStoreInstr(first) || isStoreInstr(second)) {
|
||||
MemoryLocation loc1 = getMemoryLocation(first);
|
||||
MemoryLocation loc2 = getMemoryLocation(second);
|
||||
return mayAlias(loc1, loc2);
|
||||
}
|
||||
|
||||
return false; // 两个加载指令之间没有依赖
|
||||
}
|
||||
|
||||
// 检查两个指令之间是否存在控制依赖 - 优化版本
|
||||
// 检查两个指令之间是否存在控制依赖
|
||||
static bool hasControlDependency(MachineInstr *first, MachineInstr *second) {
|
||||
const InstrInfo& info_first = getInstrInfo(first);
|
||||
const InstrInfo& info_second = getInstrInfo(second);
|
||||
|
||||
// 终结指令与任何其他指令都有控制依赖
|
||||
if (info_first.is_terminator) {
|
||||
if (isTerminatorInstr(first)) {
|
||||
return true; // first是终结指令,second不能移动到first之前
|
||||
}
|
||||
|
||||
if (info_second.is_terminator) {
|
||||
if (isTerminatorInstr(second)) {
|
||||
return false; // second是终结指令,可以保持在后面
|
||||
}
|
||||
|
||||
// CALL指令具有控制副作用,但可以参与有限的调度
|
||||
if (info_first.is_call || info_second.is_call) {
|
||||
if (isCallInstr(first) || isCallInstr(second)) {
|
||||
// CALL指令之间保持顺序
|
||||
if (info_first.is_call && info_second.is_call) {
|
||||
if (isCallInstr(first) && isCallInstr(second)) {
|
||||
return true;
|
||||
}
|
||||
// 其他情况允许调度(通过数据依赖控制)
|
||||
@@ -326,7 +287,7 @@ static bool hasControlDependency(MachineInstr *first, MachineInstr *second) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 综合检查两个指令是否可以交换 - 优化版本
|
||||
// 综合检查两个指令是否可以交换
|
||||
static bool canSwapInstructions(MachineInstr *first, MachineInstr *second) {
|
||||
// 检查所有类型的依赖
|
||||
if (hasDataDependency(first, second) || hasDataDependency(second, first)) {
|
||||
@@ -345,17 +306,15 @@ static bool canSwapInstructions(MachineInstr *first, MachineInstr *second) {
|
||||
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 (isTerminatorInstr(instrs[i])) {
|
||||
if (i > 0)
|
||||
boundaries.push_back(i);
|
||||
if (i + 1 < instrs.size())
|
||||
@@ -374,7 +333,7 @@ findSchedulingBoundaries(const std::vector<MachineInstr *> &instrs) {
|
||||
return boundaries;
|
||||
}
|
||||
|
||||
// 在单个调度区域内进行指令调度 - 优化版本
|
||||
// 在单个调度区域内进行指令调度
|
||||
static void scheduleRegion(std::vector<MachineInstr *> &instrs, size_t start,
|
||||
size_t end) {
|
||||
if (end - start <= 1) {
|
||||
@@ -388,8 +347,7 @@ static void scheduleRegion(std::vector<MachineInstr *> &instrs, size_t start,
|
||||
|
||||
// 简单的调度算法:只尝试将加载指令尽可能前移
|
||||
for (size_t i = start + 1; i < end; i++) {
|
||||
const InstrInfo& info = getInstrInfo(instrs[i]);
|
||||
if (info.is_load) {
|
||||
if (isLoadInstr(instrs[i])) {
|
||||
// 尝试将加载指令向前移动
|
||||
for (size_t j = i; j > start; j--) {
|
||||
// 检查是否可以与前一条指令交换
|
||||
@@ -411,21 +369,12 @@ static void scheduleBlock(MachineBasicBlock *mbb) {
|
||||
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);
|
||||
|
||||
@@ -437,14 +386,12 @@ static void scheduleBlock(MachineBasicBlock *mbb) {
|
||||
}
|
||||
|
||||
// 重建指令序列
|
||||
std::unordered_map<MachineInstr *, std::unique_ptr<MachineInstr>> instr_map;
|
||||
instr_map.reserve(instructions.size()); // 预分配容量
|
||||
std::map<MachineInstr *, std::unique_ptr<MachineInstr>> instr_map;
|
||||
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]));
|
||||
}
|
||||
@@ -458,9 +405,6 @@ void PreRA_Scheduler::runOnMachineFunction(MachineFunction *mfunc) {
|
||||
for (auto &mbb : mfunc->getBlocks()) {
|
||||
scheduleBlock(mbb.get());
|
||||
}
|
||||
|
||||
// 清理全局缓存
|
||||
instr_info_cache.clear();
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@@ -7,15 +7,9 @@ namespace sysy {
|
||||
// 检查是否为内存加载/存储指令,以处理特殊的打印格式
|
||||
bool isMemoryOp(RVOpcodes opcode) {
|
||||
switch (opcode) {
|
||||
// --- 整数加载/存储 (原有逻辑) ---
|
||||
case RVOpcodes::LB: case RVOpcodes::LH: case RVOpcodes::LW: case RVOpcodes::LD:
|
||||
case RVOpcodes::LBU: case RVOpcodes::LHU: case RVOpcodes::LWU:
|
||||
case RVOpcodes::SB: case RVOpcodes::SH: case RVOpcodes::SW: case RVOpcodes::SD:
|
||||
case RVOpcodes::FLW:
|
||||
case RVOpcodes::FSW:
|
||||
// 如果未来支持双精度,也在这里添加FLD/FSD
|
||||
// case RVOpcodes::FLD:
|
||||
// case RVOpcodes::FSD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -79,9 +73,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;
|
||||
@@ -90,20 +82,7 @@ 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::FNEG_S: *OS << "fneg.s "; break;
|
||||
case RVOpcodes::FEQ_S: *OS << "feq.s "; break;
|
||||
case RVOpcodes::FLT_S: *OS << "flt.s "; break;
|
||||
case RVOpcodes::FLE_S: *OS << "fle.s "; break;
|
||||
case RVOpcodes::FCVT_S_W: *OS << "fcvt.s.w "; break;
|
||||
case RVOpcodes::FCVT_W_S: *OS << "fcvt.w.s "; break;
|
||||
case RVOpcodes::FMV_S: *OS << "fmv.s "; break;
|
||||
case RVOpcodes::FMV_W_X: *OS << "fmv.w.x "; break;
|
||||
case RVOpcodes::FMV_X_W: *OS << "fmv.x.w "; break;
|
||||
case RVOpcodes::SNEZ: *OS << "snez "; break;
|
||||
case RVOpcodes::CALL: { // [核心修改] 为CALL指令添加特殊处理逻辑
|
||||
*OS << "call ";
|
||||
// 遍历所有操作数,只寻找并打印函数名标签
|
||||
@@ -138,12 +117,6 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
|
||||
// It should have been eliminated by RegAlloc
|
||||
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
|
||||
*OS << "frame_addr "; break;
|
||||
case RVOpcodes::FRAME_LOAD_F:
|
||||
if (!debug) throw std::runtime_error("FRAME_LOAD_F not eliminated before AsmPrinter");
|
||||
*OS << "frame_load_f "; break;
|
||||
case RVOpcodes::FRAME_STORE_F:
|
||||
if (!debug) throw std::runtime_error("FRAME_STORE_F not eliminated before AsmPrinter");
|
||||
*OS << "frame_store_f "; break;
|
||||
default:
|
||||
throw std::runtime_error("Unknown opcode in AsmPrinter");
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ std::string RISCv64CodeGen::code_gen() {
|
||||
std::string RISCv64CodeGen::module_gen() {
|
||||
std::stringstream ss;
|
||||
|
||||
// --- 步骤1:将全局变量分为.data和.bss两组 ---
|
||||
// --- [新逻辑] 步骤1:将全局变量分为.data和.bss两组 ---
|
||||
std::vector<GlobalValue*> data_globals;
|
||||
std::vector<GlobalValue*> bss_globals;
|
||||
|
||||
@@ -26,6 +26,7 @@ std::string RISCv64CodeGen::module_gen() {
|
||||
|
||||
// 判断是否为大型零初始化数组,以便放入.bss段
|
||||
bool is_large_zero_array = false;
|
||||
// 规则:初始化列表只有一项,且该项是值为0的整数,且数量大于一个阈值(例如16)
|
||||
if (init_values.getValues().size() == 1) {
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(init_values.getValues()[0])) {
|
||||
if (const_val->isInt() && const_val->getInt() == 0 && init_values.getNumbers()[0] > 16) {
|
||||
@@ -41,53 +42,33 @@ std::string RISCv64CodeGen::module_gen() {
|
||||
}
|
||||
}
|
||||
|
||||
// --- 步骤2:生成 .bss 段的代码 ---
|
||||
// --- [新逻辑] 步骤2:生成 .bss 段的代码 ---
|
||||
if (!bss_globals.empty()) {
|
||||
ss << ".bss\n";
|
||||
ss << ".bss\n"; // 切换到 .bss 段
|
||||
for (GlobalValue* global : bss_globals) {
|
||||
// 获取数组总大小(元素个数 * 元素大小)
|
||||
// 在SysY中,我们假设元素都是4字节(int或float)
|
||||
unsigned count = global->getInitValues().getNumbers()[0];
|
||||
unsigned total_size = count * 4; // 假设元素都是4字节
|
||||
unsigned total_size = count * 4;
|
||||
|
||||
ss << " .align 3\n";
|
||||
ss << " .align 3\n"; // 8字节对齐 (2^3)
|
||||
ss << ".globl " << global->getName() << "\n";
|
||||
ss << ".type " << global->getName() << ", @object\n";
|
||||
ss << ".size " << global->getName() << ", " << total_size << "\n";
|
||||
ss << global->getName() << ":\n";
|
||||
// 使用 .space 指令来预留指定大小的零填充空间
|
||||
ss << " .space " << total_size << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// --- 步骤3:生成 .data 段的代码 ---
|
||||
// --- [旧逻辑保留] 步骤3:生成 .data 段的代码 ---
|
||||
if (!data_globals.empty()) {
|
||||
ss << ".data\n"; // 切换到 .data 段
|
||||
for (GlobalValue* global : data_globals) {
|
||||
ss << ".globl " << global->getName() << "\n";
|
||||
ss << global->getName() << ":\n";
|
||||
const auto& init_values = global->getInitValues();
|
||||
for (size_t i = 0; i < init_values.getValues().size(); ++i) {
|
||||
auto val = init_values.getValues()[i];
|
||||
auto count = init_values.getNumbers()[i];
|
||||
if (auto constant = dynamic_cast<ConstantValue*>(val)) {
|
||||
for (unsigned j = 0; j < count; ++j) {
|
||||
if (constant->isInt()) {
|
||||
ss << " .word " << constant->getInt() << "\n";
|
||||
} else {
|
||||
float f = constant->getFloat();
|
||||
uint32_t float_bits = *(uint32_t*)&f;
|
||||
ss << " .word " << float_bits << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// b. [新增] 再处理全局常量 (ConstantVariable)
|
||||
for (const auto& const_ptr : module->getConsts()) {
|
||||
ConstantVariable* cnst = const_ptr.get();
|
||||
ss << ".globl " << cnst->getName() << "\n";
|
||||
ss << cnst->getName() << ":\n";
|
||||
const auto& init_values = cnst->getInitValues();
|
||||
// 这部分逻辑和处理 GlobalValue 完全相同
|
||||
// 使用您原有的逻辑来处理显式初始化的值
|
||||
for (size_t i = 0; i < init_values.getValues().size(); ++i) {
|
||||
auto val = init_values.getValues()[i];
|
||||
auto count = init_values.getNumbers()[i];
|
||||
@@ -106,7 +87,7 @@ std::string RISCv64CodeGen::module_gen() {
|
||||
}
|
||||
}
|
||||
|
||||
// --- 处理函数 (.text段) ---
|
||||
// --- 处理函数 (.text段) 的逻辑保持不变 ---
|
||||
if (!module->getFunctions().empty()) {
|
||||
ss << ".text\n";
|
||||
for (const auto& func_pair : module->getFunctions()) {
|
||||
@@ -118,6 +99,7 @@ std::string RISCv64CodeGen::module_gen() {
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
// function_gen 现在是包含具体优化名称的、完整的处理流水线
|
||||
std::string RISCv64CodeGen::function_gen(Function* func) {
|
||||
// === 完整的后端处理流水线 ===
|
||||
|
||||
|
||||
@@ -10,23 +10,7 @@ namespace sysy {
|
||||
|
||||
// DAG节点定义 (内部实现)
|
||||
struct RISCv64ISel::DAGNode {
|
||||
enum NodeKind {
|
||||
ARGUMENT,
|
||||
CONSTANT, // 整数或地址常量
|
||||
LOAD,
|
||||
STORE,
|
||||
BINARY, // 整数二元运算
|
||||
CALL,
|
||||
RETURN,
|
||||
BRANCH,
|
||||
ALLOCA_ADDR,
|
||||
UNARY, // 整数一元运算
|
||||
MEMSET,
|
||||
GET_ELEMENT_PTR,
|
||||
FP_CONSTANT, // 浮点常量
|
||||
FBINARY, // 浮点二元运算 (如 FADD, FSUB, FCMP)
|
||||
FUNARY, // 浮点一元运算 (如 FCVT, FNEG)
|
||||
};
|
||||
enum NodeKind {ARGUMENT, CONSTANT, LOAD, STORE, BINARY, CALL, RETURN, BRANCH, ALLOCA_ADDR, UNARY, MEMSET, GET_ELEMENT_PTR};
|
||||
NodeKind kind;
|
||||
Value* value = nullptr;
|
||||
std::vector<DAGNode*> operands;
|
||||
@@ -45,20 +29,11 @@ unsigned RISCv64ISel::getVReg(Value* val) {
|
||||
if (vreg_counter == 0) {
|
||||
vreg_counter = 1; // vreg 0 保留
|
||||
}
|
||||
unsigned new_vreg = vreg_counter++;
|
||||
vreg_map[val] = new_vreg;
|
||||
vreg_to_value_map[new_vreg] = val;
|
||||
vreg_type_map[new_vreg] = val->getType();
|
||||
vreg_map[val] = vreg_counter++;
|
||||
}
|
||||
return vreg_map.at(val);
|
||||
}
|
||||
|
||||
unsigned RISCv64ISel::getNewVReg(Type* type) {
|
||||
unsigned new_vreg = vreg_counter++;
|
||||
vreg_type_map[new_vreg] = type; // 记录这个新vreg的类型
|
||||
return new_vreg;
|
||||
}
|
||||
|
||||
// 主入口函数
|
||||
std::unique_ptr<MachineFunction> RISCv64ISel::runOnFunction(Function* func) {
|
||||
F = func;
|
||||
@@ -186,52 +161,18 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
}
|
||||
break;
|
||||
|
||||
case DAGNode::FP_CONSTANT: {
|
||||
// RISC-V没有直接加载浮点立即数的指令
|
||||
// 标准做法是:1. 将浮点数的32位二进制表示加载到一个整数寄存器
|
||||
// 2. 使用 fmv.w.x 指令将位模式从整数寄存器移动到浮点寄存器
|
||||
auto const_val = dynamic_cast<ConstantValue*>(node->value);
|
||||
auto float_vreg = getVReg(const_val);
|
||||
auto temp_int_vreg = getNewVReg(Type::getIntType()); // 临时整数虚拟寄存器
|
||||
|
||||
float f_val = const_val->getFloat();
|
||||
// 使用 reinterpret_cast 获取浮点数的32位二进制表示
|
||||
uint32_t float_bits = *reinterpret_cast<uint32_t*>(&f_val);
|
||||
|
||||
// 1. li temp_int_vreg, float_bits
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(temp_int_vreg));
|
||||
li->addOperand(std::make_unique<ImmOperand>(float_bits));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
|
||||
// 2. fmv.w.x float_vreg, temp_int_vreg
|
||||
auto fmv = std::make_unique<MachineInstr>(RVOpcodes::FMV_W_X);
|
||||
fmv->addOperand(std::make_unique<RegOperand>(float_vreg));
|
||||
fmv->addOperand(std::make_unique<RegOperand>(temp_int_vreg));
|
||||
CurMBB->addInstruction(std::move(fmv));
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::LOAD: {
|
||||
auto dest_vreg = getVReg(node->value);
|
||||
Value* ptr_val = node->operands[0]->value;
|
||||
|
||||
// --- 修改点 ---
|
||||
// 1. 获取加载结果的类型 (即这个LOAD指令自身的类型)
|
||||
Type* loaded_type = node->value->getType();
|
||||
|
||||
// 2. 根据类型选择正确的伪指令或真实指令操作码
|
||||
RVOpcodes frame_opcode;
|
||||
RVOpcodes real_opcode;
|
||||
if (loaded_type->isPointer()) {
|
||||
frame_opcode = RVOpcodes::FRAME_LOAD_D;
|
||||
real_opcode = RVOpcodes::LD;
|
||||
} else if (loaded_type->isFloat()) {
|
||||
frame_opcode = RVOpcodes::FRAME_LOAD_F;
|
||||
real_opcode = RVOpcodes::FLW;
|
||||
} else { // 默认为整数
|
||||
frame_opcode = RVOpcodes::FRAME_LOAD_W;
|
||||
real_opcode = RVOpcodes::LW;
|
||||
}
|
||||
RVOpcodes frame_opcode = loaded_type->isPointer() ? RVOpcodes::FRAME_LOAD_D : RVOpcodes::FRAME_LOAD_W;
|
||||
RVOpcodes real_opcode = loaded_type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW;
|
||||
|
||||
|
||||
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
|
||||
// 3. 创建使用新的、区分宽度的伪指令
|
||||
@@ -242,7 +183,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
|
||||
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_val)) {
|
||||
// 对于全局变量,先用 la 加载其地址
|
||||
auto addr_vreg = getNewVReg(Type::getPointerType(global->getType()));
|
||||
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()));
|
||||
@@ -279,51 +220,20 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
|
||||
// 如果要存储的值是一个常量,就在这里生成 `li` 指令加载它
|
||||
if (auto val_const = dynamic_cast<ConstantValue*>(val_to_store)) {
|
||||
// 区分整数常量和浮点常量
|
||||
if (val_const->isInt()) {
|
||||
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));
|
||||
} else if (val_const->isFloat()) {
|
||||
// 先将浮点数的位模式加载到整数vreg,再用fmv.w.x移到浮点vreg
|
||||
auto temp_int_vreg = getNewVReg(Type::getIntType());
|
||||
auto float_vreg = getVReg(val_const);
|
||||
|
||||
float f_val = val_const->getFloat();
|
||||
uint32_t float_bits = *reinterpret_cast<uint32_t*>(&f_val);
|
||||
|
||||
// 1. li temp_int_vreg, float_bits
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(temp_int_vreg));
|
||||
li->addOperand(std::make_unique<ImmOperand>(float_bits));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
|
||||
// 2. fmv.w.x float_vreg, temp_int_vreg
|
||||
auto fmv = std::make_unique<MachineInstr>(RVOpcodes::FMV_W_X);
|
||||
fmv->addOperand(std::make_unique<RegOperand>(float_vreg));
|
||||
fmv->addOperand(std::make_unique<RegOperand>(temp_int_vreg));
|
||||
CurMBB->addInstruction(std::move(fmv));
|
||||
}
|
||||
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);
|
||||
|
||||
// --- 修改点 ---
|
||||
// 1. 获取被存储的值的类型
|
||||
Type* stored_type = val_to_store->getType();
|
||||
|
||||
// 2. 根据类型选择正确的伪指令或真实指令操作码
|
||||
RVOpcodes frame_opcode;
|
||||
RVOpcodes real_opcode;
|
||||
if (stored_type->isPointer()) {
|
||||
frame_opcode = RVOpcodes::FRAME_STORE_D;
|
||||
real_opcode = RVOpcodes::SD;
|
||||
} else if (stored_type->isFloat()) {
|
||||
frame_opcode = RVOpcodes::FRAME_STORE_F;
|
||||
real_opcode = RVOpcodes::FSW;
|
||||
} else { // 默认为整数
|
||||
frame_opcode = RVOpcodes::FRAME_STORE_W;
|
||||
real_opcode = RVOpcodes::SW;
|
||||
}
|
||||
RVOpcodes frame_opcode = stored_type->isPointer() ? RVOpcodes::FRAME_STORE_D : RVOpcodes::FRAME_STORE_W;
|
||||
RVOpcodes real_opcode = stored_type->isPointer() ? RVOpcodes::SD : RVOpcodes::SW;
|
||||
|
||||
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
|
||||
// 3. 创建使用新的、区分宽度的伪指令
|
||||
@@ -334,7 +244,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
|
||||
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_val)) {
|
||||
// 向全局变量存储
|
||||
auto addr_vreg = getNewVReg(Type::getIntType());
|
||||
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()));
|
||||
@@ -394,7 +304,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
}
|
||||
|
||||
// 2. [修改] 根据基地址的类型,生成不同的指令来获取基地址
|
||||
auto base_addr_vreg = getNewVReg(Type::getIntType()); // 创建一个新的临时vreg来存放基地址
|
||||
auto base_addr_vreg = getNewVReg(); // 创建一个新的临时vreg来存放基地址
|
||||
|
||||
// 情况一:基地址是局部栈变量
|
||||
if (auto alloca_base = dynamic_cast<AllocaInst*>(base)) {
|
||||
@@ -587,109 +497,6 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::FBINARY: {
|
||||
auto bin = dynamic_cast<BinaryInst*>(node->value);
|
||||
auto dest_vreg = getVReg(bin);
|
||||
auto lhs_vreg = getVReg(bin->getLhs());
|
||||
auto rhs_vreg = getVReg(bin->getRhs());
|
||||
|
||||
switch (bin->getKind()) {
|
||||
case Instruction::kFAdd: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FADD_S);
|
||||
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::kFSub: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FSUB_S);
|
||||
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::kFMul: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FMUL_S);
|
||||
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::kFDiv: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FDIV_S);
|
||||
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;
|
||||
}
|
||||
|
||||
// --- 浮点比较指令 ---
|
||||
// 注意:比较结果(0或1)写入的是一个通用整数寄存器(dest_vreg)
|
||||
case Instruction::kFCmpEQ: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FEQ_S);
|
||||
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::kFCmpLT: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FLT_S);
|
||||
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::kFCmpLE: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FLE_S);
|
||||
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::kFCmpGT: { // a > b 等价于 b < a
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FLT_S);
|
||||
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 Instruction::kFCmpGE: { // a >= b 等价于 b <= a
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FLE_S);
|
||||
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 Instruction::kFCmpNE: { // a != b 等价于 !(a == b)
|
||||
// 1. 先用 feq.s 比较,结果存入 dest_vreg
|
||||
auto feq = std::make_unique<MachineInstr>(RVOpcodes::FEQ_S);
|
||||
feq->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
feq->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
feq->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(feq));
|
||||
// 2. 再用 seqz 对结果取反 (如果相等(1),则变0;如果不等(0),则变1)
|
||||
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;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("Unsupported float binary instruction in ISel");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::UNARY: {
|
||||
auto unary = dynamic_cast<UnaryInst*>(node->value);
|
||||
auto dest_vreg = getVReg(unary);
|
||||
@@ -717,245 +524,109 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::FUNARY: {
|
||||
auto unary = dynamic_cast<UnaryInst*>(node->value);
|
||||
auto dest_vreg = getVReg(unary);
|
||||
auto src_vreg = getVReg(unary->getOperand());
|
||||
|
||||
switch (unary->getKind()) {
|
||||
case Instruction::kItoF: { // 整数 to 浮点
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FCVT_S_W);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg)); // 目标是浮点vreg
|
||||
instr->addOperand(std::make_unique<RegOperand>(src_vreg)); // 源是整数vreg
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kFtoI: { // 浮点 to 整数
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FCVT_W_S);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg)); // 目标是整数vreg
|
||||
instr->addOperand(std::make_unique<RegOperand>(src_vreg)); // 源是浮点vreg
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kFNeg: { // 浮点取负
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FNEG_S);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
// --- 处理位传送指令 ---
|
||||
case Instruction::kBitItoF: { // 整数位模式 -> 浮点寄存器
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FMV_W_X);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg)); // 目标是浮点vreg
|
||||
instr->addOperand(std::make_unique<RegOperand>(src_vreg)); // 源是整数vreg
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kBitFtoI: { // 浮点位模式 -> 整数寄存器
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FMV_X_W);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg)); // 目标是整数vreg
|
||||
instr->addOperand(std::make_unique<RegOperand>(src_vreg)); // 源是浮点vreg
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("Unsupported float unary instruction in ISel");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::CALL: {
|
||||
auto call = dynamic_cast<CallInst*>(node->value);
|
||||
// 处理函数参数,放入a0-a7物理寄存器
|
||||
size_t num_operands = node->operands.size();
|
||||
|
||||
// --- 步骤 1: 分配寄存器参数和栈参数 ---
|
||||
// 根据RISC-V调用约定,前8个整数/指针参数通过a0-a7传递,
|
||||
// 前8个浮点参数通过fa0-fa7传递 (物理寄存器 f10-f17)。其余参数通过栈传递。
|
||||
|
||||
int int_reg_idx = 0; // a0-a7 的索引
|
||||
int fp_reg_idx = 0; // fa0-fa7 的索引
|
||||
|
||||
// 用于存储需要通过栈传递的参数
|
||||
std::vector<DAGNode*> stack_args;
|
||||
|
||||
for (size_t i = 0; i < num_operands; ++i) {
|
||||
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];
|
||||
Value* arg_val = arg_node->value;
|
||||
Type* arg_type = arg_val->getType();
|
||||
auto arg_preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + i);
|
||||
|
||||
// 判断参数是浮点类型还是整型/指针类型
|
||||
if (arg_type->isFloat()) {
|
||||
if (fp_reg_idx < 8) {
|
||||
// --- 处理浮点寄存器参数 (fa0-fa7, 对应物理寄存器 F10-F17) ---
|
||||
auto arg_preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + fp_reg_idx);
|
||||
fp_reg_idx++;
|
||||
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(arg_val)) {
|
||||
// 如果是浮点常量,需要先物化
|
||||
// 1. 获取其32位二进制表示
|
||||
float f_val = const_val->getFloat();
|
||||
uint32_t float_bits = *reinterpret_cast<uint32_t*>(&f_val);
|
||||
// 2. 将位模式加载到一个临时整数寄存器 (使用t0)
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(PhysicalReg::T0));
|
||||
li->addOperand(std::make_unique<ImmOperand>(float_bits));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
// 3. 使用fmv.w.x将位模式从整数寄存器移动到目标浮点参数寄存器
|
||||
auto fmv_wx = std::make_unique<MachineInstr>(RVOpcodes::FMV_W_X);
|
||||
fmv_wx->addOperand(std::make_unique<RegOperand>(arg_preg));
|
||||
fmv_wx->addOperand(std::make_unique<RegOperand>(PhysicalReg::T0));
|
||||
CurMBB->addInstruction(std::move(fmv_wx));
|
||||
} else {
|
||||
// 如果已经是虚拟寄存器,直接用 fmv.s 移动
|
||||
auto src_vreg = getVReg(arg_val);
|
||||
auto fmv_s = std::make_unique<MachineInstr>(RVOpcodes::FMV_S);
|
||||
fmv_s->addOperand(std::make_unique<RegOperand>(arg_preg));
|
||||
fmv_s->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
CurMBB->addInstruction(std::move(fmv_s));
|
||||
}
|
||||
} else {
|
||||
// 浮点寄存器已用完,放到栈上传递
|
||||
stack_args.push_back(arg_node);
|
||||
}
|
||||
} else { // 整数或指针参数
|
||||
if (int_reg_idx < 8) {
|
||||
// --- 处理整数/指针寄存器参数 (a0-a7) ---
|
||||
auto arg_preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + int_reg_idx);
|
||||
int_reg_idx++;
|
||||
|
||||
if (arg_node->kind == DAGNode::CONSTANT) {
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(arg_val)) {
|
||||
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_val);
|
||||
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));
|
||||
}
|
||||
} else {
|
||||
// 整数寄存器已用完,放到栈上传递
|
||||
stack_args.push_back(arg_node);
|
||||
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字节
|
||||
|
||||
// --- 步骤 2: 处理所有栈参数 ---
|
||||
int stack_space = 0;
|
||||
if (!stack_args.empty()) {
|
||||
// 计算栈参数所需的总空间,RV64中每个槽位为8字节
|
||||
stack_space = stack_args.size() * 8;
|
||||
// 根据ABI,为call分配的栈空间需要16字节对齐
|
||||
if (stack_space % 16 != 0) {
|
||||
stack_space += 16 - (stack_space % 16);
|
||||
}
|
||||
|
||||
// 在栈上分配空间
|
||||
if (stack_space > 0) {
|
||||
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));
|
||||
}
|
||||
|
||||
// 将每个参数存储到栈上对应的位置
|
||||
for (size_t i = 0; i < stack_args.size(); ++i) {
|
||||
DAGNode* arg_node = stack_args[i];
|
||||
Value* arg_val = arg_node->value;
|
||||
Type* arg_type = arg_val->getType();
|
||||
int offset = i * 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;
|
||||
// 如果是常量,先加载到临时vreg
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(arg_val)) {
|
||||
src_vreg = getNewVReg(arg_type);
|
||||
if(arg_type->isFloat()) {
|
||||
auto temp_int_vreg = getNewVReg(Type::getIntType());
|
||||
float f_val = const_val->getFloat();
|
||||
uint32_t float_bits = *reinterpret_cast<uint32_t*>(&f_val);
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(temp_int_vreg));
|
||||
li->addOperand(std::make_unique<ImmOperand>(float_bits));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
auto fmv_wx = std::make_unique<MachineInstr>(RVOpcodes::FMV_W_X);
|
||||
fmv_wx->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
fmv_wx->addOperand(std::make_unique<RegOperand>(temp_int_vreg));
|
||||
CurMBB->addInstruction(std::move(fmv_wx));
|
||||
} else {
|
||||
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));
|
||||
}
|
||||
|
||||
// 准备源寄存器
|
||||
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_val);
|
||||
src_vreg = getVReg(arg_node->value);
|
||||
}
|
||||
|
||||
// 根据类型选择 fsw (浮点) 或 sd (整型/指针) 存储指令
|
||||
std::unique_ptr<MachineInstr> store_instr;
|
||||
if (arg_type->isFloat()) {
|
||||
store_instr = std::make_unique<MachineInstr>(RVOpcodes::FSW);
|
||||
} else {
|
||||
store_instr = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
||||
}
|
||||
store_instr->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
store_instr->addOperand(std::make_unique<MemOperand>(
|
||||
// 计算在栈上的偏移量
|
||||
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(store_instr));
|
||||
CurMBB->addInstruction(std::move(sd_instr));
|
||||
}
|
||||
}
|
||||
|
||||
// --- 步骤 3: 生成CALL指令 ---
|
||||
|
||||
auto call_instr = std::make_unique<MachineInstr>(RVOpcodes::CALL);
|
||||
// [协议] 如果函数有返回值,将它的目标虚拟寄存器作为第一个操作数
|
||||
if (!call->getType()->isVoid()) {
|
||||
unsigned dest_vreg = getVReg(call);
|
||||
call_instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
}
|
||||
|
||||
// 将函数名标签作为后续操作数
|
||||
call_instr->addOperand(std::make_unique<LabelOperand>(call->getCallee()->getName()));
|
||||
|
||||
// 将所有参数的虚拟寄存器也作为后续操作数,供getInstrUseDef分析
|
||||
for (size_t i = 0; i < num_operands; ++i) {
|
||||
if (node->operands[i]->kind != DAGNode::CONSTANT && node->operands[i]->kind != DAGNode::FP_CONSTANT) {
|
||||
if (node->operands[i]->kind != DAGNode::CONSTANT) { // 常量参数已直接加载,无需作为use
|
||||
call_instr->addOperand(std::make_unique<RegOperand>(getVReg(node->operands[i]->value)));
|
||||
}
|
||||
}
|
||||
CurMBB->addInstruction(std::move(call_instr));
|
||||
|
||||
// --- 步骤 4: 处理返回值 ---
|
||||
if (!call->getType()->isVoid()) {
|
||||
unsigned dest_vreg = getVReg(call);
|
||||
if (call->getType()->isFloat()) {
|
||||
// 浮点返回值在 fa0 (物理寄存器 F10)
|
||||
auto fmv_s = std::make_unique<MachineInstr>(RVOpcodes::FMV_S);
|
||||
fmv_s->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
fmv_s->addOperand(std::make_unique<RegOperand>(PhysicalReg::F10)); // fa0
|
||||
CurMBB->addInstruction(std::move(fmv_s));
|
||||
} else {
|
||||
// 整数/指针返回值在 a0
|
||||
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
mv->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
mv->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
|
||||
CurMBB->addInstruction(std::move(mv));
|
||||
}
|
||||
}
|
||||
CurMBB->addInstruction(std::move(call_instr));
|
||||
|
||||
// --- 步骤 5: 回收为栈参数分配的空间 ---
|
||||
if (stack_space > 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -963,47 +634,17 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
auto ret_inst_ir = dynamic_cast<ReturnInst*>(node->value);
|
||||
if (ret_inst_ir && ret_inst_ir->hasReturnValue()) {
|
||||
Value* ret_val = ret_inst_ir->getReturnValue();
|
||||
Type* ret_type = ret_val->getType();
|
||||
|
||||
if (ret_type->isFloat()) {
|
||||
// --- 处理浮点返回值 ---
|
||||
// 返回值需要被放入 fa0 (物理寄存器 F10)
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(ret_val)) {
|
||||
// 如果是浮点常量,需要先物化到fa0
|
||||
float f_val = const_val->getFloat();
|
||||
uint32_t float_bits = *reinterpret_cast<uint32_t*>(&f_val);
|
||||
// 1. 加载位模式到临时整数寄存器 (t0)
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(PhysicalReg::T0));
|
||||
li->addOperand(std::make_unique<ImmOperand>(float_bits));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
// 2. 将位模式从 t0 移动到 fa0
|
||||
auto fmv_wx = std::make_unique<MachineInstr>(RVOpcodes::FMV_W_X);
|
||||
fmv_wx->addOperand(std::make_unique<RegOperand>(PhysicalReg::F10)); // fa0
|
||||
fmv_wx->addOperand(std::make_unique<RegOperand>(PhysicalReg::T0));
|
||||
CurMBB->addInstruction(std::move(fmv_wx));
|
||||
} else {
|
||||
// 如果是vreg,直接用 fmv.s 移动到 fa0
|
||||
auto fmv_s = std::make_unique<MachineInstr>(RVOpcodes::FMV_S);
|
||||
fmv_s->addOperand(std::make_unique<RegOperand>(PhysicalReg::F10)); // fa0
|
||||
fmv_s->addOperand(std::make_unique<RegOperand>(getVReg(ret_val)));
|
||||
CurMBB->addInstruction(std::move(fmv_s));
|
||||
}
|
||||
// [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 {
|
||||
// --- 处理整数/指针返回值 ---
|
||||
// 返回值需要被放入 a0
|
||||
// [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));
|
||||
}
|
||||
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节点生成,
|
||||
@@ -1221,11 +862,6 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
la_instr->addOperand(std::make_unique<RegOperand>(current_addr_vreg));
|
||||
la_instr->addOperand(std::make_unique<LabelOperand>(global_base->getName()));
|
||||
CurMBB->addInstruction(std::move(la_instr));
|
||||
} else if (auto const_global_base = dynamic_cast<ConstantVariable*>(base_ptr_node->value)) {
|
||||
auto la_instr = std::make_unique<MachineInstr>(RVOpcodes::LA);
|
||||
la_instr->addOperand(std::make_unique<RegOperand>(current_addr_vreg));
|
||||
la_instr->addOperand(std::make_unique<LabelOperand>(const_global_base->getName()));
|
||||
CurMBB->addInstruction(std::move(la_instr));
|
||||
} else {
|
||||
auto base_vreg = getVReg(base_ptr_node->value);
|
||||
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
||||
@@ -1234,7 +870,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
CurMBB->addInstruction(std::move(mv));
|
||||
}
|
||||
|
||||
// --- Step 2: 遵循LLVM GEP语义迭代计算地址 ---
|
||||
// --- Step 2: [最终权威版] 遵循LLVM GEP语义迭代计算地址 ---
|
||||
|
||||
// 初始被索引的类型,是基指针指向的那个类型 (例如, [2 x i32])
|
||||
Type* current_type = gep->getBasePointer()->getType()->as<PointerType>()->getBaseType();
|
||||
@@ -1343,17 +979,15 @@ RISCv64ISel::DAGNode* RISCv64ISel::get_operand_node(
|
||||
|
||||
// 规则1:如果这个Value已经有对应的节点,直接返回
|
||||
if (value_to_node.count(val_ir)) {
|
||||
return value_to_node[val_ir];
|
||||
return value_to_node.at(val_ir);
|
||||
}
|
||||
if (auto const_val = dynamic_cast<ConstantValue*>(val_ir)) {
|
||||
if (const_val->isInt()) {
|
||||
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
|
||||
} else {
|
||||
// 为浮点常量创建新的FP_CONSTANT节点
|
||||
return create_node(DAGNode::FP_CONSTANT, val_ir, value_to_node, nodes_storage);
|
||||
}
|
||||
|
||||
// 规则2:识别各种类型的叶子节点,并创建相应的DAG节点
|
||||
if (dynamic_cast<ConstantValue*>(val_ir)) {
|
||||
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
|
||||
}
|
||||
if (dynamic_cast<GlobalValue*>(val_ir)) {
|
||||
// 全局变量/常量数组被视为一个常量地址
|
||||
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
|
||||
}
|
||||
if (dynamic_cast<AllocaInst*>(val_ir)) {
|
||||
@@ -1425,17 +1059,6 @@ std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicB
|
||||
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() == Instruction::kFSub) {
|
||||
if (auto const_lhs = dynamic_cast<ConstantValue*>(bin->getLhs())) {
|
||||
// 使用isZero()来判断浮点数0.0,比直接比较更健壮
|
||||
if (const_lhs->isZero()) {
|
||||
// 这是一个浮点取负操作,创建 FUNARY 节点
|
||||
auto funary_node = create_node(DAGNode::FUNARY, bin, value_to_node, nodes_storage);
|
||||
funary_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
|
||||
continue; // 处理完毕,跳到下一条指令
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bin->getKind() == BinaryInst::kSub) {
|
||||
if (auto const_lhs = dynamic_cast<ConstantValue*>(bin->getLhs())) {
|
||||
if (const_lhs->getInt() == 0) {
|
||||
@@ -1445,24 +1068,13 @@ std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicB
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bin->getKind() >= Instruction::kFAdd) { // 假设浮点指令枚举值更大
|
||||
auto fbin_node = create_node(DAGNode::FBINARY, bin, value_to_node, nodes_storage);
|
||||
fbin_node->operands.push_back(get_operand_node(bin->getLhs(), value_to_node, nodes_storage));
|
||||
fbin_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
|
||||
} else {
|
||||
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));
|
||||
}
|
||||
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;
|
||||
if (un->getKind() >= Instruction::kFNeg) {
|
||||
auto funary_node = create_node(DAGNode::FUNARY, un, value_to_node, nodes_storage);
|
||||
funary_node->operands.push_back(get_operand_node(un->getOperand(), value_to_node, nodes_storage));
|
||||
} else {
|
||||
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));
|
||||
}
|
||||
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);
|
||||
|
||||
@@ -10,10 +10,9 @@
|
||||
namespace sysy {
|
||||
|
||||
RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) : MFunc(mfunc) {
|
||||
// 1. 初始化可分配的整数寄存器池
|
||||
allocable_int_regs = {
|
||||
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3,
|
||||
PhysicalReg::T4, /*PhysicalReg::T5,*/ PhysicalReg::T6, // T5是大立即数传送寄存器
|
||||
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,
|
||||
@@ -21,39 +20,26 @@ RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) : MFunc(mfunc) {
|
||||
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
|
||||
};
|
||||
|
||||
// 2. 初始化可分配的浮点寄存器池
|
||||
allocable_fp_regs = {
|
||||
// 浮点临时寄存器 ft0-ft11
|
||||
PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3,
|
||||
PhysicalReg::F4, PhysicalReg::F5, PhysicalReg::F6, PhysicalReg::F7,
|
||||
PhysicalReg::F28, PhysicalReg::F29, PhysicalReg::F30, PhysicalReg::F31,
|
||||
// 浮点参数/返回值寄存器 fa0-fa7
|
||||
PhysicalReg::F10, PhysicalReg::F11, PhysicalReg::F12, PhysicalReg::F13,
|
||||
PhysicalReg::F14, PhysicalReg::F15, PhysicalReg::F16, PhysicalReg::F17,
|
||||
// 浮点保存寄存器 fs0-fs11
|
||||
PhysicalReg::F8, PhysicalReg::F9,
|
||||
PhysicalReg::F18, PhysicalReg::F19, PhysicalReg::F20, PhysicalReg::F21,
|
||||
PhysicalReg::F22, PhysicalReg::F23, PhysicalReg::F24, PhysicalReg::F25,
|
||||
PhysicalReg::F26, PhysicalReg::F27
|
||||
// 创建一个包含所有通用整数寄存器的临时列表
|
||||
const std::vector<PhysicalReg> all_int_regs = {
|
||||
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3,
|
||||
PhysicalReg::T4, PhysicalReg::T5, PhysicalReg::T6,
|
||||
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3,
|
||||
PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7,
|
||||
PhysicalReg::S0, PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3,
|
||||
PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
|
||||
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
|
||||
};
|
||||
|
||||
// 3. 映射所有物理寄存器(包括整数、浮点和特殊寄存器)到特殊的虚拟寄存器ID
|
||||
// 这是为了让活跃性分析和干扰图构建能够统一处理所有类型的寄存器
|
||||
for (int i = 0; i < static_cast<int>(PhysicalReg::PHYS_REG_START_ID); ++i) {
|
||||
auto preg = static_cast<PhysicalReg>(i);
|
||||
preg_to_vreg_id_map[preg] = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID) + i;
|
||||
|
||||
// 映射物理寄存器到特殊的虚拟寄存器ID,用于干扰图中的物理寄存器节点
|
||||
// 确保这些特殊ID不会与vreg_counter生成的常规虚拟寄存器ID冲突
|
||||
for (PhysicalReg preg : all_int_regs) {
|
||||
preg_to_vreg_id_map[preg] = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID) + static_cast<unsigned>(preg);
|
||||
}
|
||||
}
|
||||
|
||||
// 寄存器分配的主入口点
|
||||
void RISCv64RegAlloc::run() {
|
||||
// --- 在所有流程开始前,构建完整的vreg到Value的反向映射 ---
|
||||
const auto& vreg_map_from_isel = MFunc->getISel()->getVRegMap();
|
||||
for (const auto& pair : vreg_map_from_isel) {
|
||||
Value* val = pair.first;
|
||||
unsigned vreg = pair.second;
|
||||
vreg_to_value_map[vreg] = val;
|
||||
}
|
||||
// 阶段 1: 处理函数调用约定(参数寄存器预着色)
|
||||
handleCallingConvention();
|
||||
// 阶段 2: 消除帧索引(为局部变量和栈参数分配栈偏移)
|
||||
@@ -82,10 +68,7 @@ void RISCv64RegAlloc::run() {
|
||||
// 阶段 5: 图着色算法分配物理寄存器
|
||||
colorGraph();
|
||||
// 阶段 6: 重写函数(插入溢出/填充代码,替换虚拟寄存器为物理寄存器)
|
||||
rewriteFunction();
|
||||
|
||||
// 将最终的寄存器分配结果保存到MachineFunction的帧信息中,供后续Pass使用
|
||||
MFunc->getFrameInfo().vreg_to_preg_map = this->color_map;
|
||||
rewriteFunction();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,38 +82,35 @@ void RISCv64RegAlloc::handleCallingConvention() {
|
||||
RISCv64ISel* isel = MFunc->getISel();
|
||||
|
||||
// --- 部分1:处理函数传入参数的预着色 ---
|
||||
// 获取函数的Argument对象列表
|
||||
if (F) {
|
||||
auto& args = F->getArguments();
|
||||
|
||||
// [修改] 为整数参数和浮点参数分别维护索引
|
||||
int int_arg_idx = 0;
|
||||
int float_arg_idx = 0;
|
||||
|
||||
// RISC-V RV64G调用约定:前8个整型/指针参数通过 a0-a7 传递
|
||||
int arg_idx = 0;
|
||||
// 遍历 Argument* 列表
|
||||
for (Argument* arg : args) {
|
||||
// [修改] 根据参数类型决定使用哪个寄存器池和索引
|
||||
if (arg->getType()->isFloat()) {
|
||||
// --- 处理浮点参数 ---
|
||||
if (float_arg_idx >= 8) continue; // fa0-fa7
|
||||
|
||||
unsigned vreg = isel->getVReg(arg);
|
||||
// 浮点参数使用 fa10-fa17 (在RISC-V ABI中对应F10-F17)
|
||||
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + float_arg_idx);
|
||||
color_map[vreg] = preg;
|
||||
float_arg_idx++;
|
||||
|
||||
} else {
|
||||
// --- 处理整数/指针参数 (原有逻辑) ---
|
||||
if (int_arg_idx >= 8) continue; // a0-a7
|
||||
|
||||
unsigned vreg = isel->getVReg(arg);
|
||||
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + int_arg_idx);
|
||||
color_map[vreg] = preg;
|
||||
int_arg_idx++;
|
||||
if (arg_idx >= 8) {
|
||||
break;
|
||||
}
|
||||
// 获取该 Argument 对象对应的虚拟寄存器ID
|
||||
// 通过 MachineFunction -> RISCv64ISel -> vreg_map 来获取
|
||||
const auto& vreg_map_from_isel = MFunc->getISel()->getVRegMap();
|
||||
assert(vreg_map_from_isel.count(arg) && "Argument not found in ISel's vreg_map!");
|
||||
// 1. 获取该 Argument 对象对应的虚拟寄存器
|
||||
unsigned vreg = isel->getVReg(arg);
|
||||
|
||||
// 2. 根据参数索引,确定对应的物理寄存器 (a0, a1, ...)
|
||||
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + arg_idx);
|
||||
|
||||
// 3. 在 color_map 中,将 vreg "预着色" 为对应的物理寄存器
|
||||
color_map[vreg] = preg;
|
||||
|
||||
arg_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
// --- 部分2:为CALL指令的返回值预着色 ---
|
||||
// // --- 部分2:[新逻辑] 遍历所有指令,为CALL指令的返回值预着色为 a0 ---
|
||||
// // 这是为了强制寄存器分配器知道,call的结果物理上出现在a0寄存器。
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
for (auto& instr : mbb->getInstructions()) {
|
||||
if (instr->getOpcode() == RVOpcodes::CALL) {
|
||||
@@ -141,17 +121,11 @@ void RISCv64RegAlloc::handleCallingConvention() {
|
||||
auto reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
|
||||
if (reg_op->isVirtual()) {
|
||||
unsigned ret_vreg = reg_op->getVRegNum();
|
||||
|
||||
// [修改] 检查返回值的类型,预着色到 a0 或 fa0
|
||||
assert(MFunc->getISel()->getVRegValueMap().count(ret_vreg) && "Return vreg not found in value map!");
|
||||
Value* ret_val = MFunc->getISel()->getVRegValueMap().at(ret_vreg);
|
||||
|
||||
if (ret_val->getType()->isFloat()) {
|
||||
// 浮点返回值预着色到 fa0 (F10)
|
||||
color_map[ret_vreg] = PhysicalReg::F10;
|
||||
} else {
|
||||
// 整数/指针返回值预着色到 a0
|
||||
color_map[ret_vreg] = PhysicalReg::A0;
|
||||
// 强制将这个虚拟寄存器预着色为 a0
|
||||
color_map[ret_vreg] = PhysicalReg::A0;
|
||||
if (DEBUG) {
|
||||
std::cout << "[DEBUG] Pre-coloring vreg" << ret_vreg
|
||||
<< " to a0 for CALL instruction." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -244,30 +218,6 @@ void RISCv64RegAlloc::eliminateFrameIndices() {
|
||||
std::make_unique<ImmOperand>(0)));
|
||||
new_instructions.push_back(std::move(load_instr));
|
||||
|
||||
} else if (opcode == RVOpcodes::FRAME_LOAD_F) {
|
||||
// 展开浮点加载伪指令
|
||||
RVOpcodes real_load_op = RVOpcodes::FLW; // 对应的真实指令是 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();
|
||||
|
||||
// 展开为: 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));
|
||||
|
||||
// 展开为: 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) {
|
||||
// 确定要生成的真实存储指令是 sw 还是 sd
|
||||
RVOpcodes real_store_op = (opcode == RVOpcodes::FRAME_STORE_W) ? RVOpcodes::SW : RVOpcodes::SD;
|
||||
@@ -293,30 +243,6 @@ void RISCv64RegAlloc::eliminateFrameIndices() {
|
||||
std::make_unique<ImmOperand>(0)));
|
||||
new_instructions.push_back(std::move(store_instr));
|
||||
|
||||
} else if (opcode == RVOpcodes::FRAME_STORE_F) {
|
||||
// 展开浮点存储伪指令
|
||||
RVOpcodes real_store_op = RVOpcodes::FSW; // 对应的真实指令是 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();
|
||||
|
||||
// 展开为: 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));
|
||||
|
||||
// 展开为: 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();
|
||||
@@ -351,7 +277,7 @@ void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet&
|
||||
|
||||
// 1. 特殊指令的 `is_def` 标志调整
|
||||
// 这些指令的第一个寄存器操作数是源操作数 (use),而不是目标操作数 (def)。
|
||||
if (opcode == RVOpcodes::SW || opcode == RVOpcodes::SD || opcode == RVOpcodes::FSW ||
|
||||
if (opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
|
||||
opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
|
||||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
|
||||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
|
||||
@@ -398,27 +324,6 @@ void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet&
|
||||
}
|
||||
return; // CALL 指令处理完毕
|
||||
}
|
||||
|
||||
// 2.1 浮点比较指令添加特殊规则
|
||||
// 它们的源操作数是浮点寄存器,但目标操作数是整数寄存器
|
||||
if (opcode == RVOpcodes::FEQ_S || opcode == RVOpcodes::FLT_S || opcode == RVOpcodes::FLE_S) {
|
||||
auto& operands = instr->getOperands();
|
||||
// Def: 第一个操作数 (整数vreg)
|
||||
if (operands[0]->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(operands[0].get());
|
||||
if(reg_op->isVirtual()) def.insert(reg_op->getVRegNum());
|
||||
}
|
||||
// Use: 第二、三个操作数 (浮点vreg)
|
||||
if (operands[1]->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(operands[1].get());
|
||||
if(reg_op->isVirtual()) use.insert(reg_op->getVRegNum());
|
||||
}
|
||||
if (operands[2]->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(operands[2].get());
|
||||
if(reg_op->isVirtual()) use.insert(reg_op->getVRegNum());
|
||||
}
|
||||
return; // 处理完毕
|
||||
}
|
||||
|
||||
// 3. 对其他所有指令的通用处理逻辑 [已重构和修复]
|
||||
for (const auto& op : instr->getOperands()) {
|
||||
@@ -446,7 +351,7 @@ void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet&
|
||||
}
|
||||
}
|
||||
} 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()) {
|
||||
@@ -459,7 +364,7 @@ void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet&
|
||||
}
|
||||
|
||||
// 对于存储内存指令 (SW, SD),要存储的值(第一个操作数)也是 `use`
|
||||
if ((opcode == RVOpcodes::SW || opcode == RVOpcodes::SD || opcode == RVOpcodes::FSW) &&
|
||||
if ((opcode == RVOpcodes::SW || opcode == RVOpcodes::SD) &&
|
||||
!instr->getOperands().empty() &&
|
||||
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
|
||||
auto src_reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
|
||||
@@ -700,53 +605,28 @@ void RISCv64RegAlloc::buildInterferenceGraph() {
|
||||
}
|
||||
// CALL 指令会定义(杀死)所有调用者保存的寄存器。
|
||||
// 因此,所有调用者保存的物理寄存器都与 CALL 指令的 live_out 中的所有变量冲突。
|
||||
|
||||
// 辅助函数,用于判断一个vreg是整数类型还是浮点类型
|
||||
auto is_fp_vreg = [&](unsigned vreg) {
|
||||
if (vreg_to_value_map.count(vreg)) {
|
||||
return vreg_to_value_map.at(vreg)->getType()->isFloat();
|
||||
}
|
||||
// 对于ISel创建的、没有直接IR Value对应的临时vreg,
|
||||
// 默认其为整数类型。这是一个合理的兜底策略。
|
||||
return false;
|
||||
};
|
||||
|
||||
// --- 处理整数寄存器干扰 ---
|
||||
const std::vector<PhysicalReg>& caller_saved_int_regs = getCallerSavedIntRegs();
|
||||
for (PhysicalReg cs_reg : caller_saved_int_regs) {
|
||||
// 确保物理寄存器在映射表中,我们已在构造函数中保证了这一点
|
||||
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg);
|
||||
const std::vector<PhysicalReg>& caller_saved_regs = getCallerSavedIntRegs();
|
||||
for (PhysicalReg cs_reg : caller_saved_regs) {
|
||||
if (preg_to_vreg_id_map.count(cs_reg)) {
|
||||
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg); // 获取物理寄存器对应的特殊vreg ID
|
||||
|
||||
for (unsigned live_vreg_out : live_out) {
|
||||
// 只为整数vreg添加与整数preg的干扰
|
||||
if (!is_fp_vreg(live_vreg_out)) {
|
||||
if (cs_vreg_id != live_vreg_out) {
|
||||
// 将这个物理寄存器节点与 CALL 指令的 live_out 中的所有虚拟寄存器添加干扰边。
|
||||
for (unsigned live_vreg_out : live_out) {
|
||||
if (cs_vreg_id != live_vreg_out) { // 避免自己和自己干扰
|
||||
// [新增调试逻辑] 打印添加的干扰边及其原因
|
||||
if (DEEPDEBUG && interference_graph[cs_vreg_id].find(live_vreg_out) == interference_graph[cs_vreg_id].end()) {
|
||||
std::cerr << " Edge (CALL, Int): preg(" << static_cast<int>(cs_reg) << ") <-> %vreg" << live_vreg_out << "\n";
|
||||
std::cerr << " Edge (CALL) : preg(" << static_cast<int>(cs_reg) << ") <-> %vreg" << live_vreg_out << "\n";
|
||||
}
|
||||
interference_graph[cs_vreg_id].insert(live_vreg_out);
|
||||
interference_graph[live_vreg_out].insert(cs_vreg_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- 处理浮点寄存器干扰 ---
|
||||
const std::vector<PhysicalReg>& caller_saved_fp_regs = getCallerSavedFpRegs();
|
||||
for (PhysicalReg cs_reg : caller_saved_fp_regs) {
|
||||
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg);
|
||||
|
||||
for (unsigned live_vreg_out : live_out) {
|
||||
// 只为浮点vreg添加与浮点preg的干扰
|
||||
if (is_fp_vreg(live_vreg_out)) {
|
||||
if (cs_vreg_id != live_vreg_out) {
|
||||
// 添加与整数版本一致的调试代码
|
||||
if (DEEPDEBUG && interference_graph[cs_vreg_id].find(live_vreg_out) == interference_graph[cs_vreg_id].end()) {
|
||||
std::cerr << " Edge (CALL, FP): preg(" << static_cast<int>(cs_reg) << ") <-> %vreg" << live_vreg_out << "\n";
|
||||
}
|
||||
interference_graph[cs_vreg_id].insert(live_vreg_out);
|
||||
interference_graph[live_vreg_out].insert(cs_vreg_id);
|
||||
}
|
||||
} else {
|
||||
// 如果物理寄存器没有对应的特殊虚拟寄存器ID,可能是因为它不是调用者保存的寄存器。
|
||||
// 这种情况通常不应该发生,但我们可以在这里添加一个警告或错误处理。
|
||||
if (DEEPDEBUG) {
|
||||
std::cerr << "Warning: Physical register " << static_cast<int>(cs_reg)
|
||||
<< " does not have a corresponding special vreg ID.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -770,70 +650,34 @@ void RISCv64RegAlloc::colorGraph() {
|
||||
return interference_graph[a].size() > interference_graph[b].size();
|
||||
});
|
||||
|
||||
// [调试] 辅助函数,用于判断一个vreg是整数还是浮点类型,并打印详细诊断信息
|
||||
auto is_fp_vreg = [&](unsigned vreg) {
|
||||
if (DEEPDEBUG) {
|
||||
std::cout << " [Debug is_fp_vreg] Checking vreg" << vreg << ": ";
|
||||
}
|
||||
if (vreg_to_value_map.count(vreg)) {
|
||||
Value* val = vreg_to_value_map.at(vreg);
|
||||
bool is_float = val->getType()->isFloat();
|
||||
if (DEEPDEBUG) {
|
||||
std::cout << "Found in map. Value is '" << val->getName()
|
||||
<< "', Type is " << (is_float ? "FLOAT" : "INT")
|
||||
<< ". Returning " << (is_float ? "true" : "false") << ".\n";
|
||||
}
|
||||
return is_float;
|
||||
}
|
||||
|
||||
if (DEEPDEBUG) {
|
||||
std::cout << "NOT found in vreg_to_value_map. Defaulting to INT. Returning false.\n";
|
||||
}
|
||||
// 对于ISel创建的、没有直接IR Value对应的临时vreg,默认其为整数类型。
|
||||
return false;
|
||||
};
|
||||
|
||||
// 着色
|
||||
for (unsigned vreg : sorted_vregs) {
|
||||
std::set<PhysicalReg> used_colors;
|
||||
for (unsigned neighbor_id : interference_graph.at(vreg)) {
|
||||
// 收集邻居颜色的逻辑保持不变
|
||||
// --- 关键改进 (来自 rec 分支) ---
|
||||
|
||||
// 情况 1: 邻居是一个已经被着色的虚拟寄存器
|
||||
if (color_map.count(neighbor_id)) {
|
||||
used_colors.insert(color_map.at(neighbor_id));
|
||||
}
|
||||
// 情况 2: 邻居本身就是一个代表物理寄存器的节点
|
||||
else if (neighbor_id >= static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID)) {
|
||||
// 从特殊ID反向解析出是哪个物理寄存器
|
||||
PhysicalReg neighbor_preg = static_cast<PhysicalReg>(neighbor_id - static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID));
|
||||
used_colors.insert(neighbor_preg);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_float = is_fp_vreg(vreg);
|
||||
const auto& allocable_regs = is_float ? allocable_fp_regs : allocable_int_regs;
|
||||
|
||||
// [调试] 打印着色决策过程
|
||||
if (DEBUG) {
|
||||
std::cout << "[DEBUG] Coloring %vreg" << vreg
|
||||
<< ": Type is " << (is_float ? "FLOAT" : "INT")
|
||||
<< ", choosing from " << (is_float ? "Float" : "Integer") << " pool.\n";
|
||||
}
|
||||
|
||||
bool colored = false;
|
||||
for (PhysicalReg preg : allocable_regs) {
|
||||
for (PhysicalReg preg : allocable_int_regs) {
|
||||
if (used_colors.find(preg) == used_colors.end()) {
|
||||
color_map[vreg] = preg;
|
||||
colored = true;
|
||||
if (DEBUG) {
|
||||
RISCv64AsmPrinter p(MFunc); // For regToString
|
||||
std::cout << " -> Assigned to physical register: " << p.regToString(preg) << "\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!colored) {
|
||||
spilled_vregs.insert(vreg);
|
||||
if (DEBUG) {
|
||||
std::cout << " -> FAILED to color. Spilling.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -842,7 +686,7 @@ void RISCv64RegAlloc::rewriteFunction() {
|
||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||
int current_offset = frame_info.locals_size;
|
||||
|
||||
// --- 动态计算溢出槽大小 ---
|
||||
// --- FIX 1: 动态计算溢出槽大小 ---
|
||||
// 根据溢出虚拟寄存器的真实类型,为其在栈上分配正确大小的空间。
|
||||
for (unsigned vreg : spilled_vregs) {
|
||||
// 从反向映射中查找 vreg 对应的 IR Value
|
||||
@@ -860,40 +704,23 @@ void RISCv64RegAlloc::rewriteFunction() {
|
||||
}
|
||||
frame_info.spill_size = current_offset - frame_info.locals_size;
|
||||
|
||||
// 定义专用的溢出寄存器
|
||||
const PhysicalReg INT_SPILL_REG = PhysicalReg::T6; // t6
|
||||
const PhysicalReg FP_SPILL_REG = PhysicalReg::F7; // ft7
|
||||
|
||||
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);
|
||||
|
||||
// --- 为溢出的 'use' 操作数插入正确的加载指令 ---
|
||||
// --- FIX 2: 为溢出的 'use' 操作数插入正确的加载指令 ---
|
||||
for (unsigned vreg : use) {
|
||||
if (spilled_vregs.count(vreg)) {
|
||||
// 同样地,根据 vreg 的类型决定使用 lw 还是 ld
|
||||
assert(vreg_to_value_map.count(vreg));
|
||||
Value* val = vreg_to_value_map.at(vreg);
|
||||
|
||||
// 根据vreg类型决定加载指令(lw/ld/flw)和目标物理寄存器(t6/ft7)
|
||||
RVOpcodes load_op;
|
||||
PhysicalReg target_preg;
|
||||
if (val->getType()->isFloat()) {
|
||||
load_op = RVOpcodes::FLW;
|
||||
target_preg = FP_SPILL_REG;
|
||||
} else if (val->getType()->isPointer()) {
|
||||
load_op = RVOpcodes::LD;
|
||||
target_preg = INT_SPILL_REG;
|
||||
} else {
|
||||
load_op = RVOpcodes::LW;
|
||||
target_preg = INT_SPILL_REG;
|
||||
}
|
||||
RVOpcodes load_op = val->getType()->isPointer() ? RVOpcodes::LD : RVOpcodes::LW;
|
||||
|
||||
int offset = frame_info.spill_offsets.at(vreg);
|
||||
auto load = std::make_unique<MachineInstr>(load_op);
|
||||
load->addOperand(std::make_unique<RegOperand>(target_preg)); // 加载到专用溢出寄存器
|
||||
load->addOperand(std::make_unique<RegOperand>(vreg));
|
||||
load->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(offset)
|
||||
@@ -904,29 +731,17 @@ void RISCv64RegAlloc::rewriteFunction() {
|
||||
|
||||
new_instructions.push_back(std::move(instr_ptr));
|
||||
|
||||
// --- 为溢出的 'def' 操作数插入正确的存储指令 ---
|
||||
// --- FIX 3: 为溢出的 'def' 操作数插入正确的存储指令 ---
|
||||
for (unsigned vreg : def) {
|
||||
if (spilled_vregs.count(vreg)) {
|
||||
// 根据 vreg 的类型决定使用 sw 还是 sd
|
||||
assert(vreg_to_value_map.count(vreg));
|
||||
Value* val = vreg_to_value_map.at(vreg);
|
||||
|
||||
// 根据vreg类型决定存储指令(sw/sd/fsw)和源物理寄存器(t6/ft7)
|
||||
RVOpcodes store_op;
|
||||
PhysicalReg src_preg;
|
||||
if (val->getType()->isFloat()) {
|
||||
store_op = RVOpcodes::FSW;
|
||||
src_preg = FP_SPILL_REG;
|
||||
} else if (val->getType()->isPointer()) {
|
||||
store_op = RVOpcodes::SD;
|
||||
src_preg = INT_SPILL_REG;
|
||||
} else {
|
||||
store_op = RVOpcodes::SW;
|
||||
src_preg = INT_SPILL_REG;
|
||||
}
|
||||
RVOpcodes store_op = val->getType()->isPointer() ? RVOpcodes::SD : RVOpcodes::SW;
|
||||
|
||||
int offset = frame_info.spill_offsets.at(vreg);
|
||||
auto store = std::make_unique<MachineInstr>(store_op);
|
||||
store->addOperand(std::make_unique<RegOperand>(src_preg)); // 从专用溢出寄存器存储
|
||||
store->addOperand(std::make_unique<RegOperand>(vreg));
|
||||
store->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(offset)
|
||||
@@ -942,29 +757,40 @@ void RISCv64RegAlloc::rewriteFunction() {
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||
for (auto& op_ptr : instr_ptr->getOperands()) {
|
||||
// 定义一个处理寄存器操作数的 lambda 函数
|
||||
auto process_reg_op = [&](RegOperand* reg_op) {
|
||||
|
||||
// 情况一:操作数本身就是一个寄存器 (例如 add rd, rs1, rs2 中的所有操作数)
|
||||
if(op_ptr->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(op_ptr.get());
|
||||
if (reg_op->isVirtual()) {
|
||||
unsigned vreg = reg_op->getVRegNum();
|
||||
if (color_map.count(vreg)) {
|
||||
reg_op->setPReg(color_map.at(vreg));
|
||||
PhysicalReg preg = color_map.at(vreg);
|
||||
reg_op->setPReg(preg);
|
||||
} else if (spilled_vregs.count(vreg)) {
|
||||
// 根据vreg类型,替换为对应的专用溢出寄存器
|
||||
assert(vreg_to_value_map.count(vreg));
|
||||
Value* val = vreg_to_value_map.at(vreg);
|
||||
if (val->getType()->isFloat()) {
|
||||
reg_op->setPReg(FP_SPILL_REG);
|
||||
} else {
|
||||
reg_op->setPReg(INT_SPILL_REG);
|
||||
}
|
||||
// 如果vreg被溢出,替换为专用的溢出物理寄存器t6
|
||||
reg_op->setPReg(PhysicalReg::T6);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 情况二:操作数是一个内存地址 (例如 lw rd, offset(rs1) 中的 offset(rs1))
|
||||
else if (op_ptr->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto mem_op = static_cast<MemOperand*>(op_ptr.get());
|
||||
// 获取内存操作数内部的“基址寄存器”
|
||||
auto base_reg_op = mem_op->getBase();
|
||||
|
||||
// 对这个基址寄存器,执行与情况一完全相同的替换逻辑
|
||||
if(base_reg_op->isVirtual()){
|
||||
unsigned vreg = base_reg_op->getVRegNum();
|
||||
if(color_map.count(vreg)) {
|
||||
// 如果基址vreg被成功着色,替换
|
||||
PhysicalReg preg = color_map.at(vreg);
|
||||
base_reg_op->setPReg(preg);
|
||||
|
||||
} else if (spilled_vregs.count(vreg)) {
|
||||
// 如果基址vreg被溢出,替换为t6
|
||||
base_reg_op->setPReg(PhysicalReg::T6);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if(op_ptr->getKind() == MachineOperand::KIND_REG) {
|
||||
process_reg_op(static_cast<RegOperand*>(op_ptr.get()));
|
||||
} else if (op_ptr->getKind() == MachineOperand::KIND_MEM) {
|
||||
process_reg_op(static_cast<MemOperand*>(op_ptr.get())->getBase());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,26 +12,6 @@ namespace sysy {
|
||||
* * 主要目标是优化寄存器分配器插入的spill/fill代码(lw/sw),
|
||||
* 尝试将加载指令提前,以隐藏其访存延迟。
|
||||
*/
|
||||
struct MemoryAccess {
|
||||
PhysicalReg base_reg;
|
||||
int64_t offset;
|
||||
bool valid;
|
||||
|
||||
MemoryAccess() : valid(false) {}
|
||||
MemoryAccess(PhysicalReg base, int64_t off) : base_reg(base), offset(off), valid(true) {}
|
||||
};
|
||||
|
||||
struct InstrRegInfo {
|
||||
std::unordered_set<PhysicalReg> defined_regs;
|
||||
std::unordered_set<PhysicalReg> used_regs;
|
||||
bool is_load;
|
||||
bool is_store;
|
||||
bool is_control_flow;
|
||||
MemoryAccess mem_access;
|
||||
|
||||
InstrRegInfo() : is_load(false), is_store(false), is_control_flow(false) {}
|
||||
};
|
||||
|
||||
class PostRA_Scheduler : public Pass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
@@ -18,12 +18,12 @@ public:
|
||||
void printInstruction(MachineInstr* instr, bool debug = false);
|
||||
// 辅助函数
|
||||
void setStream(std::ostream& os) { OS = &os; }
|
||||
// 辅助函数
|
||||
std::string regToString(PhysicalReg reg);
|
||||
private:
|
||||
// 打印各个部分
|
||||
void printBasicBlock(MachineBasicBlock* mbb, bool debug = false);
|
||||
|
||||
// 辅助函数
|
||||
std::string regToString(PhysicalReg reg);
|
||||
void printOperand(MachineOperand* op);
|
||||
|
||||
MachineFunction* MFunc;
|
||||
|
||||
@@ -17,11 +17,8 @@ public:
|
||||
// 公开接口,以便后续模块(如RegAlloc)可以查询或创建vreg
|
||||
unsigned getVReg(Value* val);
|
||||
unsigned getNewVReg() { return vreg_counter++; }
|
||||
unsigned getNewVReg(Type* type);
|
||||
// 获取 vreg_map 的公共接口
|
||||
const std::map<Value*, unsigned>& getVRegMap() const { return vreg_map; }
|
||||
const std::map<unsigned, Value*>& getVRegValueMap() const { return vreg_to_value_map; }
|
||||
const std::map<unsigned, Type*>& getVRegTypeMap() const { return vreg_type_map; }
|
||||
|
||||
private:
|
||||
// DAG节点定义,作为ISel的内部实现细节
|
||||
@@ -41,7 +38,6 @@ private:
|
||||
// 用于计算类型大小的辅助函数
|
||||
unsigned getTypeSizeInBytes(Type* type);
|
||||
|
||||
// 打印DAG图以供调试
|
||||
void print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, const std::string& bb_name);
|
||||
|
||||
// 状态
|
||||
@@ -51,8 +47,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;
|
||||
|
||||
@@ -32,6 +32,7 @@ enum class PhysicalReg {
|
||||
A0, A1, A2, A3, A4, A5, A6, A7,
|
||||
|
||||
// --- 浮点寄存器 ---
|
||||
// (保持您原有的 F0-F31 命名)
|
||||
F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11,
|
||||
F12, F13, F14, F15, F16, F17, F18, F19, F20, F21,
|
||||
F22, F23, F24, F25, F26, F27, F28, F29, F30, F31,
|
||||
@@ -63,97 +64,16 @@ enum class RVOpcodes {
|
||||
CALL,
|
||||
// 特殊标记,非指令
|
||||
LABEL,
|
||||
|
||||
// 浮点指令 (RISC-V 'F' 扩展)
|
||||
// 浮点加载与存储
|
||||
FLW, // flw rd, offset(rs1)
|
||||
FSW, // fsw rs2, offset(rs1)
|
||||
FLD, // fld rd, offset(rs1)
|
||||
FSD, // fsd rs2, offset(rs1)
|
||||
|
||||
// 浮点算术运算 (单精度)
|
||||
FADD_S, // fadd.s rd, rs1, rs2
|
||||
FSUB_S, // fsub.s rd, rs1, rs2
|
||||
FMUL_S, // fmul.s rd, rs1, rs2
|
||||
FDIV_S, // fdiv.s rd, rs1, rs2
|
||||
|
||||
// 浮点比较 (单精度)
|
||||
FEQ_S, // feq.s rd, rs1, rs2 (结果写入整数寄存器rd)
|
||||
FLT_S, // flt.s rd, rs1, rs2 (less than)
|
||||
FLE_S, // fle.s rd, rs1, rs2 (less than or equal)
|
||||
|
||||
// 浮点转换
|
||||
FCVT_S_W, // fcvt.s.w rd, rs1 (有符号整数 -> 单精度浮点)
|
||||
FCVT_W_S, // fcvt.w.s rd, rs1 (单精度浮点 -> 有符号整数)
|
||||
|
||||
// 浮点传送/移动
|
||||
FMV_S, // fmv.s rd, rs1 (浮点寄存器之间)
|
||||
FMV_W_X, // fmv.w.x rd, rs1 (整数寄存器位模式 -> 浮点寄存器)
|
||||
FMV_X_W, // fmv.x.w rd, rs1 (浮点寄存器位模式 -> 整数寄存器)
|
||||
FNEG_S, // fneg.s rd, rs (浮点取负)
|
||||
|
||||
// 新增伪指令,用于解耦栈帧处理
|
||||
FRAME_LOAD_W, // 从栈帧加载 32位 Word (对应 lw)
|
||||
FRAME_LOAD_D, // 从栈帧加载 64位 Doubleword (对应 ld)
|
||||
FRAME_STORE_W, // 保存 32位 Word 到栈帧 (对应 sw)
|
||||
FRAME_STORE_D, // 保存 64位 Doubleword 到栈帧 (对应 sd)
|
||||
FRAME_LOAD_F, // 从栈帧加载单精度浮点数
|
||||
FRAME_STORE_F, // 将单精度浮点数存入栈帧
|
||||
FRAME_ADDR, // 获取栈帧变量的地址
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
// 定义一个全局辅助函数或常量,提供调用者保存寄存器列表
|
||||
const std::vector<PhysicalReg>& getCallerSavedIntRegs();
|
||||
|
||||
class MachineOperand;
|
||||
class RegOperand;
|
||||
@@ -279,7 +199,6 @@ struct StackFrameInfo {
|
||||
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;
|
||||
};
|
||||
|
||||
// 机器函数
|
||||
@@ -305,6 +224,15 @@ private:
|
||||
StackFrameInfo frame_info;
|
||||
};
|
||||
|
||||
inline const std::vector<PhysicalReg>& getCallerSavedIntRegs() {
|
||||
static const std::vector<PhysicalReg> regs = {
|
||||
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3,
|
||||
PhysicalReg::T4, PhysicalReg::T5, PhysicalReg::T6,
|
||||
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3,
|
||||
PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7
|
||||
};
|
||||
return regs;
|
||||
}
|
||||
} // namespace sysy
|
||||
|
||||
#endif // RISCV64_LLIR_H
|
||||
@@ -56,7 +56,6 @@ private:
|
||||
|
||||
// 可用的物理寄存器池
|
||||
std::vector<PhysicalReg> allocable_int_regs;
|
||||
std::vector<PhysicalReg> allocable_fp_regs;
|
||||
|
||||
// 存储vreg到IR Value*的反向映射
|
||||
// 这个map将在run()函数开始时被填充,并在rewriteFunction()中使用。
|
||||
|
||||
@@ -514,12 +514,15 @@ public:
|
||||
explicit BasicBlock(Function *parent, const std::string &name = "")
|
||||
: Value(Type::getLabelType(), name), parent(parent) {}
|
||||
~BasicBlock() override {
|
||||
for (auto pre : predecessors) {
|
||||
pre->removeSuccessor(this);
|
||||
}
|
||||
for (auto suc : successors) {
|
||||
suc->removePredecessor(this);
|
||||
}
|
||||
// for (auto pre : predecessors) {
|
||||
// pre->removeSuccessor(this);
|
||||
// }
|
||||
// for (auto suc : successors) {
|
||||
// suc->removePredecessor(this);
|
||||
// }
|
||||
// 这些关系应该在 BasicBlock 被从 Function 中移除时,
|
||||
// 由负责 CFG 优化的 Pass (例如 SCCP 的 RemoveDeadBlock) 显式地清理。
|
||||
// 析构函数只负责清理 BasicBlock 自身拥有的资源(例如,指令列表)。
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -599,7 +602,7 @@ public:
|
||||
prev->addSuccessor(next);
|
||||
next->addPredecessor(prev);
|
||||
}
|
||||
void removeInst(iterator pos) { instructions.erase(pos); }
|
||||
iterator removeInst(iterator pos) { return instructions.erase(pos); }
|
||||
void removeInst(Instruction *inst) {
|
||||
auto pos = std::find_if(instructions.begin(), instructions.end(),
|
||||
[inst](const std::unique_ptr<Instruction> &i) { return i.get() == inst; });
|
||||
@@ -626,6 +629,21 @@ class User : public Value {
|
||||
explicit User(Type *type, const std::string &name = "") : Value(type, name) {}
|
||||
|
||||
public:
|
||||
// ~User() override {
|
||||
// // 当 User 对象被销毁时(例如,LoadInst 或 StoreInst 被删除时),
|
||||
// // 它必须通知它所使用的所有 Value,将对应的 Use 关系从它们的 uses 列表中移除。
|
||||
// // 这样可以防止 Value 的 uses 列表中出现悬空的 Use 对象。
|
||||
// for (const auto &use_ptr : operands) {
|
||||
// // 确保 use_ptr 非空,并且其内部指向的 Value* 也非空
|
||||
// // (虽然通常情况下不会为空,但为了健壮性考虑)
|
||||
// if (use_ptr && use_ptr->getValue()) {
|
||||
// use_ptr->getValue()->removeUse(use_ptr);
|
||||
// }
|
||||
// }
|
||||
// // operands 向量本身是 std::vector<std::shared_ptr<Use>>,
|
||||
// // 在此析构函数结束后,operands 向量会被销毁,其内部的 shared_ptr 也会被释放,
|
||||
// // 如果 shared_ptr 引用计数降为0,Use 对象本身也会被销毁。
|
||||
// }
|
||||
unsigned getNumOperands() const { return operands.size(); } ///< 获取操作数数量
|
||||
auto operand_begin() const { return operands.begin(); } ///< 返回操作数列表的开头迭代器
|
||||
auto operand_end() const { return operands.end(); } ///< 返回操作数列表的结尾迭代器
|
||||
@@ -695,15 +713,13 @@ class Instruction : public User {
|
||||
kCondBr = 0x1UL << 30,
|
||||
kBr = 0x1UL << 31,
|
||||
kReturn = 0x1UL << 32,
|
||||
kUnreachable = 0x1UL << 33,
|
||||
// mem op
|
||||
kAlloca = 0x1UL << 33,
|
||||
kLoad = 0x1UL << 34,
|
||||
kStore = 0x1UL << 35,
|
||||
kGetElementPtr = 0x1UL << 36,
|
||||
kMemset = 0x1UL << 37,
|
||||
// kGetSubArray = 0x1UL << 38,
|
||||
// Constant Kind removed as Constants are now Values, not Instructions.
|
||||
// kConstant = 0x1UL << 37, // Conflicts with kMemset if kept as is
|
||||
kAlloca = 0x1UL << 34,
|
||||
kLoad = 0x1UL << 35,
|
||||
kStore = 0x1UL << 36,
|
||||
kGetElementPtr = 0x1UL << 37,
|
||||
kMemset = 0x1UL << 38,
|
||||
// phi
|
||||
kPhi = 0x1UL << 39,
|
||||
kBitItoF = 0x1UL << 40,
|
||||
@@ -832,7 +848,7 @@ public:
|
||||
return kind & MemoryOpMask;
|
||||
}
|
||||
bool isTerminator() const {
|
||||
static constexpr uint64_t TerminatorOpMask = kCondBr | kBr | kReturn;
|
||||
static constexpr uint64_t TerminatorOpMask = kCondBr | kBr | kReturn | kUnreachable;
|
||||
return kind & TerminatorOpMask;
|
||||
}
|
||||
bool isCmp() const {
|
||||
@@ -852,6 +868,7 @@ public:
|
||||
}
|
||||
bool isUnconditional() const { return kind == kBr; }
|
||||
bool isConditional() const { return kind == kCondBr; }
|
||||
bool isCondBr() const { return kind == kCondBr; }
|
||||
bool isPhi() const { return kind == kPhi; }
|
||||
bool isAlloca() const { return kind == kAlloca; }
|
||||
bool isLoad() const { return kind == kLoad; }
|
||||
@@ -860,6 +877,7 @@ public:
|
||||
bool isMemset() const { return kind == kMemset; }
|
||||
bool isCall() const { return kind == kCall; }
|
||||
bool isReturn() const { return kind == kReturn; }
|
||||
bool isUnreachable() const { return kind == kUnreachable; }
|
||||
bool isDefine() const {
|
||||
static constexpr uint64_t DefineOpMask = kAlloca | kStore | kPhi;
|
||||
return (kind & DefineOpMask) != 0U;
|
||||
@@ -894,6 +912,9 @@ class PhiInst : public Instruction {
|
||||
public:
|
||||
Value* getValue(unsigned k) const {return getOperand(2 * k);} ///< 获取位置为k的值
|
||||
BasicBlock* getBlock(unsigned k) const {return dynamic_cast<BasicBlock*>(getOperand(2 * k + 1));}
|
||||
//增加llvm同名方法实现获取value和block
|
||||
Value* getIncomingValue(unsigned k) const {return getOperand(2 * k);} ///< 获取位置为k的值
|
||||
BasicBlock* getIncomingBlock(unsigned k) const {return dynamic_cast<BasicBlock*>(getOperand(2 * k + 1));}
|
||||
|
||||
auto& getincomings() const {return blk2val;} ///< 获取所有的基本块和对应的值
|
||||
|
||||
@@ -1059,12 +1080,10 @@ class UncondBrInst : public Instruction {
|
||||
friend class Function;
|
||||
|
||||
protected:
|
||||
UncondBrInst(BasicBlock *block, std::vector<Value *> args,
|
||||
UncondBrInst(BasicBlock *block,
|
||||
BasicBlock *parent = nullptr)
|
||||
: Instruction(kBr, Type::getVoidType(), parent, "") {
|
||||
// assert(block->getNumArguments() == args.size());
|
||||
addOperand(block);
|
||||
addOperands(args);
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -1072,6 +1091,16 @@ public:
|
||||
auto getArguments() const {
|
||||
return make_range(std::next(operand_begin()), operand_end());
|
||||
}
|
||||
std::vector<BasicBlock *> getSuccessors() const {
|
||||
std::vector<BasicBlock *> succs;
|
||||
// 假设无条件分支的目标块是它的第一个操作数
|
||||
if (getNumOperands() > 0) {
|
||||
if (auto target_bb = dynamic_cast<BasicBlock *>(getOperand(0))) {
|
||||
succs.push_back(target_bb);
|
||||
}
|
||||
}
|
||||
return succs;
|
||||
}
|
||||
|
||||
}; // class UncondBrInst
|
||||
|
||||
@@ -1083,17 +1112,12 @@ class CondBrInst : public Instruction {
|
||||
friend class Function;
|
||||
|
||||
protected:
|
||||
CondBrInst(Value *condition, BasicBlock *thenBlock, BasicBlock *elseBlock,
|
||||
const std::vector<Value *> &thenArgs,
|
||||
const std::vector<Value *> &elseArgs, BasicBlock *parent = nullptr)
|
||||
CondBrInst(Value *condition, BasicBlock *thenBlock, BasicBlock *elseBlock,
|
||||
BasicBlock *parent = nullptr)
|
||||
: Instruction(kCondBr, Type::getVoidType(), parent, "") {
|
||||
// assert(thenBlock->getNumArguments() == thenArgs.size() and
|
||||
// elseBlock->getNumArguments() == elseArgs.size());
|
||||
addOperand(condition);
|
||||
addOperand(thenBlock);
|
||||
addOperand(elseBlock);
|
||||
addOperands(thenArgs);
|
||||
addOperands(elseArgs);
|
||||
}
|
||||
public:
|
||||
Value* getCondition() const { return getOperand(0); }
|
||||
@@ -1103,29 +1127,39 @@ public:
|
||||
BasicBlock* getElseBlock() const {
|
||||
return dynamic_cast<BasicBlock *>(getOperand(2));
|
||||
}
|
||||
// auto getThenArguments() const {
|
||||
// auto begin = std::next(operand_begin(), 3);
|
||||
// // auto end = std::next(begin, getThenBlock()->getNumArguments());
|
||||
// return make_range(begin, end);
|
||||
// }
|
||||
// auto getElseArguments() const {
|
||||
// auto begin =
|
||||
// std::next(operand_begin(), 3 + getThenBlock()->getNumArguments());
|
||||
// auto end = operand_end();
|
||||
// return make_range(begin, end);
|
||||
// }
|
||||
std::vector<BasicBlock *> getSuccessors() const {
|
||||
std::vector<BasicBlock *> succs;
|
||||
// 假设条件分支的真实块是第二个操作数,假块是第三个操作数
|
||||
// 操作数通常是:[0] 条件值, [1] TrueTargetBlock, [2] FalseTargetBlock
|
||||
if (getNumOperands() > 2) {
|
||||
if (auto true_bb = getThenBlock()) {
|
||||
succs.push_back(true_bb);
|
||||
}
|
||||
if (auto false_bb = getElseBlock()) {
|
||||
succs.push_back(false_bb);
|
||||
}
|
||||
}
|
||||
return succs;
|
||||
}
|
||||
|
||||
}; // class CondBrInst
|
||||
|
||||
class UnreachableInst : public Instruction {
|
||||
public:
|
||||
// 构造函数:设置指令类型为 kUnreachable
|
||||
explicit UnreachableInst(const std::string& name, BasicBlock *parent = nullptr)
|
||||
: Instruction(kUnreachable, Type::getVoidType(), parent, "") {}
|
||||
|
||||
};
|
||||
|
||||
//! Allocate memory for stack variables, used for non-global variable declartion
|
||||
class AllocaInst : public Instruction {
|
||||
friend class IRBuilder;
|
||||
friend class Function;
|
||||
protected:
|
||||
AllocaInst(Type *type, const std::vector<Value *> &dims = {},
|
||||
AllocaInst(Type *type,
|
||||
BasicBlock *parent = nullptr, const std::string &name = "")
|
||||
: Instruction(kAlloca, type, parent, name) {
|
||||
addOperands(dims);
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -1133,9 +1167,6 @@ public:
|
||||
Type* getAllocatedType() const {
|
||||
return getType()->as<PointerType>()->getBaseType();
|
||||
} ///< 获取分配的类型
|
||||
int getNumDims() const { return getNumOperands(); }
|
||||
auto getDims() const { return getOperands(); }
|
||||
Value* getDim(int index) { return getOperand(index); }
|
||||
|
||||
}; // class AllocaInst
|
||||
|
||||
@@ -1182,21 +1213,15 @@ class LoadInst : public Instruction {
|
||||
friend class Function;
|
||||
|
||||
protected:
|
||||
LoadInst(Value *pointer, const std::vector<Value *> &indices = {},
|
||||
LoadInst(Value *pointer,
|
||||
BasicBlock *parent = nullptr, const std::string &name = "")
|
||||
: Instruction(kLoad, pointer->getType()->as<PointerType>()->getBaseType(),
|
||||
parent, name) {
|
||||
addOperand(pointer);
|
||||
addOperands(indices);
|
||||
}
|
||||
|
||||
public:
|
||||
int getNumIndices() const { return getNumOperands() - 1; }
|
||||
Value* getPointer() const { return getOperand(0); }
|
||||
auto getIndices() const {
|
||||
return make_range(std::next(operand_begin()), operand_end());
|
||||
}
|
||||
Value* getIndex(int index) const { return getOperand(index + 1); }
|
||||
|
||||
}; // class LoadInst
|
||||
|
||||
@@ -1207,22 +1232,15 @@ class StoreInst : public Instruction {
|
||||
|
||||
protected:
|
||||
StoreInst(Value *value, Value *pointer,
|
||||
const std::vector<Value *> &indices = {},
|
||||
BasicBlock *parent = nullptr, const std::string &name = "")
|
||||
: Instruction(kStore, Type::getVoidType(), parent, name) {
|
||||
addOperand(value);
|
||||
addOperand(pointer);
|
||||
addOperands(indices);
|
||||
}
|
||||
|
||||
public:
|
||||
int getNumIndices() const { return getNumOperands() - 2; }
|
||||
Value* getValue() const { return getOperand(0); }
|
||||
Value* getPointer() const { return getOperand(1); }
|
||||
auto getIndices() const {
|
||||
return make_range(std::next(operand_begin(), 2), operand_end());
|
||||
}
|
||||
Value* getIndex(int index) const { return getOperand(index + 2); }
|
||||
|
||||
}; // class StoreInst
|
||||
|
||||
@@ -1361,20 +1379,18 @@ protected:
|
||||
|
||||
protected:
|
||||
GlobalValue(Module *parent, Type *type, const std::string &name,
|
||||
const std::vector<Value *> &dims = {},
|
||||
ValueCounter init = {})
|
||||
: Value(type, name), parent(parent) {
|
||||
assert(type->isPointer());
|
||||
// addOperands(dims);
|
||||
// 维度信息已经被记录到Type中,dim只是为了方便初始化
|
||||
numDims = dims.size();
|
||||
numDims = 0;
|
||||
if (init.size() == 0) {
|
||||
unsigned num = 1;
|
||||
for (unsigned i = 0; i < numDims; i++) {
|
||||
// Assume dims elements are ConstantInteger and cast appropriately
|
||||
auto dim_val = dynamic_cast<ConstantInteger*>(dims[i]);
|
||||
assert(dim_val && "GlobalValue dims must be constant integers");
|
||||
num *= dim_val->getInt();
|
||||
auto arrayType = type->as<ArrayType>();
|
||||
while (arrayType) {
|
||||
numDims++;
|
||||
num *= arrayType->getNumElements();
|
||||
arrayType = arrayType->getElementType()->as<ArrayType>();
|
||||
}
|
||||
if (dynamic_cast<PointerType *>(type)->getBaseType() == Type::getFloatType()) {
|
||||
init.push_back(ConstantFloating::get(0.0F), num); // Use new constant factory
|
||||
@@ -1386,9 +1402,6 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
// unsigned getNumDims() const { return numDims; } ///< 获取维度数量
|
||||
// Value* getDim(unsigned index) const { return getOperand(index); } ///< 获取位置为index的维度
|
||||
// auto getDims() const { return getOperands(); } ///< 获取维度列表
|
||||
unsigned getNumIndices() const {
|
||||
return numDims;
|
||||
} ///< 获取维度数量
|
||||
@@ -1430,13 +1443,19 @@ class ConstantVariable : public Value {
|
||||
ValueCounter initValues; ///< 值
|
||||
|
||||
protected:
|
||||
ConstantVariable(Module *parent, Type *type, const std::string &name, const ValueCounter &init,
|
||||
const std::vector<Value *> &dims = {})
|
||||
ConstantVariable(Module *parent, Type *type, const std::string &name, const ValueCounter &init)
|
||||
: Value(type, name), parent(parent) {
|
||||
assert(type->isPointer());
|
||||
numDims = dims.size();
|
||||
// numDims = dims.size();
|
||||
numDims = 0;
|
||||
if(type->as<PointerType>()->getBaseType()->isArray()) {
|
||||
auto arrayType = type->as<ArrayType>();
|
||||
while (arrayType) {
|
||||
numDims++;
|
||||
arrayType = arrayType->getElementType()->as<ArrayType>();
|
||||
}
|
||||
}
|
||||
initValues = init;
|
||||
// addOperands(dims); 同GlobalValue,维度信息已经被记录到Type中,dim只是为了方便初始化
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -1468,9 +1487,6 @@ class ConstantVariable : public Value {
|
||||
|
||||
return getByIndex(index);
|
||||
} ///< 通过多维索引indices获取初始值
|
||||
// unsigned getNumDims() const { return numDims; } ///< 获取维度数量
|
||||
// Value* getDim(unsigned index) const { return getOperand(index); } ///< 获取位置为index的维度
|
||||
// auto getDims() const { return getOperands(); } ///< 获取维度列表
|
||||
const ValueCounter& getInitValues() const { return initValues; } ///< 获取初始值
|
||||
};
|
||||
|
||||
@@ -1529,13 +1545,12 @@ class Module {
|
||||
return result.first->second.get();
|
||||
} ///< 创建外部函数
|
||||
///< 变量创建伴随着符号表的更新
|
||||
GlobalValue* createGlobalValue(const std::string &name, Type *type, const std::vector<Value *> &dims = {},
|
||||
const ValueCounter &init = {}) {
|
||||
GlobalValue* createGlobalValue(const std::string &name, Type *type, const ValueCounter &init = {}) {
|
||||
bool isFinished = variableTable.isCurNodeNull();
|
||||
if (isFinished) {
|
||||
variableTable.enterGlobalScope();
|
||||
}
|
||||
auto result = variableTable.addVariable(name, new GlobalValue(this, type, name, dims, init));
|
||||
auto result = variableTable.addVariable(name, new GlobalValue(this, type, name, init));
|
||||
if (isFinished) {
|
||||
variableTable.leaveScope();
|
||||
}
|
||||
@@ -1544,9 +1559,8 @@ class Module {
|
||||
}
|
||||
return dynamic_cast<GlobalValue *>(result);
|
||||
} ///< 创建全局变量
|
||||
ConstantVariable* createConstVar(const std::string &name, Type *type, const ValueCounter &init,
|
||||
const std::vector<Value *> &dims = {}) {
|
||||
auto result = variableTable.addVariable(name, new ConstantVariable(this, type, name, init, dims));
|
||||
ConstantVariable* createConstVar(const std::string &name, Type *type, const ValueCounter &init) {
|
||||
auto result = variableTable.addVariable(name, new ConstantVariable(this, type, name, init));
|
||||
if (result == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ class IRBuilder {
|
||||
UnaryInst * createFNotInst(Value *operand, const std::string &name = "") {
|
||||
return createUnaryInst(Instruction::kFNot, Type::getIntType(), operand, name);
|
||||
} ///< 创建浮点取非指令
|
||||
UnaryInst * createItoFInst(Value *operand, const std::string &name = "") {
|
||||
UnaryInst * createIToFInst(Value *operand, const std::string &name = "") {
|
||||
return createUnaryInst(Instruction::kItoF, Type::getFloatType(), operand, name);
|
||||
} ///< 创建整型转浮点指令
|
||||
UnaryInst * createBitItoFInst(Value *operand, const std::string &name = "") {
|
||||
@@ -239,31 +239,30 @@ class IRBuilder {
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建return指令
|
||||
UncondBrInst * createUncondBrInst(BasicBlock *thenBlock, const std::vector<Value *> &args) {
|
||||
auto inst = new UncondBrInst(thenBlock, args, block);
|
||||
UncondBrInst * createUncondBrInst(BasicBlock *thenBlock) {
|
||||
auto inst = new UncondBrInst(thenBlock, block);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建无条件指令
|
||||
CondBrInst * createCondBrInst(Value *condition, BasicBlock *thenBlock, BasicBlock *elseBlock,
|
||||
const std::vector<Value *> &thenArgs, const std::vector<Value *> &elseArgs) {
|
||||
auto inst = new CondBrInst(condition, thenBlock, elseBlock, thenArgs, elseArgs, block);
|
||||
CondBrInst * createCondBrInst(Value *condition, BasicBlock *thenBlock, BasicBlock *elseBlock) {
|
||||
auto inst = new CondBrInst(condition, thenBlock, elseBlock, block);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建条件跳转指令
|
||||
AllocaInst * createAllocaInst(Type *type, const std::vector<Value *> &dims = {}, const std::string &name = "") {
|
||||
auto inst = new AllocaInst(type, dims, block, name);
|
||||
UnreachableInst * createUnreachableInst(const std::string &name = "") {
|
||||
auto inst = new UnreachableInst(name, block);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建不可达指令
|
||||
AllocaInst * createAllocaInst(Type *type, const std::string &name = "") {
|
||||
auto inst = new AllocaInst(type, block, name);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建分配指令
|
||||
AllocaInst * createAllocaInstWithoutInsert(Type *type, const std::vector<Value *> &dims = {}, BasicBlock *parent = nullptr,
|
||||
const std::string &name = "") {
|
||||
auto inst = new AllocaInst(type, dims, parent, name);
|
||||
assert(inst);
|
||||
return inst;
|
||||
} ///< 创建不插入指令列表的分配指令[仅用于phi指令]
|
||||
LoadInst * createLoadInst(Value *pointer, const std::vector<Value *> &indices = {}, const std::string &name = "") {
|
||||
std::string newName;
|
||||
if (name.empty()) {
|
||||
@@ -275,7 +274,7 @@ class IRBuilder {
|
||||
newName = name;
|
||||
}
|
||||
|
||||
auto inst = new LoadInst(pointer, indices, block, newName);
|
||||
auto inst = new LoadInst(pointer, block, newName);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
@@ -286,9 +285,8 @@ class IRBuilder {
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
} ///< 创建memset指令
|
||||
StoreInst * createStoreInst(Value *value, Value *pointer, const std::vector<Value *> &indices = {},
|
||||
const std::string &name = "") {
|
||||
auto inst = new StoreInst(value, pointer, indices, block, name);
|
||||
StoreInst * createStoreInst(Value *value, Value *pointer, const std::string &name = "") {
|
||||
auto inst = new StoreInst(value, pointer, block, name);
|
||||
assert(inst);
|
||||
block->getInstructions().emplace(position, inst);
|
||||
return inst;
|
||||
@@ -308,24 +306,6 @@ class IRBuilder {
|
||||
block->getInstructions().emplace(block->begin(), inst);
|
||||
return inst;
|
||||
} ///< 创建Phi指令
|
||||
// GetElementPtrInst* createGetElementPtrInst(Value *basePointer,
|
||||
// const std::vector<Value *> &indices = {},
|
||||
// const std::string &name = "") {
|
||||
// std::string newName;
|
||||
// if (name.empty()) {
|
||||
// std::stringstream ss;
|
||||
// ss << tmpIndex;
|
||||
// newName = ss.str();
|
||||
// tmpIndex++;
|
||||
// } else {
|
||||
// newName = name;
|
||||
// }
|
||||
|
||||
// auto inst = new GetElementPtrInst(basePointer, indices, block, newName);
|
||||
// assert(inst);
|
||||
// block->getInstructions().emplace(position, inst);
|
||||
// return inst;
|
||||
// }
|
||||
/**
|
||||
* @brief 根据 LLVM 设计模式创建 GEP 指令。
|
||||
* 它会自动推断返回类型,无需手动指定。
|
||||
|
||||
@@ -1,196 +1,139 @@
|
||||
#pragma once
|
||||
|
||||
#include "IR.h"
|
||||
#include "Pass.h"
|
||||
#include "SysYIROptUtils.h"
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <variant>
|
||||
#include <functional>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// 稀疏条件常量传播类
|
||||
// Sparse Conditional Constant Propagation
|
||||
/*
|
||||
伪代码
|
||||
function SCCP_Optimization(Module):
|
||||
for each Function in Module:
|
||||
changed = true
|
||||
while changed:
|
||||
changed = false
|
||||
// 阶段1: 常量传播与折叠
|
||||
changed |= PropagateConstants(Function)
|
||||
// 阶段2: 控制流简化
|
||||
changed |= SimplifyControlFlow(Function)
|
||||
end while
|
||||
end for
|
||||
|
||||
function PropagateConstants(Function):
|
||||
// 初始化
|
||||
executableBlocks = {entryBlock}
|
||||
valueState = map<Value, State> // 值->状态映射
|
||||
instWorkList = Queue()
|
||||
edgeWorkList = Queue()
|
||||
|
||||
// 初始化工作列表
|
||||
for each inst in entryBlock:
|
||||
instWorkList.push(inst)
|
||||
|
||||
// 迭代处理
|
||||
while !instWorkList.empty() || !edgeWorkList.empty():
|
||||
// 处理指令工作列表
|
||||
while !instWorkList.empty():
|
||||
inst = instWorkList.pop()
|
||||
// 如果指令是可执行基本块中的
|
||||
if executableBlocks.contains(inst.parent):
|
||||
ProcessInstruction(inst)
|
||||
|
||||
// 处理边工作列表
|
||||
while !edgeWorkList.empty():
|
||||
edge = edgeWorkList.pop()
|
||||
ProcessEdge(edge)
|
||||
|
||||
// 应用常量替换
|
||||
for each inst in Function:
|
||||
if valueState[inst] == CONSTANT:
|
||||
ReplaceWithConstant(inst, valueState[inst].constant)
|
||||
changed = true
|
||||
|
||||
return changed
|
||||
|
||||
function ProcessInstruction(Instruction inst):
|
||||
switch inst.type:
|
||||
//二元操作
|
||||
case BINARY_OP:
|
||||
lhs = GetValueState(inst.operands[0])
|
||||
rhs = GetValueState(inst.operands[1])
|
||||
if lhs == CONSTANT && rhs == CONSTANT:
|
||||
newState = ComputeConstant(inst.op, lhs.value, rhs.value)
|
||||
UpdateState(inst, newState)
|
||||
else if lhs == BOTTOM || rhs == BOTTOM:
|
||||
UpdateState(inst, BOTTOM)
|
||||
//phi
|
||||
case PHI:
|
||||
mergedState = ⊤
|
||||
for each incoming in inst.incomings:
|
||||
// 检查每个输入的状态
|
||||
if executableBlocks.contains(incoming.block):
|
||||
incomingState = GetValueState(incoming.value)
|
||||
mergedState = Meet(mergedState, incomingState)
|
||||
UpdateState(inst, mergedState)
|
||||
// 条件分支
|
||||
case COND_BRANCH:
|
||||
cond = GetValueState(inst.condition)
|
||||
if cond == CONSTANT:
|
||||
// 判断条件分支
|
||||
if cond.value == true:
|
||||
AddEdgeToWorkList(inst.parent, inst.trueTarget)
|
||||
else:
|
||||
AddEdgeToWorkList(inst.parent, inst.falseTarget)
|
||||
else if cond == BOTTOM:
|
||||
AddEdgeToWorkList(inst.parent, inst.trueTarget)
|
||||
AddEdgeToWorkList(inst.parent, inst.falseTarget)
|
||||
|
||||
case UNCOND_BRANCH:
|
||||
AddEdgeToWorkList(inst.parent, inst.target)
|
||||
|
||||
// 其他指令处理...
|
||||
|
||||
function ProcessEdge(Edge edge):
|
||||
fromBB, toBB = edge
|
||||
if !executableBlocks.contains(toBB):
|
||||
executableBlocks.add(toBB)
|
||||
for each inst in toBB:
|
||||
if inst is PHI:
|
||||
instWorkList.push(inst)
|
||||
else:
|
||||
instWorkList.push(inst) // 非PHI指令
|
||||
|
||||
// 更新PHI节点的输入
|
||||
for each phi in toBB.phis:
|
||||
instWorkList.push(phi)
|
||||
|
||||
function SimplifyControlFlow(Function):
|
||||
changed = false
|
||||
// 标记可达基本块
|
||||
ReachableBBs = FindReachableBlocks(Function.entry)
|
||||
|
||||
// 删除不可达块
|
||||
for each bb in Function.blocks:
|
||||
if !ReachableBBs.contains(bb):
|
||||
RemoveDeadBlock(bb)
|
||||
changed = true
|
||||
|
||||
// 简化条件分支
|
||||
for each bb in Function.blocks:
|
||||
terminator = bb.terminator
|
||||
if terminator is COND_BRANCH:
|
||||
cond = GetValueState(terminator.condition)
|
||||
if cond == CONSTANT:
|
||||
SimplifyBranch(terminator, cond.value)
|
||||
changed = true
|
||||
|
||||
return changed
|
||||
|
||||
function RemoveDeadBlock(BasicBlock bb):
|
||||
// 1. 更新前驱块的分支指令
|
||||
for each pred in bb.predecessors:
|
||||
UpdateTerminator(pred, bb)
|
||||
|
||||
// 2. 更新后继块的PHI节点
|
||||
for each succ in bb.successors:
|
||||
RemovePhiIncoming(succ, bb)
|
||||
|
||||
// 3. 删除块内所有指令
|
||||
for each inst in bb.instructions:
|
||||
inst.remove()
|
||||
|
||||
// 4. 从函数中移除基本块
|
||||
Function.removeBlock(bb)
|
||||
|
||||
function Meet(State a, State b):
|
||||
if a == ⊤: return b
|
||||
if b == ⊤: return a
|
||||
if a == ⊥ || b == ⊥: return ⊥
|
||||
if a.value == b.value: return a
|
||||
return ⊥
|
||||
|
||||
function UpdateState(Value v, State newState):
|
||||
oldState = valueState.get(v, ⊤)
|
||||
if newState != oldState:
|
||||
valueState[v] = newState
|
||||
for each user in v.users:
|
||||
if user is Instruction:
|
||||
instWorkList.push(user)
|
||||
|
||||
*/
|
||||
|
||||
enum class LatticeValue {
|
||||
Top, // ⊤ (Unknown)
|
||||
Constant, // c (Constant)
|
||||
Bottom // ⊥ (Undefined / Varying)
|
||||
// 定义三值格 (Three-valued Lattice) 的状态
|
||||
enum class LatticeVal {
|
||||
Top, // ⊤ (未知 / 未初始化)
|
||||
Constant, // c (常量)
|
||||
Bottom // ⊥ (不确定 / 变化 / 未定义)
|
||||
};
|
||||
// LatticeValue: 用于表示值的状态,Top表示未知,Constant表示常量,Bottom表示未定义或变化的值。
|
||||
// 这里的LatticeValue用于跟踪每个SSA值(变量、指令结果)的状态,
|
||||
// 以便在SCCP过程中进行常量传播和控制流简化。
|
||||
|
||||
//TODO: 下列数据结构考虑集成到类中,避免重命名问题
|
||||
static std::set<Instruction *> Worklist;
|
||||
static std::unordered_set<BasicBlock*> Executable_Blocks;
|
||||
static std::queue<std::pair<BasicBlock *, BasicBlock *> > Executable_Edges;
|
||||
static std::map<Value*, LatticeValue> valueState;
|
||||
// 新增枚举来区分常量的实际类型
|
||||
enum class ValueType {
|
||||
Integer,
|
||||
Float,
|
||||
Unknown // 用于 Top 和 Bottom 状态
|
||||
};
|
||||
|
||||
class SCCP {
|
||||
// 用于表示 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:
|
||||
Module *pModule;
|
||||
IRBuilder *builder; // IR 构建器,用于插入指令和创建常量
|
||||
|
||||
// 工作列表
|
||||
// 存储需要重新评估的指令
|
||||
std::queue<Instruction *> instWorkList;
|
||||
// 存储需要重新评估的控制流边 (pair: from_block, to_block)
|
||||
std::queue<std::pair<BasicBlock *, BasicBlock *>> edgeWorkList;
|
||||
|
||||
// 格值映射:SSA Value 到其当前状态
|
||||
std::map<Value *, SSAPValue> valueState;
|
||||
// 可执行基本块集合
|
||||
std::unordered_set<BasicBlock *> executableBlocks;
|
||||
// 追踪已访问的CFG边,防止重复添加,使用 SysYIROptUtils::PairHash
|
||||
std::unordered_set<std::pair<BasicBlock*, BasicBlock*>, SysYIROptUtils::PairHash> visitedCFGEdges;
|
||||
|
||||
// 辅助函数:格操作 Meet
|
||||
SSAPValue Meet(const SSAPValue &a, const SSAPValue &b);
|
||||
// 辅助函数:获取值的当前状态,如果不存在则默认为 Top
|
||||
SSAPValue GetValueState(Value *v);
|
||||
// 辅助函数:更新值的状态,如果状态改变,将所有用户加入指令工作列表
|
||||
void UpdateState(Value *v, SSAPValue newState);
|
||||
// 辅助函数:将边加入边工作列表,并更新可执行块
|
||||
void AddEdgeToWorkList(BasicBlock *fromBB, BasicBlock *toBB);
|
||||
// 辅助函数:标记一个块为可执行
|
||||
void MarkBlockExecutable(BasicBlock* block);
|
||||
|
||||
// 辅助函数:对二元操作进行常量折叠
|
||||
SSAPValue ComputeConstant(BinaryInst *binaryinst, SSAPValue lhsVal, SSAPValue rhsVal);
|
||||
// 辅助函数:对一元操作进行常量折叠
|
||||
SSAPValue ComputeConstant(UnaryInst *unaryInst, SSAPValue operandVal);
|
||||
|
||||
// 主要优化阶段
|
||||
// 阶段1: 常量传播与折叠
|
||||
bool PropagateConstants(Function *func);
|
||||
// 阶段2: 控制流简化
|
||||
bool SimplifyControlFlow(Function *func);
|
||||
|
||||
// 辅助函数:处理单条指令
|
||||
void ProcessInstruction(Instruction *inst);
|
||||
// 辅助函数:处理单条控制流边
|
||||
void ProcessEdge(const std::pair<BasicBlock *, BasicBlock *> &edge);
|
||||
|
||||
// 控制流简化辅助函数
|
||||
// 查找所有可达的基本块 (基于常量条件)
|
||||
std::unordered_set<BasicBlock *> FindReachableBlocks(Function *func);
|
||||
// 移除死块
|
||||
void RemoveDeadBlock(BasicBlock *bb, Function *func);
|
||||
// 简化分支(将条件分支替换为无条件分支)
|
||||
void SimplifyBranch(CondBrInst*brInst, bool condVal); // 保持 BranchInst
|
||||
// 更新前驱块的终结指令(当一个后继块被移除时)
|
||||
void UpdateTerminator(BasicBlock *predBB, BasicBlock *removedSucc);
|
||||
// 移除 Phi 节点的入边(当其前驱块被移除时)
|
||||
void RemovePhiIncoming(BasicBlock *phiParentBB, BasicBlock *removedPred);
|
||||
|
||||
public:
|
||||
SCCP(Module *pMoudle) : pModule(pMoudle) {}
|
||||
SCCPContext(IRBuilder *builder) : builder(builder) {}
|
||||
|
||||
void run();
|
||||
bool PropagateConstants(Function *function);
|
||||
bool SimplifyControlFlow(Function *function);
|
||||
void ProcessInstruction(Instruction *inst);
|
||||
void ProcessEdge(const std::pair<BasicBlock *, BasicBlock *> &edge);
|
||||
void RemoveDeadBlock(BasicBlock *bb);
|
||||
void UpdateState(Value *v, LatticeValue newState);
|
||||
LatticeValue Meet(LatticeValue a, LatticeValue b);
|
||||
LatticeValue GetValueState(Value *v);
|
||||
// 运行 SCCP 优化
|
||||
void run(Function *func, AnalysisManager &AM);
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
// 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
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "IR.h"
|
||||
|
||||
extern int DEBUG;
|
||||
namespace sysy {
|
||||
|
||||
// 优化工具类,包含一些通用的优化方法
|
||||
@@ -10,13 +11,88 @@ namespace sysy {
|
||||
class SysYIROptUtils{
|
||||
|
||||
public:
|
||||
// 仅仅删除use关系
|
||||
static void usedelete(Instruction *instr) {
|
||||
for (auto &use : instr->getOperands()) {
|
||||
Value* val = use->getValue();
|
||||
val->removeUse(use);
|
||||
struct PairHash {
|
||||
template <class T1, class T2>
|
||||
std::size_t operator () (const std::pair<T1, T2>& p) const {
|
||||
auto h1 = std::hash<T1>{}(p.first);
|
||||
auto h2 = std::hash<T2>{}(p.second);
|
||||
|
||||
// 简单的组合哈希值,可以更复杂以减少冲突
|
||||
// 使用 boost::hash_combine 的简化版本
|
||||
return h1 ^ (h2 << 1);
|
||||
}
|
||||
};
|
||||
|
||||
static void RemoveUserOperandUses(User *user) {
|
||||
if (!user) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 遍历 User 的 operands 列表。
|
||||
// 由于 operands 是 protected 成员,我们需要一个临时方法来访问它,
|
||||
// 或者在 User 类中添加一个 friend 声明。
|
||||
// 假设 User 内部有一个像 getOperands() 这样的公共方法返回 operands 的引用,
|
||||
// 或者将 SysYIROptUtils 声明为 User 的 friend。
|
||||
// 为了示例,我将假设可以直接访问 user->operands 或通过一个getter。
|
||||
// 如果无法直接访问,请在 IR.h 的 User 类中添加:
|
||||
// public: const std::vector<std::shared_ptr<Use>>& getOperands() const { return operands; }
|
||||
|
||||
// 迭代 copies of shared_ptr to avoid issues if removeUse modifies the list
|
||||
// (though remove should handle it, iterating a copy is safer or reverse iteration).
|
||||
// Since we'll clear the vector at the end, iterating forward is fine.
|
||||
for (const auto& use_ptr : user->getOperands()) { // 假设 getOperands() 可用
|
||||
if (use_ptr) {
|
||||
Value *val = use_ptr->getValue(); // 获取 Use 指向的 Value (如 AllocaInst)
|
||||
if (val) {
|
||||
val->removeUse(use_ptr); // 通知 Value 从其 uses 列表中移除此 Use 关系
|
||||
}
|
||||
}
|
||||
}
|
||||
// 清空 User 的 operands 向量。这会递减 User 持有的 shared_ptr<Use> 的引用计数。
|
||||
// 当引用计数降为 0 时,Use 对象本身将被销毁。
|
||||
// User::operands.clear(); // 这个步骤会在 Instruction 的析构函数中自动完成,因为它是 vector 成员
|
||||
// 或者我们可以在 User::removeOperand 方法中确保 Use 对象从 operands 中移除。
|
||||
// 实际上,只要 Value::removeUse(use_ptr) 被调用了,
|
||||
// 当 Instruction 所在的 unique_ptr 销毁时,它的 operands vector 也会被销毁。
|
||||
// 所以这里不需要显式 clear()
|
||||
}
|
||||
static void usedelete(Instruction *inst) {
|
||||
assert(inst && "Instruction to delete cannot be null.");
|
||||
BasicBlock *parentBlock = inst->getParent();
|
||||
assert(parentBlock && "Instruction must have a parent BasicBlock to be deleted.");
|
||||
|
||||
// 步骤1: 处理所有使用者,将他们从使用 inst 变为使用 UndefinedValue
|
||||
// 这将清理 inst 作为 Value 时的 uses 列表
|
||||
if (!inst->getUses().empty()) {
|
||||
inst->replaceAllUsesWith(UndefinedValue::get(inst->getType()));
|
||||
}
|
||||
|
||||
// 步骤2: 清理 inst 作为 User 时的操作数关系
|
||||
// 通知 inst 所使用的所有 Value (如 AllocaInst),移除对应的 Use 关系。
|
||||
// 这里的 inst 实际上是一个 User*,所以可以安全地向下转型。
|
||||
RemoveUserOperandUses(static_cast<User*>(inst));
|
||||
|
||||
// 步骤3: 物理删除指令
|
||||
// 这会导致 Instruction 对象的 unique_ptr 销毁,从而调用其析构函数链。
|
||||
parentBlock->removeInst(inst);
|
||||
}
|
||||
|
||||
static BasicBlock::iterator usedelete(BasicBlock::iterator inst_it) {
|
||||
Instruction *inst_to_delete = inst_it->get();
|
||||
BasicBlock *parentBlock = inst_to_delete->getParent();
|
||||
assert(parentBlock && "Instruction must have a parent BasicBlock for iterator deletion.");
|
||||
|
||||
// 步骤1: 处理所有使用者
|
||||
if (!inst_to_delete->getUses().empty()) {
|
||||
inst_to_delete->replaceAllUsesWith(UndefinedValue::get(inst_to_delete->getType()));
|
||||
}
|
||||
|
||||
// 步骤2: 清理操作数关系
|
||||
RemoveUserOperandUses(static_cast<User*>(inst_to_delete));
|
||||
|
||||
// 步骤3: 物理删除指令并返回下一个迭代器
|
||||
return parentBlock->removeInst(inst_it);
|
||||
}
|
||||
|
||||
// 判断是否是全局变量
|
||||
static bool isGlobal(Value *val) {
|
||||
@@ -26,7 +102,17 @@ public:
|
||||
// 判断是否是数组
|
||||
static bool isArr(Value *val) {
|
||||
auto aval = dynamic_cast<AllocaInst *>(val);
|
||||
return aval != nullptr && aval->getNumDims() != 0;
|
||||
// 如果是 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());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -59,35 +59,6 @@ private:
|
||||
std::unique_ptr<Module> module;
|
||||
IRBuilder builder;
|
||||
|
||||
using ValueOrOperator = std::variant<Value*, int>;
|
||||
std::vector<ValueOrOperator> BinaryExpStack; ///< 用于存储二元表达式的中缀表达式
|
||||
std::vector<int> BinaryExpLenStack; ///< 用于存储该层次的二元表达式的长度
|
||||
// 下面是用于后缀表达式的计算的数据结构
|
||||
std::vector<ValueOrOperator> BinaryRPNStack; ///< 用于存储二元表达式的后缀表达式
|
||||
std::vector<int> BinaryOpStack; ///< 用于存储二元表达式中缀表达式转换到后缀表达式的操作符栈
|
||||
std::vector<Value *> BinaryValueStack; ///< 用于存储后缀表达式计算的操作数栈
|
||||
|
||||
// 约定操作符:
|
||||
// 1: 'ADD', 2: 'SUB', 3: 'MUL', 4: 'DIV', 5: '%', 6: 'PLUS', 7: 'NEG', 8: 'NOT', 9: 'LPAREN', 10: 'RPAREN'
|
||||
// 这里的操作符是为了方便后缀表达式的计算而设计
|
||||
// 其中,'ADD', 'SUB', 'MUL', 'DIV', '%'
|
||||
// 分别对应加法、减法、乘法、除法和取模
|
||||
// 'PLUS' 和 'NEG' 分别对应一元加法和一元减法
|
||||
// 'NOT' 对应逻辑非
|
||||
// 'LPAREN' 和 'RPAREN' 分别对应左括号和右括号
|
||||
enum BinaryOp {
|
||||
ADD = 1, SUB = 2, MUL = 3, DIV = 4, MOD = 5, PLUS = 6, NEG = 7, NOT = 8, LPAREN = 9, RPAREN = 10,
|
||||
};
|
||||
int getOperatorPrecedence(int op) {
|
||||
switch (op) {
|
||||
case MUL: case DIV: case MOD: return 2;
|
||||
case ADD: case SUB: return 1;
|
||||
case PLUS: case NEG: case NOT: return 3;
|
||||
case LPAREN: case RPAREN: return 0; // Parentheses have lowest precedence for stack logic
|
||||
default: return -1; // Unknown operator
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
SysYIRGenerator() = default;
|
||||
|
||||
@@ -126,7 +97,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;
|
||||
@@ -160,13 +131,8 @@ public:
|
||||
std::any visitLAndExp(SysYParser::LAndExpContext *ctx) override;
|
||||
std::any visitLOrExp(SysYParser::LOrExpContext *ctx) override;
|
||||
|
||||
std::any visitConstExp(SysYParser::ConstExpContext *ctx) override;
|
||||
// std::any visitConstExp(SysYParser::ConstExpContext *ctx) override;
|
||||
|
||||
bool isRightAssociative(int op);
|
||||
Value* promoteType(Value* value, Type* targetType);
|
||||
Value* computeExp(SysYParser::ExpContext *ctx, Type* targetType = nullptr);
|
||||
Value* computeAddExp(SysYParser::AddExpContext *ctx, Type* targetType = nullptr);
|
||||
void compute();
|
||||
public:
|
||||
// 获取GEP指令的地址
|
||||
Value* getGEPAddressInst(Value* basePointer, const std::vector<Value*>& indices);
|
||||
@@ -175,7 +141,6 @@ public:
|
||||
|
||||
unsigned countArrayDimensions(Type* type);
|
||||
|
||||
|
||||
}; // class SysYIRGenerator
|
||||
|
||||
} // namespace sysy
|
||||
@@ -10,6 +10,7 @@ add_library(midend_lib STATIC
|
||||
Pass/Optimize/Mem2Reg.cpp
|
||||
Pass/Optimize/Reg2Mem.cpp
|
||||
Pass/Optimize/SysYIRCFGOpt.cpp
|
||||
Pass/Optimize/SCCP.cpp
|
||||
)
|
||||
|
||||
# 包含中端模块所需的头文件路径
|
||||
|
||||
@@ -227,12 +227,13 @@ Function * Function::clone(const std::string &suffix) const {
|
||||
auto oldAllocInst = dynamic_cast<AllocaInst *>(value);
|
||||
if (oldAllocInst != nullptr) {
|
||||
std::vector<Value *> dims;
|
||||
for (const auto &dim : oldAllocInst->getDims()) {
|
||||
dims.emplace_back(dim->getValue());
|
||||
}
|
||||
// TODO: 这里的dims用type推断
|
||||
// for (const auto &dim : oldAllocInst->getDims()) {
|
||||
// dims.emplace_back(dim->getValue());
|
||||
// }
|
||||
ss << oldAllocInst->getName() << suffix;
|
||||
auto newAllocInst =
|
||||
new AllocaInst(oldAllocInst->getType(), dims, oldNewBlockMap.at(oldAllocInst->getParent()), ss.str());
|
||||
new AllocaInst(oldAllocInst->getType(), oldNewBlockMap.at(oldAllocInst->getParent()), ss.str());
|
||||
ss.str("");
|
||||
oldNewValueMap.emplace(oldAllocInst, newAllocInst);
|
||||
if (isAddedToCreate.find(oldAllocInst) == isAddedToCreate.end()) {
|
||||
@@ -252,12 +253,13 @@ Function * Function::clone(const std::string &suffix) const {
|
||||
if (oldNewValueMap.find(inst.get()) == oldNewValueMap.end()) {
|
||||
auto oldAllocInst = dynamic_cast<AllocaInst *>(inst.get());
|
||||
std::vector<Value *> dims;
|
||||
for (const auto &dim : oldAllocInst->getDims()) {
|
||||
dims.emplace_back(dim->getValue());
|
||||
}
|
||||
// TODO: 这里的dims用type推断
|
||||
// for (const auto &dim : oldAllocInst->getDims()) {
|
||||
// dims.emplace_back(dim->getValue());
|
||||
// }
|
||||
ss << oldAllocInst->getName() << suffix;
|
||||
auto newAllocInst =
|
||||
new AllocaInst(oldAllocInst->getType(), dims, oldNewBlockMap.at(oldAllocInst->getParent()), ss.str());
|
||||
new AllocaInst(oldAllocInst->getType(), oldNewBlockMap.at(oldAllocInst->getParent()), ss.str());
|
||||
ss.str("");
|
||||
oldNewValueMap.emplace(oldAllocInst, newAllocInst);
|
||||
if (isAddedToCreate.find(oldAllocInst) == isAddedToCreate.end()) {
|
||||
@@ -422,7 +424,7 @@ Function * Function::clone(const std::string &suffix) const {
|
||||
Value *newCond;
|
||||
newCond = oldNewValueMap.at(oldCond);
|
||||
auto newCondBrInst = new CondBrInst(newCond, oldNewBlockMap.at(oldCondBrInst->getThenBlock()),
|
||||
oldNewBlockMap.at(oldCondBrInst->getElseBlock()), {}, {},
|
||||
oldNewBlockMap.at(oldCondBrInst->getElseBlock()),
|
||||
oldNewBlockMap.at(oldCondBrInst->getParent()));
|
||||
oldNewValueMap.emplace(oldCondBrInst, newCondBrInst);
|
||||
break;
|
||||
@@ -431,7 +433,7 @@ Function * Function::clone(const std::string &suffix) const {
|
||||
case Instruction::kBr: {
|
||||
auto oldBrInst = dynamic_cast<UncondBrInst *>(inst);
|
||||
auto newBrInst =
|
||||
new UncondBrInst(oldNewBlockMap.at(oldBrInst->getBlock()), {}, oldNewBlockMap.at(oldBrInst->getParent()));
|
||||
new UncondBrInst(oldNewBlockMap.at(oldBrInst->getBlock()), oldNewBlockMap.at(oldBrInst->getParent()));
|
||||
oldNewValueMap.emplace(oldBrInst, newBrInst);
|
||||
break;
|
||||
}
|
||||
@@ -460,11 +462,12 @@ Function * Function::clone(const std::string &suffix) const {
|
||||
newPointer = oldNewValueMap.at(oldPointer);
|
||||
|
||||
std::vector<Value *> newIndices;
|
||||
for (const auto &index : oldLoadInst->getIndices()) {
|
||||
newIndices.emplace_back(oldNewValueMap.at(index->getValue()));
|
||||
}
|
||||
// for (const auto &index : oldLoadInst->getIndices()) {
|
||||
// newIndices.emplace_back(oldNewValueMap.at(index->getValue()));
|
||||
// }
|
||||
ss << oldLoadInst->getName() << suffix;
|
||||
auto newLoadInst = new LoadInst(newPointer, newIndices, oldNewBlockMap.at(oldLoadInst->getParent()), ss.str());
|
||||
// TODO : 这里的newLoadInst的类型需要根据oldLoadInst的类型来推断
|
||||
auto newLoadInst = new LoadInst(newPointer, oldNewBlockMap.at(oldLoadInst->getParent()), ss.str());
|
||||
ss.str("");
|
||||
oldNewValueMap.emplace(oldLoadInst, newLoadInst);
|
||||
break;
|
||||
@@ -479,10 +482,11 @@ Function * Function::clone(const std::string &suffix) const {
|
||||
std::vector<Value *> newIndices;
|
||||
newPointer = oldNewValueMap.at(oldPointer);
|
||||
newValue = oldNewValueMap.at(oldValue);
|
||||
for (const auto &index : oldStoreInst->getIndices()) {
|
||||
newIndices.emplace_back(oldNewValueMap.at(index->getValue()));
|
||||
}
|
||||
auto newStoreInst = new StoreInst(newValue, newPointer, newIndices,
|
||||
// TODO: 这里的newIndices需要根据oldStoreInst的类型来推断
|
||||
// for (const auto &index : oldStoreInst->getIndices()) {
|
||||
// newIndices.emplace_back(oldNewValueMap.at(index->getValue()));
|
||||
// }
|
||||
auto newStoreInst = new StoreInst(newValue, newPointer,
|
||||
oldNewBlockMap.at(oldStoreInst->getParent()), oldStoreInst->getName());
|
||||
oldNewValueMap.emplace(oldStoreInst, newStoreInst);
|
||||
break;
|
||||
@@ -565,7 +569,7 @@ void User::replaceOperand(unsigned index, Value *value) {
|
||||
* phi相关函数
|
||||
*/
|
||||
|
||||
Value* PhiInst::getvalfromBlk(BasicBlock* blk){
|
||||
Value* PhiInst::getvalfromBlk(BasicBlock* blk){
|
||||
refreshB2VMap();
|
||||
if( blk2val.find(blk) != blk2val.end()) {
|
||||
return blk2val.at(blk);
|
||||
@@ -615,11 +619,13 @@ void PhiInst::delBlk(BasicBlock* blk){
|
||||
|
||||
void PhiInst::replaceBlk(BasicBlock* newBlk, unsigned k){
|
||||
refreshB2VMap();
|
||||
Value* val = blk2val.at(getBlock(k));
|
||||
BasicBlock* oldBlk = getBlock(k);
|
||||
Value* val = blk2val.at(oldBlk);
|
||||
// Value* val = blk2val.at(getBlock(k));
|
||||
// 替换基本块
|
||||
setOperand(2 * k + 1, newBlk);
|
||||
// 替换blk2val映射
|
||||
blk2val.erase(getBlock(k));
|
||||
blk2val.erase(oldBlk);
|
||||
blk2val.emplace(newBlk, val);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,10 +51,8 @@ void DCEContext::run(Function *func, AnalysisManager *AM, bool &changed) {
|
||||
// 如果指令不在活跃集合中,则删除它。
|
||||
// 分支和返回指令由 isAlive 处理,并会被保留。
|
||||
if (alive_insts.count(currentInst) == 0) {
|
||||
// 删除指令,保留用户风格的 SysYIROptUtils::usedelete 和 erase
|
||||
instIter = SysYIROptUtils::usedelete(instIter); // 删除后返回下一个迭代器
|
||||
changed = true; // 标记 IR 已被修改
|
||||
SysYIROptUtils::usedelete(currentInst);
|
||||
instIter = basicBlock->getInstructions().erase(instIter); // 删除后返回下一个迭代器
|
||||
} else {
|
||||
++instIter; // 指令活跃,移动到下一个
|
||||
}
|
||||
|
||||
@@ -240,10 +240,11 @@ void Mem2RegContext::renameVariables(AllocaInst *currentAlloca, BasicBlock *curr
|
||||
// loadInst->getPointer() 返回 AllocaInst*
|
||||
// 将 LoadInst 的所有用途替换为当前 alloca 值栈顶部的 SSA 值
|
||||
assert(!allocaToValueStackMap[alloca].empty() && "Value stack empty for alloca during load replacement!");
|
||||
if(DEBUG){
|
||||
std::cout << "Mem2Reg: Replacing load " << loadInst->getPointer()->getName() << " with SSA value." << std::endl;
|
||||
}
|
||||
loadInst->replaceAllUsesWith(allocaToValueStackMap[alloca].top());
|
||||
// instIter = currentBB->force_delete_inst(loadInst); // 删除 LoadInst
|
||||
SysYIROptUtils::usedelete(loadInst); // 仅删除 use 关系
|
||||
instIter = currentBB->getInstructions().erase(instIter); // 删除 LoadInst
|
||||
instIter = SysYIROptUtils::usedelete(instIter);
|
||||
instDeleted = true;
|
||||
// std::cerr << "Mem2Reg: Replaced load " << loadInst->name() << " with SSA value." << std::endl;
|
||||
break;
|
||||
@@ -257,10 +258,12 @@ void Mem2RegContext::renameVariables(AllocaInst *currentAlloca, BasicBlock *curr
|
||||
if (storeInst->getPointer() == alloca) {
|
||||
// 假设 storeInst->getPointer() 返回 AllocaInst*
|
||||
// 将 StoreInst 存储的值作为新的 SSA 值,压入值栈
|
||||
if(DEBUG){
|
||||
std::cout << "Mem2Reg: Replacing store to " << storeInst->getPointer()->getName() << " with SSA value." << std::endl;
|
||||
}
|
||||
allocaToValueStackMap[alloca].push(storeInst->getValue());
|
||||
localStackPushed.push(storeInst->getValue()); // 记录以便弹出
|
||||
SysYIROptUtils::usedelete(storeInst);
|
||||
instIter = currentBB->getInstructions().erase(instIter); // 删除 StoreInst
|
||||
instIter = SysYIROptUtils::usedelete(instIter);
|
||||
instDeleted = true;
|
||||
// std::cerr << "Mem2Reg: Replaced store to " << storeInst->ptr()->name() << " with SSA value." << std::endl;
|
||||
break;
|
||||
@@ -298,7 +301,9 @@ void Mem2RegContext::renameVariables(AllocaInst *currentAlloca, BasicBlock *curr
|
||||
if(dominatedBlocks){
|
||||
for (auto dominatedBB : *dominatedBlocks) {
|
||||
if (dominatedBB) {
|
||||
std::cout << "Mem2Reg: Recursively renaming variables in dominated block: " << dominatedBB->getName() << std::endl;
|
||||
if(DEBUG){
|
||||
std::cout << "Mem2Reg: Recursively renaming variables in dominated block: " << dominatedBB->getName() << std::endl;
|
||||
}
|
||||
renameVariables(currentAlloca, dominatedBB);
|
||||
}
|
||||
}
|
||||
@@ -327,7 +332,6 @@ void Mem2RegContext::cleanup() {
|
||||
if (alloca && alloca->getParent()) {
|
||||
// 删除 alloca 指令本身
|
||||
SysYIROptUtils::usedelete(alloca);
|
||||
alloca->getParent()->removeInst(alloca); // 从基本块中删除 alloca
|
||||
|
||||
// std::cerr << "Mem2Reg: Deleted alloca " << alloca->name() << std::endl;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ void Reg2MemContext::allocateMemoryForSSAValues(Function *func) {
|
||||
// 默认情况下,将所有参数是提升到内存
|
||||
if (isPromotableToMemory(arg)) {
|
||||
// 参数的类型就是 AllocaInst 需要分配的类型
|
||||
AllocaInst *alloca = builder->createAllocaInst(Type::getPointerType(arg->getType()), {}, arg->getName() + ".reg2mem");
|
||||
AllocaInst *alloca = builder->createAllocaInst(Type::getPointerType(arg->getType()), arg->getName() + ".reg2mem");
|
||||
// 将参数值 store 到 alloca 中 (这是 Mem2Reg 逆转的关键一步)
|
||||
valueToAllocaMap[arg] = alloca;
|
||||
|
||||
@@ -103,7 +103,7 @@ void Reg2MemContext::allocateMemoryForSSAValues(Function *func) {
|
||||
// AllocaInst 应该在入口块,而不是当前指令所在块
|
||||
// 这里我们只是创建,并稍后调整其位置
|
||||
// 通常的做法是在循环结束后统一将 alloca 放到 entryBlock 的顶部
|
||||
AllocaInst *alloca = builder->createAllocaInst(Type::getPointerType(inst.get()->getType()), {}, inst.get()->getName() + ".reg2mem");
|
||||
AllocaInst *alloca = builder->createAllocaInst(Type::getPointerType(inst.get()->getType()), inst.get()->getName() + ".reg2mem");
|
||||
valueToAllocaMap[inst.get()] = alloca;
|
||||
}
|
||||
}
|
||||
@@ -181,8 +181,7 @@ void Reg2MemContext::rewritePhis(Function *func) {
|
||||
// 实际删除 Phi 指令
|
||||
for (auto phi : phisToErase) {
|
||||
if (phi && phi->getParent()) {
|
||||
SysYIROptUtils::usedelete(phi); // 清理 use-def 链
|
||||
phi->getParent()->removeInst(phi); // 从基本块中删除
|
||||
SysYIROptUtils::usedelete(phi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
880
src/midend/Pass/Optimize/SCCP.cpp
Normal file
880
src/midend/Pass/Optimize/SCCP.cpp
Normal file
@@ -0,0 +1,880 @@
|
||||
#include "SCCP.h"
|
||||
#include "Dom.h"
|
||||
#include "Liveness.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath> // For std::fmod, std::fabs
|
||||
#include <limits> // For std::numeric_limits
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// Pass ID for SCCP
|
||||
void *SCCP::ID = (void *)&SCCP::ID;
|
||||
|
||||
// SCCPContext methods
|
||||
SSAPValue SCCPContext::Meet(const SSAPValue &a, const SSAPValue &b) {
|
||||
if (a.state == LatticeVal::Bottom || b.state == LatticeVal::Bottom) {
|
||||
return SSAPValue(LatticeVal::Bottom);
|
||||
}
|
||||
if (a.state == LatticeVal::Top) {
|
||||
return b;
|
||||
}
|
||||
if (b.state == LatticeVal::Top) {
|
||||
return a;
|
||||
}
|
||||
// Both are constants
|
||||
if (a.constant_type != b.constant_type) {
|
||||
return SSAPValue(LatticeVal::Bottom); // 不同类型的常量,结果为 Bottom
|
||||
}
|
||||
if (a.constantVal == b.constantVal) {
|
||||
return a; // 相同常量
|
||||
}
|
||||
return SSAPValue(LatticeVal::Bottom); // 相同类型但值不同,结果为 Bottom
|
||||
}
|
||||
|
||||
SSAPValue SCCPContext::GetValueState(Value *v) {
|
||||
if (auto constVal = dynamic_cast<ConstantValue *>(v)) {
|
||||
// 特殊处理 UndefinedValue:将其视为 Bottom
|
||||
if (dynamic_cast<UndefinedValue *>(constVal)) {
|
||||
return SSAPValue(LatticeVal::Bottom);
|
||||
}
|
||||
// 处理常规的 ConstantInteger 和 ConstantFloating
|
||||
if (constVal->getType()->isInt()) {
|
||||
return SSAPValue(constVal->getInt());
|
||||
} else if (constVal->getType()->isFloat()) {
|
||||
return SSAPValue(constVal->getFloat());
|
||||
} else {
|
||||
// 对于其他 ConstantValue 类型(例如,ConstantArray 等),
|
||||
// 如果它们的具体值不能用于标量常量传播,则保守地视为 Bottom。
|
||||
return SSAPValue(LatticeVal::Bottom);
|
||||
}
|
||||
}
|
||||
if (valueState.count(v)) {
|
||||
return valueState[v];
|
||||
}
|
||||
return SSAPValue(); // 默认初始化为 Top
|
||||
}
|
||||
|
||||
void SCCPContext::UpdateState(Value *v, SSAPValue newState) {
|
||||
SSAPValue oldState = GetValueState(v);
|
||||
if (newState != oldState) {
|
||||
if (DEBUG) {
|
||||
std::cout << "Updating state for " << v->getName() << " from (";
|
||||
if (oldState.state == LatticeVal::Top)
|
||||
std::cout << "Top";
|
||||
else if (oldState.state == LatticeVal::Constant) {
|
||||
if (oldState.constant_type == ValueType::Integer)
|
||||
std::cout << "Const<int>(" << std::get<int>(oldState.constantVal) << ")";
|
||||
else
|
||||
std::cout << "Const<float>(" << std::get<float>(oldState.constantVal) << ")";
|
||||
} else
|
||||
std::cout << "Bottom";
|
||||
std::cout << ") to (";
|
||||
if (newState.state == LatticeVal::Top)
|
||||
std::cout << "Top";
|
||||
else if (newState.state == LatticeVal::Constant) {
|
||||
if (newState.constant_type == ValueType::Integer)
|
||||
std::cout << "Const<int>(" << std::get<int>(newState.constantVal) << ")";
|
||||
else
|
||||
std::cout << "Const<float>(" << std::get<float>(newState.constantVal) << ")";
|
||||
} else
|
||||
std::cout << "Bottom";
|
||||
std::cout << ")" << std::endl;
|
||||
}
|
||||
|
||||
valueState[v] = newState;
|
||||
// 如果状态发生变化,将所有使用者添加到指令工作列表
|
||||
for (auto &use_ptr : v->getUses()) {
|
||||
if (auto userInst = dynamic_cast<Instruction *>(use_ptr->getUser())) {
|
||||
instWorkList.push(userInst);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SCCPContext::AddEdgeToWorkList(BasicBlock *fromBB, BasicBlock *toBB) {
|
||||
// 检查边是否已经访问过,防止重复处理
|
||||
if (visitedCFGEdges.count({fromBB, toBB})) {
|
||||
return;
|
||||
}
|
||||
visitedCFGEdges.insert({fromBB, toBB});
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "Adding edge to worklist: " << fromBB->getName() << " -> " << toBB->getName() << std::endl;
|
||||
}
|
||||
edgeWorkList.push({fromBB, toBB});
|
||||
}
|
||||
|
||||
void SCCPContext::MarkBlockExecutable(BasicBlock *block) {
|
||||
if (executableBlocks.insert(block).second) { // insert 返回 pair,second 为 true 表示插入成功
|
||||
if (DEBUG) {
|
||||
std::cout << "Marking block " << block->getName() << " as executable." << std::endl;
|
||||
}
|
||||
// 将新可执行块中的所有指令添加到指令工作列表
|
||||
for (auto &inst_ptr : block->getInstructions()) {
|
||||
instWorkList.push(inst_ptr.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数:对二元操作进行常量折叠
|
||||
SSAPValue SCCPContext::ComputeConstant(BinaryInst *binaryInst, SSAPValue lhsVal, SSAPValue rhsVal) {
|
||||
// 确保操作数是常量
|
||||
if (lhsVal.state != LatticeVal::Constant || rhsVal.state != LatticeVal::Constant) {
|
||||
return SSAPValue(LatticeVal::Bottom); // 如果不是常量,则不能折叠
|
||||
}
|
||||
|
||||
// 处理整数运算 (kAdd, kSub, kMul, kDiv, kRem, kICmp*, kAnd, kOr)
|
||||
if (lhsVal.constant_type == ValueType::Integer && rhsVal.constant_type == ValueType::Integer) {
|
||||
int lhs = std::get<int>(lhsVal.constantVal);
|
||||
int rhs = std::get<int>(rhsVal.constantVal);
|
||||
int result = 0;
|
||||
|
||||
switch (binaryInst->getKind()) {
|
||||
case Instruction::kAdd:
|
||||
result = lhs + rhs;
|
||||
break;
|
||||
case Instruction::kSub:
|
||||
result = lhs - rhs;
|
||||
break;
|
||||
case Instruction::kMul:
|
||||
result = lhs * rhs;
|
||||
break;
|
||||
case Instruction::kDiv:
|
||||
if (rhs == 0)
|
||||
return SSAPValue(LatticeVal::Bottom); // 除零
|
||||
result = lhs / rhs;
|
||||
break;
|
||||
case Instruction::kRem:
|
||||
if (rhs == 0)
|
||||
return SSAPValue(LatticeVal::Bottom); // 模零
|
||||
result = lhs % rhs;
|
||||
break;
|
||||
case Instruction::kICmpEQ:
|
||||
result = (lhs == rhs);
|
||||
break;
|
||||
case Instruction::kICmpNE:
|
||||
result = (lhs != rhs);
|
||||
break;
|
||||
case Instruction::kICmpLT:
|
||||
result = (lhs < rhs);
|
||||
break;
|
||||
case Instruction::kICmpGT:
|
||||
result = (lhs > rhs);
|
||||
break;
|
||||
case Instruction::kICmpLE:
|
||||
result = (lhs <= rhs);
|
||||
break;
|
||||
case Instruction::kICmpGE:
|
||||
result = (lhs >= rhs);
|
||||
break;
|
||||
case Instruction::kAnd:
|
||||
result = (lhs && rhs);
|
||||
break;
|
||||
case Instruction::kOr:
|
||||
result = (lhs || rhs);
|
||||
break;
|
||||
default:
|
||||
return SSAPValue(LatticeVal::Bottom); // 未知或不匹配的二元操作
|
||||
}
|
||||
return SSAPValue(result);
|
||||
}
|
||||
// 处理浮点运算 (kFAdd, kFSub, kFMul, kFDiv, kFCmp*)
|
||||
else if (lhsVal.constant_type == ValueType::Float && rhsVal.constant_type == ValueType::Float) {
|
||||
float lhs = std::get<float>(lhsVal.constantVal);
|
||||
float rhs = std::get<float>(rhsVal.constantVal);
|
||||
float f_result = 0.0f;
|
||||
int i_result = 0; // For comparison results
|
||||
|
||||
switch (binaryInst->getKind()) {
|
||||
case Instruction::kFAdd:
|
||||
f_result = lhs + rhs;
|
||||
break;
|
||||
case Instruction::kFSub:
|
||||
f_result = lhs - rhs;
|
||||
break;
|
||||
case Instruction::kFMul:
|
||||
f_result = lhs * rhs;
|
||||
break;
|
||||
case Instruction::kFDiv:
|
||||
if (rhs == 0.0f)
|
||||
return SSAPValue(LatticeVal::Bottom); // 除零
|
||||
f_result = lhs / rhs;
|
||||
break;
|
||||
// kRem 不支持浮点数,但如果你的 IR 定义了浮点模运算,需要使用 std::fmod
|
||||
case Instruction::kFCmpEQ:
|
||||
i_result = (lhs == rhs);
|
||||
return SSAPValue(i_result);
|
||||
case Instruction::kFCmpNE:
|
||||
i_result = (lhs != rhs);
|
||||
return SSAPValue(i_result);
|
||||
case Instruction::kFCmpLT:
|
||||
i_result = (lhs < rhs);
|
||||
return SSAPValue(i_result);
|
||||
case Instruction::kFCmpGT:
|
||||
i_result = (lhs > rhs);
|
||||
return SSAPValue(i_result);
|
||||
case Instruction::kFCmpLE:
|
||||
i_result = (lhs <= rhs);
|
||||
return SSAPValue(i_result);
|
||||
case Instruction::kFCmpGE:
|
||||
i_result = (lhs >= rhs);
|
||||
return SSAPValue(i_result);
|
||||
default:
|
||||
return SSAPValue(LatticeVal::Bottom); // 未知或不匹配的浮点二元操作
|
||||
}
|
||||
return SSAPValue(f_result);
|
||||
}
|
||||
|
||||
return SSAPValue(LatticeVal::Bottom); // 类型不匹配或不支持的类型组合
|
||||
}
|
||||
|
||||
// 辅助函数:对一元操作进行常量折叠
|
||||
SSAPValue SCCPContext::ComputeConstant(UnaryInst *unaryInst, SSAPValue operandVal) {
|
||||
if (operandVal.state != LatticeVal::Constant) {
|
||||
return SSAPValue(LatticeVal::Bottom);
|
||||
}
|
||||
|
||||
if (operandVal.constant_type == ValueType::Integer) {
|
||||
int val = std::get<int>(operandVal.constantVal);
|
||||
switch (unaryInst->getKind()) {
|
||||
case Instruction::kAdd:
|
||||
return SSAPValue(val);
|
||||
case Instruction::kNeg:
|
||||
return SSAPValue(-val);
|
||||
case Instruction::kNot:
|
||||
return SSAPValue(!val);
|
||||
default:
|
||||
return SSAPValue(LatticeVal::Bottom);
|
||||
}
|
||||
} else if (operandVal.constant_type == ValueType::Float) {
|
||||
float val = std::get<float>(operandVal.constantVal);
|
||||
switch (unaryInst->getKind()) {
|
||||
case Instruction::kAdd:
|
||||
return SSAPValue(val);
|
||||
case Instruction::kFNeg:
|
||||
return SSAPValue(-val);
|
||||
case Instruction::kFNot:
|
||||
return SSAPValue(static_cast<int>(val == 0.0f)); // 浮点数非,0.0f 为真,其他为假
|
||||
default:
|
||||
return SSAPValue(LatticeVal::Bottom);
|
||||
}
|
||||
}
|
||||
return SSAPValue(LatticeVal::Bottom);
|
||||
}
|
||||
|
||||
// 辅助函数:处理单条指令
|
||||
void SCCPContext::ProcessInstruction(Instruction *inst) {
|
||||
SSAPValue oldState = GetValueState(inst);
|
||||
SSAPValue newState;
|
||||
|
||||
if (!executableBlocks.count(inst->getParent())) {
|
||||
// 如果指令所在的块不可执行,其值应保持 Top
|
||||
// 除非它之前已经是 Bottom,因为 Bottom 是单调的
|
||||
if (oldState.state != LatticeVal::Bottom) {
|
||||
newState = SSAPValue(); // Top
|
||||
} else {
|
||||
newState = oldState; // 保持 Bottom
|
||||
}
|
||||
UpdateState(inst, newState);
|
||||
return; // 不处理不可达块中的指令的实际值
|
||||
}
|
||||
|
||||
switch (inst->getKind()) {
|
||||
case Instruction::kAdd:
|
||||
case Instruction::kSub:
|
||||
case Instruction::kMul:
|
||||
case Instruction::kDiv:
|
||||
case Instruction::kRem:
|
||||
case Instruction::kICmpEQ:
|
||||
case Instruction::kICmpNE:
|
||||
case Instruction::kICmpLT:
|
||||
case Instruction::kICmpGT:
|
||||
case Instruction::kICmpLE:
|
||||
case Instruction::kICmpGE:
|
||||
case Instruction::kFAdd:
|
||||
case Instruction::kFSub:
|
||||
case Instruction::kFMul:
|
||||
case Instruction::kFDiv:
|
||||
case Instruction::kFCmpEQ:
|
||||
case Instruction::kFCmpNE:
|
||||
case Instruction::kFCmpLT:
|
||||
case Instruction::kFCmpGT:
|
||||
case Instruction::kFCmpLE:
|
||||
case Instruction::kFCmpGE:
|
||||
case Instruction::kAnd:
|
||||
case Instruction::kOr: {
|
||||
BinaryInst *binaryInst = static_cast<BinaryInst *>(inst);
|
||||
SSAPValue lhs = GetValueState(binaryInst->getOperand(0));
|
||||
SSAPValue rhs = GetValueState(binaryInst->getOperand(1));
|
||||
// 如果任一操作数是 Bottom,结果就是 Bottom
|
||||
if (lhs.state == LatticeVal::Bottom || rhs.state == LatticeVal::Bottom) {
|
||||
newState = SSAPValue(LatticeVal::Bottom);
|
||||
} else if (lhs.state == LatticeVal::Top || rhs.state == LatticeVal::Top) {
|
||||
newState = SSAPValue(); // Top
|
||||
} else { // 都是常量
|
||||
newState = ComputeConstant(binaryInst, lhs, rhs);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Instruction::kNeg:
|
||||
case Instruction::kNot:
|
||||
case Instruction::kFNeg:
|
||||
case Instruction::kFNot: {
|
||||
UnaryInst *unaryInst = static_cast<UnaryInst *>(inst);
|
||||
SSAPValue operand = GetValueState(unaryInst->getOperand());
|
||||
if (operand.state == LatticeVal::Bottom) {
|
||||
newState = SSAPValue(LatticeVal::Bottom);
|
||||
} else if (operand.state == LatticeVal::Top) {
|
||||
newState = SSAPValue(); // Top
|
||||
} else { // 是常量
|
||||
newState = ComputeConstant(unaryInst, operand);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// 直接处理类型转换指令
|
||||
case Instruction::kFtoI: {
|
||||
SSAPValue operand = GetValueState(inst->getOperand(0));
|
||||
if (operand.state == LatticeVal::Constant && operand.constant_type == ValueType::Float) {
|
||||
newState = SSAPValue(static_cast<int>(std::get<float>(operand.constantVal)));
|
||||
} else if (operand.state == LatticeVal::Bottom) {
|
||||
newState = SSAPValue(LatticeVal::Bottom);
|
||||
} else { // Top
|
||||
newState = SSAPValue();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Instruction::kItoF: {
|
||||
SSAPValue operand = GetValueState(inst->getOperand(0));
|
||||
if (operand.state == LatticeVal::Constant && operand.constant_type == ValueType::Integer) {
|
||||
newState = SSAPValue(static_cast<float>(std::get<int>(operand.constantVal)));
|
||||
} else if (operand.state == LatticeVal::Bottom) {
|
||||
newState = SSAPValue(LatticeVal::Bottom);
|
||||
} else { // Top
|
||||
newState = SSAPValue();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Instruction::kBitFtoI: {
|
||||
SSAPValue operand = GetValueState(inst->getOperand(0));
|
||||
if (operand.state == LatticeVal::Constant && operand.constant_type == ValueType::Float) {
|
||||
float fval = std::get<float>(operand.constantVal);
|
||||
newState = SSAPValue(*reinterpret_cast<int *>(&fval));
|
||||
} else if (operand.state == LatticeVal::Bottom) {
|
||||
newState = SSAPValue(LatticeVal::Bottom);
|
||||
} else { // Top
|
||||
newState = SSAPValue();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Instruction::kBitItoF: {
|
||||
SSAPValue operand = GetValueState(inst->getOperand(0));
|
||||
if (operand.state == LatticeVal::Constant && operand.constant_type == ValueType::Integer) {
|
||||
int ival = std::get<int>(operand.constantVal);
|
||||
newState = SSAPValue(*reinterpret_cast<float *>(&ival));
|
||||
} else if (operand.state == LatticeVal::Bottom) {
|
||||
newState = SSAPValue(LatticeVal::Bottom);
|
||||
} else { // Top
|
||||
newState = SSAPValue();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Instruction::kLoad: {
|
||||
// 对于 Load 指令,除非我们有特殊的别名分析,否则假定为 Bottom
|
||||
// 或者如果它加载的是一个已知常量地址的全局常量
|
||||
Value *ptr = inst->getOperand(0);
|
||||
if (auto globalVal = dynamic_cast<GlobalValue *>(ptr)) {
|
||||
// 如果 GlobalValue 有初始化器,并且它是常量,我们可以传播
|
||||
// 这需要额外的逻辑来检查 globalVal 的初始化器
|
||||
// 暂时保守地设置为 Bottom
|
||||
newState = SSAPValue(LatticeVal::Bottom);
|
||||
} else {
|
||||
newState = SSAPValue(LatticeVal::Bottom);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Instruction::kStore:
|
||||
// Store 指令不产生值,其 SSAPValue 不重要
|
||||
newState = SSAPValue(); // 保持 Top
|
||||
break;
|
||||
case Instruction::kCall:
|
||||
// 大多数 Call 指令都假定为 Bottom,除非是纯函数且所有参数都是常量
|
||||
newState = SSAPValue(LatticeVal::Bottom);
|
||||
break;
|
||||
case Instruction::kGetElementPtr: {
|
||||
// GEP 指令计算地址,通常其结果值(地址指向的内容)是 Bottom
|
||||
// 除非所有索引和基指针都是常量,指向一个确定常量值的内存位置
|
||||
bool all_ops_constant = true;
|
||||
for (unsigned i = 0; i < inst->getNumOperands(); ++i) {
|
||||
if (GetValueState(inst->getOperand(i)).state != LatticeVal::Constant) {
|
||||
all_ops_constant = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 即使地址是常量,地址处的内容通常不是。所以通常是 Bottom
|
||||
newState = SSAPValue(LatticeVal::Bottom);
|
||||
break;
|
||||
}
|
||||
case Instruction::kPhi: {
|
||||
PhiInst *phi = static_cast<PhiInst *>(inst);
|
||||
SSAPValue phiResult = SSAPValue(); // 初始为 Top
|
||||
|
||||
for (unsigned i = 0; i < phi->getNumIncomingValues(); ++i) {
|
||||
Value *incomingVal = phi->getIncomingValue(i);
|
||||
BasicBlock *incomingBlock = phi->getIncomingBlock(i);
|
||||
|
||||
if (executableBlocks.count(incomingBlock)) { // 仅考虑可执行前驱
|
||||
phiResult = Meet(phiResult, GetValueState(incomingVal));
|
||||
if (phiResult.state == LatticeVal::Bottom)
|
||||
break; // 如果已经 Bottom,则提前退出
|
||||
}
|
||||
}
|
||||
newState = phiResult;
|
||||
break;
|
||||
}
|
||||
case Instruction::kAlloca: // 对应 kAlloca
|
||||
// Alloca 分配内存,返回一个指针,其内容是 Bottom
|
||||
newState = SSAPValue(LatticeVal::Bottom);
|
||||
break;
|
||||
case Instruction::kBr: // 对应 kBr
|
||||
case Instruction::kCondBr: // 对应 kCondBr
|
||||
case Instruction::kReturn: // 对应 kReturn
|
||||
case Instruction::kUnreachable: // 对应 kUnreachable
|
||||
// 终结符指令不产生值
|
||||
newState = SSAPValue(); // 保持 Top
|
||||
break;
|
||||
case Instruction::kMemset:
|
||||
// Memset 不产生值,但有副作用,不进行常量传播
|
||||
newState = SSAPValue(LatticeVal::Bottom);
|
||||
break;
|
||||
default:
|
||||
if (DEBUG) {
|
||||
std::cout << "Unimplemented instruction kind in SCCP: " << inst->getKind() << std::endl;
|
||||
}
|
||||
newState = SSAPValue(LatticeVal::Bottom); // 未知指令保守处理为 Bottom
|
||||
break;
|
||||
}
|
||||
UpdateState(inst, newState);
|
||||
|
||||
// 特殊处理终结符指令,影响 CFG 边的可达性
|
||||
if (inst->isTerminator()) {
|
||||
if (inst->isBranch()) {
|
||||
|
||||
if (inst->isCondBr()) { // 使用 kCondBr
|
||||
CondBrInst *branchInst = static_cast<CondBrInst *>(inst);
|
||||
SSAPValue condVal = GetValueState(branchInst->getOperand(0));
|
||||
if (condVal.state == LatticeVal::Constant) {
|
||||
bool condition_is_true = false;
|
||||
if (condVal.constant_type == ValueType::Integer) {
|
||||
condition_is_true = (std::get<int>(condVal.constantVal) != 0);
|
||||
} else if (condVal.constant_type == ValueType::Float) {
|
||||
condition_is_true = (std::get<float>(condVal.constantVal) != 0.0f);
|
||||
}
|
||||
|
||||
if (condition_is_true) {
|
||||
AddEdgeToWorkList(branchInst->getParent(), branchInst->getThenBlock());
|
||||
} else {
|
||||
AddEdgeToWorkList(branchInst->getParent(), branchInst->getElseBlock());
|
||||
}
|
||||
} else { // 条件是 Top 或 Bottom,两条路径都可能
|
||||
AddEdgeToWorkList(branchInst->getParent(), branchInst->getThenBlock());
|
||||
AddEdgeToWorkList(branchInst->getParent(), branchInst->getElseBlock());
|
||||
}
|
||||
} else { // 无条件分支 (kBr)
|
||||
UncondBrInst *branchInst = static_cast<UncondBrInst *>(inst);
|
||||
AddEdgeToWorkList(branchInst->getParent(), branchInst->getBlock());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数:处理单条控制流边
|
||||
void SCCPContext::ProcessEdge(const std::pair<BasicBlock *, BasicBlock *> &edge) {
|
||||
BasicBlock *fromBB = edge.first;
|
||||
BasicBlock *toBB = edge.second;
|
||||
|
||||
MarkBlockExecutable(toBB);
|
||||
|
||||
// 对于目标块中的所有 Phi 指令,重新评估其值,因为可能有新的前驱被激活
|
||||
for (auto &inst_ptr : toBB->getInstructions()) {
|
||||
if (dynamic_cast<PhiInst *>(inst_ptr.get())) {
|
||||
instWorkList.push(inst_ptr.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 阶段1: 常量传播与折叠
|
||||
bool SCCPContext::PropagateConstants(Function *func) {
|
||||
bool changed = false;
|
||||
|
||||
// 初始化:所有值 Top,所有块不可执行
|
||||
for (auto &bb_ptr : func->getBasicBlocks()) {
|
||||
executableBlocks.erase(bb_ptr.get());
|
||||
for (auto &inst_ptr : bb_ptr->getInstructions()) {
|
||||
valueState[inst_ptr.get()] = SSAPValue(); // Top
|
||||
}
|
||||
}
|
||||
|
||||
// 标记入口块为可执行
|
||||
if (!func->getBasicBlocks().empty()) {
|
||||
MarkBlockExecutable(func->getEntryBlock());
|
||||
}
|
||||
|
||||
// 主循环:处理工作列表直到不动点
|
||||
while (!instWorkList.empty() || !edgeWorkList.empty()) {
|
||||
while (!edgeWorkList.empty()) {
|
||||
ProcessEdge(edgeWorkList.front());
|
||||
edgeWorkList.pop();
|
||||
}
|
||||
|
||||
while (!instWorkList.empty()) {
|
||||
Instruction *inst = instWorkList.front();
|
||||
instWorkList.pop();
|
||||
ProcessInstruction(inst);
|
||||
}
|
||||
}
|
||||
|
||||
// 应用常量替换和死代码消除
|
||||
std::vector<Instruction *> instsToDelete;
|
||||
for (auto &bb_ptr : func->getBasicBlocks()) {
|
||||
BasicBlock *bb = bb_ptr.get();
|
||||
if (!executableBlocks.count(bb)) {
|
||||
// 整个块是死块,标记所有指令删除
|
||||
for (auto &inst_ptr : bb->getInstructions()) {
|
||||
instsToDelete.push_back(inst_ptr.get());
|
||||
}
|
||||
changed = true;
|
||||
continue;
|
||||
}
|
||||
for (auto it = bb->begin(); it != bb->end();) {
|
||||
Instruction *inst = it->get();
|
||||
SSAPValue ssaPVal = GetValueState(inst);
|
||||
|
||||
if (ssaPVal.state == LatticeVal::Constant) {
|
||||
ConstantValue *constVal = nullptr;
|
||||
if (ssaPVal.constant_type == ValueType::Integer) {
|
||||
constVal = ConstantInteger::get(std::get<int>(ssaPVal.constantVal));
|
||||
} else if (ssaPVal.constant_type == ValueType::Float) {
|
||||
constVal = ConstantFloating::get(std::get<float>(ssaPVal.constantVal));
|
||||
} else {
|
||||
constVal = UndefinedValue::get(inst->getType()); // 不应发生
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "Replacing " << inst->getName() << " with constant ";
|
||||
if (ssaPVal.constant_type == ValueType::Integer)
|
||||
std::cout << std::get<int>(ssaPVal.constantVal);
|
||||
else
|
||||
std::cout << std::get<float>(ssaPVal.constantVal);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
inst->replaceAllUsesWith(constVal);
|
||||
instsToDelete.push_back(inst);
|
||||
++it;
|
||||
changed = true;
|
||||
} else {
|
||||
// 如果操作数是常量,直接替换为常量值(常量折叠)
|
||||
for (unsigned i = 0; i < inst->getNumOperands(); ++i) {
|
||||
Value *operand = inst->getOperand(i);
|
||||
SSAPValue opVal = GetValueState(operand);
|
||||
if (opVal.state == LatticeVal::Constant) {
|
||||
ConstantValue *constOp = nullptr;
|
||||
if (opVal.constant_type == ValueType::Integer) {
|
||||
constOp = ConstantInteger::get(std::get<int>(opVal.constantVal));
|
||||
} else if (opVal.constant_type == ValueType::Float) {
|
||||
constOp = ConstantFloating::get(std::get<float>(opVal.constantVal));
|
||||
} else {
|
||||
constOp = UndefinedValue::get(operand->getType());
|
||||
}
|
||||
|
||||
if (constOp != operand) {
|
||||
inst->setOperand(i, constOp);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 实际删除指令
|
||||
// TODO: 删除的逻辑需要考虑修改
|
||||
for (Instruction *inst : instsToDelete) {
|
||||
// 在尝试删除之前,先检查指令是否仍然附加到其父基本块。
|
||||
// 如果它已经没有父块,可能说明它已被其他方式处理或已处于无效状态。
|
||||
if (inst->getParent() != nullptr) {
|
||||
// 调用负责完整删除的函数,该函数应负责清除uses并将其从父块中移除。
|
||||
SysYIROptUtils::usedelete(inst);
|
||||
}
|
||||
else {
|
||||
// 指令已不属于任何父块,无需再次删除。
|
||||
if (DEBUG) {
|
||||
std::cerr << "Info: Instruction " << inst->getName() << " was already detached or is not in a parent block." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
// 阶段2: 控制流简化
|
||||
bool SCCPContext::SimplifyControlFlow(Function *func) {
|
||||
bool changed = false;
|
||||
|
||||
// 重新确定可达块,因为 PropagateConstants 可能改变了分支条件
|
||||
std::unordered_set<BasicBlock *> newReachableBlocks = FindReachableBlocks(func);
|
||||
|
||||
// 移除不可达块
|
||||
std::vector<BasicBlock *> blocksToDelete;
|
||||
for (auto &bb_ptr : func->getBasicBlocks()) {
|
||||
if (bb_ptr.get() == func->getEntryBlock())
|
||||
continue; // 入口块不能删除
|
||||
if (newReachableBlocks.find(bb_ptr.get()) == newReachableBlocks.end()) {
|
||||
blocksToDelete.push_back(bb_ptr.get());
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
for (BasicBlock *bb : blocksToDelete) {
|
||||
RemoveDeadBlock(bb, func);
|
||||
}
|
||||
|
||||
// 简化分支指令
|
||||
for (auto &bb_ptr : func->getBasicBlocks()) {
|
||||
BasicBlock *bb = bb_ptr.get();
|
||||
if (!newReachableBlocks.count(bb))
|
||||
continue; // 只处理可达块
|
||||
|
||||
Instruction *terminator = bb->terminator()->get();
|
||||
if (terminator->isBranch()) {
|
||||
|
||||
if (terminator->isCondBr()) { // 检查是否是条件分支 (kCondBr)
|
||||
CondBrInst *branchInst = static_cast<CondBrInst *>(terminator);
|
||||
SSAPValue condVal = GetValueState(branchInst->getOperand(0));
|
||||
if (condVal.state == LatticeVal::Constant) {
|
||||
bool condition_is_true = false;
|
||||
if (condVal.constant_type == ValueType::Integer) {
|
||||
condition_is_true = (std::get<int>(condVal.constantVal) != 0);
|
||||
} else if (condVal.constant_type == ValueType::Float) {
|
||||
condition_is_true = (std::get<float>(condVal.constantVal) != 0.0f);
|
||||
}
|
||||
SimplifyBranch(branchInst, condition_is_true);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
// 查找所有可达的基本块 (基于常量条件)
|
||||
std::unordered_set<BasicBlock *> SCCPContext::FindReachableBlocks(Function *func) {
|
||||
std::unordered_set<BasicBlock *> reachable;
|
||||
std::queue<BasicBlock *> q;
|
||||
|
||||
if (func->getEntryBlock()) {
|
||||
q.push(func->getEntryBlock());
|
||||
reachable.insert(func->getEntryBlock());
|
||||
}
|
||||
|
||||
while (!q.empty()) {
|
||||
BasicBlock *currentBB = q.front();
|
||||
q.pop();
|
||||
|
||||
Instruction *terminator = currentBB->terminator()->get();
|
||||
if (!terminator)
|
||||
continue;
|
||||
|
||||
if (terminator->isBranch()) {
|
||||
if (terminator->isCondBr()) { // 检查是否是条件分支 (kCondBr)
|
||||
CondBrInst *branchInst = static_cast<CondBrInst *>(terminator);
|
||||
SSAPValue condVal = GetValueState(branchInst->getOperand(0));
|
||||
if (condVal.state == LatticeVal::Constant) {
|
||||
bool condition_is_true = false;
|
||||
if (condVal.constant_type == ValueType::Integer) {
|
||||
condition_is_true = (std::get<int>(condVal.constantVal) != 0);
|
||||
} else if (condVal.constant_type == ValueType::Float) {
|
||||
condition_is_true = (std::get<float>(condVal.constantVal) != 0.0f);
|
||||
}
|
||||
|
||||
if (condition_is_true) {
|
||||
BasicBlock *trueBlock = branchInst->getThenBlock();
|
||||
if (reachable.find(trueBlock) == reachable.end()) {
|
||||
reachable.insert(trueBlock);
|
||||
q.push(trueBlock);
|
||||
}
|
||||
} else {
|
||||
BasicBlock *falseBlock = branchInst->getElseBlock();
|
||||
if (reachable.find(falseBlock) == reachable.end()) {
|
||||
reachable.insert(falseBlock);
|
||||
q.push(falseBlock);
|
||||
}
|
||||
}
|
||||
} else { // 条件是 Top 或 Bottom,两条路径都可达
|
||||
for (auto succ : branchInst->getSuccessors()) {
|
||||
if (reachable.find(succ) == reachable.end()) {
|
||||
reachable.insert(succ);
|
||||
q.push(succ);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // 无条件分支 (kBr)
|
||||
UncondBrInst *branchInst = static_cast<UncondBrInst *>(terminator);
|
||||
BasicBlock *targetBlock = branchInst->getBlock();
|
||||
if (reachable.find(targetBlock) == reachable.end()) {
|
||||
reachable.insert(targetBlock);
|
||||
q.push(targetBlock);
|
||||
}
|
||||
}
|
||||
} else if (terminator->isReturn() || terminator->isUnreachable()) {
|
||||
// ReturnInst 没有后继,不需要处理
|
||||
// UnreachableInst 也没有后继,不需要处理
|
||||
}
|
||||
}
|
||||
return reachable;
|
||||
}
|
||||
|
||||
// 移除死块
|
||||
void SCCPContext::RemoveDeadBlock(BasicBlock *bb, Function *func) {
|
||||
if (DEBUG) {
|
||||
std::cout << "Removing dead block: " << bb->getName() << std::endl;
|
||||
}
|
||||
// 首先更新其所有前驱的终结指令,移除指向死块的边
|
||||
std::vector<BasicBlock *> preds_to_update;
|
||||
for (auto &pred : bb->getPredecessors()) {
|
||||
if (pred != nullptr) { // 检查是否为空指针
|
||||
preds_to_update.push_back(pred);
|
||||
}
|
||||
}
|
||||
for (BasicBlock *pred : preds_to_update) {
|
||||
if (executableBlocks.count(pred)) {
|
||||
UpdateTerminator(pred, bb);
|
||||
}
|
||||
}
|
||||
|
||||
// 移除其后继的 Phi 节点的入边
|
||||
std::vector<BasicBlock *> succs_to_update;
|
||||
for (auto succ : bb->getSuccessors()) {
|
||||
succs_to_update.push_back(succ);
|
||||
}
|
||||
for (BasicBlock *succ : succs_to_update) {
|
||||
RemovePhiIncoming(succ, bb);
|
||||
succ->removePredecessor(bb);
|
||||
}
|
||||
|
||||
func->removeBasicBlock(bb); // 从函数中移除基本块
|
||||
}
|
||||
|
||||
// 简化分支(将条件分支替换为无条件分支)
|
||||
void SCCPContext::SimplifyBranch(CondBrInst *brInst, bool condVal) {
|
||||
BasicBlock *parentBB = brInst->getParent();
|
||||
BasicBlock *trueBlock = brInst->getThenBlock();
|
||||
BasicBlock *falseBlock = brInst->getElseBlock();
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "Simplifying branch in " << parentBB->getName() << ": cond is " << (condVal ? "true" : "false")
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
builder->setPosition(parentBB, parentBB->findInstIterator(brInst));
|
||||
if (condVal) { // 条件为真,跳转到真分支
|
||||
builder->createUncondBrInst(trueBlock); // 插入无条件分支 kBr
|
||||
SysYIROptUtils::usedelete(brInst); // 移除旧的条件分支指令
|
||||
parentBB->removeSuccessor(falseBlock);
|
||||
falseBlock->removePredecessor(parentBB);
|
||||
RemovePhiIncoming(falseBlock, parentBB);
|
||||
} else { // 条件为假,跳转到假分支
|
||||
builder->createUncondBrInst(falseBlock); // 插入无条件分支 kBr
|
||||
SysYIROptUtils::usedelete(brInst); // 移除旧的条件分支指令
|
||||
parentBB->removeSuccessor(trueBlock);
|
||||
trueBlock->removePredecessor(parentBB);
|
||||
RemovePhiIncoming(trueBlock, parentBB);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新前驱块的终结指令(当一个后继块被移除时)
|
||||
void SCCPContext::UpdateTerminator(BasicBlock *predBB, BasicBlock *removedSucc) {
|
||||
Instruction *terminator = predBB->terminator()->get();
|
||||
if (!terminator)
|
||||
return;
|
||||
|
||||
if (terminator->isBranch()) {
|
||||
if (terminator->isCondBr()) { // 如果是条件分支
|
||||
CondBrInst *branchInst = static_cast<CondBrInst *>(terminator);
|
||||
if (branchInst->getThenBlock() == removedSucc) {
|
||||
if (DEBUG) {
|
||||
std::cout << "Updating cond br in " << predBB->getName() << ": True block (" << removedSucc->getName()
|
||||
<< ") removed. Converting to Br to " << branchInst->getElseBlock()->getName() << std::endl;
|
||||
}
|
||||
builder->setPosition(predBB, predBB->findInstIterator(branchInst));
|
||||
builder->createUncondBrInst(branchInst->getElseBlock());
|
||||
SysYIROptUtils::usedelete(branchInst);
|
||||
predBB->removeSuccessor(removedSucc);
|
||||
} else if (branchInst->getElseBlock() == removedSucc) {
|
||||
if (DEBUG) {
|
||||
std::cout << "Updating cond br in " << predBB->getName() << ": False block (" << removedSucc->getName()
|
||||
<< ") removed. Converting to Br to " << branchInst->getThenBlock()->getName() << std::endl;
|
||||
}
|
||||
builder->setPosition(predBB, predBB->findInstIterator(branchInst));
|
||||
builder->createUncondBrInst(branchInst->getThenBlock());
|
||||
SysYIROptUtils::usedelete(branchInst);
|
||||
predBB->removeSuccessor(removedSucc);
|
||||
}
|
||||
} else { // 无条件分支 (kBr)
|
||||
UncondBrInst *branchInst = static_cast<UncondBrInst *>(terminator);
|
||||
if (branchInst->getBlock() == removedSucc) {
|
||||
if (DEBUG) {
|
||||
std::cout << "Updating unconditional br in " << predBB->getName() << ": Target block ("
|
||||
<< removedSucc->getName() << ") removed. Replacing with Unreachable." << std::endl;
|
||||
}
|
||||
SysYIROptUtils::usedelete(branchInst);
|
||||
predBB->removeSuccessor(removedSucc);
|
||||
builder->setPosition(predBB, predBB->end());
|
||||
builder->createUnreachableInst();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 移除 Phi 节点的入边(当其前驱块被移除时)
|
||||
void SCCPContext::RemovePhiIncoming(BasicBlock *phiParentBB, BasicBlock *removedPred) { // 修正 removedPred 类型
|
||||
std::vector<Instruction *> insts_to_check;
|
||||
for (auto &inst_ptr : phiParentBB->getInstructions()) {
|
||||
insts_to_check.push_back(inst_ptr.get());
|
||||
}
|
||||
|
||||
for (Instruction *inst : insts_to_check) {
|
||||
if (auto phi = dynamic_cast<PhiInst *>(inst)) {
|
||||
phi->delBlk(removedPred);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 运行 SCCP 优化
|
||||
void SCCPContext::run(Function *func, AnalysisManager &AM) {
|
||||
bool changed_constant_propagation = PropagateConstants(func);
|
||||
bool changed_control_flow = SimplifyControlFlow(func);
|
||||
|
||||
// 如果任何一个阶段修改了 IR,标记分析结果为失效
|
||||
if (changed_constant_propagation || changed_control_flow) {
|
||||
// AM.invalidate(); // 假设有这样的方法来使所有分析结果失效
|
||||
}
|
||||
}
|
||||
|
||||
// SCCP Pass methods
|
||||
bool SCCP::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||
if (DEBUG) {
|
||||
std::cout << "Running SCCP on function: " << F->getName() << std::endl;
|
||||
}
|
||||
SCCPContext context(builder);
|
||||
context.run(F, AM);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SCCP::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
|
||||
// analysisInvalidations.insert(nullptr); // 表示使所有默认分析失效
|
||||
analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID); // 支配树可能受影响
|
||||
analysisInvalidations.insert(&LivenessAnalysisPass::ID); // 活跃性分析很可能失效
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@@ -91,13 +91,11 @@ bool SysYCFGOptUtils::SysYBlockMerge(Function *func) {
|
||||
auto thelastinstinst = block->end();
|
||||
(--thelastinstinst);
|
||||
if (thelastinstinst->get()->isUnconditional()) {
|
||||
SysYIROptUtils::usedelete(thelastinstinst->get());
|
||||
thelastinstinst = block->getInstructions().erase(thelastinstinst);
|
||||
thelastinstinst = SysYIROptUtils::usedelete(thelastinstinst);
|
||||
} else if (thelastinstinst->get()->isConditional()) {
|
||||
// 如果是条件分支,判断条件是否相同,主要优化相同布尔表达式
|
||||
if (thelastinstinst->get()->getOperand(1)->getName() == thelastinstinst->get()->getOperand(1)->getName()) {
|
||||
SysYIROptUtils::usedelete(thelastinstinst->get());
|
||||
thelastinstinst = block->getInstructions().erase(thelastinstinst);
|
||||
thelastinstinst = SysYIROptUtils::usedelete(thelastinstinst);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,8 +162,7 @@ bool SysYCFGOptUtils::SysYDelNoPreBLock(Function *func) {
|
||||
if (!blockIter->get()->getreachable()) {
|
||||
for (auto instIter = blockIter->get()->getInstructions().begin();
|
||||
instIter != blockIter->get()->getInstructions().end();) {
|
||||
SysYIROptUtils::usedelete(instIter->get());
|
||||
instIter = blockIter->get()->getInstructions().erase(instIter);
|
||||
instIter = SysYIROptUtils::usedelete(instIter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -306,10 +303,9 @@ bool SysYCFGOptUtils::SysYDelEmptyBlock(Function *func, IRBuilder* pBuilder) {
|
||||
if (dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)) ==
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) {
|
||||
auto thebrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||
SysYIROptUtils::usedelete(thelastinst->get());
|
||||
thelastinst = basicBlock->getInstructions().erase(thelastinst);
|
||||
thelastinst = SysYIROptUtils::usedelete(thelastinst);
|
||||
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||
pBuilder->createUncondBrInst(thebrBlock, {});
|
||||
pBuilder->createUncondBrInst(thebrBlock);
|
||||
changed = true; // 标记IR被修改
|
||||
continue;
|
||||
}
|
||||
@@ -345,10 +341,9 @@ bool SysYCFGOptUtils::SysYDelEmptyBlock(Function *func, IRBuilder* pBuilder) {
|
||||
if (dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1)) ==
|
||||
dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(2))) {
|
||||
auto thebrBlock = dynamic_cast<BasicBlock *>(thelastinst->get()->getOperand(1));
|
||||
SysYIROptUtils::usedelete(thelastinst->get());
|
||||
thelastinst = basicBlock->getInstructions().erase(thelastinst);
|
||||
thelastinst = SysYIROptUtils::usedelete(thelastinst);
|
||||
pBuilder->setPosition(basicBlock.get(), basicBlock->end());
|
||||
pBuilder->createUncondBrInst(thebrBlock, {});
|
||||
pBuilder->createUncondBrInst(thebrBlock);
|
||||
changed = true; // 标记IR被修改
|
||||
continue;
|
||||
}
|
||||
@@ -425,9 +420,7 @@ bool SysYCFGOptUtils::SysYDelEmptyBlock(Function *func, IRBuilder* pBuilder) {
|
||||
|
||||
for (auto instIter = iter->get()->getInstructions().begin();
|
||||
instIter != iter->get()->getInstructions().end();) {
|
||||
SysYIROptUtils::usedelete(instIter->get()); // 仅删除 use 关系
|
||||
// 显式地从基本块中删除指令并更新迭代器
|
||||
instIter = iter->get()->getInstructions().erase(instIter);
|
||||
instIter = SysYIROptUtils::usedelete(instIter);
|
||||
}
|
||||
// 删除不可达基本块的phi指令的操作数
|
||||
for (auto &succ : iter->get()->getSuccessors()) {
|
||||
@@ -523,12 +516,11 @@ bool SysYCFGOptUtils::SysYCondBr2Br(Function *func, IRBuilder* pBuilder) {
|
||||
|
||||
auto thenBlock = dynamic_cast<BasicBlock *>(thelast->get()->getOperand(1));
|
||||
auto elseBlock = dynamic_cast<BasicBlock *>(thelast->get()->getOperand(2));
|
||||
SysYIROptUtils::usedelete(thelast->get());
|
||||
thelast = basicblock->getInstructions().erase(thelast);
|
||||
thelast = SysYIROptUtils::usedelete(thelast);
|
||||
if ((constfloat_Use && constfloat == 1.0F) || (constint_Use && constint == 1)) {
|
||||
// cond为true或非0
|
||||
pBuilder->setPosition(basicblock.get(), basicblock->end());
|
||||
pBuilder->createUncondBrInst(thenBlock, {});
|
||||
pBuilder->createUncondBrInst(thenBlock);
|
||||
|
||||
// 更新CFG关系
|
||||
basicblock->removeSuccessor(elseBlock);
|
||||
@@ -546,7 +538,7 @@ bool SysYCFGOptUtils::SysYCondBr2Br(Function *func, IRBuilder* pBuilder) {
|
||||
} else { // cond为false或0
|
||||
|
||||
pBuilder->setPosition(basicblock.get(), basicblock->end());
|
||||
pBuilder->createUncondBrInst(elseBlock, {});
|
||||
pBuilder->createUncondBrInst(elseBlock);
|
||||
|
||||
// 更新CFG关系
|
||||
basicblock->removeSuccessor(thenBlock);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "DCE.h"
|
||||
#include "Mem2Reg.h"
|
||||
#include "Reg2Mem.h"
|
||||
#include "SCCP.h"
|
||||
#include "Pass.h"
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
@@ -50,6 +51,8 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
||||
registerOptimizationPass<Mem2Reg>(builderIR);
|
||||
registerOptimizationPass<Reg2Mem>(builderIR);
|
||||
|
||||
registerOptimizationPass<SCCP>(builderIR);
|
||||
|
||||
if (optLevel >= 1) {
|
||||
//经过设计安排优化遍的执行顺序以及执行逻辑
|
||||
if (DEBUG) std::cout << "Applying -O1 optimizations.\n";
|
||||
@@ -87,6 +90,15 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
||||
printPasses();
|
||||
}
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&SCCP::ID);
|
||||
this->run();
|
||||
|
||||
if(DEBUG) {
|
||||
std::cout << "=== IR After SCCP Optimizations ===\n";
|
||||
printPasses();
|
||||
}
|
||||
|
||||
this->clearPasses();
|
||||
this->addPass(&Reg2Mem::ID);
|
||||
this->run();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,7 @@
|
||||
#include "SysYIRPrinter.h"
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include "IR.h" // 确保IR.h包含了ArrayType、GetElementPtrInst等的定义
|
||||
|
||||
@@ -64,21 +61,16 @@ std::string SysYPrinter::getValueName(Value *value) {
|
||||
} else if (auto constInt = dynamic_cast<ConstantInteger*>(value)) { // 优先匹配具体的常量类型
|
||||
return std::to_string(constInt->getInt());
|
||||
} else if (auto constFloat = dynamic_cast<ConstantFloating*>(value)) { // 优先匹配具体的常量类型
|
||||
std::ostringstream oss;
|
||||
oss << std::scientific << std::setprecision(std::numeric_limits<float>::max_digits10) << constFloat->getFloat();
|
||||
return oss.str();
|
||||
return std::to_string(constFloat->getFloat());
|
||||
} else if (auto constUndef = dynamic_cast<UndefinedValue*>(value)) { // 如果有Undef类型
|
||||
return "undef";
|
||||
} else if (auto constVal = dynamic_cast<ConstantValue*>(value)) { // fallback for generic ConstantValue
|
||||
// 这里的逻辑可能需要根据你ConstantValue的实际设计调整
|
||||
// 确保它能处理所有可能的ConstantValue
|
||||
if (auto constInt = dynamic_cast<ConstantInteger*>(value)) { // 优先匹配具体的常量类型
|
||||
return std::to_string(constInt->getInt());
|
||||
} else if (auto constFloat = dynamic_cast<ConstantFloating*>(value)) { // 优先匹配具体的常量类型
|
||||
std::ostringstream oss;
|
||||
oss << std::scientific << std::setprecision(std::numeric_limits<float>::max_digits10) << constFloat->getFloat();
|
||||
return oss.str();
|
||||
if (constVal->getType()->isFloat()) {
|
||||
return std::to_string(constVal->getFloat());
|
||||
}
|
||||
return std::to_string(constVal->getInt());
|
||||
} else if (auto constVar = dynamic_cast<ConstantVariable*>(value)) {
|
||||
return constVar->getName(); // 假设ConstantVariable有自己的名字或通过getByIndices获取值
|
||||
} else if (auto argVar = dynamic_cast<Argument*>(value)) {
|
||||
@@ -408,7 +400,12 @@ void SysYPrinter::printInst(Instruction *pInst) {
|
||||
}
|
||||
std::cout << std::endl;
|
||||
} break;
|
||||
|
||||
|
||||
case Kind::kUnreachable: {
|
||||
std::cout << "Unreachable" << std::endl;
|
||||
|
||||
} break;
|
||||
|
||||
case Kind::kAlloca: {
|
||||
auto allocaInst = dynamic_cast<AllocaInst *>(pInst);
|
||||
std::cout << "%" << allocaInst->getName() << " = alloca ";
|
||||
@@ -419,17 +416,6 @@ void SysYPrinter::printInst(Instruction *pInst) {
|
||||
auto allocatedType = allocaInst->getAllocatedType();
|
||||
printType(allocatedType);
|
||||
|
||||
// 仍然打印维度信息,如果存在的话
|
||||
if (allocaInst->getNumDims() > 0) {
|
||||
std::cout << ", ";
|
||||
for (size_t i = 0; i < allocaInst->getNumDims(); i++) {
|
||||
if (i > 0) std::cout << ", ";
|
||||
printType(Type::getIntType()); // 维度大小通常是 i32 类型
|
||||
std::cout << " ";
|
||||
printValue(allocaInst->getDim(i));
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << ", align 4" << std::endl;
|
||||
} break;
|
||||
|
||||
@@ -442,17 +428,6 @@ void SysYPrinter::printInst(Instruction *pInst) {
|
||||
std::cout << " ";
|
||||
printValue(loadInst->getPointer()); // 要加载的地址
|
||||
|
||||
// 仍然打印索引信息,如果存在的话
|
||||
if (loadInst->getNumIndices() > 0) {
|
||||
std::cout << ", indices "; // 或者其他分隔符,取决于你期望的格式
|
||||
for (size_t i = 0; i < loadInst->getNumIndices(); i++) {
|
||||
if (i > 0) std::cout << ", ";
|
||||
printType(loadInst->getIndex(i)->getType());
|
||||
std::cout << " ";
|
||||
printValue(loadInst->getIndex(i));
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << ", align 4" << std::endl;
|
||||
} break;
|
||||
|
||||
@@ -467,16 +442,6 @@ void SysYPrinter::printInst(Instruction *pInst) {
|
||||
std::cout << " ";
|
||||
printValue(storeInst->getPointer()); // 目标地址
|
||||
|
||||
// 仍然打印索引信息,如果存在的话
|
||||
if (storeInst->getNumIndices() > 0) {
|
||||
std::cout << ", indices "; // 或者其他分隔符
|
||||
for (size_t i = 0; i < storeInst->getNumIndices(); i++) {
|
||||
if (i > 0) std::cout << ", ";
|
||||
printType(storeInst->getIndex(i)->getType());
|
||||
std::cout << " ";
|
||||
printValue(storeInst->getIndex(i));
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << ", align 4" << std::endl;
|
||||
} break;
|
||||
|
||||
Reference in New Issue
Block a user