Compare commits

..

4 Commits

17 changed files with 1359 additions and 426 deletions

View File

@@ -33,8 +33,11 @@ add_executable(sysyc
RISCv64ISel.cpp
RISCv64RegAlloc.cpp
RISCv64AsmPrinter.cpp
RISCv64Passes.cpp
RISCv64LLIR.cpp
# RISCv64Passes.cpp
RISCv64Peephole.cpp
PreRA_Scheduler.cpp
PostRA_Scheduler.cpp
CalleeSavedHandler.cpp
)
# 设置 include 路径,包含 ANTLR 运行时库和项目头文件

109
src/CalleeSavedHandler.cpp Normal file
View File

@@ -0,0 +1,109 @@
#include "CalleeSavedHandler.h"
#include <set>
#include <algorithm>
namespace sysy {
char CalleeSavedHandler::ID = 0;
bool CalleeSavedHandler::runOnFunction(Function *F, AnalysisManager& AM) {
// This pass works on MachineFunction level, not IR level
return false;
}
void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
StackFrameInfo& frame_info = mfunc->getFrameInfo();
std::set<PhysicalReg> used_callee_saved;
// 1. 扫描所有指令找出被使用的s寄存器
for (auto& mbb : mfunc->getBlocks()) {
for (auto& instr : mbb->getInstructions()) {
for (auto& op : instr->getOperands()) {
// 辅助Lambda用于检查和插入寄存器
auto check_and_insert_reg = [&](RegOperand* reg_op) {
if (!reg_op->isVirtual()) {
PhysicalReg preg = reg_op->getPReg();
// --- 关键检查点 ---
// 必须严格判断是否在 s0-s11 的范围内。
// a0, t0 等寄存器绝对不应被视为被调用者保存寄存器。
if (preg >= PhysicalReg::S0 && preg <= PhysicalReg::S11) {
used_callee_saved.insert(preg);
}
}
};
if (op->getKind() == MachineOperand::KIND_REG) {
check_and_insert_reg(static_cast<RegOperand*>(op.get()));
} else if (op->getKind() == MachineOperand::KIND_MEM) {
check_and_insert_reg(static_cast<MemOperand*>(op.get())->getBase());
}
}
}
}
// 如果没有使用s寄存器除了可能作为帧指针的s0则无需操作
if (used_callee_saved.empty() || (used_callee_saved.size() == 1 && used_callee_saved.count(PhysicalReg::S0))) {
return;
}
// 将结果存入StackFrameInfo供后续使用
frame_info.used_callee_saved_regs = used_callee_saved;
// 2. 在函数序言插入保存指令
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
auto& entry_instrs = entry_block->getInstructions();
auto prologue_end = entry_instrs.begin();
// 找到序言结束的位置通常是addi s0, sp, size之后
for (auto it = entry_instrs.begin(); it != entry_instrs.end(); ++it) {
if ((*it)->getOpcode() == RVOpcodes::ADDI &&
(*it)->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
static_cast<RegOperand*>((*it)->getOperands()[0].get())->getPReg() == PhysicalReg::S0)
{
prologue_end = std::next(it);
break;
}
}
// 为了栈帧布局确定性,对寄存器进行排序
std::vector<PhysicalReg> sorted_regs(used_callee_saved.begin(), used_callee_saved.end());
std::sort(sorted_regs.begin(), sorted_regs.end());
int current_offset = -16; // ra和s0已经占用了-8和-16的位置
for (PhysicalReg reg : sorted_regs) {
if (reg == PhysicalReg::S0) continue; // s0已经在序言中处理
current_offset -= 8;
auto sd = std::make_unique<MachineInstr>(RVOpcodes::SD);
sd->addOperand(std::make_unique<RegOperand>(reg));
sd->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0), // 假设s0是帧指针
std::make_unique<ImmOperand>(current_offset)
));
entry_instrs.insert(prologue_end, std::move(sd));
}
// 3. 在函数结尾ret之前插入恢复指令
for (auto& mbb : mfunc->getBlocks()) {
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
if ((*it)->getOpcode() == RVOpcodes::RET) {
// 以相反的顺序恢复
current_offset = -16;
for (PhysicalReg reg : sorted_regs) {
if (reg == PhysicalReg::S0) continue;
current_offset -= 8;
auto ld = std::make_unique<MachineInstr>(RVOpcodes::LD);
ld->addOperand(std::make_unique<RegOperand>(reg));
ld->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(current_offset)
));
mbb->getInstructions().insert(it, std::move(ld));
}
break; // 处理完一个基本块的ret即可
}
}
}
}
} // namespace sysy

383
src/PostRA_Scheduler.cpp Normal file
View File

