[midend]重构了src目录

This commit is contained in:
Lixuanwang
2025-07-29 21:30:30 +08:00
parent f5922d0178
commit 09ae47924e
84 changed files with 85 additions and 1715 deletions

View 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

View File

@@ -0,0 +1,36 @@
#ifndef SYSY_LEGALIZE_IMMEDIATES_H
#define SYSY_LEGALIZE_IMMEDIATES_H
#include "RISCv64LLIR.h"
#include "Pass.h"
namespace sysy {
// MachineFunction 的前向声明在这里是可选的,因为 RISCv64LLIR.h 已经定义了它
// class MachineFunction;
/**
* @class LegalizeImmediatesPass
* @brief 一个用于“合法化”机器指令的Pass。
*
* 这个Pass的主要职责是遍历所有机器指令查找那些包含了超出
* 目标架构RISC-V编码范围的大立即数immediate的指令
* 并将它们展开成一个等价的、只包含合法立即数的指令序列。
*
* 它在指令选择之后、寄存器分配之前运行,确保进入后续阶段的
* 所有指令都符合硬件约束。
*/
class LegalizeImmediatesPass : public Pass {
public:
static char ID;
LegalizeImmediatesPass() : Pass("legalize-immediates", Granularity::Function, PassKind::Optimization) {}
void *getPassID() const override { return &ID; }
void runOnMachineFunction(MachineFunction* mfunc);
};
} // namespace sysy
#endif // SYSY_LEGALIZE_IMMEDIATES_H

View File

@@ -0,0 +1,35 @@
#ifndef SYSY_PROLOGUE_EPILOGUE_INSERTION_H
#define SYSY_PROLOGUE_EPILOGUE_INSERTION_H
#include "RISCv64LLIR.h"
#include "Pass.h"
namespace sysy {
class MachineFunction;
/**
* @class PrologueEpilogueInsertionPass
* @brief 在函数中插入序言和尾声的机器指令。
*
* 这个Pass在所有栈帧大小计算完毕后包括局部变量、溢出槽、被调用者保存寄存器
* 在寄存器分配之后运行。它的职责是:
* 1. 根据 StackFrameInfo 中的最终栈大小,生成用于分配和释放栈帧的指令 (addi sp, sp, +/-size)。
* 2. 生成用于保存和恢复返回地址(ra)和旧帧指针(s0)的指令。
* 3. 将这些指令作为 MachineInstr 对象插入到 MachineFunction 的入口块和所有返回块中。
* 4. 这个Pass可能会生成带有大立即数的指令需要后续的 LegalizeImmediatesPass 来处理。
*/
class PrologueEpilogueInsertionPass : public Pass {
public:
static char ID;
PrologueEpilogueInsertionPass() : Pass("prologue-epilogue-insertion", Granularity::Function, PassKind::Optimization) {}
void *getPassID() const override { return &ID; }
void runOnMachineFunction(MachineFunction* mfunc);
};
} // namespace sysy
#endif // SYSY_PROLOGUE_EPILOGUE_INSERTION_H

View 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

View 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

View 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

View File

@@ -0,0 +1,36 @@
#ifndef RISCV64_ASMPRINTER_H
#define RISCV64_ASMPRINTER_H
#include "RISCv64LLIR.h"
#include <iostream>
extern int DEBUG;
extern int DEEPDEBUG;
namespace sysy {
class RISCv64AsmPrinter {
public:
RISCv64AsmPrinter(MachineFunction* mfunc);
// 主入口
void run(std::ostream& os, bool debug = false);
void printInstruction(MachineInstr* instr, bool debug = false);
// 辅助函数
void setStream(std::ostream& os) { OS = &os; }
private:
// 打印各个部分
void printBasicBlock(MachineBasicBlock* mbb, bool debug = false);
// 辅助函数
std::string regToString(PhysicalReg reg);
void printOperand(MachineOperand* op);
MachineFunction* MFunc;
std::ostream* OS = nullptr;
};
} // namespace sysy
#endif // RISCV64_ASMPRINTER_H

View File

@@ -0,0 +1,30 @@
#ifndef RISCV64_BACKEND_H
#define RISCV64_BACKEND_H
#include "IR.h"
#include <string>
extern int DEBUG;
extern int DEEPDEBUG;
namespace sysy {
// RISCv64CodeGen 现在是一个高层驱动器
class RISCv64CodeGen {
public:
RISCv64CodeGen(Module* mod) : module(mod) {}
// 唯一的公共入口点
std::string code_gen();
private:
// 模块级代码生成
std::string module_gen();
// 函数级代码生成 (实现新的流水线)
std::string function_gen(Function* func);
Module* module;
};
} // namespace sysy
#endif // RISCV64_BACKEND_H

