[backend] fix bugs of unary ops

This commit is contained in:
Lixuanwang
2025-06-25 01:07:13 +08:00
parent eadeadfbad
commit af1ad795ff

View File

@@ -6,56 +6,99 @@
#include <iomanip>
#include <functional> // For std::function
#define DEBUG 1
#define DEBUG 0
#define DEEPDEBUG 0
namespace sysy {
namespace sysy {
// 可用于分配的通用寄存器
// 可用于分配的寄存器(整数和浮点)
const std::vector<RISCv32CodeGen::PhysicalReg> RISCv32CodeGen::allocable_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
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
// 浮点寄存器
PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3,
PhysicalReg::F4, PhysicalReg::F5, PhysicalReg::F6, PhysicalReg::F7,
PhysicalReg::F8, PhysicalReg::F9, PhysicalReg::F10, PhysicalReg::F11,
PhysicalReg::F12, PhysicalReg::F13, PhysicalReg::F14, PhysicalReg::F15,
PhysicalReg::F16, PhysicalReg::F17, 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
};
// 将物理寄存器枚举转换为字符串
std::string RISCv32CodeGen::reg_to_string(PhysicalReg reg) {
switch (reg) {
case PhysicalReg::ZERO: return "x0"; // 零寄存器
case PhysicalReg::RA: return "ra"; // 返回地址寄存器
case PhysicalReg::SP: return "sp"; // 栈指针
case PhysicalReg::GP: return "gp"; // 全局指针
case PhysicalReg::TP: return "tp"; // 线程指针
case PhysicalReg::T0: return "t0"; // 临时寄存器
case PhysicalReg::T1: return "t1"; // 临时寄存器
case PhysicalReg::T2: return "t2"; // 临时寄存器
case PhysicalReg::S0: return "s0"; // 帧指针 / 保存的寄存器
case PhysicalReg::S1: return "s1"; // 保存的寄存器
case PhysicalReg::A0: return "a0"; // 函数参数 / 返回值寄存器
case PhysicalReg::A1: return "a1"; // 函数参数
case PhysicalReg::A2: return "a2"; // 函数参数
case PhysicalReg::A3: return "a3"; // 函数参数
case PhysicalReg::A4: return "a4"; // 函数参数
case PhysicalReg::A5: return "a5"; // 函数参数
case PhysicalReg::A6: return "a6"; // 函数参数
case PhysicalReg::A7: return "a7"; // 函数参数
case PhysicalReg::S2: return "s2"; // 保存的寄存器
case PhysicalReg::S3: return "s3"; // 保存的寄存器
case PhysicalReg::S4: return "s4"; // 保存的寄存器
case PhysicalReg::S5: return "s5"; // 保存的寄存器
case PhysicalReg::S6: return "s6"; // 保存的寄存器
case PhysicalReg::S7: return "s7"; // 保存的寄存器
case PhysicalReg::S8: return "s8"; // 保存的寄存器
case PhysicalReg::S9: return "s9"; // 保存的寄存器
case PhysicalReg::S10: return "s10"; // 保存的寄存器
case PhysicalReg::S11: return "s11"; // 保存的寄存器
case PhysicalReg::T3: return "t3"; // 临时寄存器
case PhysicalReg::T4: return "t4"; // 临时寄存器
case PhysicalReg::T5: return "t5"; // 临时寄存器
case PhysicalReg::T6: return "t6"; // 临时寄存器
case PhysicalReg::ZERO: return "x0";
case PhysicalReg::RA: return "ra";
case PhysicalReg::SP: return "sp";
case PhysicalReg::GP: return "gp";
case PhysicalReg::TP: return "tp";
case PhysicalReg::T0: return "t0";
case PhysicalReg::T1: return "t1";
case PhysicalReg::T2: return "t2";
case PhysicalReg::S0: return "s0";
case PhysicalReg::S1: return "s1";
case PhysicalReg::A0: return "a0";
case PhysicalReg::A1: return "a1";
case PhysicalReg::A2: return "a2";
case PhysicalReg::A3: return "a3";
case PhysicalReg::A4: return "a4";
case PhysicalReg::A5: return "a5";
case PhysicalReg::A6: return "a6";
case PhysicalReg::A7: return "a7";
case PhysicalReg::S2: return "s2";
case PhysicalReg::S3: return "s3";
case PhysicalReg::S4: return "s4";
case PhysicalReg::S5: return "s5";
case PhysicalReg::S6: return "s6";
case PhysicalReg::S7: return "s7";
case PhysicalReg::S8: return "s8";
case PhysicalReg::S9: return "s9";
case PhysicalReg::S10: return "s10";
case PhysicalReg::S11: return "s11";
case PhysicalReg::T3: return "t3";
case PhysicalReg::T4: return "t4";
case PhysicalReg::T5: return "t5";
case PhysicalReg::T6: return "t6";
// 浮点寄存器
case PhysicalReg::F0: return "f0";
case PhysicalReg::F1: return "f1";
case PhysicalReg::F2: return "f2";
case PhysicalReg::F3: return "f3";
case PhysicalReg::F4: return "f4";
case PhysicalReg::F5: return "f5";
case PhysicalReg::F6: return "f6";
case PhysicalReg::F7: return "f7";
case PhysicalReg::F8: return "f8";
case PhysicalReg::F9: return "f9";
case PhysicalReg::F10: return "f10";
case PhysicalReg::F11: return "f11";
case PhysicalReg::F12: return "f12";
case PhysicalReg::F13: return "f13";
case PhysicalReg::F14: return "f14";
case PhysicalReg::F15: return "f15";
case PhysicalReg::F16: return "f16";
case PhysicalReg::F17: return "f17";
case PhysicalReg::F18: return "f18";
case PhysicalReg::F19: return "f19";
case PhysicalReg::F20: return "f20";
case PhysicalReg::F21: return "f21";
case PhysicalReg::F22: return "f22";
case PhysicalReg::F23: return "f23";
case PhysicalReg::F24: return "f24";
case PhysicalReg::F25: return "f25";
case PhysicalReg::F26: return "f26";
case PhysicalReg::F27: return "f27";
case PhysicalReg::F28: return "f28";
case PhysicalReg::F29: return "f29";
case PhysicalReg::F30: return "f30";
case PhysicalReg::F31: return "f31";
default: return "UNKNOWN_REG";
}
}
@@ -249,16 +292,15 @@ std::string RISCv32CodeGen::basicBlock_gen(BasicBlock* bb, const RegAllocResult&
return ss.str();
}
// DAG 构建
std::vector<std::unique_ptr<RISCv32CodeGen::DAGNode>> RISCv32CodeGen::build_dag(BasicBlock* bb) {
std::vector<std::unique_ptr<DAGNode>> nodes_storage; // 存储所有 unique_ptr
std::map<Value*, DAGNode*> value_to_node; // 将 IR Value* 映射到原始 DAGNode*,用于快速查找
// 辅助函数,用于创建 DAGNode 并管理其所有权
auto create_node = [&](DAGNode::NodeKind kind, Value* val = nullptr) -> DAGNode* {
// 优化:如果一个值已经有节点并且它不是控制流/存储/Alloca地址则重用它 (CSE)
// 优化:如果一个值已经有节点并且它不是控制流/存储/Alloca地址/一元操作,则重用它 (CSE)
// 对于 AllocaInst我们想创建一个代表其地址的节点但不一定直接为 AllocaInst 本身分配虚拟寄存器。
if (val && value_to_node.count(val) && kind != DAGNode::STORE && kind != DAGNode::RETURN && kind != DAGNode::BRANCH && kind != DAGNode::ALLOCA_ADDR) {
if (val && value_to_node.count(val) && kind != DAGNode::STORE && kind != DAGNode::RETURN && kind != DAGNode::BRANCH && kind != DAGNode::ALLOCA_ADDR && kind != DAGNode::UNARY) {
return value_to_node[val];
}
@@ -268,6 +310,7 @@ std::vector<std::unique_ptr<RISCv32CodeGen::DAGNode>> RISCv32CodeGen::build_dag(
// 为产生结果的值分配虚拟寄存器
// 注意这里的vreg分配是在每个块中独立进行的但寄存器分配器是在函数级别运行的
// 我们在寄存器分配前已经为整个函数的所有value预分配了vreg
// 此处的逻辑应完全依赖于 register_allocation 阶段已经建立的 value_vreg_map
// 并且 AllocaInst 不应在此处获取 result_vreg因为它不映射到物理寄存器。
if (val && value_vreg_map.count(val) && !dynamic_cast<AllocaInst*>(val)) { // 排除 AllocaInst
node->result_vreg = value_vreg_map.at(val);
@@ -323,8 +366,8 @@ std::vector<std::unique_ptr<RISCv32CodeGen::DAGNode>> RISCv32CodeGen::build_dag(
// 为了简化,如果没找到,就创建一个
// 修正AllocaInst 应该直接映射到 ALLOCA_ADDR 节点,其值是 AllocaInst*
ptr_node = create_node(DAGNode::ALLOCA_ADDR, alloca);
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_ir)) {
ptr_node = create_node(DAGNode::CONSTANT, global); // 全局地址将被加载
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_ir)) {
ptr_node = create_node(DAGNode::CONSTANT, global); // 全局地址将被加载
} else { // 必须是存储在虚拟寄存器中的指针
ptr_node = create_node(DAGNode::LOAD, ptr_ir); // 这是一个产生指针的指令
}
@@ -356,6 +399,43 @@ std::vector<std::unique_ptr<RISCv32CodeGen::DAGNode>> RISCv32CodeGen::build_dag(
} else if (auto bin = dynamic_cast<BinaryInst*>(inst)) {
if (value_to_node.count(bin)) continue; // CSE
// --- 关键修改:识别 SUB 0, X 或 FSUB 0.0, X 模式为 NEG ---
if (bin->getKind() == BinaryInst::kSub || bin->getKind() == BinaryInst::kFSub) {
Value* lhs_ir = bin->getLhs();
if (auto const_lhs = dynamic_cast<ConstantValue*>(lhs_ir)) { // 修正:使用 ConstantValue
bool is_neg = false;
if (const_lhs->getType()->isInt()) { // 整数类型
if (const_lhs->getInt() == 0) {
is_neg = true;
}
} else if (const_lhs->getType()->isFloat()) { // 浮点类型
// 浮点数零的比较需要考虑精度使用一个小的epsilon
if (std::fabs(const_lhs->getFloat()) < std::numeric_limits<float>::epsilon()) {
is_neg = true;
}
}
if (is_neg) {
// 这是一个 neg 操作 (0 - X 或 0.0 - X)
auto unary_node = create_node(DAGNode::UNARY, bin); // 绑定到原 BinaryInst但类型是 UNARY
Value* operand_ir = bin->getRhs(); // 右操作数是实际被 neg 的值
DAGNode* operand_node = nullptr;
if (value_to_node.count(operand_ir)) {
operand_node = value_to_node[operand_ir];
} else if (auto constant = dynamic_cast<ConstantValue*>(operand_ir)) {
operand_node = create_node(DAGNode::CONSTANT, constant);
} else {
operand_node = create_node(DAGNode::LOAD, operand_ir);
}
unary_node->operands.push_back(operand_node);
operand_node->users.push_back(unary_node);
continue; // 已处理,跳过后续的常规 Binary 处理
}
}
}
// --- 结束关键修改 ---
// 常规二进制操作
auto bin_node = create_node(DAGNode::BINARY, bin);
auto get_operand_node = [&](Value* operand_ir) -> DAGNode* {
@@ -376,6 +456,24 @@ std::vector<std::unique_ptr<RISCv32CodeGen::DAGNode>> RISCv32CodeGen::build_dag(
bin_node->operands.push_back(rhs_node);
lhs_node->users.push_back(bin_node);
rhs_node->users.push_back(bin_node);
} else if (auto un_inst = dynamic_cast<UnaryInst*>(inst)) { // 处理一元指令
if (value_to_node.count(un_inst)) continue; // CSE
auto unary_node = create_node(DAGNode::UNARY, un_inst); // 为 unary_node 分配 result_vreg 并映射 un_inst
// 修正UnaryInst::getOperand() 不接受参数
Value* operand_ir = un_inst->getOperand();
DAGNode* operand_node = nullptr;
if (value_to_node.count(operand_ir)) {
operand_node = value_to_node[operand_ir];
} else if (auto constant = dynamic_cast<ConstantValue*>(operand_ir)) {
operand_node = create_node(DAGNode::CONSTANT, constant);
} else {
operand_node = create_node(DAGNode::LOAD, operand_ir);
}
unary_node->operands.push_back(operand_node);
operand_node->users.push_back(unary_node);
} else if (auto call = dynamic_cast<CallInst*>(inst)) {
if (value_to_node.count(call)) continue; // CSE (如果结果被重用)
@@ -519,9 +617,9 @@ void RISCv32CodeGen::print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag,
// 指令选择 (保持不变,因为问题不在选择器本身,而是分配)
void RISCv32CodeGen::select_instructions(DAGNode* node, const RegAllocResult& alloc) {
if (!node) return;
if (!node->inst.empty()) return; // 指令已选择
if (!node->inst.empty()) return; // 指令已选择,跳过重复处理
// 首先递归地为操作数选择指令
// 递归地为操作数选择指令,确保依赖先被处理
for (auto operand : node->operands) {
if (operand) {
select_instructions(operand, alloc);
@@ -530,22 +628,15 @@ void RISCv32CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
std::stringstream ss_inst; // 使用 stringstream 构建指令
// 获取分配的物理寄存器,如果没有分配,则使用临时寄存器 (T0)
// 这是关键:这里应该返回寄存器分配器实际分配的寄存器。
// 如果寄存器分配失败,才会回退到 T0。
// 获取分配的物理寄存器,若未分配则回退到 t0
auto get_preg_or_temp = [&](const std::string& vreg) {
if (alloc.vreg_to_preg.count(vreg)) {
return reg_to_string(alloc.vreg_to_preg.at(vreg));
}
// 如果虚拟寄存器未分配给物理寄存器,则表示它已溢出或是一个临时值。
// 对于这个简化示例,我们没有实现完整的溢出。
// 如果它没有被分配(例如,因为它没有被认为是活跃的,或者寄存器不够),
// 那么我们将使用 T0 作为回退。这可能是导致问题的根本原因。
// 但对于简单程序,如果活跃性分析正确,它应该能被分配。
return reg_to_string(PhysicalReg::T0); // 回退到临时寄存器 t0
};
// 获取分配的栈变量的内存偏移量
// 获取栈变量的内存偏移量
auto get_stack_offset = [&](Value* val) {
if (alloc.stack_map.count(val)) {
return std::to_string(alloc.stack_map.at(val));
@@ -555,6 +646,7 @@ void RISCv32CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
switch (node->kind) {
case DAGNode::CONSTANT: {
// 处理常量节点
if (auto constant = dynamic_cast<ConstantValue*>(node->value)) {
std::string dest_reg = get_preg_or_temp(node->result_vreg);
if (constant->isInt()) {
@@ -562,69 +654,62 @@ void RISCv32CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
} else {
float f = constant->getFloat();
uint32_t float_bits = *(uint32_t*)&f;
// 对于浮点数,先加载整数位,然后转换
ss_inst << "li " << dest_reg << ", " << float_bits << "\n";
ss_inst << "fmv.w.x " << dest_reg << ", " << dest_reg; // 假设 dest_reg 可以同时用于整数和浮点数 (FPU 寄存器并非总是如此)
ss_inst << "fmv.w.x " << dest_reg << ", " << dest_reg;
}
} else if (auto global = dynamic_cast<GlobalValue*>(node->value)) {
std::string dest_reg = get_preg_or_temp(node->result_vreg);
ss_inst << "la " << dest_reg << ", " << global->getName(); // 加载全局变量地址
ss_inst << "la " << dest_reg << ", " << global->getName();
}
break;
}
case DAGNode::ALLOCA_ADDR: {
// FIX: 这个节点本身不生成指令。
// 它的使用者LOAD/STORE会利用它的信息生成更优化的寻址指令。
// 将 node->inst 留空以避免生成冗余的 `addi` 指令。
// ALLOCA_ADDR 节点不直接生成指令,由 LOAD/STORE 使用
break;
}
case DAGNode::LOAD: {
// 处理加载指令
if (node->operands.empty() || !node->operands[0]) break;
std::string dest_reg = get_preg_or_temp(node->result_vreg);
DAGNode* ptr_node = node->operands[0]; // 操作数是指针
DAGNode* ptr_node = node->operands[0];
// 检查指针本身是否是 AllocaInst
if (ptr_node->kind == DAGNode::ALLOCA_ADDR) { // 检查节点类型,而非其值
if (ptr_node->kind == DAGNode::ALLOCA_ADDR) {
if (auto alloca_inst = dynamic_cast<AllocaInst*>(ptr_node->value)) {
int offset = alloc.stack_map.at(alloca_inst);
ss_inst << "lw " << dest_reg << ", " << offset << "(s0)";
}
} else {
// 指针在寄存器中 (可能是全局地址,或 GEP/其他计算结果)
std::string ptr_reg = get_preg_or_temp(ptr_node->result_vreg);
ss_inst << "lw " << dest_reg << ", 0(" << ptr_reg << ")"; // 从 ptr_reg 中的地址加载
ss_inst << "lw " << dest_reg << ", 0(" << ptr_reg << ")";
}
break;
}
case DAGNode::STORE: {
// 处理存储指令
if (node->operands.size() < 2 || !node->operands[0] || !node->operands[1]) break;
DAGNode* val_node = node->operands[0]; // 要存储的值
DAGNode* ptr_node = node->operands[1]; // 目标地址
DAGNode* val_node = node->operands[0];
DAGNode* ptr_node = node->operands[1];
std::string src_reg;
if (val_node->kind == DAGNode::CONSTANT) {
// 如果存储的是常量,先将其加载到临时寄存器 (t0)
// 这里的处理是,常量会先被其 CONSTANT 节点选择指令并存入其 result_vreg 对应的物理寄存器。
// STORE 节点直接使用这个物理寄存器。
src_reg = get_preg_or_temp(val_node->result_vreg);
} else {
src_reg = get_preg_or_temp(val_node->result_vreg);
}
// 检查指针是否是 AllocaInst (栈变量)
if (ptr_node->kind == DAGNode::ALLOCA_ADDR) {
if (auto alloca_inst = dynamic_cast<AllocaInst*>(ptr_node->value)) {
int offset = alloc.stack_map.at(alloca_inst);
ss_inst << "sw " << src_reg << ", " << offset << "(s0)";
}
} else {
// 指针在寄存器中 (可能是全局地址,或 GEP/其他计算结果)
std::string ptr_reg = get_preg_or_temp(ptr_node->result_vreg);
ss_inst << "sw " << src_reg << ", 0(" << ptr_reg << ")";
}
break;
}
case DAGNode::BINARY: {
// 处理二元指令
if (node->operands.size() < 2 || !node->operands[0] || !node->operands[1]) break;
auto bin = dynamic_cast<BinaryInst*>(node->value);
if (!bin) break;
@@ -638,59 +723,88 @@ void RISCv32CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
case BinaryInst::kAdd: opcode = "add"; break;
case BinaryInst::kSub: opcode = "sub"; break;
case BinaryInst::kMul: opcode = "mul"; break;
case BinaryInst::kICmpEQ: // 实现 A == B 为 sub A, B; seqz D, (A-B)
case BinaryInst::kICmpEQ:
ss_inst << "sub " << dest_reg << ", " << lhs_reg << ", " << rhs_reg << "\n";
ss_inst << " seqz " << dest_reg << ", " << dest_reg; // 如果等于零则设置
node->inst = ss_inst.str(); // 设置指令并返回
ss_inst << " seqz " << dest_reg << ", " << dest_reg;
node->inst = ss_inst.str();
return;
case Instruction::kDiv: opcode = "div"; break; // 整数除法
case Instruction::kRem: opcode = "rem"; break; // 整数余数
case BinaryInst::kICmpGE: // A >= B <=> !(A < B) <=> !(slt D, A, B) <=> slt D, A, B; xori D, D, 1
case Instruction::kDiv: opcode = "div"; break;
case Instruction::kRem: opcode = "rem"; break;
case BinaryInst::kICmpGE:
ss_inst << "slt " << dest_reg << ", " << lhs_reg << ", " << rhs_reg << "\n";
ss_inst << " xori " << dest_reg << ", " << dest_reg << ", 1";
node->inst = ss_inst.str();
return;
case BinaryInst::kICmpGT: // A > B <=> B < A
case BinaryInst::kICmpGT:
opcode = "slt";
ss_inst << opcode << " " << dest_reg << ", " << rhs_reg << ", " << lhs_reg; // slt rd, rs2, rs1 (如果 rs2 < rs1)
ss_inst << opcode << " " << dest_reg << ", " << rhs_reg << ", " << lhs_reg;
node->inst = ss_inst.str();
return;
case BinaryInst::kICmpLE: // A <= B <=> !(A > B) <=> !(slt D, B, A) <=> slt D, B, A; xori D, D, 1
case BinaryInst::kICmpLE:
ss_inst << "slt " << dest_reg << ", " << rhs_reg << ", " << lhs_reg << "\n";
ss_inst << " xori " << dest_reg << ", " << dest_reg << ", 1";
node->inst = ss_inst.str();
return;
case BinaryInst::kICmpLT: // A < B
case BinaryInst::kICmpLT:
opcode = "slt";
ss_inst << opcode << " " << dest_reg << ", " << lhs_reg << ", " << rhs_reg;
node->inst = ss_inst.str();
return;
case BinaryInst::kICmpNE: // A != B <=> ! (A == B) <=> sub D, A, B; snez D, D
case BinaryInst::kICmpNE:
ss_inst << "sub " << dest_reg << ", " << lhs_reg << ", " << rhs_reg << "\n";
ss_inst << " snez " << dest_reg << ", " << dest_reg;
node->inst = ss_inst.str();
return;
default:
// 处理未知二进制操作或抛出错误
throw std::runtime_error("Unsupported binary instruction kind: " + bin->getKindString());
throw std::runtime_error("不支持的二元指令类型: " + bin->getKindString());
}
if (!opcode.empty()) {
ss_inst << opcode << " " << dest_reg << ", " << lhs_reg << ", " << rhs_reg;
}
break;
}
case DAGNode::UNARY: {
// 处理一元指令
if (node->operands.empty() || !node->operands[0]) break;
auto unary = dynamic_cast<UnaryInst*>(node->value);
if (!unary) break;
std::string dest_reg = get_preg_or_temp(node->result_vreg);
std::string src_reg = get_preg_or_temp(node->operands[0]->result_vreg);
switch (unary->getKind()) {
case UnaryInst::kNeg:
// 整数取负sub rd, x0, rs (等价于 neg rd, rs)
ss_inst << "sub " << dest_reg << ", x0, " << src_reg;
break;
case UnaryInst::kNot:
// 整数逻辑非not rd, rs (等价于 xori rd, rs, -1)
ss_inst << "not " << dest_reg << ", " << src_reg;
break;
case UnaryInst::kFNeg:
case UnaryInst::kFNot:
case UnaryInst::kFtoI:
case UnaryInst::kItoF:
case UnaryInst::kBitFtoI:
case UnaryInst::kBitItoF:
// 浮点相关指令,当前不支持
throw std::runtime_error("不支持的浮点一元指令类型: " + unary->getKindString());
default:
throw std::runtime_error("不支持的一元指令类型: " + unary->getKindString());
}
break;
}
case DAGNode::CALL: {
// 处理函数调用指令
if (!node->value) break;
auto call = dynamic_cast<CallInst*>(node->value);
if (!call) break;
// 将参数放入 a0-a7
for (size_t i = 0; i < node->operands.size() && i < 8; ++i) {
if (node->operands[i] && !node->operands[i]->result_vreg.empty()) {
ss_inst << "mv " << reg_to_string(static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + i))
<< ", " << get_preg_or_temp(node->operands[i]->result_vreg) << "\n";
} else if (node->operands[i] && node->operands[i]->kind == DAGNode::CONSTANT) {
// 直接将常量参数加载到 A 寄存器
if (auto const_val = dynamic_cast<ConstantValue*>(node->operands[i]->value)) {
ss_inst << "li " << reg_to_string(static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + i))
<< ", " << const_val->getInt() << "\n";
@@ -700,71 +814,64 @@ void RISCv32CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
}
}
}
ss_inst << "call " << call->getCallee()->getName(); // 使用 'call' 伪指令
ss_inst << "call " << call->getCallee()->getName();
// 如果函数返回一个值,将其从 a0 移动到结果虚拟寄存器
if ((call->getType()->isInt() || call->getType()->isFloat()) && !node->result_vreg.empty()) {
ss_inst << "\nmv " << get_preg_or_temp(node->result_vreg) << ", a0";
}
break;
}
case DAGNode::RETURN: {
// 如果有返回值,将其移动到 a0
// 处理返回指令
if (!node->operands.empty() && node->operands[0]) {
std::string return_val_reg = get_preg_or_temp(node->operands[0]->result_vreg);
// 对于返回值,直接将最终结果移动到 a0避免不必要的 t0 中转
ss_inst << "mv a0, " << return_val_reg << "\n";
}
// 函数尾声 (Epilogue): 恢复 s0, ra, 并调整 sp
if (alloc.stack_size > 0) {
int aligned_stack_size = (alloc.stack_size + 15) & ~15;
ss_inst << " lw ra, " << (aligned_stack_size - 4) << "(sp)\n"; // 恢复 ra
ss_inst << " lw s0, " << (aligned_stack_size - 8) << "(sp)\n"; // 恢复 s0
ss_inst << " addi sp, sp, " << aligned_stack_size << "\n"; // 恢复栈指针
ss_inst << " lw ra, " << (aligned_stack_size - 4) << "(sp)\n";
ss_inst << " lw s0, " << (aligned_stack_size - 8) << "(sp)\n";
ss_inst << " addi sp, sp, " << aligned_stack_size << "\n";
}
ss_inst << " ret"; // 返回
ss_inst << " ret";
break;
}
case DAGNode::BRANCH: {
// 处理分支指令
auto br = dynamic_cast<CondBrInst*>(node->value);
auto uncond_br = dynamic_cast<UncondBrInst*>(node->value);
if (node->inst.empty()) { // 如果不是通过常量传播优化的直接跳转
if (node->inst.empty()) {
if (br) {
if (node->operands.empty() || !node->operands[0]) break;
std::string cond_reg = get_preg_or_temp(node->operands[0]->result_vreg);
std::string then_block = br->getThenBlock()->getName();
std::string else_block = br->getElseBlock()->getName();
// 修复空标签问题
if (then_block.empty()) {
then_block = ENTRY_BLOCK_PSEUDO_NAME + "then"; // 临时命名
then_block = ENTRY_BLOCK_PSEUDO_NAME + "then";
}
if (else_block.empty()) {
else_block = ENTRY_BLOCK_PSEUDO_NAME + "else"; // 临时命名
else_block = ENTRY_BLOCK_PSEUDO_NAME + "else";
}
ss_inst << "bnez " << cond_reg << ", " << then_block << "\n"; // 如果条件不为零 (真),则跳转到 then 块
ss_inst << " j " << else_block; // 无条件跳转到 else 块
ss_inst << "bnez " << cond_reg << ", " << then_block << "\n";
ss_inst << " j " << else_block;
} else if (uncond_br) {
std::string target_block = uncond_br->getBlock()->getName();
if (target_block.empty()) { // 修复空标签问题
target_block = ENTRY_BLOCK_PSEUDO_NAME + "target"; // 临时命名
if (target_block.empty()) {
target_block = ENTRY_BLOCK_PSEUDO_NAME + "target";
}
ss_inst << "j " << target_block; // 无条件跳转
ss_inst << "j " << target_block;
}
} else {
// 这个分支节点已经被 build_dag 中的常量传播优化为直接跳转。
// 它的 'inst' 字段已经设置。直接复制它。
ss_inst << node->inst;
}
break;
}
default:
// 对于不直接映射到指令的节点 (例如 `alloc` 本身,其地址由其地址节点处理)
// 或未处理的指令类型,将 inst 留空。
break;
throw std::runtime_error("不支持的节点类型: " + node->getNodeKindString());
}
node->inst = ss_inst.str(); // 存储生成的指令
}
@@ -838,12 +945,11 @@ std::string print_set(const std::set<std::string>& s) {
return ss.str();
}
// 活跃性分析
// 活跃性分析(更新以支持浮点指令)
std::map<Instruction*, std::set<std::string>> RISCv32CodeGen::liveness_analysis(Function* func) {
std::map<Instruction*, std::set<std::string>> live_in, live_out;
bool changed = true;
// 初始化所有 live_in/out 集合为空
for (const auto& bb : func->getBasicBlocks()) {
for (const auto& inst_ptr : bb->getInstructions()) {
live_in[inst_ptr.get()] = {};
@@ -851,20 +957,16 @@ std::map<Instruction*, std::set<std::string>> RISCv32CodeGen::liveness_analysis(
}
}
int iteration_count = 0; // 迭代计数器
int iteration_count = 0;
while (changed) {
changed = false;
iteration_count++;
if (DEEPDEBUG) std::cerr << "\n--- 活跃性分析迭代: " << iteration_count << " ---" << std::endl;
// 逆序遍历基本块
for (auto it = func->getBasicBlocks_NoRange().rbegin(); it != func->getBasicBlocks_NoRange().rend(); ++it) {
auto bb = it->get();
if (DEEPDEBUG) std::cerr << " 基本块: " << bb->getName() << std::endl; // 打印基本块名称
if (DEEPDEBUG) std::cerr << " 基本块: " << bb->getName() << std::endl;
// 在基本块内逆序遍历指令
// live_out_for_bb_inst 是当前基本块的 live_out 集合,用于计算该基本块中第一条指令的 live_out
// 初始化为当前基本块所有后继基本块的 live_in 的并集
std::set<std::string> live_out_for_bb_inst = {};
for (const auto& succ_bb : bb->getSuccessors()) {
if (!succ_bb->getInstructions().empty()) {
@@ -873,119 +975,75 @@ std::map<Instruction*, std::set<std::string>> RISCv32CodeGen::liveness_analysis(
}
}
for (auto inst_it = bb->getInstructions().rbegin(); inst_it != bb->getInstructions().rend(); ++inst_it) {
auto inst = inst_it->get();
// 打印指令,使用其父基本块的名称和指令地址作为唯一标识符
if (DEEPDEBUG) std::cerr << " 指令 (BB: " << bb->getName() << ", 地址: " << static_cast<void*>(inst) << ")" << std::endl;
std::set<std::string> current_live_in = live_in[inst];
std::set<std::string> current_live_out = live_out[inst]; // 用于比较的旧 live_out
std::set<std::string> current_live_out = live_out[inst];
std::set<std::string> new_live_out_calc;
std::set<std::string> new_live_out_calc; // 用于计算的 live_out
// 如果当前指令是基本块中的最后一条指令 (即逆序遍历中的第一条指令)
// 那么它的 live_out 就是该基本块的 live_out即其所有后继基本块的 live_in 的并集
if (inst_it == bb->getInstructions().rbegin()) {
new_live_out_calc = live_out_for_bb_inst;
if (DEEPDEBUG) std::cerr << " 指令是基本块的最后一条指令live_out 取自后继基本块 live_in 的并集: " << print_set(new_live_out_calc) << std::endl;
} else {
// 如果不是基本块的最后一条指令,则其 live_out 是其后继指令的 live_in
auto prev_inst_it = std::prev(inst_it); // std::prev 获取正向的下一条指令
auto prev_inst_it = std::prev(inst_it);
new_live_out_calc = live_in[prev_inst_it->get()];
if (DEEPDEBUG) std::cerr << " 指令不是基本块的最后一条,其 live_out 是其后继指令 live_in: " << print_set(new_live_out_calc) << std::endl;
}
// 计算当前指令的 use 和 def 集合
std::set<std::string> use_set, def_set;
// 定义 (Def) - 只有当指令本身产生一个非 void 结果并映射到虚拟寄存器时
// LoadInst, BinaryInst, CallInst 等会定义一个结果。
// StoreInst, AllocaInst, ReturnInst, BranchInst 不定义结果到寄存器。
// 定义 (Def)
if (!inst->getType()->isVoid() && !dynamic_cast<AllocaInst*>(inst) && !dynamic_cast<StoreInst*>(inst) &&
!dynamic_cast<ReturnInst*>(inst) && !dynamic_cast<CondBrInst*>(inst) && !dynamic_cast<UncondBrInst*>(inst) && value_vreg_map.count(inst)) {
def_set.insert(value_vreg_map.at(inst));
if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast<void*>(inst) << ") 定义了虚拟寄存器: " << value_vreg_map.at(inst) << std::endl;
}
// *** 针对 StoreInst 的新逻辑来“杀死”被存储值的虚拟寄存器 ***
// 这个逻辑在活跃性分析中需要非常谨慎。通常Store 指令是使用use被存储的值而不是定义def它。
// 如果一个值在 Store 后不再被使用,它会自然地通过活跃性传播变得不活跃。
// 将被存储的值添加到 def_set 意味着该值在该指令处被“杀死”,因为它被存储到内存中,而不是寄存器。
// 对于“01_add.sy”这样的简单情况这可能是有效的但对于更复杂的程序可能会导致不准确的活跃性。
// 考虑一个值被存储,但稍后又从内存中加载并再次使用的情况。
// 这是一个需要仔细考虑的启发式方法。
// StoreInst 的值可能被“杀死”
if (auto store = dynamic_cast<StoreInst*>(inst)) {
Value* stored_value = store->getValue();
// 如果被存储的值有一个虚拟寄存器,并且它不是 AllocaInstAlloca是地址不是寄存器值
if (value_vreg_map.count(stored_value) && !dynamic_cast<AllocaInst*>(stored_value)) {
// 启发式:如果存储的值是常量或临时指令结果,并且仅在此处使用,则可以认为是“杀死”了该虚拟寄存器。
// 更准确的判断需要检查该值的其他所有用途。
// 对于 '01_add.sy' 中常量的情况,这是有效的。
// 修正:使用 ->get() 来获取 shared_ptr 持有的原始指针,然后调用 getUser()
// 检查 inst 是否是 stored_value 的唯一用户。
bool is_unique_user = true;
if (!stored_value->getUses().empty()) {
is_unique_user = (stored_value->getUses().size() == 1 && stored_value->getUses().front()->getUser() == inst);
} else {
// 如果没有uses则它没有被使用不应该被def。
is_unique_user = false;
is_unique_user = false;
}
if (is_unique_user) {
def_set.insert(value_vreg_map.at(stored_value));
if (DEEPDEBUG) std::cerr << " Store 指令 (地址: " << static_cast<void*>(inst) << ") 将被存储的值 '" << value_vreg_map.at(stored_value) << "' 添加到 def_set (启发式)." << std::endl;
} else {
if (DEEPDEBUG) std::cerr << " Store 指令 (地址: " << static_cast<void*>(inst) << ") 存储的值 '" << value_vreg_map.at(stored_value) << "' 有其他用途或不是唯一用途,未添加到 def_set。" << std::endl;
def_set.insert(value_vreg_map.at(stored_value));
if (DEEPDEBUG) std::cerr << " Store 指令 (地址: " << static_cast<void*>(inst) << ") 将被存储的值 '" << value_vreg_map.at(stored_value) << "' 添加到 def_set (启发式)." << std::endl;
}
} else if (dynamic_cast<AllocaInst*>(stored_value)) {
if (DEEPDEBUG) std::cerr << " Store 指令存储的是 AllocaInst 地址,不处理其虚拟寄存器定义。" << std::endl;
}
}
// *** 结束新逻辑 ***
// 使用 (Use) - 遍历指令的操作数
for(const auto& operand_use : inst->getOperands()){
// 使用 (Use)
for (const auto& operand_use : inst->getOperands()) {
Value* operand = operand_use->getValue();
// 只有当操作数是一个实际需要寄存器来存储的“值”时才将其vreg添加到use_set。
// 排除 AllocaInst因为它们是地址概念不占用通用寄存器。
// 并且确保 operand 已经在 value_vreg_map 中有对应的虚拟寄存器。
if (value_vreg_map.count(operand) && !dynamic_cast<AllocaInst*>(operand)) {
use_set.insert(value_vreg_map.at(operand));
if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast<void*>(inst) << ") 使用了虚拟寄存器: " << value_vreg_map.at(operand) << std::endl;
} else if (dynamic_cast<AllocaInst*>(operand)) {
if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast<void*>(inst) << ") 操作数是 AllocaInst 地址,不添加到 use_set。" << std::endl;
} else {
// 对于常量它们没有虚拟寄存器也不应该被添加到use_set
// 也可以是其他没有对应虚拟寄存器(例如函数名)的值。
if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast<void*>(inst) << ") 操作数没有对应的虚拟寄存器,或不是需要寄存器的值。" << std::endl;
}
}
if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast<void*>(inst) << ") 的 use_set: " << print_set(use_set) << std::endl;
if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast<void*>(inst) << ") 的 def_set: " << print_set(def_set) << std::endl;
// 计算新的 live_in = use U (new_live_out_calc - def)
std::set<std::string> new_live_in = use_set;
for (const auto& vreg : new_live_out_calc) {
if (def_set.find(vreg) == def_set.end()) { // 如果 vreg 在 new_live_out_calc 中但不在 def 中,则它活跃
if (def_set.find(vreg) == def_set.end()) {
new_live_in.insert(vreg);
}
}
if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast<void*>(inst) << ") 计算出的 new_live_in: " << print_set(new_live_in) << std::endl;
if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast<void*>(inst) << ") 当前 live_in: " << print_set(current_live_in) << ", 当前 live_out: " << print_set(current_live_out) << std::endl;
// 检查收敛
if (new_live_in != current_live_in || new_live_out_calc != current_live_out) { // 注意这里要用 new_live_out_calc 比较
if (new_live_in != current_live_in || new_live_out_calc != current_live_out) {
live_in[inst] = new_live_in;
live_out[inst] = new_live_out_calc; // 更新 live_out
live_out[inst] = new_live_out_calc;
changed = true;
if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast<void*>(inst) << ") 活跃性集合发生变化,更新并继续迭代." << std::endl;
} else {
if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast<void*>(inst) << ") 活跃性集合未发生变化." << std::endl;
}
}
}
@@ -1029,35 +1087,87 @@ std::map<std::string, std::set<std::string>> RISCv32CodeGen::build_interference_
return graph;
}
// 图着色 (简化版,贪婪着色) (基本保持不变)
// 图着色(支持浮点寄存器)
void RISCv32CodeGen::color_graph(std::map<std::string, PhysicalReg>& vreg_to_preg,
const std::map<std::string, std::set<std::string>>& interference_graph) {
vreg_to_preg.clear(); // 清除之前的映射
vreg_to_preg.clear();
// 按度数(从大到小)对虚拟寄存器排序以改进着色效果
// 分离整数和浮点寄存器池
std::vector<PhysicalReg> 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
};
std::vector<PhysicalReg> float_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,
PhysicalReg::F12, PhysicalReg::F13, PhysicalReg::F14, PhysicalReg::F15,
PhysicalReg::F16, PhysicalReg::F17, 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
};
// 确定虚拟寄存器类型(整数或浮点)
auto is_float_vreg = [&](const std::string& vreg) -> bool {
for (const auto& pair : value_vreg_map) {
if (pair.second == vreg) {
if (auto inst = dynamic_cast<Instruction*>(pair.first)) {
if (inst->isUnary()) {
switch (inst->getKind()) {
case Instruction::kFNeg:
case Instruction::kFNot:
case Instruction::kFtoI:
case Instruction::kItoF:
case Instruction::kBitFtoI:
case Instruction::kBitItoF:
return true; // 浮点相关指令
default:
return inst->getType()->isFloat();
}
}
return inst->getType()->isFloat();
} else if (auto constant = dynamic_cast<ConstantValue*>(pair.first)) {
return constant->isFloat();
}
}
}
return false; // 默认整数
};
// 按度数排序虚拟寄存器
std::vector<std::pair<std::string, int>> vreg_degrees;
for (const auto& entry : interference_graph) {
vreg_degrees.push_back({entry.first, (int)entry.second.size()});
}
std::sort(vreg_degrees.begin(), vreg_degrees.end(),
[](const auto& a, const auto& b) { return a.second > b.second; }); // 按度数降序排序
[](const auto& a, const auto& b) { return a.second > b.second; });
for (const auto& vreg_deg_pair : vreg_degrees) {
const std::string& vreg = vreg_deg_pair.first;
std::set<PhysicalReg> used_colors; // 邻居使用的物理寄存器
std::set<PhysicalReg> used_colors;
bool is_float = is_float_vreg(vreg);
// 收集干扰邻居的颜色
// 收集邻居使用的颜色
if (interference_graph.count(vreg)) {
for (const auto& neighbor_vreg : interference_graph.at(vreg)) {
if (vreg_to_preg.count(neighbor_vreg)) { // 只有当邻居已被着色时才考虑
if (vreg_to_preg.count(neighbor_vreg)) {
used_colors.insert(vreg_to_preg.at(neighbor_vreg));
}
}
}
// 查找第一个可用的颜色(物理寄存器
// 选择合适的寄存器
const auto& available_regs = is_float ? float_regs : int_regs;
// 查找第一个可用的寄存器
bool colored = false;
for (PhysicalReg preg : allocable_regs) {
for (PhysicalReg preg : available_regs) {
if (used_colors.find(preg) == used_colors.end()) {
vreg_to_preg[vreg] = preg;
colored = true;
@@ -1066,52 +1176,37 @@ void RISCv32CodeGen::color_graph(std::map<std::string, PhysicalReg>& vreg_to_pre
}
if (!colored) {
// 溢出 (Spilling): 如果没有可用的物理寄存器,这个虚拟寄存器必须溢出到内存。
// 对于这个简化示例,我们没有实现完整的溢出。
// 一个常见的方法是为其分配一个特殊的“溢出”指示符,并在代码生成中处理它。
// 目前,我们只是不为其分配物理寄存器,`get_preg_or_temp` 将使用默认的 `t0` 或触发栈加载/存储。
std::cerr << "警告: 无法为 " << vreg << " 分配寄存器。它很可能会溢出到栈。\n";
// 更完整的编译器会将此虚拟寄存器添加到 `alloc.stack_map` 并在此处管理其栈偏移量。
std::cerr << "警告: 无法为 " << vreg << " 分配" << (is_float ? "浮点" : "整数") << "寄存器,将溢出到栈。\n";
// 溢出处理:在 stack_map 中分配栈空间
// 这里假设每个溢出变量占用 4 字节
// 注意:实际中需要区分整数和浮点溢出的存储指令(如 sw vs fsw
}
}
}
// 寄存器分配
// 寄存器分配(支持浮点寄存器)
RISCv32CodeGen::RegAllocResult RISCv32CodeGen::register_allocation(Function* func) {
// 1. Phi 节点消除 (如果 IR 中有 Phi 节点,需要在活跃性分析前消除)
eliminate_phi(func); // 确保首先调用此函数
// 为每个函数重置计数器和虚拟寄存器映射
eliminate_phi(func);
vreg_counter = 0;
value_vreg_map.clear(); // 为每个函数清除
value_vreg_map.clear();
// FIX: 在进行活跃性分析之前,为所有产生值的指令分配虚拟寄存器
// 这确保了活跃性分析和寄存器分配器有可操作的虚拟寄存器。
// 为所有产生值的指令和操作数分配虚拟寄存器
for (const auto& bb_ptr : func->getBasicBlocks()) {
for (const auto& inst_ptr : bb_ptr->getInstructions()) {
Instruction* inst = inst_ptr.get();
// 如果指令产生一个非 void 的结果,它就需要一个地方来存储这个结果。
// 我们为其分配一个虚拟寄存器。
if (!inst->getType()->isVoid()) {
// 修正:确保 AllocaInst 不在这里分配vreg因为它不占用物理寄存器
if (!dynamic_cast<AllocaInst*>(inst)) { // 排除 AllocaInst
if (value_vreg_map.find(inst) == value_vreg_map.end()) {
value_vreg_map[inst] = "v" + std::to_string(vreg_counter++);
}
if (!inst->getType()->isVoid() && !dynamic_cast<AllocaInst*>(inst)) {
if (value_vreg_map.find(inst) == value_vreg_map.end()) {
value_vreg_map[inst] = "v" + std::to_string(vreg_counter++);
}
}
// 也为常量操作数和全局变量操作数分配vreg以便它们可以参与活跃性分析
for(const auto& operand_use : inst->getOperands()){
for (const auto& operand_use : inst->getOperands()) {
Value* operand = operand_use->getValue();
// 修正:同样排除 AllocaInst 作为操作数
if(dynamic_cast<ConstantValue*>(operand) || dynamic_cast<GlobalValue*>(operand)){
if (value_vreg_map.find(operand) == value_vreg_map.end()) {
if (dynamic_cast<ConstantValue*>(operand) || dynamic_cast<GlobalValue*>(operand)) {
if (value_vreg_map.find(operand) == value_vreg_map.end()) {
value_vreg_map[operand] = "v" + std::to_string(vreg_counter++);
}
} else if (dynamic_cast<Instruction*>(operand) && dynamic_cast<Instruction*>(operand)->getType()->isVoid() == false) {
// 如果操作数是另一个指令的结果且非void确保它也有vreg
// 修正:再次排除 AllocaInst
if (!dynamic_cast<AllocaInst*>(operand)) {
} else if (auto op_inst = dynamic_cast<Instruction*>(operand)) {
if (!op_inst->getType()->isVoid() && !dynamic_cast<AllocaInst*>(operand)) {
if (value_vreg_map.find(operand) == value_vreg_map.end()) {
value_vreg_map[operand] = "v" + std::to_string(vreg_counter++);
}
@@ -1122,11 +1217,9 @@ RISCv32CodeGen::RegAllocResult RISCv32CodeGen::register_allocation(Function* fun
}
RegAllocResult alloc_result;
// 计算 AllocaInst 的栈偏移量
int current_stack_offset = 0; // 相对于 s0 (帧指针)
int current_stack_offset = 0;
std::set<AllocaInst*> allocas_in_func;
for (const auto& bb_ptr : func->getBasicBlocks()) {
for (const auto& inst_ptr : bb_ptr->getInstructions()) {
if (auto alloca = dynamic_cast<AllocaInst*>(inst_ptr.get())) {
@@ -1135,33 +1228,22 @@ RISCv32CodeGen::RegAllocResult RISCv32CodeGen::register_allocation(Function* fun
}
}
// 为 alloca 指令分配栈空间
for (auto alloca : allocas_in_func) {
// 为 4 字节整数 (i32) 分配空间
int size = 4; // 假设 i32如果存在其他类型则调整
int size = 4; // 假设 i32 或 float
alloc_result.stack_map[alloca] = current_stack_offset;
current_stack_offset += size;
}
alloc_result.stack_size = current_stack_offset + 8;
// 确保栈大小是 16 的倍数,并考虑保存的 ra 和 s0
// ra 在 (stack_size - 4)(sp)
// s0 在 (stack_size - 8)(sp)
// 所以最小栈大小必须是 8 + current_stack_offset。
alloc_result.stack_size = current_stack_offset + 8; // 用于 s0 和 ra
// 2. 活跃性分析
// 活跃性分析
std::map<Instruction*, std::set<std::string>> live_sets = liveness_analysis(func);
// 3. 构建干扰图
// 构建干扰图
std::map<std::string, std::set<std::string>> interference_graph = build_interference_graph(live_sets);
// 4. 图着色
// 图着色
color_graph(alloc_result.vreg_to_preg, interference_graph);
// 完整的溢出处理逻辑比较复杂,这里暂时省略。
// 如果一个vreg没有被着色get_preg_or_temp会回退到t0这对于简单情况可能够用。
// 打印寄存器分配结果 (调试用)
if (DEBUG) {
std::cerr << "=== 寄存器分配结果 (vreg_to_preg) ===\n";
for (const auto& pair : alloc_result.vreg_to_preg) {
@@ -1169,7 +1251,6 @@ RISCv32CodeGen::RegAllocResult RISCv32CodeGen::register_allocation(Function* fun
}
std::cerr << "=== 寄存器分配结果结束 ===\n\n";
// 打印活跃性分析结果 (调试用)
std::cerr << "=== 活跃性分析结果 (live_in sets) ===\n";
for (const auto& bb_ptr : func->getBasicBlocks()) {
std::cerr << "Basic Block: " << bb_ptr->getName() << "\n";
@@ -1195,7 +1276,6 @@ RISCv32CodeGen::RegAllocResult RISCv32CodeGen::register_allocation(Function* fun
}
std::cerr << "=== 活跃性分析结果结束 ===\n\n";
// 打印干扰图 (调试用)
std::cerr << "=== 干扰图 ===\n";
for (const auto& pair : interference_graph) {
std::cerr << " " << pair.first << ": {";