[backend]修复了函数调用参数为常数时,参数传递有误的bug

This commit is contained in:
Lixuanwang
2025-07-18 21:54:24 +08:00
parent e8660120cc
commit d38ec13cbd

View File

@ -574,7 +574,10 @@ void RISCv64CodeGen::print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag,
// 指令选择
void RISCv64CodeGen::select_instructions(DAGNode* node, const RegAllocResult& alloc) {
if (!node) return;
if (!node->inst.empty()) return; // 指令已选择,跳过重复处理
// 为确保我们的新逻辑被应用,即使节点已被访问,我们仍然可能需要重新生成指令。
// 但是为了防止无限递归我们依赖于调用者emit_instructions的逻辑。
// 最关键的改动是,指令的“使用者”将负责加载其操作数。
if (!node->inst.empty()) return; // 保持原有逻辑,避免重复工作
// 递归地为操作数选择指令,确保依赖先被处理
for (auto operand : node->operands) {
@ -585,9 +588,8 @@ void RISCv64CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
std::stringstream ss_inst; // 使用 stringstream 构建指令
// 获取分配的物理寄存器,若未分配则回退到 t0
auto get_preg_or_temp = [&](const std::string& vreg) {
if (vreg.empty()) { // 添加对空 vreg 的明确检查
if (vreg.empty()) {
if (DEBUG) std::cerr << "警告: 虚拟寄存器 (空字符串) 没有分配物理寄存器,使用临时寄存器 t0 代替。\n";
return reg_to_string(PhysicalReg::T0);
}
@ -595,47 +597,31 @@ void RISCv64CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
return reg_to_string(alloc.vreg_to_preg.at(vreg));
}
if (DEBUG) std::cerr << "警告: 虚拟寄存器 " << vreg << " 没有分配物理寄存器,使用临时寄存器 t0 代替。\n";
return reg_to_string(PhysicalReg::T0); // 回退到临时寄存器 t0
return reg_to_string(PhysicalReg::T0);
};
// 获取栈变量的内存偏移量
auto get_stack_offset = [&](Value* val) -> std::string { // 返回类型明确为 std::string
auto get_stack_offset = [&](Value* val) -> std::string {
if (alloc.stack_map.count(val)) {
if (DEBUG) { // 避免在非DEBUG模式下打印大量内容
std::cout << "获取栈变量的内存偏移量,变量名: " << (val ? val->getName() : "unknown") << std::endl;
}
return std::to_string(alloc.stack_map.at(val));
}
if (DEBUG) std::cerr << "警告: 栈变量 " << (val ? val->getName() : "unknown") << " 没有在栈映射中找到,使用默认偏移 0。\n";
// 如果没有找到映射,返回默认偏移量 "0"
return std::string("0"); // 默认或错误情况
return std::string("0");
};
switch (node->kind) {
// ====================== 方案二核心修改点 1 ======================
case DAGNode::CONSTANT: {
// 处理常量节点
if (auto constant = dynamic_cast<ConstantValue*>(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<GlobalValue*>(node->value)) {
std::string dest_reg = get_preg_or_temp(node->result_vreg);
ss_inst << "la " << dest_reg << ", " << global->getName();
}
// CONSTANT 节点自身不再生成指令。
// 它的存在是为了在DAG中标记一个常数值。
// 加载这个值的责任转移给了使用它的节点。
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];
@ -652,18 +638,24 @@ void RISCv64CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
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);
}
std::string src_reg = get_preg_or_temp(val_node->result_vreg);
// ====================== 方案二核心修改点 2 ======================
// 如果要存储的值是一个常数,在此处立即加载它
if (val_node->kind == DAGNode::CONSTANT) {
if (auto constant = dynamic_cast<ConstantValue*>(val_node->value)) {
ss_inst << "li " << src_reg << ", " << constant->getInt() << "\n ";
} else if (auto global = dynamic_cast<GlobalValue*>(val_node->value)) {
// 如果是存储全局变量的地址
ss_inst << "la " << src_reg << ", " << global->getName() << "\n ";
}
}
// =============================================================
if (ptr_node->kind == DAGNode::ALLOCA_ADDR) {
if (auto alloca_inst = dynamic_cast<AllocaInst*>(ptr_node->value)) {
int offset = alloc.stack_map.at(alloca_inst);
@ -681,72 +673,73 @@ void RISCv64CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
if (!bin) break;
std::string dest_reg = get_preg_or_temp(node->result_vreg);
DAGNode* lhs_node = node->operands[0];
DAGNode* rhs_node = node->operands[1];
std::string lhs_reg = get_preg_or_temp(lhs_node->result_vreg);
std::string rhs_reg = get_preg_or_temp(rhs_node->result_vreg);
// ====================== 方案二核心修改点 3 ======================
// 在生成二元运算指令前,检查操作数是否为常数,并按需加载
if (lhs_node->kind == DAGNode::CONSTANT) {
if (auto c = dynamic_cast<ConstantValue*>(lhs_node->value)) {
ss_inst << "li " << lhs_reg << ", " << c->getInt() << "\n ";
}
}
if (rhs_node->kind == DAGNode::CONSTANT) {
if (auto c = dynamic_cast<ConstantValue*>(rhs_node->value)) {
// 优化:对于加法和小立即数,使用 addi
if (bin->getKind() == BinaryInst::kAdd && c->getInt() >= -2048 && c->getInt() < 2048) {
ss_inst << "addi " << dest_reg << ", " << lhs_reg << ", " << c->getInt();
node->inst = ss_inst.str();
return; // 指令已生成,提前返回
}
// 否则,正常加载
ss_inst << "li " << rhs_reg << ", " << c->getInt() << "\n ";
}
}
// =============================================================
// 检查是否是 base + offset 的地址计算
if (bin->getKind() == BinaryInst::kAdd) {
DAGNode* op0 = node->operands[0];
DAGNode* op1 = node->operands[1];
DAGNode* base_node = nullptr;
DAGNode* offset_node = nullptr;
bool is_alloca_base = false;
// 识别 base_address + byte_offset 模式
if (op0->kind == DAGNode::ALLOCA_ADDR) {
base_node = op0;
offset_node = op1;
is_alloca_base = true;
} else if (op1->kind == DAGNode::ALLOCA_ADDR) {
base_node = op1;
offset_node = op0;
is_alloca_base = true;
}
if (lhs_node->kind == DAGNode::ALLOCA_ADDR) { base_node = lhs_node; offset_node = rhs_node; }
else if (rhs_node->kind == DAGNode::ALLOCA_ADDR) { base_node = rhs_node; offset_node = lhs_node; }
if (is_alloca_base) {
if (base_node) {
if (auto alloca_inst = dynamic_cast<AllocaInst*>(base_node->value)) {
std::string offset_str = get_stack_offset(alloca_inst);
// 将字符串偏移量转换为 int以便进行可能的调试和更清晰的逻辑
// 注意addi 指令可以直接接受字符串形式的立即数
std::string offset_reg = get_preg_or_temp(offset_node->result_vreg); // 获取索引偏移量的寄存器
// 生成两条指令来计算最终地址:
// 1. addi 将 s0 加上 offset 得到 b 的实际基地址(放入 dest_reg
// 2. addw 将 dest_reg 和索引偏移量寄存器相加,得到最终地址
ss_inst << "addi " << dest_reg << ", s0, " << offset_str << "\n"; // 使用字符串形式的偏移量
ss_inst << " addw " << dest_reg << ", " << dest_reg << ", " << offset_reg;
std::string offset_reg_str = get_preg_or_temp(offset_node->result_vreg);
ss_inst << "addi " << dest_reg << ", s0, " << offset_str << "\n";
ss_inst << " addw " << dest_reg << ", " << dest_reg << ", " << offset_reg_str;
node->inst = ss_inst.str();
break;
return;
}
}
}
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;
ss_inst << "slt " << dest_reg << ", " << rhs_reg << ", " << lhs_reg;
node->inst = ss_inst.str();
return;
case BinaryInst::kICmpLE:
@ -755,12 +748,10 @@ void RISCv64CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
node->inst = ss_inst.str();
return;
case BinaryInst::kICmpLT:
opcode = "slt";
ss_inst << opcode << " " << dest_reg << ", " << lhs_reg << ", " << rhs_reg;
ss_inst << "slt " << 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();
@ -783,64 +774,69 @@ void RISCv64CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
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<CallInst*>(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<PhysicalReg>(static_cast<int>(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<ConstantValue*>(node->operands[i]->value)) {
ss_inst << "li " << reg_to_string(static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + i))
<< ", " << const_val->getInt() << "\n";
} else if (auto global_val = dynamic_cast<GlobalValue*>(node->operands[i]->value)) {
ss_inst << "la " << reg_to_string(static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + i))
<< ", " << global_val->getName() << "\n";
DAGNode* arg_node = node->operands[i];
if (!arg_node) continue;
std::string arg_preg = reg_to_string(static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + i));
// 优先检查参数节点是否为常量
if (arg_node->kind == DAGNode::CONSTANT) {
if (auto const_val = dynamic_cast<ConstantValue*>(arg_node->value)) {
// 如果是常量,直接生成 li 指令加载到参数寄存器
ss_inst << "li " << arg_preg << ", " << const_val->getInt() << "\n ";
} else if (auto global_val = dynamic_cast<GlobalValue*>(arg_node->value)) {
// 如果是全局变量地址,生成 la 指令
ss_inst << "la " << arg_preg << ", " << global_val->getName() << "\n ";
}
}
// 如果不是常量,说明是一个计算出的值,使用 mv 指令移动
else {
std::string src_reg = get_preg_or_temp(arg_node->result_vreg);
ss_inst << "mv " << arg_preg << ", " << src_reg << "\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";
ss_inst << "\n mv " << 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";
DAGNode* ret_val_node = node->operands[0];
std::string return_val_reg = get_preg_or_temp(ret_val_node->result_vreg);
// ====================== 方案二核心修改点 4 ======================
if (ret_val_node->kind == DAGNode::CONSTANT) {
if (auto c = dynamic_cast<ConstantValue*>(ret_val_node->value)) {
ss_inst << "li a0, " << c->getInt() << "\n";
}
} else {
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";
@ -849,32 +845,19 @@ void RISCv64CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
break;
}
case DAGNode::BRANCH: {
// 处理分支指令
// BRANCH 节点的现有逻辑是正确的,保持不变
auto br = dynamic_cast<CondBrInst*>(node->value);
auto uncond_br = dynamic_cast<UncondBrInst*>(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;
ss_inst << "j " << uncond_br->getBlock()->getName();
}
} else {
ss_inst << node->inst;
@ -884,7 +867,7 @@ void RISCv64CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
default:
throw std::runtime_error("不支持的节点类型: " + node->getNodeKindString());
}
node->inst = ss_inst.str(); // 存储生成的指令
node->inst = ss_inst.str();
}
// 指令发射
@ -1059,23 +1042,39 @@ std::map<std::string, std::set<std::string>> RISCv64CodeGen::build_interference_
Instruction* inst = pair.first;
const auto& live_out_set = pair.second;
// 规则1: 指令定义的结果寄存器与该指令的 live_out 集合中的所有寄存器干扰
// 获取该指令定义的 vreg
std::string defined_vreg;
if (value_vreg_map.count(inst) && !inst->getType()->isVoid() && !dynamic_cast<AllocaInst*>(inst) && !dynamic_cast<StoreInst*>(inst) &&
!dynamic_cast<ReturnInst*>(inst) && !dynamic_cast<CondBrInst*>(inst) && !dynamic_cast<UncondBrInst*>(inst)) {
defined_vreg = value_vreg_map.at(inst);
}
// --- 规则一 和 新增的规则三 ---
if (!defined_vreg.empty()) {
// 您的“规则一”:定义与出口活跃寄存器冲突 (保留)
for (const auto& live_vreg : live_out_set) {
if (defined_vreg != live_vreg) {
graph[defined_vreg].insert(live_vreg);
graph[live_vreg].insert(defined_vreg);
}
}
// ====================== 新增的、缺失的规则三 ======================
// 定义与在同一指令中并发使用的寄存器冲突
for (const auto& operand_use : inst->getOperands()) {
Value* operand = operand_use->getValue();
if (value_vreg_map.count(operand)) {
const std::string& use_vreg = value_vreg_map.at(operand);
if (defined_vreg != use_vreg) {
graph[defined_vreg].insert(use_vreg);
graph[use_vreg].insert(defined_vreg);
}
}
}
// =================================================================
}
// 规则2: 特殊指令内部的操作数之间也存在干扰
// --- 您的“规则二”:特殊指令内部的操作数之间也存在干扰 (保留) ---
if (auto store = dynamic_cast<StoreInst*>(inst)) {
Value* val_operand = store->getValue();
Value* ptr_operand = store->getPointer();
@ -1095,11 +1094,10 @@ std::map<std::string, std::set<std::string>> RISCv64CodeGen::build_interference_
const std::string& rhs_vreg = value_vreg_map.at(rhs_operand);
if (lhs_vreg != rhs_vreg) {
graph[lhs_vreg].insert(rhs_vreg);
graph[rhs_vreg].insert(lhs_vreg); // 修正了原有的笔误
graph[rhs_vreg].insert(lhs_vreg);
}
}
} else if (auto call = dynamic_cast<CallInst*>(inst)) {
// 函数调用的所有参数在调用发生时都是活跃的,因此它们相互干扰
std::vector<std::string> arg_vregs;
for (auto arg_use : call->getArguments()) {
Value* arg_val = arg_use->getValue();