[midend][backend-GEP]解决了一个32/64位宽的错误问题
This commit is contained in:
@ -31,6 +31,8 @@ void RISCv64AsmPrinter::run(std::ostream& os, bool debug) {
|
||||
}
|
||||
}
|
||||
|
||||
// 在 RISCv64AsmPrinter.cpp 文件中
|
||||
|
||||
void RISCv64AsmPrinter::printPrologue() {
|
||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||
// 序言需要为保存ra和s0预留16字节
|
||||
@ -44,12 +46,16 @@ void RISCv64AsmPrinter::printPrologue() {
|
||||
*OS << " sd s0, " << (aligned_stack_size - 16) << "(sp)\n";
|
||||
*OS << " addi s0, sp, " << aligned_stack_size << "\n";
|
||||
}
|
||||
|
||||
// 忠实还原保存函数入口参数的逻辑
|
||||
|
||||
// 为函数参数分配寄存器
|
||||
Function* F = MFunc->getFunc();
|
||||
if (F && F->getEntryBlock()) {
|
||||
int arg_idx = 0;
|
||||
RISCv64ISel* isel = MFunc->getISel();
|
||||
|
||||
// 获取函数所有参数的类型列表
|
||||
auto param_types = F->getParamTypes();
|
||||
|
||||
for (AllocaInst* alloca_for_param : F->getEntryBlock()->getArguments()) {
|
||||
if (arg_idx >= 8) break;
|
||||
|
||||
@ -57,7 +63,25 @@ void RISCv64AsmPrinter::printPrologue() {
|
||||
if (frame_info.alloca_offsets.count(vreg)) {
|
||||
int offset = frame_info.alloca_offsets.at(vreg);
|
||||
auto arg_reg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + arg_idx);
|
||||
*OS << " sw " << regToString(arg_reg) << ", " << offset << "(s0)\n";
|
||||
|
||||
// 1. 获取当前参数的真实类型
|
||||
// 注意:F->getParamTypes() 返回的是一个 range-based view,需要转换为vector或直接使用
|
||||
Type* current_param_type = nullptr;
|
||||
int temp_idx = 0;
|
||||
for(auto p_type : param_types) {
|
||||
if (temp_idx == arg_idx) {
|
||||
current_param_type = p_type;
|
||||
break;
|
||||
}
|
||||
temp_idx++;
|
||||
}
|
||||
assert(current_param_type && "Could not find parameter type.");
|
||||
|
||||
// 2. 根据类型决定使用 "sw" 还是 "sd"
|
||||
const char* store_op = current_param_type->isPointer() ? "sd" : "sw";
|
||||
|
||||
// 3. 打印正确的存储指令
|
||||
*OS << " " << store_op << " " << regToString(arg_reg) << ", " << offset << "(s0)\n";
|
||||
}
|
||||
arg_idx++;
|
||||
}
|
||||
@ -133,17 +157,23 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
|
||||
case RVOpcodes::SNEZ: *OS << "snez "; break;
|
||||
case RVOpcodes::CALL: *OS << "call "; break;
|
||||
case RVOpcodes::LABEL:
|
||||
// printOperand(instr->getOperands()[0].get());
|
||||
// *OS << ":";
|
||||
break;
|
||||
case RVOpcodes::FRAME_LOAD:
|
||||
case RVOpcodes::FRAME_LOAD_W:
|
||||
// It should have been eliminated by RegAlloc
|
||||
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
|
||||
*OS << "frame_load "; break;
|
||||
case RVOpcodes::FRAME_STORE:
|
||||
*OS << "frame_load_w "; break;
|
||||
case RVOpcodes::FRAME_LOAD_D:
|
||||
// It should have been eliminated by RegAlloc
|
||||
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
|
||||
*OS << "frame_store "; break;
|
||||
*OS << "frame_load_d "; break;
|
||||
case RVOpcodes::FRAME_STORE_W:
|
||||
// It should have been eliminated by RegAlloc
|
||||
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
|
||||
*OS << "frame_store_w "; break;
|
||||
case RVOpcodes::FRAME_STORE_D:
|
||||
// It should have been eliminated by RegAlloc
|
||||
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
|
||||
*OS << "frame_store_d "; break;
|
||||
case RVOpcodes::FRAME_ADDR:
|
||||
// It should have been eliminated by RegAlloc
|
||||
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
|
||||
|
||||
@ -85,7 +85,7 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
||||
std::stringstream ss;
|
||||
RISCv64AsmPrinter printer(mfunc.get());
|
||||
printer.run(ss);
|
||||
if (DEBUG) ss << ss1.str(); // 将指令选择阶段的结果也包含在最终输出中
|
||||
if (DEBUG) ss << "\n" << ss1.str(); // 将指令选择阶段的结果也包含在最终输出中
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
@ -149,38 +149,51 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
auto dest_vreg = getVReg(node->value);
|
||||
Value* ptr_val = node->operands[0]->value;
|
||||
|
||||
// [V1设计保留] 对于从栈变量加载,继续使用伪指令 FRAME_LOAD。
|
||||
// 这种设计将栈帧布局的具体计算推迟到后续的 `eliminateFrameIndices` 阶段,保持了模块化。
|
||||
// --- 修改点 ---
|
||||
// 1. 获取加载结果的类型 (即这个LOAD指令自身的类型)
|
||||
Type* loaded_type = node->value->getType();
|
||||
|
||||
// 2. 根据类型选择正确的伪指令或真实指令操作码
|
||||
RVOpcodes frame_opcode = loaded_type->isPointer() ? RVOpcodes::FRAME_LOAD_D : RVOpcodes::FRAME_LOAD_W;
|
||||
RVOpcodes real_opcode = loaded_type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW;
|
||||
|
||||
|
||||
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_LOAD);
|
||||
// 3. 创建使用新的、区分宽度的伪指令
|
||||
auto instr = std::make_unique<MachineInstr>(frame_opcode);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(getVReg(alloca)));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
|
||||
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_val)) {
|
||||
// 对于全局变量,先用 la 加载其地址,再用 lw 加载其值。
|
||||
// 对于全局变量,先用 la 加载其地址
|
||||
auto addr_vreg = getNewVReg();
|
||||
auto la = std::make_unique<MachineInstr>(RVOpcodes::LA);
|
||||
la->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
||||
la->addOperand(std::make_unique<LabelOperand>(global->getName()));
|
||||
CurMBB->addInstruction(std::move(la));
|
||||
|
||||
auto lw = std::make_unique<MachineInstr>(RVOpcodes::LW);
|
||||
lw->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
lw->addOperand(std::make_unique<MemOperand>(
|
||||
// 然后根据类型使用 ld 或 lw 加载其值
|
||||
auto load_instr = std::make_unique<MachineInstr>(real_opcode);
|
||||
load_instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
load_instr->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(addr_vreg),
|
||||
std::make_unique<ImmOperand>(0)
|
||||
));
|
||||
CurMBB->addInstruction(std::move(lw));
|
||||
CurMBB->addInstruction(std::move(load_instr));
|
||||
|
||||
} else {
|
||||
// 对于已经在虚拟寄存器中的指针地址,直接通过该地址加载。
|
||||
// 对于已经在虚拟寄存器中的指针地址,直接通过该地址加载
|
||||
auto ptr_vreg = getVReg(ptr_val);
|
||||
auto lw = std::make_unique<MachineInstr>(RVOpcodes::LW);
|
||||
lw->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
lw->addOperand(std::make_unique<MemOperand>(
|
||||
|
||||
// 根据类型使用 ld 或 lw
|
||||
auto load_instr = std::make_unique<MachineInstr>(real_opcode);
|
||||
load_instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
load_instr->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(ptr_vreg),
|
||||
std::make_unique<ImmOperand>(0)
|
||||
));
|
||||
CurMBB->addInstruction(std::move(lw));
|
||||
CurMBB->addInstruction(std::move(load_instr));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -189,13 +202,8 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
Value* val_to_store = node->operands[0]->value;
|
||||
Value* ptr_val = node->operands[1]->value;
|
||||
|
||||
// [V2优点] 在STORE节点内部负责加载作为源的常量。
|
||||
// 如果要存储的值是一个常量,就在这里生成 `li` 指令加载它。
|
||||
// 如果要存储的值是一个常量,就在这里生成 `li` 指令加载它
|
||||
if (auto val_const = dynamic_cast<ConstantValue*>(val_to_store)) {
|
||||
if (DEBUG) {
|
||||
std::cout << "[DEBUG] selectNode-BINARY: Found constant operand with value " << val_const->getInt()
|
||||
<< ". Generating LI instruction." << std::endl;
|
||||
}
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(getVReg(val_const)));
|
||||
li->addOperand(std::make_unique<ImmOperand>(val_const->getInt()));
|
||||
@ -203,37 +211,50 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
}
|
||||
auto val_vreg = getVReg(val_to_store);
|
||||
|
||||
// [V1设计保留] 同样,对于向栈变量的存储,使用 FRAME_STORE 伪指令。
|
||||
// --- 修改点 ---
|
||||
// 1. 获取被存储的值的类型
|
||||
Type* stored_type = val_to_store->getType();
|
||||
|
||||
// 2. 根据类型选择正确的伪指令或真实指令操作码
|
||||
RVOpcodes frame_opcode = stored_type->isPointer() ? RVOpcodes::FRAME_STORE_D : RVOpcodes::FRAME_STORE_W;
|
||||
RVOpcodes real_opcode = stored_type->isPointer() ? RVOpcodes::SD : RVOpcodes::SW;
|
||||
|
||||
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FRAME_STORE);
|
||||
// 3. 创建使用新的、区分宽度的伪指令
|
||||
auto instr = std::make_unique<MachineInstr>(frame_opcode);
|
||||
instr->addOperand(std::make_unique<RegOperand>(val_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(getVReg(alloca)));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
|
||||
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_val)) {
|
||||
// 向全局变量存储。
|
||||
// 向全局变量存储
|
||||
auto addr_vreg = getNewVReg();
|
||||
auto la = std::make_unique<MachineInstr>(RVOpcodes::LA);
|
||||
la->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
||||
la->addOperand(std::make_unique<LabelOperand>(global->getName()));
|
||||
CurMBB->addInstruction(std::move(la));
|
||||
|
||||
auto sw = std::make_unique<MachineInstr>(RVOpcodes::SW);
|
||||
sw->addOperand(std::make_unique<RegOperand>(val_vreg));
|
||||
sw->addOperand(std::make_unique<MemOperand>(
|
||||
// 根据类型使用 sd 或 sw
|
||||
auto store_instr = std::make_unique<MachineInstr>(real_opcode);
|
||||
store_instr->addOperand(std::make_unique<RegOperand>(val_vreg));
|
||||
store_instr->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(addr_vreg),
|
||||
std::make_unique<ImmOperand>(0)
|
||||
));
|
||||
CurMBB->addInstruction(std::move(sw));
|
||||
CurMBB->addInstruction(std::move(store_instr));
|
||||
|
||||
} else {
|
||||
// 向一个指针(存储在虚拟寄存器中)指向的地址存储。
|
||||
// 向一个指针(存储在虚拟寄存器中)指向的地址存储
|
||||
auto ptr_vreg = getVReg(ptr_val);
|
||||
auto sw = std::make_unique<MachineInstr>(RVOpcodes::SW);
|
||||
sw->addOperand(std::make_unique<RegOperand>(val_vreg));
|
||||
sw->addOperand(std::make_unique<MemOperand>(
|
||||
|
||||
// 根据类型使用 sd 或 sw
|
||||
auto store_instr = std::make_unique<MachineInstr>(real_opcode);
|
||||
store_instr->addOperand(std::make_unique<RegOperand>(val_vreg));
|
||||
store_instr->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(ptr_vreg),
|
||||
std::make_unique<ImmOperand>(0)
|
||||
));
|
||||
CurMBB->addInstruction(std::move(sw));
|
||||
CurMBB->addInstruction(std::move(store_instr));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -27,24 +27,26 @@ void RISCv64RegAlloc::run() {
|
||||
|
||||
void RISCv64RegAlloc::eliminateFrameIndices() {
|
||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||
int current_offset = 20; // 这里写20是为了在$s0和第一个变量之间留出20字节的安全区,
|
||||
// 以防止一些函数调用方面的恶性bug。
|
||||
// 初始偏移量,为保存ra和s0留出空间。可以根据你的函数序言调整。
|
||||
// 假设序言是 addi sp, sp, -stack_size; sd ra, stack_size-8(sp); sd s0, stack_size-16(sp);
|
||||
int current_offset = 16;
|
||||
|
||||
Function* F = MFunc->getFunc();
|
||||
RISCv64ISel* isel = MFunc->getISel();
|
||||
|
||||
// --- MODIFICATION START: 动态计算栈帧大小 ---
|
||||
// 遍历AllocaInst来计算局部变量所需的总空间
|
||||
for (auto& bb : F->getBasicBlocks()) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
if (auto alloca = dynamic_cast<AllocaInst*>(inst.get())) {
|
||||
int size = 4;
|
||||
if (!alloca->getDims().empty()) {
|
||||
int num_elements = 1;
|
||||
for (const auto& dim_use : alloca->getDims()) {
|
||||
if (auto const_dim = dynamic_cast<ConstantValue*>(dim_use->getValue())) {
|
||||
num_elements *= const_dim->getInt();
|
||||
}
|
||||
}
|
||||
size *= num_elements;
|
||||
}
|
||||
// 获取Alloca指令指向的类型 (例如 alloca i32* 中,获取 i32)
|
||||
Type* allocated_type = alloca->getType()->as<PointerType>()->getBaseType();
|
||||
int size = getTypeSizeInBytes(allocated_type);
|
||||
|
||||
// RISC-V要求栈地址8字节对齐
|
||||
size = (size + 7) & ~7;
|
||||
if (size == 0) size = 8; // 至少分配8字节
|
||||
|
||||
current_offset += size;
|
||||
unsigned alloca_vreg = isel->getVReg(alloca);
|
||||
frame_info.alloca_offsets[alloca_vreg] = -current_offset;
|
||||
@ -52,50 +54,66 @@ void RISCv64RegAlloc::eliminateFrameIndices() {
|
||||
}
|
||||
}
|
||||
frame_info.locals_size = current_offset;
|
||||
// --- MODIFICATION END ---
|
||||
|
||||
// 遍历所有机器指令,将伪指令展开为真实指令
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
std::vector<std::unique_ptr<MachineInstr>> new_instructions;
|
||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||
if (instr_ptr->getOpcode() == RVOpcodes::FRAME_LOAD) {
|
||||
RVOpcodes opcode = instr_ptr->getOpcode();
|
||||
|
||||
// --- MODIFICATION START: 处理区分宽度的伪指令 ---
|
||||
if (opcode == RVOpcodes::FRAME_LOAD_W || opcode == RVOpcodes::FRAME_LOAD_D) {
|
||||
// 确定要生成的真实加载指令是 lw 还是 ld
|
||||
RVOpcodes real_load_op = (opcode == RVOpcodes::FRAME_LOAD_W) ? RVOpcodes::LW : RVOpcodes::LD;
|
||||
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
unsigned dest_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
|
||||
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
|
||||
int offset = frame_info.alloca_offsets.at(alloca_vreg);
|
||||
auto addr_vreg = isel->getNewVReg();
|
||||
|
||||
// 展开为: addi addr_vreg, s0, offset
|
||||
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
addi->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
||||
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
addi->addOperand(std::make_unique<ImmOperand>(offset));
|
||||
new_instructions.push_back(std::move(addi));
|
||||
|
||||
auto lw = std::make_unique<MachineInstr>(RVOpcodes::LW);
|
||||
lw->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
lw->addOperand(std::make_unique<MemOperand>(
|
||||
// 展开为: lw/ld dest_vreg, 0(addr_vreg)
|
||||
auto load_instr = std::make_unique<MachineInstr>(real_load_op);
|
||||
load_instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
load_instr->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(addr_vreg),
|
||||
std::make_unique<ImmOperand>(0)));
|
||||
new_instructions.push_back(std::move(lw));
|
||||
new_instructions.push_back(std::move(load_instr));
|
||||
|
||||
} else if (opcode == RVOpcodes::FRAME_STORE_W || opcode == RVOpcodes::FRAME_STORE_D) {
|
||||
// 确定要生成的真实存储指令是 sw 还是 sd
|
||||
RVOpcodes real_store_op = (opcode == RVOpcodes::FRAME_STORE_W) ? RVOpcodes::SW : RVOpcodes::SD;
|
||||
|
||||
} else if (instr_ptr->getOpcode() == RVOpcodes::FRAME_STORE) {
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
unsigned src_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
|
||||
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
|
||||
int offset = frame_info.alloca_offsets.at(alloca_vreg);
|
||||
auto addr_vreg = isel->getNewVReg();
|
||||
|
||||
// 展开为: addi addr_vreg, s0, offset
|
||||
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
addi->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
||||
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
addi->addOperand(std::make_unique<ImmOperand>(offset));
|
||||
new_instructions.push_back(std::move(addi));
|
||||
|
||||
auto sw = std::make_unique<MachineInstr>(RVOpcodes::SW);
|
||||
sw->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
sw->addOperand(std::make_unique<MemOperand>(
|
||||
// 展开为: sw/sd src_vreg, 0(addr_vreg)
|
||||
auto store_instr = std::make_unique<MachineInstr>(real_store_op);
|
||||
store_instr->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
store_instr->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(addr_vreg),
|
||||
std::make_unique<ImmOperand>(0)));
|
||||
new_instructions.push_back(std::move(sw));
|
||||
} else if (instr_ptr->getOpcode() == RVOpcodes::FRAME_ADDR) { // [新] 处理FRAME_ADDR
|
||||
new_instructions.push_back(std::move(store_instr));
|
||||
|
||||
} else if (instr_ptr->getOpcode() == RVOpcodes::FRAME_ADDR) {
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
unsigned dest_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
|
||||
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
|
||||
@ -104,12 +122,13 @@ void RISCv64RegAlloc::eliminateFrameIndices() {
|
||||
// 将 `frame_addr rd, rs` 展开为 `addi rd, s0, offset`
|
||||
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
addi->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0)); // 基地址是帧指针 s0
|
||||
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
addi->addOperand(std::make_unique<ImmOperand>(offset));
|
||||
new_instructions.push_back(std::move(addi));
|
||||
} else {
|
||||
new_instructions.push_back(std::move(instr_ptr));
|
||||
}
|
||||
// --- MODIFICATION END ---
|
||||
}
|
||||
mbb->getInstructions() = std::move(new_instructions);
|
||||
}
|
||||
@ -119,30 +138,72 @@ void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet&
|
||||
bool is_def = true;
|
||||
auto opcode = instr->getOpcode();
|
||||
|
||||
// 预定义def和use规则
|
||||
// --- MODIFICATION START: 细化对指令的 use/def 定义 ---
|
||||
|
||||
// 对于没有定义目标寄存器的指令,预先设置 is_def = false
|
||||
if (opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
|
||||
opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
|
||||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
|
||||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
|
||||
opcode == RVOpcodes::RET || opcode == RVOpcodes::J) {
|
||||
is_def = false;
|
||||
}
|
||||
|
||||
// 对 CALL 指令进行特殊处理
|
||||
if (opcode == RVOpcodes::CALL) {
|
||||
// CALL会杀死所有调用者保存寄存器,这是一个简化处理
|
||||
// 同时也使用了传入a0-a7的参数
|
||||
// CALL 指令的第一个操作数通常是目标函数标签,不是寄存器。
|
||||
// 它可能会有一个可选的返回值(def),以及一系列参数(use)。
|
||||
// 这里的处理假定 CALL 的机器指令操作数布局是:
|
||||
// [可选: dest_vreg (def)], [函数标签], [可选: arg1_vreg (use)], [可选: arg2_vreg (use)], ...
|
||||
|
||||
// 我们需要一种方法来识别哪些操作数是def,哪些是use。
|
||||
// 一个简单的约定:如果第一个操作数是寄存器,则它是def(返回值)。
|
||||
if (!instr->getOperands().empty() && instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
|
||||
if (reg_op->isVirtual()) {
|
||||
def.insert(reg_op->getVRegNum());
|
||||
}
|
||||
}
|
||||
|
||||
// 遍历所有操作数,非第一个寄存器操作数均视为use
|
||||
bool first_reg_skipped = false;
|
||||
for (const auto& op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
if (!first_reg_skipped) {
|
||||
first_reg_skipped = true;
|
||||
continue; // 跳过我们已经作为def处理的返回值
|
||||
}
|
||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||
if (reg_op->isVirtual()) {
|
||||
use.insert(reg_op->getVRegNum());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// **重要**: CALL指令还隐式定义(杀死)了所有调用者保存的寄存器。
|
||||
// 一个完整的实现会在这里将所有caller-saved寄存器标记为def,
|
||||
// 以确保任何跨调用存活的变量都不会被分配到这些寄存器中。
|
||||
// 这个简化的实现暂不处理隐式def,但这是未来优化的关键点。
|
||||
|
||||
return; // CALL 指令处理完毕,直接返回
|
||||
}
|
||||
|
||||
// --- MODIFICATION END ---
|
||||
|
||||
// 对其他所有指令的通用处理逻辑
|
||||
for (const auto& op : instr->getOperands()) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||
if (reg_op->isVirtual()) {
|
||||
if (is_def) {
|
||||
def.insert(reg_op->getVRegNum());
|
||||
is_def = false;
|
||||
is_def = false; // 一条指令通常只有一个目标寄存ator
|
||||
} else {
|
||||
use.insert(reg_op->getVRegNum());
|
||||
}
|
||||
}
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
// 内存操作数 `offset(base)` 中的 base 寄存器是 use
|
||||
auto mem_op = static_cast<MemOperand*>(op.get());
|
||||
if (mem_op->getBase()->isVirtual()) {
|
||||
use.insert(mem_op->getBase()->getVRegNum());
|
||||
@ -151,6 +212,43 @@ void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet&
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 计算一个类型在内存中占用的字节数。
|
||||
* @param type 需要计算大小的IR类型。
|
||||
* @return 该类型占用的字节数。
|
||||
*/
|
||||
unsigned RISCv64RegAlloc::getTypeSizeInBytes(Type* type) {
|
||||
if (!type) {
|
||||
assert(false && "Cannot get size of a null type.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (type->getKind()) {
|
||||
// 对于SysY语言,基本类型int和float都占用4字节
|
||||
case Type::kInt:
|
||||
case Type::kFloat:
|
||||
return 4;
|
||||
|
||||
// 指针类型在RISC-V 64位架构下占用8字节
|
||||
// 虽然SysY没有'int*'语法,但数组变量在IR层面本身就是指针类型
|
||||
case Type::kPointer:
|
||||
return 8;
|
||||
|
||||
// 数组类型的总大小 = 元素数量 * 单个元素的大小
|
||||
case Type::kArray: {
|
||||
auto arrayType = type->as<ArrayType>();
|
||||
// 递归调用以计算元素大小
|
||||
return arrayType->getNumElements() * getTypeSizeInBytes(arrayType->getElementType());
|
||||
}
|
||||
|
||||
// 其他类型,如Void, Label等不占用栈空间,或者不应该出现在这里
|
||||
default:
|
||||
// 如果遇到未处理的类型,触发断言,方便调试
|
||||
assert(false && "Unsupported type for size calculation.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64RegAlloc::analyzeLiveness() {
|
||||
bool changed = true;
|
||||
while (changed) {
|
||||
@ -259,8 +357,21 @@ void RISCv64RegAlloc::colorGraph() {
|
||||
void RISCv64RegAlloc::rewriteFunction() {
|
||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||
int current_offset = frame_info.locals_size;
|
||||
|
||||
// --- FIX 1: 动态计算溢出槽大小 ---
|
||||
// 根据溢出虚拟寄存器的真实类型,为其在栈上分配正确大小的空间。
|
||||
for (unsigned vreg : spilled_vregs) {
|
||||
current_offset += 4;
|
||||
// 从反向映射中查找 vreg 对应的 IR Value
|
||||
assert(vreg_to_value_map.count(vreg) && "Spilled vreg not found in map!");
|
||||
Value* val = vreg_to_value_map.at(vreg);
|
||||
|
||||
// 使用辅助函数获取类型大小
|
||||
int size = getTypeSizeInBytes(val->getType());
|
||||
|
||||
// 保持栈8字节对齐
|
||||
current_offset += size;
|
||||
current_offset = (current_offset + 7) & ~7;
|
||||
|
||||
frame_info.spill_offsets[vreg] = -current_offset;
|
||||
}
|
||||
frame_info.spill_size = current_offset - frame_info.locals_size;
|
||||
@ -271,10 +382,16 @@ void RISCv64RegAlloc::rewriteFunction() {
|
||||
LiveSet use, def;
|
||||
getInstrUseDef(instr_ptr.get(), use, def);
|
||||
|
||||
// --- FIX 2: 为溢出的 'use' 操作数插入正确的加载指令 ---
|
||||
for (unsigned vreg : use) {
|
||||
if (spilled_vregs.count(vreg)) {
|
||||
// 同样地,根据 vreg 的类型决定使用 lw 还是 ld
|
||||
assert(vreg_to_value_map.count(vreg));
|
||||
Value* val = vreg_to_value_map.at(vreg);
|
||||
RVOpcodes load_op = val->getType()->isPointer() ? RVOpcodes::LD : RVOpcodes::LW;
|
||||
|
||||
int offset = frame_info.spill_offsets.at(vreg);
|
||||
auto load = std::make_unique<MachineInstr>(RVOpcodes::LW);
|
||||
auto load = std::make_unique<MachineInstr>(load_op);
|
||||
load->addOperand(std::make_unique<RegOperand>(vreg));
|
||||
load->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
@ -286,10 +403,16 @@ void RISCv64RegAlloc::rewriteFunction() {
|
||||
|
||||
new_instructions.push_back(std::move(instr_ptr));
|
||||
|
||||
// --- FIX 3: 为溢出的 'def' 操作数插入正确的存储指令 ---
|
||||
for (unsigned vreg : def) {
|
||||
if (spilled_vregs.count(vreg)) {
|
||||
// 根据 vreg 的类型决定使用 sw 还是 sd
|
||||
assert(vreg_to_value_map.count(vreg));
|
||||
Value* val = vreg_to_value_map.at(vreg);
|
||||
RVOpcodes store_op = val->getType()->isPointer() ? RVOpcodes::SD : RVOpcodes::SW;
|
||||
|
||||
int offset = frame_info.spill_offsets.at(vreg);
|
||||
auto store = std::make_unique<MachineInstr>(RVOpcodes::SW);
|
||||
auto store = std::make_unique<MachineInstr>(store_op);
|
||||
store->addOperand(std::make_unique<RegOperand>(vreg));
|
||||
store->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
@ -302,27 +425,39 @@ void RISCv64RegAlloc::rewriteFunction() {
|
||||
mbb->getInstructions() = std::move(new_instructions);
|
||||
}
|
||||
|
||||
// 最后的虚拟寄存器到物理寄存器的替换过程保持不变
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||
for (auto& op_ptr : instr_ptr->getOperands()) {
|
||||
|
||||
// 情况一:操作数本身就是一个寄存器 (例如 add rd, rs1, rs2 中的所有操作数)
|
||||
if(op_ptr->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(op_ptr.get());
|
||||
if (reg_op->isVirtual()) {
|
||||
unsigned vreg = reg_op->getVRegNum();
|
||||
if (color_map.count(vreg)) {
|
||||
// 如果vreg被成功着色,替换为物理寄存器
|
||||
reg_op->setPReg(color_map.at(vreg));
|
||||
} else if (spilled_vregs.count(vreg)) {
|
||||
reg_op->setPReg(PhysicalReg::T6); // 溢出统一用t6
|
||||
// 如果vreg被溢出,替换为专用的溢出物理寄存器t6
|
||||
reg_op->setPReg(PhysicalReg::T6);
|
||||
}
|
||||
}
|
||||
} else if (op_ptr->getKind() == MachineOperand::KIND_MEM) {
|
||||
}
|
||||
// 情况二:操作数是一个内存地址 (例如 lw rd, offset(rs1) 中的 offset(rs1))
|
||||
else if (op_ptr->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto mem_op = static_cast<MemOperand*>(op_ptr.get());
|
||||
// 获取内存操作数内部的“基址寄存器”
|
||||
auto base_reg_op = mem_op->getBase();
|
||||
|
||||
// 对这个基址寄存器,执行与情况一完全相同的替换逻辑
|
||||
if(base_reg_op->isVirtual()){
|
||||
unsigned vreg = base_reg_op->getVRegNum();
|
||||
if(color_map.count(vreg)) {
|
||||
// 如果基址vreg被成功着色,替换
|
||||
base_reg_op->setPReg(color_map.at(vreg));
|
||||
} else if (spilled_vregs.count(vreg)) {
|
||||
// 如果基址vreg被溢出,替换为t6
|
||||
base_reg_op->setPReg(PhysicalReg::T6);
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,9 +44,11 @@ enum class RVOpcodes {
|
||||
// 特殊标记,非指令
|
||||
LABEL,
|
||||
// 新增伪指令,用于解耦栈帧处理
|
||||
FRAME_LOAD, // 从栈帧加载 (AllocaInst)
|
||||
FRAME_STORE, // 保存到栈帧 (AllocaInst)
|
||||
FRAME_ADDR, // [新] 获取栈帧变量的地址
|
||||
FRAME_LOAD_W, // 从栈帧加载 32位 Word (对应 lw)
|
||||
FRAME_LOAD_D, // 从栈帧加载 64位 Doubleword (对应 ld)
|
||||
FRAME_STORE_W, // 保存 32位 Word 到栈帧 (对应 sw)
|
||||
FRAME_STORE_D, // 保存 64位 Doubleword 到栈帧 (对应 sd)
|
||||
FRAME_ADDR, // 获取栈帧变量的地址
|
||||
};
|
||||
|
||||
class MachineOperand;
|
||||
|
||||
@ -49,6 +49,13 @@ private:
|
||||
|
||||
// 可用的物理寄存器池
|
||||
std::vector<PhysicalReg> allocable_int_regs;
|
||||
|
||||
// 存储vreg到IR Value*的反向映射
|
||||
// 这个map将在run()函数开始时被填充,并在rewriteFunction()中使用。
|
||||
std::map<unsigned, Value*> vreg_to_value_map;
|
||||
|
||||
// 用于计算类型大小的辅助函数
|
||||
unsigned getTypeSizeInBytes(Type* type);
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
Reference in New Issue
Block a user