[peephole]Pass架构重构优化
This commit is contained in:
@@ -33,7 +33,11 @@ add_executable(sysyc
|
|||||||
RISCv64ISel.cpp
|
RISCv64ISel.cpp
|
||||||
RISCv64RegAlloc.cpp
|
RISCv64RegAlloc.cpp
|
||||||
RISCv64AsmPrinter.cpp
|
RISCv64AsmPrinter.cpp
|
||||||
RISCv64Passes.cpp
|
# RISCv64Passes.cpp
|
||||||
|
RISCv64Peephole.cpp
|
||||||
|
PreRA_Scheduler.cpp
|
||||||
|
PostRA_Scheduler.cpp
|
||||||
|
CalleeSavedHandler.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# 设置 include 路径,包含 ANTLR 运行时库和项目头文件
|
# 设置 include 路径,包含 ANTLR 运行时库和项目头文件
|
||||||
|
|||||||
109
src/CalleeSavedHandler.cpp
Normal file
109
src/CalleeSavedHandler.cpp
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
#include "CalleeSavedHandler.h"
|
||||||
|
#include <set>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
char CalleeSavedHandler::ID = 0;
|
||||||
|
|
||||||
|
bool CalleeSavedHandler::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||||
|
// This pass works on MachineFunction level, not IR level
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
|
||||||
|
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
||||||
|
std::set<PhysicalReg> used_callee_saved;
|
||||||
|
|
||||||
|
// 1. 扫描所有指令,找出被使用的s寄存器
|
||||||
|
for (auto& mbb : mfunc->getBlocks()) {
|
||||||
|
for (auto& instr : mbb->getInstructions()) {
|
||||||
|
for (auto& op : instr->getOperands()) {
|
||||||
|
|
||||||
|
// 辅助Lambda,用于检查和插入寄存器
|
||||||
|
auto check_and_insert_reg = [&](RegOperand* reg_op) {
|
||||||
|
if (!reg_op->isVirtual()) {
|
||||||
|
PhysicalReg preg = reg_op->getPReg();
|
||||||
|
// --- 关键检查点 ---
|
||||||
|
// 必须严格判断是否在 s0-s11 的范围内。
|
||||||
|
// a0, t0 等寄存器绝对不应被视为被调用者保存寄存器。
|
||||||
|
if (preg >= PhysicalReg::S0 && preg <= PhysicalReg::S11) {
|
||||||
|
used_callee_saved.insert(preg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||||
|
check_and_insert_reg(static_cast<RegOperand*>(op.get()));
|
||||||
|
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||||
|
check_and_insert_reg(static_cast<MemOperand*>(op.get())->getBase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有使用s寄存器(除了可能作为帧指针的s0),则无需操作
|
||||||
|
if (used_callee_saved.empty() || (used_callee_saved.size() == 1 && used_callee_saved.count(PhysicalReg::S0))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将结果存入StackFrameInfo,供后续使用
|
||||||
|
frame_info.used_callee_saved_regs = used_callee_saved;
|
||||||
|
|
||||||
|
// 2. 在函数序言插入保存指令
|
||||||
|
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
|
||||||
|
auto& entry_instrs = entry_block->getInstructions();
|
||||||
|
auto prologue_end = entry_instrs.begin();
|
||||||
|
|
||||||
|
// 找到序言结束的位置(通常是addi s0, sp, size之后)
|
||||||
|
for (auto it = entry_instrs.begin(); it != entry_instrs.end(); ++it) {
|
||||||
|
if ((*it)->getOpcode() == RVOpcodes::ADDI &&
|
||||||
|
(*it)->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
|
||||||
|
static_cast<RegOperand*>((*it)->getOperands()[0].get())->getPReg() == PhysicalReg::S0)
|
||||||
|
{
|
||||||
|
prologue_end = std::next(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为了栈帧布局确定性,对寄存器进行排序
|
||||||
|
std::vector<PhysicalReg> sorted_regs(used_callee_saved.begin(), used_callee_saved.end());
|
||||||
|
std::sort(sorted_regs.begin(), sorted_regs.end());
|
||||||
|
|
||||||
|
int current_offset = -16; // ra和s0已经占用了-8和-16的位置
|
||||||
|
for (PhysicalReg reg : sorted_regs) {
|
||||||
|
if (reg == PhysicalReg::S0) continue; // s0已经在序言中处理
|
||||||
|
current_offset -= 8;
|
||||||
|
auto sd = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
||||||
|
sd->addOperand(std::make_unique<RegOperand>(reg));
|
||||||
|
sd->addOperand(std::make_unique<MemOperand>(
|
||||||
|
std::make_unique<RegOperand>(PhysicalReg::S0), // 假设s0是帧指针
|
||||||
|
std::make_unique<ImmOperand>(current_offset)
|
||||||
|
));
|
||||||
|
entry_instrs.insert(prologue_end, std::move(sd));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 在函数结尾(ret之前)插入恢复指令
|
||||||
|
for (auto& mbb : mfunc->getBlocks()) {
|
||||||
|
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
|
||||||
|
if ((*it)->getOpcode() == RVOpcodes::RET) {
|
||||||
|
// 以相反的顺序恢复
|
||||||
|
current_offset = -16;
|
||||||
|
for (PhysicalReg reg : sorted_regs) {
|
||||||
|
if (reg == PhysicalReg::S0) continue;
|
||||||
|
current_offset -= 8;
|
||||||
|
auto ld = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
||||||
|
ld->addOperand(std::make_unique<RegOperand>(reg));
|
||||||
|
ld->addOperand(std::make_unique<MemOperand>(
|
||||||
|
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||||
|
std::make_unique<ImmOperand>(current_offset)
|
||||||
|
));
|
||||||
|
mbb->getInstructions().insert(it, std::move(ld));
|
||||||
|
}
|
||||||
|
break; // 处理完一个基本块的ret即可
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sysy
|
||||||
36
src/PostRA_Scheduler.cpp
Normal file
36
src/PostRA_Scheduler.cpp
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#include "PostRA_Scheduler.h"
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
char PostRA_Scheduler::ID = 0;
|
||||||
|
|
||||||
|
bool PostRA_Scheduler::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||||
|
// TODO: 在此实现寄存器分配后的局部指令调度。
|
||||||
|
// 遍历mfunc中的每一个MachineBasicBlock。
|
||||||
|
// 重点关注由寄存器分配器插入的spill/fill代码。
|
||||||
|
//
|
||||||
|
// 实现思路:
|
||||||
|
// 1. 识别出用于spill/fill的lw/sw指令。
|
||||||
|
// 2. 在不违反数据依赖(包括物理寄存器引入的伪依赖)的前提下,
|
||||||
|
// 尝试将lw指令向上移动,使其与使用它的指令之间有足够的距离,以隐藏访存延迟。
|
||||||
|
// 3. 同样,可以尝试将sw指令向下移动。
|
||||||
|
//
|
||||||
|
// std::cout << "Running Post-RA Local Scheduler... " << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sysy
|
||||||
36
src/PreRA_Scheduler.cpp
Normal file
36
src/PreRA_Scheduler.cpp
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#include "PreRA_Scheduler.h"
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
char PreRA_Scheduler::ID = 0;
|
||||||
|
|
||||||
|
bool PreRA_Scheduler::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||||
|
// TODO: 在此实现寄存器分配前的指令调度。
|
||||||
|
// 遍历mfunc中的每一个MachineBasicBlock。
|
||||||
|
// 对每个基本块内的MachineInstr列表进行重排。
|
||||||
|
//
|
||||||
|
// 实现思路:
|
||||||
|
// 1. 分析每个基本块内指令的数据依赖关系,构建依赖图(DAG)。
|
||||||
|
// 2.
|
||||||
|
// 根据目标处理器的流水线特性(指令延迟等),使用列表调度等算法对指令进行重排。
|
||||||
|
// 3. 此时操作的是虚拟寄存器,只存在真依赖,调度自由度最大。
|
||||||
|
//
|
||||||
|
// std::cout << "Running Pre-RA Instruction Scheduler..." << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PreRA_Scheduler::runOnMachineFunction(MachineFunction *mfunc) {
|
||||||
|
// TODO: 在此实现寄存器分配前的指令调度。
|
||||||
|
// 遍历mfunc中的每一个MachineBasicBlock。
|
||||||
|
// 对每个基本块内的MachineInstr列表进行重排。
|
||||||
|
//
|
||||||
|
// 实现思路:
|
||||||
|
// 1. 分析每个基本块内指令的数据依赖关系,构建依赖图(DAG)。
|
||||||
|
// 2.
|
||||||
|
// 根据目标处理器的流水线特性(指令延迟等),使用列表调度等算法对指令进行重排。
|
||||||
|
// 3. 此时操作的是虚拟寄存器,只存在真依赖,调度自由度最大。
|
||||||
|
//
|
||||||
|
// std::cout << "Running Pre-RA Instruction Scheduler..." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sysy
|
||||||
@@ -1,27 +1,15 @@
|
|||||||
#include "RISCv64Passes.h"
|
#include "RISCv64Peephole.h"
|
||||||
// #include <iostream>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
// --- 寄存器分配前优化 ---
|
char PeepholeOptimizer::ID = 0;
|
||||||
|
|
||||||
void PreRA_Scheduler::runOnMachineFunction(MachineFunction *mfunc) {
|
bool PeepholeOptimizer::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||||
// TODO: 在此实现寄存器分配前的指令调度。
|
// This pass works on MachineFunction level, not IR level
|
||||||
// 遍历mfunc中的每一个MachineBasicBlock。
|
return false;
|
||||||
// 对每个基本块内的MachineInstr列表进行重排。
|
|
||||||
//
|
|
||||||
// 实现思路:
|
|
||||||
// 1. 分析每个基本块内指令的数据依赖关系,构建依赖图(DAG)。
|
|
||||||
// 2.
|
|
||||||
// 根据目标处理器的流水线特性(指令延迟等),使用列表调度等算法对指令进行重排。
|
|
||||||
// 3. 此时操作的是虚拟寄存器,只存在真依赖,调度自由度最大。
|
|
||||||
//
|
|
||||||
// std::cout << "Running Pre-RA Instruction Scheduler..." << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- 寄存器分配后优化 ---
|
|
||||||
|
|
||||||
void PeepholeOptimizer::runOnMachineFunction(MachineFunction *mfunc) {
|
void PeepholeOptimizer::runOnMachineFunction(MachineFunction *mfunc) {
|
||||||
if (!mfunc)
|
if (!mfunc)
|
||||||
return;
|
return;
|
||||||
@@ -661,113 +649,4 @@ void PeepholeOptimizer::runOnMachineFunction(MachineFunction *mfunc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
|
||||||
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
|
||||||
std::set<PhysicalReg> used_callee_saved;
|
|
||||||
|
|
||||||
// 1. 扫描所有指令,找出被使用的s寄存器
|
|
||||||
for (auto& mbb : mfunc->getBlocks()) {
|
|
||||||
for (auto& instr : mbb->getInstructions()) {
|
|
||||||
for (auto& op : instr->getOperands()) {
|
|
||||||
|
|
||||||
// 辅助Lambda,用于检查和插入寄存器
|
|
||||||
auto check_and_insert_reg = [&](RegOperand* reg_op) {
|
|
||||||
if (!reg_op->isVirtual()) {
|
|
||||||
PhysicalReg preg = reg_op->getPReg();
|
|
||||||
// --- 关键检查点 ---
|
|
||||||
// 必须严格判断是否在 s0-s11 的范围内。
|
|
||||||
// a0, t0 等寄存器绝对不应被视为被调用者保存寄存器。
|
|
||||||
if (preg >= PhysicalReg::S0 && preg <= PhysicalReg::S11) {
|
|
||||||
used_callee_saved.insert(preg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
|
||||||
check_and_insert_reg(static_cast<RegOperand*>(op.get()));
|
|
||||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
|
||||||
check_and_insert_reg(static_cast<MemOperand*>(op.get())->getBase());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果没有使用s寄存器(除了可能作为帧指针的s0),则无需操作
|
|
||||||
if (used_callee_saved.empty() || (used_callee_saved.size() == 1 && used_callee_saved.count(PhysicalReg::S0))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将结果存入StackFrameInfo,供后续使用
|
|
||||||
frame_info.used_callee_saved_regs = used_callee_saved;
|
|
||||||
|
|
||||||
// 2. 在函数序言插入保存指令
|
|
||||||
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
|
|
||||||
auto& entry_instrs = entry_block->getInstructions();
|
|
||||||
auto prologue_end = entry_instrs.begin();
|
|
||||||
|
|
||||||
// 找到序言结束的位置(通常是addi s0, sp, size之后)
|
|
||||||
for (auto it = entry_instrs.begin(); it != entry_instrs.end(); ++it) {
|
|
||||||
if ((*it)->getOpcode() == RVOpcodes::ADDI &&
|
|
||||||
(*it)->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
|
|
||||||
static_cast<RegOperand*>((*it)->getOperands()[0].get())->getPReg() == PhysicalReg::S0)
|
|
||||||
{
|
|
||||||
prologue_end = std::next(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 为了栈帧布局确定性,对寄存器进行排序
|
|
||||||
std::vector<PhysicalReg> sorted_regs(used_callee_saved.begin(), used_callee_saved.end());
|
|
||||||
std::sort(sorted_regs.begin(), sorted_regs.end());
|
|
||||||
|
|
||||||
int current_offset = -16; // ra和s0已经占用了-8和-16的位置
|
|
||||||
for (PhysicalReg reg : sorted_regs) {
|
|
||||||
if (reg == PhysicalReg::S0) continue; // s0已经在序言中处理
|
|
||||||
current_offset -= 8;
|
|
||||||
auto sd = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
|
||||||
sd->addOperand(std::make_unique<RegOperand>(reg));
|
|
||||||
sd->addOperand(std::make_unique<MemOperand>(
|
|
||||||
std::make_unique<RegOperand>(PhysicalReg::S0), // 假设s0是帧指针
|
|
||||||
std::make_unique<ImmOperand>(current_offset)
|
|
||||||
));
|
|
||||||
entry_instrs.insert(prologue_end, std::move(sd));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 在函数结尾(ret之前)插入恢复指令
|
|
||||||
for (auto& mbb : mfunc->getBlocks()) {
|
|
||||||
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
|
|
||||||
if ((*it)->getOpcode() == RVOpcodes::RET) {
|
|
||||||
// 以相反的顺序恢复
|
|
||||||
current_offset = -16;
|
|
||||||
for (PhysicalReg reg : sorted_regs) {
|
|
||||||
if (reg == PhysicalReg::S0) continue;
|
|
||||||
current_offset -= 8;
|
|
||||||
auto ld = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
|
||||||
ld->addOperand(std::make_unique<RegOperand>(reg));
|
|
||||||
ld->addOperand(std::make_unique<MemOperand>(
|
|
||||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
|
||||||
std::make_unique<ImmOperand>(current_offset)
|
|
||||||
));
|
|
||||||
mbb->getInstructions().insert(it, std::move(ld));
|
|
||||||
}
|
|
||||||
break; // 处理完一个基本块的ret即可
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace sysy
|
} // namespace sysy
|
||||||
33
src/include/CalleeSavedHandler.h
Normal file
33
src/include/CalleeSavedHandler.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#ifndef CALLEE_SAVED_HANDLER_H
|
||||||
|
#define CALLEE_SAVED_HANDLER_H
|
||||||
|
|
||||||
|
#include "RISCv64LLIR.h"
|
||||||
|
#include "Pass.h"
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class CalleeSavedHandler
|
||||||
|
* @brief 处理被调用者保存寄存器(Callee-Saved Registers)的Pass。
|
||||||
|
* * 这个Pass在寄存器分配之后运行。它的主要职责是:
|
||||||
|
* 1. 扫描整个函数,找出所有被使用的 `s` 系列寄存器。
|
||||||
|
* 2. 在函数序言中插入 `sd` 指令来保存这些寄存器。
|
||||||
|
* 3. 在函数结尾(ret指令前)插入 `ld` 指令来恢复这些寄存器。
|
||||||
|
* 4. 正确计算因保存这些寄存器而需要的额外栈空间,并更新StackFrameInfo。
|
||||||
|
*/
|
||||||
|
class CalleeSavedHandler : public Pass {
|
||||||
|
public:
|
||||||
|
static char ID;
|
||||||
|
|
||||||
|
CalleeSavedHandler() : Pass("callee-saved-handler", Granularity::Function, PassKind::Optimization) {}
|
||||||
|
|
||||||
|
void *getPassID() const override { return &ID; }
|
||||||
|
|
||||||
|
bool runOnFunction(Function *F, AnalysisManager& AM) override;
|
||||||
|
|
||||||
|
void runOnMachineFunction(MachineFunction* mfunc);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sysy
|
||||||
|
|
||||||
|
#endif // CALLEE_SAVED_HANDLER_H
|
||||||
30
src/include/PostRA_Scheduler.h
Normal file
30
src/include/PostRA_Scheduler.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#ifndef POST_RA_SCHEDULER_H
|
||||||
|
#define POST_RA_SCHEDULER_H
|
||||||
|
|
||||||
|
#include "RISCv64LLIR.h"
|
||||||
|
#include "Pass.h"
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class PostRA_Scheduler
|
||||||
|
* @brief 寄存器分配后的局部指令调度器
|
||||||
|
* * 主要目标是优化寄存器分配器插入的spill/fill代码(lw/sw),
|
||||||
|
* 尝试将加载指令提前,以隐藏其访存延迟。
|
||||||
|
*/
|
||||||
|
class PostRA_Scheduler : public Pass {
|
||||||
|
public:
|
||||||
|
static char ID;
|
||||||
|
|
||||||
|
PostRA_Scheduler() : Pass("post-ra-scheduler", Granularity::Function, PassKind::Optimization) {}
|
||||||
|
|
||||||
|
void *getPassID() const override { return &ID; }
|
||||||
|
|
||||||
|
bool runOnFunction(Function *F, AnalysisManager& AM) override;
|
||||||
|
|
||||||
|
void runOnMachineFunction(MachineFunction* mfunc);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sysy
|
||||||
|
|
||||||
|
#endif // POST_RA_SCHEDULER_H
|
||||||
30
src/include/PreRA_Scheduler.h
Normal file
30
src/include/PreRA_Scheduler.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#ifndef PRE_RA_SCHEDULER_H
|
||||||
|
#define PRE_RA_SCHEDULER_H
|
||||||
|
|
||||||
|
#include "RISCv64LLIR.h"
|
||||||
|
#include "Pass.h"
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class PreRA_Scheduler
|
||||||
|
* @brief 寄存器分配前的指令调度器
|
||||||
|
* * 在虚拟寄存器上进行操作,此时调度自由度最大,
|
||||||
|
* 主要目标是隐藏指令延迟,提高流水线效率。
|
||||||
|
*/
|
||||||
|
class PreRA_Scheduler : public Pass {
|
||||||
|
public:
|
||||||
|
static char ID;
|
||||||
|
|
||||||
|
PreRA_Scheduler() : Pass("pre-ra-scheduler", Granularity::Function, PassKind::Optimization) {}
|
||||||
|
|
||||||
|
void *getPassID() const override { return &ID; }
|
||||||
|
|
||||||
|
bool runOnFunction(Function *F, AnalysisManager& AM) override;
|
||||||
|
|
||||||
|
void runOnMachineFunction(MachineFunction* mfunc);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sysy
|
||||||
|
|
||||||
|
#endif // PRE_RA_SCHEDULER_H
|
||||||
@@ -2,74 +2,14 @@
|
|||||||
#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
|
||||||
30
src/include/RISCv64Peephole.h
Normal file
30
src/include/RISCv64Peephole.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#ifndef RISCV64_PEEPHOLE_H
|
||||||
|
#define RISCV64_PEEPHOLE_H
|
||||||
|
|
||||||
|
#include "RISCv64LLIR.h"
|
||||||
|
#include "Pass.h"
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class PeepholeOptimizer
|
||||||
|
* @brief 窥孔优化器
|
||||||
|
* * 在已分配物理寄存器的指令流上,通过一个小的滑动窗口来查找
|
||||||
|
* 并替换掉一些冗余或低效的指令模式。
|
||||||
|
*/
|
||||||
|
class PeepholeOptimizer : public Pass {
|
||||||
|
public:
|
||||||
|
static char ID;
|
||||||
|
|
||||||
|
PeepholeOptimizer() : Pass("peephole-optimizer", Granularity::Function, PassKind::Optimization) {}
|
||||||
|
|
||||||
|
void *getPassID() const override { return &ID; }
|
||||||
|
|
||||||
|
bool runOnFunction(Function *F, AnalysisManager& AM) override;
|
||||||
|
|
||||||
|
void runOnMachineFunction(MachineFunction* mfunc);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sysy
|
||||||
|
|
||||||
|
#endif // RISCV64_PEEPHOLE_H
|
||||||
Reference in New Issue
Block a user