[backend]引入新的活跃性分析

This commit is contained in:
Lixuanwang
2025-07-18 20:24:47 +08:00
parent 1bcb5eba2a
commit 3657c08644
2 changed files with 92 additions and 106 deletions

View File

@@ -1044,16 +1044,16 @@ std::string print_set(const std::set<std::string>& s) {
return ss.str();
}
// 活跃性分析(更新以支持浮点指令
std::map<Instruction*, std::set<std::string>> RISCv64CodeGen::liveness_analysis(Function* func) {
std::map<Instruction*, std::set<std::string>> live_in, live_out;
// 活跃性分析(更新以返回 live_in 和 live_out
LivenessResult RISCv64CodeGen::liveness_analysis(Function* func) {
LivenessResult result;
bool changed = true;
// 初始化 live_in 和 live_out
for (const auto& bb : func->getBasicBlocks()) {
for (const auto& inst_ptr : bb->getInstructions()) {
live_in[inst_ptr.get()] = {};
live_out[inst_ptr.get()] = {};
result.live_in[inst_ptr.get()] = {};
result.live_out[inst_ptr.get()] = {};
}
}
@@ -1068,11 +1068,15 @@ std::map<Instruction*, std::set<std::string>> RISCv64CodeGen::liveness_analysis(
auto bb = it->get();
if (DEEPDEBUG) std::cerr << " 基本块: " << bb->getName() << std::endl;
std::set<std::string> live_out_for_bb_inst = {};
// 计算基本块末尾的 live_out 集合,即所有后继基本块 live_in 的并集
std::set<std::string> live_out_for_bb;
for (const auto& succ_bb : bb->getSuccessors()) {
if (!succ_bb->getInstructions().empty()) {
Instruction* first_inst_in_succ = succ_bb->getInstructions().front().get();
live_out_for_bb_inst.insert(live_in[first_inst_in_succ].begin(), live_in[first_inst_in_succ].end());
if (result.live_in.count(first_inst_in_succ)) {
const auto& succ_live_in = result.live_in.at(first_inst_in_succ);
live_out_for_bb.insert(succ_live_in.begin(), succ_live_in.end());
}
}
}
@@ -1080,111 +1084,93 @@ std::map<Instruction*, std::set<std::string>> RISCv64CodeGen::liveness_analysis(
for (auto inst_it = bb->getInstructions().rbegin(); inst_it != bb->getInstructions().rend(); ++inst_it) {
auto inst = inst_it->get();
if (DEEPDEBUG) std::cerr << " 指令 (BB: " << bb->getName() << ", 地址: " << static_cast<void*>(inst) << ")" << std::endl;
std::set<std::string> current_live_in = result.live_in[inst];
std::set<std::string> current_live_out = result.live_out[inst];
std::set<std::string> new_live_out;
std::set<std::string> current_live_in = live_in[inst];
std::set<std::string> current_live_out = live_out[inst];
std::set<std::string> new_live_out_calc;
// 计算 live_out
// 计算当前指令的 live_out
if (inst_it == bb->getInstructions().rbegin()) {
new_live_out_calc = live_out_for_bb_inst;
if (DEEPDEBUG) std::cerr << " 指令是基本块的最后一条指令live_out 取自后继基本块 live_in 的并集: " << print_set(new_live_out_calc) << std::endl;
// 对于块中的最后一条指令,其 live_out 是块的 live_out
new_live_out = live_out_for_bb;
} else {
auto prev_inst_it = std::prev(inst_it);
new_live_out_calc = live_in[prev_inst_it->get()];
if (DEEPDEBUG) std::cerr << " 指令不是基本块的最后一条,其 live_out 是其后继指令 live_in: " << print_set(new_live_out_calc) << std::endl;
// 否则,其 live_out 是其后继指令的 live_in
auto next_inst_it = std::prev(inst_it);
new_live_out = result.live_in[next_inst_it->get()];
}
std::set<std::string> use_set, def_set;
// 定义 (Def)
if (!inst->getType()->isVoid() && !dynamic_cast<AllocaInst*>(inst) && !dynamic_cast<StoreInst*>(inst) &&
!dynamic_cast<ReturnInst*>(inst) && !dynamic_cast<CondBrInst*>(inst) && !dynamic_cast<UncondBrInst*>(inst) && value_vreg_map.count(inst)) {
if (value_vreg_map.count(inst) && !inst->getType()->isVoid() && !dynamic_cast<AllocaInst*>(inst) && !dynamic_cast<StoreInst*>(inst) &&
!dynamic_cast<ReturnInst*>(inst) && !dynamic_cast<CondBrInst*>(inst) && !dynamic_cast<UncondBrInst*>(inst)) {
def_set.insert(value_vreg_map.at(inst));
if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast<void*>(inst) << ") 定义了虚拟寄存器: " << value_vreg_map.at(inst) << std::endl;
}
// 使用 (Use) - 增强对常量的处理
// 使用 (Use)
for (const auto& operand_use : inst->getOperands()) {
Value* operand = operand_use->getValue();
if (value_vreg_map.count(operand) && !dynamic_cast<AllocaInst*>(operand)) {
use_set.insert(value_vreg_map.at(operand));
if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast<void*>(inst) << ") 使用了虚拟寄存器: " << value_vreg_map.at(operand) << std::endl;
}
// 如果是常量,确保其活跃性被记录
if (auto constant = dynamic_cast<ConstantValue*>(operand)) {
if (value_vreg_map.count(constant)) {
use_set.insert(value_vreg_map.at(constant));
if (DEEPDEBUG) std::cerr << " 常量 (值: " << (constant->isInt() ? std::to_string(constant->getInt()) : std::to_string(constant->getFloat())) << ") 使用了虚拟寄存器: " << value_vreg_map.at(constant) << std::endl;
}
}
}
if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast<void*>(inst) << ") 的 use_set: " << print_set(use_set) << std::endl;
if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast<void*>(inst) << ") 的 def_set: " << print_set(def_set) << std::endl;
// 计算新的 live_in
// 数据流方程: live_in[i] = use[i] U (live_out[i] - def[i])
std::set<std::string> new_live_in = use_set;
for (const auto& vreg : new_live_out_calc) {
for (const auto& vreg : new_live_out) {
if (def_set.find(vreg) == def_set.end()) {
new_live_in.insert(vreg);
}
}
if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast<void*>(inst) << ") 计算出的 new_live_in: " << print_set(new_live_in) << std::endl;
if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast<void*>(inst) << ") 当前 live_in: " << print_set(current_live_in) << ", 当前 live_out: " << print_set(current_live_out) << std::endl;
// 如果活跃性集合发生变化,更新并继续迭代
if (new_live_in != current_live_in || new_live_out_calc != current_live_out) {
live_in[inst] = new_live_in;
live_out[inst] = new_live_out_calc;
if (new_live_in != current_live_in || new_live_out != current_live_out) {
result.live_in[inst] = new_live_in;
result.live_out[inst] = new_live_out;
changed = true;
if (DEEPDEBUG) std::cerr << " 指令 (地址: " << static_cast<void*>(inst) << ") 活跃性集合发生变化,更新并继续迭代." << std::endl;
}
}
}
}
return live_in;
return result;
}
// 干扰图构建 (基本保持不变)
// 干扰图构建 (使用正确的 live_out 集合)
std::map<std::string, std::set<std::string>> RISCv64CodeGen::build_interference_graph(
const std::map<Instruction*, std::set<std::string>>& live_sets) {
const LivenessResult& liveness) {
std::map<std::string, std::set<std::string>> graph;
// 确保 live_sets 中所有存在的虚拟寄存器最初都在图中
for (const auto& pair : live_sets) {
for (const auto& vreg : pair.second) {
graph[vreg] = {}; // 初始化空集合
}
// 初始化图,确保每个虚拟寄存器都有一个节点
for (const auto& pair : value_vreg_map) {
graph[pair.second] = {};
}
for (const auto& pair : live_sets) {
auto inst = pair.first;
const auto& live_after_inst = pair.second; // 这实际上是下一条指令/基本块入口的 live_in
// 遍历每条指令来构建干扰
for (const auto& pair : liveness.live_out) {
Instruction* inst = pair.first;
const auto& live_out_set = pair.second;
// 规则1: 指令定义的结果寄存器与该指令的 live_out 集合中的所有寄存器干扰
std::string defined_vreg;
// 修正:只有当指令结果是需要物理寄存器时才视为定义。
// AllocaInst 不应在此处处理。
if (value_vreg_map.count(inst) && !dynamic_cast<AllocaInst*>(inst)) {
if (value_vreg_map.count(inst) && !inst->getType()->isVoid() && !dynamic_cast<AllocaInst*>(inst) && !dynamic_cast<StoreInst*>(inst) &&
!dynamic_cast<ReturnInst*>(inst) && !dynamic_cast<CondBrInst*>(inst) && !dynamic_cast<UncondBrInst*>(inst)) {
defined_vreg = value_vreg_map.at(inst);
}
// 将从 defined vreg 到此时所有其他活跃 vreg 的边添加
if (!defined_vreg.empty()) {
for (const auto& live_vreg : live_after_inst) {
if (live_vreg != defined_vreg) { // 虚拟寄存器不与其自身干扰
for (const auto& live_vreg : live_out_set) {
if (defined_vreg != live_vreg) {
graph[defined_vreg].insert(live_vreg);
graph[live_vreg].insert(defined_vreg); // 对称边
graph[live_vreg].insert(defined_vreg);
}
}
}
// 对于 store 指令,要存储的值和目标地址指针是同时活跃的,必须互相干扰
// 规则2: 特殊指令内部的操作数之间也存在干扰
if (auto store = dynamic_cast<StoreInst*>(inst)) {
Value* val_operand = store->getValue();
Value* ptr_operand = store->getPointer();
if (value_vreg_map.count(val_operand) && value_vreg_map.count(ptr_operand)) {
const std::string& val_vreg = value_vreg_map.at(val_operand);
const std::string& ptr_vreg = value_vreg_map.at(ptr_operand);
@@ -1193,10 +1179,7 @@ std::map<std::string, std::set<std::string>> RISCv64CodeGen::build_interference_
graph[ptr_vreg].insert(val_vreg);
}
}
}
// 可选:为其他有两个或以上源操作数的指令(如 add添加类似逻辑
// 确保它们的操作数虚拟寄存器互相干扰。
else if (auto bin = dynamic_cast<BinaryInst*>(inst)) {
} else if (auto bin = dynamic_cast<BinaryInst*>(inst)) {
Value* lhs_operand = bin->getLhs();
Value* rhs_operand = bin->getRhs();
if (value_vreg_map.count(lhs_operand) && value_vreg_map.count(rhs_operand)) {
@@ -1204,9 +1187,24 @@ std::map<std::string, std::set<std::string>> RISCv64CodeGen::build_interference_
const std::string& rhs_vreg = value_vreg_map.at(rhs_operand);
if (lhs_vreg != rhs_vreg) {
graph[lhs_vreg].insert(rhs_vreg);
graph[rhs_vreg].insert(rhs_vreg);
graph[rhs_vreg].insert(lhs_vreg); // 修正了原有的笔误
}
}
} else if (auto call = dynamic_cast<CallInst*>(inst)) {
// 函数调用的所有参数在调用发生时都是活跃的,因此它们相互干扰
std::vector<std::string> arg_vregs;
for (auto arg_use : call->getArguments()) {
Value* arg_val = arg_use->getValue();
if (value_vreg_map.count(arg_val)) {
arg_vregs.push_back(value_vreg_map.at(arg_val));
}
}
for (size_t i = 0; i < arg_vregs.size(); ++i) {
for (size_t j = i + 1; j < arg_vregs.size(); ++j) {
graph[arg_vregs[i]].insert(arg_vregs[j]);
graph[arg_vregs[j]].insert(arg_vregs[i]);
}
}
}
}
return graph;
@@ -1345,7 +1343,7 @@ RISCv64CodeGen::RegAllocResult RISCv64CodeGen::register_allocation(Function* fun
int current_stack_offset = 0;
std::set<AllocaInst*> allocas_in_func;
// 收集函数中的所有 AllocaInst
// AllocaInst 计算栈空间并分配偏移量
for (const auto& bb_ptr : func->getBasicBlocks()) {
for (const auto& inst_ptr : bb_ptr->getInstructions()) {
if (auto alloca = dynamic_cast<AllocaInst*>(inst_ptr.get())) {
@@ -1353,21 +1351,15 @@ RISCv64CodeGen::RegAllocResult RISCv64CodeGen::register_allocation(Function* fun
}
}
}
// 为每个 AllocaInst 计算栈空间并分配偏移量
for (auto alloca : allocas_in_func) {
int total_size = 4; // 基本元素大小int 或 float
int total_size = 4;
auto dims = alloca->getDims();
if (!dims.empty()) {
int num_elements = 1;
for (const auto& dim_use : dims) {
Value* dim_value = dim_use->getValue();
if (auto const_dim = dynamic_cast<ConstantValue*>(dim_value)) {
if (const_dim->isInt()) {
num_elements *= const_dim->getInt();
} else {
throw std::runtime_error("数组维度必须是整数");
}
num_elements *= const_dim->getInt();
} else {
throw std::runtime_error("数组维度必须是编译时常量");
}
@@ -1377,14 +1369,14 @@ RISCv64CodeGen::RegAllocResult RISCv64CodeGen::register_allocation(Function* fun
alloc_result.stack_map[alloca] = current_stack_offset;
current_stack_offset += total_size;
}
// RV64 修改: 为保存的 ra 和 s0 (各8字节) 预留16字节空间
// 为保存的 ra 和 s0 (各8字节) 预留16字节空间
alloc_result.stack_size = current_stack_offset + 16;
// 活跃性分析
std::map<Instruction*, std::set<std::string>> live_sets = liveness_analysis(func);
LivenessResult liveness = liveness_analysis(func);
// 构建干扰图
std::map<std::string, std::set<std::string>> interference_graph = build_interference_graph(live_sets);
std::map<std::string, std::set<std::string>> interference_graph = build_interference_graph(liveness);
// 图着色
color_graph(alloc_result.vreg_to_preg, interference_graph);
@@ -1401,36 +1393,23 @@ RISCv64CodeGen::RegAllocResult RISCv64CodeGen::register_allocation(Function* fun
std::cerr << "Basic Block: " << bb_ptr->getName() << "\n";
for (const auto& inst_ptr : bb_ptr->getInstructions()) {
std::cerr << " Inst: " << inst_ptr->getKindString();
if (!inst_ptr->getName().empty()) {
std::cerr << "(" << inst_ptr->getName() << ")";
if (!inst_ptr->getName().empty()) std::cerr << "(" << inst_ptr->getName() << ")";
if (value_vreg_map.count(inst_ptr.get())) std::cerr << " (Def vreg: " << value_vreg_map.at(inst_ptr.get()) << ")";
std::cerr << " (Live In: ";
if (liveness.live_in.count(inst_ptr.get())) {
std::cerr << print_set(liveness.live_in.at(inst_ptr.get()));
} else {
std::cerr << "{}";
}
if (value_vreg_map.count(inst_ptr.get())) {
std::cerr << " (Def vreg: " << value_vreg_map.at(inst_ptr.get()) << ")";
}
std::cerr << " (Live In: {";
bool first = true;
if (live_sets.count(inst_ptr.get())) {
for (const auto& vreg : live_sets.at(inst_ptr.get())) {
if (!first) std::cerr << ", ";
std::cerr << vreg;
first = false;
}
}
std::cerr << "})\n";
std::cerr << ")\n";
}
}
std::cerr << "=== 活跃性分析结果结束 ===\n\n";
std::cerr << "=== 干扰图 ===\n";
for (const auto& pair : interference_graph) {
std::cerr << " " << pair.first << ": {";
bool first = true;
for (const auto& neighbor : pair.second) {
if (!first) std::cerr << ", ";
std::cerr << neighbor;
first = false;
}
std::cerr << "}\n";
std::cerr << " " << pair.first << ": " << print_set(pair.second) << "\n";
}
std::cerr << "=== 干扰图结束 ===\n\n";
}

View File

@@ -13,8 +13,16 @@
extern int DEBUG;
extern int DEEPDEBUG;
namespace sysy {
// 为活跃性分析的结果定义一个结构体,以同时持有 live_in 和 live_out 集合
struct LivenessResult {
std::map<Instruction*, std::set<std::string>> live_in;
std::map<Instruction*, std::set<std::string>> live_out;
};
class RISCv64CodeGen {
public:
enum class PhysicalReg {
@@ -71,9 +79,8 @@ public:
void emit_instructions(DAGNode* node, std::stringstream& ss, const RegAllocResult& alloc, std::set<DAGNode*>& emitted_nodes);
// Register Allocation related
std::map<Instruction*, std::set<std::string>> liveness_analysis(Function* func);
std::map<std::string, std::set<std::string>> build_interference_graph(
const std::map<Instruction*, std::set<std::string>>& live_sets);
LivenessResult liveness_analysis(Function* func);
std::map<std::string, std::set<std::string>> build_interference_graph(const LivenessResult& liveness);
void color_graph(std::map<std::string, PhysicalReg>& vreg_to_preg,
const std::map<std::string, std::set<std::string>>& interference_graph);
RegAllocResult register_allocation(Function* func);