From b2b88ee5112ec8ade3a3274cb04c33a94aeea368 Mon Sep 17 00:00:00 2001 From: Lixuanwang Date: Tue, 24 Jun 2025 05:02:11 +0800 Subject: [PATCH] [backend-beta] saving for simpler implementation for register allocation --- src/RISCv32Backend.cpp | 1423 ++++++++++++++-------------------------- src/RISCv32Backend.h | 73 ++- 2 files changed, 523 insertions(+), 973 deletions(-) diff --git a/src/RISCv32Backend.cpp b/src/RISCv32Backend.cpp index 1d8d917..5eb4c2b 100644 --- a/src/RISCv32Backend.cpp +++ b/src/RISCv32Backend.cpp @@ -1,1073 +1,618 @@ #include "RISCv32Backend.h" #include #include -#include -#include -#include -#include // For std::function +#include -#define DEBUG 0 namespace sysy { -// 可用于分配的通用寄存器 -const std::vector 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 -}; - -// 将物理寄存器枚举转换为字符串 -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"; // 临时寄存器 - default: return "UNKNOWN_REG"; - } -} - -// 总体代码生成入口 std::string RISCv32CodeGen::code_gen() { std::stringstream ss; + ss << ".text\n"; ss << module_gen(); return ss.str(); } -// 模块级代码生成 (处理全局变量和函数) std::string RISCv32CodeGen::module_gen() { std::stringstream ss; - bool has_globals = !module->getGlobals().empty(); - if (has_globals) { - ss << ".data\n"; // 数据段 - for (const auto& global : module->getGlobals()) { - ss << ".globl " << global->getName() << "\n"; // 声明全局符号 - ss << global->getName() << ":\n"; // 标签 - const auto& init_values = global->getInitValues(); - for (size_t i = 0; i < init_values.getValues().size(); ++i) { - auto val = init_values.getValues()[i]; - auto count = init_values.getNumbers()[i]; - if (auto constant = dynamic_cast(val)) { - for (unsigned j = 0; j < count; ++j) { - if (constant->isInt()) { - ss << " .word " << constant->getInt() << "\n"; // 整数常量 - } else { - float f = constant->getFloat(); - uint32_t float_bits = *(uint32_t*)&f; - ss << " .word " << float_bits << "\n"; // 浮点常量 (按位存储) - } - } - } + for (auto& global : module->getGlobals()) { + ss << ".global " << global->getName() << "\n"; + ss << ".section .data\n"; + ss << ".align 2\n"; + ss << global->getName() << ":\n"; + for (auto value : global->getInitValues().getValues()) { + auto const_val = dynamic_cast(value); + if (const_val->isInt()) { + ss << ".word " << const_val->getInt() << "\n"; + } else { + ss << ".float " << const_val->getFloat() << "\n"; } } } - if (!module->getFunctions().empty()) { - ss << ".text\n"; // 代码段 - for (const auto& func : module->getFunctions()) { - ss << function_gen(func.second.get()); - } + ss << ".section .text\n"; + for (auto& func : module->getFunctions()) { + ss << function_gen(func.second.get()); } return ss.str(); } -// 函数级代码生成 std::string RISCv32CodeGen::function_gen(Function* func) { std::stringstream ss; - ss << ".globl " << func->getName() << "\n"; // 声明函数为全局符号 - ss << func->getName() << ":\n"; // 函数入口标签 + ss << ".global " << func->getName() << "\n"; + ss << ".type " << func->getName() << ", @function\n"; + ss << func->getName() << ":\n"; - // 执行寄存器分配 - auto alloc = register_allocation(func); - int stack_size = alloc.stack_size; + // Perform register allocation + auto live_sets = liveness_analysis(func); + auto interference_graph = build_interference_graph(live_sets); + auto alloc = color_graph(func, interference_graph); - // 函数序言 (Prologue) - // 保存 ra 和 s0, 调整栈指针 - // s0 指向当前帧的底部(分配局部变量/溢出空间后的 sp) - // 栈布局: - // +------------+ 高地址 - // | 参数溢出 | (如果参数超过 8 个) - // +------------+ - // | 保存的 RA | (stack_size - 4)(sp) - // +------------+ - // | 保存的 S0 | (stack_size - 8)(sp) - // +------------+ - // | 局部变量/溢出 | 0(sp) 到 (stack_size - 8 - 局部变量大小)(sp) - // +------------+ 低地址 - // 确保栈大小 16 字节对齐 - int aligned_stack_size = (stack_size + 15) & ~15; - - // 只有当需要栈空间时才生成序言 - if (aligned_stack_size > 0) { - ss << " addi sp, sp, -" << aligned_stack_size << "\n"; // 调整栈指针 - ss << " sw ra, " << (aligned_stack_size - 4) << "(sp)\n"; // 保存返回地址 - ss << " sw s0, " << (aligned_stack_size - 8) << "(sp)\n"; // 保存帧指针 - ss << " mv s0, sp\n"; // 设置新的帧指针 + // Prologue: Adjust stack and save callee-saved registers + if (alloc.stack_size > 0) { + ss << " addi sp, sp, -" << alloc.stack_size << "\n"; + ss << " sw ra, " << (alloc.stack_size - 4) << "(sp)\n"; + } + for (auto preg : callee_saved) { + if (std::find_if(alloc.vreg_to_preg.begin(), alloc.vreg_to_preg.end(), + [preg](const auto& pair) { return pair.second == preg; }) != alloc.vreg_to_preg.end()) { + ss << " sw " << get_preg_str(preg) << ", " << (alloc.stack_size - 8) << "(sp)\n"; + } } - // 生成每个基本块的代码 - int block_idx = 0; // 用于生成默认 entry 标签的索引 - for (const auto& bb : func->getBasicBlocks()) { + int block_idx = 0; + for (auto& bb : func->getBasicBlocks()) { ss << basicBlock_gen(bb.get(), alloc, block_idx++); } - // 函数尾声 (Epilogue) 由 RETURN DAGNode 的指令选择处理,确保正确恢复栈和寄存器 + // Epilogue: Restore callee-saved registers and stack + for (auto preg : callee_saved) { + if (std::find_if(alloc.vreg_to_preg.begin(), alloc.vreg_to_preg.end(), + [preg](const auto& pair) { return pair.second == preg; }) != alloc.vreg_to_preg.end()) { + ss << " lw " << get_preg_str(preg) << ", " << (alloc.stack_size - 8) << "(sp)\n"; + } + } + if (alloc.stack_size > 0) { + ss << " lw ra, " << (alloc.stack_size - 4) << "(sp)\n"; + ss << " addi sp, sp, " << alloc.stack_size << "\n"; + } + ss << " ret\n"; return ss.str(); } -// 基本块代码生成 std::string RISCv32CodeGen::basicBlock_gen(BasicBlock* bb, const RegAllocResult& alloc, int block_idx) { std::stringstream ss; - - // 修复空标签问题:如果块名为空,使用伪名称 (例如 entry_block_0) - std::string bb_name = bb->getName(); - if (bb_name.empty()) { - bb_name = ENTRY_BLOCK_PSEUDO_NAME + std::to_string(block_idx); - // 如果是第一个块,且没有名称,则通常是函数入口块,可以考虑直接使用 "entry" - // 但为了通用性,伪名称更安全 - if (block_idx == 0) { // 第一个块通常是 entry 块 - bb_name = "entry"; - } + ss << ".L" << block_idx << ":\n"; + auto dag_nodes = build_dag(bb); + for (auto& node : dag_nodes) { + select_instructions(node.get(), alloc); } - ss << bb_name << ":\n"; // 基本块标签 - - // 为每个基本块重置虚拟寄存器映射和计数器,因为 DAG 是按块构建的 - // 注意:这里的重置可能会影响跨块的活跃性分析,如果 DAG 构建是跨块的,则不能在这里重置 - // 但目前 DAG 是按块构建,所以在此重置是合理的。 - value_vreg_map.clear(); - vreg_counter = 0; // 为每个块重置虚拟寄存器计数器 - - // 构建当前基本块的 DAG - // 注意:DAGNode 的唯一性在当前函数范围内是重要的, - // 所以 build_dag 应该返回一个完整的 DAG 节点列表,而不是每次都创建新的。 - // 为了简化,这里仍然按块构建,但需要注意跨块值的使用。 - auto dag_nodes_for_bb = build_dag(bb); - if (DEBUG) - print_dag(dag_nodes_for_bb, bb_name); // 打印 DAG 调试信息 - - // 存储最终生成的指令 - std::set emitted_nodes; // 跟踪已发射的节点,防止重复 - std::vector ordered_insts; // 用于收集指令并按序排列 - - // 在 DAG 中遍历并生成指令。由于 select_instructions 可能会递归地为操作数选择指令, - // 并且 emit_instructions 也会递归地发射,我们需要一个机制来确保指令的正确顺序和唯一性。 - // 最简单的方法是逆拓扑序遍历所有节点,确保其操作数先被处理。 - // 但是目前的 DAG 构建方式可能不支持直接的拓扑排序, - // 我们将依赖 emit_instructions 的递归特性来处理依赖。 - - // 遍历 DAG 的根节点(没有用户的节点,或者 Store/Return/Branch 节点) - // 从这些节点开始递归发射指令。 - // NOTE: 这种发射方式可能不总是产生最优的代码顺序,但可以确保依赖关系。 - for (auto it = dag_nodes_for_bb.rbegin(); it != dag_nodes_for_bb.rend(); ++it) { - DAGNode* node = it->get(); - // 只有那些没有用户(或者代表副作用,如STORE, RETURN, BRANCH)的节点才需要作为发射的“根” - // 否则,它们会被其用户节点递归地发射 - // 然而,为了确保所有指令都被发射,我们通常从所有节点(或者至少是副作用节点)开始发射 - // 并且利用 emitted_nodes 集合防止重复 - // 这里简化为对所有 DAG 节点进行一次 select_instructions 和 emit_instructions 调用。 - // emit_instructions 会通过递归处理其操作数来保证依赖顺序。 - select_instructions(node, alloc); // 为当前节点选择指令 + std::set emitted_nodes; + for (auto& node : dag_nodes) { + emit_instructions(node.get(), ss, alloc, emitted_nodes); } - - // 收集所有指令到一个临时的 vector 中,然后进行排序 - // 注意:这里的发射逻辑需要重新设计,目前的 emit_instructions 是直接添加到 std::vector& insts 中 - // 并且期望是按顺序添加的,这在递归时难以保证。 - // 更好的方法是让 emit_instructions 直接输出到 stringstream,并控制递归顺序。 - // 但是为了最小化改动,我们先保持 emit_instructions 的现有签名, - // 然后在它内部处理指令的收集和去重。 - - // 重新设计 emit_instructions 的调用方式 - // 这里的思路是,每个 DAGNode 都存储了自己及其依赖(如果未被其他节点引用)的指令。 - // 最终,我们遍历 BasicBlock 中的所有原始 IR 指令,找到它们对应的 DAGNode,然后发射。 - // 这是因为 IR 指令的顺序决定了代码的逻辑顺序。 - - // 遍历 IR 指令,并找到对应的 DAGNode 进行发射 - // 由于 build_dag 是从 IR 指令顺序构建的,我们应该按照 IR 指令的顺序来发射。 - emitted_nodes.clear(); // 再次清空已发射节点集合 - // 临时存储每个 IR 指令对应的 DAGNode,因为 DAGNode 列表是平铺的 - std::map inst_to_dag_node; - for (const auto& dag_node_ptr : dag_nodes_for_bb) { - if (dag_node_ptr->value && dynamic_cast(dag_node_ptr->value)) { - inst_to_dag_node[dynamic_cast(dag_node_ptr->value)] = dag_node_ptr.get(); - } - } - - for (const auto& inst_ptr : bb->getInstructions()) { - DAGNode* node_to_emit = nullptr; - // 查找当前 IR 指令在 DAG 中对应的节点。 - // 注意:不是所有 IR 指令都会直接映射到一个“根”DAGNode (例如,某些值可能只作为操作数存在) - // 但终结符(如 Branch, Return)和 Store 指令总是重要的。 - // 对于 load/binary 等,我们应该在 build_dag 中确保它们有一个结果 vreg,并被后续指令使用。 - // 如果一个 IR 指令是某个 DAGNode 的 value,那么我们就发射那个 DAGNode。 - if (inst_to_dag_node.count(inst_ptr.get())) { - node_to_emit = inst_to_dag_node.at(inst_ptr.get()); - } - - if (node_to_emit) { - // 注意:select_instructions 已经在上面统一调用过,这里只需要 emit。 - // 但如果 select_instructions 没有递归地为所有依赖选择指令,这里可能需要重新考虑。 - // 为了简化,我们假定 select_instructions 在第一次被调用时(通常在 emit 之前)已经递归地为所有操作数选择了指令。 - - // 直接将指令添加到 ss 中,而不是通过 vector 中转 - emit_instructions(node_to_emit, ss, alloc, emitted_nodes); - } - } - return ss.str(); } -// DAG 构建 std::vector> RISCv32CodeGen::build_dag(BasicBlock* bb) { - std::vector> nodes_storage; // 存储所有 unique_ptr - std::map value_to_node; // 将 IR Value* 映射到原始 DAGNode*,用于快速查找 + std::vector> nodes; + std::map value_to_node; + int vreg_counter = 0; - // 辅助函数,用于创建 DAGNode 并管理其所有权 - auto create_node = [&](DAGNode::NodeKind kind, Value* val = nullptr) -> DAGNode* { - // 优化:如果一个值已经有节点并且它不是控制流/存储/Alloca地址,则重用它 (CSE) - // 对于 AllocaInst,我们想创建一个代表其地址的节点,但不一定直接为 AllocaInst 本身分配虚拟寄存器。 - if (val && value_to_node.count(val) && kind != DAGNode::STORE && kind != DAGNode::RETURN && kind != DAGNode::BRANCH && kind != DAGNode::ALLOCA_ADDR) { - return value_to_node[val]; - } - - auto node = std::make_unique(kind); - node->value = val; - - // 为产生结果的值分配虚拟寄存器 - // 注意:这里的vreg分配是在每个块中独立进行的,但寄存器分配器是在函数级别运行的 - // 我们在寄存器分配前,已经为整个函数的所有value预分配了vreg - if (val && value_vreg_map.count(val)) { - node->result_vreg = value_vreg_map.at(val); - } else if (val && kind != DAGNode::STORE && kind != DAGNode::RETURN && kind != DAGNode::BRANCH) { - // 如果一个值(例如常量)在预分配阶段没有vreg,这里可以给一个 - if(value_vreg_map.find(val) == value_vreg_map.end()){ - value_vreg_map[val] = "v" + std::to_string(vreg_counter++); + for (auto& inst : bb->getInstructions()) { + if (auto alloca = dynamic_cast(inst.get())) { + auto node = std::make_unique(DAGNode::ALLOCA_ADDR); + node->value = alloca; + node->result_vreg = "%" + inst->getName(); // Use IR name (%a(0), %b(0)) + value_to_node[alloca] = node.get(); + nodes.push_back(std::move(node)); + } else if (auto load = dynamic_cast(inst.get())) { + auto node = std::make_unique(DAGNode::LOAD); + node->value = load; + node->result_vreg = "%" + inst->getName(); // Use IR name (%0, %1) + auto pointer = load->getPointer(); + if (value_to_node.count(pointer)) { + node->operands.push_back(value_to_node[pointer]); + value_to_node[pointer]->users.push_back(node.get()); } - node->result_vreg = value_vreg_map.at(val); - } - - - DAGNode* raw_node_ptr = node.get(); - nodes_storage.push_back(std::move(node)); // 存储 unique_ptr - - // 仅当 IR Value 表示一个计算值时,才将其映射到创建的 DAGNode - if (val && kind != DAGNode::STORE && kind != DAGNode::RETURN && kind != DAGNode::BRANCH) { - value_to_node[val] = raw_node_ptr; - } - return raw_node_ptr; - }; - - - for (const auto& inst_ptr : bb->getInstructions()) { - auto inst = inst_ptr.get(); - - if (auto alloca = dynamic_cast(inst)) { - // AllocaInst 本身不产生寄存器中的值,但其地址将被 load/store 使用。 - // 创建一个节点来表示分配内存的地址。 - // 这个地址将是 s0 (帧指针) 的偏移量。 - // 我们将 AllocaInst 指针存储在 DAGNode 的 `value` 字段中。 - auto alloca_addr_node = create_node(DAGNode::ALLOCA_ADDR, alloca); - // 此节点将有一个 result_vreg,表示计算出的地址 (s0 + 偏移量) - // 实际偏移量将在寄存器分配阶段 (stack_map) 确定。 - } else if (auto store = dynamic_cast(inst)) { - auto store_node = create_node(DAGNode::STORE, store); // 将 store inst 绑定到 node - - // 获取要存储的值 - Value* val_to_store_ir = store->getValue(); - DAGNode* val_node = nullptr; - if (value_to_node.count(val_to_store_ir)) { - val_node = value_to_node[val_to_store_ir]; - } else if (auto constant = dynamic_cast(val_to_store_ir)) { - val_node = create_node(DAGNode::CONSTANT, constant); - } else { // 这是一个尚未在此块中计算的值,假设它需要加载 (从内存或参数) - val_node = create_node(DAGNode::LOAD, val_to_store_ir); + value_to_node[load] = node.get(); + nodes.push_back(std::move(node)); + } else if (auto store = dynamic_cast(inst.get())) { + auto node = std::make_unique(DAGNode::STORE); + node->value = store; + auto value_operand = store->getValue(); + auto pointer = store->getPointer(); + if (value_to_node.count(value_operand)) { + node->operands.push_back(value_to_node[value_operand]); + value_to_node[value_operand]->users.push_back(node.get()); + } else if (auto const_val = dynamic_cast(value_operand)) { + auto const_node = std::make_unique(DAGNode::CONSTANT); + const_node->value = const_val; + const_node->result_vreg = "%" + std::to_string(vreg_counter++); // Use simple %N for constants + value_to_node[value_operand] = const_node.get(); + node->operands.push_back(const_node.get()); + const_node->users.push_back(node.get()); + nodes.push_back(std::move(const_node)); } - - // 获取内存位置的指针 - Value* ptr_ir = store->getPointer(); - DAGNode* ptr_node = nullptr; - if (value_to_node.count(ptr_ir)) { - ptr_node = value_to_node[ptr_ir]; - } else if (auto alloca = dynamic_cast(ptr_ir)) { - // 如果是alloca,我们应该找到代表它地址的节点 - // 为了简化,如果没找到,就创建一个 - ptr_node = create_node(DAGNode::ALLOCA_ADDR, alloca); - } else if (auto global = dynamic_cast(ptr_ir)) { - ptr_node = create_node(DAGNode::CONSTANT, global); // 全局地址将被加载 - } else { // 必须是存储在虚拟寄存器中的指针 - ptr_node = create_node(DAGNode::LOAD, ptr_ir); // 这是一个产生指针的指令 + if (value_to_node.count(pointer)) { + node->operands.push_back(value_to_node[pointer]); + value_to_node[pointer]->users.push_back(node.get()); } - - store_node->operands.push_back(val_node); - store_node->operands.push_back(ptr_node); - val_node->users.push_back(store_node); - ptr_node->users.push_back(store_node); - } else if (auto load = dynamic_cast(inst)) { - if (value_to_node.count(load)) continue; // 共同子表达式消除 (CSE) - - auto load_node = create_node(DAGNode::LOAD, load); // 为 load_node 分配 result_vreg 并映射 load - - Value* ptr_ir = load->getPointer(); - DAGNode* ptr_node = nullptr; - if (value_to_node.count(ptr_ir)) { - ptr_node = value_to_node[ptr_ir]; - } else if (auto alloca = dynamic_cast(ptr_ir)) { - ptr_node = create_node(DAGNode::ALLOCA_ADDR, alloca); - } else if (auto global = dynamic_cast(ptr_ir)) { - ptr_node = create_node(DAGNode::CONSTANT, global); // 全局地址将被加载 - } else { // 必须是存储在虚拟寄存器中的指针 - ptr_node = create_node(DAGNode::LOAD, ptr_ir); // 这是一个产生指针的指令 - } - - load_node->operands.push_back(ptr_node); - ptr_node->users.push_back(load_node); - } else if (auto bin = dynamic_cast(inst)) { - if (value_to_node.count(bin)) continue; // CSE - - auto bin_node = create_node(DAGNode::BINARY, bin); - - auto get_operand_node = [&](Value* operand_ir) -> DAGNode* { - if (value_to_node.count(operand_ir)) { - return value_to_node[operand_ir]; - } else if (auto constant = dynamic_cast(operand_ir)) { - return create_node(DAGNode::CONSTANT, constant); - } else { - // 这是一个由另一个指令或参数产生的值,如果不在 map 中,则假设需要加载 - return create_node(DAGNode::LOAD, operand_ir); + nodes.push_back(std::move(node)); + } else if (auto binary = dynamic_cast(inst.get())) { + auto node = std::make_unique(DAGNode::BINARY); + node->value = binary; + node->result_vreg = "%" + inst->getName(); // Use IR name (%2) + for (auto operand : binary->getOperands()) { + auto op_value = operand->getValue(); + if (value_to_node.count(op_value)) { + node->operands.push_back(value_to_node[op_value]); + value_to_node[op_value]->users.push_back(node.get()); + } else if (auto const_val = dynamic_cast(op_value)) { + auto const_node = std::make_unique(DAGNode::CONSTANT); + const_node->value = const_val; + const_node->result_vreg = "%" + std::to_string(vreg_counter++); + value_to_node[op_value] = const_node.get(); + node->operands.push_back(const_node.get()); + const_node->users.push_back(node.get()); + nodes.push_back(std::move(const_node)); } - }; - - DAGNode* lhs_node = get_operand_node(bin->getLhs()); - DAGNode* rhs_node = get_operand_node(bin->getRhs()); - - bin_node->operands.push_back(lhs_node); - bin_node->operands.push_back(rhs_node); - lhs_node->users.push_back(bin_node); - rhs_node->users.push_back(bin_node); - } else if (auto call = dynamic_cast(inst)) { - if (value_to_node.count(call)) continue; // CSE (如果结果被重用) - - auto call_node = create_node(DAGNode::CALL, call); // 如果调用返回一个值,则分配 result_vreg - - for (auto arg : call->getArguments()) { - auto arg_val_ir = arg->getValue(); - DAGNode* arg_node = nullptr; - if (value_to_node.count(arg_val_ir)) { - arg_node = value_to_node[arg_val_ir]; - } else if (auto constant = dynamic_cast(arg_val_ir)) { - arg_node = create_node(DAGNode::CONSTANT, constant); - } else { - arg_node = create_node(DAGNode::LOAD, arg_val_ir); - } - call_node->operands.push_back(arg_node); - arg_node->users.push_back(call_node); } - } else if (auto ret = dynamic_cast(inst)) { - auto ret_node = create_node(DAGNode::RETURN, ret); // 将 return inst 绑定到 node + value_to_node[binary] = node.get(); + nodes.push_back(std::move(node)); + } else if (auto ret = dynamic_cast(inst.get())) { + auto node = std::make_unique(DAGNode::RETURN); + node->value = ret; if (ret->hasReturnValue()) { - auto val_ir = ret->getReturnValue(); - DAGNode* val_node = nullptr; - if (value_to_node.count(val_ir)) { - val_node = value_to_node[val_ir]; - } else if (auto constant = dynamic_cast(val_ir)) { - val_node = create_node(DAGNode::CONSTANT, constant); - } else { - val_node = create_node(DAGNode::LOAD, val_ir); + auto value_operand = ret->getReturnValue(); + if (value_to_node.count(value_operand)) { + node->operands.push_back(value_to_node[value_operand]); + value_to_node[value_operand]->users.push_back(node.get()); + } else if (auto const_val = dynamic_cast(value_operand)) { + auto const_node = std::make_unique(DAGNode::CONSTANT); + const_node->value = const_val; + const_node->result_vreg = "%" + std::to_string(vreg_counter++); + value_to_node[value_operand] = const_node.get(); + node->operands.push_back(const_node.get()); + const_node->users.push_back(node.get()); + nodes.push_back(std::move(const_node)); } - ret_node->operands.push_back(val_node); - val_node->users.push_back(ret_node); } - } else if (auto cond_br = dynamic_cast(inst)) { - auto br_node = create_node(DAGNode::BRANCH, cond_br); // 将 cond_br inst 绑定到 node - auto cond_ir = cond_br->getCondition(); - - if (auto constant_cond = dynamic_cast(cond_ir)) { - // 优化常量条件分支为无条件跳转 - br_node->inst = "j " + (constant_cond->getInt() ? cond_br->getThenBlock()->getName() : cond_br->getElseBlock()->getName()); - // 对于直接跳转,不需要操作数 - } else { - DAGNode* cond_node = nullptr; - if (value_to_node.count(cond_ir)) { - cond_node = value_to_node[cond_ir]; - } else if (auto bin_cond = dynamic_cast(cond_ir)) { - cond_node = create_node(DAGNode::BINARY, bin_cond); - } else { // 必须是一个需要加载的值 - cond_node = create_node(DAGNode::LOAD, cond_ir); - } - br_node->operands.push_back(cond_node); - cond_node->users.push_back(br_node); + nodes.push_back(std::move(node)); + } else if (auto cond_br = dynamic_cast(inst.get())) { + auto node = std::make_unique(DAGNode::BRANCH); + node->value = cond_br; + auto condition = cond_br->getCondition(); + if (value_to_node.count(condition)) { + node->operands.push_back(value_to_node[condition]); + value_to_node[condition]->users.push_back(node.get()); + } else if (auto const_val = dynamic_cast(condition)) { + auto const_node = std::make_unique(DAGNode::CONSTANT); + const_node->value = const_val; + const_node->result_vreg = "%" + std::to_string(vreg_counter++); + value_to_node[condition] = const_node.get(); + node->operands.push_back(const_node.get()); + const_node->users.push_back(node.get()); + nodes.push_back(std::move(const_node)); } - } else if (auto uncond_br = dynamic_cast(inst)) { - auto br_node = create_node(DAGNode::BRANCH, uncond_br); // 将 uncond_br inst 绑定到 node - br_node->inst = "j " + uncond_br->getBlock()->getName(); + nodes.push_back(std::move(node)); + } else if (auto uncond_br = dynamic_cast(inst.get())) { + auto node = std::make_unique(DAGNode::BRANCH); + node->value = uncond_br; + nodes.push_back(std::move(node)); } } - - return nodes_storage; + return nodes; } -// 打印 DAG -void RISCv32CodeGen::print_dag(const std::vector>& dag, const std::string& bb_name) { - std::cerr << "=== DAG for Basic Block: " << bb_name << " ===\n"; - std::set visited; - - // 辅助映射,用于在打印输出中为节点分配顺序 ID - std::map node_to_id; - int current_id = 0; - for (const auto& node_ptr : dag) { - node_to_id[node_ptr.get()] = current_id++; - } - - std::function print_node = [&](DAGNode* node, int indent) { - if (!node) return; - - std::string current_indent(indent, ' '); - int node_id = node_to_id.count(node) ? node_to_id[node] : -1; // 获取分配的 ID - - std::cerr << current_indent << "Node#" << node_id << ": " << node->getNodeKindString(); - if (!node->result_vreg.empty()) { - std::cerr << " (vreg: " << node->result_vreg << ")"; - } - - if (node->value) { - std::cerr << " ["; - if (auto inst = dynamic_cast(node->value)) { - std::cerr << inst->getKindString(); - if (!inst->getName().empty()) { - std::cerr << "(" << inst->getName() << ")"; - } - } else if (auto constant = dynamic_cast(node->value)) { - if (constant->isInt()) { - std::cerr << "ConstInt(" << constant->getInt() << ")"; - } else { - std::cerr << "ConstFloat(" << constant->getFloat() << ")"; - } - } else if (auto global = dynamic_cast(node->value)) { - std::cerr << "Global(" << global->getName() << ")"; - } else if (auto alloca = dynamic_cast(node->value)) { - std::cerr << "Alloca(" << (alloca->getName().empty() ? ("%" + std::to_string(reinterpret_cast(alloca) % 1000)) : alloca->getName()) << ")"; - } - std::cerr << "]"; - } - std::cerr << " -> Inst: \"" << node->inst << "\""; // 打印选定的指令 - std::cerr << "\n"; - - if (visited.find(node) != visited.end()) { - std::cerr << current_indent << " (已打印后代)\n"; - return; // 避免循环的无限递归 - } - visited.insert(node); - - - if (!node->operands.empty()) { - std::cerr << current_indent << " 操作数:\n"; - for (auto operand : node->operands) { - print_node(operand, indent + 4); - } - } - // 移除了 users 打印,以简化输出并避免 DAG 中的冗余递归。 - // Users 更适用于向上遍历,而不是向下遍历。 - }; - - // 遍历 DAG,以尊重依赖的方式打印。 - // 当前实现:遍历所有节点,从作为“根”的节点开始打印(没有用户或副作用节点)。 - // 每次打印新的根时,重置 visited 集合,以允许共享子图被重新打印(尽管这不是最高效的方式)。 - for (const auto& node_ptr : dag) { - // 只有那些没有用户或者表示副作用(如 store/branch/return)的节点才被视为“根” - // 这样可以确保所有指令(包括那些没有明确结果的)都被打印 - if (node_ptr->users.empty() || node_ptr->kind == DAGNode::STORE || node_ptr->kind == DAGNode::RETURN || node_ptr->kind == DAGNode::BRANCH) { - visited.clear(); // 为每个根重置 visited,允许重新打印共享子图 - print_node(node_ptr.get(), 0); - } - } - std::cerr << "=== DAG 结束 ===\n\n"; -} - - -// 指令选择 void RISCv32CodeGen::select_instructions(DAGNode* node, const RegAllocResult& alloc) { - if (!node) return; - if (!node->inst.empty()) return; // 指令已选择 - - // 首先递归地为操作数选择指令 - for (auto operand : node->operands) { - if (operand) { - select_instructions(operand, alloc); - } - } - - std::stringstream ss_inst; // 使用 stringstream 构建指令 - - // 获取分配的物理寄存器,如果没有分配,则使用临时寄存器 (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); // 回退到临时寄存器 - }; - - // 获取分配的栈变量的内存偏移量 - auto get_stack_offset = [&](Value* val) { - if (alloc.stack_map.count(val)) { - return std::to_string(alloc.stack_map.at(val)); - } - return std::string("0"); // 默认或错误情况 - }; - - switch (node->kind) { - case DAGNode::CONSTANT: { - if (auto constant = dynamic_cast(node->value)) { - std::string dest_reg = get_preg_or_temp(node->result_vreg); - if (constant->isInt()) { - ss_inst << "li " << dest_reg << ", " << constant->getInt(); + if (node->inst.empty()) { + switch (node->kind) { + case DAGNode::CONSTANT: { + auto const_val = dynamic_cast(node->value); + if (const_val->isInt()) { + node->inst = "li " + node->result_vreg + ", " + std::to_string(const_val->getInt()); } 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 寄存器并非总是如此) + node->inst = "# float constant not implemented"; } - } else if (auto global = dynamic_cast(node->value)) { - std::string dest_reg = get_preg_or_temp(node->result_vreg); - ss_inst << "la " << dest_reg << ", " << global->getName(); // 加载全局变量地址 + break; } - break; - } - case DAGNode::ALLOCA_ADDR: { - // FIX: 这个节点本身不生成指令。 - // 它的使用者(LOAD/STORE)会利用它的信息生成更优化的寻址指令。 - // 将 node->inst 留空以避免生成冗余的 `addi` 指令。 - 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]; // 操作数是指针 - - // 检查指针本身是否是 AllocaInst - if (ptr_node->kind == DAGNode::ALLOCA_ADDR) { // 检查节点类型,而非其值 - if (auto alloca_inst = dynamic_cast(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 中的地址加载 - } - 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]; // 目标地址 - - std::string src_reg; - if (val_node->kind == DAGNode::CONSTANT) { - // 如果存储的是常量,先将其加载到临时寄存器 (t0) - if (auto constant = dynamic_cast(val_node->value)) { - src_reg = get_preg_or_temp(val_node->result_vreg); // 常量也应该有vreg - // 注意:这里的li指令会由CONSTANT节点自己生成,STORE节点不应重复生成 - } else { // 存储全局地址 - 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(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(node->value); - if (!bin) break; - - std::string dest_reg = get_preg_or_temp(node->result_vreg); - std::string lhs_reg = get_preg_or_temp(node->operands[0]->result_vreg); - std::string rhs_reg = get_preg_or_temp(node->operands[1]->result_vreg); - - std::string opcode; - switch (bin->getKind()) { - 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) - ss_inst << "sub " << dest_reg << ", " << lhs_reg << ", " << rhs_reg << "\n"; - 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 - 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 - opcode = "slt"; - ss_inst << opcode << " " << dest_reg << ", " << rhs_reg << ", " << lhs_reg; // slt rd, rs2, rs1 (如果 rs2 < rs1) - 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 - 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 - 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 - 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()); - } - if (!opcode.empty()) { - ss_inst << opcode << " " << dest_reg << ", " << lhs_reg << ", " << rhs_reg; - } - break; - } - case DAGNode::CALL: { - if (!node->value) break; - auto call = dynamic_cast(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(static_cast(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(node->operands[i]->value)) { - ss_inst << "li " << reg_to_string(static_cast(static_cast(PhysicalReg::A0) + i)) - << ", " << const_val->getInt() << "\n"; - } else if (auto global_val = dynamic_cast(node->operands[i]->value)) { - ss_inst << "la " << reg_to_string(static_cast(static_cast(PhysicalReg::A0) + i)) - << ", " << global_val->getName() << "\n"; + case DAGNode::LOAD: { + auto load = dynamic_cast(node->value); + auto pointer = load->getPointer(); + if (auto alloca = dynamic_cast(pointer)) { + if (alloc.stack_map.count(alloca)) { + node->inst = "lw " + node->result_vreg + ", " + std::to_string(alloc.stack_map.at(alloca)) + "(sp)"; } + } else if (auto global = dynamic_cast(pointer)) { + node->inst = "lw " + node->result_vreg + ", " + global->getName() + "(gp)"; } + break; } - ss_inst << "call " << call->getCallee()->getName(); // 使用 'call' 伪指令 - - // 如果函数返回一个值,将其从 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 - // 确保 load 的结果最终进入 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 << " ret"; // 返回 - break; - } - case DAGNode::BRANCH: { - auto br = dynamic_cast(node->value); - auto uncond_br = dynamic_cast(node->value); - - 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"; // 临时命名 + case DAGNode::STORE: { + auto store = dynamic_cast(node->value); + auto pointer = store->getPointer(); + auto value_vreg = node->operands[0]->result_vreg; + if (auto alloca = dynamic_cast(pointer)) { + if (alloc.stack_map.count(alloca)) { + node->inst = "sw " + value_vreg + ", " + std::to_string(alloc.stack_map.at(alloca)) + "(sp)"; } - if (else_block.empty()) { - else_block = ENTRY_BLOCK_PSEUDO_NAME + "else"; // 临时命名 - } - - ss_inst << "bnez " << cond_reg << ", " << then_block << "\n"; // 如果条件不为零 (真),则跳转到 then 块 - ss_inst << " j " << else_block; // 无条件跳转到 else 块 - } else if (uncond_br) { - std::string target_block = uncond_br->getBlock()->getName(); - if (target_block.empty()) { // 修复空标签问题 - target_block = ENTRY_BLOCK_PSEUDO_NAME + "target"; // 临时命名 - } - ss_inst << "j " << target_block; // 无条件跳转 + } else if (auto global = dynamic_cast(pointer)) { + node->inst = "sw " + value_vreg + ", " + global->getName() + "(gp)"; } - } else { - // 这个分支节点已经被 build_dag 中的常量传播优化为直接跳转。 - // 它的 'inst' 字段已经设置。直接复制它。 - ss_inst << node->inst; + break; } - break; + case DAGNode::BINARY: { + auto binary = dynamic_cast(node->value); + auto lhs_vreg = node->operands[0]->result_vreg; + auto rhs_vreg = node->operands[1]->result_vreg; + std::string op; + switch (binary->getKind()) { + case Instruction::kAdd: op = "add"; break; + case Instruction::kSub: op = "sub"; break; + case Instruction::kMul: op = "mul"; break; + case Instruction::kDiv: op = "div"; break; + case Instruction::kICmpEQ: op = "seq"; break; + case Instruction::kICmpNE: op = "sne"; break; + case Instruction::kICmpLT: op = "slt"; break; + case Instruction::kICmpGT: op = "sgt"; break; + case Instruction::kICmpLE: op = "sle"; break; + case Instruction::kICmpGE: op = "sge"; break; + default: op = "# unknown"; break; + } + node->inst = op + " " + node->result_vreg + ", " + lhs_vreg + ", " + rhs_vreg; + break; + } + case DAGNode::RETURN: { + auto ret = dynamic_cast(node->value); + if (ret->hasReturnValue()) { + auto value_vreg = node->operands[0]->result_vreg; + node->inst = "mv a0, " + value_vreg; + } else { + node->inst = "ret"; + } + break; + } + case DAGNode::BRANCH: { + if (auto cond_br = dynamic_cast(node->value)) { + auto condition_vreg = node->operands[0]->result_vreg; + auto then_block = cond_br->getThenBlock(); + auto else_block = cond_br->getElseBlock(); + int then_idx = 0, else_idx = 0; + int idx = 0; + for (auto& bb : cond_br->getFunction()->getBasicBlocks()) { + if (bb.get() == then_block) then_idx = idx; + if (bb.get() == else_block) else_idx = idx; + idx++; + } + node->inst = "bne " + condition_vreg + ", zero, .L" + std::to_string(then_idx) + "\n j .L" + std::to_string(else_idx); + } else if (auto uncond_br = dynamic_cast(node->value)) { + auto target_block = uncond_br->getBlock(); + int target_idx = 0; + int idx = 0; + for (auto& bb : uncond_br->getFunction()->getBasicBlocks()) { + if (bb.get() == target_block) target_idx = idx; + idx++; + } + node->inst = "j .L" + std::to_string(target_idx); + } + break; + } + default: + node->inst = "# unimplemented"; + break; } - default: - // 对于不直接映射到指令的节点 (例如 `alloca` 本身,其地址由其地址节点处理) - // 或未处理的指令类型,将 inst 留空。 - break; } - node->inst = ss_inst.str(); // 存储生成的指令 } -// 修改:指令发射,直接输出到 stringstream,处理依赖和去重 void RISCv32CodeGen::emit_instructions(DAGNode* node, std::stringstream& ss, const RegAllocResult& alloc, std::set& emitted_nodes) { - if (!node || emitted_nodes.count(node)) { - return; // 已发射或为空 - } - - // 递归地发射操作数以确保满足依赖关系 + if (emitted_nodes.count(node)) return; for (auto operand : node->operands) { - if (operand) { - emit_instructions(operand, ss, alloc, emitted_nodes); - } + emit_instructions(operand, ss, alloc, emitted_nodes); } + if (!node->inst.empty() && node->inst != "# unimplemented" && node->inst.find("# alloca") == std::string::npos) { + std::string inst = node->inst; + std::vector> replacements; - // 标记当前节点为已发射 - emitted_nodes.insert(node); - - // 分割多行指令并处理每一行 - std::stringstream node_inst_ss(node->inst); - std::string line; - - while (std::getline(node_inst_ss, line, '\n')) { - // 清除前导/尾随空白并移除行开头的潜在标签 - line = std::regex_replace(line, std::regex("^\\s*[^\\s:]*:\\s*"), ""); // 移除标签(例如 `label: inst`) - line = std::regex_replace(line, std::regex("^\\s+|\\s+$"), ""); // 清除空白 - - if (line.empty()) continue; - - // 处理虚拟寄存器替换和溢出/加载逻辑 - std::string processed_line = line; - - // 注意:这里的替换逻辑比较脆弱,因为 select_instructions 已经直接生成了物理寄存器名 - // 在一个更健壮的系统中,select_instructions 会生成带vreg的指令,而这里会进行替换 - // 当前的实现下,这个替换逻辑大部分时间是空操作,但为了安全保留 - - // 替换结果虚拟寄存器 (如果此行中存在) - if (!node->result_vreg.empty() && alloc.vreg_to_preg.count(node->result_vreg)) { - std::string preg = reg_to_string(alloc.vreg_to_preg.at(node->result_vreg)); - processed_line = std::regex_replace(processed_line, std::regex("\\b" + node->result_vreg + "\\b"), preg); + // Collect replacements for result and operand virtual registers + if (node->result_vreg != "" && node->kind != DAGNode::ALLOCA_ADDR) { + if (alloc.vreg_to_preg.count(node->result_vreg)) { + replacements.emplace_back(node->result_vreg, get_preg_str(alloc.vreg_to_preg.at(node->result_vreg))); + } else if (alloc.spill_map.count(node->result_vreg)) { + auto temp_reg = PhysicalReg::T0; + replacements.emplace_back(node->result_vreg, get_preg_str(temp_reg)); + inst = inst.substr(0, inst.find('\n')); // Handle multi-line instructions + ss << " " << inst << "\n"; + ss << " sw " << get_preg_str(temp_reg) << ", " << alloc.spill_map.at(node->result_vreg) << "(sp)\n"; + emitted_nodes.insert(node); + return; + } else { + ss << "# Error: Virtual register " << node->result_vreg << " not allocated (kind: " << node->getNodeKindString() << ")\n"; + } } - - // 替换操作数虚拟寄存器 (如果此行中存在) for (auto operand : node->operands) { - if (operand && !operand->result_vreg.empty() && alloc.vreg_to_preg.count(operand->result_vreg)) { - std::string operand_preg = reg_to_string(alloc.vreg_to_preg.at(operand->result_vreg)); - processed_line = std::regex_replace(processed_line, std::regex("\\b" + operand->result_vreg + "\\b"), operand_preg); + if (operand->result_vreg != "" && operand->kind != DAGNode::ALLOCA_ADDR) { + if (alloc.vreg_to_preg.count(operand->result_vreg)) { + replacements.emplace_back(operand->result_vreg, get_preg_str(alloc.vreg_to_preg.at(operand->result_vreg))); + } else if (alloc.spill_map.count(operand->result_vreg)) { + auto temp_reg = PhysicalReg::T1; + ss << " lw " << get_preg_str(temp_reg) << ", " << alloc.spill_map.at(operand->result_vreg) << "(sp)\n"; + replacements.emplace_back(operand->result_vreg, get_preg_str(temp_reg)); + } else { + ss << "# Error: Operand virtual register " << operand->result_vreg << " not allocated (kind: " << operand->getNodeKindString() << ")\n"; + } } } - // 添加处理后的指令 - ss << " " << processed_line << "\n"; + // Perform all replacements only if vreg exists in inst + for (const auto& [vreg, preg] : replacements) { + size_t pos = inst.find(vreg); + while (pos != std::string::npos) { + inst.replace(pos, vreg.length(), preg); + pos = inst.find(vreg, pos + preg.length()); + } + } + + // Emit the instruction + if (node->kind == DAGNode::BRANCH || inst.find('\n') != std::string::npos) { + ss << inst << "\n"; + } else if (inst != "ret") { + ss << " " << inst << "\n"; + } } + emitted_nodes.insert(node); } - -// 活跃性分析 (基本保持不变,因为是通用的数据流分析) std::map> RISCv32CodeGen::liveness_analysis(Function* func) { std::map> live_in, live_out; - bool changed = true; + bool changed; - // 初始化所有 live_in/out 集合为空 - for (const auto& bb : func->getBasicBlocks()) { - for (const auto& inst_ptr : bb->getInstructions()) { - live_in[inst_ptr.get()] = {}; - live_out[inst_ptr.get()] = {}; + // Build DAG for all basic blocks + std::map>> bb_dags; + for (auto& bb : func->getBasicBlocks()) { + bb_dags[bb.get()] = build_dag(bb.get()); + } + + // Initialize live_in and live_out + for (auto& bb : func->getBasicBlocks()) { + for (auto& inst : bb->getInstructions()) { + live_in[inst.get()]; + live_out[inst.get()]; } } - while (changed) { + do { changed = false; - // 逆序遍历基本块 - for (auto it = func->getBasicBlocks_NoRange().rbegin(); it != func->getBasicBlocks_NoRange().rend(); ++it) { - auto bb = it->get(); - // 在基本块内逆序遍历指令 - for (auto inst_it = bb->getInstructions().rbegin(); inst_it != bb->getInstructions().rend(); ++inst_it) { - auto inst = inst_it->get(); - std::set current_live_in = live_in[inst]; - std::set current_live_out = live_out[inst]; + for (auto& bb : func->getBasicBlocks()) { + // Reverse iterate for backward analysis + for (auto it = bb->getInstructions().rbegin(); it != bb->getInstructions().rend(); ++it) { + auto inst = it->get(); + std::set new_live_in, new_live_out; - std::set new_live_out; - // 后继的 live_in 集合的并集 - if (inst->isTerminator()) { - if (auto br = dynamic_cast(inst)) { - new_live_out.insert(live_in[br->getThenBlock()->getInstructions().front().get()].begin(), - live_in[br->getThenBlock()->getInstructions().front().get()].end()); - new_live_out.insert(live_in[br->getElseBlock()->getInstructions().front().get()].begin(), - live_in[br->getElseBlock()->getInstructions().front().get()].end()); - } else if (auto uncond = dynamic_cast(inst)) { - new_live_out.insert(live_in[uncond->getBlock()->getInstructions().front().get()].begin(), - live_in[uncond->getBlock()->getInstructions().front().get()].end()); - } - // 返回指令没有后继,所以 new_live_out 保持为空 - } else { - auto next_inst_it = std::next(inst_it); - if (next_inst_it != bb->getInstructions().rend()) { - // 不是终结符,所以块中的下一条指令是后继 - new_live_out = live_in[next_inst_it->get()]; + // live_out = union of live_in of successors + for (auto succ : bb->getSuccessors()) { + if (!succ->getInstructions().empty()) { + auto succ_inst = succ->getInstructions().front().get(); + new_live_out.insert(live_in[succ_inst].begin(), live_in[succ_inst].end()); } } - // 计算当前指令的 use 和 def 集合 - std::set use_set, def_set; - - // 定义 (Def) - if (value_vreg_map.count(inst)) { - def_set.insert(value_vreg_map.at(inst)); + // Collect def and use + std::set def, use; + // IR instruction def + if (inst->getName() != "" && !dynamic_cast(inst)) { + def.insert("%" + inst->getName()); } - - // 使用 (Use) - 遍历指令的操作数 - for(const auto& operand_use : inst->getOperands()){ - Value* operand = operand_use->getValue(); - // 只有非立即数的值才生活在虚拟寄存器中 - if(!dynamic_cast(operand) && value_vreg_map.count(operand)){ - use_set.insert(value_vreg_map.at(operand)); + // IR instruction use + for (auto operand : inst->getOperands()) { + auto value = operand->getValue(); + if (auto op_inst = dynamic_cast(value)) { + if (op_inst->getName() != "" && !dynamic_cast(op_inst)) { + use.insert("%" + op_inst->getName()); + } } } - - // 计算新的 live_in = use U (new_live_out - def) - std::set new_live_in = use_set; - for (const auto& vreg : new_live_out) { - if (def_set.find(vreg) == def_set.end()) { - new_live_in.insert(vreg); + // DAG node def and use + for (auto& node : bb_dags[bb.get()]) { + if (node->value == inst && node->kind != DAGNode::ALLOCA_ADDR) { + if (node->result_vreg != "") { + def.insert(node->result_vreg); + } + for (auto operand : node->operands) { + if (operand->result_vreg != "" && operand->kind != DAGNode::ALLOCA_ADDR) { + use.insert(operand->result_vreg); + } + } + } + // Constants + if (node->kind == DAGNode::CONSTANT) { + for (auto user : node->users) { + if (user->value == inst) { + use.insert(node->result_vreg); + } + } } } - // 检查收敛 - if (new_live_in != current_live_in || new_live_out != current_live_out) { + // live_in = use U (live_out - def) + std::set live_out_minus_def; + std::set_difference(new_live_out.begin(), new_live_out.end(), + def.begin(), def.end(), + std::inserter(live_out_minus_def, live_out_minus_def.begin())); + new_live_in.insert(use.begin(), use.end()); + new_live_in.insert(live_out_minus_def.begin(), live_out_minus_def.end()); + + // Debug + std::cerr << "Instruction: " << (inst->getName() != "" ? "%" + inst->getName() : "none") << "\n"; + std::cerr << " def: "; for (const auto& d : def) std::cerr << d << " "; std::cerr << "\n"; + std::cerr << " use: "; for (const auto& u : use) std::cerr << u << " "; std::cerr << "\n"; + std::cerr << " live_in: "; for (const auto& v : new_live_in) std::cerr << v << " "; std::cerr << "\n"; + std::cerr << " live_out: "; for (const auto& v : new_live_out) std::cerr << v << " "; std::cerr << "\n"; + + if (live_in[inst] != new_live_in || live_out[inst] != new_live_out) { live_in[inst] = new_live_in; live_out[inst] = new_live_out; changed = true; } } } + } while (changed); + + // Debug live_out + for (const auto& [inst, live_vars] : live_out) { + std::cerr << "Instruction: " << (inst->getName() != "" ? "%" + inst->getName() : "none") << " live_out: "; + for (const auto& var : live_vars) { + std::cerr << var << " "; + } + std::cerr << "\n"; } - return live_in; + + return live_out; } -// 干扰图构建 (基本保持不变) std::map> RISCv32CodeGen::build_interference_graph( const std::map>& live_sets) { - std::map> graph; - - // 确保 live_sets 中所有存在的虚拟寄存器最初都在图中 - for (const auto& pair : live_sets) { - for (const auto& vreg : pair.second) { - graph[vreg] = {}; // 初始化空集合 - } - } - - for (const auto& pair : live_sets) { - auto inst = pair.first; - const auto& live_after_inst = pair.second; // 这实际上是下一条指令/基本块入口的 live_in - - std::string defined_vreg; - if (value_vreg_map.count(inst)) { - defined_vreg = value_vreg_map.at(inst); - } - - // 将从 defined vreg 到此时所有其他活跃 vreg 的边添加 - if (!defined_vreg.empty()) { - for (const auto& live_vreg : live_after_inst) { - if (live_vreg != defined_vreg) { // 虚拟寄存器不与其自身干扰 - graph[defined_vreg].insert(live_vreg); - graph[live_vreg].insert(defined_vreg); // 对称边 + std::map> interference_graph; + for (const auto& [inst, live_vars] : live_sets) { + std::string def_var = inst->getName() != "" && !dynamic_cast(inst) ? "%" + inst->getName() : ""; + if (def_var != "") { + interference_graph[def_var]; // Initialize + for (const auto& live_var : live_vars) { + if (live_var != def_var && live_var.find("%a(") != 0 && live_var.find("%b(") != 0) { + interference_graph[def_var].insert(live_var); + interference_graph[live_var].insert(def_var); } } } + // Initialize all live variables + for (const auto& live_var : live_vars) { + if (live_var.find("%a(") != 0 && live_var.find("%b(") != 0) { + interference_graph[live_var]; + } + } + // Live variables interfere with each other + for (auto it1 = live_vars.begin(); it1 != live_vars.end(); ++it1) { + if (it1->find("%a(") == 0 || it1->find("%b(") == 0) continue; + for (auto it2 = std::next(it1); it2 != live_vars.end(); ++it2) { + if (it2->find("%a(") == 0 || it2->find("%b(") == 0) continue; + interference_graph[*it1].insert(*it2); + interference_graph[*it2].insert(*it1); + } + } } - return graph; + + // Debug + for (const auto& [vreg, neighbors] : interference_graph) { + std::cerr << "Vreg " << vreg << " interferes with: "; + for (const auto& neighbor : neighbors) { + std::cerr << neighbor << " "; + } + std::cerr << "\n"; + } + + return interference_graph; } -// 图着色 (简化版,贪婪着色) (基本保持不变) -void RISCv32CodeGen::color_graph(std::map& vreg_to_preg, - const std::map>& interference_graph) { - vreg_to_preg.clear(); // 清除之前的映射 +RISCv32CodeGen::RegAllocResult RISCv32CodeGen::color_graph(Function* func, const std::map>& interference_graph) { + RegAllocResult alloc; + std::map> ig = interference_graph; + std::stack stack; + std::set spilled; - // 按度数(从大到小)对虚拟寄存器排序以改进着色效果 - std::vector> vreg_degrees; - for (const auto& entry : interference_graph) { - vreg_degrees.push_back({entry.first, (int)entry.second.size()}); + // Available physical registers + std::vector available_regs = { + PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3, PhysicalReg::T4, PhysicalReg::T5, PhysicalReg::T6, + PhysicalReg::S0, PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3, PhysicalReg::S4, PhysicalReg::S5, + PhysicalReg::S6, PhysicalReg::S7, PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11 + }; + + // Simplify: Push nodes with degree < number of registers + while (!ig.empty()) { + bool simplified = false; + for (auto it = ig.begin(); it != ig.end();) { + if (it->second.size() < available_regs.size()) { + stack.push(it->first); + for (auto& [vreg, neighbors] : ig) { + neighbors.erase(it->first); + } + it = ig.erase(it); + simplified = true; + } else { + ++it; + } + } + if (!simplified) { + // Spill the node with the highest degree + auto max_it = ig.begin(); + for (auto it = ig.begin(); it != ig.end(); ++it) { + if (it->second.size() > max_it->second.size()) { + max_it = it; + } + } + spilled.insert(max_it->first); + for (auto& [vreg, neighbors] : ig) { + neighbors.erase(max_it->first); + } + ig.erase(max_it); + } } - std::sort(vreg_degrees.begin(), vreg_degrees.end(), - [](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 used_colors; // 邻居使用的物理寄存器 - - // 收集干扰邻居的颜色 + // Assign colors (physical registers) + while (!stack.empty()) { + auto vreg = stack.top(); + stack.pop(); + std::set used_colors; if (interference_graph.count(vreg)) { - for (const auto& neighbor_vreg : interference_graph.at(vreg)) { - if (vreg_to_preg.count(neighbor_vreg)) { - used_colors.insert(vreg_to_preg.at(neighbor_vreg)); + for (const auto& neighbor : interference_graph.at(vreg)) { + if (alloc.vreg_to_preg.count(neighbor)) { + used_colors.insert(alloc.vreg_to_preg.at(neighbor)); } } } - - // 查找第一个可用的颜色(物理寄存器) - bool colored = false; - for (PhysicalReg preg : allocable_regs) { - if (used_colors.find(preg) == used_colors.end()) { - vreg_to_preg[vreg] = preg; - colored = true; + bool assigned = false; + for (auto preg : available_regs) { + if (!used_colors.count(preg)) { + alloc.vreg_to_preg[vreg] = preg; + assigned = true; break; } } - - if (!colored) { - // 溢出 (Spilling): 如果没有可用的物理寄存器,这个虚拟寄存器必须溢出到内存。 - // 对于这个简化示例,我们没有实现完整的溢出。 - // 一个常见的方法是为其分配一个特殊的“溢出”指示符,并在代码生成中处理它。 - // 目前,我们只是不为其分配物理寄存器,`get_preg_or_temp` 将使用默认的 `t0` 或触发栈加载/存储。 - std::cerr << "警告: 无法为 " << vreg << " 分配寄存器。它很可能会溢出到栈。\n"; - // 更完整的编译器会将此虚拟寄存器添加到 `alloc.stack_map` 并在此处管理其栈偏移量。 + if (!assigned) { + spilled.insert(vreg); } } + + // Allocate stack space for AllocaInst and spilled virtual registers + int stack_offset = 0; + for (auto& bb : func->getBasicBlocks()) { + for (auto& inst : bb->getInstructions()) { + if (auto alloca = dynamic_cast(inst.get())) { + alloc.stack_map[alloca] = stack_offset; + stack_offset += 4; // 4 bytes per variable + } + } + } + for (const auto& vreg : spilled) { + alloc.spill_map[vreg] = stack_offset; + stack_offset += 4; + } + alloc.stack_size = stack_offset + 8; // Extra space for ra and callee-saved + + // Debug output to verify register allocation + for (const auto& [vreg, preg] : alloc.vreg_to_preg) { + std::cerr << "Vreg " << vreg << " assigned to " << get_preg_str(preg) << "\n"; + } + for (const auto& vreg : spilled) { + std::cerr << "Vreg " << vreg << " spilled to stack offset " << alloc.spill_map.at(vreg) << "\n"; + } + + return alloc; } -// 寄存器分配 -RISCv32CodeGen::RegAllocResult RISCv32CodeGen::register_allocation(Function* func) { - // 1. Phi 节点消除 (如果 IR 中有 Phi 节点,需要在活跃性分析前消除) - eliminate_phi(func); // 确保首先调用此函数 - - // 为每个函数重置计数器 - vreg_counter = 0; - 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()) { - 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()){ - Value* operand = operand_use->getValue(); - if(dynamic_cast(operand) || dynamic_cast(operand)){ - if (value_vreg_map.find(operand) == value_vreg_map.end()) { - value_vreg_map[operand] = "v" + std::to_string(vreg_counter++); - } - } - } - } +RISCv32CodeGen::PhysicalReg RISCv32CodeGen::get_preg_or_temp(const std::string& vreg, const RegAllocResult& alloc) const { + if (alloc.vreg_to_preg.count(vreg)) { + return alloc.vreg_to_preg.at(vreg); } - - RegAllocResult alloc_result; - - // 计算 AllocaInst 的栈偏移量 - int current_stack_offset = 0; // 相对于 s0 (帧指针) - - std::set allocas_in_func; - for (const auto& bb_ptr : func->getBasicBlocks()) { - for (const auto& inst_ptr : bb_ptr->getInstructions()) { - if (auto alloca = dynamic_cast(inst_ptr.get())) { - allocas_in_func.insert(alloca); - } - } - } - - // 为 alloca 指令分配栈空间 - for (auto alloca : allocas_in_func) { - // 为 4 字节整数 (i32) 分配空间 - int size = 4; // 假设 i32,如果存在其他类型则调整 - alloc_result.stack_map[alloca] = current_stack_offset; - current_stack_offset += size; - } - - // 确保栈大小是 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> live_sets = liveness_analysis(func); - - // 3. 构建干扰图 - std::map> interference_graph = build_interference_graph(live_sets); - - // 4. 图着色 - color_graph(alloc_result.vreg_to_preg, interference_graph); - - // 完整的溢出处理逻辑比较复杂,这里暂时省略。 - // 如果一个vreg没有被着色,get_preg_or_temp会回退到t0,这对于简单情况可能够用。 - - return alloc_result; -} - -// Phi 消除 (简化版,将 Phi 的结果直接复制到每个前驱基本块的末尾) -void RISCv32CodeGen::eliminate_phi(Function* func) { - // 这是一个占位符。适当的 phi 消除将涉及 - // 在每个前驱基本块的末尾插入 `mov` 指令,用于每个 phi 操作数。 - // 对于给定的 IR 示例,没有 phi 节点,所以这可能不是严格必要的, - // 但如果前端生成 phi 节点,则有此阶段是好的做法。 - // 目前,我们假设没有生成 phi 节点或者它们已在前端处理。 + return PhysicalReg::T0; // Fallback for spilled registers, handled in emit_instructions } } // namespace sysy \ No newline at end of file diff --git a/src/RISCv32Backend.h b/src/RISCv32Backend.h index 7ee332a..d6dd6e0 100644 --- a/src/RISCv32Backend.h +++ b/src/RISCv32Backend.h @@ -8,7 +8,8 @@ #include #include #include -#include // For std::function +#include +#include namespace sysy { @@ -18,18 +19,16 @@ public: ZERO, RA, SP, GP, TP, T0, T1, T2, S0, S1, A0, A1, A2, A3, A4, A5, A6, A7, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, T3, T4, T5, T6 }; - // Move DAGNode and RegAllocResult to public section struct DAGNode { - enum NodeKind { CONSTANT, LOAD, STORE, BINARY, CALL, RETURN, BRANCH, ALLOCA_ADDR }; // Added ALLOCA_ADDR + enum NodeKind { CONSTANT, LOAD, STORE, BINARY, CALL, RETURN, BRANCH, ALLOCA_ADDR }; NodeKind kind; - Value* value = nullptr; // For IR Value - std::string inst; // Generated RISC-V instruction(s) for this node - std::string result_vreg; // Virtual register assigned to this node's result + Value* value = nullptr; + std::string inst; + std::string result_vreg; std::vector operands; - std::vector users; // For debugging and potentially optimizations + std::vector users; DAGNode(NodeKind k) : kind(k) {} - // Debugging / helper std::string getNodeKindString() const { switch (kind) { case CONSTANT: return "CONSTANT"; @@ -46,9 +45,10 @@ public: }; struct RegAllocResult { - std::map vreg_to_preg; // Virtual register to Physical Register mapping - std::map stack_map; // Value (AllocaInst) to stack offset - int stack_size = 0; // Total stack frame size for locals and spills + std::map vreg_to_preg; // 虚拟寄存器到物理寄存器的映射 + std::map stack_map; // AllocaInst到栈偏移的映射 + std::map spill_map; // 溢出的虚拟寄存器到栈偏移的映射 + int stack_size = 0; // 总栈帧大小 }; RISCv32CodeGen(Module* mod) : module(mod) {} @@ -56,41 +56,46 @@ public: std::string code_gen(); std::string module_gen(); std::string function_gen(Function* func); - // 修改 basicBlock_gen 的声明,添加 int block_idx 参数 std::string basicBlock_gen(BasicBlock* bb, const RegAllocResult& alloc, int block_idx); - - // DAG related std::vector> build_dag(BasicBlock* bb); void select_instructions(DAGNode* node, const RegAllocResult& alloc); - // 改变 emit_instructions 的参数,使其可以直接添加汇编指令到 main ss void emit_instructions(DAGNode* node, std::stringstream& ss, const RegAllocResult& alloc, std::set& emitted_nodes); - - // Register Allocation related std::map> liveness_analysis(Function* func); std::map> build_interference_graph( const std::map>& live_sets); - void color_graph(std::map& vreg_to_preg, - const std::map>& interference_graph); - RegAllocResult register_allocation(Function* func); - void eliminate_phi(Function* func); // Phi elimination is typically done before DAG building - - // Utility - std::string reg_to_string(PhysicalReg reg); - void print_dag(const std::vector>& dag, const std::string& bb_name); + RegAllocResult color_graph(Function* func, const std::map>& interference_graph); private: - static const std::vector allocable_regs; - std::map value_vreg_map; // Maps IR Value* to its virtual register name Module* module; - int vreg_counter = 0; // Counter for unique virtual register names - int alloca_offset_counter = 0; // Counter for alloca offsets + std::map preg_to_str = { + {PhysicalReg::ZERO, "zero"}, {PhysicalReg::RA, "ra"}, {PhysicalReg::SP, "sp"}, + {PhysicalReg::GP, "gp"}, {PhysicalReg::TP, "tp"}, {PhysicalReg::T0, "t0"}, + {PhysicalReg::T1, "t1"}, {PhysicalReg::T2, "t2"}, {PhysicalReg::S0, "s0"}, + {PhysicalReg::S1, "s1"}, {PhysicalReg::A0, "a0"}, {PhysicalReg::A1, "a1"}, + {PhysicalReg::A2, "a2"}, {PhysicalReg::A3, "a3"}, {PhysicalReg::A4, "a4"}, + {PhysicalReg::A5, "a5"}, {PhysicalReg::A6, "a6"}, {PhysicalReg::A7, "a7"}, + {PhysicalReg::S2, "s2"}, {PhysicalReg::S3, "s3"}, {PhysicalReg::S4, "s4"}, + {PhysicalReg::S5, "s5"}, {PhysicalReg::S6, "s6"}, {PhysicalReg::S7, "s7"}, + {PhysicalReg::S8, "s8"}, {PhysicalReg::S9, "s9"}, {PhysicalReg::S10, "s10"}, + {PhysicalReg::S11, "s11"}, {PhysicalReg::T3, "t3"}, {PhysicalReg::T4, "t4"}, + {PhysicalReg::T5, "t5"}, {PhysicalReg::T6, "t6"} + }; - // 新增一个成员变量来存储当前函数的所有 DAGNode,以确保其生命周期贯穿整个函数代码生成 - // 这样可以在多个 BasicBlock_gen 调用中访问到完整的 DAG 节点 - std::vector> current_function_dag_nodes; + std::vector caller_saved = { + 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 + }; - // 为空标签定义一个伪名称前缀,加上块索引以确保唯一性 - const std::string ENTRY_BLOCK_PSEUDO_NAME = "entry_block_"; + std::vector callee_saved = { + 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::string get_preg_str(PhysicalReg preg) const { + return preg_to_str.at(preg); + } + + PhysicalReg get_preg_or_temp(const std::string& vreg, const RegAllocResult& alloc) const; }; } // namespace sysy