@@ -0,0 +1,383 @@
#include "PostRA_Scheduler.h"
#include <set>
#include <map>
#include <vector>
#include <algorithm>
#define MAX_SCHEDULING_BLOCK_SIZE 10000 // 限制调度块大小,避免过大导致性能问题
namespace sysy {
char PostRA_Scheduler::ID = 0;
// 检查指令是否是加载指令 (LW, LD)
bool isLoadInstr(MachineInstr* instr) {
RVOpcodes opcode = instr->getOpcode();
return opcode == RVOpcodes::LW || opcode == RVOpcodes::LD ||
opcode == RVOpcodes::LH || opcode == RVOpcodes::LB ||
opcode == RVOpcodes::LHU || opcode == RVOpcodes::LBU ||
opcode == RVOpcodes::LWU;
}
// 检查指令是否是存储指令 (SW, SD)
bool isStoreInstr(MachineInstr* instr) {
RVOpcodes opcode = instr->getOpcode();
return opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
opcode == RVOpcodes::SH || opcode == RVOpcodes::SB;
}
// 检查指令是否为控制流指令
bool isControlFlowInstr(MachineInstr* instr) {
RVOpcodes opcode = instr->getOpcode();
return opcode == RVOpcodes::RET || opcode == RVOpcodes::J ||
opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
opcode == RVOpcodes::CALL;
}
// 获取指令定义的寄存器 - 修复版本
std::set<PhysicalReg> getDefinedRegisters(MachineInstr* instr) {
std::set<PhysicalReg> defined_regs;
RVOpcodes opcode = instr->getOpcode();
// 特殊处理CALL指令
if (opcode == RVOpcodes::CALL) {
// CALL指令可能定义返回值寄存器
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()) {
defined_regs.insert(reg_op->getPReg());
}
}
return defined_regs;
}
// 存储指令不定义寄存器
if (isStoreInstr(instr)) {
return defined_regs;
}
// 分支指令不定义寄存器
if (opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
opcode == RVOpcodes::J || opcode == RVOpcodes::RET) {
return defined_regs;
}
// 对于其他指令,第一个寄存器操作数通常是定义的
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()) {
defined_regs.insert(reg_op->getPReg());
}
}
return defined_regs;
}
// 获取指令使用的寄存器 - 修复版本
std::set<PhysicalReg> getUsedRegisters(MachineInstr* instr) {
std::set<PhysicalReg> used_regs;
RVOpcodes opcode = instr->getOpcode();
// 特殊处理CALL指令
if (opcode == RVOpcodes::CALL) {
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; // 跳过返回值寄存器
}
auto reg_op = static_cast<RegOperand*>(op.get());
if (!reg_op->isVirtual()) {
used_regs.insert(reg_op->getPReg());
}
}
}
return used_regs;
}
// 对于存储指令,所有寄存器操作数都是使用的
if (isStoreInstr(instr)) {
for (const auto& op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(op.get());
if (!reg_op->isVirtual()) {
used_regs.insert(reg_op->getPReg());
}
} else if (op->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<MemOperand*>(op.get());
if (!mem_op->getBase()->isVirtual()) {
used_regs.insert(mem_op->getBase()->getPReg());
}
}
}
return used_regs;
}
// 对于分支指令,所有寄存器操作数都是使用的
if (opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU) {
for (const auto& op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(op.get());
if (!reg_op->isVirtual()) {
used_regs.insert(reg_op->getPReg());
}
}
}
return used_regs;
}
// 对于其他指令,除了第一个寄存器操作数(通常是定义),其余都是使用的
bool first_reg = true;
for (const auto& op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
if (first_reg) {
first_reg = false;
continue; // 跳过第一个寄存器(定义)
}
auto reg_op = static_cast<RegOperand*>(op.get());
if (!reg_op->isVirtual()) {
used_regs.insert(reg_op->getPReg());
}
} else if (op->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<MemOperand*>(op.get());
if (!mem_op->getBase()->isVirtual()) {
used_regs.insert(mem_op->getBase()->getPReg());
}
}
}
return used_regs;
}
// 获取内存访问的基址和偏移
struct MemoryAccess {
PhysicalReg base_reg;
int64_t offset;
bool valid;
MemoryAccess() : valid(false) {}
MemoryAccess(PhysicalReg base, int64_t off) : base_reg(base), offset(off), valid(true) {}
};
MemoryAccess getMemoryAccess(MachineInstr* instr) {
if (!isLoadInstr(instr) && !isStoreInstr(instr)) {
return MemoryAccess();
}
// 查找内存操作数
for (const auto& op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<MemOperand*>(op.get());
if (!mem_op->getBase()->isVirtual()) {
return MemoryAccess(mem_op->getBase()->getPReg(), mem_op->getOffset()->getValue());
}
}
}
return MemoryAccess();
}
// 检查内存依赖 - 加强版本
bool hasMemoryDependency(MachineInstr* instr1, MachineInstr* instr2) {
// 如果都不是内存指令,没有内存依赖
if (!isLoadInstr(instr1) && !isStoreInstr(instr1) &&
!isLoadInstr(instr2) && !isStoreInstr(instr2)) {
return false;
}
MemoryAccess mem1 = getMemoryAccess(instr1);
MemoryAccess mem2 = getMemoryAccess(instr2);
if (!mem1.valid || !mem2.valid) {
// 如果无法确定内存访问模式,保守地认为存在依赖
return true;
}
// 如果访问相同的内存位置
if (mem1.base_reg == mem2.base_reg && mem1.offset == mem2.offset) {
// Store->Load: RAW依赖
// Load->Store: WAR依赖
// Store->Store: WAW依赖
return isStoreInstr(instr1) || isStoreInstr(instr2);
}
// 不同内存位置通常没有依赖,但为了安全起见,
// 如果涉及store指令我们需要更保守
if (isStoreInstr(instr1) && isLoadInstr(instr2)) {
// 保守处理不同store和load之间可能有别名
return false; // 这里可以根据需要调整策略
}
return false;
}
// 检查两个指令之间是否存在依赖关系 - 修复版本
bool hasDependency(MachineInstr* instr1, MachineInstr* instr2) {
// 检查RAW依赖instr1定义的寄存器是否被instr2使用
auto defined_regs1 = getDefinedRegisters(instr1);
auto used_regs2 = getUsedRegisters(instr2);
for (const auto& reg : defined_regs1) {
if (used_regs2.find(reg) != used_regs2.end()) {
return true; // RAW依赖 - instr2读取instr1写入的值
}
}
// 检查WAR依赖instr1使用的寄存器是否被instr2定义
auto used_regs1 = getUsedRegisters(instr1);
auto defined_regs2 = getDefinedRegisters(instr2);
for (const auto& reg : used_regs1) {
if (defined_regs2.find(reg) != defined_regs2.end()) {
return true; // WAR依赖 - instr2覆盖instr1需要的值
}
}
// 检查WAW依赖两个指令定义相同寄存器
for (const auto& reg : defined_regs1) {
if (defined_regs2.find(reg) != defined_regs2.end()) {
return true; // WAW依赖 - 两条指令写入同一寄存器
}
}
// 检查内存依赖
if (hasMemoryDependency(instr1, instr2)) {
return true;
}
return false;
}
// 检查是否可以安全地将instr1和instr2交换位置
bool canSwapInstructions(MachineInstr* instr1, MachineInstr* instr2) {
// 不能移动控制流指令
if (isControlFlowInstr(instr1) || isControlFlowInstr(instr2)) {
return false;
}
// 检查双向依赖关系
return !hasDependency(instr1, instr2) && !hasDependency(instr2, instr1);
}
// 新增:验证调度结果的正确性
void validateSchedule(const std::vector<MachineInstr*>& instr_list) {
for (int i = 0; i < (int)instr_list.size(); i++) {
for (int j = i + 1; j < (int)instr_list.size(); j++) {
MachineInstr* earlier = instr_list[i];
MachineInstr* later = instr_list[j];
// 检查是否存在被违反的依赖关系
auto defined_regs = getDefinedRegisters(earlier);
auto used_regs = getUsedRegisters(later);
// 检查RAW依赖
for (const auto& reg : defined_regs) {
if (used_regs.find(reg) != used_regs.end()) {
// 这是正常的依赖关系earlier应该在later之前
continue;
}
}
// 检查内存依赖
if (hasMemoryDependency(earlier, later)) {
MemoryAccess mem1 = getMemoryAccess(earlier);
MemoryAccess mem2 = getMemoryAccess(later);
if (mem1.valid && mem2.valid &&
mem1.base_reg == mem2.base_reg && mem1.offset == mem2.offset) {
if (isStoreInstr(earlier) && isLoadInstr(later)) {
// Store->Load依赖顺序正确
continue;
}
}
}
}
}
}
// 在基本块内对指令进行调度优化 - 完全重写版本
void scheduleBlock(MachineBasicBlock* mbb) {
auto& instructions = mbb->getInstructions();
if (instructions.size() <= 1) return;
if (instructions.size() > MAX_SCHEDULING_BLOCK_SIZE) {
return; // 跳过超大块,防止卡住
}
std::vector<MachineInstr*> instr_list;
for (auto& instr : instructions) {
instr_list.push_back(instr.get());
}
// 使用更严格的调度策略,避免破坏依赖关系
bool changed = true;
int max_iterations = 10; // 限制迭代次数避免死循环
int iteration = 0;
while (changed && iteration < max_iterations) {
changed = false;
iteration++;
for (int i = 0; i < (int)instr_list.size() - 1; i++) {
MachineInstr* instr1 = instr_list[i];
MachineInstr* instr2 = instr_list[i + 1];
// 只进行非常保守的优化
bool should_swap = false;
// 策略1: 将load指令提前减少load-use延迟
if (isLoadInstr(instr2) && !isLoadInstr(instr1) && !isStoreInstr(instr1)) {
should_swap = canSwapInstructions(instr1, instr2);
}
// 策略2: 将非关键store指令延后为其他指令让路
else if (isStoreInstr(instr1) && !isLoadInstr(instr2) && !isStoreInstr(instr2)) {
should_swap = canSwapInstructions(instr1, instr2);
}
if (should_swap) {
std::swap(instr_list[i], instr_list[i + 1]);
changed = true;
// 调试输出
// std::cout << "Swapped instructions at positions " << i << " and " << (i+1) << std::endl;
}
}
}
// 验证调度结果的正确性
validateSchedule(instr_list);
// 将调度后的指令顺序写回
std::map<MachineInstr*, std::unique_ptr<MachineInstr>> instr_map;
for (auto& instr : instructions) {
instr_map[instr.get()] = std::move(instr);
}
instructions.clear();
for (auto instr : instr_list) {
instructions.push_back(std::move(instr_map[instr]));
}
}
bool PostRA_Scheduler::runOnFunction(Function *F, AnalysisManager& AM) {
// 这个函数在IR级别运行但我们需要在机器指令级别运行
// 所以我们返回false表示没有对IR进行修改
return false;
}
void PostRA_Scheduler::runOnMachineFunction(MachineFunction *mfunc) {
// std::cout << "Running Post-RA Local Scheduler... " << std::endl;
// 遍历每个机器基本块
for (auto& mbb : mfunc->getBlocks()) {
scheduleBlock(mbb.get());
}
}
} // namespace sysy

36
src/PreRA_Scheduler.cpp Normal file
View File

@@ -0,0 +1,36 @@
#include "PreRA_Scheduler.h"
namespace sysy {
char PreRA_Scheduler::ID = 0;
bool PreRA_Scheduler::runOnFunction(Function *F, AnalysisManager& AM) {
// TODO: 在此实现寄存器分配前的指令调度。
// 遍历mfunc中的每一个MachineBasicBlock。
// 对每个基本块内的MachineInstr列表进行重排。
//
// 实现思路:
// 1. 分析每个基本块内指令的数据依赖关系,构建依赖图(DAG)。
// 2.
// 根据目标处理器的流水线特性(指令延迟等),使用列表调度等算法对指令进行重排。
// 3. 此时操作的是虚拟寄存器,只存在真依赖,调度自由度最大。
//
// std::cout << "Running Pre-RA Instruction Scheduler..." << std::endl;
return false;
}
void PreRA_Scheduler::runOnMachineFunction(MachineFunction *mfunc) {
// TODO: 在此实现寄存器分配前的指令调度。
// 遍历mfunc中的每一个MachineBasicBlock。
// 对每个基本块内的MachineInstr列表进行重排。
//
// 实现思路:
// 1. 分析每个基本块内指令的数据依赖关系,构建依赖图(DAG)。
// 2.
// 根据目标处理器的流水线特性(指令延迟等),使用列表调度等算法对指令进行重排。
// 3. 此时操作的是虚拟寄存器,只存在真依赖,调度自由度最大。
//
// std::cout << "Running Pre-RA Instruction Scheduler..." << std::endl;
}
} // namespace sysy

View File

@@ -16,59 +16,13 @@ std::string RISCv64CodeGen::code_gen() {
std::string RISCv64CodeGen::module_gen() {
std::stringstream ss;
// --- [新逻辑] 步骤1全局变量分为.data和.bss两组 ---
std::vector<GlobalValue*> data_globals;
std::vector<GlobalValue*> bss_globals;
for (const auto& global_ptr : module->getGlobals()) {
GlobalValue* global = global_ptr.get();
const auto& init_values = global->getInitValues();
// 判断是否为大型零初始化数组,以便放入.bss段
bool is_large_zero_array = false;
// 规则初始化列表只有一项且该项是值为0的整数且数量大于一个阈值例如16
if (init_values.getValues().size() == 1) {
if (auto const_val = dynamic_cast<ConstantValue*>(init_values.getValues()[0])) {
if (const_val->isInt() && const_val->getInt() == 0 && init_values.getNumbers()[0] > 16) {
is_large_zero_array = true;
}
}
}
if (is_large_zero_array) {
bss_globals.push_back(global);
} else {
data_globals.push_back(global);
}
}
// --- [新逻辑] 步骤2生成 .bss 段的代码 ---
if (!bss_globals.empty()) {
ss << ".bss\n"; // 切换到 .bss 段
for (GlobalValue* global : bss_globals) {
// 获取数组总大小(元素个数 * 元素大小)
// 在SysY中我们假设元素都是4字节int或float
unsigned count = global->getInitValues().getNumbers()[0];
unsigned total_size = count * 4;
ss << " .align 3\n"; // 8字节对齐 (2^3)
ss << ".globl " << global->getName() << "\n";
ss << ".type " << global->getName() << ", @object\n";
ss << ".size " << global->getName() << ", " << total_size << "\n";
ss << global->getName() << ":\n";
// 使用 .space 指令来预留指定大小的零填充空间
ss << " .space " << total_size << "\n";
}
}
// --- [旧逻辑保留] 步骤3生成 .data 段的代码 ---
if (!data_globals.empty()) {
ss << ".data\n"; // 切换到 .data 段
for (GlobalValue* global : data_globals) {
// 1. 处理全局变量 (.data段)
if (!module->getGlobals().empty()) {
ss << ".data\n";
for (const auto& global : module->getGlobals()) {
ss << ".globl " << global->getName() << "\n";
ss << global->getName() << ":\n";
const auto& init_values = global->getInitValues();
// 使用您原有的逻辑来处理显式初始化的值
for (size_t i = 0; i < init_values.getValues().size(); ++i) {
auto val = init_values.getValues()[i];
auto count = init_values.getNumbers()[i];
@@ -87,7 +41,7 @@ std::string RISCv64CodeGen::module_gen() {
}
}
// --- 处理函数 (.text段) 的逻辑保持不变 ---
// 2. 处理函数 (.text段)
if (!module->getFunctions().empty()) {
ss << ".text\n";
for (const auto& func_pair : module->getFunctions()) {

View File

@@ -1,6 +0,0 @@
#include "RISCv64LLIR.h"
#include <vector>
namespace sysy {
}

View File

@@ -1,153 +0,0 @@
#include "RISCv64Passes.h"
#include <iostream>
namespace sysy {
// --- 寄存器分配前优化 ---
void PreRA_Scheduler::runOnMachineFunction(MachineFunction* mfunc) {
// TODO: 在此实现寄存器分配前的指令调度。
// 遍历mfunc中的每一个MachineBasicBlock。
// 对每个基本块内的MachineInstr列表进行重排。
//
// 实现思路:
// 1. 分析每个基本块内指令的数据依赖关系,构建依赖图(DAG)。
// 2. 根据目标处理器的流水线特性(指令延迟等),使用列表调度等算法对指令进行重排。
// 3. 此时操作的是虚拟寄存器,只存在真依赖,调度自由度最大。
//
// std::cout << "Running Pre-RA Instruction Scheduler..." << std::endl;
}
// --- 寄存器分配后优化 ---
void PeepholeOptimizer::runOnMachineFunction(MachineFunction* mfunc) {
// TODO: 在此实现窥孔优化。
// 遍历mfunc中的每一个MachineBasicBlock。
// 对每个基本块内的MachineInstr列表进行扫描和替换。
//
// 实现思路:
// 1. 维护一个大小固定例如3-5条指令的滑动窗口。
// 2. 识别特定的冗余模式,例如:
// - `mv a0, a1` 后紧跟 `mv a1, a0` (可消除的交换)
// - `sw t0, 12(s0)` 后紧跟 `lw t1, 12(s0)` (冗余加载)
// - 强度削减: `mul x, x, 2` -> `slli x, x, 1`
// 3. 识别后直接修改MachineInstr列表删除、替换或插入指令
//
// std::cout << "Running Post-RA Peephole Optimizer..." << std::endl;
}
void PostRA_Scheduler::runOnMachineFunction(MachineFunction* mfunc) {
// TODO: 在此实现寄存器分配后的局部指令调度。
// 遍历mfunc中的每一个MachineBasicBlock。
// 重点关注由寄存器分配器插入的spill/fill代码。
//
// 实现思路:
// 1. 识别出用于spill/fill的lw/sw指令。
// 2. 在不违反数据依赖(包括物理寄存器引入的伪依赖)的前提下,
// 尝试将lw指令向上移动使其与使用它的指令之间有足够的距离以隐藏访存延迟。
// 3. 同样可以尝试将sw指令向下移动。
//
// std::cout << "Running Post-RA Local Scheduler..." << std::endl;
}
void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
// 【最终方案】: 此 Pass 负责分析、分配栈空间并插入 callee-saved 寄存器的保存/恢复指令。
// 它通过与 FrameInfo 协作,确保为 callee-saved 寄存器分配的空间与局部变量/溢出槽的空间不冲突。
// 这样做可以使生成的 sd/ld 指令能被后续的优化 Pass (如 PostRA-Scheduler) 处理。
StackFrameInfo& frame_info = mfunc->getFrameInfo();
std::set<PhysicalReg> used_callee_saved;
// 1. 扫描所有指令找出被使用的s寄存器 (s1-s11)
for (auto& mbb : mfunc->getBlocks()) {
for (auto& instr : mbb->getInstructions()) {
for (auto& op : instr->getOperands()) {
auto check_and_insert_reg = [&](RegOperand* reg_op) {
if (!reg_op->isVirtual()) {
PhysicalReg preg = reg_op->getPReg();
if (preg >= PhysicalReg::S1 && preg <= PhysicalReg::S11) {
used_callee_saved.insert(preg);
}
}
};
if (op->getKind() == MachineOperand::KIND_REG) {
check_and_insert_reg(static_cast<RegOperand*>(op.get()));
} else if (op->getKind() == MachineOperand::KIND_MEM) {
check_and_insert_reg(static_cast<MemOperand*>(op.get())->getBase());
}
}
}
}
if (used_callee_saved.empty()) {
frame_info.callee_saved_size = 0; // 确保大小被初始化
return; // 无需操作
}
// 2. 计算为 callee-saved 寄存器分配的栈空间
// 这里的关键是,偏移的基准点要在局部变量和溢出槽之下。
int callee_saved_size = used_callee_saved.size() * 8;
frame_info.callee_saved_size = callee_saved_size; // 将大小存入 FrameInfo
// 3. 计算无冲突的栈偏移
// 栈向下增长,所以偏移是负数。
// ra/s0 占用 -8 和 -16。局部变量和溢出区在它们之下。callee-saved 区在更下方。
// 我们使用相对于 s0 的偏移。s0 将指向栈顶 (sp + total_size)。
int base_offset = -16 - frame_info.locals_size - frame_info.spill_size;
// 为了栈帧布局确定性,对寄存器进行排序
std::vector<PhysicalReg> sorted_regs(used_callee_saved.begin(), used_callee_saved.end());
std::sort(sorted_regs.begin(), sorted_regs.end());
// 4. 在函数序言插入保存指令
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
auto& entry_instrs = entry_block->getInstructions();
auto prologue_end = entry_instrs.begin();
// 找到序言结束的位置通常是addi s0, sp, size之后但为了让优化器看到我们插在更前面
// 合理的位置是在 IR 指令开始之前,即在任何非序言指令(如第一个标签)之前。
// 为简单起见,我们直接插入到块的开头,后续重排 pass 会处理。
// (更优的实现会寻找一个特定的插入点)
int current_offset = base_offset;
for (PhysicalReg reg : sorted_regs) {
auto sd = std::make_unique<MachineInstr>(RVOpcodes::SD);
sd->addOperand(std::make_unique<RegOperand>(reg));
sd->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0), // 基址为帧指针 s0
std::make_unique<ImmOperand>(current_offset)
));
// 从头部插入,但要放在函数标签之后
entry_instrs.insert(entry_instrs.begin() + 1, std::move(sd));
current_offset -= 8;
}
// 5. 【已修复】在函数结尾ret之前插入恢复指令使用反向遍历来避免迭代器失效
for (auto& mbb : mfunc->getBlocks()) {
// 使用手动控制的反向循环
for (auto it = mbb->getInstructions().end(); it != mbb->getInstructions().begin(); ) {
// 在循环开始时就递减迭代器
--it;
if ((*it)->getOpcode() == RVOpcodes::RET) {
int current_offset_load = base_offset;
// 以相同的顺序恢复(从 s1 开始)
for (PhysicalReg reg : sorted_regs) {
auto ld = std::make_unique<MachineInstr>(RVOpcodes::LD);
ld->addOperand(std::make_unique<RegOperand>(reg));
ld->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(current_offset_load)
));
// 在 'it' (即 RET 指令) 之前插入。
// 因为我们是反向遍历,所以这不会影响下一次循环的 'it'。
mbb->getInstructions().insert(it, std::move(ld));
current_offset_load -= 8;
}
}
}
}
}
} // namespace sysy

652
src/RISCv64Peephole.cpp Normal file
View File

@@ -0,0 +1,652 @@
#include "RISCv64Peephole.h"
#include <functional>
namespace sysy {
char PeepholeOptimizer::ID = 0;
bool PeepholeOptimizer::runOnFunction(Function *F, AnalysisManager& AM) {
// This pass works on MachineFunction level, not IR level
return false;
}
void PeepholeOptimizer::runOnMachineFunction(MachineFunction *mfunc) {
if (!mfunc)
return;
using namespace sysy;
// areRegsEqual: 检查两个寄存器操作数是否相等(考虑虚拟和物理寄存器)。
auto areRegsEqual = [](RegOperand *r1, RegOperand *r2) {
if (!r1 || !r2 || r1->isVirtual() != r2->isVirtual()) {
return false;
}
if (r1->isVirtual()) {
return r1->getVRegNum() == r2->getVRegNum();
} else {
return r1->getPReg() == r2->getPReg();
}
};
// 改进的 isRegUsedLater 函数 - 更完整和准确的实现
auto isRegUsedLater =
[&](const std::vector<std::unique_ptr<MachineInstr>> &instrs,
RegOperand *reg, size_t start_idx) -> bool {
for (size_t j = start_idx; j < instrs.size(); ++j) {
auto *instr = instrs[j].get();
auto opcode = instr->getOpcode();
// 检查所有操作数
for (size_t k = 0; k < instr->getOperands().size(); ++k) {
bool isDefOperand = false;
// 更完整的定义操作数判断逻辑
if (k == 0) { // 第一个操作数通常是目标寄存器
switch (opcode) {
// 算术和逻辑指令 - 第一个操作数是定义
case RVOpcodes::MV:
case RVOpcodes::ADDI:
case RVOpcodes::SLLI:
case RVOpcodes::SRLI:
case RVOpcodes::SRAI:
case RVOpcodes::SLTI:
case RVOpcodes::SLTIU:
case RVOpcodes::XORI:
case RVOpcodes::ORI:
case RVOpcodes::ANDI:
case RVOpcodes::ADD:
case RVOpcodes::SUB:
case RVOpcodes::SLL:
case RVOpcodes::SLT:
case RVOpcodes::SLTU:
case RVOpcodes::XOR:
case RVOpcodes::SRL:
case RVOpcodes::SRA:
case RVOpcodes::OR:
case RVOpcodes::AND:
case RVOpcodes::MUL:
case RVOpcodes::DIV:
case RVOpcodes::REM:
case RVOpcodes::LW:
case RVOpcodes::LH:
case RVOpcodes::LB:
case RVOpcodes::LHU:
case RVOpcodes::LBU:
// 存储指令 - 第一个操作数是使用(要存储的值)
case RVOpcodes::SW:
case RVOpcodes::SH:
case RVOpcodes::SB:
// 分支指令 - 第一个操作数是使用
case RVOpcodes::BEQ:
case RVOpcodes::BNE:
case RVOpcodes::BLT:
case RVOpcodes::BGE:
case RVOpcodes::BLTU:
case RVOpcodes::BGEU:
// 跳转指令 - 可能使用寄存器
case RVOpcodes::JALR:
isDefOperand = false;
break;
default:
// 对于未知指令,保守地假设第一个操作数可能是使用
isDefOperand = false;
break;
}
}
// 如果不是定义操作数,检查是否使用了目标寄存器
if (!isDefOperand) {
if (instr->getOperands()[k]->getKind() == MachineOperand::KIND_REG) {
auto *use_reg =
static_cast<RegOperand *>(instr->getOperands()[k].get());
if (areRegsEqual(reg, use_reg))
return true;
}
// 检查内存操作数中的基址寄存器
if (instr->getOperands()[k]->getKind() == MachineOperand::KIND_MEM) {
auto *mem =
static_cast<MemOperand *>(instr->getOperands()[k].get());
if (areRegsEqual(reg, mem->getBase()))
return true;
}
}
}
}
return false;
};
// 检查寄存器是否在指令中被重新定义(用于更精确的分析)
auto isRegRedefinedAt =
[](MachineInstr *instr, RegOperand *reg,
const std::function<bool(RegOperand *, RegOperand *)> &areRegsEqual)
-> bool {
if (instr->getOperands().empty())
return false;
auto opcode = instr->getOpcode();
// 只有当第一个操作数是定义操作数时才检查
switch (opcode) {
case RVOpcodes::MV:
case RVOpcodes::ADDI:
case RVOpcodes::ADD:
case RVOpcodes::SUB:
case RVOpcodes::MUL:
case RVOpcodes::LW:
// ... 其他定义指令
if (instr->getOperands()[0]->getKind() == MachineOperand::KIND_REG) {
auto *def_reg =
static_cast<RegOperand *>(instr->getOperands()[0].get());
return areRegsEqual(reg, def_reg);
}
break;
default:
break;
}
return false;
};
// 检查是否为存储-加载模式,支持不同大小的访问
auto isStoreLoadPattern = [](MachineInstr *store_instr,
MachineInstr *load_instr) -> bool {
auto store_op = store_instr->getOpcode();
auto load_op = load_instr->getOpcode();
// 检查存储-加载对应关系
return (store_op == RVOpcodes::SW && load_op == RVOpcodes::LW) || // 32位
(store_op == RVOpcodes::SH &&
load_op == RVOpcodes::LH) || // 16位有符号
(store_op == RVOpcodes::SH &&
load_op == RVOpcodes::LHU) || // 16位无符号
(store_op == RVOpcodes::SB &&
load_op == RVOpcodes::LB) || // 8位有符号
(store_op == RVOpcodes::SB &&
load_op == RVOpcodes::LBU) || // 8位无符号
(store_op == RVOpcodes::SD && load_op == RVOpcodes::LD); // 64位
};
// 检查两个内存访问是否访问相同的内存位置
auto areMemoryAccessesEqual =
[&areRegsEqual](MachineInstr *store_instr, MemOperand *store_mem,
MachineInstr *load_instr, MemOperand *load_mem) -> bool {
// 基址寄存器必须相同
if (!areRegsEqual(store_mem->getBase(), load_mem->getBase())) {
return false;
}
// 偏移量必须相同
if (store_mem->getOffset()->getValue() !=
load_mem->getOffset()->getValue()) {
return false;
}
// 检查访问大小是否兼容
auto store_op = store_instr->getOpcode();
auto load_op = load_instr->getOpcode();
// 获取访问大小(字节数)
auto getAccessSize = [](RVOpcodes opcode) -> int {
switch (opcode) {
case RVOpcodes::LB:
case RVOpcodes::LBU:
case RVOpcodes::SB:
return 1; // 8位
case RVOpcodes::LH:
case RVOpcodes::LHU:
case RVOpcodes::SH:
return 2; // 16位
case RVOpcodes::LW:
case RVOpcodes::SW:
return 4; // 32位
case RVOpcodes::LD:
case RVOpcodes::SD:
return 8; // 64位
default:
return -1; // 未知
}
};
int store_size = getAccessSize(store_op);
int load_size = getAccessSize(load_op);
// 只有访问大小完全匹配时才能进行优化
// 这避免了部分重叠访问的复杂情况
return store_size > 0 && store_size == load_size;
};
// 简单的内存别名分析:检查两个内存访问之间是否可能有冲突的内存操作
auto isMemoryAccessSafe =
[&](const std::vector<std::unique_ptr<MachineInstr>> &instrs,
size_t store_idx, size_t load_idx, MemOperand *mem) -> bool {
// 检查存储和加载之间是否有可能影响内存的指令
for (size_t j = store_idx + 1; j < load_idx; ++j) {
auto *between_instr = instrs[j].get();
auto between_op = between_instr->getOpcode();
// 检查是否有其他内存写入操作
switch (between_op) {
case RVOpcodes::SW:
case RVOpcodes::SH:
case RVOpcodes::SB:
case RVOpcodes::SD: {
// 如果有其他存储操作,需要检查是否可能访问相同的内存
if (between_instr->getOperands().size() >= 2 &&
between_instr->getOperands()[1]->getKind() ==
MachineOperand::KIND_MEM) {
auto *other_mem =
static_cast<MemOperand *>(between_instr->getOperands()[1].get());
// 保守的别名分析:如果使用不同的基址寄存器,假设可能别名
if (!areRegsEqual(mem->getBase(), other_mem->getBase())) {
return false; // 可能的别名,不安全
}
// 如果基址相同但偏移量不同,检查是否重叠
int64_t offset1 = mem->getOffset()->getValue();
int64_t offset2 = other_mem->getOffset()->getValue();
// 获取访问大小来检查重叠
auto getAccessSize = [](RVOpcodes opcode) -> int {
switch (opcode) {
case RVOpcodes::SB:
return 1;
case RVOpcodes::SH:
return 2;
case RVOpcodes::SW:
return 4;
case RVOpcodes::SD:
return 8;
default:
return 4; // 默认假设4字节
}
};
int size1 = getAccessSize(RVOpcodes::SW); // 从原存储指令推断
int size2 = getAccessSize(between_op);
// 检查内存区域是否重叠
bool overlaps =
!(offset1 + size1 <= offset2 || offset2 + size2 <= offset1);
if (overlaps) {
return false; // 内存重叠,不安全
}
}
break;
}
// 函数调用可能有副作用
case RVOpcodes::JAL:
case RVOpcodes::JALR:
return false; // 函数调用可能修改内存,不安全
// 原子操作或其他可能修改内存的指令
// 根据具体的RISC-V扩展添加更多指令
default:
// 对于未知指令,采用保守策略
// 可以根据具体需求调整
break;
}
}
return true; // 没有发现潜在的内存冲突
};
// isPowerOfTwo: 检查数值是否为2的幂次并返回其指数。
auto isPowerOfTwo = [](int64_t n) -> int {
if (n <= 0 || (n & (n - 1)) != 0)
return -1;
int shift = 0;
while (n > 1) {
n >>= 1;
shift++;
}
return shift;
};
for (auto &mbb_uptr : mfunc->getBlocks()) {
auto &mbb = *mbb_uptr;
auto &instrs = mbb.getInstructions();
if (instrs.size() < 2)
continue; // 基本块至少需要两条指令进行窥孔
// 遍历指令序列进行窥孔优化
for (size_t i = 0; i + 1 < instrs.size();) {
auto *mi1 = instrs[i].get();
auto *mi2 = instrs[i + 1].get();
bool changed = false;
// 1. 消除冗余交换移动: mv a, b; mv b, a -> mv a, b
if (mi1->getOpcode() == RVOpcodes::MV &&
mi2->getOpcode() == RVOpcodes::MV) {
if (mi1->getOperands().size() == 2 && mi2->getOperands().size() == 2) {
if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG &&
mi2->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi2->getOperands()[1]->getKind() == MachineOperand::KIND_REG) {
auto *dst1 = static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *src1 = static_cast<RegOperand *>(mi1->getOperands()[1].get());
auto *dst2 = static_cast<RegOperand *>(mi2->getOperands()[0].get());
auto *src2 = static_cast<RegOperand *>(mi2->getOperands()[1].get());
if (areRegsEqual(dst1, src2) && areRegsEqual(src1, dst2)) {
instrs.erase(instrs.begin() + i + 1); // 移除第二条指令
changed = true;
}
}
}
}
// 2. 冗余加载消除: sw t0, offset(base); lw t1, offset(base) -> 替换或消除
// lw 添加ld sd支持
else if (isStoreLoadPattern(mi1, mi2)) {
if (mi1->getOperands().size() == 2 && mi2->getOperands().size() == 2) {
if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_MEM &&
mi2->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi2->getOperands()[1]->getKind() == MachineOperand::KIND_MEM) {
auto *store_val =
static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *store_mem =
static_cast<MemOperand *>(mi1->getOperands()[1].get());
auto *load_val =
static_cast<RegOperand *>(mi2->getOperands()[0].get());
auto *load_mem =
static_cast<MemOperand *>(mi2->getOperands()[1].get());
// 检查内存访问是否匹配(基址、偏移量和访问大小)
if (areMemoryAccessesEqual(mi1, store_mem, mi2, load_mem)) {
// 进行简单的内存别名分析
if (isMemoryAccessSafe(instrs, i, i + 1, store_mem)) {
if (areRegsEqual(store_val, load_val)) {
// sw r1, mem; lw r1, mem -> 消除冗余的lw
instrs.erase(instrs.begin() + i + 1);
changed = true;
} else {
// sw r1, mem; lw r2, mem -> 替换lw为mv r2, r1
auto newInstr = std::make_unique<MachineInstr>(RVOpcodes::MV);
newInstr->addOperand(std::make_unique<RegOperand>(*load_val));
newInstr->addOperand(
std::make_unique<RegOperand>(*store_val));
instrs[i + 1] = std::move(newInstr);
changed = true;
}
}
}
}
}
}
// 3. 强度削减: mul y, x, 2^n -> slli y, x, n
else if (mi1->getOpcode() == RVOpcodes::MUL &&
mi1->getOperands().size() == 3) {
auto *dst_op = mi1->getOperands()[0].get();
auto *src1_op = mi1->getOperands()[1].get();
auto *src2_op = mi1->getOperands()[2].get();
if (dst_op->getKind() == MachineOperand::KIND_REG) {
auto *dst_reg = static_cast<RegOperand *>(dst_op);
RegOperand *src_reg = nullptr;
int shift = -1;
if (src1_op->getKind() == MachineOperand::KIND_REG &&
src2_op->getKind() == MachineOperand::KIND_IMM) {
shift =
isPowerOfTwo(static_cast<ImmOperand *>(src2_op)->getValue());
if (shift >= 0)
src_reg = static_cast<RegOperand *>(src1_op);
} else if (src1_op->getKind() == MachineOperand::KIND_IMM &&
src2_op->getKind() == MachineOperand::KIND_REG) {
shift =
isPowerOfTwo(static_cast<ImmOperand *>(src1_op)->getValue());
if (shift >= 0)
src_reg = static_cast<RegOperand *>(src2_op);
}
if (src_reg && shift >= 0 &&
shift <= 31) { // RISC-V 移位量限制 (0-31)
auto newInstr = std::make_unique<MachineInstr>(RVOpcodes::SLLI);
newInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
newInstr->addOperand(std::make_unique<RegOperand>(*src_reg));
newInstr->addOperand(std::make_unique<ImmOperand>(shift));
instrs[i] = std::move(newInstr);
changed = true;
}
}
}
// 4. 地址计算优化: addi dst, base, imm1; lw/sw val, imm2(dst) -> lw/sw
// val, (imm1+imm2)(base)
else if (mi1->getOpcode() == RVOpcodes::ADDI &&
mi1->getOperands().size() == 3) {
auto opcode2 = mi2->getOpcode();
if (opcode2 == RVOpcodes::LW || opcode2 == RVOpcodes::SW) {
if (mi2->getOperands().size() == 2 &&
mi2->getOperands()[1]->getKind() == MachineOperand::KIND_MEM &&
mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[2]->getKind() == MachineOperand::KIND_IMM) {
auto *addi_dst =
static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *addi_base =
static_cast<RegOperand *>(mi1->getOperands()[1].get());
auto *addi_imm =
static_cast<ImmOperand *>(mi1->getOperands()[2].get());
auto *mem_op =
static_cast<MemOperand *>(mi2->getOperands()[1].get());
auto *mem_base = mem_op->getBase();
auto *mem_imm = mem_op->getOffset();
// 检查 ADDI 的目标寄存器是否是内存操作的基址
if (areRegsEqual(addi_dst, mem_base)) {
// 改进的使用检查:考虑寄存器可能在后续被重新定义的情况
bool canOptimize = true;
// 检查从 i+2 开始的指令
for (size_t j = i + 2; j < instrs.size(); ++j) {
auto *later_instr = instrs[j].get();
// 如果寄存器被重新定义,那么它后面的使用就不相关了
if (isRegRedefinedAt(later_instr, addi_dst, areRegsEqual)) {
break; // 寄存器被重新定义,可以安全优化
}
// 如果寄存器被使用,则不能优化
if (isRegUsedLater(instrs, addi_dst, j)) {
canOptimize = false;
break;
}
}
if (canOptimize) {
int64_t new_offset = addi_imm->getValue() + mem_imm->getValue();
// 检查新偏移量是否符合 RISC-V 12位有符号立即数范围
if (new_offset >= -2048 && new_offset <= 2047) {
auto new_mem_op = std::make_unique<MemOperand>(
std::make_unique<RegOperand>(*addi_base),
std::make_unique<ImmOperand>(new_offset));
mi2->getOperands()[1] = std::move(new_mem_op);
instrs.erase(instrs.begin() + i);
changed = true;
}
}
}
}
}
}
// 5. 冗余移动指令消除: mv x, y; op z, x, ... -> op z, y, ... (如果 x
// 之后不再使用)
else if (mi1->getOpcode() == RVOpcodes::MV &&
mi1->getOperands().size() == 2) {
if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG) {
auto *mv_dst = static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *mv_src = static_cast<RegOperand *>(mi1->getOperands()[1].get());
// 检查第二条指令是否使用了 mv 的目标寄存器
std::vector<size_t> use_positions;
for (size_t k = 1; k < mi2->getOperands().size(); ++k) {
if (mi2->getOperands()[k]->getKind() == MachineOperand::KIND_REG) {
auto *use_reg =
static_cast<RegOperand *>(mi2->getOperands()[k].get());
if (areRegsEqual(mv_dst, use_reg)) {
use_positions.push_back(k);
}
}
// 也检查内存操作数中的基址寄存器
else if (mi2->getOperands()[k]->getKind() ==
MachineOperand::KIND_MEM) {
auto *mem =
static_cast<MemOperand *>(mi2->getOperands()[k].get());
if (areRegsEqual(mv_dst, mem->getBase())) {
// 对于内存操作数我们需要创建新的MemOperand
auto new_mem = std::make_unique<MemOperand>(
std::make_unique<RegOperand>(*mv_src),
std::make_unique<ImmOperand>(mem->getOffset()->getValue()));
mi2->getOperands()[k] = std::move(new_mem);
use_positions.push_back(k); // 标记已处理
}
}
}
if (!use_positions.empty()) {
// 改进的后续使用检查
bool canOptimize = true;
for (size_t j = i + 2; j < instrs.size(); ++j) {
auto *later_instr = instrs[j].get();
// 如果寄存器被重新定义,后续使用就不相关了
if (isRegRedefinedAt(later_instr, mv_dst, areRegsEqual)) {
break;
}
// 检查是否还有其他使用
if (isRegUsedLater(instrs, mv_dst, j)) {
canOptimize = false;
break;
}
}
if (canOptimize) {
// 替换所有寄存器使用(内存操作数已在上面处理)
for (size_t pos : use_positions) {
if (mi2->getOperands()[pos]->getKind() ==
MachineOperand::KIND_REG) {
mi2->getOperands()[pos] =
std::make_unique<RegOperand>(*mv_src);
}
}
instrs.erase(instrs.begin() + i);
changed = true;
}
}
}
}
// 6. 连续加法指令合并: addi t1, t0, imm1; addi t2, t1, imm2 -> addi t2,
// t0, (imm1+imm2)
else if (mi1->getOpcode() == RVOpcodes::ADDI &&
mi2->getOpcode() == RVOpcodes::ADDI) {
if (mi1->getOperands().size() == 3 && mi2->getOperands().size() == 3) {
if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[2]->getKind() == MachineOperand::KIND_IMM &&
mi2->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi2->getOperands()[1]->getKind() == MachineOperand::KIND_REG &&
mi2->getOperands()[2]->getKind() == MachineOperand::KIND_IMM) {
auto *addi1_dst =
static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *addi1_src =
static_cast<RegOperand *>(mi1->getOperands()[1].get());
auto *addi1_imm =
static_cast<ImmOperand *>(mi1->getOperands()[2].get());
auto *addi2_dst =
static_cast<RegOperand *>(mi2->getOperands()[0].get());
auto *addi2_src =
static_cast<RegOperand *>(mi2->getOperands()[1].get());
auto *addi2_imm =
static_cast<ImmOperand *>(mi2->getOperands()[2].get());
// 检查第一个ADDI的目标是否是第二个ADDI的源
if (areRegsEqual(addi1_dst, addi2_src)) {
// 改进的中间寄存器使用检查
bool canOptimize = true;
for (size_t j = i + 2; j < instrs.size(); ++j) {
auto *later_instr = instrs[j].get();
// 如果中间寄存器被重新定义,后续使用不相关
if (isRegRedefinedAt(later_instr, addi1_dst, areRegsEqual)) {
break;
}
// 检查是否有其他使用
if (isRegUsedLater(instrs, addi1_dst, j)) {
canOptimize = false;
break;
}
}
if (canOptimize) {
int64_t new_imm = addi1_imm->getValue() + addi2_imm->getValue();
// 检查新立即数范围
if (new_imm >= -2048 && new_imm <= 2047) {
auto newInstr =
std::make_unique<MachineInstr>(RVOpcodes::ADDI);
newInstr->addOperand(
std::make_unique<RegOperand>(*addi2_dst));
newInstr->addOperand(
std::make_unique<RegOperand>(*addi1_src));
newInstr->addOperand(std::make_unique<ImmOperand>(new_imm));
instrs[i + 1] = std::move(newInstr);
instrs.erase(instrs.begin() + i);
changed = true;
}
}
}
}
}
}
// 7. ADD with zero optimization: add r1, r2, zero -> mv r1, r2
else if (mi1->getOpcode() == RVOpcodes::ADD &&
mi1->getOperands().size() == 3) {
if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG &&
mi1->getOperands()[2]->getKind() == MachineOperand::KIND_REG) {
auto *add_dst =
static_cast<RegOperand *>(mi1->getOperands()[0].get());
auto *add_src1 =
static_cast<RegOperand *>(mi1->getOperands()[1].get());
auto *add_src2 =
static_cast<RegOperand *>(mi1->getOperands()[2].get());
// 检查第二个源操作数是否为ZERO寄存器
if (!add_src2->isVirtual() &&
add_src2->getPReg() == PhysicalReg::ZERO) {
// 创建新的 MV 指令
auto newInstr = std::make_unique<MachineInstr>(RVOpcodes::MV);
newInstr->addOperand(std::make_unique<RegOperand>(*add_dst));
newInstr->addOperand(std::make_unique<RegOperand>(*add_src1));
instrs[i] = std::move(newInstr);
changed = true;
}
}
}
// 根据是否发生变化调整遍历索引
if (!changed) {
++i; // 没有优化,继续检查下一对指令
} else {
// 发生变化,适当回退以捕获新的优化机会。
// 这是一种安全的回退策略,可以触发连锁优化,且不会导致无限循环。
if (i > 0) {
--i;
}
}
}
}
}
} // namespace sysy

