From c04f508171880a987e12ba80a15e40e237431787 Mon Sep 17 00:00:00 2001 From: Lixuanwang Date: Wed, 25 Jun 2025 06:27:05 +0800 Subject: [PATCH] [backend] implemented call function parameter passing using registers --- src/RISCv32Backend.cpp | 77 ++++++++++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 17 deletions(-) diff --git a/src/RISCv32Backend.cpp b/src/RISCv32Backend.cpp index aaf1fd6..c02f9e1 100644 --- a/src/RISCv32Backend.cpp +++ b/src/RISCv32Backend.cpp @@ -152,24 +152,15 @@ std::string RISCv32CodeGen::function_gen(Function* func) { ss << ".globl " << func->getName() << "\n"; // 声明函数为全局符号 ss << func->getName() << ":\n"; // 函数入口标签 - // 执行寄存器分配 - // 注意:vreg_counter 和 value_vreg_map 在 register_allocation 内部会被初始化 - auto alloc = register_allocation(func); - int stack_size = alloc.stack_size; + // 执行寄存器分配。alloc_result 包含了虚拟寄存器到物理寄存器的映射, + // 以及 AllocaInst 到栈偏移的映射 (stack_map)。 + // 在 register_allocation 内部,我们将确保参数和它们的 AllocaInst 之间建立映射。 + RegAllocResult alloc_result = register_allocation(func); + int stack_size = alloc_result.stack_size; // 函数序言 (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; @@ -181,16 +172,68 @@ std::string RISCv32CodeGen::function_gen(Function* func) { ss << " mv s0, sp\n"; // 设置新的帧指针 } + // *** 新增的逻辑:处理传入的函数参数 *** + // 将传入的寄存器参数 (a0-a7 / f10-f17) 保存到对应的栈槽 (AllocaInst)。 + // 这适用于参数被前端视为局部变量并立即 alloca 的情况。 + int arg_idx = 0; + BasicBlock* entry_bb = func->getEntryBlock(); // 获取函数的入口基本块 + + if (entry_bb) { // 确保入口基本块存在 + // 遍历入口基本块的形式参数列表 (这些通常是对应的 AllocaInst) + for (AllocaInst* alloca_for_param : entry_bb->getArguments()) { + // RISC-V ABI 规定前8个参数通过寄存器传递 (a0-a7 for int, f10-f17 for float) + if (arg_idx >= 8) { + std::cerr << "警告: 函数 '" << func->getName() << "' 的参数 (索引 " << arg_idx << ") 数量超过了 RISC-V 寄存器传递限制 (8个参数)。\n" + << " 这些参数目前未通过栈正确处理,可能导致错误。\n"; + break; // 简化处理,暂时不支持超过8个的栈传递参数 + } + + // 检查该 AllocaInst 是否有栈映射(应该在 register_allocation 阶段被分配) + if (alloc_result.stack_map.count(alloca_for_param)) { // AllocaInst* 直接作为键 + int offset = alloc_result.stack_map.at(alloca_for_param); // 获取栈偏移 + + // 获取 AllocaInst 所分配的内存的基类型(例如,i32* %x0 对应的基类型是 i32) + 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); + ss << " sw " << arg_reg_str << ", " << offset << "(s0)\n"; + } else if (allocated_type->isFloat()) { + PhysicalReg farg_reg = static_cast(static_cast(PhysicalReg::F10) + arg_idx); // RISC-V 浮点参数通常从f10开始 + std::string farg_reg_str = reg_to_string(farg_reg); + 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; // 用于生成默认 entry 标签的索引 for (const auto& bb : func->getBasicBlocks()) { - ss << basicBlock_gen(bb.get(), alloc, block_idx++); + // basicBlock_gen 的第三个参数是 int block_idx,与 RISCv32Backend.h 中的定义一致 + ss << basicBlock_gen(bb.get(), alloc_result, block_idx++); } // 函数尾声 (Epilogue) 由 RETURN DAGNode 的指令选择处理,确保正确恢复栈和寄存器 + // 注意:这里的尾声生成在 select_instructions 的 RETURN case 中实现, + // 因此在 function_gen 结束时,只需要返回 ss.str()。 return ss.str(); } + // 基本块代码生成 std::string RISCv32CodeGen::basicBlock_gen(BasicBlock* bb, const RegAllocResult& alloc, int block_idx) { std::stringstream ss; @@ -778,8 +821,8 @@ void RISCv32CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al ss_inst << "sub " << dest_reg << ", x0, " << src_reg; break; case UnaryInst::kNot: - // 整数逻辑非:not rd, rs (等价于 xori rd, rs, -1) - ss_inst << "not " << dest_reg << ", " << src_reg; + // 整数逻辑非:seqz rd, rs (rs == 0 时 rd = 1,否则 rd = 0) + ss_inst << "seqz " << dest_reg << ", " << src_reg; break; case UnaryInst::kFNeg: case UnaryInst::kFNot: