diff --git a/include/opt/confgraph.h b/include/opt/confgraph.h index e748033..d509587 100644 --- a/include/opt/confgraph.h +++ b/include/opt/confgraph.h @@ -1,4 +1,5 @@ #pragma once +#include #include "IR/IR_basic.h" #include "cfg.h" class ConfGraphNode { @@ -9,8 +10,17 @@ class ConfGraphNode { size_t degree; bool is_binded_with_physical_reg; std::list neighbors; - std::list move_neighbors; - ConfGraphNode() = default; + std::list> move_neighbors; + + // the following are for graph maintenance + ConfGraphNode *is_merged_into; + static ConfGraphNode *FindFather(ConfGraphNode *x) { + if (x->is_merged_into == x) return x; + return x->is_merged_into = FindFather(x->is_merged_into); + } + bool is_temporarily_removed; + std::list neighbors_half_available; + std::list neighbors_not_available; }; class ConfGraph { public: @@ -27,6 +37,7 @@ class ConfGraph { std::unordered_set low_degree_and_move_related; std::unordered_set high_degree_nodes; std::unordered_set pending_moves; + std::unordered_set potential_moves; }; diff --git a/src/opt/confgraph.cpp b/src/opt/confgraph.cpp index 5ea502d..966e732 100644 --- a/src/opt/confgraph.cpp +++ b/src/opt/confgraph.cpp @@ -14,6 +14,8 @@ ConfGraph BuildConfGraph(CFGType &cfg) { res.id_to_node[id] = node.get(); res.nodes.push_back(node); node->is_binded_with_physical_reg = false; + node->is_merged_into = node.get(); // the same as `fa` in DSU + node->is_temporarily_removed = false; } for (auto cfg_node : cfg.nodes) { for (const auto &[act, out_active] : cfg_node->action_out_active_vars) { @@ -42,10 +44,22 @@ ConfGraph BuildConfGraph(CFGType &cfg) { res.id_to_node[reg_id]->color = std::stoi(reg.substr(1)); res.id_to_node[reg_id]->degree = ConfGraphNode::kInf; } + for (auto cfg_node : cfg.nodes) { + auto block = cfg_node->corresponding_block; + for (auto act : block->actions) { + if (auto move_act = std::dynamic_pointer_cast(act)) { + size_t src_id = cfg.var_to_id[move_act->src_full]; + size_t dest_id = cfg.var_to_id[move_act->dest_full]; + res.id_to_node[src_id]->move_neighbors.push_back({res.id_to_node[dest_id], move_act.get()}); + res.id_to_node[dest_id]->move_neighbors.push_back({res.id_to_node[src_id], move_act.get()}); + } + } + } return res; } const static size_t kMaxRegs = allocating_regs.size(); -void InitializeBeforeColoring(std::shared_ptr src, CFGType &cfg, ConfGraph &confgraph) { +void InitializeBeforeColoring([[maybe_unused]] std::shared_ptr src, [[maybe_unused]] CFGType &cfg, + ConfGraph &confgraph) { confgraph.stack.clear(); confgraph.actual_spills.clear(); @@ -55,18 +69,137 @@ void InitializeBeforeColoring(std::shared_ptr src, CFGType &cfg confgraph.pending_moves.clear(); confgraph.potential_moves.clear(); + for (auto confg_node : confgraph.nodes) { + for (auto [move_neighbor, move] : confg_node->move_neighbors) { + if (confgraph.adj_table[confg_node.get()].find(move_neighbor) == confgraph.adj_table[confg_node.get()].end()) { + if (confg_node->degree < kMaxRegs && move_neighbor->degree < kMaxRegs) { + confgraph.pending_moves.insert(move); + } else if (confg_node->is_binded_with_physical_reg || move_neighbor->is_binded_with_physical_reg) { + if (confg_node->is_binded_with_physical_reg && move_neighbor->is_binded_with_physical_reg) + throw std::runtime_error( + "something strange happened: at the beginning two physical registers are directly move related"); + confgraph.pending_moves.insert(move); + } else { + confgraph.potential_moves.insert(move); + } + } else { + // do nothing + } + } + if (confg_node->degree < kMaxRegs) { + if (confg_node->move_neighbors.size() == 0) { + confgraph.low_degree_and_not_move_related.insert(confg_node.get()); + } else { + confgraph.low_degree_and_move_related.insert(confg_node.get()); + } + } else if (!confg_node->is_binded_with_physical_reg) { + confgraph.high_degree_nodes.insert(confg_node.get()); + } + } +} + +void DetachNode(ConfGraphNode *node, ConfGraph &confgraph, bool during_selecting = false) { + // 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 +} + +void JoinNode(ConfGraphNode *node, ConfGraph &confgraph, bool during_selecting = false) { + // 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 +} + +void MergeNodeInto(ConfGraphNode *node, ConfGraphNode *target, ConfGraph &confgraph) { + // this function operates on both the conflict graph and the move link graph, and the effect is permanent + // It is also responsible for maintaining all the changes caused by the merge of the node +} + +void Simplify(std::shared_ptr src, CFGType &cfg, ConfGraph &confgraph) { + auto u = *(confgraph.low_degree_and_not_move_related.begin()); + confgraph.low_degree_and_not_move_related.erase(u); + DetachNode(u, confgraph); + confgraph.stack.push_back(u); +} + +void Coalesce(std::shared_ptr src, CFGType &cfg, ConfGraph &confgraph) { + auto move = *(confgraph.pending_moves.begin()); + confgraph.pending_moves.erase(move); + size_t src_id = cfg.var_to_id[move->src_full]; + size_t dest_id = cfg.var_to_id[move->dest_full]; + auto src_node = confgraph.id_to_node[src_id]; + auto dest_node = confgraph.id_to_node[dest_id]; + 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 + return; + } + if (src_node->is_binded_with_physical_reg && dest_node->is_binded_with_physical_reg) + throw std::runtime_error("something strange happened: two physical registers do not conflict"); + if (src_node->is_binded_with_physical_reg || dest_node->is_binded_with_physical_reg) { + // George condition + if (src_node->is_binded_with_physical_reg) { + std::swap(src_node, dest_node); + } + bool condition_satisfied = true; + for (auto t : src_node->neighbors) { + if (t->degree >= kMaxRegs && confgraph.adj_table[t].find(dest_node) == confgraph.adj_table[t].end()) { + condition_satisfied = false; + break; + } + } + if (condition_satisfied) { + MergeNodeInto(src_node, dest_node, confgraph); + } else { + confgraph.pending_moves.insert(move); + } + } else { + // Briggs condition + std::unordered_set dangerous_neighbors; + for (auto t : src_node->neighbors) { + if (t != dest_node && t->degree >= kMaxRegs) { + dangerous_neighbors.insert(t); + } + } + for (auto t : dest_node->neighbors) { + if (t != src_node && t->degree >= kMaxRegs) { + dangerous_neighbors.insert(t); + } + } + if (dangerous_neighbors.size() < kMaxRegs) { + MergeNodeInto(src_node, dest_node, confgraph); + } else { + confgraph.pending_moves.insert(move); + } + } +} + +void Freeze(std::shared_ptr src, CFGType &cfg, ConfGraph &confgraph) { + auto u = *confgraph.low_degree_and_move_related.begin(); + confgraph.low_degree_and_move_related.erase(u); + confgraph.low_degree_and_not_move_related.insert(u); + for (auto [_, ins] : u->move_neighbors) { + confgraph.potential_moves.erase(ins); + } +} + +void PotentailSpill(std::shared_ptr src, CFGType &cfg, ConfGraph &confgraph) { + auto u = *confgraph.high_degree_nodes.begin(); + confgraph.high_degree_nodes.erase(u); + DetachNode(u, confgraph); + confgraph.stack.push_back(u); } bool ConductColoring(std::shared_ptr src, CFGType &cfg, ConfGraph &confgraph) { InitializeBeforeColoring(src, cfg, confgraph); do { if (confgraph.low_degree_and_not_move_related.size() > 0) { - // simplify + Simplify(src, cfg, confgraph); } else if (confgraph.pending_moves.size() > 0) { - // coalesce + Coalesce(src, cfg, confgraph); } else if (confgraph.low_degree_and_move_related.size() > 0) { - // freeze + Freeze(src, cfg, confgraph); } else if (confgraph.high_degree_nodes.size() > 0) { - // potential spill + 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); @@ -74,6 +207,7 @@ bool ConductColoring(std::shared_ptr src, CFGType &cfg, ConfGra 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;