View File

@@ -0,0 +1,58 @@
#ifndef RISCV64_ISEL_H
#define RISCV64_ISEL_H
#include "RISCv64LLIR.h"
extern int DEBUG;
extern int DEEPDEBUG;
namespace sysy {
class RISCv64ISel {
public:
RISCv64ISel();
// 模块主入口将一个高层IR函数转换为底层LLIR函数
std::unique_ptr<MachineFunction> runOnFunction(Function* func);
// 公开接口以便后续模块如RegAlloc可以查询或创建vreg
unsigned getVReg(Value* val);
unsigned getNewVReg() { return vreg_counter++; }
// 获取 vreg_map 的公共接口
const std::map<Value*, unsigned>& getVRegMap() const { return vreg_map; }
private:
// DAG节点定义作为ISel的内部实现细节
struct DAGNode;
// 指令选择主流程
void select();
// 为单个基本块生成指令
void selectBasicBlock(BasicBlock* bb);
// 核心函数为DAG节点选择并生成MachineInstr
void selectNode(DAGNode* node);
// DAG 构建相关函数 (从原RISCv64Backend迁移)
std::vector<std::unique_ptr<DAGNode>> build_dag(BasicBlock* bb);
DAGNode* get_operand_node(Value* val_ir, std::map<Value*, DAGNode*>&, std::vector<std::unique_ptr<DAGNode>>&);
DAGNode* create_node(int kind, Value* val, std::map<Value*, DAGNode*>&, std::vector<std::unique_ptr<DAGNode>>&);
// 用于计算类型大小的辅助函数
unsigned getTypeSizeInBytes(Type* type);
void print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, const std::string& bb_name);
// 状态
Function* F; // 当前处理的高层IR函数
std::unique_ptr<MachineFunction> MFunc; // 正在构建的底层LLIR函数
MachineBasicBlock* CurMBB; // 当前正在处理的机器基本块
// 映射关系
std::map<Value*, unsigned> vreg_map;
std::map<const BasicBlock*, MachineBasicBlock*> bb_map;
unsigned vreg_counter;
int local_label_counter;
};
} // namespace sysy
#endif // RISCV64_ISEL_H

View File

