diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b5053bc..1c17eb1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,6 +31,7 @@ add_executable(sysyc RISCv64ISel.cpp RISCv64RegAlloc.cpp RISCv64AsmPrinter.cpp + RISCv64Passes.cpp ) # 设置 include 路径,包含 ANTLR 运行时库和项目头文件 diff --git a/src/RISCv64Backend.cpp b/src/RISCv64Backend.cpp index b2a7da0..cccbf40 100644 --- a/src/RISCv64Backend.cpp +++ b/src/RISCv64Backend.cpp @@ -2,6 +2,7 @@ #include "RISCv64ISel.h" #include "RISCv64RegAlloc.h" #include "RISCv64AsmPrinter.h" +#include "RISCv64Passes.h" // 包含优化Pass的头文件 #include namespace sysy { @@ -11,7 +12,7 @@ std::string RISCv64CodeGen::code_gen() { return module_gen(); } -// 模块级代码生成 (移植自原文件,处理.data段和驱动函数生成) +// 模块级代码生成 std::string RISCv64CodeGen::module_gen() { std::stringstream ss; @@ -52,17 +53,31 @@ std::string RISCv64CodeGen::module_gen() { return ss.str(); } -// function_gen 现在是新的、模块化的处理流水线 +// function_gen 现在是包含具体优化名称的、完整的处理流水线 std::string RISCv64CodeGen::function_gen(Function* func) { + // === 完整的后端处理流水线 === + // 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers) RISCv64ISel isel; std::unique_ptr mfunc = isel.runOnFunction(func); - // 阶段 2: 寄存器分配 (包含栈帧布局, 活跃性分析, 图着色, spill/rewrite) + // 阶段 2: 指令调度 (Instruction Scheduling) + PreRA_Scheduler scheduler; + scheduler.runOnMachineFunction(mfunc.get()); + + // 阶段 3: 物理寄存器分配 (Register Allocation) RISCv64RegAlloc reg_alloc(mfunc.get()); reg_alloc.run(); - // 阶段 3: 代码发射 (LLIR with physical regs -> Assembly Text) + // 阶段 4: 窥孔优化 (Peephole Optimization) + PeepholeOptimizer peephole; + peephole.runOnMachineFunction(mfunc.get()); + + // 阶段 5: 局部指令调度 (Local Scheduling) + PostRA_Scheduler local_scheduler; + local_scheduler.runOnMachineFunction(mfunc.get()); + + // 阶段 6: 代码发射 (Code Emission) std::stringstream ss; RISCv64AsmPrinter printer(mfunc.get()); printer.run(ss); diff --git a/src/RISCv64Passes.cpp b/src/RISCv64Passes.cpp index 40aff21..5d7c8ad 100644 --- a/src/RISCv64Passes.cpp +++ b/src/RISCv64Passes.cpp @@ -1,8 +1,54 @@ -// RISCv64Passes.cpp #include "RISCv64Passes.h" +#include namespace sysy { -// 此处为未来优化Pass的实现 +// --- 寄存器分配前优化 --- + +void PreRA_Scheduler::runOnMachineFunction(MachineFunction* mfunc) { + // TODO: 在此实现寄存器分配前的指令调度。 + // 遍历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; +} } // namespace sysy \ No newline at end of file diff --git a/src/include/RISCv64Passes.h b/src/include/RISCv64Passes.h index 3a4bcd1..7205b10 100644 --- a/src/include/RISCv64Passes.h +++ b/src/include/RISCv64Passes.h @@ -1,4 +1,3 @@ -// RISCv64Passes.h #ifndef RISCV64_PASSES_H #define RISCV64_PASSES_H @@ -6,12 +5,56 @@ namespace sysy { -// 此处为未来优化Pass的基类或独立类定义 -// 例如: -// class PeepholeOptimizer { -// public: -// void runOnMachineFunction(MachineFunction* mfunc); -// }; +/** + * @class Pass + * @brief 所有优化Pass的抽象基类 (可选,但推荐) + * * 定义一个通用的接口,所有优化都应该实现它。 + */ +class Pass { +public: + virtual ~Pass() = default; + virtual void runOnMachineFunction(MachineFunction* mfunc) = 0; +}; + + +// --- 寄存器分配前优化 --- + +/** + * @class PreRA_Scheduler + * @brief 寄存器分配前的指令调度器 + * * 在虚拟寄存器上进行操作,此时调度自由度最大, + * 主要目标是隐藏指令延迟,提高流水线效率。 + */ +class PreRA_Scheduler : public Pass { +public: + void runOnMachineFunction(MachineFunction* mfunc) override; +}; + + +// --- 寄存器分配后优化 --- + +/** + * @class PeepholeOptimizer + * @brief 窥孔优化器 + * * 在已分配物理寄存器的指令流上,通过一个小的滑动窗口来查找 + * 并替换掉一些冗余或低效的指令模式。 + */ +class PeepholeOptimizer : public Pass { +public: + void runOnMachineFunction(MachineFunction* mfunc) override; +}; + +/** + * @class PostRA_Scheduler + * @brief 寄存器分配后的局部指令调度器 + * * 主要目标是优化寄存器分配器插入的spill/fill代码(lw/sw), + * 尝试将加载指令提前,以隐藏其访存延迟。 + */ +class PostRA_Scheduler : public Pass { +public: + void runOnMachineFunction(MachineFunction* mfunc) override; +}; + } // namespace sysy diff --git a/test_script/runit.sh b/test_script/runit.sh index 38f0878..ce66b5d 100644 --- a/test_script/runit.sh +++ b/test_script/runit.sh @@ -9,7 +9,7 @@ TESTDATA_DIR="${SCRIPT_DIR}/../testdata" BUILD_BIN_DIR="${SCRIPT_DIR}/../build/bin" LIB_DIR="${SCRIPT_DIR}/../lib" # TMP_DIR="${SCRIPT_DIR}/tmp" -TMP_DIR="/home/ladev987/paraComp/debug/share_folder/tmp" +TMP_DIR="${SCRIPT_DIR}/tmp" # 定义编译器和模拟器 SYSYC="${BUILD_BIN_DIR}/sysyc"