[backend]数组访存问题基本修复

This commit is contained in:
Lixuanwang
2025-07-19 00:32:47 +08:00
parent 0f26be3586
commit 6ed5965b29

View File

@@ -574,10 +574,7 @@ void RISCv64CodeGen::print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag,
// 指令选择 // 指令选择
void RISCv64CodeGen::select_instructions(DAGNode* node, const RegAllocResult& alloc) { void RISCv64CodeGen::select_instructions(DAGNode* node, const RegAllocResult& alloc) {
if (!node) return; if (!node) return;
// 为确保我们的新逻辑被应用,即使节点已被访问,我们仍然可能需要重新生成指令。 if (!node->inst.empty()) return; // 指令已选择,跳过重复处理
// 但是为了防止无限递归我们依赖于调用者emit_instructions的逻辑。
// 最关键的改动是,指令的“使用者”将负责加载其操作数。
if (!node->inst.empty()) return; // 保持原有逻辑,避免重复工作
// 递归地为操作数选择指令,确保依赖先被处理 // 递归地为操作数选择指令,确保依赖先被处理
for (auto operand : node->operands) { for (auto operand : node->operands) {
@@ -588,8 +585,9 @@ void RISCv64CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
std::stringstream ss_inst; // 使用 stringstream 构建指令 std::stringstream ss_inst; // 使用 stringstream 构建指令
// 获取分配的物理寄存器,若未分配则回退到 t0
auto get_preg_or_temp = [&](const std::string& vreg) { auto get_preg_or_temp = [&](const std::string& vreg) {
if (vreg.empty()) { if (vreg.empty()) { // 添加对空 vreg 的明确检查
if (DEBUG) std::cerr << "警告: 虚拟寄存器 (空字符串) 没有分配物理寄存器,使用临时寄存器 t0 代替。\n"; if (DEBUG) std::cerr << "警告: 虚拟寄存器 (空字符串) 没有分配物理寄存器,使用临时寄存器 t0 代替。\n";
return reg_to_string(PhysicalReg::T0); return reg_to_string(PhysicalReg::T0);
} }
@@ -597,31 +595,35 @@ void RISCv64CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
return reg_to_string(alloc.vreg_to_preg.at(vreg)); return reg_to_string(alloc.vreg_to_preg.at(vreg));
} }
if (DEBUG) std::cerr << "警告: 虚拟寄存器 " << vreg << " 没有分配物理寄存器,使用临时寄存器 t0 代替。\n"; if (DEBUG) std::cerr << "警告: 虚拟寄存器 " << vreg << " 没有分配物理寄存器,使用临时寄存器 t0 代替。\n";
return reg_to_string(PhysicalReg::T0); return reg_to_string(PhysicalReg::T0); // 回退到临时寄存器 t0
}; };
auto get_stack_offset = [&](Value* val) -> std::string { // 获取栈变量的内存偏移量
auto get_stack_offset = [&](Value* val) -> std::string { // 返回类型明确为 std::string
if (alloc.stack_map.count(val)) { 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)); return std::to_string(alloc.stack_map.at(val));
} }
return std::string("0"); if (DEBUG) std::cerr << "警告: 栈变量 " << (val ? val->getName() : "unknown") << " 没有在栈映射中找到,使用默认偏移 0。\n";
// 如果没有找到映射,返回默认偏移量 "0"
return std::string("0"); // 默认或错误情况
}; };
switch (node->kind) { switch (node->kind) {
// ====================== 方案二核心修改点 1 ======================
case DAGNode::CONSTANT: { case DAGNode::CONSTANT: {
// CONSTANT 节点自身不再生成指令。 // [V2 特性] CONSTANT 节点自身不再生成指令。
// 它的存在是为了在DAG中标记一个常数值。 // 它的存在是为了在DAG中标记一个常数值或全局地址
// 加载这个值的责任转移给了使用它的节点。 // 加载这个值的责任转移给了使用它的节点 (STORE, BINARY, CALL, RETURN)
break; break;
} }
// =============================================================
case DAGNode::ALLOCA_ADDR: { case DAGNode::ALLOCA_ADDR: {
// ALLOCA_ADDR 节点不直接生成指令,由 LOAD/STORE 使用 // ALLOCA_ADDR 节点不直接生成指令,它仅作为一个地址标记,由 LOAD/STORE 或地址计算使用
break; break;
} }
case DAGNode::LOAD: { case DAGNode::LOAD: {
// 处理加载指令
if (node->operands.empty() || !node->operands[0]) break; if (node->operands.empty() || !node->operands[0]) break;
std::string dest_reg = get_preg_or_temp(node->result_vreg); std::string dest_reg = get_preg_or_temp(node->result_vreg);
DAGNode* ptr_node = node->operands[0]; DAGNode* ptr_node = node->operands[0];
@@ -638,23 +640,30 @@ void RISCv64CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
break; break;
} }
case DAGNode::STORE: { case DAGNode::STORE: {
// 处理存储指令
if (node->operands.size() < 2 || !node->operands[0] || !node->operands[1]) break; if (node->operands.size() < 2 || !node->operands[0] || !node->operands[1]) break;
DAGNode* val_node = node->operands[0]; DAGNode* val_node = node->operands[0];
DAGNode* ptr_node = node->operands[1]; DAGNode* ptr_node = node->operands[1];
std::string src_reg = get_preg_or_temp(val_node->result_vreg); std::string src_reg = get_preg_or_temp(val_node->result_vreg);
// ====================== 方案二核心修改点 2 ====================== // [V2 特性] 如果要存储的值是一个常数,在此处立即加载它
// 如果要存储的值是一个常数,在此处立即加载它
if (val_node->kind == DAGNode::CONSTANT) { if (val_node->kind == DAGNode::CONSTANT) {
if (auto constant = dynamic_cast<ConstantValue*>(val_node->value)) { if (auto constant = dynamic_cast<ConstantValue*>(val_node->value)) {
ss_inst << "li " << src_reg << ", " << constant->getInt() << "\n "; if (constant->isInt()) {
ss_inst << "li " << src_reg << ", " << constant->getInt() << "\n\t";
} else { // 浮点数常量
float f = constant->getFloat();
uint32_t float_bits = *(uint32_t*)&f;
ss_inst << "li " << src_reg << ", " << float_bits << "\n\t";
// 注意:这里假设 src_reg 是一个通用寄存器,需要额外指令移动到浮点寄存器
// 如果 STORE 的目标是浮点数,这里逻辑需要调整
}
} else if (auto global = dynamic_cast<GlobalValue*>(val_node->value)) { } else if (auto global = dynamic_cast<GlobalValue*>(val_node->value)) {
// 如果是存储全局变量的地址 // 如果是存储全局变量的地址
ss_inst << "la " << src_reg << ", " << global->getName() << "\n "; ss_inst << "la " << src_reg << ", " << global->getName() << "\n\t";
} }
} }
// =============================================================
if (ptr_node->kind == DAGNode::ALLOCA_ADDR) { if (ptr_node->kind == DAGNode::ALLOCA_ADDR) {
if (auto alloca_inst = dynamic_cast<AllocaInst*>(ptr_node->value)) { if (auto alloca_inst = dynamic_cast<AllocaInst*>(ptr_node->value)) {
@@ -676,32 +685,7 @@ void RISCv64CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
DAGNode* lhs_node = node->operands[0]; DAGNode* lhs_node = node->operands[0];
DAGNode* rhs_node = node->operands[1]; DAGNode* rhs_node = node->operands[1];
std::string lhs_reg = get_preg_or_temp(lhs_node->result_vreg); // [V1 特性] 检查是否是 base + offset 的地址计算
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) { if (bin->getKind() == BinaryInst::kAdd) {
DAGNode* base_node = nullptr; DAGNode* base_node = nullptr;
DAGNode* offset_node = nullptr; DAGNode* offset_node = nullptr;
@@ -711,31 +695,65 @@ void RISCv64CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
if (base_node) { if (base_node) {
if (auto alloca_inst = dynamic_cast<AllocaInst*>(base_node->value)) { if (auto alloca_inst = dynamic_cast<AllocaInst*>(base_node->value)) {
std::string offset_str = get_stack_offset(alloca_inst); std::string stack_offset_str = get_stack_offset(alloca_inst);
std::string offset_reg_str = get_preg_or_temp(offset_node->result_vreg); std::string index_offset_reg = 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; // 生成两条指令来计算最终地址:
// 1. addi 将 s0 加上 b 的栈偏移量得到 b 的实际基地址
ss_inst << "addi " << dest_reg << ", s0, " << stack_offset_str << "\n";
// 2. [V3 修复] add 将基地址和索引偏移量相加得到最终地址。地址计算必须用64位指令。
ss_inst << "\tadd " << dest_reg << ", " << dest_reg << ", " << index_offset_reg;
node->inst = ss_inst.str(); node->inst = ss_inst.str();
return; return; // 指令已生成,提前返回
} }
} }
} }
std::string lhs_reg = get_preg_or_temp(lhs_node->result_vreg);
std::string rhs_reg = get_preg_or_temp(rhs_node->result_vreg);
// [V2 特性] 在生成二元运算指令前,检查操作数是否为常数,并按需加载
if (lhs_node->kind == DAGNode::CONSTANT) {
if (auto c = dynamic_cast<ConstantValue*>(lhs_node->value)) {
ss_inst << "li " << lhs_reg << ", " << c->getInt() << "\n\t";
}
}
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\t";
}
}
std::string opcode; std::string opcode;
switch (bin->getKind()) { switch (bin->getKind()) {
case BinaryInst::kAdd: opcode = "addw"; break; // [V1 特性] & [V3 修复] RV64 修改: 整数运算使用带 'w' 后缀的32位指令地址运算使用64位指令
case BinaryInst::kAdd:
// 通过检查操作数类型来决定使用 64位(add) 还是 32位(addw) 加法
if (bin->getLhs()->getType()->isPointer() || bin->getRhs()->getType()->isPointer()) {
opcode = "add"; // 指针/地址运算
} else {
opcode = "addw"; // 普通整数运算
}
break;
case BinaryInst::kSub: opcode = "subw"; break; case BinaryInst::kSub: opcode = "subw"; break;
case BinaryInst::kMul: opcode = "mulw"; break; case BinaryInst::kMul: opcode = "mulw"; break;
case Instruction::kDiv: opcode = "divw"; break; case Instruction::kDiv: opcode = "divw"; break;
case Instruction::kRem: opcode = "remw"; break; case Instruction::kRem: opcode = "remw"; break;
case BinaryInst::kICmpEQ: case BinaryInst::kICmpEQ:
ss_inst << "subw " << dest_reg << ", " << lhs_reg << ", " << rhs_reg << "\n"; ss_inst << "subw " << dest_reg << ", " << lhs_reg << ", " << rhs_reg << "\n";
ss_inst << " seqz " << dest_reg << ", " << dest_reg; ss_inst << "\tseqz " << dest_reg << ", " << dest_reg;
node->inst = ss_inst.str(); node->inst = ss_inst.str();
return; return;
case BinaryInst::kICmpGE: case BinaryInst::kICmpGE:
ss_inst << "slt " << dest_reg << ", " << lhs_reg << ", " << rhs_reg << "\n"; ss_inst << "slt " << dest_reg << ", " << lhs_reg << ", " << rhs_reg << "\n";
ss_inst << " xori " << dest_reg << ", " << dest_reg << ", 1"; ss_inst << "\txori " << dest_reg << ", " << dest_reg << ", 1";
node->inst = ss_inst.str(); node->inst = ss_inst.str();
return; return;
case BinaryInst::kICmpGT: case BinaryInst::kICmpGT:
@@ -744,7 +762,7 @@ void RISCv64CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
return; return;
case BinaryInst::kICmpLE: case BinaryInst::kICmpLE:
ss_inst << "slt " << dest_reg << ", " << rhs_reg << ", " << lhs_reg << "\n"; ss_inst << "slt " << dest_reg << ", " << rhs_reg << ", " << lhs_reg << "\n";
ss_inst << " xori " << dest_reg << ", " << dest_reg << ", 1"; ss_inst << "\txori " << dest_reg << ", " << dest_reg << ", 1";
node->inst = ss_inst.str(); node->inst = ss_inst.str();
return; return;
case BinaryInst::kICmpLT: case BinaryInst::kICmpLT:
@@ -753,10 +771,11 @@ void RISCv64CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
return; return;
case BinaryInst::kICmpNE: case BinaryInst::kICmpNE:
ss_inst << "subw " << dest_reg << ", " << lhs_reg << ", " << rhs_reg << "\n"; ss_inst << "subw " << dest_reg << ", " << lhs_reg << ", " << rhs_reg << "\n";
ss_inst << " snez " << dest_reg << ", " << dest_reg; ss_inst << "\tsnez " << dest_reg << ", " << dest_reg;
node->inst = ss_inst.str(); node->inst = ss_inst.str();
return; return;
default: default:
// [V1 特性] 保留对未实现指令的定义和报错
throw std::runtime_error("不支持的二元指令类型: " + bin->getKindString()); throw std::runtime_error("不支持的二元指令类型: " + bin->getKindString());
} }
if (!opcode.empty()) { if (!opcode.empty()) {
@@ -774,100 +793,122 @@ void RISCv64CodeGen::select_instructions(DAGNode* node, const RegAllocResult& al
switch (unary->getKind()) { switch (unary->getKind()) {
case UnaryInst::kNeg: case UnaryInst::kNeg:
// RV64 修改: 使用 subw 实现32位取负 (negw 伪指令)
ss_inst << "subw " << dest_reg << ", x0, " << src_reg; ss_inst << "subw " << dest_reg << ", x0, " << src_reg;
break; break;
case UnaryInst::kNot: case UnaryInst::kNot:
// 整数逻辑非seqz rd, rs (rs == 0 时 rd = 1否则 rd = 0)
ss_inst << "seqz " << dest_reg << ", " << src_reg; ss_inst << "seqz " << dest_reg << ", " << src_reg;
break; break;
// [V1 特性] 保留对未实现指令的定义和报错
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: default:
throw std::runtime_error("不支持的一元指令类型: " + unary->getKindString()); throw std::runtime_error("不支持的一元指令类型: " + unary->getKindString());
} }
break; break;
} }
case DAGNode::CALL: { case DAGNode::CALL: {
// 处理函数调用指令
if (!node->value) break; if (!node->value) break;
auto call = dynamic_cast<CallInst*>(node->value); auto call = dynamic_cast<CallInst*>(node->value);
if (!call) break; if (!call) break;
// ====================== 此处是修正点 ====================== // [V2/V3 特性] 修正参数处理逻辑
for (size_t i = 0; i < node->operands.size() && i < 8; ++i) { for (size_t i = 0; i < node->operands.size() && i < 8; ++i) {
DAGNode* arg_node = node->operands[i]; DAGNode* arg_node = node->operands[i];
if (!arg_node) continue; if (!arg_node) continue;
std::string arg_preg = reg_to_string(static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + i)); std::string arg_preg = reg_to_string(static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + i));
// 优先检查参数节点是否为常量 // 优先检查参数节点是否为常量,并直接加载
if (arg_node->kind == DAGNode::CONSTANT) { if (arg_node->kind == DAGNode::CONSTANT) {
if (auto const_val = dynamic_cast<ConstantValue*>(arg_node->value)) { if (auto const_val = dynamic_cast<ConstantValue*>(arg_node->value)) {
// 如果是常量,直接生成 li 指令加载到参数寄存器 ss_inst << "li " << arg_preg << ", " << const_val->getInt() << "\n\t";
ss_inst << "li " << arg_preg << ", " << const_val->getInt() << "\n ";
} else if (auto global_val = dynamic_cast<GlobalValue*>(arg_node->value)) { } else if (auto global_val = dynamic_cast<GlobalValue*>(arg_node->value)) {
// 如果是全局变量地址,生成 la 指令 ss_inst << "la " << arg_preg << ", " << global_val->getName() << "\n\t";
ss_inst << "la " << arg_preg << ", " << global_val->getName() << "\n ";
} }
} }
// 如果不是常量,说明是一个计算出的值,使用 mv 指令移动 // 如果不是常量,说明是一个计算出的值,使用 mv 指令移动
else { else {
std::string src_reg = get_preg_or_temp(arg_node->result_vreg); std::string src_reg = get_preg_or_temp(arg_node->result_vreg);
ss_inst << "mv " << arg_preg << ", " << src_reg << "\n "; ss_inst << "mv " << arg_preg << ", " << src_reg << "\n\t";
} }
} }
ss_inst << "call " << call->getCallee()->getName(); ss_inst << "call " << call->getCallee()->getName();
// 处理返回值
if ((call->getType()->isInt() || call->getType()->isFloat()) && !node->result_vreg.empty()) { if ((call->getType()->isInt() || call->getType()->isFloat()) && !node->result_vreg.empty()) {
ss_inst << "\n mv " << get_preg_or_temp(node->result_vreg) << ", a0"; ss_inst << "\nmv " << get_preg_or_temp(node->result_vreg) << ", a0";
} }
break; break;
} }
case DAGNode::RETURN: { case DAGNode::RETURN: {
// 处理返回指令
if (!node->operands.empty() && node->operands[0]) { if (!node->operands.empty() && node->operands[0]) {
DAGNode* ret_val_node = node->operands[0]; DAGNode* ret_val_node = node->operands[0];
std::string return_val_reg = get_preg_or_temp(ret_val_node->result_vreg);
// ====================== 方案二核心修改点 4 ====================== // [V2 特性] 如果返回值是常量,直接加载到 a0
if (ret_val_node->kind == DAGNode::CONSTANT) { if (ret_val_node->kind == DAGNode::CONSTANT) {
if (auto c = dynamic_cast<ConstantValue*>(ret_val_node->value)) { if (auto c = dynamic_cast<ConstantValue*>(ret_val_node->value)) {
ss_inst << "li a0, " << c->getInt() << "\n"; ss_inst << "li a0, " << c->getInt() << "\n";
} }
} else { } else {
std::string return_val_reg = get_preg_or_temp(ret_val_node->result_vreg);
ss_inst << "mv a0, " << return_val_reg << "\n"; ss_inst << "mv a0, " << return_val_reg << "\n";
} }
// =============================================================
} }
// 恢复栈帧
if (alloc.stack_size > 0) { if (alloc.stack_size > 0) {
int aligned_stack_size = (alloc.stack_size + 15) & ~15; int aligned_stack_size = (alloc.stack_size + 15) & ~15;
ss_inst << " ld ra, " << (aligned_stack_size - 8) << "(sp)\n"; // RV64 修改: 使用 ld (load doubleword) 恢复 8 字节的 ra 和 s0
ss_inst << " ld s0, " << (aligned_stack_size - 16) << "(sp)\n"; ss_inst << "\tld ra, " << (aligned_stack_size - 8) << "(sp)\n";
ss_inst << " addi sp, sp, " << aligned_stack_size << "\n"; ss_inst << "\tld s0, " << (aligned_stack_size - 16) << "(sp)\n";
ss_inst << "\taddi sp, sp, " << aligned_stack_size << "\n";
} }
ss_inst << " ret"; ss_inst << "\tret";
break; break;
} }
case DAGNode::BRANCH: { case DAGNode::BRANCH: {
// BRANCH 节点的现有逻辑是正确的,保持不变 // 处理分支指令
auto br = dynamic_cast<CondBrInst*>(node->value); auto br = dynamic_cast<CondBrInst*>(node->value);
auto uncond_br = dynamic_cast<UncondBrInst*>(node->value); auto uncond_br = dynamic_cast<UncondBrInst*>(node->value);
if (node->inst.empty()) {
if (br) { if (br) { // 条件分支
if (node->operands.empty() || !node->operands[0]) break; if (node->operands.empty() || !node->operands[0]) break;
std::string cond_reg = get_preg_or_temp(node->operands[0]->result_vreg); std::string cond_reg = get_preg_or_temp(node->operands[0]->result_vreg);
std::string then_block = br->getThenBlock()->getName(); std::string then_block = br->getThenBlock()->getName();
std::string else_block = br->getElseBlock()->getName(); std::string else_block = br->getElseBlock()->getName();
ss_inst << "bnez " << cond_reg << ", " << then_block << "\n";
ss_inst << " j " << else_block; // [V1 特性] 如果基本块没有名字(例如,匿名块),给它一个伪名称
} else if (uncond_br) { if (then_block.empty()) {
ss_inst << "j " << uncond_br->getBlock()->getName(); then_block = ENTRY_BLOCK_PSEUDO_NAME + "_then_" + std::to_string((uintptr_t)br);
} }
} else { if (else_block.empty()) {
ss_inst << node->inst; else_block = ENTRY_BLOCK_PSEUDO_NAME + "_else_" + std::to_string((uintptr_t)br);
}
ss_inst << "bnez " << cond_reg << ", " << then_block << "\n";
ss_inst << "\tj " << 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_" + std::to_string((uintptr_t)uncond_br);
}
ss_inst << "j " << target_block;
} }
break; break;
} }
default: default:
throw std::runtime_error("不支持的节点类型: " + node->getNodeKindString()); throw std::runtime_error("不支持的节点类型: " + node->getNodeKindString());
} }
node->inst = ss_inst.str(); node->inst = ss_inst.str(); // 存储生成的指令
} }
// 指令发射 // 指令发射