View File

@@ -2,8 +2,6 @@
#include "RISCv64ISel.h"
#include <algorithm>
#include <vector>
#include <iostream> // For DEBUG output
#include <cassert> // For assert
namespace sysy {
@@ -13,33 +11,19 @@ RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) : MFunc(mfunc) {
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::S0, PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3,
PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
};
// 映射物理寄存器到特殊的虚拟寄存器ID用于干扰图中的物理寄存器节点
// 确保这些特殊ID不会与vreg_counter生成的常规虚拟寄存器ID冲突
for (PhysicalReg preg : allocable_int_regs) {
preg_to_vreg_id_map[preg] = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID) + static_cast<unsigned>(preg);
}
}
// 寄存器分配的主入口点
void RISCv64RegAlloc::run() {
// 阶段 1: 处理函数调用约定(参数寄存器预着色)
handleCallingConvention();
// 阶段 2: 消除帧索引(为局部变量和栈参数分配栈偏移)
eliminateFrameIndices();
// 阶段 3: 活跃性分析
analyzeLiveness();
// 阶段 4: 构建干扰图包含CALL指令对调用者保存寄存器的影响
buildInterferenceGraph();
// 阶段 5: 图着色算法分配物理寄存器
colorGraph();
// 阶段 6: 重写函数(插入溢出/填充代码,替换虚拟寄存器为物理寄存器)
rewriteFunction();
handleCallingConvention();
eliminateFrameIndices();
analyzeLiveness();
buildInterferenceGraph();
colorGraph();
rewriteFunction();
}
/**
@@ -59,10 +43,7 @@ void RISCv64RegAlloc::handleCallingConvention() {
if (arg_idx >= 8) {
break;
}
// 获取该 Argument 对象对应的虚拟寄存器ID
// 通过 MachineFunction -> RISCv64ISel -> vreg_map 来获取
const auto& vreg_map_from_isel = MFunc->getISel()->getVRegMap();
assert(vreg_map_from_isel.count(arg) && "Argument not found in ISel's vreg_map!");
// 1. 获取该 Argument 对象对应的虚拟寄存器
unsigned vreg = isel->getVReg(arg);
@@ -77,9 +58,6 @@ void RISCv64RegAlloc::handleCallingConvention() {
}
}
/**
* @brief 消除帧索引,为局部变量和栈参数分配栈偏移量,并展开伪指令。
*/
void RISCv64RegAlloc::eliminateFrameIndices() {
StackFrameInfo& frame_info = MFunc->getFrameInfo();
// 初始偏移量为保存ra和s0留出空间。
@@ -207,38 +185,30 @@ void RISCv64RegAlloc::eliminateFrameIndices() {
}
}
/**
* @brief 计算给定 MachineInstr 的 Use (读取) 和 Def (写入) 寄存器集合。
* 这是活跃性分析的基础。
* @param instr 要分析的机器指令。
* @param use 存储 Use 寄存器(虚拟寄存器 ID的集合。
* @param def 存储 Def 寄存器(虚拟寄存器 ID的集合。
*/
void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def) {
bool first_reg_is_def = true; // 默认情况下,指令的第一个寄存器操作数是定义 (def)
bool is_def = true;
auto opcode = instr->getOpcode();
// 1. 特殊指令的 `is_def` 标志调整
// 这些指令的第一个寄存器操作数是源操作数 (use),而不是目标操作数 (def)。
// --- 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) {
first_reg_is_def = false;
}
// JAL 和 JALR 指令定义 ra (x1)
if (opcode == RVOpcodes::JAL || opcode == RVOpcodes::JALR) {
// 使用 ra 对应的特殊虚拟寄存器ID
def.insert(static_cast<unsigned>(PhysicalReg::RA));
first_reg_is_def = false; // JAL/JALR 的第一个操作数是 ra已经处理为 def
is_def = false;
}
// 2. CALL 指令特殊处理
// CALL 指令进行特殊处理
if (opcode == RVOpcodes::CALL) {
// 1.1 处理返回值 (def)
// 约定如果CALL指令有返回值IR阶段会将返回值vreg作为指令的第一个操作数
// 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()) {
@@ -246,19 +216,14 @@ void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet&
}
}
// 1.2 处理参数 (use)
// 参数通常是指令的后续操作数
bool first_operand_processed = false; // 用于跳过已作为def处理的返回值
// 遍历所有操作数,非第一个寄存器操作数均视为use
bool first_reg_skipped = false;
for (const auto& op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
if (!first_operand_processed) { // 如果是第一个操作数
first_operand_processed = true;
// 如果第一个操作数是返回值已被加入def则跳过
if (def.count(static_cast<RegOperand*>(op.get())->getVRegNum())) {
continue;
}
if (!first_reg_skipped) {
first_reg_skipped = true;
continue; // 跳过我们已经作为def处理的返回值
}
// 否则,该寄存器是 use
auto reg_op = static_cast<RegOperand*>(op.get());
if (reg_op->isVirtual()) {
use.insert(reg_op->getVRegNum());
@@ -266,43 +231,34 @@ void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet&
}
}
// **重要**: CALL指令隐式定义杀死了所有调用者保存的寄存器。
// **这部分逻辑不在getInstrUseDef中直接处理**。
// 而是通过`buildInterferenceGraph`中添加物理寄存器节点与活跃虚拟寄存器之间的干扰边来完成
// 这样 Liveness Analysis 可以在虚拟寄存器层面进行,而物理寄存器干扰的复杂性则留给干扰图
// **重要**: CALL指令隐式定义(杀死)了所有调用者保存的寄存器。
// 一个完整的实现会在这里将所有caller-saved寄存器标记为def
// 以确保任何跨调用存活的变量都不会被分配到这些寄存器中
// 这个简化的实现暂不处理隐式def但这是未来优化的关键点
return; // CALL 指令处理完毕,直接返回
}
// 3. 对其他所有指令的通用处理逻辑
// --- 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()) { // 只有虚拟寄存器才需要处理 Use/Def
// 如果是第一个寄存器操作数,且指令类型表明它是定义 (def),则加入 def 集合
// 否则,它是 use (读取)
if (first_reg_is_def) {
if (reg_op->isVirtual()) {
if (is_def) {
def.insert(reg_op->getVRegNum());
first_reg_is_def = false; // 确保每条指令只定义一个目标寄存
is_def = false; // 一条指令通常只有一个目标寄存ator
} else {
use.insert(reg_op->getVRegNum());
}
}
} else if (op->getKind() == MachineOperand::KIND_MEM) {
// 内存操作数 `offset(base)` 中的 `base` 寄存器是 `use`
// 内存操作数 `offset(base)` 中的 base 寄存器是 use
auto mem_op = static_cast<MemOperand*>(op.get());
if (mem_op->getBase()->isVirtual()) {
use.insert(mem_op->getBase()->getVRegNum());
}
// 对于存储内存指令 (SW, SD),要存储的值(第一个操作数)也是 `use`
if ((opcode == RVOpcodes::SW || opcode == RVOpcodes::SD) &&
!instr->getOperands().empty() && // 确保有操作数
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) { // 且第一个操作数是寄存器
auto src_reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
if (src_reg_op->isVirtual()) {
use.insert(src_reg_op->getVRegNum());
}
}
}
}
}
@@ -388,7 +344,6 @@ void RISCv64RegAlloc::analyzeLiveness() {
void RISCv64RegAlloc::buildInterferenceGraph() {
std::set<unsigned> all_vregs;
// 收集所有虚拟寄存器和物理寄存器在干扰图中的节点ID
for (auto& mbb : MFunc->getBlocks()) {
for(auto& instr : mbb->getInstructions()) {
LiveSet use, def;
@@ -397,11 +352,6 @@ void RISCv64RegAlloc::buildInterferenceGraph() {
for(auto d : def) all_vregs.insert(d);
}
}
// 添加所有物理寄存器对应的特殊虚拟寄存器ID到all_vregs作为干扰图节点
for (auto preg : allocable_int_regs) {
all_vregs.insert(preg_to_vreg_id_map.at(preg));
}
for (auto vreg : all_vregs) { interference_graph[vreg] = {}; }
@@ -411,7 +361,6 @@ void RISCv64RegAlloc::buildInterferenceGraph() {
getInstrUseDef(instr.get(), use, def);
const LiveSet& live_out = live_out_map.at(instr.get());
// 标准干扰图构建def 与 live_out 中的其他变量干扰
for (unsigned d : def) {
for (unsigned l : live_out) {
if (d != l) {
@@ -420,24 +369,6 @@ void RISCv64RegAlloc::buildInterferenceGraph() {
}
}
}
// *** 核心修改点:处理 CALL 指令的隐式 def ***
if (instr->getOpcode() == RVOpcodes::CALL) {
// CALL 指令会定义(杀死)所有调用者保存的寄存器。
// 因此,所有调用者保存的物理寄存器都与 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
// 将这个物理寄存器节点与 CALL 指令的 live_out 中的所有虚拟寄存器添加干扰边。
for (unsigned live_vreg_out : live_out) {
if (cs_vreg_id != live_vreg_out) { // 避免自己和自己干扰
interference_graph[cs_vreg_id].insert(live_vreg_out);
interference_graph[live_vreg_out].insert(cs_vreg_id);
}
}
}
}
}
}
}
@@ -458,27 +389,10 @@ void RISCv64RegAlloc::colorGraph() {
// 着色
for (unsigned vreg : sorted_vregs) {
std::set<PhysicalReg> used_colors;
for (unsigned neighbor_id : interference_graph.at(vreg)) {
// --- 修改开始 ---
// 情况 1: 邻居是一个已经被着色的虚拟寄存器
if (color_map.count(neighbor_id)) {
used_colors.insert(color_map.at(neighbor_id));
}
// 情况 2: 邻居本身就是一个代表物理寄存器的节点
else if (neighbor_id >= static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID)) {
// 需要一个反向映射来从特殊ID找回PhysicalReg
// 假设你有这样一个映射 inv_preg_to_vreg_id_map
// 或者,你可以重新计算
for (auto const& [preg, id] : preg_to_vreg_id_map) {
if (id == neighbor_id) {
used_colors.insert(preg);
break;
}
}
for (unsigned neighbor : interference_graph.at(vreg)) {
if (color_map.count(neighbor)) {
used_colors.insert(color_map.at(neighbor));
}
// --- 修改结束 ---
}
bool colored = false;

View File

@@ -0,0 +1,33 @@
#ifndef CALLEE_SAVED_HANDLER_H
#define CALLEE_SAVED_HANDLER_H
#include "RISCv64LLIR.h"
#include "Pass.h"
namespace sysy {
/**
* @class CalleeSavedHandler
* @brief 处理被调用者保存寄存器(Callee-Saved Registers)的Pass。
* * 这个Pass在寄存器分配之后运行。它的主要职责是
* 1. 扫描整个函数,找出所有被使用的 `s` 系列寄存器。
* 2. 在函数序言中插入 `sd` 指令来保存这些寄存器。
* 3. 在函数结尾ret指令前插入 `ld` 指令来恢复这些寄存器。
* 4. 正确计算因保存这些寄存器而需要的额外栈空间并更新StackFrameInfo。
*/
class CalleeSavedHandler : public Pass {
public:
static char ID;
CalleeSavedHandler() : Pass("callee-saved-handler", Granularity::Function, PassKind::Optimization) {}
void *getPassID() const override { return &ID; }
bool runOnFunction(Function *F, AnalysisManager& AM) override;
void runOnMachineFunction(MachineFunction* mfunc);
};
} // namespace sysy
#endif // CALLEE_SAVED_HANDLER_H

View File

@@ -0,0 +1,30 @@
#ifndef POST_RA_SCHEDULER_H
#define POST_RA_SCHEDULER_H
#include "RISCv64LLIR.h"
#include "Pass.h"
namespace sysy {
/**
* @class PostRA_Scheduler
* @brief 寄存器分配后的局部指令调度器
* * 主要目标是优化寄存器分配器插入的spill/fill代码(lw/sw)
* 尝试将加载指令提前,以隐藏其访存延迟。
*/
class PostRA_Scheduler : public Pass {
public:
static char ID;
PostRA_Scheduler() : Pass("post-ra-scheduler", Granularity::Function, PassKind::Optimization) {}
void *getPassID() const override { return &ID; }
bool runOnFunction(Function *F, AnalysisManager& AM) override;
void runOnMachineFunction(MachineFunction* mfunc);
};
} // namespace sysy
#endif // POST_RA_SCHEDULER_H

View File

@@ -0,0 +1,30 @@
#ifndef PRE_RA_SCHEDULER_H
#define PRE_RA_SCHEDULER_H
#include "RISCv64LLIR.h"
#include "Pass.h"
namespace sysy {
/**
* @class PreRA_Scheduler
* @brief 寄存器分配前的指令调度器
* * 在虚拟寄存器上进行操作,此时调度自由度最大,
* 主要目标是隐藏指令延迟,提高流水线效率。
*/
class PreRA_Scheduler : public Pass {
public:
static char ID;
PreRA_Scheduler() : Pass("pre-ra-scheduler", Granularity::Function, PassKind::Optimization) {}
void *getPassID() const override { return &ID; }
bool runOnFunction(Function *F, AnalysisManager& AM) override;
void runOnMachineFunction(MachineFunction* mfunc);
};
} // namespace sysy
#endif // PRE_RA_SCHEDULER_H

View File

@@ -17,8 +17,6 @@ public:
// 公开接口以便后续模块如RegAlloc可以查询或创建vreg
unsigned getVReg(Value* val);
unsigned getNewVReg() { return vreg_counter++; }
// 获取 vreg_map 的公共接口
const std::map<Value*, unsigned>& getVRegMap() const { return vreg_map; }
private:
// DAG节点定义作为ISel的内部实现细节

View File

@@ -35,12 +35,7 @@ enum class PhysicalReg {
// (保持您原有的 F0-F31 命名)
F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11,
F12, F13, F14, F15, F16, F17, F18, F19, F20, F21,
F22, F23, F24, F25, F26, F27, F28, F29, F30, F31,
// 用于内部表示物理寄存器在干扰图中的节点ID一个简单的特殊ID确保不与vreg_counter冲突
// 假设 vreg_counter 不会达到这么大的值
PHYS_REG_START_ID = 10000,
PHYS_REG_END_ID = PHYS_REG_START_ID + 32, // 预留足够的空间
F22, F23, F24, F25, F26, F27, F28, F29, F30, F31
};
// RISC-V 指令操作码枚举
@@ -72,9 +67,6 @@ enum class RVOpcodes {
FRAME_ADDR, // 获取栈帧变量的地址
};
// 定义一个全局辅助函数或常量,提供调用者保存寄存器列表
const std::vector<PhysicalReg>& getCallerSavedIntRegs();
class MachineOperand;
class RegOperand;
class ImmOperand;
@@ -195,7 +187,6 @@ struct StackFrameInfo {
int locals_size = 0; // 仅为AllocaInst分配的大小
int spill_size = 0; // 仅为溢出分配的大小
int total_size = 0; // 总大小
int callee_saved_size = 0; // 保存寄存器的大小
std::map<unsigned, int> alloca_offsets; // <AllocaInst的vreg, 栈偏移>
std::map<unsigned, int> spill_offsets; // <溢出vreg, 栈偏移>
std::set<PhysicalReg> used_callee_saved_regs; // 使用的保存寄存器
@@ -224,15 +215,6 @@ private:
StackFrameInfo frame_info;
};
inline const std::vector<PhysicalReg>& getCallerSavedIntRegs() {
static const std::vector<PhysicalReg> 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
};
return regs;
}
} // namespace sysy
#endif // RISCV64_LLIR_H

View File

@@ -2,74 +2,14 @@
#define RISCV64_PASSES_H
#include "RISCv64LLIR.h"
#include "RISCv64Peephole.h"
#include "PreRA_Scheduler.h"
#include "PostRA_Scheduler.h"
#include "CalleeSavedHandler.h"
#include "Pass.h"
namespace sysy {
/**
* @class BackendPass
* @brief 所有优化Pass的抽象基类 (可选,但推荐)
* * 定义一个通用的接口,所有优化都应该实现它。
*/
class BackendPass {
public:
virtual ~BackendPass() = default;
virtual void runOnMachineFunction(MachineFunction* mfunc) = 0;
};
// --- 寄存器分配前优化 ---
/**
* @class PreRA_Scheduler
* @brief 寄存器分配前的指令调度器
* * 在虚拟寄存器上进行操作,此时调度自由度最大,
* 主要目标是隐藏指令延迟,提高流水线效率。
*/
class PreRA_Scheduler : public BackendPass {
public:
void runOnMachineFunction(MachineFunction* mfunc) override;
};
/**
* @class CalleeSavedHandler
* @brief 处理被调用者保存寄存器(Callee-Saved Registers)的Pass。
* * 这个Pass在寄存器分配之后运行。它的主要职责是
* 1. 扫描整个函数,找出所有被使用的 `s` 系列寄存器。
* 2. 在函数序言中插入 `sd` 指令来保存这些寄存器。
* 3. 在函数结尾ret指令前插入 `ld` 指令来恢复这些寄存器。
* 4. 正确计算因保存这些寄存器而需要的额外栈空间并更新StackFrameInfo。
*/
class CalleeSavedHandler : public BackendPass {
public:
void runOnMachineFunction(MachineFunction* mfunc) override;
};
// --- 寄存器分配后优化 ---
/**
* @class PeepholeOptimizer
* @brief 窥孔优化器
* * 在已分配物理寄存器的指令流上,通过一个小的滑动窗口来查找
* 并替换掉一些冗余或低效的指令模式。
*/
class PeepholeOptimizer : public BackendPass {
public:
void runOnMachineFunction(MachineFunction* mfunc) override;
};
/**
* @class PostRA_Scheduler
* @brief 寄存器分配后的局部指令调度器
* * 主要目标是优化寄存器分配器插入的spill/fill代码(lw/sw)
* 尝试将加载指令提前,以隐藏其访存延迟。
*/
class PostRA_Scheduler : public BackendPass {
public:
void runOnMachineFunction(MachineFunction* mfunc) override;
};
} // namespace sysy
#endif // RISCV64_PASSES_H

View File

@@ -0,0 +1,30 @@
#ifndef RISCV64_PEEPHOLE_H
#define RISCV64_PEEPHOLE_H
#include "RISCv64LLIR.h"
#include "Pass.h"
namespace sysy {
/**
* @class PeepholeOptimizer
* @brief 窥孔优化器
* * 在已分配物理寄存器的指令流上,通过一个小的滑动窗口来查找
* 并替换掉一些冗余或低效的指令模式。
*/
class PeepholeOptimizer : public Pass {
public:
static char ID;
PeepholeOptimizer() : Pass("peephole-optimizer", Granularity::Function, PassKind::Optimization) {}
void *getPassID() const override { return &ID; }
bool runOnFunction(Function *F, AnalysisManager& AM) override;
void runOnMachineFunction(MachineFunction* mfunc);
};
} // namespace sysy
#endif // RISCV64_PEEPHOLE_H

View File

@@ -2,7 +2,6 @@
#define RISCV64_REGALLOC_H
#include "RISCv64LLIR.h"
#include "RISCv64ISel.h" // 包含 RISCv64ISel.h 以访问 ISel 和 Value 类型
namespace sysy {
@@ -57,7 +56,6 @@ private:
// 存储vreg到IR Value*的反向映射
// 这个map将在run()函数开始时被填充并在rewriteFunction()中使用。
std::map<unsigned, Value*> vreg_to_value_map;
std::map<PhysicalReg, unsigned> preg_to_vreg_id_map; // 物理寄存器到特殊vreg ID的映射
// 用于计算类型大小的辅助函数
unsigned getTypeSizeInBytes(Type* type);