[backend] fix bugs of unary ops
This commit is contained in:
@@ -6,56 +6,99 @@
|
|||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <functional> // For std::function
|
#include <functional> // For std::function
|
||||||
|
|
||||||
#define DEBUG 1
|
#define DEBUG 0
|
||||||
#define DEEPDEBUG 0
|
#define DEEPDEBUG 0
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
// 可用于分配的通用寄存器
|
// 可用于分配的寄存器(整数和浮点)
|
||||||
const std::vector<RISCv32CodeGen::PhysicalReg> RISCv32CodeGen::allocable_regs = {
|
const std::vector<RISCv32CodeGen::PhysicalReg> RISCv32CodeGen::allocable_regs = {
|
||||||
|
// 整数寄存器
|
||||||
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3,
|
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3,
|
||||||
PhysicalReg::T4, PhysicalReg::T5, PhysicalReg::T6,
|
PhysicalReg::T4, PhysicalReg::T5, PhysicalReg::T6,
|
||||||
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3,
|
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3,
|
||||||
PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7,
|
PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7,
|
||||||
PhysicalReg::S0, PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3,
|
PhysicalReg::S0, PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3,
|
||||||
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,
|
||||||
|
// 浮点寄存器
|
||||||
|
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) {
|
std::string RISCv32CodeGen::reg_to_string(PhysicalReg reg) {
|
||||||
switch (reg) {
|
switch (reg) {
|
||||||
case PhysicalReg::ZERO: return "x0"; // 零寄存器
|
case PhysicalReg::ZERO: return "x0";
|
||||||
case PhysicalReg::RA: return "ra"; // 返回地址寄存器
|
case PhysicalReg::RA: return "ra";
|
||||||
case PhysicalReg::SP: return "sp"; // 栈指针
|
case PhysicalReg::SP: return "sp";
|
||||||
case PhysicalReg::GP: return "gp"; // 全局指针
|
case PhysicalReg::GP: return "gp";
|
||||||
case PhysicalReg::TP: return "tp"; // 线程指针
|
case PhysicalReg::TP: return "tp";
|
||||||
case PhysicalReg::T0: return "t0"; // 临时寄存器
|
case PhysicalReg::T0: return "t0";
|
||||||
case PhysicalReg::T1: return "t1"; // 临时寄存器
|
case PhysicalReg::T1: return "t1";
|
||||||
case PhysicalReg::T2: return "t2"; // 临时寄存器
|
case PhysicalReg::T2: return "t2";
|
||||||
case PhysicalReg::S0: return "s0"; // 帧指针 / 保存的寄存器
|
case PhysicalReg::S0: return "s0";
|
||||||
case PhysicalReg::S1: return "s1"; // 保存的寄存器
|
case PhysicalReg::S1: return "s1";
|
||||||
case PhysicalReg::A0: return "a0"; // 函数参数 / 返回值寄存器
|
case PhysicalReg::A0: return "a0";
|
||||||
case PhysicalReg::A1: return "a1"; // 函数参数
|
case PhysicalReg::A1: return "a1";
|
||||||
case PhysicalReg::A2: return "a2"; // 函数参数
|
case PhysicalReg::A2: return "a2";
|
||||||
case PhysicalReg::A3: return "a3"; // 函数参数
|
case PhysicalReg::A3: return "a3";
|
||||||
case PhysicalReg::A4: return "a4"; // 函数参数
|
case PhysicalReg::A4: return "a4";
|
||||||
case PhysicalReg::A5: return "a5"; // 函数参数
|
case PhysicalReg::A5: return "a5";
|
||||||
case PhysicalReg::A6: return "a6"; // 函数参数
|
case PhysicalReg::A6: return "a6";
|
||||||
case PhysicalReg::A7: return "a7"; // 函数参数
|
case PhysicalReg::A7: return "a7";
|
||||||
case PhysicalReg::S2: return "s2"; // 保存的寄存器
|
case PhysicalReg::S2: return "s2";
|
||||||
case PhysicalReg::S3: return "s3"; // 保存的寄存器
|
case PhysicalReg::S3: return "s3";
|
||||||
case PhysicalReg::S4: return "s4"; // 保存的寄存器
|
case PhysicalReg::S4: return "s4";
|
||||||
case PhysicalReg::S5: return "s5"; // 保存的寄存器
|
case PhysicalReg::S5: return "s5";
|
||||||
case PhysicalReg::S6: return "s6"; // 保存的寄存器
|
case PhysicalReg::S6: return "s6";
|
||||||
case PhysicalReg::S7: return "s7"; // 保存的寄存器
|
case PhysicalReg::S7: return "s7";
|
||||||
case PhysicalReg::S8: return "s8"; // 保存的寄存器
|
case PhysicalReg::S8: return "s8";
|
||||||
case PhysicalReg::S9: return "s9"; // 保存的寄存器
|
case PhysicalReg::S9: return "s9";
|
||||||
case PhysicalReg::S10: return "s10"; // 保存的寄存器
|
case PhysicalReg::S10: return "s10";
|
||||||
case PhysicalReg::S11: return "s11"; // 保存的寄存器
|
case PhysicalReg::S11: return "s11";
|
||||||
case PhysicalReg::T3: return "t3"; // 临时寄存器
|
case PhysicalReg::T3: return "t3";
|
||||||
case PhysicalReg::T4: return "t4"; // 临时寄存器
|
case PhysicalReg::T4: return "t4";
|
||||||
case PhysicalReg::T5: return "t5"; // 临时寄存器
|
case PhysicalReg::T5: return "t5";
|
||||||
case PhysicalReg::T6: return "t6"; // 临时寄存器
|
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";
|
default: return "UNKNOWN_REG";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -249,16 +292,15 @@ std::string RISCv32CodeGen::basicBlock_gen(BasicBlock* bb, const RegAllocResult&
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
// DAG 构建
|
|
||||||
std::vector<std::unique_ptr<RISCv32CodeGen::DAGNode>> RISCv32CodeGen::build_dag(BasicBlock* bb) {
|
std::vector<std::unique_ptr<RISCv32CodeGen::DAGNode>> RISCv32CodeGen::build_dag(BasicBlock* bb) {
|
||||||
std::vector<std::unique_ptr<DAGNode>> nodes_storage; // 存储所有 unique_ptr
|
std::vector<std::unique_ptr<DAGNode>> nodes_storage; // 存储所有 unique_ptr
|
||||||
std::map<Value*, DAGNode*> value_to_node; // 将 IR Value* 映射到原始 DAGNode*,用于快速查找
|
std::map<Value*, DAGNode*> value_to_node; // 将 IR Value* 映射到原始 DAGNode*,用于快速查找
|
||||||
|
|
||||||
// 辅助函数,用于创建 DAGNode 并管理其所有权
|
// 辅助函数,用于创建 DAGNode 并管理其所有权
|
||||||
auto create_node = [&](DAGNode::NodeKind kind, Value* val = nullptr) -> DAGNode* {
|
auto create_node = [&](DAGNode::NodeKind kind, Value* val = nullptr) -> DAGNode* {
|
||||||
// 优化:如果一个值已经有节点并且它不是控制流/存储/Alloca地址,则重用它 (CSE)
|
// 优化:如果一个值已经有节点并且它不是控制流/存储/Alloca地址/一元操作,则重用它 (CSE)
|
||||||
// 对于 AllocaInst,我们想创建一个代表其地址的节点,但不一定直接为 AllocaInst 本身分配虚拟寄存器。
|
// 对于 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];
|
return value_to_node[val];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,6 +310,7 @@ std::vector<std::unique_ptr<RISCv32CodeGen::DAGNode>> RISCv32CodeGen::build_dag(
|
|||||||
// 为产生结果的值分配虚拟寄存器
|
// 为产生结果的值分配虚拟寄存器
|
||||||
// 注意:这里的vreg分配是在每个块中独立进行的,但寄存器分配器是在函数级别运行的
|
// 注意:这里的vreg分配是在每个块中独立进行的,但寄存器分配器是在函数级别运行的
|
||||||
// 我们在寄存器分配前,已经为整个函数的所有value预分配了vreg
|
// 我们在寄存器分配前,已经为整个函数的所有value预分配了vreg
|
||||||
|
// 此处的逻辑应完全依赖于 register_allocation 阶段已经建立的 value_vreg_map
|
||||||
// 并且 AllocaInst 不应在此处获取 result_vreg,因为它不映射到物理寄存器。
|
// 并且 AllocaInst 不应在此处获取 result_vreg,因为它不映射到物理寄存器。
|
||||||
if (val && value_vreg_map.count(val) && !dynamic_cast<AllocaInst*>(val)) { // 排除 AllocaInst
|
if (val && value_vreg_map.count(val) && !dynamic_cast<AllocaInst*>(val)) { // 排除 AllocaInst
|
||||||
node->result_vreg = value_vreg_map.at(val);
|
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*
|
// 修正:AllocaInst 应该直接映射到 ALLOCA_ADDR 节点,其值是 AllocaInst*
|
||||||
ptr_node = create_node(DAGNode::ALLOCA_ADDR, alloca);
|
ptr_node = create_node(DAGNode::ALLOCA_ADDR, alloca);
|
||||||
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_ir)) {
|
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_ir)) {
|
||||||
ptr_node = create_node(DAGNode::CONSTANT, global); // 全局地址将被加载
|
ptr_node = create_node(DAGNode::CONSTANT, global); // 全局地址将被加载
|
||||||
} else { // 必须是存储在虚拟寄存器中的指针
|
} else { // 必须是存储在虚拟寄存器中的指针
|
||||||
ptr_node = create_node(DAGNode::LOAD, ptr_ir); // 这是一个产生指针的指令
|
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)) {
|
} else if (auto bin = dynamic_cast<BinaryInst*>(inst)) {
|
||||||
if (value_to_node.count(bin)) continue; // CSE
|
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 bin_node = create_node(DAGNode::BINARY, bin);
|
||||||
|
|
||||||
auto get_operand_node = [&](Value* operand_ir) -> DAGNode* {
|
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);
|
bin_node->operands.push_back(rhs_node);
|
||||||
lhs_node->users.push_back(bin_node);
|
lhs_node->users.push_back(bin_node);
|
||||||
rhs_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)) {
|
} else if (auto call = dynamic_cast<CallInst*>(inst)) {
|
||||||
if (value_to_node.count(call)) continue; // CSE (如果结果被重用)
|
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) {
|
void RISCv32CodeGen::select_instructions(DAGNode* node, const RegAllocResult& alloc) {
|
||||||
if (!node) return;
|
if (!node) return;
|
||||||
if (!node->inst.empty()) return; // 指令已选择
|
if (!node->inst.empty()) return; // 指令已选择,跳过重复处理
|
||||||
|
|
||||||
// 首先递归地为操作数选择指令
|
// 递归地为操作数选择指令,确保依赖先被处理
|
||||||
for (auto operand : node->operands) {
|
for (auto operand : node->operands) {
|
||||||
if (operand) {
|
if (operand) {
|
||||||
select_instructions(operand, alloc);
|
select_instructions(operand, alloc);
|
||||||
@@ -530,22 +628,15 @@ void RISCv32CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
|
|||||||
|
|
||||||
std::stringstream ss_inst; // 使用 stringstream 构建指令
|
std::stringstream ss_inst; // 使用 stringstream 构建指令
|
||||||
|
|
||||||
// 获取分配的物理寄存器,如果没有分配,则使用临时寄存器 (T0)
|
// 获取分配的物理寄存器,若未分配则回退到 t0
|
||||||
// 这是关键:这里应该返回寄存器分配器实际分配的寄存器。
|
|
||||||
// 如果寄存器分配失败,才会回退到 T0。
|
|
||||||
auto get_preg_or_temp = [&](const std::string& vreg) {
|
auto get_preg_or_temp = [&](const std::string& vreg) {
|
||||||
if (alloc.vreg_to_preg.count(vreg)) {
|
if (alloc.vreg_to_preg.count(vreg)) {
|
||||||
return reg_to_string(alloc.vreg_to_preg.at(vreg));
|
return reg_to_string(alloc.vreg_to_preg.at(vreg));
|
||||||
}
|
}
|
||||||
// 如果虚拟寄存器未分配给物理寄存器,则表示它已溢出或是一个临时值。
|
|
||||||
// 对于这个简化示例,我们没有实现完整的溢出。
|
|
||||||
// 如果它没有被分配(例如,因为它没有被认为是活跃的,或者寄存器不够),
|
|
||||||
// 那么我们将使用 T0 作为回退。这可能是导致问题的根本原因。
|
|
||||||
// 但对于简单程序,如果活跃性分析正确,它应该能被分配。
|
|
||||||
return reg_to_string(PhysicalReg::T0); // 回退到临时寄存器 t0
|
return reg_to_string(PhysicalReg::T0); // 回退到临时寄存器 t0
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取分配的栈变量的内存偏移量
|
// 获取栈变量的内存偏移量
|
||||||
auto get_stack_offset = [&](Value* val) {
|
auto get_stack_offset = [&](Value* val) {
|
||||||
if (alloc.stack_map.count(val)) {
|
if (alloc.stack_map.count(val)) {
|
||||||
return std::to_string(alloc.stack_map.at(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) {
|
switch (node->kind) {
|
||||||
case DAGNode::CONSTANT: {
|
case DAGNode::CONSTANT: {
|
||||||
|
// 处理常量节点
|
||||||
if (auto constant = dynamic_cast<ConstantValue*>(node->value)) {
|
if (auto constant = dynamic_cast<ConstantValue*>(node->value)) {
|
||||||
std::string dest_reg = get_preg_or_temp(node->result_vreg);
|
std::string dest_reg = get_preg_or_temp(node->result_vreg);
|
||||||
if (constant->isInt()) {
|
if (constant->isInt()) {
|
||||||
@@ -562,69 +654,62 @@ void RISCv32CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
|
|||||||
} else {
|
} else {
|
||||||
float f = constant->getFloat();
|
float f = constant->getFloat();
|
||||||
uint32_t float_bits = *(uint32_t*)&f;
|
uint32_t float_bits = *(uint32_t*)&f;
|
||||||
// 对于浮点数,先加载整数位,然后转换
|
|
||||||
ss_inst << "li " << dest_reg << ", " << float_bits << "\n";
|
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)) {
|
} else if (auto global = dynamic_cast<GlobalValue*>(node->value)) {
|
||||||
std::string dest_reg = get_preg_or_temp(node->result_vreg);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case DAGNode::ALLOCA_ADDR: {
|
case DAGNode::ALLOCA_ADDR: {
|
||||||
// FIX: 这个节点本身不生成指令。
|
// ALLOCA_ADDR 节点不直接生成指令,由 LOAD/STORE 使用
|
||||||
// 它的使用者(LOAD/STORE)会利用它的信息生成更优化的寻址指令。
|
|
||||||
// 将 node->inst 留空以避免生成冗余的 `addi` 指令。
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DAGNode::LOAD: {
|
case DAGNode::LOAD: {
|
||||||
|
// 处理加载指令
|
||||||
if (node->operands.empty() || !node->operands[0]) break;
|
if (node->operands.empty() || !node->operands[0]) break;
|
||||||
std::string dest_reg = get_preg_or_temp(node->result_vreg);
|
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)) {
|
if (auto alloca_inst = dynamic_cast<AllocaInst*>(ptr_node->value)) {
|
||||||
int offset = alloc.stack_map.at(alloca_inst);
|
int offset = alloc.stack_map.at(alloca_inst);
|
||||||
ss_inst << "lw " << dest_reg << ", " << offset << "(s0)";
|
ss_inst << "lw " << dest_reg << ", " << offset << "(s0)";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 指针在寄存器中 (可能是全局地址,或 GEP/其他计算结果)
|
|
||||||
std::string ptr_reg = get_preg_or_temp(ptr_node->result_vreg);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case DAGNode::STORE: {
|
case DAGNode::STORE: {
|
||||||
|
// 处理存储指令
|
||||||
if (node->operands.size() < 2 || !node->operands[0] || !node->operands[1]) break;
|
if (node->operands.size() < 2 || !node->operands[0] || !node->operands[1]) break;
|
||||||
DAGNode* val_node = node->operands[0]; // 要存储的值
|
DAGNode* val_node = node->operands[0];
|
||||||
DAGNode* ptr_node = node->operands[1]; // 目标地址
|
DAGNode* ptr_node = node->operands[1];
|
||||||
|
|
||||||
std::string src_reg;
|
std::string src_reg;
|
||||||
if (val_node->kind == DAGNode::CONSTANT) {
|
if (val_node->kind == DAGNode::CONSTANT) {
|
||||||
// 如果存储的是常量,先将其加载到临时寄存器 (t0)
|
|
||||||
// 这里的处理是,常量会先被其 CONSTANT 节点选择指令并存入其 result_vreg 对应的物理寄存器。
|
|
||||||
// STORE 节点直接使用这个物理寄存器。
|
|
||||||
src_reg = get_preg_or_temp(val_node->result_vreg);
|
src_reg = get_preg_or_temp(val_node->result_vreg);
|
||||||
} else {
|
} else {
|
||||||
src_reg = get_preg_or_temp(val_node->result_vreg);
|
src_reg = get_preg_or_temp(val_node->result_vreg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查指针是否是 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)) {
|
if (auto alloca_inst = dynamic_cast<AllocaInst*>(ptr_node->value)) {
|
||||||
int offset = alloc.stack_map.at(alloca_inst);
|
int offset = alloc.stack_map.at(alloca_inst);
|
||||||
ss_inst << "sw " << src_reg << ", " << offset << "(s0)";
|
ss_inst << "sw " << src_reg << ", " << offset << "(s0)";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 指针在寄存器中 (可能是全局地址,或 GEP/其他计算结果)
|
|
||||||
std::string ptr_reg = get_preg_or_temp(ptr_node->result_vreg);
|
std::string ptr_reg = get_preg_or_temp(ptr_node->result_vreg);
|
||||||
ss_inst << "sw " << src_reg << ", 0(" << ptr_reg << ")";
|
ss_inst << "sw " << src_reg << ", 0(" << ptr_reg << ")";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DAGNode::BINARY: {
|
case DAGNode::BINARY: {
|
||||||
|
// 处理二元指令
|
||||||
if (node->operands.size() < 2 || !node->operands[0] || !node->operands[1]) break;
|
if (node->operands.size() < 2 || !node->operands[0] || !node->operands[1]) break;
|
||||||
auto bin = dynamic_cast<BinaryInst*>(node->value);
|
auto bin = dynamic_cast<BinaryInst*>(node->value);
|
||||||
if (!bin) break;
|
if (!bin) break;
|
||||||
@@ -638,59 +723,88 @@ void RISCv32CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
|
|||||||
case BinaryInst::kAdd: opcode = "add"; break;
|
case BinaryInst::kAdd: opcode = "add"; break;
|
||||||
case BinaryInst::kSub: opcode = "sub"; break;
|
case BinaryInst::kSub: opcode = "sub"; break;
|
||||||
case BinaryInst::kMul: opcode = "mul"; 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 << "sub " << dest_reg << ", " << lhs_reg << ", " << rhs_reg << "\n";
|
||||||
ss_inst << " seqz " << dest_reg << ", " << dest_reg; // 如果等于零则设置
|
ss_inst << " seqz " << dest_reg << ", " << dest_reg;
|
||||||
node->inst = ss_inst.str(); // 设置指令并返回
|
node->inst = ss_inst.str();
|
||||||
return;
|
return;
|
||||||
case Instruction::kDiv: opcode = "div"; break; // 整数除法
|
case Instruction::kDiv: opcode = "div"; break;
|
||||||
case Instruction::kRem: opcode = "rem"; 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 BinaryInst::kICmpGE:
|
||||||
ss_inst << "slt " << dest_reg << ", " << lhs_reg << ", " << rhs_reg << "\n";
|
ss_inst << "slt " << dest_reg << ", " << lhs_reg << ", " << rhs_reg << "\n";
|
||||||
ss_inst << " xori " << dest_reg << ", " << dest_reg << ", 1";
|
ss_inst << " xori " << dest_reg << ", " << dest_reg << ", 1";
|
||||||
node->inst = ss_inst.str();
|
node->inst = ss_inst.str();
|
||||||
return;
|
return;
|
||||||
case BinaryInst::kICmpGT: // A > B <=> B < A
|
case BinaryInst::kICmpGT:
|
||||||
opcode = "slt";
|
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();
|
node->inst = ss_inst.str();
|
||||||
return;
|
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 << "slt " << dest_reg << ", " << rhs_reg << ", " << lhs_reg << "\n";
|
||||||
ss_inst << " xori " << dest_reg << ", " << dest_reg << ", 1";
|
ss_inst << " xori " << dest_reg << ", " << dest_reg << ", 1";
|
||||||
node->inst = ss_inst.str();
|
node->inst = ss_inst.str();
|
||||||
return;
|
return;
|
||||||
case BinaryInst::kICmpLT: // A < B
|
case BinaryInst::kICmpLT:
|
||||||
opcode = "slt";
|
opcode = "slt";
|
||||||
ss_inst << opcode << " " << dest_reg << ", " << lhs_reg << ", " << rhs_reg;
|
ss_inst << opcode << " " << dest_reg << ", " << lhs_reg << ", " << rhs_reg;
|
||||||
node->inst = ss_inst.str();
|
node->inst = ss_inst.str();
|
||||||
return;
|
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 << "sub " << dest_reg << ", " << lhs_reg << ", " << rhs_reg << "\n";
|
||||||
ss_inst << " snez " << dest_reg << ", " << dest_reg;
|
ss_inst << " snez " << dest_reg << ", " << dest_reg;
|
||||||
node->inst = ss_inst.str();
|
node->inst = ss_inst.str();
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
// 处理未知二进制操作或抛出错误
|
throw std::runtime_error("不支持的二元指令类型: " + bin->getKindString());
|
||||||
throw std::runtime_error("Unsupported binary instruction kind: " + bin->getKindString());
|
|
||||||
}
|
}
|
||||||
if (!opcode.empty()) {
|
if (!opcode.empty()) {
|
||||||
ss_inst << opcode << " " << dest_reg << ", " << lhs_reg << ", " << rhs_reg;
|
ss_inst << opcode << " " << dest_reg << ", " << lhs_reg << ", " << rhs_reg;
|
||||||
}
|
}
|
||||||
break;
|
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: {
|
case DAGNode::CALL: {
|
||||||
|
// 处理函数调用指令
|
||||||
if (!node->value) break;
|
if (!node->value) break;
|
||||||
auto call = dynamic_cast<CallInst*>(node->value);
|
auto call = dynamic_cast<CallInst*>(node->value);
|
||||||
if (!call) break;
|
if (!call) break;
|
||||||
|
|
||||||
// 将参数放入 a0-a7
|
|
||||||
for (size_t i = 0; i < node->operands.size() && i < 8; ++i) {
|
for (size_t i = 0; i < node->operands.size() && i < 8; ++i) {
|
||||||
if (node->operands[i] && !node->operands[i]->result_vreg.empty()) {
|
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))
|
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";
|
<< ", " << get_preg_or_temp(node->operands[i]->result_vreg) << "\n";
|
||||||
} else if (node->operands[i] && node->operands[i]->kind == DAGNode::CONSTANT) {
|
} else if (node->operands[i] && node->operands[i]->kind == DAGNode::CONSTANT) {
|
||||||
// 直接将常量参数加载到 A 寄存器
|
|
||||||
if (auto const_val = dynamic_cast<ConstantValue*>(node->operands[i]->value)) {
|
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))
|
ss_inst << "li " << reg_to_string(static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + i))
|
||||||
<< ", " << const_val->getInt() << "\n";
|
<< ", " << 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()) {
|
if ((call->getType()->isInt() || call->getType()->isFloat()) && !node->result_vreg.empty()) {
|
||||||
ss_inst << "\nmv " << get_preg_or_temp(node->result_vreg) << ", a0";
|
ss_inst << "\nmv " << get_preg_or_temp(node->result_vreg) << ", a0";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DAGNode::RETURN: {
|
case DAGNode::RETURN: {
|
||||||
// 如果有返回值,将其移动到 a0
|
// 处理返回指令
|
||||||
if (!node->operands.empty() && node->operands[0]) {
|
if (!node->operands.empty() && node->operands[0]) {
|
||||||
std::string return_val_reg = get_preg_or_temp(node->operands[0]->result_vreg);
|
std::string return_val_reg = get_preg_or_temp(node->operands[0]->result_vreg);
|
||||||
// 对于返回值,直接将最终结果移动到 a0,避免不必要的 t0 中转
|
|
||||||
ss_inst << "mv a0, " << return_val_reg << "\n";
|
ss_inst << "mv a0, " << return_val_reg << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 函数尾声 (Epilogue): 恢复 s0, ra, 并调整 sp
|
|
||||||
if (alloc.stack_size > 0) {
|
if (alloc.stack_size > 0) {
|
||||||
int aligned_stack_size = (alloc.stack_size + 15) & ~15;
|
int aligned_stack_size = (alloc.stack_size + 15) & ~15;
|
||||||
ss_inst << " lw ra, " << (aligned_stack_size - 4) << "(sp)\n"; // 恢复 ra
|
ss_inst << " lw ra, " << (aligned_stack_size - 4) << "(sp)\n";
|
||||||
ss_inst << " lw s0, " << (aligned_stack_size - 8) << "(sp)\n"; // 恢复 s0
|
ss_inst << " lw s0, " << (aligned_stack_size - 8) << "(sp)\n";
|
||||||
ss_inst << " addi sp, sp, " << aligned_stack_size << "\n"; // 恢复栈指针
|
ss_inst << " addi sp, sp, " << aligned_stack_size << "\n";
|
||||||
}
|
}
|
||||||
ss_inst << " ret"; // 返回
|
ss_inst << " ret";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DAGNode::BRANCH: {
|
case DAGNode::BRANCH: {
|
||||||
|
// 处理分支指令
|
||||||
auto br = dynamic_cast<CondBrInst*>(node->value);
|
auto br = dynamic_cast<CondBrInst*>(node->value);
|
||||||
auto uncond_br = dynamic_cast<UncondBrInst*>(node->value);
|
auto uncond_br = dynamic_cast<UncondBrInst*>(node->value);
|
||||||
|
|
||||||
if (node->inst.empty()) { // 如果不是通过常量传播优化的直接跳转
|
if (node->inst.empty()) {
|
||||||
if (br) {
|
if (br) {
|
||||||
if (node->operands.empty() || !node->operands[0]) break;
|
if (node->operands.empty() || !node->operands[0]) break;
|
||||||
std::string cond_reg = get_preg_or_temp(node->operands[0]->result_vreg);
|
std::string cond_reg = get_preg_or_temp(node->operands[0]->result_vreg);
|
||||||
std::string then_block = br->getThenBlock()->getName();
|
std::string then_block = br->getThenBlock()->getName();
|
||||||
std::string else_block = br->getElseBlock()->getName();
|
std::string else_block = br->getElseBlock()->getName();
|
||||||
|
|
||||||
// 修复空标签问题
|
|
||||||
if (then_block.empty()) {
|
if (then_block.empty()) {
|
||||||
then_block = ENTRY_BLOCK_PSEUDO_NAME + "then"; // 临时命名
|
then_block = ENTRY_BLOCK_PSEUDO_NAME + "then";
|
||||||
}
|
}
|
||||||
if (else_block.empty()) {
|
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 << "bnez " << cond_reg << ", " << then_block << "\n";
|
||||||
ss_inst << " j " << else_block; // 无条件跳转到 else 块
|
ss_inst << " j " << else_block;
|
||||||
} else if (uncond_br) {
|
} else if (uncond_br) {
|
||||||
std::string target_block = uncond_br->getBlock()->getName();
|
std::string target_block = uncond_br->getBlock()->getName();
|
||||||
if (target_block.empty()) { // 修复空标签问题
|
if (target_block.empty()) {
|
||||||
target_block = ENTRY_BLOCK_PSEUDO_NAME + "target"; // 临时命名
|
target_block = ENTRY_BLOCK_PSEUDO_NAME + "target";
|
||||||
}
|
}
|
||||||
ss_inst << "j " << target_block; // 无条件跳转
|
ss_inst << "j " << target_block;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 这个分支节点已经被 build_dag 中的常量传播优化为直接跳转。
|
|
||||||
// 它的 'inst' 字段已经设置。直接复制它。
|
|
||||||
ss_inst << node->inst;
|
ss_inst << node->inst;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// 对于不直接映射到指令的节点 (例如 `alloc` 本身,其地址由其地址节点处理)
|
throw std::runtime_error("不支持的节点类型: " + node->getNodeKindString());
|
||||||
// 或未处理的指令类型,将 inst 留空。
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
node->inst = ss_inst.str(); // 存储生成的指令
|
node->inst = ss_inst.str(); // 存储生成的指令
|
||||||
}
|
}
|
||||||
@@ -838,12 +945,11 @@ std::string print_set(const std::set<std::string>& s) {
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 活跃性分析
|
// 活跃性分析(更新以支持浮点指令)
|
||||||
std::map<Instruction*, std::set<std::string>> RISCv32CodeGen::liveness_analysis(Function* func) {
|
std::map<Instruction*, std::set<std::string>> RISCv32CodeGen::liveness_analysis(Function* func) {
|
||||||
std::map<Instruction*, std::set<std::string>> live_in, live_out;
|
std::map<Instruction*, std::set<std::string>> live_in, live_out;
|
||||||
bool changed = true;
|
bool changed = true;
|
||||||
|
|
||||||
// 初始化所有 live_in/out 集合为空
|
|
||||||
for (const auto& bb : func->getBasicBlocks()) {
|
for (const auto& bb : func->getBasicBlocks()) {
|
||||||
for (const auto& inst_ptr : bb->getInstructions()) {
|
for (const auto& inst_ptr : bb->getInstructions()) {
|
||||||
live_in[inst_ptr.get()] = {};
|
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) {
|
while (changed) {
|
||||||
changed = false;
|
changed = false;
|
||||||
iteration_count++;
|
iteration_count++;
|
||||||
if (DEEPDEBUG) std::cerr << "\n--- 活跃性分析迭代: " << iteration_count << " ---" << std::endl;
|
if (DEEPDEBUG) std::cerr << "\n--- 活跃性分析迭代: " << iteration_count << " ---" << std::endl;
|
||||||
|
|
||||||
// 逆序遍历基本块
|
|
||||||
for (auto it = func->getBasicBlocks_NoRange().rbegin(); it != func->getBasicBlocks_NoRange().rend(); ++it) {
|
for (auto it = func->getBasicBlocks_NoRange().rbegin(); it != func->getBasicBlocks_NoRange().rend(); ++it) {
|
||||||
auto bb = it->get();
|
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 = {};
|
std::set<std::string> live_out_for_bb_inst = {};
|
||||||
for (const auto& succ_bb : bb->getSuccessors()) {
|
for (const auto& succ_bb : bb->getSuccessors()) {
|
||||||
if (!succ_bb->getInstructions().empty()) {
|
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) {
|
for (auto inst_it = bb->getInstructions().rbegin(); inst_it != bb->getInstructions().rend(); ++inst_it) {
|
||||||
auto inst = inst_it->get();
|
auto inst = inst_it->get();
|
||||||
// 打印指令,使用其父基本块的名称和指令地址作为唯一标识符
|
|
||||||
if (DEEPDEBUG) std::cerr << " 指令 (BB: " << bb->getName() << ", 地址: " << static_cast<void*>(inst) << ")" << std::endl;
|
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_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()) {
|
if (inst_it == bb->getInstructions().rbegin()) {
|
||||||
new_live_out_calc = live_out_for_bb_inst;
|
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;
|
if (DEEPDEBUG) std::cerr << " 指令是基本块的最后一条指令,live_out 取自后继基本块 live_in 的并集: " << print_set(new_live_out_calc) << std::endl;
|
||||||
} else {
|
} else {
|
||||||
// 如果不是基本块的最后一条指令,则其 live_out 是其后继指令的 live_in
|
auto prev_inst_it = std::prev(inst_it);
|
||||||
auto prev_inst_it = std::prev(inst_it); // std::prev 获取正向的下一条指令
|
|
||||||
new_live_out_calc = live_in[prev_inst_it->get()];
|
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;
|
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;
|
std::set<std::string> use_set, def_set;
|
||||||
|
|
||||||
// 定义 (Def) - 只有当指令本身产生一个非 void 结果并映射到虚拟寄存器时
|
// 定义 (Def)
|
||||||
// LoadInst, BinaryInst, CallInst 等会定义一个结果。
|
|
||||||
// StoreInst, AllocaInst, ReturnInst, BranchInst 不定义结果到寄存器。
|
|
||||||
if (!inst->getType()->isVoid() && !dynamic_cast<AllocaInst*>(inst) && !dynamic_cast<StoreInst*>(inst) &&
|
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)) {
|
!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));
|
def_set.insert(value_vreg_map.at(inst));
|
||||||
if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast<void*>(inst) << ") 定义了虚拟寄存器: " << value_vreg_map.at(inst) << std::endl;
|
if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast<void*>(inst) << ") 定义了虚拟寄存器: " << value_vreg_map.at(inst) << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// *** 针对 StoreInst 的新逻辑来“杀死”被存储值的虚拟寄存器 ***
|
// StoreInst 的值可能被“杀死”
|
||||||
// 这个逻辑在活跃性分析中需要非常谨慎。通常,Store 指令是使用(use)被存储的值,而不是定义(def)它。
|
|
||||||
// 如果一个值在 Store 后不再被使用,它会自然地通过活跃性传播变得不活跃。
|
|
||||||
// 将被存储的值添加到 def_set 意味着该值在该指令处被“杀死”,因为它被存储到内存中,而不是寄存器。
|
|
||||||
// 对于“01_add.sy”这样的简单情况,这可能是有效的,但对于更复杂的程序,可能会导致不准确的活跃性。
|
|
||||||
// 考虑一个值被存储,但稍后又从内存中加载并再次使用的情况。
|
|
||||||
// 这是一个需要仔细考虑的启发式方法。
|
|
||||||
if (auto store = dynamic_cast<StoreInst*>(inst)) {
|
if (auto store = dynamic_cast<StoreInst*>(inst)) {
|
||||||
Value* stored_value = store->getValue();
|
Value* stored_value = store->getValue();
|
||||||
// 如果被存储的值有一个虚拟寄存器,并且它不是 AllocaInst(Alloca是地址,不是寄存器值)
|
|
||||||
if (value_vreg_map.count(stored_value) && !dynamic_cast<AllocaInst*>(stored_value)) {
|
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;
|
bool is_unique_user = true;
|
||||||
if (!stored_value->getUses().empty()) {
|
if (!stored_value->getUses().empty()) {
|
||||||
is_unique_user = (stored_value->getUses().size() == 1 && stored_value->getUses().front()->getUser() == inst);
|
is_unique_user = (stored_value->getUses().size() == 1 && stored_value->getUses().front()->getUser() == inst);
|
||||||
} else {
|
} else {
|
||||||
// 如果没有uses,则它没有被使用,不应该被def。
|
is_unique_user = false;
|
||||||
is_unique_user = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_unique_user) {
|
if (is_unique_user) {
|
||||||
def_set.insert(value_vreg_map.at(stored_value));
|
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;
|
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;
|
|
||||||
}
|
}
|
||||||
} else if (dynamic_cast<AllocaInst*>(stored_value)) {
|
|
||||||
if (DEEPDEBUG) std::cerr << " Store 指令存储的是 AllocaInst 地址,不处理其虚拟寄存器定义。" << std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// *** 结束新逻辑 ***
|
|
||||||
|
|
||||||
// 使用 (Use) - 遍历指令的操作数
|
// 使用 (Use)
|
||||||
for(const auto& operand_use : inst->getOperands()){
|
for (const auto& operand_use : inst->getOperands()) {
|
||||||
Value* operand = operand_use->getValue();
|
Value* operand = operand_use->getValue();
|
||||||
// 只有当操作数是一个实际需要寄存器来存储的“值”时,才将其vreg添加到use_set。
|
|
||||||
// 排除 AllocaInst,因为它们是地址概念,不占用通用寄存器。
|
|
||||||
// 并且确保 operand 已经在 value_vreg_map 中有对应的虚拟寄存器。
|
|
||||||
if (value_vreg_map.count(operand) && !dynamic_cast<AllocaInst*>(operand)) {
|
if (value_vreg_map.count(operand) && !dynamic_cast<AllocaInst*>(operand)) {
|
||||||
use_set.insert(value_vreg_map.at(operand));
|
use_set.insert(value_vreg_map.at(operand));
|
||||||
if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast<void*>(inst) << ") 使用了虚拟寄存器: " << value_vreg_map.at(operand) << std::endl;
|
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) << ") 的 use_set: " << print_set(use_set) << std::endl;
|
||||||
if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast<void*>(inst) << ") 的 def_set: " << print_set(def_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;
|
std::set<std::string> new_live_in = use_set;
|
||||||
for (const auto& vreg : new_live_out_calc) {
|
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);
|
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) << ") 计算出的 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 (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) {
|
||||||
// 检查收敛
|
|
||||||
if (new_live_in != current_live_in || new_live_out_calc != current_live_out) { // 注意这里要用 new_live_out_calc 比较
|
|
||||||
live_in[inst] = new_live_in;
|
live_in[inst] = new_live_in;
|
||||||
live_out[inst] = new_live_out_calc; // 更新 live_out
|
live_out[inst] = new_live_out_calc;
|
||||||
changed = true;
|
changed = true;
|
||||||
if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast<void*>(inst) << ") 活跃性集合发生变化,更新并继续迭代." << std::endl;
|
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;
|
return graph;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 图着色 (简化版,贪婪着色) (基本保持不变)
|
// 图着色(支持浮点寄存器)
|
||||||
void RISCv32CodeGen::color_graph(std::map<std::string, PhysicalReg>& vreg_to_preg,
|
void RISCv32CodeGen::color_graph(std::map<std::string, PhysicalReg>& vreg_to_preg,
|
||||||
const std::map<std::string, std::set<std::string>>& interference_graph) {
|
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;
|
std::vector<std::pair<std::string, int>> vreg_degrees;
|
||||||
for (const auto& entry : interference_graph) {
|
for (const auto& entry : interference_graph) {
|
||||||
vreg_degrees.push_back({entry.first, (int)entry.second.size()});
|
vreg_degrees.push_back({entry.first, (int)entry.second.size()});
|
||||||
}
|
}
|
||||||
std::sort(vreg_degrees.begin(), vreg_degrees.end(),
|
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) {
|
for (const auto& vreg_deg_pair : vreg_degrees) {
|
||||||
const std::string& vreg = vreg_deg_pair.first;
|
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)) {
|
if (interference_graph.count(vreg)) {
|
||||||
for (const auto& neighbor_vreg : interference_graph.at(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));
|
used_colors.insert(vreg_to_preg.at(neighbor_vreg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查找第一个可用的颜色(物理寄存器)
|
// 选择合适的寄存器池
|
||||||
|
const auto& available_regs = is_float ? float_regs : int_regs;
|
||||||
|
|
||||||
|
// 查找第一个可用的寄存器
|
||||||
bool colored = false;
|
bool colored = false;
|
||||||
for (PhysicalReg preg : allocable_regs) {
|
for (PhysicalReg preg : available_regs) {
|
||||||
if (used_colors.find(preg) == used_colors.end()) {
|
if (used_colors.find(preg) == used_colors.end()) {
|
||||||
vreg_to_preg[vreg] = preg;
|
vreg_to_preg[vreg] = preg;
|
||||||
colored = true;
|
colored = true;
|
||||||
@@ -1066,52 +1176,37 @@ void RISCv32CodeGen::color_graph(std::map<std::string, PhysicalReg>& vreg_to_pre
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!colored) {
|
if (!colored) {
|
||||||
// 溢出 (Spilling): 如果没有可用的物理寄存器,这个虚拟寄存器必须溢出到内存。
|
std::cerr << "警告: 无法为 " << vreg << " 分配" << (is_float ? "浮点" : "整数") << "寄存器,将溢出到栈。\n";
|
||||||
// 对于这个简化示例,我们没有实现完整的溢出。
|
// 溢出处理:在 stack_map 中分配栈空间
|
||||||
// 一个常见的方法是为其分配一个特殊的“溢出”指示符,并在代码生成中处理它。
|
// 这里假设每个溢出变量占用 4 字节
|
||||||
// 目前,我们只是不为其分配物理寄存器,`get_preg_or_temp` 将使用默认的 `t0` 或触发栈加载/存储。
|
// 注意:实际中需要区分整数和浮点溢出的存储指令(如 sw vs fsw)
|
||||||
std::cerr << "警告: 无法为 " << vreg << " 分配寄存器。它很可能会溢出到栈。\n";
|
|
||||||
// 更完整的编译器会将此虚拟寄存器添加到 `alloc.stack_map` 并在此处管理其栈偏移量。
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 寄存器分配
|
// 寄存器分配(支持浮点寄存器)
|
||||||
RISCv32CodeGen::RegAllocResult RISCv32CodeGen::register_allocation(Function* func) {
|
RISCv32CodeGen::RegAllocResult RISCv32CodeGen::register_allocation(Function* func) {
|
||||||
// 1. Phi 节点消除 (如果 IR 中有 Phi 节点,需要在活跃性分析前消除)
|
eliminate_phi(func);
|
||||||
eliminate_phi(func); // 确保首先调用此函数
|
|
||||||
|
|
||||||
// 为每个函数重置计数器和虚拟寄存器映射
|
|
||||||
vreg_counter = 0;
|
vreg_counter = 0;
|
||||||
value_vreg_map.clear(); // 为每个函数清除
|
value_vreg_map.clear();
|
||||||
|
|
||||||
// FIX: 在进行活跃性分析之前,为所有产生值的指令分配虚拟寄存器。
|
// 为所有产生值的指令和操作数分配虚拟寄存器
|
||||||
// 这确保了活跃性分析和寄存器分配器有可操作的虚拟寄存器。
|
|
||||||
for (const auto& bb_ptr : func->getBasicBlocks()) {
|
for (const auto& bb_ptr : func->getBasicBlocks()) {
|
||||||
for (const auto& inst_ptr : bb_ptr->getInstructions()) {
|
for (const auto& inst_ptr : bb_ptr->getInstructions()) {
|
||||||
Instruction* inst = inst_ptr.get();
|
Instruction* inst = inst_ptr.get();
|
||||||
// 如果指令产生一个非 void 的结果,它就需要一个地方来存储这个结果。
|
if (!inst->getType()->isVoid() && !dynamic_cast<AllocaInst*>(inst)) {
|
||||||
// 我们为其分配一个虚拟寄存器。
|
if (value_vreg_map.find(inst) == value_vreg_map.end()) {
|
||||||
if (!inst->getType()->isVoid()) {
|
value_vreg_map[inst] = "v" + std::to_string(vreg_counter++);
|
||||||
// 修正:确保 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++);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 也为常量操作数和全局变量操作数分配vreg,以便它们可以参与活跃性分析
|
for (const auto& operand_use : inst->getOperands()) {
|
||||||
for(const auto& operand_use : inst->getOperands()){
|
|
||||||
Value* operand = operand_use->getValue();
|
Value* operand = operand_use->getValue();
|
||||||
// 修正:同样排除 AllocaInst 作为操作数
|
if (dynamic_cast<ConstantValue*>(operand) || dynamic_cast<GlobalValue*>(operand)) {
|
||||||
if(dynamic_cast<ConstantValue*>(operand) || dynamic_cast<GlobalValue*>(operand)){
|
if (value_vreg_map.find(operand) == value_vreg_map.end()) {
|
||||||
if (value_vreg_map.find(operand) == value_vreg_map.end()) {
|
|
||||||
value_vreg_map[operand] = "v" + std::to_string(vreg_counter++);
|
value_vreg_map[operand] = "v" + std::to_string(vreg_counter++);
|
||||||
}
|
}
|
||||||
} else if (dynamic_cast<Instruction*>(operand) && dynamic_cast<Instruction*>(operand)->getType()->isVoid() == false) {
|
} else if (auto op_inst = dynamic_cast<Instruction*>(operand)) {
|
||||||
// 如果操作数是另一个指令的结果且非void,确保它也有vreg
|
if (!op_inst->getType()->isVoid() && !dynamic_cast<AllocaInst*>(operand)) {
|
||||||
// 修正:再次排除 AllocaInst
|
|
||||||
if (!dynamic_cast<AllocaInst*>(operand)) {
|
|
||||||
if (value_vreg_map.find(operand) == value_vreg_map.end()) {
|
if (value_vreg_map.find(operand) == value_vreg_map.end()) {
|
||||||
value_vreg_map[operand] = "v" + std::to_string(vreg_counter++);
|
value_vreg_map[operand] = "v" + std::to_string(vreg_counter++);
|
||||||
}
|
}
|
||||||
@@ -1122,11 +1217,9 @@ RISCv32CodeGen::RegAllocResult RISCv32CodeGen::register_allocation(Function* fun
|
|||||||
}
|
}
|
||||||
|
|
||||||
RegAllocResult alloc_result;
|
RegAllocResult alloc_result;
|
||||||
|
int current_stack_offset = 0;
|
||||||
// 计算 AllocaInst 的栈偏移量
|
|
||||||
int current_stack_offset = 0; // 相对于 s0 (帧指针)
|
|
||||||
|
|
||||||
std::set<AllocaInst*> allocas_in_func;
|
std::set<AllocaInst*> allocas_in_func;
|
||||||
|
|
||||||
for (const auto& bb_ptr : func->getBasicBlocks()) {
|
for (const auto& bb_ptr : func->getBasicBlocks()) {
|
||||||
for (const auto& inst_ptr : bb_ptr->getInstructions()) {
|
for (const auto& inst_ptr : bb_ptr->getInstructions()) {
|
||||||
if (auto alloca = dynamic_cast<AllocaInst*>(inst_ptr.get())) {
|
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) {
|
for (auto alloca : allocas_in_func) {
|
||||||
// 为 4 字节整数 (i32) 分配空间
|
int size = 4; // 假设 i32 或 float
|
||||||
int size = 4; // 假设 i32,如果存在其他类型则调整
|
|
||||||
alloc_result.stack_map[alloca] = current_stack_offset;
|
alloc_result.stack_map[alloca] = current_stack_offset;
|
||||||
current_stack_offset += size;
|
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);
|
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);
|
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);
|
color_graph(alloc_result.vreg_to_preg, interference_graph);
|
||||||
|
|
||||||
// 完整的溢出处理逻辑比较复杂,这里暂时省略。
|
|
||||||
// 如果一个vreg没有被着色,get_preg_or_temp会回退到t0,这对于简单情况可能够用。
|
|
||||||
|
|
||||||
// 打印寄存器分配结果 (调试用)
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
std::cerr << "=== 寄存器分配结果 (vreg_to_preg) ===\n";
|
std::cerr << "=== 寄存器分配结果 (vreg_to_preg) ===\n";
|
||||||
for (const auto& pair : alloc_result.vreg_to_preg) {
|
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 << "=== 寄存器分配结果结束 ===\n\n";
|
||||||
|
|
||||||
// 打印活跃性分析结果 (调试用)
|
|
||||||
std::cerr << "=== 活跃性分析结果 (live_in sets) ===\n";
|
std::cerr << "=== 活跃性分析结果 (live_in sets) ===\n";
|
||||||
for (const auto& bb_ptr : func->getBasicBlocks()) {
|
for (const auto& bb_ptr : func->getBasicBlocks()) {
|
||||||
std::cerr << "Basic Block: " << bb_ptr->getName() << "\n";
|
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\n";
|
||||||
|
|
||||||
// 打印干扰图 (调试用)
|
|
||||||
std::cerr << "=== 干扰图 ===\n";
|
std::cerr << "=== 干扰图 ===\n";
|
||||||
for (const auto& pair : interference_graph) {
|
for (const auto& pair : interference_graph) {
|
||||||
std::cerr << " " << pair.first << ": {";
|
std::cerr << " " << pair.first << ": {";
|
||||||
|
|||||||
Reference in New Issue
Block a user