@@ -0,0 +1,238 @@
#ifndef RISCV64_LLIR_H
#define RISCV64_LLIR_H
#include "IR.h" // 确保包含了您自己的IR头文件
#include <string>
#include <vector>
#include <memory>
#include <cstdint>
#include <map>
// 前向声明,避免循环引用
namespace sysy {
class Function;
class RISCv64ISel;
}
namespace sysy {
// 物理寄存器定义
enum class PhysicalReg {
// --- 特殊功能寄存器 ---
ZERO, RA, SP, GP, TP,
// --- 整数寄存器 (按调用约定分组) ---
// 临时寄存器 (调用者保存)
T0, T1, T2, T3, T4, T5, T6,
// 保存寄存器 (被调用者保存)
S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11,
// 参数/返回值寄存器 (调用者保存)
A0, A1, A2, A3, A4, A5, A6, A7,
// --- 浮点寄存器 ---
// (保持您原有的 F0-F31 命名)
F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11,
F12, F13, F14, F15, F16, F17, F18, F19, F20, F21,
F22, F23, F24, F25, F26, F27, F28, F29, F30, F31,
// 用于内部表示物理寄存器在干扰图中的节点ID一个简单的特殊ID确保不与vreg_counter冲突
// 假设 vreg_counter 不会达到这么大的值
PHYS_REG_START_ID = 100000,
PHYS_REG_END_ID = PHYS_REG_START_ID + 320, // 预留足够的空间
};
// RISC-V 指令操作码枚举
enum class RVOpcodes {
// 算术指令
ADD, ADDI, ADDW, ADDIW, SUB, SUBW, MUL, MULW, DIV, DIVW, REM, REMW,
// 逻辑指令
XOR, XORI, OR, ORI, AND, ANDI,
// 移位指令
SLL, SLLI, SLLW, SLLIW, SRL, SRLI, SRLW, SRLIW, SRA, SRAI, SRAW, SRAIW,
// 比较指令
SLT, SLTI, SLTU, SLTIU,
// 内存访问指令
LW, LH, LB, LWU, LHU, LBU, SW, SH, SB, LD, SD,
// 控制流指令
J, JAL, JALR, RET,
BEQ, BNE, BLT, BGE, BLTU, BGEU,
// 伪指令
LI, LA, MV, NEG, NEGW, SEQZ, SNEZ,
// 函数调用
CALL,
// 特殊标记,非指令
LABEL,
// 新增伪指令,用于解耦栈帧处理
FRAME_LOAD_W, // 从栈帧加载 32位 Word (对应 lw)
FRAME_LOAD_D, // 从栈帧加载 64位 Doubleword (对应 ld)
FRAME_STORE_W, // 保存 32位 Word 到栈帧 (对应 sw)
FRAME_STORE_D, // 保存 64位 Doubleword 到栈帧 (对应 sd)
FRAME_ADDR, // 获取栈帧变量的地址
};
// 定义一个全局辅助函数或常量,提供调用者保存寄存器列表
const std::vector<PhysicalReg>& getCallerSavedIntRegs();
class MachineOperand;
class RegOperand;
class ImmOperand;
class LabelOperand;
class MemOperand;
class MachineInstr;
class MachineBasicBlock;
class MachineFunction;
// 操作数基类
class MachineOperand {
public:
enum OperandKind { KIND_REG, KIND_IMM, KIND_LABEL, KIND_MEM };
MachineOperand(OperandKind kind) : kind(kind) {}
virtual ~MachineOperand() = default;
OperandKind getKind() const { return kind; }
private:
OperandKind kind;
};
// 寄存器操作数
class RegOperand : public MachineOperand {
public:
// 构造虚拟寄存器
RegOperand(unsigned vreg_num)
: MachineOperand(KIND_REG), vreg_num(vreg_num), is_virtual(true) {}
// 构造物理寄存器
RegOperand(PhysicalReg preg)
: MachineOperand(KIND_REG), preg(preg), is_virtual(false) {}
bool isVirtual() const { return is_virtual; }
unsigned getVRegNum() const { return vreg_num; }
PhysicalReg getPReg() const { return preg; }
void setPReg(PhysicalReg new_preg) {
preg = new_preg;
is_virtual = false;
}
private:
unsigned vreg_num = 0;
PhysicalReg preg = PhysicalReg::ZERO;
bool is_virtual;
};
// 立即数操作数
class ImmOperand : public MachineOperand {
public:
ImmOperand(int64_t value) : MachineOperand(KIND_IMM), value(value) {}
int64_t getValue() const { return value; }
private:
int64_t value;
};
// 标签操作数
class LabelOperand : public MachineOperand {
public:
LabelOperand(const std::string& name) : MachineOperand(KIND_LABEL), name(name) {}
const std::string& getName() const { return name; }
private:
std::string name;
};
// 内存操作数, 表示 offset(base_reg)
class MemOperand : public MachineOperand {
public:
MemOperand(std::unique_ptr<RegOperand> base, std::unique_ptr<ImmOperand> offset)
: MachineOperand(KIND_MEM), base(std::move(base)), offset(std::move(offset)) {}
RegOperand* getBase() const { return base.get(); }
ImmOperand* getOffset() const { return offset.get(); }
private:
std::unique_ptr<RegOperand> base;
std::unique_ptr<ImmOperand> offset;
};
// 机器指令
class MachineInstr {
public:
MachineInstr(RVOpcodes opcode) : opcode(opcode) {}
RVOpcodes getOpcode() const { return opcode; }
const std::vector<std::unique_ptr<MachineOperand>>& getOperands() const { return operands; }
std::vector<std::unique_ptr<MachineOperand>>& getOperands() { return operands; }
void addOperand(std::unique_ptr<MachineOperand> operand) {
operands.push_back(std::move(operand));
}
private:
RVOpcodes opcode;
std::vector<std::unique_ptr<MachineOperand>> operands;
};
// 机器基本块
class MachineBasicBlock {
public:
MachineBasicBlock(const std::string& name, MachineFunction* parent)
: name(name), parent(parent) {}
const std::string& getName() const { return name; }
MachineFunction* getParent() const { return parent; }
const std::vector<std::unique_ptr<MachineInstr>>& getInstructions() const { return instructions; }
std::vector<std::unique_ptr<MachineInstr>>& getInstructions() { return instructions; }
void addInstruction(std::unique_ptr<MachineInstr> instr) {
instructions.push_back(std::move(instr));
}
std::vector<MachineBasicBlock*> successors;
std::vector<MachineBasicBlock*> predecessors;
private:
std::string name;
std::vector<std::unique_ptr<MachineInstr>> instructions;
MachineFunction* parent;
};
// 栈帧信息
struct StackFrameInfo {
int locals_size = 0; // 仅为AllocaInst分配的大小
int spill_size = 0; // 仅为溢出分配的大小
int total_size = 0; // 总大小
int callee_saved_size = 0; // 保存寄存器的大小
std::map<unsigned, int> alloca_offsets; // <AllocaInst的vreg, 栈偏移>
std::map<unsigned, int> spill_offsets; // <溢出vreg, 栈偏移>
std::set<PhysicalReg> used_callee_saved_regs; // 使用的保存寄存器
};
// 机器函数
class MachineFunction {
public:
MachineFunction(Function* func, RISCv64ISel* isel) : F(func), name(func->getName()), isel(isel) {}
Function* getFunc() const { return F; }
RISCv64ISel* getISel() const { return isel; }
const std::string& getName() const { return name; }
StackFrameInfo& getFrameInfo() { return frame_info; }
const std::vector<std::unique_ptr<MachineBasicBlock>>& getBlocks() const { return blocks; }
std::vector<std::unique_ptr<MachineBasicBlock>>& getBlocks() { return blocks; }
void addBlock(std::unique_ptr<MachineBasicBlock> block) {
blocks.push_back(std::move(block));
}
private:
Function* F;
RISCv64ISel* isel; // 指向创建它的ISel用于获取vreg映射等信息
std::string name;
std::vector<std::unique_ptr<MachineBasicBlock>> blocks;
StackFrameInfo frame_info;
};
inline const std::vector<PhysicalReg>& getCallerSavedIntRegs() {
static const std::vector<PhysicalReg> regs = {
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3,
PhysicalReg::T4, PhysicalReg::T5, PhysicalReg::T6,
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3,
PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7
};
return regs;
}
} // namespace sysy
#endif // RISCV64_LLIR_H

