Compare commits
2 Commits
peephole
...
backend-bs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
429e477776 | ||
|
|
af318b6c0e |
@@ -33,11 +33,8 @@ add_executable(sysyc
|
|||||||
RISCv64ISel.cpp
|
RISCv64ISel.cpp
|
||||||
RISCv64RegAlloc.cpp
|
RISCv64RegAlloc.cpp
|
||||||
RISCv64AsmPrinter.cpp
|
RISCv64AsmPrinter.cpp
|
||||||
# RISCv64Passes.cpp
|
RISCv64Passes.cpp
|
||||||
RISCv64Peephole.cpp
|
RISCv64LLIR.cpp
|
||||||
PreRA_Scheduler.cpp
|
|
||||||
PostRA_Scheduler.cpp
|
|
||||||
CalleeSavedHandler.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# 设置 include 路径,包含 ANTLR 运行时库和项目头文件
|
# 设置 include 路径,包含 ANTLR 运行时库和项目头文件
|
||||||
|
|||||||
@@ -1,383 +0,0 @@
|
|||||||
#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
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
#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
|
|
||||||
@@ -16,13 +16,59 @@ std::string RISCv64CodeGen::code_gen() {
|
|||||||
std::string RISCv64CodeGen::module_gen() {
|
std::string RISCv64CodeGen::module_gen() {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
// 1. 处理全局变量 (.data段)
|
// --- [新逻辑] 步骤1:将全局变量分为.data和.bss两组 ---
|
||||||
if (!module->getGlobals().empty()) {
|
std::vector<GlobalValue*> data_globals;
|
||||||
ss << ".data\n";
|
std::vector<GlobalValue*> bss_globals;
|
||||||
for (const auto& global : module->getGlobals()) {
|
|
||||||
|
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) {
|
||||||
ss << ".globl " << global->getName() << "\n";
|
ss << ".globl " << global->getName() << "\n";
|
||||||
ss << global->getName() << ":\n";
|
ss << global->getName() << ":\n";
|
||||||
const auto& init_values = global->getInitValues();
|
const auto& init_values = global->getInitValues();
|
||||||
|
// 使用您原有的逻辑来处理显式初始化的值
|
||||||
for (size_t i = 0; i < init_values.getValues().size(); ++i) {
|
for (size_t i = 0; i < init_values.getValues().size(); ++i) {
|
||||||
auto val = init_values.getValues()[i];
|
auto val = init_values.getValues()[i];
|
||||||
auto count = init_values.getNumbers()[i];
|
auto count = init_values.getNumbers()[i];
|
||||||
@@ -41,7 +87,7 @@ std::string RISCv64CodeGen::module_gen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 处理函数 (.text段)
|
// --- 处理函数 (.text段) 的逻辑保持不变 ---
|
||||||
if (!module->getFunctions().empty()) {
|
if (!module->getFunctions().empty()) {
|
||||||
ss << ".text\n";
|
ss << ".text\n";
|
||||||
for (const auto& func_pair : module->getFunctions()) {
|
for (const auto& func_pair : module->getFunctions()) {
|
||||||
|
|||||||
6
src/RISCv64LLIR.cpp
Normal file
6
src/RISCv64LLIR.cpp
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#include "RISCv64LLIR.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,14 +1,54 @@
|
|||||||
#include "CalleeSavedHandler.h"
|
#include "RISCv64Passes.h"
|
||||||
#include <set>
|
#include <iostream>
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
char CalleeSavedHandler::ID = 0;
|
// --- 寄存器分配前优化 ---
|
||||||
|
|
||||||
bool CalleeSavedHandler::runOnFunction(Function *F, AnalysisManager& AM) {
|
void PreRA_Scheduler::runOnMachineFunction(MachineFunction* mfunc) {
|
||||||
// This pass works on MachineFunction level, not IR level
|
// TODO: 在此实现寄存器分配前的指令调度。
|
||||||
return false;
|
// 遍历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) {
|
void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
|
||||||
@@ -1,652 +0,0 @@
|
|||||||
#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
|
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
#include "RISCv64ISel.h"
|
#include "RISCv64ISel.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <iostream> // For DEBUG output
|
||||||
|
#include <cassert> // For assert
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
@@ -15,15 +17,28 @@ RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) : MFunc(mfunc) {
|
|||||||
PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
|
PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
|
||||||
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
|
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() {
|
void RISCv64RegAlloc::run() {
|
||||||
handleCallingConvention();
|
// 阶段 1: 处理函数调用约定(参数寄存器预着色)
|
||||||
eliminateFrameIndices();
|
handleCallingConvention();
|
||||||
analyzeLiveness();
|
// 阶段 2: 消除帧索引(为局部变量和栈参数分配栈偏移)
|
||||||
buildInterferenceGraph();
|
eliminateFrameIndices();
|
||||||
colorGraph();
|
// 阶段 3: 活跃性分析
|
||||||
rewriteFunction();
|
analyzeLiveness();
|
||||||
|
// 阶段 4: 构建干扰图(包含CALL指令对调用者保存寄存器的影响)
|
||||||
|
buildInterferenceGraph();
|
||||||
|
// 阶段 5: 图着色算法分配物理寄存器
|
||||||
|
colorGraph();
|
||||||
|
// 阶段 6: 重写函数(插入溢出/填充代码,替换虚拟寄存器为物理寄存器)
|
||||||
|
rewriteFunction();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -43,7 +58,10 @@ void RISCv64RegAlloc::handleCallingConvention() {
|
|||||||
if (arg_idx >= 8) {
|
if (arg_idx >= 8) {
|
||||||
break;
|
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 对象对应的虚拟寄存器
|
// 1. 获取该 Argument 对象对应的虚拟寄存器
|
||||||
unsigned vreg = isel->getVReg(arg);
|
unsigned vreg = isel->getVReg(arg);
|
||||||
|
|
||||||
@@ -58,6 +76,9 @@ void RISCv64RegAlloc::handleCallingConvention() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 消除帧索引,为局部变量和栈参数分配栈偏移量,并展开伪指令。
|
||||||
|
*/
|
||||||
void RISCv64RegAlloc::eliminateFrameIndices() {
|
void RISCv64RegAlloc::eliminateFrameIndices() {
|
||||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||||
// 初始偏移量,为保存ra和s0留出空间。
|
// 初始偏移量,为保存ra和s0留出空间。
|
||||||
@@ -185,30 +206,38 @@ 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) {
|
void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def) {
|
||||||
bool is_def = true;
|
bool first_reg_is_def = true; // 默认情况下,指令的第一个寄存器操作数是定义 (def)
|
||||||
auto opcode = instr->getOpcode();
|
auto opcode = instr->getOpcode();
|
||||||
|
|
||||||
// --- MODIFICATION START: 细化对指令的 use/def 定义 ---
|
// 1. 特殊指令的 `is_def` 标志调整
|
||||||
|
// 这些指令的第一个寄存器操作数是源操作数 (use),而不是目标操作数 (def)。
|
||||||
// 对于没有定义目标寄存器的指令,预先设置 is_def = false
|
|
||||||
if (opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
|
if (opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
|
||||||
opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
|
opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
|
||||||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
|
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
|
||||||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
|
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
|
||||||
opcode == RVOpcodes::RET || opcode == RVOpcodes::J) {
|
opcode == RVOpcodes::RET || opcode == RVOpcodes::J) {
|
||||||
is_def = false;
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// 对 CALL 指令进行特殊处理
|
// 2. CALL 指令的特殊处理
|
||||||
if (opcode == RVOpcodes::CALL) {
|
if (opcode == RVOpcodes::CALL) {
|
||||||
// CALL 指令的第一个操作数通常是目标函数标签,不是寄存器。
|
// 1.1 处理返回值 (def)
|
||||||
// 它可能会有一个可选的返回值(def),以及一系列参数(use)。
|
// 约定:如果CALL指令有返回值,IR阶段会将返回值vreg作为指令的第一个操作数。
|
||||||
// 这里的处理假定 CALL 的机器指令操作数布局是:
|
|
||||||
// [可选: dest_vreg (def)], [函数标签], [可选: arg1_vreg (use)], [可选: arg2_vreg (use)], ...
|
|
||||||
|
|
||||||
// 我们需要一种方法来识别哪些操作数是def,哪些是use。
|
|
||||||
// 一个简单的约定:如果第一个操作数是寄存器,则它是def(返回值)。
|
|
||||||
if (!instr->getOperands().empty() && instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
|
if (!instr->getOperands().empty() && instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
|
||||||
auto reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
|
auto reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
|
||||||
if (reg_op->isVirtual()) {
|
if (reg_op->isVirtual()) {
|
||||||
@@ -216,14 +245,19 @@ void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 遍历所有操作数,非第一个寄存器操作数均视为use
|
// 1.2 处理参数 (use)
|
||||||
bool first_reg_skipped = false;
|
// 参数通常是指令的后续操作数
|
||||||
|
bool first_operand_processed = false; // 用于跳过已作为def处理的返回值
|
||||||
for (const auto& op : instr->getOperands()) {
|
for (const auto& op : instr->getOperands()) {
|
||||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||||
if (!first_reg_skipped) {
|
if (!first_operand_processed) { // 如果是第一个操作数
|
||||||
first_reg_skipped = true;
|
first_operand_processed = true;
|
||||||
continue; // 跳过我们已经作为def处理的返回值
|
// 如果第一个操作数是返回值(已被加入def),则跳过
|
||||||
|
if (def.count(static_cast<RegOperand*>(op.get())->getVRegNum())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// 否则,该寄存器是 use
|
||||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||||
if (reg_op->isVirtual()) {
|
if (reg_op->isVirtual()) {
|
||||||
use.insert(reg_op->getVRegNum());
|
use.insert(reg_op->getVRegNum());
|
||||||
@@ -231,34 +265,43 @@ void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// **重要**: CALL指令还隐式定义(杀死)了所有调用者保存的寄存器。
|
// **重要**: CALL指令隐式定义(杀死)了所有调用者保存的寄存器。
|
||||||
// 一个完整的实现会在这里将所有caller-saved寄存器标记为def,
|
// **这部分逻辑不在getInstrUseDef中直接处理**。
|
||||||
// 以确保任何跨调用存活的变量都不会被分配到这些寄存器中。
|
// 而是通过`buildInterferenceGraph`中添加物理寄存器节点与活跃虚拟寄存器之间的干扰边来完成。
|
||||||
// 这个简化的实现暂不处理隐式def,但这是未来优化的关键点。
|
// 这样 Liveness Analysis 可以在虚拟寄存器层面进行,而物理寄存器干扰的复杂性则留给干扰图。
|
||||||
|
|
||||||
return; // CALL 指令处理完毕,直接返回
|
return; // CALL 指令处理完毕,直接返回
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- MODIFICATION END ---
|
// 3. 对其他所有指令的通用处理逻辑
|
||||||
|
|
||||||
// 对其他所有指令的通用处理逻辑
|
|
||||||
for (const auto& op : instr->getOperands()) {
|
for (const auto& op : instr->getOperands()) {
|
||||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||||
if (reg_op->isVirtual()) {
|
if (reg_op->isVirtual()) { // 只有虚拟寄存器才需要处理 Use/Def
|
||||||
if (is_def) {
|
// 如果是第一个寄存器操作数,且指令类型表明它是定义 (def),则加入 def 集合
|
||||||
|
// 否则,它是 use (读取)
|
||||||
|
if (first_reg_is_def) {
|
||||||
def.insert(reg_op->getVRegNum());
|
def.insert(reg_op->getVRegNum());
|
||||||
is_def = false; // 一条指令通常只有一个目标寄存ator
|
first_reg_is_def = false; // 确保每条指令只定义一个目标寄存器
|
||||||
} else {
|
} else {
|
||||||
use.insert(reg_op->getVRegNum());
|
use.insert(reg_op->getVRegNum());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||||
// 内存操作数 `offset(base)` 中的 base 寄存器是 use
|
// 内存操作数 `offset(base)` 中的 `base` 寄存器是 `use`
|
||||||
auto mem_op = static_cast<MemOperand*>(op.get());
|
auto mem_op = static_cast<MemOperand*>(op.get());
|
||||||
if (mem_op->getBase()->isVirtual()) {
|
if (mem_op->getBase()->isVirtual()) {
|
||||||
use.insert(mem_op->getBase()->getVRegNum());
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -344,6 +387,7 @@ void RISCv64RegAlloc::analyzeLiveness() {
|
|||||||
|
|
||||||
void RISCv64RegAlloc::buildInterferenceGraph() {
|
void RISCv64RegAlloc::buildInterferenceGraph() {
|
||||||
std::set<unsigned> all_vregs;
|
std::set<unsigned> all_vregs;
|
||||||
|
// 收集所有虚拟寄存器和物理寄存器在干扰图中的节点ID
|
||||||
for (auto& mbb : MFunc->getBlocks()) {
|
for (auto& mbb : MFunc->getBlocks()) {
|
||||||
for(auto& instr : mbb->getInstructions()) {
|
for(auto& instr : mbb->getInstructions()) {
|
||||||
LiveSet use, def;
|
LiveSet use, def;
|
||||||
@@ -352,6 +396,11 @@ void RISCv64RegAlloc::buildInterferenceGraph() {
|
|||||||
for(auto d : def) all_vregs.insert(d);
|
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] = {}; }
|
for (auto vreg : all_vregs) { interference_graph[vreg] = {}; }
|
||||||
|
|
||||||
@@ -361,6 +410,7 @@ void RISCv64RegAlloc::buildInterferenceGraph() {
|
|||||||
getInstrUseDef(instr.get(), use, def);
|
getInstrUseDef(instr.get(), use, def);
|
||||||
const LiveSet& live_out = live_out_map.at(instr.get());
|
const LiveSet& live_out = live_out_map.at(instr.get());
|
||||||
|
|
||||||
|
// 标准干扰图构建:def 与 live_out 中的其他变量干扰
|
||||||
for (unsigned d : def) {
|
for (unsigned d : def) {
|
||||||
for (unsigned l : live_out) {
|
for (unsigned l : live_out) {
|
||||||
if (d != l) {
|
if (d != l) {
|
||||||
@@ -369,6 +419,24 @@ 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
#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
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
#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
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
#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
|
|
||||||
@@ -17,6 +17,8 @@ public:
|
|||||||
// 公开接口,以便后续模块(如RegAlloc)可以查询或创建vreg
|
// 公开接口,以便后续模块(如RegAlloc)可以查询或创建vreg
|
||||||
unsigned getVReg(Value* val);
|
unsigned getVReg(Value* val);
|
||||||
unsigned getNewVReg() { return vreg_counter++; }
|
unsigned getNewVReg() { return vreg_counter++; }
|
||||||
|
// 获取 vreg_map 的公共接口
|
||||||
|
const std::map<Value*, unsigned>& getVRegMap() const { return vreg_map; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// DAG节点定义,作为ISel的内部实现细节
|
// DAG节点定义,作为ISel的内部实现细节
|
||||||
|
|||||||
@@ -35,7 +35,12 @@ enum class PhysicalReg {
|
|||||||
// (保持您原有的 F0-F31 命名)
|
// (保持您原有的 F0-F31 命名)
|
||||||
F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11,
|
F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11,
|
||||||
F12, F13, F14, F15, F16, F17, F18, F19, F20, F21,
|
F12, F13, F14, F15, F16, F17, F18, F19, F20, F21,
|
||||||
F22, F23, F24, F25, F26, F27, F28, F29, F30, F31
|
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, // 预留足够的空间
|
||||||
};
|
};
|
||||||
|
|
||||||
// RISC-V 指令操作码枚举
|
// RISC-V 指令操作码枚举
|
||||||
@@ -67,6 +72,9 @@ enum class RVOpcodes {
|
|||||||
FRAME_ADDR, // 获取栈帧变量的地址
|
FRAME_ADDR, // 获取栈帧变量的地址
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 定义一个全局辅助函数或常量,提供调用者保存寄存器列表
|
||||||
|
const std::vector<PhysicalReg>& getCallerSavedIntRegs();
|
||||||
|
|
||||||
class MachineOperand;
|
class MachineOperand;
|
||||||
class RegOperand;
|
class RegOperand;
|
||||||
class ImmOperand;
|
class ImmOperand;
|
||||||
@@ -215,6 +223,15 @@ private:
|
|||||||
StackFrameInfo frame_info;
|
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
|
} // namespace sysy
|
||||||
|
|
||||||
#endif // RISCV64_LLIR_H
|
#endif // RISCV64_LLIR_H
|
||||||
@@ -2,14 +2,74 @@
|
|||||||
#define RISCV64_PASSES_H
|
#define RISCV64_PASSES_H
|
||||||
|
|
||||||
#include "RISCv64LLIR.h"
|
#include "RISCv64LLIR.h"
|
||||||
#include "RISCv64Peephole.h"
|
|
||||||
#include "PreRA_Scheduler.h"
|
|
||||||
#include "PostRA_Scheduler.h"
|
|
||||||
#include "CalleeSavedHandler.h"
|
|
||||||
#include "Pass.h"
|
|
||||||
|
|
||||||
namespace sysy {
|
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
|
} // namespace sysy
|
||||||
|
|
||||||
#endif // RISCV64_PASSES_H
|
#endif // RISCV64_PASSES_H
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
#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
|
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
#define RISCV64_REGALLOC_H
|
#define RISCV64_REGALLOC_H
|
||||||
|
|
||||||
#include "RISCv64LLIR.h"
|
#include "RISCv64LLIR.h"
|
||||||
|
#include "RISCv64ISel.h" // 包含 RISCv64ISel.h 以访问 ISel 和 Value 类型
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
@@ -56,6 +57,7 @@ private:
|
|||||||
// 存储vreg到IR Value*的反向映射
|
// 存储vreg到IR Value*的反向映射
|
||||||
// 这个map将在run()函数开始时被填充,并在rewriteFunction()中使用。
|
// 这个map将在run()函数开始时被填充,并在rewriteFunction()中使用。
|
||||||
std::map<unsigned, Value*> vreg_to_value_map;
|
std::map<unsigned, Value*> vreg_to_value_map;
|
||||||
|
std::map<PhysicalReg, unsigned> preg_to_vreg_id_map; // 物理寄存器到特殊vreg ID的映射
|
||||||
|
|
||||||
// 用于计算类型大小的辅助函数
|
// 用于计算类型大小的辅助函数
|
||||||
unsigned getTypeSizeInBytes(Type* type);
|
unsigned getTypeSizeInBytes(Type* type);
|
||||||
|
|||||||
Reference in New Issue
Block a user