[backend] implemented call function parameter passing using registers
This commit is contained in:
@@ -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<PointerType>()->getBaseType();
|
||||
|
||||
// 根据参数类型选择源寄存器和存储指令
|
||||
if (allocated_type->isInt()) {
|
||||
PhysicalReg arg_reg = static_cast<PhysicalReg>(static_cast<int>(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<PhysicalReg>(static_cast<int>(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:
|
||||
|
||||
Reference in New Issue
Block a user