From bc742f4ee722b4cdf461fcc416fdbc70834618a7 Mon Sep 17 00:00:00 2001 From: ZhuangYumin Date: Tue, 22 Oct 2024 02:05:22 +0000 Subject: [PATCH] can out put colored program --- include/IR/IR_basic.h | 1 + src/opt/confgraph.cpp | 166 +++++++++++++++++++++++++++++++++-------- src/opt/regalloc.cpp | 167 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 303 insertions(+), 31 deletions(-) diff --git a/include/IR/IR_basic.h b/include/IR/IR_basic.h index 50e57e1..129eedf 100644 --- a/include/IR/IR_basic.h +++ b/include/IR/IR_basic.h @@ -372,6 +372,7 @@ class FunctionDefItem : public LLVMIRItemBase { std::vector args_full_name; std::shared_ptr init_block; std::vector> basic_blocks; + size_t spilled_vars; FunctionDefItem() = default; void RecursivePrint(std::ostream &os) const { diff --git a/src/opt/confgraph.cpp b/src/opt/confgraph.cpp index 267cbaa..0440052 100644 --- a/src/opt/confgraph.cpp +++ b/src/opt/confgraph.cpp @@ -43,7 +43,7 @@ ConfGraph BuildConfGraph(CFGType &cfg) { size_t reg_id = cfg.var_to_id["%reg." + reg]; res.id_to_node[reg_id]->is_binded_with_physical_reg = true; res.id_to_node[reg_id]->color = std::stoi(reg.substr(1)); - std::cerr << "coloring node whith id=" << reg_id << " with color=" << res.id_to_node[reg_id]->color << std::endl; + // std::cerr << "coloring node whith id=" << reg_id << " with color=" << res.id_to_node[reg_id]->color << std::endl; res.id_to_node[reg_id]->degree = ConfGraphNode::kInf; } for (auto cfg_node : cfg.nodes) { @@ -123,11 +123,11 @@ void DetachNode(ConfGraphNode *node, ConfGraph &confgraph) { node->is_temporarily_removed = true; if (node->is_binded_with_physical_reg) throw std::runtime_error("something strange happened: a physical register is removed"); - std::cerr << "detaching node containing var ids:"; - for (auto id : node->var_ids) { - std::cerr << id << " "; - } - std::cerr << std::endl; + // std::cerr << "detaching node containing var ids:"; + // for (auto id : node->var_ids) { + // std::cerr << id << " "; + // } + // std::cerr << std::endl; for (auto neighbor : node->neighbors_half_available) { neighbor->neighbors_half_available.erase(confgraph.adj_table_half_available[neighbor][node]); confgraph.adj_table_half_available[neighbor].erase(node); @@ -170,6 +170,35 @@ void JoinNode(ConfGraphNode *node, ConfGraph &confgraph) { // this function operates on the conflict graph, temporarily remove the node from the graph, it do nothing on the move // link graph although they share the same node set // It is also responsible for maintaining all the changes caused by the removal of the node + if (!node->is_temporarily_removed) + throw std::runtime_error("something strange happened: a node is not temporarily removed"); + node->is_temporarily_removed = false; + if (node->is_binded_with_physical_reg) + throw std::runtime_error("something strange happened: a physical register is removed"); + // upgrade half available neighbors to available neighbors + for (auto neighbor : node->neighbors_half_available) { + neighbor->neighbors_half_available.erase(confgraph.adj_table_half_available[neighbor][node]); + confgraph.adj_table_half_available[neighbor].erase(node); + // node->neighbors_half_available.erase(confgraph.adj_table_half_available[node][neighbor]); + confgraph.adj_table_half_available[node].erase(neighbor); + neighbor->neighbors.push_back(node); + confgraph.adj_table[neighbor][node] = std::prev(neighbor->neighbors.end()); + node->neighbors.push_back(neighbor); + confgraph.adj_table[node][neighbor] = std::prev(node->neighbors.end()); + } + node->neighbors_half_available.clear(); + // upgrade not available neighbors to half available neighbors + for (auto neighbor : node->neighbors_not_available) { + neighbor->neighbors_not_available.erase(confgraph.adj_table_not_available[neighbor][node]); + confgraph.adj_table_not_available[neighbor].erase(node); + // node->neighbors_not_available.erase(confgraph.adj_table_not_available[node][neighbor]); + confgraph.adj_table_not_available[node].erase(neighbor); + neighbor->neighbors_half_available.push_back(node); + confgraph.adj_table_half_available[neighbor][node] = std::prev(neighbor->neighbors_half_available.end()); + node->neighbors_half_available.push_back(neighbor); + confgraph.adj_table_half_available[node][neighbor] = std::prev(node->neighbors_half_available.end()); + } + node->neighbors_not_available.clear(); } void MergeNodeInto(ConfGraphNode *node, ConfGraphNode *target, ConfGraph &confgraph) { @@ -177,16 +206,16 @@ void MergeNodeInto(ConfGraphNode *node, ConfGraphNode *target, ConfGraph &confgr // It is also responsible for maintaining all the changes caused by the merge of the node if (node->is_temporarily_removed) throw std::runtime_error("something strange happened: a temporarily removed node is merged"); - std::cerr << "node ids:"; - for (auto id : node->var_ids) { - std::cerr << id << " "; - } - std::cerr << std::endl; - std::cerr << "target ids:"; - for (auto id : target->var_ids) { - std::cerr << id << " "; - } - std::cerr << std::endl; + // std::cerr << "node ids:"; + // for (auto id : node->var_ids) { + // std::cerr << id << " "; + // } + // std::cerr << std::endl; + // std::cerr << "target ids:"; + // for (auto id : target->var_ids) { + // std::cerr << id << " "; + // } + // std::cerr << std::endl; confgraph.low_degree_and_move_related.erase(node); confgraph.low_degree_and_not_move_related.erase(node); confgraph.high_degree_nodes.erase(node); @@ -264,6 +293,9 @@ void Coalesce(std::shared_ptr src, CFGType &cfg, ConfGraph &con if (src_node == dest_node) { return; } + if (src_node->is_temporarily_removed || dest_node->is_temporarily_removed) { + return; + } if (confgraph.adj_table[src_node].find(dest_node) != confgraph.adj_table[src_node].end()) { // no need to update low_degree_and_move_related, when confgraph.pending_moves.size()==0, nodes in // low_degree_and_move_related will automatically be moved to low_degree_and_not_move_related @@ -328,12 +360,12 @@ bool ConductColoring(std::shared_ptr src, CFGType &cfg, ConfGra if (cfg.id_to_var.size() != cfg.var_to_id.size()) { throw std::runtime_error("something strange happened: id_to_var and var_to_id do not match"); } - for (size_t i = 0; i < cfg.id_to_var.size(); i++) { - std::cerr << "id=" << i << " var=" << cfg.id_to_var[i] << std::endl; - if (i != cfg.var_to_id[cfg.id_to_var[i]]) { - throw std::runtime_error("something strange happened: id_to_var and var_to_id do not match"); - } - } + // for (size_t i = 0; i < cfg.id_to_var.size(); i++) { + // std::cerr << "id=" << i << " var=" << cfg.id_to_var[i] << std::endl; + // if (i != cfg.var_to_id[cfg.id_to_var[i]]) { + // throw std::runtime_error("something strange happened: id_to_var and var_to_id do not match"); + // } + // } if (cfg.id_to_var.size() != confgraph.nodes.size()) { throw std::runtime_error("something strange happened: id_to_var and confgraph.nodes do not match"); } @@ -376,19 +408,93 @@ bool ConductColoring(std::shared_ptr src, CFGType &cfg, ConfGra } else if (confgraph.pending_moves.size() > 0) { Coalesce(src, cfg, confgraph); } else if (confgraph.low_degree_and_move_related.size() > 0) { - Freeze(src, cfg, confgraph); + bool new_pending_move_available = false; + if (confgraph.potential_moves.size() > 0) { + std::vector removed; + for (auto move : confgraph.potential_moves) { + auto src_node = confgraph.id_to_node[cfg.var_to_id[move->src_full]]; + auto dest_node = confgraph.id_to_node[cfg.var_to_id[move->dest_full]]; + src_node = ConfGraphNode::FindFather(src_node); + dest_node = ConfGraphNode::FindFather(dest_node); + if (src_node == dest_node) { + removed.push_back(move); + } else if (src_node->is_temporarily_removed || dest_node->is_temporarily_removed) { + removed.push_back(move); + } else if (confgraph.adj_table[src_node].find(dest_node) != confgraph.adj_table[src_node].end()) { + removed.push_back(move); + } else { + if (src_node->degree < kMaxRegs && dest_node->degree < kMaxRegs) { + removed.push_back(move); + confgraph.pending_moves.insert(move); + new_pending_move_available = true; + } else if (src_node->is_binded_with_physical_reg && dest_node->is_binded_with_physical_reg) { + removed.push_back(move); + confgraph.pending_moves.insert(move); + new_pending_move_available = true; + } + } + } + // std::cerr << "removed size=" << removed.size() << std::endl; + for (auto move : removed) { + confgraph.potential_moves.erase(move); + } + } + if (!new_pending_move_available) { + Freeze(src, cfg, confgraph); + } } else if (confgraph.high_degree_nodes.size() > 0) { PotentailSpill(src, cfg, confgraph); } } while (confgraph.low_degree_and_not_move_related.size() > 0 || confgraph.pending_moves.size() > 0 || confgraph.low_degree_and_move_related.size() > 0 || confgraph.high_degree_nodes.size() > 0); // select and spill - return false; - if (confgraph.actual_spills.size() > 0) { - std::cerr << "spilled " << confgraph.actual_spills.size() << " nodes" << std::endl; - // allocate memory for spilled nodes - // rewrite the spilled nodes - return true; + size_t living_nodes = confgraph.nodes.size(); + for (auto node : confgraph.nodes) { + if (node->is_merged_into != node.get()) { + living_nodes--; + } } - return false; + living_nodes -= allocating_regs.size(); + if (living_nodes != confgraph.stack.size()) { + throw std::runtime_error("something strange happened: living_nodes!=confgraph.stack.size()"); + } + std::vector all_colors; + for (auto reg : allocating_regs) { + all_colors.push_back(std::stoi(reg.substr(1))); + } + while (confgraph.stack.size() > 0) { + auto node = confgraph.stack.back(); + confgraph.stack.pop_back(); + std::unordered_set available_colors; + for (auto color : all_colors) { + available_colors.insert(color); + } + for (auto neighbor : node->neighbors_half_available) { + if (!neighbor->is_binded_with_physical_reg) { + throw std::runtime_error("something strange happened: neighbor is not binded with physical reg"); + } + available_colors.erase(neighbor->color); + } + if (available_colors.size() > 0) { + node->color = *(available_colors.begin()); + JoinNode(node, confgraph); + node->is_binded_with_physical_reg = true; + } else { + confgraph.actual_spills.push_back(node); + } + } + std::cerr << "totally allocating " << confgraph.nodes.size() - allocating_regs.size() << " nodes" << std::endl; + std::cerr << living_nodes << std::endl; + std::cerr << "spilled " << confgraph.actual_spills.size() << " nodes" << std::endl; + // allocate memory for spilled nodes + // rewrite the spilled nodes + return false; // as our compiler always hold 4 extra registers in hand, the spilled nodes can be easily handled, so + // no need to run many iterations + // if (confgraph.actual_spills.size() > 0) { + // std::cerr << "spilled " << confgraph.actual_spills.size() << " nodes" << std::endl; + // // allocate memory for spilled nodes + // // rewrite the spilled nodes + // return true; + // } + // return false; } \ No newline at end of file diff --git a/src/opt/regalloc.cpp b/src/opt/regalloc.cpp index 473f5f8..1b577d7 100644 --- a/src/opt/regalloc.cpp +++ b/src/opt/regalloc.cpp @@ -136,13 +136,176 @@ void EnforcePhysicalRegs(CFGType &cfg) { entry_node->corresponding_block->actions.push_front(new_def); } } +void TranslateColorResult(std::shared_ptr func, CFGType &cfg, ConfGraph &confgraph) { + using namespace opt; + std::unordered_map spilled_var_to_id; + auto &var_to_id = cfg.var_to_id; + auto ApplyColoringResult = [&](std::string &var) { + auto confnode = confgraph.id_to_node[var_to_id[var]]; + confnode = ConfGraphNode::FindFather(confnode); + if (!confnode->is_binded_with_physical_reg) { + if (spilled_var_to_id.find(var) != spilled_var_to_id.end()) { + var = "#" + std::to_string(spilled_var_to_id[var]); + } else { + spilled_var_to_id[var] = func->spilled_vars++; + var = "#" + std::to_string(spilled_var_to_id[var]); + } + } else { + var = "$reg." + std::to_string(confnode->color); + } + }; + for (auto node : cfg.nodes) { + auto block = node->corresponding_block; + std::vector cur_node_use; + std::vector cur_node_def; + bool use_def_init = false; + func->spilled_vars = 0; + for (auto act : block->actions) { + if (auto br_act = std::dynamic_pointer_cast(act)) { + if (var_to_id.find(br_act->cond) != var_to_id.end()) { + ApplyColoringResult(br_act->cond); + } + } else if (auto ret_act = std::dynamic_pointer_cast(act)) { + if (!std::holds_alternative(ret_act->type) && var_to_id.find(ret_act->value) != var_to_id.end()) { + ApplyColoringResult(ret_act->value); + } + } else if (auto bin_act = std::dynamic_pointer_cast(act)) { + if (var_to_id.find(bin_act->operand1_full) != var_to_id.end()) { + ApplyColoringResult(bin_act->operand1_full); + } + if (var_to_id.find(bin_act->operand2_full) != var_to_id.end()) { + ApplyColoringResult(bin_act->operand2_full); + } + if (var_to_id.find(bin_act->result_full) != var_to_id.end()) { + ApplyColoringResult(bin_act->result_full); + } + } else if (auto load_act = std::dynamic_pointer_cast(act)) { + if (var_to_id.find(load_act->ptr_full) != var_to_id.end()) { + ApplyColoringResult(load_act->ptr_full); + } + if (var_to_id.find(load_act->result_full) != var_to_id.end()) { + ApplyColoringResult(load_act->result_full); + } + } else if (auto store_act = std::dynamic_pointer_cast(act)) { + if (var_to_id.find(store_act->value_full) != var_to_id.end()) { + ApplyColoringResult(store_act->value_full); + } + if (var_to_id.find(store_act->ptr_full) != var_to_id.end()) { + ApplyColoringResult(store_act->ptr_full); + } + } else if (auto get_act = std::dynamic_pointer_cast(act)) { + std::unordered_set used_vars; + if (var_to_id.find(get_act->ptr_full) != var_to_id.end()) { + ApplyColoringResult(get_act->ptr_full); + } + for (auto &idx : get_act->indices) { + if (var_to_id.find(idx) != var_to_id.end()) { + ApplyColoringResult(idx); + } + } + if (var_to_id.find(get_act->result_full) != var_to_id.end()) { + ApplyColoringResult(get_act->result_full); + } + } else if (auto icmp_act = std::dynamic_pointer_cast(act)) { + if (var_to_id.find(icmp_act->operand1_full) != var_to_id.end()) { + ApplyColoringResult(icmp_act->operand1_full); + } + if (var_to_id.find(icmp_act->operand2_full) != var_to_id.end()) { + ApplyColoringResult(icmp_act->operand2_full); + } + if (var_to_id.find(icmp_act->result_full) != var_to_id.end()) { + ApplyColoringResult(icmp_act->result_full); + } + } else if (auto call_act = std::dynamic_pointer_cast(act)) { + for (auto &arg : call_act->args_val_full) { + if (var_to_id.find(arg) != var_to_id.end()) { + ApplyColoringResult(arg); + } + } + if (!std::holds_alternative(call_act->return_type) && + var_to_id.find(call_act->result_full) != var_to_id.end()) { + ApplyColoringResult(call_act->result_full); + } + } else if (auto select_act = std::dynamic_pointer_cast(act)) { + if (var_to_id.find(select_act->cond_full) != var_to_id.end()) { + ApplyColoringResult(select_act->cond_full); + } + if (var_to_id.find(select_act->true_val_full) != var_to_id.end()) { + ApplyColoringResult(select_act->true_val_full); + } + if (var_to_id.find(select_act->false_val_full) != var_to_id.end()) { + ApplyColoringResult(select_act->false_val_full); + } + if (var_to_id.find(select_act->result_full) != var_to_id.end()) { + ApplyColoringResult(select_act->result_full); + } + } else if (auto move_act = std::dynamic_pointer_cast(act)) { + if (VRegCheck(move_act->src_full) && var_to_id.find(move_act->src_full) != var_to_id.end()) { + ApplyColoringResult(move_act->src_full); + } + if (var_to_id.find(move_act->dest_full) != var_to_id.end()) { + ApplyColoringResult(move_act->dest_full); + } + } else if (auto force_def_act = std::dynamic_pointer_cast(act)) { + if (var_to_id.find(force_def_act->var_full) != var_to_id.end()) { + ApplyColoringResult(force_def_act->var_full); + } + } else if (auto force_use_act = std::dynamic_pointer_cast(act)) { + if (var_to_id.find(force_use_act->var_full) != var_to_id.end()) { + ApplyColoringResult(force_use_act->var_full); + } + } else if (auto load_spilled_args_act = std::dynamic_pointer_cast(act)) { + if (var_to_id.find(load_spilled_args_act->var_full) != var_to_id.end()) { + ApplyColoringResult(load_spilled_args_act->var_full); + } + } else if (auto store_spilled_args_act = std::dynamic_pointer_cast(act)) { + if (var_to_id.find(store_spilled_args_act->var_full) != var_to_id.end()) { + ApplyColoringResult(store_spilled_args_act->var_full); + } + } else if (auto alloca_act = std::dynamic_pointer_cast(act)) { + ApplyColoringResult(alloca_act->name_full); + } + } + { + auto act = block->exit_action; + if (auto br_act = std::dynamic_pointer_cast(act)) { + if (var_to_id.find(br_act->cond) != var_to_id.end()) { + ApplyColoringResult(br_act->cond); + } + } else if (auto ret_act = std::dynamic_pointer_cast(act)) { + if (!std::holds_alternative(ret_act->type) && var_to_id.find(ret_act->value) != var_to_id.end()) { + ApplyColoringResult(ret_act->value); + } + } + } + for (auto act_it = block->actions.begin(); act_it != block->actions.end(); ++act_it) { + bool need_remove = false; + if (auto move_act = std::dynamic_pointer_cast(*act_it)) { + if (move_act->src_full == move_act->dest_full) { + need_remove = true; + } + } else if (auto force_def_act = std::dynamic_pointer_cast(*act_it)) { + need_remove = true; + } else if (auto force_use_act = std::dynamic_pointer_cast(*act_it)) { + need_remove = true; + } + if (need_remove) { + auto it_next = act_it; + ++it_next; + block->actions.erase(act_it); + act_it = it_next; + --act_it; + } + } + } +} void ConductRegAllocForFunction(std::shared_ptr func) { std::cerr << "processing function " << func->func_name_raw << std::endl; CFGType cfg; ConfGraph confgraph; cfg = BuildCFGForFunction(func); EnforcePhysicalRegs(cfg); - func->RecursivePrint(std::cerr); + // func->RecursivePrint(std::cerr); do { cfg.init(); cfg = BuildCFGForFunction(func); @@ -150,6 +313,8 @@ void ConductRegAllocForFunction(std::shared_ptr func) { confgraph.init(); confgraph = BuildConfGraph(cfg); } while (ConductColoring(func, cfg, confgraph)); + TranslateColorResult(func, cfg, confgraph); + func->RecursivePrint(std::cerr); } std::shared_ptr RegAlloc(std::shared_ptr src) {