Compare commits
10 Commits
peephole
...
deploy-202
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed8fc32a23 | ||
|
|
9ba08126fb | ||
|
|
875100ec01 | ||
|
|
b0cecca081 | ||
|
|
fcc3806342 | ||
|
|
792dc9c1f6 | ||
|
|
429e477776 | ||
|
|
2e8b564d8f | ||
|
|
2dd6a17fca | ||
|
|
af318b6c0e |
@@ -33,11 +33,11 @@ add_executable(sysyc
|
|||||||
RISCv64ISel.cpp
|
RISCv64ISel.cpp
|
||||||
RISCv64RegAlloc.cpp
|
RISCv64RegAlloc.cpp
|
||||||
RISCv64AsmPrinter.cpp
|
RISCv64AsmPrinter.cpp
|
||||||
# RISCv64Passes.cpp
|
|
||||||
RISCv64Peephole.cpp
|
RISCv64Peephole.cpp
|
||||||
PreRA_Scheduler.cpp
|
PreRA_Scheduler.cpp
|
||||||
PostRA_Scheduler.cpp
|
PostRA_Scheduler.cpp
|
||||||
CalleeSavedHandler.cpp
|
CalleeSavedHandler.cpp
|
||||||
|
RISCv64LLIR.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# 设置 include 路径,包含 ANTLR 运行时库和项目头文件
|
# 设置 include 路径,包含 ANTLR 运行时库和项目头文件
|
||||||
|
|||||||
@@ -12,27 +12,25 @@ bool CalleeSavedHandler::runOnFunction(Function *F, AnalysisManager& AM) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
|
void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
|
||||||
|
// 【最终方案】: 此 Pass 负责分析、分配栈空间并插入 callee-saved 寄存器的保存/恢复指令。
|
||||||
|
// 它通过与 FrameInfo 协作,确保为 callee-saved 寄存器分配的空间与局部变量/溢出槽的空间不冲突。
|
||||||
|
// 这样做可以使生成的 sd/ld 指令能被后续的优化 Pass (如 PostRA-Scheduler) 处理。
|
||||||
|
|
||||||
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
||||||
std::set<PhysicalReg> used_callee_saved;
|
std::set<PhysicalReg> used_callee_saved;
|
||||||
|
|
||||||
// 1. 扫描所有指令,找出被使用的s寄存器
|
// 1. 扫描所有指令,找出被使用的s寄存器 (s1-s11)
|
||||||
for (auto& mbb : mfunc->getBlocks()) {
|
for (auto& mbb : mfunc->getBlocks()) {
|
||||||
for (auto& instr : mbb->getInstructions()) {
|
for (auto& instr : mbb->getInstructions()) {
|
||||||
for (auto& op : instr->getOperands()) {
|
for (auto& op : instr->getOperands()) {
|
||||||
|
|
||||||
// 辅助Lambda,用于检查和插入寄存器
|
|
||||||
auto check_and_insert_reg = [&](RegOperand* reg_op) {
|
auto check_and_insert_reg = [&](RegOperand* reg_op) {
|
||||||
if (!reg_op->isVirtual()) {
|
if (!reg_op->isVirtual()) {
|
||||||
PhysicalReg preg = reg_op->getPReg();
|
PhysicalReg preg = reg_op->getPReg();
|
||||||
// --- 关键检查点 ---
|
if (preg >= PhysicalReg::S1 && preg <= PhysicalReg::S11) {
|
||||||
// 必须严格判断是否在 s0-s11 的范围内。
|
|
||||||
// a0, t0 等寄存器绝对不应被视为被调用者保存寄存器。
|
|
||||||
if (preg >= PhysicalReg::S0 && preg <= PhysicalReg::S11) {
|
|
||||||
used_callee_saved.insert(preg);
|
used_callee_saved.insert(preg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||||
check_and_insert_reg(static_cast<RegOperand*>(op.get()));
|
check_and_insert_reg(static_cast<RegOperand*>(op.get()));
|
||||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||||
@@ -41,66 +39,82 @@ void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果没有使用s寄存器(除了可能作为帧指针的s0),则无需操作
|
if (used_callee_saved.empty()) {
|
||||||
if (used_callee_saved.empty() || (used_callee_saved.size() == 1 && used_callee_saved.count(PhysicalReg::S0))) {
|
frame_info.callee_saved_size = 0; // 确保大小被初始化
|
||||||
return;
|
return; // 无需操作
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将结果存入StackFrameInfo,供后续使用
|
// 2. 计算为 callee-saved 寄存器分配的栈空间
|
||||||
frame_info.used_callee_saved_regs = used_callee_saved;
|
// 这里的关键是,偏移的基准点要在局部变量和溢出槽之下。
|
||||||
|
int callee_saved_size = used_callee_saved.size() * 8;
|
||||||
|
frame_info.callee_saved_size = callee_saved_size; // 将大小存入 FrameInfo
|
||||||
|
|
||||||
|
// 3. 计算无冲突的栈偏移
|
||||||
|
// 栈向下增长,所以偏移是负数。
|
||||||
|
// ra/s0 占用 -8 和 -16。局部变量和溢出区在它们之下。callee-saved 区在更下方。
|
||||||
|
// 我们使用相对于 s0 的偏移。s0 将指向栈顶 (sp + total_size)。
|
||||||
|
int base_offset = -16 - frame_info.locals_size - frame_info.spill_size;
|
||||||
|
|
||||||
// 2. 在函数序言插入保存指令
|
|
||||||
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
|
|
||||||
auto& entry_instrs = entry_block->getInstructions();
|
|
||||||
auto prologue_end = entry_instrs.begin();
|
|
||||||
|
|
||||||
// 找到序言结束的位置(通常是addi s0, sp, size之后)
|
|
||||||
for (auto it = entry_instrs.begin(); it != entry_instrs.end(); ++it) {
|
|
||||||
if ((*it)->getOpcode() == RVOpcodes::ADDI &&
|
|
||||||
(*it)->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
|
|
||||||
static_cast<RegOperand*>((*it)->getOperands()[0].get())->getPReg() == PhysicalReg::S0)
|
|
||||||
{
|
|
||||||
prologue_end = std::next(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 为了栈帧布局确定性,对寄存器进行排序
|
// 为了栈帧布局确定性,对寄存器进行排序
|
||||||
std::vector<PhysicalReg> sorted_regs(used_callee_saved.begin(), used_callee_saved.end());
|
std::vector<PhysicalReg> sorted_regs(used_callee_saved.begin(), used_callee_saved.end());
|
||||||
std::sort(sorted_regs.begin(), sorted_regs.end());
|
std::sort(sorted_regs.begin(), sorted_regs.end());
|
||||||
|
|
||||||
int current_offset = -16; // ra和s0已经占用了-8和-16的位置
|
// 4. 在函数序言插入保存指令
|
||||||
|
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
|
||||||
|
auto& entry_instrs = entry_block->getInstructions();
|
||||||
|
auto prologue_end = entry_instrs.begin();
|
||||||
|
|
||||||
|
// 找到序言结束的位置(通常是addi s0, sp, size之后,但为了让优化器看到,我们插在更前面)
|
||||||
|
// 合理的位置是在 IR 指令开始之前,即在任何非序言指令(如第一个标签)之前。
|
||||||
|
// 为简单起见,我们直接插入到块的开头,后续重排 pass 会处理。
|
||||||
|
// (更优的实现会寻找一个特定的插入点)
|
||||||
|
|
||||||
|
int current_offset = base_offset;
|
||||||
for (PhysicalReg reg : sorted_regs) {
|
for (PhysicalReg reg : sorted_regs) {
|
||||||
if (reg == PhysicalReg::S0) continue; // s0已经在序言中处理
|
|
||||||
current_offset -= 8;
|
|
||||||
auto sd = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
auto sd = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
||||||
sd->addOperand(std::make_unique<RegOperand>(reg));
|
sd->addOperand(std::make_unique<RegOperand>(reg));
|
||||||
sd->addOperand(std::make_unique<MemOperand>(
|
sd->addOperand(std::make_unique<MemOperand>(
|
||||||
std::make_unique<RegOperand>(PhysicalReg::S0), // 假设s0是帧指针
|
std::make_unique<RegOperand>(PhysicalReg::S0), // 基址为帧指针 s0
|
||||||
std::make_unique<ImmOperand>(current_offset)
|
std::make_unique<ImmOperand>(current_offset)
|
||||||
));
|
));
|
||||||
entry_instrs.insert(prologue_end, std::move(sd));
|
// 从头部插入,但要放在函数标签之后
|
||||||
|
entry_instrs.insert(entry_instrs.begin() + 1, std::move(sd));
|
||||||
|
current_offset -= 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 在函数结尾(ret之前)插入恢复指令
|
// 5. 【已修复】在函数结尾(ret之前)插入恢复指令,使用反向遍历来避免迭代器失效
|
||||||
for (auto& mbb : mfunc->getBlocks()) {
|
for (auto& mbb : mfunc->getBlocks()) {
|
||||||
|
// 使用手动控制的反向循环
|
||||||
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
|
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
|
||||||
if ((*it)->getOpcode() == RVOpcodes::RET) {
|
if ((*it)->getOpcode() == RVOpcodes::RET) {
|
||||||
// 以相反的顺序恢复
|
// 1. 创建一个临时vector来存储所有需要插入的恢复指令
|
||||||
current_offset = -16;
|
std::vector<std::unique_ptr<MachineInstr>> restore_instrs;
|
||||||
|
|
||||||
|
int current_offset_load = base_offset;
|
||||||
|
// 以相同的顺序(例如 s1, s2, ...)创建恢复指令
|
||||||
for (PhysicalReg reg : sorted_regs) {
|
for (PhysicalReg reg : sorted_regs) {
|
||||||
if (reg == PhysicalReg::S0) continue;
|
|
||||||
current_offset -= 8;
|
|
||||||
auto ld = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
auto ld = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
||||||
ld->addOperand(std::make_unique<RegOperand>(reg));
|
ld->addOperand(std::make_unique<RegOperand>(reg));
|
||||||
ld->addOperand(std::make_unique<MemOperand>(
|
ld->addOperand(std::make_unique<MemOperand>(
|
||||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||||
std::make_unique<ImmOperand>(current_offset)
|
std::make_unique<ImmOperand>(current_offset_load)
|
||||||
));
|
));
|
||||||
mbb->getInstructions().insert(it, std::move(ld));
|
restore_instrs.push_back(std::move(ld));
|
||||||
|
current_offset_load -= 8;
|
||||||
}
|
}
|
||||||
break; // 处理完一个基本块的ret即可
|
|
||||||
|
// 2. 使用 make_move_iterator 一次性将所有恢复指令插入到 RET 指令之前
|
||||||
|
// 这可以高效地转移指令的所有权,并且只让迭代器失效一次。
|
||||||
|
if (!restore_instrs.empty()) {
|
||||||
|
mbb->getInstructions().insert(it,
|
||||||
|
std::make_move_iterator(restore_instrs.begin()),
|
||||||
|
std::make_move_iterator(restore_instrs.end())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 找到了RET并处理完毕后,就可以跳出内层循环,继续寻找下一个基本块
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,15 +35,26 @@ void RISCv64AsmPrinter::run(std::ostream& os, bool debug) {
|
|||||||
|
|
||||||
void RISCv64AsmPrinter::printPrologue() {
|
void RISCv64AsmPrinter::printPrologue() {
|
||||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||||
// 序言需要为保存ra和s0预留16字节
|
// 计算总栈帧大小。
|
||||||
int total_stack_size = frame_info.locals_size + frame_info.spill_size + 16;
|
// 包含三部分:局部变量区、寄存器溢出区、以及为被调用者保存(callee-saved)寄存器预留的区域。
|
||||||
|
// 最后再加上为保存 ra 和 s0 固定的16字节。
|
||||||
|
int total_stack_size = frame_info.locals_size +
|
||||||
|
frame_info.spill_size +
|
||||||
|
frame_info.callee_saved_size +
|
||||||
|
16;
|
||||||
|
|
||||||
|
// 保持栈指针16字节对齐
|
||||||
int aligned_stack_size = (total_stack_size + 15) & ~15;
|
int aligned_stack_size = (total_stack_size + 15) & ~15;
|
||||||
frame_info.total_size = aligned_stack_size;
|
frame_info.total_size = aligned_stack_size; // 更新最终的栈大小
|
||||||
|
|
||||||
|
// 只有在需要分配栈空间时才生成指令
|
||||||
if (aligned_stack_size > 0) {
|
if (aligned_stack_size > 0) {
|
||||||
|
// 1. 一次性分配整个栈帧
|
||||||
*OS << " addi sp, sp, -" << aligned_stack_size << "\n";
|
*OS << " addi sp, sp, -" << aligned_stack_size << "\n";
|
||||||
|
// 2. 在新的栈顶附近保存 ra 和 s0
|
||||||
*OS << " sd ra, " << (aligned_stack_size - 8) << "(sp)\n";
|
*OS << " sd ra, " << (aligned_stack_size - 8) << "(sp)\n";
|
||||||
*OS << " sd s0, " << (aligned_stack_size - 16) << "(sp)\n";
|
*OS << " sd s0, " << (aligned_stack_size - 16) << "(sp)\n";
|
||||||
|
// 3. 设置新的帧指针 s0,使其指向栈帧的底部(高地址)
|
||||||
*OS << " addi s0, sp, " << aligned_stack_size << "\n";
|
*OS << " addi s0, sp, " << aligned_stack_size << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,7 +126,18 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
|
|||||||
case RVOpcodes::MV: *OS << "mv "; break; case RVOpcodes::NEG: *OS << "neg "; 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::NEGW: *OS << "negw "; break; case RVOpcodes::SEQZ: *OS << "seqz "; break;
|
||||||
case RVOpcodes::SNEZ: *OS << "snez "; break;
|
case RVOpcodes::SNEZ: *OS << "snez "; break;
|
||||||
case RVOpcodes::CALL: *OS << "call "; break;
|
case RVOpcodes::CALL: { // [核心修改] 为CALL指令添加特殊处理逻辑
|
||||||
|
*OS << "call ";
|
||||||
|
// 遍历所有操作数,只寻找并打印函数名标签
|
||||||
|
for (const auto& op : instr->getOperands()) {
|
||||||
|
if (op->getKind() == MachineOperand::KIND_LABEL) {
|
||||||
|
printOperand(op.get());
|
||||||
|
break; // 找到标签后即可退出
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*OS << "\n";
|
||||||
|
return; // 处理完毕,直接返回,不再执行后续的通用操作数打印
|
||||||
|
}
|
||||||
case RVOpcodes::LABEL:
|
case RVOpcodes::LABEL:
|
||||||
break;
|
break;
|
||||||
case RVOpcodes::FRAME_LOAD_W:
|
case RVOpcodes::FRAME_LOAD_W:
|
||||||
|
|||||||
@@ -16,13 +16,59 @@ std::string RISCv64CodeGen::code_gen() {
|
|||||||
std::string RISCv64CodeGen::module_gen() {
|
std::string RISCv64CodeGen::module_gen() {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
// 1. 处理全局变量 (.data段)
|
// --- [新逻辑] 步骤1:将全局变量分为.data和.bss两组 ---
|
||||||
if (!module->getGlobals().empty()) {
|
std::vector<GlobalValue*> data_globals;
|
||||||
ss << ".data\n";
|
std::vector<GlobalValue*> bss_globals;
|
||||||
for (const auto& global : module->getGlobals()) {
|
|
||||||
|
for (const auto& global_ptr : module->getGlobals()) {
|
||||||
|
GlobalValue* global = global_ptr.get();
|
||||||
|
const auto& init_values = global->getInitValues();
|
||||||
|
|
||||||
|
// 判断是否为大型零初始化数组,以便放入.bss段
|
||||||
|
bool is_large_zero_array = false;
|
||||||
|
// 规则:初始化列表只有一项,且该项是值为0的整数,且数量大于一个阈值(例如16)
|
||||||
|
if (init_values.getValues().size() == 1) {
|
||||||
|
if (auto const_val = dynamic_cast<ConstantValue*>(init_values.getValues()[0])) {
|
||||||
|
if (const_val->isInt() && const_val->getInt() == 0 && init_values.getNumbers()[0] > 16) {
|
||||||
|
is_large_zero_array = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_large_zero_array) {
|
||||||
|
bss_globals.push_back(global);
|
||||||
|
} else {
|
||||||
|
data_globals.push_back(global);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- [新逻辑] 步骤2:生成 .bss 段的代码 ---
|
||||||
|
if (!bss_globals.empty()) {
|
||||||
|
ss << ".bss\n"; // 切换到 .bss 段
|
||||||
|
for (GlobalValue* global : bss_globals) {
|
||||||
|
// 获取数组总大小(元素个数 * 元素大小)
|
||||||
|
// 在SysY中,我们假设元素都是4字节(int或float)
|
||||||
|
unsigned count = global->getInitValues().getNumbers()[0];
|
||||||
|
unsigned total_size = count * 4;
|
||||||
|
|
||||||
|
ss << " .align 3\n"; // 8字节对齐 (2^3)
|
||||||
|
ss << ".globl " << global->getName() << "\n";
|
||||||
|
ss << ".type " << global->getName() << ", @object\n";
|
||||||
|
ss << ".size " << global->getName() << ", " << total_size << "\n";
|
||||||
|
ss << global->getName() << ":\n";
|
||||||
|
// 使用 .space 指令来预留指定大小的零填充空间
|
||||||
|
ss << " .space " << total_size << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- [旧逻辑保留] 步骤3:生成 .data 段的代码 ---
|
||||||
|
if (!data_globals.empty()) {
|
||||||
|
ss << ".data\n"; // 切换到 .data 段
|
||||||
|
for (GlobalValue* global : data_globals) {
|
||||||
ss << ".globl " << global->getName() << "\n";
|
ss << ".globl " << global->getName() << "\n";
|
||||||
ss << global->getName() << ":\n";
|
ss << global->getName() << ":\n";
|
||||||
const auto& init_values = global->getInitValues();
|
const auto& init_values = global->getInitValues();
|
||||||
|
// 使用您原有的逻辑来处理显式初始化的值
|
||||||
for (size_t i = 0; i < init_values.getValues().size(); ++i) {
|
for (size_t i = 0; i < init_values.getValues().size(); ++i) {
|
||||||
auto val = init_values.getValues()[i];
|
auto val = init_values.getValues()[i];
|
||||||
auto count = init_values.getNumbers()[i];
|
auto count = init_values.getNumbers()[i];
|
||||||
@@ -41,7 +87,7 @@ std::string RISCv64CodeGen::module_gen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 处理函数 (.text段)
|
// --- 处理函数 (.text段) 的逻辑保持不变 ---
|
||||||
if (!module->getFunctions().empty()) {
|
if (!module->getFunctions().empty()) {
|
||||||
ss << ".text\n";
|
ss << ".text\n";
|
||||||
for (const auto& func_pair : module->getFunctions()) {
|
for (const auto& func_pair : module->getFunctions()) {
|
||||||
|
|||||||
@@ -582,7 +582,22 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto call_instr = std::make_unique<MachineInstr>(RVOpcodes::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()));
|
call_instr->addOperand(std::make_unique<LabelOperand>(call->getCallee()->getName()));
|
||||||
|
|
||||||
|
// 将所有参数的虚拟寄存器也作为后续操作数,供getInstrUseDef分析
|
||||||
|
for (size_t i = 0; i < num_operands; ++i) {
|
||||||
|
if (node->operands[i]->kind != DAGNode::CONSTANT) { // 常量参数已直接加载,无需作为use
|
||||||
|
call_instr->addOperand(std::make_unique<RegOperand>(getVReg(node->operands[i]->value)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CurMBB->addInstruction(std::move(call_instr));
|
CurMBB->addInstruction(std::move(call_instr));
|
||||||
|
|
||||||
if (num_operands > 8) {
|
if (num_operands > 8) {
|
||||||
@@ -596,12 +611,12 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
CurMBB->addInstruction(std::move(dealloc_instr));
|
CurMBB->addInstruction(std::move(dealloc_instr));
|
||||||
}
|
}
|
||||||
// 处理返回值,从a0移动到目标虚拟寄存器
|
// 处理返回值,从a0移动到目标虚拟寄存器
|
||||||
if (!call->getType()->isVoid()) {
|
// if (!call->getType()->isVoid()) {
|
||||||
auto mv_instr = std::make_unique<MachineInstr>(RVOpcodes::MV);
|
// 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>(getVReg(call)));
|
||||||
mv_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
|
// mv_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
|
||||||
CurMBB->addInstruction(std::move(mv_instr));
|
// CurMBB->addInstruction(std::move(mv_instr));
|
||||||
}
|
// }
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
6
src/RISCv64LLIR.cpp
Normal file
6
src/RISCv64LLIR.cpp
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#include "RISCv64LLIR.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
#include "RISCv64RegAlloc.h"
|
#include "RISCv64RegAlloc.h"
|
||||||
#include "RISCv64ISel.h"
|
#include "RISCv64ISel.h"
|
||||||
|
#include "RISCv64AsmPrinter.h" // For DEBUG output
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <iostream> // For DEBUG output
|
||||||
|
#include <cassert> // For assert
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
@@ -15,35 +18,69 @@ RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) : MFunc(mfunc) {
|
|||||||
PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
|
PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
|
||||||
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
|
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 映射物理寄存器到特殊的虚拟寄存器ID,用于干扰图中的物理寄存器节点
|
||||||
|
// 确保这些特殊ID不会与vreg_counter生成的常规虚拟寄存器ID冲突
|
||||||
|
for (PhysicalReg preg : allocable_int_regs) {
|
||||||
|
preg_to_vreg_id_map[preg] = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID) + static_cast<unsigned>(preg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 寄存器分配的主入口点
|
||||||
void RISCv64RegAlloc::run() {
|
void RISCv64RegAlloc::run() {
|
||||||
handleCallingConvention();
|
// 阶段 1: 处理函数调用约定(参数寄存器预着色)
|
||||||
|
handleCallingConvention();
|
||||||
|
// 阶段 2: 消除帧索引(为局部变量和栈参数分配栈偏移)
|
||||||
eliminateFrameIndices();
|
eliminateFrameIndices();
|
||||||
analyzeLiveness();
|
{ // 使用大括号创建一个局部作用域,避免printer变量泄露
|
||||||
buildInterferenceGraph();
|
if (DEBUG) {
|
||||||
colorGraph();
|
std::cerr << "\n===== LLIR after eliminateFrameIndices for function: "
|
||||||
rewriteFunction();
|
<< MFunc->getName() << " =====\n";
|
||||||
|
// 1. 创建一个 AsmPrinter 实例,传入当前的 MachineFunction
|
||||||
|
RISCv64AsmPrinter printer(MFunc);
|
||||||
|
// 2. 调用 run 方法,将结果打印到标准错误流 (std::cerr)
|
||||||
|
// 3. 必须将 debug 参数设为 true!
|
||||||
|
// 因为此时指令中仍然包含虚拟寄存器 (%vreg),
|
||||||
|
// debug模式下的 AsmPrinter 才能正确处理它们而不会报错。
|
||||||
|
printer.run(std::cerr, true);
|
||||||
|
std::cerr << "===== End of LLIR =====\n\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 阶段 3: 活跃性分析
|
||||||
|
analyzeLiveness();
|
||||||
|
// 阶段 4: 构建干扰图(包含CALL指令对调用者保存寄存器的影响)
|
||||||
|
buildInterferenceGraph();
|
||||||
|
// 阶段 5: 图着色算法分配物理寄存器
|
||||||
|
colorGraph();
|
||||||
|
// 阶段 6: 重写函数(插入溢出/填充代码,替换虚拟寄存器为物理寄存器)
|
||||||
|
rewriteFunction();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 处理调用约定,预先为函数参数分配物理寄存器。
|
* @brief 处理调用约定,预先为函数参数和调用返回值分配物理寄存器。
|
||||||
|
* 这个函数现在负责处理调用约定的两个方面:
|
||||||
|
* 1. 作为被调用者(callee),如何接收传入的参数。
|
||||||
|
* 2. 作为调用者(caller),如何接收调用的其他函数的返回值。
|
||||||
*/
|
*/
|
||||||
void RISCv64RegAlloc::handleCallingConvention() {
|
void RISCv64RegAlloc::handleCallingConvention() {
|
||||||
Function* F = MFunc->getFunc();
|
Function* F = MFunc->getFunc();
|
||||||
RISCv64ISel* isel = MFunc->getISel();
|
RISCv64ISel* isel = MFunc->getISel();
|
||||||
|
|
||||||
|
// --- 部分1:处理函数传入参数的预着色 ---
|
||||||
// 获取函数的Argument对象列表
|
// 获取函数的Argument对象列表
|
||||||
if (F) {
|
if (F) {
|
||||||
auto& args = F->getArguments();
|
auto& args = F->getArguments();
|
||||||
// RISC-V RV64G调用约定:前8个整型/指针参数通过 a0-a7 传递
|
// RISC-V RV64G调用约定:前8个整型/指针参数通过 a0-a7 传递
|
||||||
int arg_idx = 0;
|
int arg_idx = 0;
|
||||||
// 遍历 AllocaInst* 列表
|
// 遍历 Argument* 列表
|
||||||
for (Argument* arg : args) {
|
for (Argument* arg : args) {
|
||||||
if (arg_idx >= 8) {
|
if (arg_idx >= 8) {
|
||||||
break;
|
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 对象对应的虚拟寄存器
|
// 1. 获取该 Argument 对象对应的虚拟寄存器
|
||||||
unsigned vreg = isel->getVReg(arg);
|
unsigned vreg = isel->getVReg(arg);
|
||||||
|
|
||||||
@@ -56,8 +93,35 @@ void RISCv64RegAlloc::handleCallingConvention() {
|
|||||||
arg_idx++;
|
arg_idx++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// // --- 部分2:[新逻辑] 遍历所有指令,为CALL指令的返回值预着色为 a0 ---
|
||||||
|
// // 这是为了强制寄存器分配器知道,call的结果物理上出现在a0寄存器。
|
||||||
|
for (auto& mbb : MFunc->getBlocks()) {
|
||||||
|
for (auto& instr : mbb->getInstructions()) {
|
||||||
|
if (instr->getOpcode() == RVOpcodes::CALL) {
|
||||||
|
// 根据协议,如果CALL有返回值,其目标vreg是第一个操作数
|
||||||
|
if (!instr->getOperands().empty() &&
|
||||||
|
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG)
|
||||||
|
{
|
||||||
|
auto reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
|
||||||
|
if (reg_op->isVirtual()) {
|
||||||
|
unsigned ret_vreg = reg_op->getVRegNum();
|
||||||
|
// 强制将这个虚拟寄存器预着色为 a0
|
||||||
|
color_map[ret_vreg] = PhysicalReg::A0;
|
||||||
|
if (DEBUG) {
|
||||||
|
std::cout << "[DEBUG] Pre-coloring vreg" << ret_vreg
|
||||||
|
<< " to a0 for CALL instruction." << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 消除帧索引,为局部变量和栈参数分配栈偏移量,并展开伪指令。
|
||||||
|
*/
|
||||||
void RISCv64RegAlloc::eliminateFrameIndices() {
|
void RISCv64RegAlloc::eliminateFrameIndices() {
|
||||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||||
// 初始偏移量,为保存ra和s0留出空间。
|
// 初始偏移量,为保存ra和s0留出空间。
|
||||||
@@ -185,79 +249,117 @@ void RISCv64RegAlloc::eliminateFrameIndices() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 计算给定 MachineInstr 的 Use (读取) 和 Def (写入) 寄存器集合。
|
||||||
|
* 这是活跃性分析的基础。
|
||||||
|
* @param instr 要分析的机器指令。
|
||||||
|
* @param use 存储 Use 寄存器(虚拟寄存器 ID)的集合。
|
||||||
|
* @param def 存储 Def 寄存器(虚拟寄存器 ID)的集合。
|
||||||
|
*/
|
||||||
void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def) {
|
void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def) {
|
||||||
bool is_def = true;
|
bool first_reg_is_def = true; // 默认情况下,指令的第一个寄存器操作数是定义 (def)
|
||||||
auto opcode = instr->getOpcode();
|
auto opcode = instr->getOpcode();
|
||||||
|
|
||||||
// --- MODIFICATION START: 细化对指令的 use/def 定义 ---
|
// 1. 特殊指令的 `is_def` 标志调整
|
||||||
|
// 这些指令的第一个寄存器操作数是源操作数 (use),而不是目标操作数 (def)。
|
||||||
// 对于没有定义目标寄存器的指令,预先设置 is_def = false
|
|
||||||
if (opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
|
if (opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
|
||||||
opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
|
opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
|
||||||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
|
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
|
||||||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
|
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
|
||||||
opcode == RVOpcodes::RET || opcode == RVOpcodes::J) {
|
opcode == RVOpcodes::RET || opcode == RVOpcodes::J) {
|
||||||
is_def = false;
|
first_reg_is_def = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// JAL 和 JALR 指令定义 ra (x1)
|
||||||
|
if (opcode == RVOpcodes::JAL || opcode == RVOpcodes::JALR) {
|
||||||
|
// 使用 ra 对应的特殊虚拟寄存器ID
|
||||||
|
def.insert(preg_to_vreg_id_map.at(PhysicalReg::RA));
|
||||||
|
first_reg_is_def = false; // JAL/JALR 的第一个操作数是 ra,已经处理为 def
|
||||||
}
|
}
|
||||||
|
|
||||||
// 对 CALL 指令进行特殊处理
|
// 2. CALL 指令的特殊处理
|
||||||
if (opcode == RVOpcodes::CALL) {
|
if (opcode == RVOpcodes::CALL) {
|
||||||
// CALL 指令的第一个操作数通常是目标函数标签,不是寄存器。
|
// 根据 s1 分支 ISel 定义的协议来解析操作数列表
|
||||||
// 它可能会有一个可选的返回值(def),以及一系列参数(use)。
|
bool first_reg_operand_is_def = true;
|
||||||
// 这里的处理假定 CALL 的机器指令操作数布局是:
|
for (auto& op : instr->getOperands()) {
|
||||||
// [可选: dest_vreg (def)], [函数标签], [可选: arg1_vreg (use)], [可选: arg2_vreg (use)], ...
|
|
||||||
|
|
||||||
// 我们需要一种方法来识别哪些操作数是def,哪些是use。
|
|
||||||
// 一个简单的约定:如果第一个操作数是寄存器,则它是def(返回值)。
|
|
||||||
if (!instr->getOperands().empty() && instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
|
|
||||||
auto reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
|
|
||||||
if (reg_op->isVirtual()) {
|
|
||||||
def.insert(reg_op->getVRegNum());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 遍历所有操作数,非第一个寄存器操作数均视为use
|
|
||||||
bool first_reg_skipped = false;
|
|
||||||
for (const auto& op : instr->getOperands()) {
|
|
||||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||||
if (!first_reg_skipped) {
|
|
||||||
first_reg_skipped = true;
|
|
||||||
continue; // 跳过我们已经作为def处理的返回值
|
|
||||||
}
|
|
||||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||||
if (reg_op->isVirtual()) {
|
if (reg_op->isVirtual()) {
|
||||||
use.insert(reg_op->getVRegNum());
|
// 协议:第一个寄存器操作数是返回值 (def)
|
||||||
|
if (first_reg_operand_is_def) {
|
||||||
|
def.insert(reg_op->getVRegNum());
|
||||||
|
first_reg_operand_is_def = false;
|
||||||
|
} else {
|
||||||
|
// 后续所有寄存器操作数都是参数 (use)
|
||||||
|
use.insert(reg_op->getVRegNum());
|
||||||
|
}
|
||||||
|
} else { // [修复] CALL指令也可能定义物理寄存器(如a0)
|
||||||
|
if (first_reg_operand_is_def) {
|
||||||
|
if (preg_to_vreg_id_map.count(reg_op->getPReg())) {
|
||||||
|
def.insert(preg_to_vreg_id_map.at(reg_op->getPReg()));
|
||||||
|
}
|
||||||
|
first_reg_operand_is_def = false;
|
||||||
|
} else {
|
||||||
|
if (preg_to_vreg_id_map.count(reg_op->getPReg())) {
|
||||||
|
use.insert(preg_to_vreg_id_map.at(reg_op->getPReg()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return; // CALL 指令处理完毕
|
||||||
// **重要**: CALL指令还隐式定义(杀死)了所有调用者保存的寄存器。
|
|
||||||
// 一个完整的实现会在这里将所有caller-saved寄存器标记为def,
|
|
||||||
// 以确保任何跨调用存活的变量都不会被分配到这些寄存器中。
|
|
||||||
// 这个简化的实现暂不处理隐式def,但这是未来优化的关键点。
|
|
||||||
|
|
||||||
return; // CALL 指令处理完毕,直接返回
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- MODIFICATION END ---
|
// 3. 对其他所有指令的通用处理逻辑 [已重构和修复]
|
||||||
|
|
||||||
// 对其他所有指令的通用处理逻辑
|
|
||||||
for (const auto& op : instr->getOperands()) {
|
for (const auto& op : instr->getOperands()) {
|
||||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||||
if (reg_op->isVirtual()) {
|
|
||||||
if (is_def) {
|
if (first_reg_is_def) {
|
||||||
|
// --- 处理定义(Def) ---
|
||||||
|
if (reg_op->isVirtual()) {
|
||||||
def.insert(reg_op->getVRegNum());
|
def.insert(reg_op->getVRegNum());
|
||||||
is_def = false; // 一条指令通常只有一个目标寄存ator
|
} else { // 物理寄存器也可以是 Def
|
||||||
} else {
|
if (preg_to_vreg_id_map.count(reg_op->getPReg())) {
|
||||||
|
def.insert(preg_to_vreg_id_map.at(reg_op->getPReg()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
first_reg_is_def = false; // **关键**:处理完第一个寄存器后,立即更新标志
|
||||||
|
} else {
|
||||||
|
// --- 处理使用(Use) ---
|
||||||
|
if (reg_op->isVirtual()) {
|
||||||
use.insert(reg_op->getVRegNum());
|
use.insert(reg_op->getVRegNum());
|
||||||
|
} else { // 物理寄存器也可以是 Use
|
||||||
|
if (preg_to_vreg_id_map.count(reg_op->getPReg())) {
|
||||||
|
use.insert(preg_to_vreg_id_map.at(reg_op->getPReg()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||||
// 内存操作数 `offset(base)` 中的 base 寄存器是 use
|
// [保持不变] 内存操作数的处理逻辑看起来是正确的
|
||||||
auto mem_op = static_cast<MemOperand*>(op.get());
|
auto mem_op = static_cast<MemOperand*>(op.get());
|
||||||
if (mem_op->getBase()->isVirtual()) {
|
auto base_reg = mem_op->getBase();
|
||||||
use.insert(mem_op->getBase()->getVRegNum());
|
if (base_reg->isVirtual()) {
|
||||||
|
use.insert(base_reg->getVRegNum());
|
||||||
|
} else {
|
||||||
|
PhysicalReg preg = base_reg->getPReg();
|
||||||
|
if (preg_to_vreg_id_map.count(preg)) {
|
||||||
|
use.insert(preg_to_vreg_id_map.at(preg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对于存储内存指令 (SW, SD),要存储的值(第一个操作数)也是 `use`
|
||||||
|
if ((opcode == RVOpcodes::SW || opcode == RVOpcodes::SD) &&
|
||||||
|
!instr->getOperands().empty() &&
|
||||||
|
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
|
||||||
|
auto src_reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
|
||||||
|
if (src_reg_op->isVirtual()) {
|
||||||
|
use.insert(src_reg_op->getVRegNum());
|
||||||
|
} else {
|
||||||
|
if (preg_to_vreg_id_map.count(src_reg_op->getPReg())) {
|
||||||
|
use.insert(preg_to_vreg_id_map.at(src_reg_op->getPReg()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -301,49 +403,109 @@ unsigned RISCv64RegAlloc::getTypeSizeInBytes(Type* type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RISCv64RegAlloc::analyzeLiveness() {
|
void RISCv64RegAlloc::analyzeLiveness() {
|
||||||
|
// === 阶段 1: 预计算每个基本块的 use 和 def 集合 ===
|
||||||
|
// 这样可以避免在主循环中重复计算
|
||||||
|
std::map<MachineBasicBlock*, LiveSet> block_uses;
|
||||||
|
std::map<MachineBasicBlock*, LiveSet> block_defs;
|
||||||
|
for (auto& mbb_ptr : MFunc->getBlocks()) {
|
||||||
|
MachineBasicBlock* mbb = mbb_ptr.get();
|
||||||
|
LiveSet uses, defs;
|
||||||
|
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||||
|
LiveSet instr_use, instr_def;
|
||||||
|
getInstrUseDef(instr_ptr.get(), instr_use, instr_def);
|
||||||
|
// use[B] = use[B] U (instr_use - def[B])
|
||||||
|
for (unsigned u : instr_use) {
|
||||||
|
if (defs.find(u) == defs.end()) {
|
||||||
|
uses.insert(u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// def[B] = def[B] U instr_def
|
||||||
|
defs.insert(instr_def.begin(), instr_def.end());
|
||||||
|
}
|
||||||
|
block_uses[mbb] = uses;
|
||||||
|
block_defs[mbb] = defs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// === 阶段 2: 在“块”粒度上进行迭代数据流分析,直到收敛 ===
|
||||||
|
std::map<MachineBasicBlock*, LiveSet> block_live_in;
|
||||||
|
std::map<MachineBasicBlock*, LiveSet> block_live_out;
|
||||||
bool changed = true;
|
bool changed = true;
|
||||||
while (changed) {
|
while (changed) {
|
||||||
changed = false;
|
changed = false;
|
||||||
|
// 以逆后序遍历基本块,可以加速收敛,但简单的逆序对于大多数情况也有效
|
||||||
for (auto it = MFunc->getBlocks().rbegin(); it != MFunc->getBlocks().rend(); ++it) {
|
for (auto it = MFunc->getBlocks().rbegin(); it != MFunc->getBlocks().rend(); ++it) {
|
||||||
auto& mbb = *it;
|
auto& mbb = *it;
|
||||||
LiveSet live_out;
|
|
||||||
|
// 2.1 计算 live_out[B] = U_{S in succ(B)} live_in[S]
|
||||||
|
LiveSet new_live_out;
|
||||||
for (auto succ : mbb->successors) {
|
for (auto succ : mbb->successors) {
|
||||||
if (!succ->getInstructions().empty()) {
|
new_live_out.insert(block_live_in[succ].begin(), block_live_in[succ].end());
|
||||||
auto first_instr = succ->getInstructions().front().get();
|
|
||||||
if (live_in_map.count(first_instr)) {
|
|
||||||
live_out.insert(live_in_map.at(first_instr).begin(), live_in_map.at(first_instr).end());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto instr_it = mbb->getInstructions().rbegin(); instr_it != mbb->getInstructions().rend(); ++instr_it) {
|
// 2.2 计算 live_in[B] = use[B] U (live_out[B] - def[B])
|
||||||
MachineInstr* instr = instr_it->get();
|
LiveSet live_out_minus_def = new_live_out;
|
||||||
LiveSet old_live_in = live_in_map[instr];
|
for (unsigned d : block_defs[mbb.get()]) {
|
||||||
live_out_map[instr] = live_out;
|
live_out_minus_def.erase(d);
|
||||||
|
|
||||||
LiveSet use, def;
|
|
||||||
getInstrUseDef(instr, use, def);
|
|
||||||
|
|
||||||
LiveSet live_in = use;
|
|
||||||
LiveSet diff = live_out;
|
|
||||||
for (auto vreg : def) {
|
|
||||||
diff.erase(vreg);
|
|
||||||
}
|
|
||||||
live_in.insert(diff.begin(), diff.end());
|
|
||||||
live_in_map[instr] = live_in;
|
|
||||||
|
|
||||||
live_out = live_in;
|
|
||||||
|
|
||||||
if (live_in_map[instr] != old_live_in) {
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
LiveSet new_live_in = block_uses[mbb.get()];
|
||||||
|
new_live_in.insert(live_out_minus_def.begin(), live_out_minus_def.end());
|
||||||
|
|
||||||
|
// 2.3 检查 live_in 和 live_out 是否变化,以判断是否达到不动点
|
||||||
|
if (block_live_out[mbb.get()] != new_live_out) {
|
||||||
|
changed = true;
|
||||||
|
block_live_out[mbb.get()] = new_live_out;
|
||||||
|
}
|
||||||
|
if (block_live_in[mbb.get()] != new_live_in) {
|
||||||
|
changed = true;
|
||||||
|
block_live_in[mbb.get()] = new_live_in;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// === 阶段 3: 进行一次指令粒度的遍历,填充最终的 live_in_map 和 live_out_map ===
|
||||||
|
// 此时块级别的活跃信息已经稳定,我们只需遍历一次即可
|
||||||
|
for (auto& mbb_ptr : MFunc->getBlocks()) {
|
||||||
|
MachineBasicBlock* mbb = mbb_ptr.get();
|
||||||
|
LiveSet live_out = block_live_out[mbb]; // 从已收敛的块级 live_out 开始
|
||||||
|
|
||||||
|
for (auto instr_it = mbb->getInstructions().rbegin(); instr_it != mbb->getInstructions().rend(); ++instr_it) {
|
||||||
|
MachineInstr* instr = instr_it->get();
|
||||||
|
live_out_map[instr] = live_out;
|
||||||
|
|
||||||
|
LiveSet use, def;
|
||||||
|
getInstrUseDef(instr, use, def);
|
||||||
|
|
||||||
|
LiveSet live_in = use;
|
||||||
|
LiveSet diff = live_out;
|
||||||
|
for (auto vreg : def) {
|
||||||
|
diff.erase(vreg);
|
||||||
|
}
|
||||||
|
live_in.insert(diff.begin(), diff.end());
|
||||||
|
live_in_map[instr] = live_in;
|
||||||
|
|
||||||
|
// 更新 live_out,为块内的上一条指令做准备
|
||||||
|
live_out = live_in;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 辅助函数,用于清晰地打印寄存器集合。可以放在 .cpp 文件的顶部。
|
||||||
|
void RISCv64RegAlloc::printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os) {
|
||||||
|
os << " " << name << ": { ";
|
||||||
|
for (unsigned vreg : s) {
|
||||||
|
// 为了可读性,将物理寄存器对应的特殊ID进行转换
|
||||||
|
if (vreg >= static_cast<unsigned>(sysy::PhysicalReg::PHYS_REG_START_ID)) {
|
||||||
|
os << "preg(" << (vreg - static_cast<unsigned>(sysy::PhysicalReg::PHYS_REG_START_ID)) << ") ";
|
||||||
|
} else {
|
||||||
|
os << "%vreg" << vreg << " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os << "}\n";
|
||||||
|
}
|
||||||
|
|
||||||
void RISCv64RegAlloc::buildInterferenceGraph() {
|
void RISCv64RegAlloc::buildInterferenceGraph() {
|
||||||
std::set<unsigned> all_vregs;
|
std::set<unsigned> all_vregs;
|
||||||
|
// 收集所有虚拟寄存器和物理寄存器在干扰图中的节点ID
|
||||||
for (auto& mbb : MFunc->getBlocks()) {
|
for (auto& mbb : MFunc->getBlocks()) {
|
||||||
for(auto& instr : mbb->getInstructions()) {
|
for(auto& instr : mbb->getInstructions()) {
|
||||||
LiveSet use, def;
|
LiveSet use, def;
|
||||||
@@ -352,23 +514,100 @@ void RISCv64RegAlloc::buildInterferenceGraph() {
|
|||||||
for(auto d : def) all_vregs.insert(d);
|
for(auto d : def) all_vregs.insert(d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 添加所有物理寄存器对应的特殊虚拟寄存器ID到all_vregs,作为干扰图节点
|
||||||
|
for (auto preg : allocable_int_regs) {
|
||||||
|
all_vregs.insert(preg_to_vreg_id_map.at(preg));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化干扰图邻接表
|
||||||
for (auto vreg : all_vregs) { interference_graph[vreg] = {}; }
|
for (auto vreg : all_vregs) { interference_graph[vreg] = {}; }
|
||||||
|
|
||||||
for (auto& mbb : MFunc->getBlocks()) {
|
// 创建一个临时的AsmPrinter用于打印指令,方便调试
|
||||||
for (auto& instr : mbb->getInstructions()) {
|
RISCv64AsmPrinter temp_printer(MFunc);
|
||||||
LiveSet def, use;
|
temp_printer.setStream(std::cerr);
|
||||||
getInstrUseDef(instr.get(), use, def);
|
|
||||||
const LiveSet& live_out = live_out_map.at(instr.get());
|
|
||||||
|
|
||||||
|
for (auto& mbb : MFunc->getBlocks()) {
|
||||||
|
if (DEEPDEBUG) std::cerr << "--- Building Graph for Basic Block: " << mbb->getName() << " ---\n";
|
||||||
|
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||||
|
MachineInstr* instr = instr_ptr.get();
|
||||||
|
if (DEEPDEBUG) {
|
||||||
|
// 打印当前正在处理的指令
|
||||||
|
std::cerr << " Instr: ";
|
||||||
|
temp_printer.printInstruction(instr, true); // 使用 true 来打印虚拟寄存器
|
||||||
|
}
|
||||||
|
|
||||||
|
LiveSet def, use;
|
||||||
|
getInstrUseDef(instr, use, def);
|
||||||
|
const LiveSet& live_out = live_out_map.at(instr);
|
||||||
|
|
||||||
|
// [新增调试逻辑] 打印所有相关的寄存器集合
|
||||||
|
if (DEEPDEBUG) {
|
||||||
|
printLiveSet(use, "Use ", std::cerr);
|
||||||
|
printLiveSet(def, "Def ", std::cerr);
|
||||||
|
printLiveSet(live_out, "Live_Out", std::cerr); // 这是我们最关心的信息
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标准干扰图构建:def 与 live_out 中的其他变量干扰
|
||||||
for (unsigned d : def) {
|
for (unsigned d : def) {
|
||||||
for (unsigned l : live_out) {
|
for (unsigned l : live_out) {
|
||||||
if (d != l) {
|
if (d != l) {
|
||||||
|
// [新增调试逻辑] 打印添加的干扰边及其原因
|
||||||
|
if (DEEPDEBUG && interference_graph[d].find(l) == interference_graph[d].end()) {
|
||||||
|
std::cerr << " Edge (Def-LiveOut): %vreg" << d << " <-> %vreg" << l << "\n";
|
||||||
|
}
|
||||||
interference_graph[d].insert(l);
|
interference_graph[d].insert(l);
|
||||||
interference_graph[l].insert(d);
|
interference_graph[l].insert(d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 在非move指令中,def 与 use 互相干扰
|
||||||
|
if (instr->getOpcode() != RVOpcodes::MV) {
|
||||||
|
for (unsigned d : def) {
|
||||||
|
for (unsigned u : use) {
|
||||||
|
if (d != u) {
|
||||||
|
// [新增调试逻辑] 打印添加的干扰边及其原因
|
||||||
|
if (DEEPDEBUG && interference_graph[d].find(u) == interference_graph[d].end()) {
|
||||||
|
std::cerr << " Edge (Def-Use) : %vreg" << d << " <-> %vreg" << u << "\n";
|
||||||
|
}
|
||||||
|
interference_graph[d].insert(u);
|
||||||
|
interference_graph[u].insert(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// *** 处理 CALL 指令的隐式 def ***
|
||||||
|
if (instr->getOpcode() == RVOpcodes::CALL) {
|
||||||
|
// 你的原始CALL调试信息
|
||||||
|
if (DEEPDEBUG) {
|
||||||
|
std::string live_out_str;
|
||||||
|
for (unsigned vreg : live_out) {
|
||||||
|
live_out_str += "%vreg" + std::to_string(vreg) + " ";
|
||||||
|
}
|
||||||
|
std::cerr << "[DEEPDEBUG] buildInterferenceGraph: CALL instruction found. Live out set is: {"
|
||||||
|
<< live_out_str << "}" << std::endl;
|
||||||
|
}
|
||||||
|
// CALL 指令会定义(杀死)所有调用者保存的寄存器。
|
||||||
|
// 因此,所有调用者保存的物理寄存器都与 CALL 指令的 live_out 中的所有变量冲突。
|
||||||
|
const std::vector<PhysicalReg>& caller_saved_regs = getCallerSavedIntRegs();
|
||||||
|
for (PhysicalReg cs_reg : caller_saved_regs) {
|
||||||
|
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg); // 获取物理寄存器对应的特殊vreg ID
|
||||||
|
|
||||||
|
// 将这个物理寄存器节点与 CALL 指令的 live_out 中的所有虚拟寄存器添加干扰边。
|
||||||
|
for (unsigned live_vreg_out : live_out) {
|
||||||
|
if (cs_vreg_id != live_vreg_out) { // 避免自己和自己干扰
|
||||||
|
// [新增调试逻辑] 打印添加的干扰边及其原因
|
||||||
|
if (DEEPDEBUG && interference_graph[cs_vreg_id].find(live_vreg_out) == interference_graph[cs_vreg_id].end()) {
|
||||||
|
std::cerr << " Edge (CALL) : preg(" << static_cast<int>(cs_reg) << ") <-> %vreg" << live_vreg_out << "\n";
|
||||||
|
}
|
||||||
|
interference_graph[cs_vreg_id].insert(live_vreg_out);
|
||||||
|
interference_graph[live_vreg_out].insert(cs_vreg_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (DEEPDEBUG) std::cerr << " ----------------\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -376,7 +615,8 @@ void RISCv64RegAlloc::buildInterferenceGraph() {
|
|||||||
void RISCv64RegAlloc::colorGraph() {
|
void RISCv64RegAlloc::colorGraph() {
|
||||||
std::vector<unsigned> sorted_vregs;
|
std::vector<unsigned> sorted_vregs;
|
||||||
for (auto const& [vreg, neighbors] : interference_graph) {
|
for (auto const& [vreg, neighbors] : interference_graph) {
|
||||||
if (color_map.find(vreg) == color_map.end()) {
|
// 只为未预着色的虚拟寄存器排序和着色
|
||||||
|
if (color_map.find(vreg) == color_map.end() && vreg < static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID)) {
|
||||||
sorted_vregs.push_back(vreg);
|
sorted_vregs.push_back(vreg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -389,9 +629,18 @@ void RISCv64RegAlloc::colorGraph() {
|
|||||||
// 着色
|
// 着色
|
||||||
for (unsigned vreg : sorted_vregs) {
|
for (unsigned vreg : sorted_vregs) {
|
||||||
std::set<PhysicalReg> used_colors;
|
std::set<PhysicalReg> used_colors;
|
||||||
for (unsigned neighbor : interference_graph.at(vreg)) {
|
for (unsigned neighbor_id : interference_graph.at(vreg)) {
|
||||||
if (color_map.count(neighbor)) {
|
// --- 关键改进 (来自 rec 分支) ---
|
||||||
used_colors.insert(color_map.at(neighbor));
|
|
||||||
|
// 情况 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,529 +0,0 @@
|
|||||||
#include "SysYIRAnalyser.h"
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
|
|
||||||
namespace sysy {
|
|
||||||
|
|
||||||
|
|
||||||
void ControlFlowAnalysis::init() {
|
|
||||||
// 初始化分析器
|
|
||||||
auto &functions = pModule->getFunctions();
|
|
||||||
for (const auto &function : functions) {
|
|
||||||
auto func = function.second.get();
|
|
||||||
auto basicBlocks = func->getBasicBlocks();
|
|
||||||
for (auto &basicBlock : basicBlocks) {
|
|
||||||
blockAnalysisInfo[basicBlock.get()] = new BlockAnalysisInfo();
|
|
||||||
blockAnalysisInfo[basicBlock.get()]->clear();
|
|
||||||
}
|
|
||||||
functionAnalysisInfo[func] = new FunctionAnalysisInfo();
|
|
||||||
functionAnalysisInfo[func]->clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ControlFlowAnalysis::runControlFlowAnalysis() {
|
|
||||||
// 运行控制流分析
|
|
||||||
clear(); // 清空之前的分析结果
|
|
||||||
init(); // 初始化分析器
|
|
||||||
computeDomNode();
|
|
||||||
computeDomTree();
|
|
||||||
computeDomFrontierAllBlk();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ControlFlowAnalysis::intersectOP4Dom(std::unordered_set<BasicBlock *> &dom, const std::unordered_set<BasicBlock *> &other) {
|
|
||||||
// 计算交集
|
|
||||||
for (auto it = dom.begin(); it != dom.end();) {
|
|
||||||
if (other.find(*it) == other.end()) {
|
|
||||||
// 如果other中没有这个基本块,则从dom中删除
|
|
||||||
it = dom.erase(it);
|
|
||||||
} else {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ControlFlowAnalysis::findCommonDominator(BasicBlock *a, BasicBlock *b) -> BasicBlock * {
|
|
||||||
// 查找两个基本块的共同支配结点
|
|
||||||
while (a != b) {
|
|
||||||
BlockAnalysisInfo* infoA = blockAnalysisInfo[a];
|
|
||||||
BlockAnalysisInfo* infoB = blockAnalysisInfo[b];
|
|
||||||
// 如果深度不同,则向上移动到直接支配结点
|
|
||||||
// TODO:空间换时间倍增优化,优先级较低
|
|
||||||
while (infoA->getDomDepth() > infoB->getDomDepth()) {
|
|
||||||
a = const_cast<BasicBlock*>(infoA->getIdom());
|
|
||||||
infoA = blockAnalysisInfo[a];
|
|
||||||
}
|
|
||||||
while (infoB->getDomDepth() > infoA->getDomDepth()) {
|
|
||||||
b = const_cast<BasicBlock*>(infoB->getIdom());
|
|
||||||
infoB = blockAnalysisInfo[b];
|
|
||||||
}
|
|
||||||
if (a == b) break;
|
|
||||||
a = const_cast<BasicBlock*>(infoA->getIdom());
|
|
||||||
b = const_cast<BasicBlock*>(infoB->getIdom());
|
|
||||||
}
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ControlFlowAnalysis::computeDomNode(){
|
|
||||||
auto &functions = pModule->getFunctions();
|
|
||||||
// 分析每个函数内的基本块
|
|
||||||
for (const auto &function : functions) {
|
|
||||||
auto func = function.second.get();
|
|
||||||
auto basicBlocks = func->getBasicBlocks();
|
|
||||||
std::unordered_set<BasicBlock *> domSetTmp;
|
|
||||||
// 一开始把domSetTmp置为所有block
|
|
||||||
auto entry_block = func->getEntryBlock();
|
|
||||||
entry_block->setName("Entry");
|
|
||||||
blockAnalysisInfo[entry_block]->addDominants(entry_block);
|
|
||||||
for (auto &basicBlock : basicBlocks) {
|
|
||||||
domSetTmp.emplace(basicBlock.get());
|
|
||||||
}
|
|
||||||
// 初始化
|
|
||||||
for (auto &basicBlock : basicBlocks) {
|
|
||||||
if (basicBlock.get() != entry_block) {
|
|
||||||
blockAnalysisInfo[basicBlock.get()]->setDominants(domSetTmp);
|
|
||||||
// 先把所有block的必经结点都设为N
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 支配节点计算公式
|
|
||||||
//DOM[B]={B}∪ {⋂P∈pred(B) DOM[P]}
|
|
||||||
// 其中pred(B)是B的所有前驱结点
|
|
||||||
// 迭代计算支配结点,直到不再变化
|
|
||||||
// 这里使用迭代法,直到支配结点不再变化
|
|
||||||
// TODO:Lengauer-Tarjan 算法可以更高效地计算支配结点
|
|
||||||
// 或者按照CFG拓扑序遍历效率更高
|
|
||||||
bool changed = true;
|
|
||||||
while (changed) {
|
|
||||||
changed = false;
|
|
||||||
// 循环非start结点
|
|
||||||
for (auto &basicBlock : basicBlocks) {
|
|
||||||
if (basicBlock.get() != entry_block) {
|
|
||||||
auto olddom =
|
|
||||||
blockAnalysisInfo[basicBlock.get()]->getDominants();
|
|
||||||
|
|
||||||
std::unordered_set<BasicBlock *> dom =
|
|
||||||
blockAnalysisInfo[basicBlock->getPredecessors().front()]->getDominants();
|
|
||||||
|
|
||||||
// 对于每个基本块,计算其支配结点
|
|
||||||
// 取其前驱结点的支配结点的交集和自己
|
|
||||||
for (auto pred : basicBlock->getPredecessors()) {
|
|
||||||
intersectOP4Dom(dom, blockAnalysisInfo[pred]->getDominants());
|
|
||||||
}
|
|
||||||
dom.emplace(basicBlock.get());
|
|
||||||
blockAnalysisInfo[basicBlock.get()]->setDominants(dom);
|
|
||||||
|
|
||||||
if (dom != olddom) {
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: SEMI-NCA算法改进
|
|
||||||
void ControlFlowAnalysis::computeDomTree() {
|
|
||||||
// 构造支配树
|
|
||||||
auto &functions = pModule->getFunctions();
|
|
||||||
for (const auto &function : functions) {
|
|
||||||
auto func = function.second.get();
|
|
||||||
auto basicBlocks = func->getBasicBlocks();
|
|
||||||
auto entry_block = func->getEntryBlock();
|
|
||||||
|
|
||||||
blockAnalysisInfo[entry_block]->setIdom(entry_block);
|
|
||||||
blockAnalysisInfo[entry_block]->setDomDepth(0); // 入口块深度为0
|
|
||||||
|
|
||||||
bool changed = true;
|
|
||||||
while (changed) {
|
|
||||||
changed = false;
|
|
||||||
|
|
||||||
for (auto &basicBlock : basicBlocks) {
|
|
||||||
if (basicBlock.get() == entry_block) continue;
|
|
||||||
|
|
||||||
BasicBlock *new_idom = nullptr;
|
|
||||||
for (auto pred : basicBlock->getPredecessors()) {
|
|
||||||
// 跳过未处理的前驱
|
|
||||||
if (blockAnalysisInfo[pred]->getIdom() == nullptr) continue;
|
|
||||||
// new_idom = (new_idom == nullptr) ? pred : findCommonDominator(new_idom, pred);
|
|
||||||
if (new_idom == nullptr)
|
|
||||||
new_idom = pred;
|
|
||||||
else
|
|
||||||
new_idom = findCommonDominator(new_idom, pred);
|
|
||||||
}
|
|
||||||
// 更新直接支配节点
|
|
||||||
if (new_idom && new_idom != blockAnalysisInfo[basicBlock.get()]->getIdom()) {
|
|
||||||
// 移除旧的支配关系
|
|
||||||
if (blockAnalysisInfo[basicBlock.get()]->getIdom()) {
|
|
||||||
blockAnalysisInfo[const_cast<BasicBlock*>(blockAnalysisInfo[basicBlock.get()]->getIdom())]->removeSdoms(basicBlock.get());
|
|
||||||
}
|
|
||||||
// 设置新的支配关系
|
|
||||||
|
|
||||||
// std::cout << "Block: " << basicBlock->getName()
|
|
||||||
// << " New Idom: " << new_idom->getName() << std::endl;
|
|
||||||
|
|
||||||
blockAnalysisInfo[basicBlock.get()]->setIdom(new_idom);
|
|
||||||
blockAnalysisInfo[new_idom]->addSdoms(basicBlock.get());
|
|
||||||
// 更新深度 = 直接支配节点深度 + 1
|
|
||||||
blockAnalysisInfo[basicBlock.get()]->setDomDepth(
|
|
||||||
blockAnalysisInfo[new_idom]->getDomDepth() + 1);
|
|
||||||
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// for (auto &basicBlock : basicBlocks) {
|
|
||||||
// if (basicBlock.get() != func->getEntryBlock()) {
|
|
||||||
// auto dominats =
|
|
||||||
// blockAnalysisInfo[basicBlock.get()]->getDominants();
|
|
||||||
// bool found = false;
|
|
||||||
// // 从前驱结点开始寻找直接支配结点
|
|
||||||
// std::queue<BasicBlock *> q;
|
|
||||||
// for (auto pred : basicBlock->getPredecessors()) {
|
|
||||||
// q.push(pred);
|
|
||||||
// }
|
|
||||||
// // BFS遍历前驱结点,直到找到直接支配结点
|
|
||||||
// while (!found && !q.empty()) {
|
|
||||||
// auto curr = q.front();
|
|
||||||
// q.pop();
|
|
||||||
// if (curr == basicBlock.get())
|
|
||||||
// continue;
|
|
||||||
// if (dominats.count(curr) != 0U) {
|
|
||||||
// blockAnalysisInfo[basicBlock.get()]->setIdom(curr);
|
|
||||||
// blockAnalysisInfo[curr]->addSdoms(basicBlock.get());
|
|
||||||
// found = true;
|
|
||||||
// } else {
|
|
||||||
// for (auto pred : curr->getPredecessors()) {
|
|
||||||
// q.push(pred);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
// std::unordered_set<BasicBlock *> ControlFlowAnalysis::computeDomFrontier(BasicBlock *block) {
|
|
||||||
// std::unordered_set<BasicBlock *> ret_list;
|
|
||||||
// // 计算 localDF
|
|
||||||
// for (auto local_successor : block->getSuccessors()) {
|
|
||||||
// if (local_successor->getIdom() != block) {
|
|
||||||
// ret_list.emplace(local_successor);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// // 计算 upDF
|
|
||||||
// for (auto up_successor : block->getSdoms()) {
|
|
||||||
// auto childrenDF = computeDF(up_successor);
|
|
||||||
// for (auto w : childrenDF) {
|
|
||||||
// if (block != w->getIdom() || block == w) {
|
|
||||||
// ret_list.emplace(w);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return ret_list;
|
|
||||||
// }
|
|
||||||
|
|
||||||
void ControlFlowAnalysis::computeDomFrontierAllBlk() {
|
|
||||||
auto &functions = pModule->getFunctions();
|
|
||||||
for (const auto &function : functions) {
|
|
||||||
auto func = function.second.get();
|
|
||||||
auto basicBlocks = func->getBasicBlocks();
|
|
||||||
|
|
||||||
// 按支配树深度排序(从深到浅)
|
|
||||||
std::vector<BasicBlock *> orderedBlocks;
|
|
||||||
for (auto &bb : basicBlocks) {
|
|
||||||
orderedBlocks.push_back(bb.get());
|
|
||||||
}
|
|
||||||
std::sort(orderedBlocks.begin(), orderedBlocks.end(),
|
|
||||||
[this](BasicBlock *a, BasicBlock *b) {
|
|
||||||
return blockAnalysisInfo[a]->getDomDepth() > blockAnalysisInfo[b]->getDomDepth();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 计算支配边界
|
|
||||||
for (auto block : orderedBlocks) {
|
|
||||||
std::unordered_set<BasicBlock *> df;
|
|
||||||
|
|
||||||
// Local DF: 直接后继中不被当前块支配的
|
|
||||||
for (auto succ : block->getSuccessors()) {
|
|
||||||
// 当前块不支配该后继(即不是其直接支配节点)
|
|
||||||
if (blockAnalysisInfo[succ]->getIdom() != block) {
|
|
||||||
df.insert(succ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Up DF: 从支配子树中继承
|
|
||||||
for (auto child : blockAnalysisInfo[block]->getSdoms()) {
|
|
||||||
for (auto w : blockAnalysisInfo[child]->getDomFrontiers()) {
|
|
||||||
// 如果w不被当前块支配
|
|
||||||
if (block != blockAnalysisInfo[w]->getIdom()) {
|
|
||||||
df.insert(w);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
blockAnalysisInfo[block]->setDomFrontiers(df);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==========================
|
|
||||||
// dataflow analysis utils
|
|
||||||
// ==========================
|
|
||||||
|
|
||||||
// 先引用学长的代码
|
|
||||||
// TODO: Worklist 增加逆后序遍历机制
|
|
||||||
void DataFlowAnalysisUtils::forwardAnalyze(Module *pModule){
|
|
||||||
std::map<DataFlowAnalysis *, bool> workAnalysis;
|
|
||||||
for (auto &dataflow : forwardAnalysisList) {
|
|
||||||
dataflow->init(pModule);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &function : pModule->getFunctions()) {
|
|
||||||
for (auto &dataflow : forwardAnalysisList) {
|
|
||||||
workAnalysis.emplace(dataflow, false);
|
|
||||||
}
|
|
||||||
while (!workAnalysis.empty()) {
|
|
||||||
for (const auto &block : function.second->getBasicBlocks()) {
|
|
||||||
for (auto &elem : workAnalysis) {
|
|
||||||
if (elem.first->analyze(pModule, block.get())) {
|
|
||||||
elem.second = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::map<DataFlowAnalysis *, bool> tmp;
|
|
||||||
std::remove_copy_if(workAnalysis.begin(), workAnalysis.end(), std::inserter(tmp, tmp.end()),
|
|
||||||
[](const std::pair<DataFlowAnalysis *, bool> &elem) -> bool { return !elem.second; });
|
|
||||||
workAnalysis.swap(tmp);
|
|
||||||
|
|
||||||
for (auto &elem : workAnalysis) {
|
|
||||||
elem.second = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataFlowAnalysisUtils::backwardAnalyze(Module *pModule) {
|
|
||||||
std::map<DataFlowAnalysis *, bool> workAnalysis;
|
|
||||||
for (auto &dataflow : backwardAnalysisList) {
|
|
||||||
dataflow->init(pModule);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &function : pModule->getFunctions()) {
|
|
||||||
for (auto &dataflow : backwardAnalysisList) {
|
|
||||||
workAnalysis.emplace(dataflow, false);
|
|
||||||
}
|
|
||||||
while (!workAnalysis.empty()) {
|
|
||||||
for (const auto &block : function.second->getBasicBlocks()) {
|
|
||||||
for (auto &elem : workAnalysis) {
|
|
||||||
if (elem.first->analyze(pModule, block.get())) {
|
|
||||||
elem.second = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::map<DataFlowAnalysis *, bool> tmp;
|
|
||||||
std::remove_copy_if(workAnalysis.begin(), workAnalysis.end(), std::inserter(tmp, tmp.end()),
|
|
||||||
[](const std::pair<DataFlowAnalysis *, bool> &elem) -> bool { return !elem.second; });
|
|
||||||
workAnalysis.swap(tmp);
|
|
||||||
|
|
||||||
for (auto &elem : workAnalysis) {
|
|
||||||
elem.second = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::set<User *> ActiveVarAnalysis::getUsedSet(Instruction *inst) {
|
|
||||||
using Kind = Instruction::Kind;
|
|
||||||
std::vector<User *> operands;
|
|
||||||
for (const auto &operand : inst->getOperands()) {
|
|
||||||
operands.emplace_back(dynamic_cast<User *>(operand->getValue()));
|
|
||||||
}
|
|
||||||
std::set<User *> result;
|
|
||||||
switch (inst->getKind()) {
|
|
||||||
// phi op
|
|
||||||
case Kind::kPhi:
|
|
||||||
case Kind::kCall:
|
|
||||||
result.insert(std::next(operands.begin()), operands.end());
|
|
||||||
break;
|
|
||||||
case Kind::kCondBr:
|
|
||||||
result.insert(operands[0]);
|
|
||||||
break;
|
|
||||||
case Kind::kBr:
|
|
||||||
case Kind::kAlloca:
|
|
||||||
break;
|
|
||||||
// mem op
|
|
||||||
case Kind::kStore:
|
|
||||||
// StoreInst 的第一个操作数是被存储的值,第二个操作数是存储的变量
|
|
||||||
// 后续的是可能的数组维度
|
|
||||||
result.insert(operands[0]);
|
|
||||||
result.insert(operands.begin() + 2, operands.end());
|
|
||||||
break;
|
|
||||||
case Kind::kLoad:
|
|
||||||
case Kind::kLa: {
|
|
||||||
auto variable = dynamic_cast<AllocaInst *>(operands[0]);
|
|
||||||
auto global = dynamic_cast<GlobalValue *>(operands[0]);
|
|
||||||
auto constArray = dynamic_cast<ConstantVariable *>(operands[0]);
|
|
||||||
if ((variable != nullptr && variable->getNumDims() == 0) || (global != nullptr && global->getNumDims() == 0) ||
|
|
||||||
(constArray != nullptr && constArray->getNumDims() == 0)) {
|
|
||||||
result.insert(operands[0]);
|
|
||||||
}
|
|
||||||
result.insert(std::next(operands.begin()), operands.end());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Kind::kGetSubArray: {
|
|
||||||
for (unsigned i = 2; i < operands.size(); i++) {
|
|
||||||
// 数组的维度信息
|
|
||||||
result.insert(operands[i]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Kind::kMemset: {
|
|
||||||
result.insert(std::next(operands.begin()), operands.end());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Kind::kInvalid:
|
|
||||||
// Binary
|
|
||||||
case Kind::kAdd:
|
|
||||||
case Kind::kSub:
|
|
||||||
case Kind::kMul:
|
|
||||||
case Kind::kDiv:
|
|
||||||
case Kind::kRem:
|
|
||||||
case Kind::kICmpEQ:
|
|
||||||
case Kind::kICmpNE:
|
|
||||||
case Kind::kICmpLT:
|
|
||||||
case Kind::kICmpLE:
|
|
||||||
case Kind::kICmpGT:
|
|
||||||
case Kind::kICmpGE:
|
|
||||||
case Kind::kFAdd:
|
|
||||||
case Kind::kFSub:
|
|
||||||
case Kind::kFMul:
|
|
||||||
case Kind::kFDiv:
|
|
||||||
case Kind::kFCmpEQ:
|
|
||||||
case Kind::kFCmpNE:
|
|
||||||
case Kind::kFCmpLT:
|
|
||||||
case Kind::kFCmpLE:
|
|
||||||
case Kind::kFCmpGT:
|
|
||||||
case Kind::kFCmpGE:
|
|
||||||
case Kind::kAnd:
|
|
||||||
case Kind::kOr:
|
|
||||||
// Unary
|
|
||||||
case Kind::kNeg:
|
|
||||||
case Kind::kNot:
|
|
||||||
case Kind::kFNot:
|
|
||||||
case Kind::kFNeg:
|
|
||||||
case Kind::kFtoI:
|
|
||||||
case Kind::kItoF:
|
|
||||||
// terminator
|
|
||||||
case Kind::kReturn:
|
|
||||||
result.insert(operands.begin(), operands.end());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
result.erase(nullptr);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
User * ActiveVarAnalysis::getDefine(Instruction *inst) {
|
|
||||||
User *result = nullptr;
|
|
||||||
if (inst->isStore()) {
|
|
||||||
StoreInst* store = dynamic_cast<StoreInst *>(inst);
|
|
||||||
auto operand = store->getPointer();
|
|
||||||
AllocaInst* variable = dynamic_cast<AllocaInst *>(operand);
|
|
||||||
GlobalValue* global = dynamic_cast<GlobalValue *>(operand);
|
|
||||||
if ((variable != nullptr && variable->getNumDims() != 0) || (global != nullptr && global->getNumDims() != 0)) {
|
|
||||||
// 如果是数组变量或者全局变量,则不返回定义
|
|
||||||
// TODO:兼容数组变量
|
|
||||||
result = nullptr;
|
|
||||||
} else {
|
|
||||||
result = dynamic_cast<User *>(operand);
|
|
||||||
}
|
|
||||||
} else if (inst->isPhi()) {
|
|
||||||
result = dynamic_cast<User *>(inst->getOperand(0));
|
|
||||||
} else if (inst->isBinary() || inst->isUnary() || inst->isCall() ||
|
|
||||||
inst->isLoad() || inst->isLa()) {
|
|
||||||
result = dynamic_cast<User *>(inst);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActiveVarAnalysis::init(Module *pModule) {
|
|
||||||
for (const auto &function : pModule->getFunctions()) {
|
|
||||||
for (const auto &block : function.second->getBasicBlocks()) {
|
|
||||||
activeTable.emplace(block.get(), std::vector<std::set<User *>>{});
|
|
||||||
for (unsigned i = 0; i < block->getNumInstructions() + 1; i++)
|
|
||||||
activeTable.at(block.get()).emplace_back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 活跃变量分析公式 每个块内的分析动作供分析器调用
|
|
||||||
bool ActiveVarAnalysis::analyze(Module *pModule, BasicBlock *block) {
|
|
||||||
bool changed = false; // 标记数据流结果是否有变化
|
|
||||||
std::set<User *> activeSet{}; // 当前计算的活跃变量集合
|
|
||||||
|
|
||||||
// 步骤1: 计算基本块出口的活跃变量集 (OUT[B])
|
|
||||||
// 公式: OUT[B] = ∪_{S ∈ succ(B)} IN[S]
|
|
||||||
for (const auto &succ : block->getSuccessors()) {
|
|
||||||
// 获取后继块入口的活跃变量集 (IN[S])
|
|
||||||
auto succActiveSet = activeTable.at(succ).front();
|
|
||||||
// 合并所有后继块的入口活跃变量
|
|
||||||
activeSet.insert(succActiveSet.begin(), succActiveSet.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 步骤2: 处理基本块出口处的活跃变量集
|
|
||||||
const auto &instructions = block->getInstructions();
|
|
||||||
const auto numInstructions = instructions.size();
|
|
||||||
|
|
||||||
// 获取旧的出口活跃变量集 (block出口对应索引numInstructions)
|
|
||||||
const auto &oldEndActiveSet = activeTable.at(block)[numInstructions];
|
|
||||||
|
|
||||||
// 检查出口活跃变量集是否有变化
|
|
||||||
if (!std::equal(activeSet.begin(), activeSet.end(),
|
|
||||||
oldEndActiveSet.begin(), oldEndActiveSet.end()))
|
|
||||||
{
|
|
||||||
changed = true; // 标记变化
|
|
||||||
activeTable.at(block)[numInstructions] = activeSet; // 更新出口活跃变量集
|
|
||||||
}
|
|
||||||
|
|
||||||
// 步骤3: 逆序遍历基本块中的指令
|
|
||||||
// 从最后一条指令开始向前计算每个程序点的活跃变量
|
|
||||||
auto instructionIter = instructions.end();
|
|
||||||
instructionIter--; // 指向最后一条指令
|
|
||||||
|
|
||||||
// 从出口向入口遍历 (索引从numInstructions递减到1)
|
|
||||||
for (unsigned i = numInstructions; i > 0; i--) {
|
|
||||||
auto inst = instructionIter->get(); // 当前指令
|
|
||||||
|
|
||||||
auto used = getUsedSet(inst);
|
|
||||||
User *defined = getDefine(inst);
|
|
||||||
|
|
||||||
// 步骤3.3: 计算指令入口的活跃变量 (IN[i])
|
|
||||||
// 公式: IN[i] = use_i ∪ (OUT[i] - def_i)
|
|
||||||
activeSet.erase(defined); // 移除被定义的变量 (OUT[i] - def_i)
|
|
||||||
activeSet.insert(used.begin(), used.end()); // 添加使用的变量
|
|
||||||
|
|
||||||
// 获取旧的入口活跃变量集 (位置i-1对应当前指令的入口)
|
|
||||||
const auto &oldActiveSet = activeTable.at(block)[i - 1];
|
|
||||||
|
|
||||||
// 检查活跃变量集是否有变化
|
|
||||||
if (!std::equal(activeSet.begin(), activeSet.end(),
|
|
||||||
oldActiveSet.begin(), oldActiveSet.end()))
|
|
||||||
{
|
|
||||||
changed = true; // 标记变化
|
|
||||||
activeTable.at(block)[i - 1] = activeSet; // 更新入口活跃变量集
|
|
||||||
}
|
|
||||||
|
|
||||||
instructionIter--; // 移动到前一条指令
|
|
||||||
}
|
|
||||||
|
|
||||||
return changed; // 返回数据流结果是否变化
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace sysy
|
|
||||||
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
// PassManager.cpp
|
|
||||||
#include "SysYIRPassManager.h"
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace sysy {
|
|
||||||
|
|
||||||
void PassManager::run(Module& M) {
|
|
||||||
// 首先运行Module级别的Pass
|
|
||||||
for (auto& pass : modulePasses) {
|
|
||||||
std::cout << "Running Module Pass: " << pass->getPassName() << std::endl;
|
|
||||||
pass->runOnModule(M);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 然后对每个函数运行Function级别的Pass
|
|
||||||
auto& functions = M.getFunctions();
|
|
||||||
for (auto& pair : functions) {
|
|
||||||
Function& F = *(pair.second); // 获取Function的引用
|
|
||||||
std::cout << " Processing Function: " << F.getName() << std::endl;
|
|
||||||
|
|
||||||
// 在每个函数上运行FunctionPasses
|
|
||||||
bool changedInFunction;
|
|
||||||
do {
|
|
||||||
changedInFunction = false;
|
|
||||||
for (auto& pass : functionPasses) {
|
|
||||||
// 对于FunctionPasses,可以考虑一个迭代执行的循环,直到稳定
|
|
||||||
std::cout << " Running Function Pass: " << pass->getPassName() << std::endl;
|
|
||||||
changedInFunction |= pass->runOnFunction(F);
|
|
||||||
}
|
|
||||||
} while (changedInFunction); // 循环直到函数稳定,这模拟了您SysYCFGOpt的while(changed)逻辑
|
|
||||||
}
|
|
||||||
|
|
||||||
// 分析Pass的运行可以在其他Pass需要时触发,或者在特定的PassManager阶段触发
|
|
||||||
// 对于依赖于分析结果的Pass,可以在其run方法中通过PassManager::getAnalysis()来获取
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace sysy
|
|
||||||
@@ -12,22 +12,25 @@ namespace sysy {
|
|||||||
class RISCv64AsmPrinter {
|
class RISCv64AsmPrinter {
|
||||||
public:
|
public:
|
||||||
RISCv64AsmPrinter(MachineFunction* mfunc);
|
RISCv64AsmPrinter(MachineFunction* mfunc);
|
||||||
|
|
||||||
// 主入口
|
// 主入口
|
||||||
void run(std::ostream& os, bool debug = false);
|
void run(std::ostream& os, bool debug = false);
|
||||||
|
void printInstruction(MachineInstr* instr, bool debug = false);
|
||||||
|
// 辅助函数
|
||||||
|
void setStream(std::ostream& os) { OS = &os; }
|
||||||
private:
|
private:
|
||||||
// 打印各个部分
|
// 打印各个部分
|
||||||
void printPrologue();
|
void printPrologue();
|
||||||
void printEpilogue();
|
void printEpilogue();
|
||||||
void printBasicBlock(MachineBasicBlock* mbb, bool debug = false);
|
void printBasicBlock(MachineBasicBlock* mbb, bool debug = false);
|
||||||
void printInstruction(MachineInstr* instr, bool debug = false);
|
|
||||||
|
|
||||||
// 辅助函数
|
// 辅助函数
|
||||||
std::string regToString(PhysicalReg reg);
|
std::string regToString(PhysicalReg reg);
|
||||||
void printOperand(MachineOperand* op);
|
void printOperand(MachineOperand* op);
|
||||||
|
|
||||||
MachineFunction* MFunc;
|
MachineFunction* MFunc;
|
||||||
std::ostream* OS;
|
std::ostream* OS = nullptr;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sysy
|
} // namespace sysy
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ public:
|
|||||||
// 公开接口,以便后续模块(如RegAlloc)可以查询或创建vreg
|
// 公开接口,以便后续模块(如RegAlloc)可以查询或创建vreg
|
||||||
unsigned getVReg(Value* val);
|
unsigned getVReg(Value* val);
|
||||||
unsigned getNewVReg() { return vreg_counter++; }
|
unsigned getNewVReg() { return vreg_counter++; }
|
||||||
|
// 获取 vreg_map 的公共接口
|
||||||
|
const std::map<Value*, unsigned>& getVRegMap() const { return vreg_map; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// DAG节点定义,作为ISel的内部实现细节
|
// DAG节点定义,作为ISel的内部实现细节
|
||||||
|
|||||||
@@ -35,7 +35,12 @@ enum class PhysicalReg {
|
|||||||
// (保持您原有的 F0-F31 命名)
|
// (保持您原有的 F0-F31 命名)
|
||||||
F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11,
|
F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11,
|
||||||
F12, F13, F14, F15, F16, F17, F18, F19, F20, F21,
|
F12, F13, F14, F15, F16, F17, F18, F19, F20, F21,
|
||||||
F22, F23, F24, F25, F26, F27, F28, F29, F30, F31
|
F22, F23, F24, F25, F26, F27, F28, F29, F30, F31,
|
||||||
|
|
||||||
|
// 用于内部表示物理寄存器在干扰图中的节点ID(一个简单的特殊ID,确保不与vreg_counter冲突)
|
||||||
|
// 假设 vreg_counter 不会达到这么大的值
|
||||||
|
PHYS_REG_START_ID = 100000,
|
||||||
|
PHYS_REG_END_ID = PHYS_REG_START_ID + 320, // 预留足够的空间
|
||||||
};
|
};
|
||||||
|
|
||||||
// RISC-V 指令操作码枚举
|
// RISC-V 指令操作码枚举
|
||||||
@@ -67,6 +72,9 @@ enum class RVOpcodes {
|
|||||||
FRAME_ADDR, // 获取栈帧变量的地址
|
FRAME_ADDR, // 获取栈帧变量的地址
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 定义一个全局辅助函数或常量,提供调用者保存寄存器列表
|
||||||
|
const std::vector<PhysicalReg>& getCallerSavedIntRegs();
|
||||||
|
|
||||||
class MachineOperand;
|
class MachineOperand;
|
||||||
class RegOperand;
|
class RegOperand;
|
||||||
class ImmOperand;
|
class ImmOperand;
|
||||||
@@ -187,6 +195,7 @@ struct StackFrameInfo {
|
|||||||
int locals_size = 0; // 仅为AllocaInst分配的大小
|
int locals_size = 0; // 仅为AllocaInst分配的大小
|
||||||
int spill_size = 0; // 仅为溢出分配的大小
|
int spill_size = 0; // 仅为溢出分配的大小
|
||||||
int total_size = 0; // 总大小
|
int total_size = 0; // 总大小
|
||||||
|
int callee_saved_size = 0; // 保存寄存器的大小
|
||||||
std::map<unsigned, int> alloca_offsets; // <AllocaInst的vreg, 栈偏移>
|
std::map<unsigned, int> alloca_offsets; // <AllocaInst的vreg, 栈偏移>
|
||||||
std::map<unsigned, int> spill_offsets; // <溢出vreg, 栈偏移>
|
std::map<unsigned, int> spill_offsets; // <溢出vreg, 栈偏移>
|
||||||
std::set<PhysicalReg> used_callee_saved_regs; // 使用的保存寄存器
|
std::set<PhysicalReg> used_callee_saved_regs; // 使用的保存寄存器
|
||||||
@@ -215,6 +224,15 @@ private:
|
|||||||
StackFrameInfo frame_info;
|
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
|
} // namespace sysy
|
||||||
|
|
||||||
#endif // RISCV64_LLIR_H
|
#endif // RISCV64_LLIR_H
|
||||||
@@ -2,6 +2,10 @@
|
|||||||
#define RISCV64_REGALLOC_H
|
#define RISCV64_REGALLOC_H
|
||||||
|
|
||||||
#include "RISCv64LLIR.h"
|
#include "RISCv64LLIR.h"
|
||||||
|
#include "RISCv64ISel.h" // 包含 RISCv64ISel.h 以访问 ISel 和 Value 类型
|
||||||
|
|
||||||
|
extern int DEBUG;
|
||||||
|
extern int DEEPDEBUG;
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
@@ -56,9 +60,13 @@ private:
|
|||||||
// 存储vreg到IR Value*的反向映射
|
// 存储vreg到IR Value*的反向映射
|
||||||
// 这个map将在run()函数开始时被填充,并在rewriteFunction()中使用。
|
// 这个map将在run()函数开始时被填充,并在rewriteFunction()中使用。
|
||||||
std::map<unsigned, Value*> vreg_to_value_map;
|
std::map<unsigned, Value*> vreg_to_value_map;
|
||||||
|
std::map<PhysicalReg, unsigned> preg_to_vreg_id_map; // 物理寄存器到特殊vreg ID的映射
|
||||||
|
|
||||||
// 用于计算类型大小的辅助函数
|
// 用于计算类型大小的辅助函数
|
||||||
unsigned getTypeSizeInBytes(Type* type);
|
unsigned getTypeSizeInBytes(Type* type);
|
||||||
|
|
||||||
|
// 辅助函数,用于打印集合
|
||||||
|
static void printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ QEMU_RISCV64="qemu-riscv64"
|
|||||||
|
|
||||||
# --- 初始化变量 ---
|
# --- 初始化变量 ---
|
||||||
EXECUTE_MODE=false
|
EXECUTE_MODE=false
|
||||||
|
CLEAN_MODE=false
|
||||||
SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒)
|
SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒)
|
||||||
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
|
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
|
||||||
EXEC_TIMEOUT=5 # qemu 自动化执行超时 (秒)
|
EXEC_TIMEOUT=5 # qemu 自动化执行超时 (秒)
|
||||||
@@ -37,6 +38,7 @@ show_help() {
|
|||||||
echo ""
|
echo ""
|
||||||
echo "选项:"
|
echo "选项:"
|
||||||
echo " -e, --executable 编译为可执行文件并运行测试 (必须)。"
|
echo " -e, --executable 编译为可执行文件并运行测试 (必须)。"
|
||||||
|
echo " -c, --clean 清理 tmp 临时目录下的所有文件。"
|
||||||
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 10)。"
|
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 10)。"
|
||||||
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
||||||
echo " -et N 设置 qemu 自动化执行超时为 N 秒 (默认: 5)。"
|
echo " -et N 设置 qemu 自动化执行超时为 N 秒 (默认: 5)。"
|
||||||
@@ -74,6 +76,10 @@ for arg in "$@"; do
|
|||||||
-e|--executable)
|
-e|--executable)
|
||||||
EXECUTE_MODE=true
|
EXECUTE_MODE=true
|
||||||
;;
|
;;
|
||||||
|
-c|--clean)
|
||||||
|
CLEAN_MODE=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
-sct|-gct|-et|-ml|--max-lines)
|
-sct|-gct|-et|-ml|--max-lines)
|
||||||
# 选项和其值将在下一个循环中处理
|
# 选项和其值将在下一个循环中处理
|
||||||
;;
|
;;
|
||||||
@@ -110,6 +116,23 @@ for arg in "$@"; do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
if ${CLEAN_MODE}; then
|
||||||
|
echo "检测到 -c/--clean 选项,正在清空 ${TMP_DIR}..."
|
||||||
|
if [ -d "${TMP_DIR}" ]; then
|
||||||
|
# 使用 * 而不是 . 来确保只删除内容,不删除目录本身
|
||||||
|
# 忽略 rm 可能因目录为空而报告的错误
|
||||||
|
rm -rf "${TMP_DIR}"/* 2>/dev/null
|
||||||
|
echo "清理完成。"
|
||||||
|
else
|
||||||
|
echo "临时目录 ${TMP_DIR} 不存在,无需清理。"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 如果只提供了 -c 选项而没有其他 .sy 文件,则在清理后退出
|
||||||
|
if [ ${#SY_FILES[@]} -eq 0 ] && ! ${EXECUTE_MODE}; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# --- 主逻辑开始 ---
|
# --- 主逻辑开始 ---
|
||||||
if ! ${EXECUTE_MODE}; then
|
if ! ${EXECUTE_MODE}; then
|
||||||
echo "错误: 请提供 -e 或 --executable 选项来运行测试。"
|
echo "错误: 请提供 -e 或 --executable 选项来运行测试。"
|
||||||
@@ -138,6 +161,7 @@ for sy_file in "${SY_FILES[@]}"; do
|
|||||||
|
|
||||||
ir_file="${TMP_DIR}/${base_name}_sysyc_riscv64.ll"
|
ir_file="${TMP_DIR}/${base_name}_sysyc_riscv64.ll"
|
||||||
assembly_file="${TMP_DIR}/${base_name}.s"
|
assembly_file="${TMP_DIR}/${base_name}.s"
|
||||||
|
assembly_debug_file="${TMP_DIR}/${base_name}_d.s"
|
||||||
executable_file="${TMP_DIR}/${base_name}"
|
executable_file="${TMP_DIR}/${base_name}"
|
||||||
input_file="${source_dir}/${base_name}.in"
|
input_file="${source_dir}/${base_name}.in"
|
||||||
output_reference_file="${source_dir}/${base_name}.out"
|
output_reference_file="${source_dir}/${base_name}.out"
|
||||||
@@ -162,6 +186,7 @@ for sy_file in "${SY_FILES[@]}"; do
|
|||||||
echo -e "\e[31m错误: SysY 编译失败或超时。\e[0m"
|
echo -e "\e[31m错误: SysY 编译失败或超时。\e[0m"
|
||||||
is_passed=0
|
is_passed=0
|
||||||
fi
|
fi
|
||||||
|
# timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s asmd "${sy_file}" > "${assembly_debug_file}" 2>&1
|
||||||
|
|
||||||
# 步骤 2: GCC 编译
|
# 步骤 2: GCC 编译
|
||||||
if [ "$is_passed" -eq 1 ]; then
|
if [ "$is_passed" -eq 1 ]; then
|
||||||
|
|||||||
Reference in New Issue
Block a user