[PreRA_Scheduler]添加寄存器分配前的指令调度优化

This commit is contained in:
2025-07-29 17:00:27 +08:00
parent e4fd16e36a
commit 6ba05e0d8c

View File

@@ -1,36 +1,410 @@
#include "PreRA_Scheduler.h"
#include "RISCv64LLIR.h"
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#define MAX_SCHEDULING_BLOCK_SIZE 1000 // 严格限制调度块大小
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;
// 检查指令是否是加载指令 (LW, LD)
static 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)
static bool isStoreInstr(MachineInstr *instr) {
RVOpcodes opcode = instr->getOpcode();
return opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
opcode == RVOpcodes::SH || opcode == RVOpcodes::SB;
}
// 检查指令是否为分支指令
static bool isBranchInstr(MachineInstr *instr) {
RVOpcodes opcode = instr->getOpcode();
return opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU;
}
// 检查指令是否为跳转指令
static bool isJumpInstr(MachineInstr *instr) {
RVOpcodes opcode = instr->getOpcode();
return opcode == RVOpcodes::J;
}
// 检查指令是否为返回指令
static bool isReturnInstr(MachineInstr *instr) {
return instr->getOpcode() == RVOpcodes::RET;
}
// 检查指令是否为调用指令
static bool isCallInstr(MachineInstr *instr) {
return instr->getOpcode() == RVOpcodes::CALL;
}
// 检查指令是否为块终结指令(必须保持在块尾)
static bool isTerminatorInstr(MachineInstr *instr) {
return isBranchInstr(instr) || isJumpInstr(instr) || isReturnInstr(instr);
}
// 检查指令是否有副作用(需要谨慎处理)
static bool hasSideEffect(MachineInstr *instr) {
return isStoreInstr(instr) || isCallInstr(instr) || isTerminatorInstr(instr);
}
// 检查指令是否涉及内存操作
static bool hasMemoryAccess(MachineInstr *instr) {
return isLoadInstr(instr) || isStoreInstr(instr);
}
// 获取指令定义的虚拟寄存器
static std::set<unsigned> getDefinedVirtualRegisters(MachineInstr *instr) {
std::set<unsigned> defined_regs;
RVOpcodes opcode = instr->getOpcode();
// CALL指令可能定义返回值寄存器
if (opcode == RVOpcodes::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->getVRegNum());
}
}
return defined_regs;
}
// 存储指令和终结指令不定义寄存器
if (isStoreInstr(instr) || isTerminatorInstr(instr)) {
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->getVRegNum());
}
}
return defined_regs;
}
// 获取指令使用的虚拟寄存器
static std::set<unsigned> getUsedVirtualRegisters(MachineInstr *instr) {
std::set<unsigned> 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->getVRegNum());
}
}
}
return used_regs;
}
// 存储指令和终结指令:所有操作数都是使用的
if (isStoreInstr(instr) || isTerminatorInstr(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->getVRegNum());
}
} 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()->getVRegNum());
}
}
}
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->getVRegNum());
}
} 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()->getVRegNum());
}
}
}
return used_regs;
}
// 获取内存访问位置信息
struct MemoryLocation {
unsigned base_reg;
int64_t offset;
bool is_valid;
MemoryLocation() : base_reg(0), offset(0), is_valid(false) {}
MemoryLocation(unsigned base, int64_t off)
: base_reg(base), offset(off), is_valid(true) {}
bool operator==(const MemoryLocation &other) const {
return is_valid && other.is_valid && base_reg == other.base_reg &&
offset == other.offset;
}
};
// 获取内存访问位置
static MemoryLocation getMemoryLocation(MachineInstr *instr) {
if (!isLoadInstr(instr) && !isStoreInstr(instr)) {
return MemoryLocation();
}
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 MemoryLocation(mem_op->getBase()->getVRegNum(),
mem_op->getOffset()->getValue());
}
}
}
return MemoryLocation();
}
// 检查两个内存位置是否可能别名
static bool mayAlias(const MemoryLocation &loc1, const MemoryLocation &loc2) {
if (!loc1.is_valid || !loc2.is_valid) {
return true; // 保守处理:未知位置可能别名
}
// 不同基址寄存器,保守假设可能别名
if (loc1.base_reg != loc2.base_reg) {
return true;
}
// 相同基址寄存器,检查偏移
return loc1.offset == loc2.offset;
}
// 检查两个指令之间是否存在数据依赖
static bool hasDataDependency(MachineInstr *first, MachineInstr *second) {
auto defined_regs_first = getDefinedVirtualRegisters(first);
auto used_regs_first = getUsedVirtualRegisters(first);
auto defined_regs_second = getDefinedVirtualRegisters(second);
auto used_regs_second = getUsedVirtualRegisters(second);
// RAW依赖: second读取first写入的寄存器
for (const auto &reg : defined_regs_first) {
if (used_regs_second.count(reg)) {
return true;
}
}
// WAR依赖: second写入first读取的寄存器
for (const auto &reg : used_regs_first) {
if (defined_regs_second.count(reg)) {
return true;
}
}
// WAW依赖: 两个指令写入同一寄存器
for (const auto &reg : defined_regs_first) {
if (defined_regs_second.count(reg)) {
return true;
}
}
return false;
}
// 检查两个指令之间是否存在内存依赖
static bool hasMemoryDependency(MachineInstr *first, MachineInstr *second) {
bool first_accesses_memory = isLoadInstr(first) || isStoreInstr(first);
bool second_accesses_memory = isLoadInstr(second) || isStoreInstr(second);
if (!first_accesses_memory || !second_accesses_memory) {
return false;
}
// 如果至少有一个是存储指令,需要检查别名
if (isStoreInstr(first) || isStoreInstr(second)) {
MemoryLocation loc1 = getMemoryLocation(first);
MemoryLocation loc2 = getMemoryLocation(second);
return mayAlias(loc1, loc2);
}
return false; // 两个加载指令之间没有依赖
}
// 检查两个指令之间是否存在控制依赖
static bool hasControlDependency(MachineInstr *first, MachineInstr *second) {
// 终结指令与任何其他指令都有控制依赖
if (isTerminatorInstr(first)) {
return true; // first是终结指令second不能移动到first之前
}
if (isTerminatorInstr(second)) {
return false; // second是终结指令可以保持在后面
}
// CALL指令具有控制副作用但可以参与有限的调度
if (isCallInstr(first) || isCallInstr(second)) {
// CALL指令之间保持顺序
if (isCallInstr(first) && isCallInstr(second)) {
return true;
}
// 其他情况允许调度(通过数据依赖控制)
}
return false;
}
// 综合检查两个指令是否可以交换
static bool canSwapInstructions(MachineInstr *first, MachineInstr *second) {
// 检查所有类型的依赖
if (hasDataDependency(first, second) || hasDataDependency(second, first)) {
return false;
}
if (hasMemoryDependency(first, second)) {
return false;
}
if (hasControlDependency(first, second) ||
hasControlDependency(second, first)) {
return false;
}
return true;
}
// 找到基本块中的调度边界
static std::vector<size_t>
findSchedulingBoundaries(const std::vector<MachineInstr *> &instrs) {
std::vector<size_t> boundaries;
boundaries.push_back(0); // 起始边界
for (size_t i = 0; i < instrs.size(); i++) {
// 终结指令前后都是边界
if (isTerminatorInstr(instrs[i])) {
if (i > 0)
boundaries.push_back(i);
if (i + 1 < instrs.size())
boundaries.push_back(i + 1);
}
// 跳转目标标签也可能是边界(这里简化处理)
}
boundaries.push_back(instrs.size()); // 结束边界
// 去重并排序
std::sort(boundaries.begin(), boundaries.end());
boundaries.erase(std::unique(boundaries.begin(), boundaries.end()),
boundaries.end());
return boundaries;
}
// 在单个调度区域内进行指令调度
static void scheduleRegion(std::vector<MachineInstr *> &instrs, size_t start,
size_t end) {
if (end - start <= 1) {
return; // 区域太小,无需调度
}
// 保守的调度策略:
// 1. 只对小规模区域进行调度
// 2. 优先将加载指令向前调度,以隐藏内存延迟
// 3. 确保不破坏数据依赖和内存依赖
// 简单的调度算法:只尝试将加载指令尽可能前移
for (size_t i = start + 1; i < end; i++) {
if (isLoadInstr(instrs[i])) {
// 尝试将加载指令向前移动
for (size_t j = i; j > start; j--) {
// 检查是否可以与前一条指令交换
if (canSwapInstructions(instrs[j - 1], instrs[j])) {
std::swap(instrs[j - 1], instrs[j]);
} else {
// 一旦遇到依赖关系就停止移动
break;
}
}
}
}
}
static void scheduleBlock(MachineBasicBlock *mbb) {
auto &instructions = mbb->getInstructions();
if (instructions.size() <= 1 ||
instructions.size() > MAX_SCHEDULING_BLOCK_SIZE) {
return;
}
// 构建指令列表
std::vector<MachineInstr *> instr_list;
for (auto &instr : instructions) {
instr_list.push_back(instr.get());
}
// 找到调度边界
std::vector<size_t> boundaries = findSchedulingBoundaries(instr_list);
// 在每个调度区域内进行局部调度
for (size_t i = 0; i < boundaries.size() - 1; i++) {
size_t region_start = boundaries[i];
size_t region_end = boundaries[i + 1];
scheduleRegion(instr_list, region_start, region_end);
}
// 重建指令序列
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 PreRA_Scheduler::runOnFunction(Function *F, AnalysisManager &AM) {
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;
for (auto &mbb : mfunc->getBlocks()) {
scheduleBlock(mbb.get());
}
}
} // namespace sysy