[backend]修复了一个全局数组地址的计算问题

This commit is contained in:
Lixuanwang
2025-07-22 00:16:37 +08:00
parent fd6fe22020
commit cf88ca77cb

View File

@ -239,23 +239,21 @@ void RISCv64ISel::selectNode(DAGNode* node) {
Value* lhs = bin->getLhs();
Value* rhs = bin->getRhs();
// 检查是否是“基地址+偏移量”的地址计算模式
if (bin->getKind() == BinaryInst::kAdd) {
Value* base = nullptr;
Value* offset = nullptr;
// 判断哪个是基地址AllocaInst哪个是偏移量
if (dynamic_cast<AllocaInst*>(lhs)) {
// [修改] 扩展基地址的判断,使其可以识别 AllocaInst 或 GlobalValue
if (dynamic_cast<AllocaInst*>(lhs) || dynamic_cast<GlobalValue*>(lhs)) {
base = lhs;
offset = rhs;
} else if (dynamic_cast<AllocaInst*>(rhs)) {
} else if (dynamic_cast<AllocaInst*>(rhs) || dynamic_cast<GlobalValue*>(rhs)) {
base = rhs;
offset = lhs;
}
// 如果成功匹配到模式
// 如果成功匹配到地址计算模式
if (base) {
// [最终修复]
// 1. 先为偏移量加载常量(如果它是常量的话)
if (auto const_offset = dynamic_cast<ConstantValue*>(offset)) {
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
@ -264,14 +262,25 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(li));
}
// 2. 使用FRAME_ADDR伪指令来获取基地址
// 2. [修改] 根据基地址的类型,生成不同的指令来获取基地址
auto base_addr_vreg = getNewVReg(); // 创建一个新的临时vreg来存放基地址
auto frame_addr_instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_ADDR);
frame_addr_instr->addOperand(std::make_unique<RegOperand>(base_addr_vreg));
frame_addr_instr->addOperand(std::make_unique<RegOperand>(getVReg(base)));
CurMBB->addInstruction(std::move(frame_addr_instr));
// 3. 生成真正的add指令计算最终地址
// 情况一:基地址是局部栈变量
if (auto alloca_base = dynamic_cast<AllocaInst*>(base)) {
auto frame_addr_instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_ADDR);
frame_addr_instr->addOperand(std::make_unique<RegOperand>(base_addr_vreg));
frame_addr_instr->addOperand(std::make_unique<RegOperand>(getVReg(alloca_base)));
CurMBB->addInstruction(std::move(frame_addr_instr));
}
// 情况二:基地址是全局变量
else if (auto global_base = dynamic_cast<GlobalValue*>(base)) {
auto la_instr = std::make_unique<MachineInstr>(RVOpcodes::LA);
la_instr->addOperand(std::make_unique<RegOperand>(base_addr_vreg));
la_instr->addOperand(std::make_unique<LabelOperand>(global_base->getName()));
CurMBB->addInstruction(std::move(la_instr));
}
// 3. 生成真正的add指令计算最终地址这部分逻辑保持不变
auto final_addr_vreg = getVReg(bin); // 这是整个二元运算的结果vreg
auto offset_vreg = getVReg(offset);
auto add_instr = std::make_unique<MachineInstr>(RVOpcodes::ADD); // 指针运算是64位
@ -283,7 +292,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
return; // 地址计算处理完毕,直接返回
}
}
// [V2优点] 在BINARY节点内部按需加载常量操作数。
auto load_val_if_const = [&](Value* val) {
if (auto c = dynamic_cast<ConstantValue*>(val)) {