diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f6f841a..7d59021 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -18,7 +18,7 @@ add_executable(sysyc # Backend.cpp SysYIRPrinter.cpp SysYIROptPre.cpp - RISCv32Backend.cpp + RISCv64Backend.cpp ) target_include_directories(sysyc PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include) target_compile_options(sysyc PRIVATE -frtti) diff --git a/src/RISCv64Backend.cpp b/src/RISCv64Backend.cpp new file mode 100644 index 0000000..82ac0f4 --- /dev/null +++ b/src/RISCv64Backend.cpp @@ -0,0 +1,1344 @@ +#include "RISCv64Backend.h" // 修改头文件名 +#include +#include +#include +#include +#include +#include // For std::function + +#define DEBUG 0 +#define DEEPDEBUG 0 +namespace sysy { + +// 可用于分配的寄存器(整数和浮点) +const std::vector RISCv64CodeGen::allocable_regs = { + // 整数寄存器 + PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3, + PhysicalReg::T4, PhysicalReg::T5, PhysicalReg::T6, + PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3, + PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7, + PhysicalReg::S0, PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3, + PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7, + PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11, + // 浮点寄存器 + PhysicalReg::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 RISCv64CodeGen::reg_to_string(PhysicalReg reg) { + switch (reg) { + case PhysicalReg::ZERO: return "x0"; + case PhysicalReg::RA: return "ra"; + case PhysicalReg::SP: return "sp"; + case PhysicalReg::GP: return "gp"; + case PhysicalReg::TP: return "tp"; + case PhysicalReg::T0: return "t0"; + case PhysicalReg::T1: return "t1"; + case PhysicalReg::T2: return "t2"; + case PhysicalReg::S0: return "s0"; + case PhysicalReg::S1: return "s1"; + case PhysicalReg::A0: return "a0"; + case PhysicalReg::A1: return "a1"; + case PhysicalReg::A2: return "a2"; + case PhysicalReg::A3: return "a3"; + case PhysicalReg::A4: return "a4"; + case PhysicalReg::A5: return "a5"; + case PhysicalReg::A6: return "a6"; + case PhysicalReg::A7: return "a7"; + case PhysicalReg::S2: return "s2"; + case PhysicalReg::S3: return "s3"; + case PhysicalReg::S4: return "s4"; + case PhysicalReg::S5: return "s5"; + case PhysicalReg::S6: return "s6"; + case PhysicalReg::S7: return "s7"; + case PhysicalReg::S8: return "s8"; + case PhysicalReg::S9: return "s9"; + case PhysicalReg::S10: return "s10"; + case PhysicalReg::S11: return "s11"; + case PhysicalReg::T3: return "t3"; + case PhysicalReg::T4: return "t4"; + case PhysicalReg::T5: return "t5"; + case PhysicalReg::T6: return "t6"; + // 浮点寄存器 + case PhysicalReg::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"; + } +} + +// 总体代码生成入口 +std::string RISCv64CodeGen::code_gen() { + std::stringstream ss; + ss << module_gen(); + return ss.str(); +} + +// 模块级代码生成 (处理全局变量和函数) +// 注意:由于 int 和 float 仍然是32位,.word 的使用是正确的。 +std::string RISCv64CodeGen::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"; // 整数常量 (32位) + } else { + float f = constant->getFloat(); + uint32_t float_bits = *(uint32_t*)&f; + ss << " .word " << float_bits << "\n"; // 浮点常量 (32位) + } + } + } + } + } + } + if (!module->getFunctions().empty()) { + ss << ".text\n"; // 代码段 + for (const auto& func : module->getFunctions()) { + ss << function_gen(func.second.get()); + } + } + return ss.str(); +} + +// 函数级代码生成 +std::string RISCv64CodeGen::function_gen(Function* func) { + std::stringstream ss; + ss << ".globl " << func->getName() << "\n"; // 声明函数为全局符号 + ss << func->getName() << ":\n"; // 函数入口标签 + + RegAllocResult alloc_result = register_allocation(func); + int stack_size = alloc_result.stack_size; + + // 函数序言 (Prologue) + // RV64: ra 和 s0 都是64位(8字节)寄存器 + // 保存 ra 和 s0, 调整栈指针 + // s0 指向当前帧的底部(分配局部变量/溢出空间后的 sp) + // 确保栈大小 16 字节对齐 + int aligned_stack_size = (stack_size + 15) & ~15; + + // 只有当需要栈空间时才生成序言 + if (aligned_stack_size > 0) { + ss << " addi sp, sp, -" << aligned_stack_size << "\n"; // 调整栈指针 + // RV64 修改: 使用 sd (store doubleword) 保存 8 字节的 ra 和 s0 + // 同时更新偏移量,为每个寄存器保留8字节 + ss << " sd ra, " << (aligned_stack_size - 8) << "(sp)\n"; // 保存返回地址 (8字节) + ss << " sd s0, " << (aligned_stack_size - 16) << "(sp)\n"; // 保存帧指针 (8字节) + ss << " mv s0, sp\n"; // 设置新的帧指针 + } + + // *** 新增的逻辑:处理传入的函数参数 *** + // 将传入的寄存器参数 (a0-a7 / f10-f17) 保存到对应的栈槽 (AllocaInst)。 + // RV64中,a0-a7是64位寄存器,但我们传入的int/float是32位。 + // 使用 sw/fsw 会正确地存储低32位,这是正确的行为。 + int arg_idx = 0; + BasicBlock* entry_bb = func->getEntryBlock(); // 获取函数的入口基本块 + + if (entry_bb) { // 确保入口基本块存在 + for (AllocaInst* alloca_for_param : entry_bb->getArguments()) { + if (arg_idx >= 8) { + std::cerr << "警告: 函数 '" << func->getName() << "' 的参数 (索引 " << arg_idx << ") 数量超过了 RISC-V 寄存器传递限制 (8个参数)。\n" + << " 这些参数目前未通过栈正确处理,可能导致错误。\n"; + break; + } + + if (alloc_result.stack_map.count(alloca_for_param)) { + int offset = alloc_result.stack_map.at(alloca_for_param); + Type* allocated_type = alloca_for_param->getType()->as()->getBaseType(); + + if (allocated_type->isInt()) { + PhysicalReg arg_reg = static_cast(static_cast(PhysicalReg::A0) + arg_idx); + std::string arg_reg_str = reg_to_string(arg_reg); + // 使用 sw 保存 int (32位) 参数,这是正确的 + ss << " sw " << arg_reg_str << ", " << offset << "(s0)\n"; + } else if (allocated_type->isFloat()) { + PhysicalReg farg_reg = static_cast(static_cast(PhysicalReg::F10) + arg_idx); + std::string farg_reg_str = reg_to_string(farg_reg); + // 使用 fsw 保存 float (32位) 参数,这是正确的 + ss << " fsw " << farg_reg_str << ", " << offset << "(s0)\n"; + } else { + throw std::runtime_error("Unsupported function argument type encountered during parameter saving to stack."); + } + } else { + std::cerr << "警告: 函数参数对应的 AllocaInst '" + << (alloca_for_param->getName().empty() ? "anonymous" : alloca_for_param->getName()) + << "' 没有在栈映射中找到。这可能导致后续代码生成错误。\n"; + } + arg_idx++; + } + } else { + std::cerr << "错误: 函数 '" << func->getName() << "' 没有入口基本块。\n"; + } + + // 生成每个基本块的代码 + int block_idx = 0; + for (const auto& bb : func->getBasicBlocks()) { + ss << basicBlock_gen(bb.get(), alloc_result, block_idx++); + } + + // 函数尾声 (Epilogue) 由 RETURN DAGNode 的指令选择处理 + return ss.str(); +} + + +// 基本块代码生成 (无修改) +std::string RISCv64CodeGen::basicBlock_gen(BasicBlock* bb, const RegAllocResult& alloc, int block_idx) { + std::stringstream ss; + + std::string bb_name = bb->getName(); + if (bb_name.empty()) { + bb_name = ENTRY_BLOCK_PSEUDO_NAME + std::to_string(block_idx); + if (block_idx == 0) { + bb_name = "entry"; + } + } + else { + ss << bb_name << ":\n"; // 基本块标签 + } + // !!! 重要的修改:此处不再清除 value_vreg_map 和 vreg_counter。 + // !!! 这些映射在 function_gen -> register_allocation 阶段为整个函数建立。 + // 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); // 为当前节点选择指令 + } + + // 收集所有指令到一个临时的 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(); +} + + +std::vector> RISCv64CodeGen::build_dag(BasicBlock* bb) { + std::vector> nodes_storage; // 存储所有 unique_ptr + std::map value_to_node; // 将 IR Value* 映射到原始 DAGNode*,用于快速查找 + + // 辅助函数,用于创建 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 && kind != DAGNode::UNARY) { + return value_to_node[val]; + } + + auto node = std::make_unique(kind); + node->value = val; + + // 为产生结果的值分配虚拟寄存器 + // 注意:这里的vreg分配是在每个块中独立进行的,但寄存器分配器是在函数级别运行的 + // 我们在寄存器分配前,已经为整个函数的所有value预分配了vreg + // 此处的逻辑应完全依赖于 register_allocation 阶段已经建立的 value_vreg_map + // 并且 AllocaInst 不应在此处获取 result_vreg,因为它不映射到物理寄存器。 + if (val && value_vreg_map.count(val) && !dynamic_cast(val)) { // 排除 AllocaInst + node->result_vreg = value_vreg_map.at(val); + } + // 如果 val 即使在 value_vreg_map 中存在,但它是 AllocaInst,则不分配 result_vreg。 + // 对于 DAGNode::ALLOCA_ADDR 节点,它的 result_vreg 应该为空,因为其“值”是内存地址, + // 在指令选择时直接转换为 s0 + 偏移量。 + + DAGNode* raw_node_ptr = node.get(); + nodes_storage.push_back(std::move(node)); // 存储 unique_ptr + + // 仅当 IR Value 表示一个计算值时,才将其映射到创建的 DAGNode + // 且它应该已经在 register_allocation 中被分配了 vreg + if (val && value_vreg_map.count(val) && kind != DAGNode::STORE && kind != DAGNode::RETURN && kind != DAGNode::BRANCH && !dynamic_cast(val)) { + 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` 字段中。 + // 修正:AllocaInst 类型的 DAGNode 应该有一个 value 对应 AllocaInst* + // 但它本身不应该有 result_vreg,因为不映射到物理寄存器。 + create_node(DAGNode::ALLOCA_ADDR, alloca); + } 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* 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,我们应该找到代表它地址的节点 + // 为了简化,如果没找到,就创建一个 + // 修正:AllocaInst 应该直接映射到 ALLOCA_ADDR 节点,其值是 AllocaInst* + 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); // 这是一个产生指针的指令 + } + + 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)) { + // 修正:AllocaInst 应该直接映射到 ALLOCA_ADDR 节点 + 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 + + // --- 关键修改:识别 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(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::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(operand_ir)) { + operand_node = create_node(DAGNode::CONSTANT, constant); + } else { + operand_node = create_node(DAGNode::LOAD, operand_ir); + } + unary_node->operands.push_back(operand_node); + operand_node->users.push_back(unary_node); + continue; // 已处理,跳过后续的常规 Binary 处理 + } + } + } + // --- 结束关键修改 --- + + // 常规二进制操作 + auto bin_node = create_node(DAGNode::BINARY, bin); + + auto get_operand_node = [&](Value* operand_ir) -> DAGNode* { + 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); + } + }; + + 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 un_inst = dynamic_cast(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(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(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 + 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); + } + 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); + } + } 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(); + } + } + + return nodes_storage; +} + +// 打印 DAG (保持不变) +void RISCv64CodeGen::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 RISCv64CodeGen::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)); + } + return reg_to_string(PhysicalReg::T0); // 回退到临时寄存器 t0 + }; + + // 获取栈变量的内存偏移量 + auto get_stack_offset = [&](Value* val) { + if (alloc.stack_map.count(val)) { + return std::to_string(alloc.stack_map.at(val)); + } + 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(); + } 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; + } + } 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; + } + case DAGNode::ALLOCA_ADDR: { + // ALLOCA_ADDR 节点不直接生成指令,由 LOAD/STORE 使用 + break; + } + case DAGNode::LOAD: { + // 处理加载指令 + if (node->operands.empty() || !node->operands[0]) break; + std::string dest_reg = get_preg_or_temp(node->result_vreg); + DAGNode* ptr_node = node->operands[0]; + + 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 { + std::string ptr_reg = get_preg_or_temp(ptr_node->result_vreg); + ss_inst << "lw " << dest_reg << ", 0(" << ptr_reg << ")"; + } + break; + } + case DAGNode::STORE: { + // 处理存储指令 + if (node->operands.size() < 2 || !node->operands[0] || !node->operands[1]) break; + DAGNode* val_node = node->operands[0]; + DAGNode* ptr_node = node->operands[1]; + + std::string src_reg; + if (val_node->kind == DAGNode::CONSTANT) { + src_reg = get_preg_or_temp(val_node->result_vreg); + } else { + src_reg = get_preg_or_temp(val_node->result_vreg); + } + + 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 { + 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()) { + // RV64 修改: 使用带 'w' 后缀的32位指令,确保结果被正确符号扩展 + case BinaryInst::kAdd: opcode = "addw"; break; + case BinaryInst::kSub: opcode = "subw"; break; + case BinaryInst::kMul: opcode = "mulw"; break; + case Instruction::kDiv: opcode = "divw"; break; + case Instruction::kRem: opcode = "remw"; break; + case BinaryInst::kICmpEQ: + // RV64 修改: 使用 subw + ss_inst << "subw " << dest_reg << ", " << lhs_reg << ", " << rhs_reg << "\n"; + ss_inst << " seqz " << dest_reg << ", " << dest_reg; + node->inst = ss_inst.str(); + return; + case BinaryInst::kICmpGE: + // slt 比较64位寄存器,由于 lw 和 'w' 指令都进行了符号扩展,这里的比较是正确的 + 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: + opcode = "slt"; + ss_inst << opcode << " " << dest_reg << ", " << rhs_reg << ", " << lhs_reg; + node->inst = ss_inst.str(); + return; + case BinaryInst::kICmpLE: + ss_inst << "slt " << dest_reg << ", " << rhs_reg << ", " << lhs_reg << "\n"; + ss_inst << " xori " << dest_reg << ", " << dest_reg << ", 1"; + node->inst = ss_inst.str(); + return; + case BinaryInst::kICmpLT: + opcode = "slt"; + ss_inst << opcode << " " << dest_reg << ", " << lhs_reg << ", " << rhs_reg; + node->inst = ss_inst.str(); + return; + case BinaryInst::kICmpNE: + // RV64 修改: 使用 subw + ss_inst << "subw " << 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("不支持的二元指令类型: " + bin->getKindString()); + } + if (!opcode.empty()) { + ss_inst << opcode << " " << dest_reg << ", " << lhs_reg << ", " << rhs_reg; + } + break; + } + case DAGNode::UNARY: { + if (node->operands.empty() || !node->operands[0]) break; + auto unary = dynamic_cast(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: + // RV64 修改: 使用 subw 实现32位取负 (negw 伪指令) + ss_inst << "subw " << dest_reg << ", x0, " << src_reg; + break; + case UnaryInst::kNot: + // 整数逻辑非:seqz rd, rs (rs == 0 时 rd = 1,否则 rd = 0) + ss_inst << "seqz " << dest_reg << ", " << src_reg; + break; + case UnaryInst::kFNeg: + case UnaryInst::kFNot: + case UnaryInst::kFtoI: + case UnaryInst::kItoF: + case UnaryInst::kBitFtoI: + case UnaryInst::kBitItoF: + // 浮点相关指令,当前不支持 + throw std::runtime_error("不支持的浮点一元指令类型: " + unary->getKindString()); + default: + throw std::runtime_error("不支持的一元指令类型: " + unary->getKindString()); + } + break; + } + case DAGNode::CALL: { + // 处理函数调用指令 + if (!node->value) break; + auto call = dynamic_cast(node->value); + if (!call) break; + + 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) { + 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"; + } + } + } + ss_inst << "call " << call->getCallee()->getName(); + + 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: { + // 处理返回指令 + if (!node->operands.empty() && node->operands[0]) { + std::string return_val_reg = get_preg_or_temp(node->operands[0]->result_vreg); + ss_inst << "mv a0, " << return_val_reg << "\n"; + } + + if (alloc.stack_size > 0) { + int aligned_stack_size = (alloc.stack_size + 15) & ~15; + // RV64 修改: 使用 ld (load doubleword) 恢复 8 字节的 ra 和 s0 + // 并使用正确的偏移量 + ss_inst << " ld ra, " << (aligned_stack_size - 8) << "(sp)\n"; + ss_inst << " ld s0, " << (aligned_stack_size - 16) << "(sp)\n"; + 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"; + } + if (else_block.empty()) { + else_block = ENTRY_BLOCK_PSEUDO_NAME + "else"; + } + + ss_inst << "bnez " << cond_reg << ", " << then_block << "\n"; + ss_inst << " j " << else_block; + } else if (uncond_br) { + std::string target_block = uncond_br->getBlock()->getName(); + if (target_block.empty()) { + target_block = ENTRY_BLOCK_PSEUDO_NAME + "target"; + } + ss_inst << "j " << target_block; + } + } else { + ss_inst << node->inst; + } + break; + } + default: + throw std::runtime_error("不支持的节点类型: " + node->getNodeKindString()); + } + node->inst = ss_inst.str(); // 存储生成的指令 +} + +// 指令发射 +void RISCv64CodeGen::emit_instructions(DAGNode* node, std::stringstream& ss, const RegAllocResult& alloc, std::set& emitted_nodes) { + if (!node || emitted_nodes.count(node)) { + return; // 已发射或为空 + } + + // 递归地发射操作数以确保满足依赖关系 + for (auto operand : node->operands) { + if (operand) { + emit_instructions(operand, ss, alloc, emitted_nodes); + } + } + + // 标记当前节点为已发射 + 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); + } + + // 替换操作数虚拟寄存器 (如果此行中存在) + 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); + } + } + + // 添加处理后的指令 + ss << " " << processed_line << "\n"; + } +} + +// 辅助函数:将集合打印为字符串 +std::string print_set(const std::set& s) { + std::stringstream ss; + ss << "{"; + bool first = true; + for (const auto& elem : s) { + if (!first) { + ss << ", "; + } + ss << elem; + first = false; + } + ss << "}"; + return ss.str(); +} + +// 活跃性分析(更新以支持浮点指令) +std::map> RISCv64CodeGen::liveness_analysis(Function* func) { + std::map> live_in, live_out; + bool changed = true; + + for (const auto& bb : func->getBasicBlocks()) { + for (const auto& inst_ptr : bb->getInstructions()) { + live_in[inst_ptr.get()] = {}; + live_out[inst_ptr.get()] = {}; + } + } + + int iteration_count = 0; + while (changed) { + changed = false; + iteration_count++; + if (DEEPDEBUG) std::cerr << "\n--- 活跃性分析迭代: " << iteration_count << " ---" << std::endl; + + for (auto it = func->getBasicBlocks_NoRange().rbegin(); it != func->getBasicBlocks_NoRange().rend(); ++it) { + auto bb = it->get(); + if (DEEPDEBUG) std::cerr << " 基本块: " << bb->getName() << std::endl; + + std::set live_out_for_bb_inst = {}; + for (const auto& succ_bb : bb->getSuccessors()) { + if (!succ_bb->getInstructions().empty()) { + Instruction* first_inst_in_succ = succ_bb->getInstructions().front().get(); + live_out_for_bb_inst.insert(live_in[first_inst_in_succ].begin(), live_in[first_inst_in_succ].end()); + } + } + + for (auto inst_it = bb->getInstructions().rbegin(); inst_it != bb->getInstructions().rend(); ++inst_it) { + auto inst = inst_it->get(); + if (DEEPDEBUG) std::cerr << " 指令 (BB: " << bb->getName() << ", 地址: " << static_cast(inst) << ")" << std::endl; + + std::set current_live_in = live_in[inst]; + std::set current_live_out = live_out[inst]; + std::set new_live_out_calc; + + if (inst_it == bb->getInstructions().rbegin()) { + new_live_out_calc = live_out_for_bb_inst; + if (DEEPDEBUG) std::cerr << " 指令是基本块的最后一条指令,live_out 取自后继基本块 live_in 的并集: " << print_set(new_live_out_calc) << std::endl; + } else { + auto prev_inst_it = std::prev(inst_it); + new_live_out_calc = live_in[prev_inst_it->get()]; + if (DEEPDEBUG) std::cerr << " 指令不是基本块的最后一条,其 live_out 是其后继指令 live_in: " << print_set(new_live_out_calc) << std::endl; + } + + std::set use_set, def_set; + + // 定义 (Def) + if (!inst->getType()->isVoid() && !dynamic_cast(inst) && !dynamic_cast(inst) && + !dynamic_cast(inst) && !dynamic_cast(inst) && !dynamic_cast(inst) && value_vreg_map.count(inst)) { + def_set.insert(value_vreg_map.at(inst)); + if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast(inst) << ") 定义了虚拟寄存器: " << value_vreg_map.at(inst) << std::endl; + } + + // StoreInst 的值可能被“杀死” + if (auto store = dynamic_cast(inst)) { + Value* stored_value = store->getValue(); + if (value_vreg_map.count(stored_value) && !dynamic_cast(stored_value)) { + bool is_unique_user = true; + if (!stored_value->getUses().empty()) { + is_unique_user = (stored_value->getUses().size() == 1 && stored_value->getUses().front()->getUser() == inst); + } else { + is_unique_user = false; + } + if (is_unique_user) { + def_set.insert(value_vreg_map.at(stored_value)); + if (DEEPDEBUG) std::cerr << " Store 指令 (地址: " << static_cast(inst) << ") 将被存储的值 '" << value_vreg_map.at(stored_value) << "' 添加到 def_set (启发式)." << std::endl; + } + } + } + + // 使用 (Use) + for (const auto& operand_use : inst->getOperands()) { + Value* operand = operand_use->getValue(); + if (value_vreg_map.count(operand) && !dynamic_cast(operand)) { + use_set.insert(value_vreg_map.at(operand)); + if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast(inst) << ") 使用了虚拟寄存器: " << value_vreg_map.at(operand) << std::endl; + } + } + if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast(inst) << ") 的 use_set: " << print_set(use_set) << std::endl; + if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast(inst) << ") 的 def_set: " << print_set(def_set) << std::endl; + + std::set new_live_in = use_set; + for (const auto& vreg : new_live_out_calc) { + if (def_set.find(vreg) == def_set.end()) { + new_live_in.insert(vreg); + } + } + + if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast(inst) << ") 计算出的 new_live_in: " << print_set(new_live_in) << std::endl; + if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast(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) { + live_in[inst] = new_live_in; + live_out[inst] = new_live_out_calc; + changed = true; + if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast(inst) << ") 活跃性集合发生变化,更新并继续迭代." << std::endl; + } + } + } + } + return live_in; +} + +// 干扰图构建 (基本保持不变) +std::map> RISCv64CodeGen::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; + // 修正:只有当指令结果是需要物理寄存器时才视为定义。 + // AllocaInst 不应在此处处理。 + if (value_vreg_map.count(inst) && !dynamic_cast(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); // 对称边 + } + } + } + } + return graph; +} + +// 图着色(支持浮点寄存器) +void RISCv64CodeGen::color_graph(std::map& vreg_to_preg, + const std::map>& interference_graph) { + vreg_to_preg.clear(); + + // 分离整数和浮点寄存器池 + std::vector 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 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(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(pair.first)) { + return constant->isFloat(); + } + } + } + return false; // 默认整数 + }; + + // 按度数排序虚拟寄存器 + std::vector> vreg_degrees; + for (const auto& entry : interference_graph) { + vreg_degrees.push_back({entry.first, (int)entry.second.size()}); + } + std::sort(vreg_degrees.begin(), vreg_degrees.end(), + [](const auto& a, const auto& b) { return a.second > b.second; }); + + for (const auto& vreg_deg_pair : vreg_degrees) { + const std::string& vreg = vreg_deg_pair.first; + std::set used_colors; + bool is_float = is_float_vreg(vreg); + + // 收集邻居使用的颜色 + if (interference_graph.count(vreg)) { + for (const auto& neighbor_vreg : interference_graph.at(vreg)) { + if (vreg_to_preg.count(neighbor_vreg)) { + used_colors.insert(vreg_to_preg.at(neighbor_vreg)); + } + } + } + + // 选择合适的寄存器池 + const auto& available_regs = is_float ? float_regs : int_regs; + + // 查找第一个可用的寄存器 + bool colored = false; + for (PhysicalReg preg : available_regs) { + if (used_colors.find(preg) == used_colors.end()) { + vreg_to_preg[vreg] = preg; + colored = true; + break; + } + } + + if (!colored) { + std::cerr << "警告: 无法为 " << vreg << " 分配" << (is_float ? "浮点" : "整数") << "寄存器,将溢出到栈。\n"; + // 溢出处理:在 stack_map 中分配栈空间 + // 这里假设每个溢出变量占用 4 字节 + // 注意:实际中需要区分整数和浮点溢出的存储指令(如 sw vs fsw) + } + } +} + +// 寄存器分配 +RISCv64CodeGen::RegAllocResult RISCv64CodeGen::register_allocation(Function* func) { + eliminate_phi(func); + vreg_counter = 0; + value_vreg_map.clear(); + + // 为所有产生值的指令和操作数分配虚拟寄存器 + for (const auto& bb_ptr : func->getBasicBlocks()) { + for (const auto& inst_ptr : bb_ptr->getInstructions()) { + Instruction* inst = inst_ptr.get(); + if (!inst->getType()->isVoid() && !dynamic_cast(inst)) { + if (value_vreg_map.find(inst) == value_vreg_map.end()) { + value_vreg_map[inst] = "v" + std::to_string(vreg_counter++); + } + } + 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++); + } + } else if (auto op_inst = dynamic_cast(operand)) { + if (!op_inst->getType()->isVoid() && !dynamic_cast(operand)) { + if (value_vreg_map.find(operand) == value_vreg_map.end()) { + value_vreg_map[operand] = "v" + std::to_string(vreg_counter++); + } + } + } + } + } + } + + RegAllocResult alloc_result; + int current_stack_offset = 0; + 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); + } + } + } + + for (auto alloca : allocas_in_func) { + int size = 4; // 假设 i32 或 float, 依旧是4字节 + alloc_result.stack_map[alloca] = current_stack_offset; + current_stack_offset += size; + } + // RV64 修改: 为保存的 ra 和 s0 (各8字节) 预留16字节空间 + alloc_result.stack_size = current_stack_offset + 16; + + // 活跃性分析 + std::map> live_sets = liveness_analysis(func); + + // 构建干扰图 + std::map> interference_graph = build_interference_graph(live_sets); + + // 图着色 + color_graph(alloc_result.vreg_to_preg, interference_graph); + + if (DEBUG) { + std::cerr << "=== 寄存器分配结果 (vreg_to_preg) ===\n"; + for (const auto& pair : alloc_result.vreg_to_preg) { + std::cerr << " " << pair.first << " -> " << reg_to_string(pair.second) << "\n"; + } + std::cerr << "=== 寄存器分配结果结束 ===\n\n"; + + std::cerr << "=== 活跃性分析结果 (live_in sets) ===\n"; + for (const auto& bb_ptr : func->getBasicBlocks()) { + std::cerr << "Basic Block: " << bb_ptr->getName() << "\n"; + for (const auto& inst_ptr : bb_ptr->getInstructions()) { + std::cerr << " Inst: " << inst_ptr->getKindString(); + if (!inst_ptr->getName().empty()) { + std::cerr << "(" << inst_ptr->getName() << ")"; + } + if (value_vreg_map.count(inst_ptr.get())) { + std::cerr << " (Def vreg: " << value_vreg_map.at(inst_ptr.get()) << ")"; + } + std::cerr << " (Live In: {"; + bool first = true; + if (live_sets.count(inst_ptr.get())) { + for (const auto& vreg : live_sets.at(inst_ptr.get())) { + if (!first) std::cerr << ", "; + std::cerr << vreg; + first = false; + } + } + std::cerr << "})\n"; + } + } + std::cerr << "=== 活跃性分析结果结束 ===\n\n"; + + std::cerr << "=== 干扰图 ===\n"; + for (const auto& pair : interference_graph) { + std::cerr << " " << pair.first << ": {"; + bool first = true; + for (const auto& neighbor : pair.second) { + if (!first) std::cerr << ", "; + std::cerr << neighbor; + first = false; + } + std::cerr << "}\n"; + } + std::cerr << "=== 干扰图结束 ===\n\n"; + } + + return alloc_result; +} + +// Phi 消除 (简化版,将 Phi 的结果直接复制到每个前驱基本块的末尾) +void RISCv64CodeGen::eliminate_phi(Function* func) { + // 这是一个占位符。适当的 phi 消除将涉及 + // 在每个前驱基本块的末尾插入 `mov` 指令,用于每个 phi 操作数。 + // 对于给定的 IR 示例,没有 phi 节点,所以这可能不是严格必要的, + // 但如果前端生成 phi 节点,则有此阶段是好的做法。 + // 目前,我们假设没有生成 phi 节点或者它们已在前端处理。 +} + +} // namespace sysy \ No newline at end of file diff --git a/src/RISCv64Backend.h b/src/RISCv64Backend.h new file mode 100644 index 0000000..beea4e2 --- /dev/null +++ b/src/RISCv64Backend.h @@ -0,0 +1,100 @@ +#ifndef RISCV64_BACKEND_H +#define RISCV64_BACKEND_H + +#include "IR.h" +#include +#include +#include +#include +#include +#include +#include // For std::function + +namespace sysy { + +class RISCv64CodeGen { +public: + enum class PhysicalReg { + 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, + F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15,F16, F17, F18, F19, F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, F31 + }; + + // Move DAGNode and RegAllocResult to public section + struct DAGNode { + enum NodeKind { CONSTANT, LOAD, STORE, BINARY, CALL, RETURN, BRANCH, ALLOCA_ADDR, UNARY }; + 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 + std::vector operands; + std::vector users; // For debugging and potentially optimizations + DAGNode(NodeKind k) : kind(k) {} + + // Debugging / helper + std::string getNodeKindString() const { + switch (kind) { + case CONSTANT: return "CONSTANT"; + case LOAD: return "LOAD"; + case STORE: return "STORE"; + case BINARY: return "BINARY"; + case CALL: return "CALL"; + case RETURN: return "RETURN"; + case BRANCH: return "BRANCH"; + case ALLOCA_ADDR: return "ALLOCA_ADDR"; + case UNARY: return "UNARY"; + default: return "UNKNOWN"; + } + } + }; + + 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 + }; + + RISCv64CodeGen(Module* mod) : module(mod) {} + + 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); + +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 + + // 新增一个成员变量来存储当前函数的所有 DAGNode,以确保其生命周期贯穿整个函数代码生成 + // 这样可以在多个 BasicBlock_gen 调用中访问到完整的 DAG 节点 + std::vector> current_function_dag_nodes; + + // 为空标签定义一个伪名称前缀,加上块索引以确保唯一性 + const std::string ENTRY_BLOCK_PSEUDO_NAME = "entry_block_"; +}; + +} // namespace sysy + +#endif // RISCV64_BACKEND_H \ No newline at end of file diff --git a/src/sysyc.cpp b/src/sysyc.cpp index 0b3d701..17faa35 100644 --- a/src/sysyc.cpp +++ b/src/sysyc.cpp @@ -10,7 +10,7 @@ using namespace antlr4; #include "SysYIRGenerator.h" #include "SysYIRPrinter.h" #include "SysYIROptPre.h" -#include "RISCv32Backend.h" +#include "RISCv64Backend.h" // #include "LLVMIRGenerator.h" using namespace sysy; @@ -88,7 +88,7 @@ int main(int argc, char **argv) { // generate assembly auto module = generator.get(); - sysy::RISCv32CodeGen codegen(module); + sysy::RISCv64CodeGen codegen(module); string asmCode = codegen.code_gen(); if (argStopAfter == "asm") { cout << asmCode << endl; diff --git a/test_script/runit.sh b/test_script/runit.sh index 6e95bff..1627882 100644 --- a/test_script/runit.sh +++ b/test_script/runit.sh @@ -8,7 +8,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" TESTDATA_DIR="${SCRIPT_DIR}/../testdata" BUILD_BIN_DIR="${SCRIPT_DIR}/../build/bin" LIB_DIR="${SCRIPT_DIR}/../lib" -TMP_DIR="${SCRIPT_DIR}/tmp" +TMP_DIR="/home/ladev987/paraComp/debug/share_folder" # 定义编译器和模拟器 SYSYC="${BUILD_BIN_DIR}/sysyc"