[Optimize]对PreRA指令调度进行优化

This commit is contained in:
2025-07-30 15:27:23 +08:00
parent 860ebcd447
commit a3c4d5a2b8

View File

@ -1,8 +1,8 @@
#include "PreRA_Scheduler.h"
#include "RISCv64LLIR.h"
#include <algorithm>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#define MAX_SCHEDULING_BLOCK_SIZE 1000 // 严格限制调度块大小
@ -66,9 +66,44 @@ static bool hasMemoryAccess(MachineInstr *instr) {
return isLoadInstr(instr) || isStoreInstr(instr);
}
// 获取指令定义的虚拟寄存器
static std::set<unsigned> getDefinedVirtualRegisters(MachineInstr *instr) {
std::set<unsigned> defined_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;
}
};
// 缓存指令分析信息
struct InstrInfo {
std::unordered_set<unsigned> defined_regs;
std::unordered_set<unsigned> used_regs;
MemoryLocation mem_location;
bool is_load;
bool is_store;
bool is_terminator;
bool is_call;
bool has_side_effect;
bool has_memory_access;
InstrInfo() : is_load(false), is_store(false), is_terminator(false),
is_call(false), has_side_effect(false), has_memory_access(false) {}
};
// 指令信息缓存
static std::unordered_map<MachineInstr*, InstrInfo> instr_info_cache;
// 获取指令定义的虚拟寄存器 - 优化版本
static std::unordered_set<unsigned> getDefinedVirtualRegisters(MachineInstr *instr) {
std::unordered_set<unsigned> defined_regs;
RVOpcodes opcode = instr->getOpcode();
// CALL指令可能定义返回值寄存器
@ -101,9 +136,9 @@ static std::set<unsigned> getDefinedVirtualRegisters(MachineInstr *instr) {
return defined_regs;
}
// 获取指令使用的虚拟寄存器
static std::set<unsigned> getUsedVirtualRegisters(MachineInstr *instr) {
std::set<unsigned> used_regs;
// 获取指令使用的虚拟寄存器 - 优化版本
static std::unordered_set<unsigned> getUsedVirtualRegisters(MachineInstr *instr) {
std::unordered_set<unsigned> used_regs;
RVOpcodes opcode = instr->getOpcode();
// CALL指令跳过第一个操作数返回值其余为参数
@ -164,22 +199,6 @@ static std::set<unsigned> getUsedVirtualRegisters(MachineInstr *instr) {
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)) {
@ -199,6 +218,27 @@ static MemoryLocation getMemoryLocation(MachineInstr *instr) {
return MemoryLocation();
}
// 预计算并缓存指令信息
static const InstrInfo& getInstrInfo(MachineInstr *instr) {
auto it = instr_info_cache.find(instr);
if (it != instr_info_cache.end()) {
return it->second;
}
InstrInfo& info = instr_info_cache[instr];
info.defined_regs = getDefinedVirtualRegisters(instr);
info.used_regs = getUsedVirtualRegisters(instr);
info.mem_location = getMemoryLocation(instr);
info.is_load = isLoadInstr(instr);
info.is_store = isStoreInstr(instr);
info.is_terminator = isTerminatorInstr(instr);
info.is_call = isCallInstr(instr);
info.has_side_effect = hasSideEffect(instr);
info.has_memory_access = hasMemoryAccess(instr);
return info;
}
// 检查两个内存位置是否可能别名
static bool mayAlias(const MemoryLocation &loc1, const MemoryLocation &loc2) {
if (!loc1.is_valid || !loc2.is_valid) {
@ -214,30 +254,28 @@ static bool mayAlias(const MemoryLocation &loc1, const MemoryLocation &loc2) {
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);
const InstrInfo& info_first = getInstrInfo(first);
const InstrInfo& info_second = getInstrInfo(second);
// RAW依赖: second读取first写入的寄存器
for (const auto &reg : defined_regs_first) {
if (used_regs_second.count(reg)) {
for (const auto &reg : info_first.defined_regs) {
if (info_second.used_regs.find(reg) != info_second.used_regs.end()) {
return true;
}
}
// WAR依赖: second写入first读取的寄存器
for (const auto &reg : used_regs_first) {
if (defined_regs_second.count(reg)) {
for (const auto &reg : info_first.used_regs) {
if (info_second.defined_regs.find(reg) != info_second.defined_regs.end()) {
return true;
}
}
// WAW依赖: 两个指令写入同一寄存器
for (const auto &reg : defined_regs_first) {
if (defined_regs_second.count(reg)) {
for (const auto &reg : info_first.defined_regs) {
if (info_second.defined_regs.find(reg) != info_second.defined_regs.end()) {
return true;
}
}
@ -245,40 +283,41 @@ static bool hasDataDependency(MachineInstr *first, MachineInstr *second) {
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);
const InstrInfo& info_first = getInstrInfo(first);
const InstrInfo& info_second = getInstrInfo(second);
if (!first_accesses_memory || !second_accesses_memory) {
if (!info_first.has_memory_access || !info_second.has_memory_access) {
return false;
}
// 如果至少有一个是存储指令,需要检查别名
if (isStoreInstr(first) || isStoreInstr(second)) {
MemoryLocation loc1 = getMemoryLocation(first);
MemoryLocation loc2 = getMemoryLocation(second);
return mayAlias(loc1, loc2);
if (info_first.is_store || info_second.is_store) {
return mayAlias(info_first.mem_location, info_second.mem_location);
}
return false; // 两个加载指令之间没有依赖
}
// 检查两个指令之间是否存在控制依赖
// 检查两个指令之间是否存在控制依赖 - 优化版本
static bool hasControlDependency(MachineInstr *first, MachineInstr *second) {
const InstrInfo& info_first = getInstrInfo(first);
const InstrInfo& info_second = getInstrInfo(second);
// 终结指令与任何其他指令都有控制依赖
if (isTerminatorInstr(first)) {
if (info_first.is_terminator) {
return true; // first是终结指令second不能移动到first之前
}
if (isTerminatorInstr(second)) {
if (info_second.is_terminator) {
return false; // second是终结指令可以保持在后面
}
// CALL指令具有控制副作用但可以参与有限的调度
if (isCallInstr(first) || isCallInstr(second)) {
if (info_first.is_call || info_second.is_call) {
// CALL指令之间保持顺序
if (isCallInstr(first) && isCallInstr(second)) {
if (info_first.is_call && info_second.is_call) {
return true;
}
// 其他情况允许调度(通过数据依赖控制)
@ -287,7 +326,7 @@ static bool hasControlDependency(MachineInstr *first, MachineInstr *second) {
return false;
}
// 综合检查两个指令是否可以交换
// 综合检查两个指令是否可以交换 - 优化版本
static bool canSwapInstructions(MachineInstr *first, MachineInstr *second) {
// 检查所有类型的依赖
if (hasDataDependency(first, second) || hasDataDependency(second, first)) {
@ -306,15 +345,17 @@ static bool canSwapInstructions(MachineInstr *first, MachineInstr *second) {
return true;
}
// 找到基本块中的调度边界
// 找到基本块中的调度边界 - 优化版本
static std::vector<size_t>
findSchedulingBoundaries(const std::vector<MachineInstr *> &instrs) {
std::vector<size_t> boundaries;
boundaries.reserve(instrs.size() / 10); // 预估边界数量
boundaries.push_back(0); // 起始边界
for (size_t i = 0; i < instrs.size(); i++) {
const InstrInfo& info = getInstrInfo(instrs[i]);
// 终结指令前后都是边界
if (isTerminatorInstr(instrs[i])) {
if (info.is_terminator) {
if (i > 0)
boundaries.push_back(i);
if (i + 1 < instrs.size())
@ -333,7 +374,7 @@ findSchedulingBoundaries(const std::vector<MachineInstr *> &instrs) {
return boundaries;
}
// 在单个调度区域内进行指令调度
// 在单个调度区域内进行指令调度 - 优化版本
static void scheduleRegion(std::vector<MachineInstr *> &instrs, size_t start,
size_t end) {
if (end - start <= 1) {
@ -347,7 +388,8 @@ static void scheduleRegion(std::vector<MachineInstr *> &instrs, size_t start,
// 简单的调度算法:只尝试将加载指令尽可能前移
for (size_t i = start + 1; i < end; i++) {
if (isLoadInstr(instrs[i])) {
const InstrInfo& info = getInstrInfo(instrs[i]);
if (info.is_load) {
// 尝试将加载指令向前移动
for (size_t j = i; j > start; j--) {
// 检查是否可以与前一条指令交换
@ -369,12 +411,21 @@ static void scheduleBlock(MachineBasicBlock *mbb) {
return;
}
// 清理缓存,避免无效指针
instr_info_cache.clear();
// 构建指令列表
std::vector<MachineInstr *> instr_list;
instr_list.reserve(instructions.size()); // 预分配容量
for (auto &instr : instructions) {
instr_list.push_back(instr.get());
}
// 预计算所有指令信息
for (auto* instr : instr_list) {
getInstrInfo(instr);
}
// 找到调度边界
std::vector<size_t> boundaries = findSchedulingBoundaries(instr_list);
@ -386,12 +437,14 @@ static void scheduleBlock(MachineBasicBlock *mbb) {
}
// 重建指令序列
std::map<MachineInstr *, std::unique_ptr<MachineInstr>> instr_map;
std::unordered_map<MachineInstr *, std::unique_ptr<MachineInstr>> instr_map;
instr_map.reserve(instructions.size()); // 预分配容量
for (auto &instr : instructions) {
instr_map[instr.get()] = std::move(instr);
}
instructions.clear();
instructions.reserve(instr_list.size()); // 预分配容量
for (auto *instr : instr_list) {
instructions.push_back(std::move(instr_map[instr]));
}
@ -405,6 +458,9 @@ void PreRA_Scheduler::runOnMachineFunction(MachineFunction *mfunc) {
for (auto &mbb : mfunc->getBlocks()) {
scheduleBlock(mbb.get());
}
// 清理全局缓存
instr_info_cache.clear();
}
} // namespace sysy