Files
mysysy/src/PostRA_Scheduler.cpp

383 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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