View File

@@ -0,0 +1,17 @@
#ifndef RISCV64_PASSES_H
#define RISCV64_PASSES_H
#include "RISCv64LLIR.h"
#include "Peephole.h"
#include "PreRA_Scheduler.h"
#include "PostRA_Scheduler.h"
#include "CalleeSavedHandler.h"
#include "LegalizeImmediates.h"
#include "PrologueEpilogueInsertion.h"
#include "Pass.h"
namespace sysy {
} // namespace sysy
#endif // RISCV64_PASSES_H

View File

@@ -0,0 +1,75 @@
#ifndef RISCV64_REGALLOC_H
#define RISCV64_REGALLOC_H
#include "RISCv64LLIR.h"
#include "RISCv64ISel.h" // 包含 RISCv64ISel.h 以访问 ISel 和 Value 类型
extern int DEBUG;
extern int DEEPDEBUG;
namespace sysy {
class RISCv64RegAlloc {
public:
RISCv64RegAlloc(MachineFunction* mfunc);
// 模块主入口
void run();
private:
using LiveSet = std::set<unsigned>; // 活跃虚拟寄存器集合
using InterferenceGraph = std::map<unsigned, std::set<unsigned>>;
// 栈帧管理
void eliminateFrameIndices();
// 活跃性分析
void analyzeLiveness();
// 构建干扰图
void buildInterferenceGraph();
// 图着色分配寄存器
void colorGraph();
// 重写函数替换vreg并插入溢出代码
void rewriteFunction();
// 辅助函数获取指令的Use/Def集合
void getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def);
// 辅助函数,处理调用约定
void handleCallingConvention();
MachineFunction* MFunc;
// 活跃性分析结果
std::map<const MachineInstr*, LiveSet> live_in_map;
std::map<const MachineInstr*, LiveSet> live_out_map;
// 干扰图
InterferenceGraph interference_graph;
// 图着色结果
std::map<unsigned, PhysicalReg> color_map; // vreg -> preg
std::set<unsigned> spilled_vregs; // 被溢出的vreg集合
// 可用的物理寄存器池
std::vector<PhysicalReg> allocable_int_regs;
// 存储vreg到IR Value*的反向映射
// 这个map将在run()函数开始时被填充并在rewriteFunction()中使用。
std::map<unsigned, Value*> vreg_to_value_map;
std::map<PhysicalReg, unsigned> preg_to_vreg_id_map; // 物理寄存器到特殊vreg ID的映射
// 用于计算类型大小的辅助函数
unsigned getTypeSizeInBytes(Type* type);
// 辅助函数,用于打印集合
static void printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os);
};
} // namespace sysy
#endif // RISCV64_REGALLOC_H