deploy-20250820-3 #1
@@ -37,6 +37,8 @@ add_executable(sysyc
|
||||
PreRA_Scheduler.cpp
|
||||
PostRA_Scheduler.cpp
|
||||
CalleeSavedHandler.cpp
|
||||
LegalizeImmediates.cpp
|
||||
PrologueEpilogueInsertion.cpp
|
||||
RISCv64LLIR.cpp
|
||||
)
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ bool CalleeSavedHandler::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||
}
|
||||
|
||||
void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
// 【最终方案】: 此 Pass 负责分析、分配栈空间并插入 callee-saved 寄存器的保存/恢复指令。
|
||||
// 此 Pass 负责分析、分配栈空间并插入 callee-saved 寄存器的保存/恢复指令。
|
||||
// 它通过与 FrameInfo 协作,确保为 callee-saved 寄存器分配的空间与局部变量/溢出槽的空间不冲突。
|
||||
// 这样做可以使生成的 sd/ld 指令能被后续的优化 Pass (如 PostRA-Scheduler) 处理。
|
||||
|
||||
@@ -83,7 +83,7 @@ void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
current_offset -= 8;
|
||||
}
|
||||
|
||||
// 5. 【已修复】在函数结尾(ret之前)插入恢复指令,使用反向遍历来避免迭代器失效
|
||||
// 5. 在函数结尾(ret之前)插入恢复指令,使用反向遍历来避免迭代器失效
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
// 使用手动控制的反向循环
|
||||
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
|
||||
|
||||
168
src/LegalizeImmediates.cpp
Normal file
168
src/LegalizeImmediates.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
#include "LegalizeImmediates.h"
|
||||
#include "RISCv64ISel.h" // 需要包含它以调用 getNewVReg()
|
||||
#include "RISCv64AsmPrinter.h"
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
// 声明外部调试控制变量
|
||||
extern int DEBUG;
|
||||
extern int DEEPDEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
char LegalizeImmediatesPass::ID = 0;
|
||||
|
||||
// 辅助函数:检查一个立即数是否在RISC-V的12位有符号范围内
|
||||
static bool isLegalImmediate(int64_t imm) {
|
||||
return imm >= -2048 && imm <= 2047;
|
||||
}
|
||||
|
||||
void LegalizeImmediatesPass::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
if (DEBUG) {
|
||||
std::cerr << "===== Running Legalize Immediates Pass on function: " << mfunc->getName() << " =====\n";
|
||||
}
|
||||
|
||||
// 定义我们保留的、用于暂存的物理寄存器
|
||||
const PhysicalReg TEMP_REG = PhysicalReg::T5;
|
||||
|
||||
// 创建一个临时的AsmPrinter用于打印指令,方便调试
|
||||
RISCv64AsmPrinter temp_printer(mfunc);
|
||||
if (DEEPDEBUG) {
|
||||
temp_printer.setStream(std::cerr);
|
||||
}
|
||||
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
if (DEEPDEBUG) {
|
||||
std::cerr << "--- Processing Basic Block: " << mbb->getName() << " ---\n";
|
||||
}
|
||||
// 创建一个新的指令列表,用于存放合法化后的指令
|
||||
std::vector<std::unique_ptr<MachineInstr>> new_instructions;
|
||||
|
||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||
if (DEEPDEBUG) {
|
||||
std::cerr << " Checking: ";
|
||||
// 打印指令时末尾会带换行符,所以这里不用 std::endl
|
||||
temp_printer.printInstruction(instr_ptr.get(), true);
|
||||
}
|
||||
|
||||
bool legalized = false; // 标记当前指令是否已被展开处理
|
||||
|
||||
switch (instr_ptr->getOpcode()) {
|
||||
case RVOpcodes::ADDI:
|
||||
case RVOpcodes::ADDIW: {
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
auto imm_op = static_cast<ImmOperand*>(operands.back().get());
|
||||
|
||||
if (!isLegalImmediate(imm_op->getValue())) {
|
||||
if (DEEPDEBUG) {
|
||||
std::cerr << " >> ILLEGAL immediate (" << imm_op->getValue() << "). Expanding...\n";
|
||||
}
|
||||
// 立即数超出范围,需要展开
|
||||
auto rd_op = std::make_unique<RegOperand>(*static_cast<RegOperand*>(operands[0].get()));
|
||||
auto rs1_op = std::make_unique<RegOperand>(*static_cast<RegOperand*>(operands[1].get()));
|
||||
|
||||
// 1. li t5, immediate
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(TEMP_REG));
|
||||
li->addOperand(std::make_unique<ImmOperand>(imm_op->getValue()));
|
||||
|
||||
// 2. add/addw rd, rs1, t5
|
||||
auto new_op = (instr_ptr->getOpcode() == RVOpcodes::ADDI) ? RVOpcodes::ADD : RVOpcodes::ADDW;
|
||||
auto add = std::make_unique<MachineInstr>(new_op);
|
||||
add->addOperand(std::move(rd_op));
|
||||
add->addOperand(std::move(rs1_op));
|
||||
add->addOperand(std::make_unique<RegOperand>(TEMP_REG));
|
||||
|
||||
if (DEEPDEBUG) {
|
||||
std::cerr << " New sequence:\n ";
|
||||
temp_printer.printInstruction(li.get(), true);
|
||||
std::cerr << " ";
|
||||
temp_printer.printInstruction(add.get(), true);
|
||||
}
|
||||
|
||||
new_instructions.push_back(std::move(li));
|
||||
new_instructions.push_back(std::move(add));
|
||||
|
||||
legalized = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// 处理所有内存加载/存储指令
|
||||
case RVOpcodes::LB: case RVOpcodes::LH: case RVOpcodes::LW: case RVOpcodes::LD:
|
||||
case RVOpcodes::LBU: case RVOpcodes::LHU: case RVOpcodes::LWU:
|
||||
case RVOpcodes::SB: case RVOpcodes::SH: case RVOpcodes::SW: case RVOpcodes::SD: {
|
||||
auto& operands = instr_ptr->getOperands();
|
||||
auto mem_op = static_cast<MemOperand*>(operands.back().get());
|
||||
auto offset_op = mem_op->getOffset();
|
||||
|
||||
if (!isLegalImmediate(offset_op->getValue())) {
|
||||
if (DEEPDEBUG) {
|
||||
std::cerr << " >> ILLEGAL immediate offset (" << offset_op->getValue() << "). Expanding...\n";
|
||||
}
|
||||
// 偏移量超出范围,需要展开
|
||||
auto data_reg_op = std::make_unique<RegOperand>(*static_cast<RegOperand*>(operands[0].get()));
|
||||
auto base_reg_op = std::make_unique<RegOperand>(*mem_op->getBase());
|
||||
|
||||
// 1. li t5, offset
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(TEMP_REG));
|
||||
li->addOperand(std::make_unique<ImmOperand>(offset_op->getValue()));
|
||||
|
||||
// 2. add t5, base_reg, t5 (计算最终地址,结果也放在t5)
|
||||
auto add = std::make_unique<MachineInstr>(RVOpcodes::ADD);
|
||||
add->addOperand(std::make_unique<RegOperand>(TEMP_REG));
|
||||
add->addOperand(std::move(base_reg_op));
|
||||
add->addOperand(std::make_unique<RegOperand>(TEMP_REG));
|
||||
|
||||
// 3. lw/sw data_reg, 0(t5)
|
||||
auto mem_instr = std::make_unique<MachineInstr>(instr_ptr->getOpcode());
|
||||
mem_instr->addOperand(std::move(data_reg_op));
|
||||
mem_instr->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(TEMP_REG),
|
||||
std::make_unique<ImmOperand>(0)
|
||||
));
|
||||
|
||||
if (DEEPDEBUG) {
|
||||
std::cerr << " New sequence:\n ";
|
||||
temp_printer.printInstruction(li.get(), true);
|
||||
std::cerr << " ";
|
||||
temp_printer.printInstruction(add.get(), true);
|
||||
std::cerr << " ";
|
||||
temp_printer.printInstruction(mem_instr.get(), true);
|
||||
}
|
||||
|
||||
new_instructions.push_back(std::move(li));
|
||||
new_instructions.push_back(std::move(add));
|
||||
new_instructions.push_back(std::move(mem_instr));
|
||||
|
||||
legalized = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// 其他指令不需要处理
|
||||
break;
|
||||
}
|
||||
|
||||
if (!legalized) {
|
||||
if (DEEPDEBUG) {
|
||||
std::cerr << " -- Immediate is legal. Skipping.\n";
|
||||
}
|
||||
// 如果当前指令不需要合法化,直接将其移动到新列表中
|
||||
new_instructions.push_back(std::move(instr_ptr));
|
||||
}
|
||||
}
|
||||
|
||||
// 用新的、已合法化的指令列表替换旧的列表
|
||||
mbb->getInstructions() = std::move(new_instructions);
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
std::cerr << "===== Finished Legalize Immediates Pass =====\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
121
src/PrologueEpilogueInsertion.cpp
Normal file
121
src/PrologueEpilogueInsertion.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
#include "include/PrologueEpilogueInsertion.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
char PrologueEpilogueInsertionPass::ID = 0;
|
||||
|
||||
void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
||||
// 最终计算总栈帧大小。
|
||||
int total_stack_size = frame_info.locals_size +
|
||||
frame_info.spill_size +
|
||||
frame_info.callee_saved_size +
|
||||
16; // 为 ra 和 s0 固定的16字节
|
||||
|
||||
// 保持栈指针16字节对齐
|
||||
int aligned_stack_size = (total_stack_size + 15) & ~15;
|
||||
frame_info.total_size = aligned_stack_size;
|
||||
|
||||
if (aligned_stack_size == 0) {
|
||||
return; // 无需插入序言/尾声
|
||||
}
|
||||
|
||||
// --- 1. 插入序言 ---
|
||||
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
|
||||
auto& entry_instrs = entry_block->getInstructions();
|
||||
|
||||
// [修复] 创建一个临时 vector 来存放所有序言指令,以避免迭代器失效
|
||||
std::vector<std::unique_ptr<MachineInstr>> prologue_instrs;
|
||||
|
||||
// a. addi sp, sp, -aligned_stack_size
|
||||
auto alloc_stack = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
alloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
alloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
alloc_stack->addOperand(std::make_unique<ImmOperand>(-aligned_stack_size));
|
||||
prologue_instrs.push_back(std::move(alloc_stack));
|
||||
|
||||
// b. sd ra, offset(sp)
|
||||
auto save_ra = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
||||
save_ra->addOperand(std::make_unique<RegOperand>(PhysicalReg::RA));
|
||||
save_ra->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::SP),
|
||||
std::make_unique<ImmOperand>(aligned_stack_size - 8)
|
||||
));
|
||||
prologue_instrs.push_back(std::move(save_ra));
|
||||
|
||||
// c. sd s0, offset(sp)
|
||||
auto save_fp = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
||||
save_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
save_fp->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::SP),
|
||||
std::make_unique<ImmOperand>(aligned_stack_size - 16)
|
||||
));
|
||||
prologue_instrs.push_back(std::move(save_fp));
|
||||
|
||||
// d. addi s0, sp, aligned_stack_size
|
||||
auto set_fp = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
set_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
set_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
set_fp->addOperand(std::make_unique<ImmOperand>(aligned_stack_size));
|
||||
prologue_instrs.push_back(std::move(set_fp));
|
||||
|
||||
// 确定插入点(在函数名标签之后)
|
||||
auto insert_pos = entry_instrs.begin();
|
||||
if (!entry_instrs.empty() && entry_instrs.front()->getOpcode() == RVOpcodes::LABEL) {
|
||||
insert_pos++;
|
||||
}
|
||||
|
||||
// 一次性将所有序言指令插入,安全且高效
|
||||
if (!prologue_instrs.empty()) {
|
||||
entry_instrs.insert(insert_pos,
|
||||
std::make_move_iterator(prologue_instrs.begin()),
|
||||
std::make_move_iterator(prologue_instrs.end()));
|
||||
}
|
||||
|
||||
// --- 2. 插入尾声 ---
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
|
||||
if ((*it)->getOpcode() == RVOpcodes::RET) {
|
||||
// [修复] 创建一个临时 vector 来存放所有尾声指令
|
||||
std::vector<std::unique_ptr<MachineInstr>> epilogue_instrs;
|
||||
|
||||
// a. ld ra, offset(sp)
|
||||
auto restore_ra = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
||||
restore_ra->addOperand(std::make_unique<RegOperand>(PhysicalReg::RA));
|
||||
restore_ra->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::SP),
|
||||
std::make_unique<ImmOperand>(aligned_stack_size - 8)
|
||||
));
|
||||
epilogue_instrs.push_back(std::move(restore_ra));
|
||||
|
||||
// b. ld s0, offset(sp)
|
||||
auto restore_fp = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
||||
restore_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
restore_fp->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::SP),
|
||||
std::make_unique<ImmOperand>(aligned_stack_size - 16)
|
||||
));
|
||||
epilogue_instrs.push_back(std::move(restore_fp));
|
||||
|
||||
// c. addi sp, sp, aligned_stack_size
|
||||
auto dealloc_stack = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
dealloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
dealloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
dealloc_stack->addOperand(std::make_unique<ImmOperand>(aligned_stack_size));
|
||||
epilogue_instrs.push_back(std::move(dealloc_stack));
|
||||
|
||||
// 在 RET 指令前一次性插入所有尾声指令
|
||||
if (!epilogue_instrs.empty()) {
|
||||
mbb->getInstructions().insert(it,
|
||||
std::make_move_iterator(epilogue_instrs.begin()),
|
||||
std::make_move_iterator(epilogue_instrs.end()));
|
||||
}
|
||||
|
||||
// 处理完当前基本块的RET后即可跳出内层循环
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@@ -22,52 +22,12 @@ void RISCv64AsmPrinter::run(std::ostream& os, bool debug) {
|
||||
OS = &os;
|
||||
|
||||
*OS << ".globl " << MFunc->getName() << "\n";
|
||||
*OS << MFunc->getName() << ":\n";
|
||||
|
||||
printPrologue();
|
||||
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
printBasicBlock(mbb.get(), debug);
|
||||
}
|
||||
}
|
||||
|
||||
// 在 RISCv64AsmPrinter.cpp 文件中
|
||||
|
||||
void RISCv64AsmPrinter::printPrologue() {
|
||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||
// 计算总栈帧大小。
|
||||
// 包含三部分:局部变量区、寄存器溢出区、以及为被调用者保存(callee-saved)寄存器预留的区域。
|
||||
// 最后再加上为保存 ra 和 s0 固定的16字节。
|
||||
int total_stack_size = frame_info.locals_size +
|
||||
frame_info.spill_size +
|
||||
frame_info.callee_saved_size +
|
||||
16;
|
||||
|
||||
// 保持栈指针16字节对齐
|
||||
int aligned_stack_size = (total_stack_size + 15) & ~15;
|
||||
frame_info.total_size = aligned_stack_size; // 更新最终的栈大小
|
||||
|
||||
// 只有在需要分配栈空间时才生成指令
|
||||
if (aligned_stack_size > 0) {
|
||||
// 1. 一次性分配整个栈帧
|
||||
*OS << " addi sp, sp, -" << aligned_stack_size << "\n";
|
||||
// 2. 在新的栈顶附近保存 ra 和 s0
|
||||
*OS << " sd ra, " << (aligned_stack_size - 8) << "(sp)\n";
|
||||
*OS << " sd s0, " << (aligned_stack_size - 16) << "(sp)\n";
|
||||
// 3. 设置新的帧指针 s0,使其指向栈帧的底部(高地址)
|
||||
*OS << " addi s0, sp, " << aligned_stack_size << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64AsmPrinter::printEpilogue() {
|
||||
int aligned_stack_size = MFunc->getFrameInfo().total_size;
|
||||
if (aligned_stack_size > 0) {
|
||||
*OS << " ld ra, " << (aligned_stack_size - 8) << "(sp)\n";
|
||||
*OS << " ld s0, " << (aligned_stack_size - 16) << "(sp)\n";
|
||||
*OS << " addi sp, sp, " << aligned_stack_size << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64AsmPrinter::printBasicBlock(MachineBasicBlock* mbb, bool debug) {
|
||||
if (!mbb->getName().empty()) {
|
||||
*OS << mbb->getName() << ":\n";
|
||||
@@ -79,9 +39,6 @@ void RISCv64AsmPrinter::printBasicBlock(MachineBasicBlock* mbb, bool debug) {
|
||||
|
||||
void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
|
||||
auto opcode = instr->getOpcode();
|
||||
if (opcode == RVOpcodes::RET) {
|
||||
printEpilogue();
|
||||
}
|
||||
|
||||
if (opcode == RVOpcodes::LABEL) {
|
||||
// 标签直接打印,不加缩进
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "RISCv64ISel.h"
|
||||
#include "RISCv64RegAlloc.h"
|
||||
#include "RISCv64AsmPrinter.h"
|
||||
#include "RISCv64Passes.h" // 包含优化Pass的头文件
|
||||
#include "RISCv64Passes.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace sysy {
|
||||
@@ -107,6 +107,7 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
||||
RISCv64ISel isel;
|
||||
std::unique_ptr<MachineFunction> mfunc = isel.runOnFunction(func);
|
||||
|
||||
// 第一次调试打印输出
|
||||
std::stringstream ss1;
|
||||
RISCv64AsmPrinter printer1(mfunc.get());
|
||||
printer1.run(ss1, true);
|
||||
@@ -119,10 +120,18 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
||||
RISCv64RegAlloc reg_alloc(mfunc.get());
|
||||
reg_alloc.run();
|
||||
|
||||
// 阶段 3.5: 处理被调用者保存寄存器
|
||||
// 阶段 3.1: 处理被调用者保存寄存器
|
||||
CalleeSavedHandler callee_handler;
|
||||
callee_handler.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 3.2: 插入序言和尾声
|
||||
PrologueEpilogueInsertionPass pei_pass;
|
||||
pei_pass.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 3.3: 清理产生的大立即数
|
||||
LegalizeImmediatesPass legalizer;
|
||||
legalizer.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 4: 窥孔优化 (Peephole Optimization)
|
||||
PeepholeOptimizer peephole;
|
||||
peephole.runOnMachineFunction(mfunc.get());
|
||||
|
||||
@@ -52,8 +52,18 @@ std::unique_ptr<MachineFunction> RISCv64ISel::runOnFunction(Function* func) {
|
||||
// 指令选择主流程
|
||||
void RISCv64ISel::select() {
|
||||
// 遍历基本块,为它们创建对应的MachineBasicBlock
|
||||
bool is_first_block = true;
|
||||
for (const auto& bb_ptr : F->getBasicBlocks()) {
|
||||
auto mbb = std::make_unique<MachineBasicBlock>(bb_ptr->getName(), MFunc.get());
|
||||
std::string mbb_name;
|
||||
if (is_first_block) {
|
||||
// 对于函数的第一个基本块,其标签必须与函数名完全相同
|
||||
mbb_name = F->getName();
|
||||
is_first_block = false;
|
||||
} else {
|
||||
// 对于后续的基本块,继续使用它们在IR中的原始名称
|
||||
mbb_name = bb_ptr->getName();
|
||||
}
|
||||
auto mbb = std::make_unique<MachineBasicBlock>(mbb_name, MFunc.get());
|
||||
bb_map[bb_ptr.get()] = mbb.get();
|
||||
MFunc->addBlock(std::move(mbb));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "RISCv64RegAlloc.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include "RISCv64AsmPrinter.h" // For DEBUG output
|
||||
#include "LegalizeImmediates.h"
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <iostream> // For DEBUG output
|
||||
@@ -10,6 +11,17 @@ namespace sysy {
|
||||
|
||||
RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) : MFunc(mfunc) {
|
||||
allocable_int_regs = {
|
||||
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3,
|
||||
PhysicalReg::T4, /*PhysicalReg::T5,*/PhysicalReg::T6,
|
||||
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3,
|
||||
PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7,
|
||||
PhysicalReg::S0, PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3,
|
||||
PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
|
||||
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
|
||||
};
|
||||
|
||||
// 创建一个包含所有通用整数寄存器的临时列表
|
||||
const std::vector<PhysicalReg> all_int_regs = {
|
||||
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3,
|
||||
PhysicalReg::T4, PhysicalReg::T5, PhysicalReg::T6,
|
||||
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3,
|
||||
@@ -21,7 +33,7 @@ RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) : MFunc(mfunc) {
|
||||
|
||||
// 映射物理寄存器到特殊的虚拟寄存器ID,用于干扰图中的物理寄存器节点
|
||||
// 确保这些特殊ID不会与vreg_counter生成的常规虚拟寄存器ID冲突
|
||||
for (PhysicalReg preg : allocable_int_regs) {
|
||||
for (PhysicalReg preg : all_int_regs) {
|
||||
preg_to_vreg_id_map[preg] = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID) + static_cast<unsigned>(preg);
|
||||
}
|
||||
}
|
||||
@@ -32,6 +44,8 @@ void RISCv64RegAlloc::run() {
|
||||
handleCallingConvention();
|
||||
// 阶段 2: 消除帧索引(为局部变量和栈参数分配栈偏移)
|
||||
eliminateFrameIndices();
|
||||
|
||||
// 调试输出当前的LLIR状态
|
||||
{ // 使用大括号创建一个局部作用域,避免printer变量泄露
|
||||
if (DEBUG) {
|
||||
std::cerr << "\n===== LLIR after eliminateFrameIndices for function: "
|
||||
@@ -46,6 +60,7 @@ void RISCv64RegAlloc::run() {
|
||||
std::cerr << "===== End of LLIR =====\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
// 阶段 3: 活跃性分析
|
||||
analyzeLiveness();
|
||||
// 阶段 4: 构建干扰图(包含CALL指令对调用者保存寄存器的影响)
|
||||
@@ -592,17 +607,26 @@ void RISCv64RegAlloc::buildInterferenceGraph() {
|
||||
// 因此,所有调用者保存的物理寄存器都与 CALL 指令的 live_out 中的所有变量冲突。
|
||||
const std::vector<PhysicalReg>& caller_saved_regs = getCallerSavedIntRegs();
|
||||
for (PhysicalReg cs_reg : caller_saved_regs) {
|
||||
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg); // 获取物理寄存器对应的特殊vreg ID
|
||||
if (preg_to_vreg_id_map.count(cs_reg)) {
|
||||
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg); // 获取物理寄存器对应的特殊vreg ID
|
||||
|
||||
// 将这个物理寄存器节点与 CALL 指令的 live_out 中的所有虚拟寄存器添加干扰边。
|
||||
for (unsigned live_vreg_out : live_out) {
|
||||
if (cs_vreg_id != live_vreg_out) { // 避免自己和自己干扰
|
||||
// [新增调试逻辑] 打印添加的干扰边及其原因
|
||||
if (DEEPDEBUG && interference_graph[cs_vreg_id].find(live_vreg_out) == interference_graph[cs_vreg_id].end()) {
|
||||
std::cerr << " Edge (CALL) : preg(" << static_cast<int>(cs_reg) << ") <-> %vreg" << live_vreg_out << "\n";
|
||||
// 将这个物理寄存器节点与 CALL 指令的 live_out 中的所有虚拟寄存器添加干扰边。
|
||||
for (unsigned live_vreg_out : live_out) {
|
||||
if (cs_vreg_id != live_vreg_out) { // 避免自己和自己干扰
|
||||
// [新增调试逻辑] 打印添加的干扰边及其原因
|
||||
if (DEEPDEBUG && interference_graph[cs_vreg_id].find(live_vreg_out) == interference_graph[cs_vreg_id].end()) {
|
||||
std::cerr << " Edge (CALL) : preg(" << static_cast<int>(cs_reg) << ") <-> %vreg" << live_vreg_out << "\n";
|
||||
}
|
||||
interference_graph[cs_vreg_id].insert(live_vreg_out);
|
||||
interference_graph[live_vreg_out].insert(cs_vreg_id);
|
||||
}
|
||||
interference_graph[cs_vreg_id].insert(live_vreg_out);
|
||||
interference_graph[live_vreg_out].insert(cs_vreg_id);
|
||||
}
|
||||
} else {
|
||||
// 如果物理寄存器没有对应的特殊虚拟寄存器ID,可能是因为它不是调用者保存的寄存器。
|
||||
// 这种情况通常不应该发生,但我们可以在这里添加一个警告或错误处理。
|
||||
if (DEEPDEBUG) {
|
||||
std::cerr << "Warning: Physical register " << static_cast<int>(cs_reg)
|
||||
<< " does not have a corresponding special vreg ID.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
36
src/include/LegalizeImmediates.h
Normal file
36
src/include/LegalizeImmediates.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef SYSY_LEGALIZE_IMMEDIATES_H
|
||||
#define SYSY_LEGALIZE_IMMEDIATES_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "Pass.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// MachineFunction 的前向声明在这里是可选的,因为 RISCv64LLIR.h 已经定义了它
|
||||
// class MachineFunction;
|
||||
|
||||
/**
|
||||
* @class LegalizeImmediatesPass
|
||||
* @brief 一个用于“合法化”机器指令的Pass。
|
||||
*
|
||||
* 这个Pass的主要职责是遍历所有机器指令,查找那些包含了超出
|
||||
* 目标架构(RISC-V)编码范围的大立即数(immediate)的指令,
|
||||
* 并将它们展开成一个等价的、只包含合法立即数的指令序列。
|
||||
*
|
||||
* 它在指令选择之后、寄存器分配之前运行,确保进入后续阶段的
|
||||
* 所有指令都符合硬件约束。
|
||||
*/
|
||||
class LegalizeImmediatesPass : public Pass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
LegalizeImmediatesPass() : Pass("legalize-immediates", Granularity::Function, PassKind::Optimization) {}
|
||||
|
||||
void *getPassID() const override { return &ID; }
|
||||
|
||||
void runOnMachineFunction(MachineFunction* mfunc);
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // SYSY_LEGALIZE_IMMEDIATES_H
|
||||
35
src/include/PrologueEpilogueInsertion.h
Normal file
35
src/include/PrologueEpilogueInsertion.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef SYSY_PROLOGUE_EPILOGUE_INSERTION_H
|
||||
#define SYSY_PROLOGUE_EPILOGUE_INSERTION_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "Pass.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
class MachineFunction;
|
||||
|
||||
/**
|
||||
* @class PrologueEpilogueInsertionPass
|
||||
* @brief 在函数中插入序言和尾声的机器指令。
|
||||
*
|
||||
* 这个Pass在所有栈帧大小计算完毕后(包括局部变量、溢出槽、被调用者保存寄存器),
|
||||
* 在寄存器分配之后运行。它的职责是:
|
||||
* 1. 根据 StackFrameInfo 中的最终栈大小,生成用于分配和释放栈帧的指令 (addi sp, sp, +/-size)。
|
||||
* 2. 生成用于保存和恢复返回地址(ra)和旧帧指针(s0)的指令。
|
||||
* 3. 将这些指令作为 MachineInstr 对象插入到 MachineFunction 的入口块和所有返回块中。
|
||||
* 4. 这个Pass可能会生成带有大立即数的指令,需要后续的 LegalizeImmediatesPass 来处理。
|
||||
*/
|
||||
class PrologueEpilogueInsertionPass : public Pass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
PrologueEpilogueInsertionPass() : Pass("prologue-epilogue-insertion", Granularity::Function, PassKind::Optimization) {}
|
||||
|
||||
void *getPassID() const override { return &ID; }
|
||||
|
||||
void runOnMachineFunction(MachineFunction* mfunc);
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // SYSY_PROLOGUE_EPILOGUE_INSERTION_H
|
||||
@@ -20,8 +20,6 @@ public:
|
||||
void setStream(std::ostream& os) { OS = &os; }
|
||||
private:
|
||||
// 打印各个部分
|
||||
void printPrologue();
|
||||
void printEpilogue();
|
||||
void printBasicBlock(MachineBasicBlock* mbb, bool debug = false);
|
||||
|
||||
// 辅助函数
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "PreRA_Scheduler.h"
|
||||
#include "PostRA_Scheduler.h"
|
||||
#include "CalleeSavedHandler.h"
|
||||
#include "LegalizeImmediates.h"
|
||||
#include "PrologueEpilogueInsertion.h"
|
||||
#include "Pass.h"
|
||||
|
||||
namespace sysy {
|
||||
|
||||
Reference in New Issue
Block a user