#include "confgraph.h" #include #include #include #include #include #include "cfg.h" ConfGraph BuildConfGraph(CFGType &cfg) { std::unordered_map> edges; ConfGraph res; for (size_t id = 0; id < cfg.id_to_var.size(); id++) { auto node = std::make_shared(); node->var_ids.push_back(id); 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) { const auto &def_vars = cfg_node->action_def_vars[act]; for (auto def_var : def_vars) { for (auto out_var : out_active) { edges[res.id_to_node[def_var]].insert(res.id_to_node[out_var]); edges[res.id_to_node[out_var]].insert(res.id_to_node[def_var]); } } } } for (const auto &[u, neighbors] : edges) { for (auto v : neighbors) { if (u == v) continue; u->neighbors.push_back(v); res.adj_table[u][v] = std::prev(u->neighbors.end()); // { // std::string u_name = cfg.id_to_var[u->var_ids.front()]; // std::string v_name = cfg.id_to_var[v->var_ids.front()]; // std::cerr << "edge between " << u_name << " and " << v_name << std::endl; // } } u->neighbors.sort(); } for (auto node : res.nodes) { node->degree = node->neighbors.size(); } for (auto reg : allocating_regs) { 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; // 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)) { if (!VRegCheck(move_act->src_full)) continue; if (cfg.var_to_id.find(move_act->src_full) == cfg.var_to_id.end()) { move_act->src_full = "0"; continue; move_act->RecursivePrint(std::cerr); std::cerr << std::endl; throw std::runtime_error("move_act->src_full not found in var_to_id"); } if (cfg.var_to_id.find(move_act->dest_full) == cfg.var_to_id.end()) { throw std::runtime_error("move_act->dest_full not found in var_to_id"); } 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]->original_move_neighbors.push_back({res.id_to_node[dest_id], move_act.get()}); res.id_to_node[dest_id]->original_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([[maybe_unused]] std::shared_ptr src, [[maybe_unused]] CFGType &cfg, ConfGraph &confgraph) { confgraph.stack.clear(); confgraph.actual_spills.clear(); confgraph.low_degree_and_not_move_related.clear(); confgraph.low_degree_and_move_related.clear(); confgraph.high_degree_nodes.clear(); // note that physical registers are not included in this set confgraph.pending_moves.clear(); confgraph.potential_moves.clear(); for (auto confg_node : confgraph.nodes) { for (auto [move_neighbor, move] : confg_node->original_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) { std::cerr << confg_node->var_ids.front() << " " << move_neighbor->var_ids.front() << std::endl; std::cerr << confg_node->color << " " << move_neighbor->color << std::endl; move->RecursivePrint(std::cerr); std::cerr << std::endl; 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->is_binded_with_physical_reg) { if (confg_node->degree < kMaxRegs) { if (confg_node->original_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 { confgraph.high_degree_nodes.insert(confg_node.get()); } } } } void DetachNode(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 temporarily removed node is removed"); 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; 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_not_available.push_back(node); confgraph.adj_table_not_available[neighbor][node] = std::prev(neighbor->neighbors_not_available.end()); node->neighbors_not_available.push_back(neighbor); confgraph.adj_table_not_available[node][neighbor] = std::prev(node->neighbors_not_available.end()); } node->neighbors_half_available.clear(); for (auto neighbor : node->neighbors) { if (neighbor == node) throw std::runtime_error("something strange happened: a node is its own neighbor"); neighbor->neighbors.erase(confgraph.adj_table[neighbor][node]); confgraph.adj_table[neighbor].erase(node); neighbor->degree = neighbor->neighbors.size(); confgraph.low_degree_and_not_move_related.erase(neighbor); confgraph.low_degree_and_move_related.erase(neighbor); confgraph.high_degree_nodes.erase(neighbor); if (!neighbor->is_binded_with_physical_reg) { if (neighbor->degree >= kMaxRegs) { confgraph.high_degree_nodes.insert(neighbor); } else { confgraph.low_degree_and_move_related.insert(neighbor); // it may be wrong, but it is safe } } // node->neighbors.erase(confgraph.adj_table[node][neighbor]); confgraph.adj_table[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.clear(); } 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) { // 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 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; confgraph.low_degree_and_move_related.erase(node); confgraph.low_degree_and_not_move_related.erase(node); confgraph.high_degree_nodes.erase(node); node->is_merged_into = target; target->var_ids.splice(target->var_ids.end(), node->var_ids); for (auto neighbor : node->neighbors) { if (neighbor == target) continue; if (confgraph.adj_table[target].find(neighbor) == confgraph.adj_table[target].end()) { target->neighbors.push_back(neighbor); confgraph.adj_table[target][neighbor] = std::prev(target->neighbors.end()); neighbor->neighbors.push_back(target); confgraph.adj_table[neighbor][target] = std::prev(neighbor->neighbors.end()); } neighbor->neighbors.erase(confgraph.adj_table[neighbor][node]); // node->neighbors.erase(confgraph.adj_table[node][neighbor]); confgraph.adj_table[neighbor].erase(node); confgraph.adj_table[node].erase(neighbor); neighbor->degree = neighbor->neighbors.size(); confgraph.low_degree_and_not_move_related.erase(neighbor); confgraph.low_degree_and_move_related.erase(neighbor); confgraph.high_degree_nodes.erase(neighbor); if (!neighbor->is_binded_with_physical_reg) { if (neighbor->degree >= kMaxRegs) { confgraph.high_degree_nodes.insert(neighbor); } else { confgraph.low_degree_and_move_related.insert(neighbor); // it may be wrong, but it is safe } } } node->neighbors.clear(); for (auto neighbor : node->neighbors_half_available) { if (neighbor == target) continue; if (confgraph.adj_table_half_available[target].find(neighbor) == confgraph.adj_table_half_available[target].end()) { target->neighbors_half_available.push_back(neighbor); confgraph.adj_table_half_available[target][neighbor] = std::prev(target->neighbors_half_available.end()); neighbor->neighbors_half_available.push_back(target); confgraph.adj_table_half_available[neighbor][target] = std::prev(neighbor->neighbors_half_available.end()); } neighbor->neighbors_half_available.erase(confgraph.adj_table_half_available[neighbor][node]); // node->neighbors_half_available.erase(confgraph.adj_table_half_available[node][neighbor]); confgraph.adj_table_half_available[neighbor].erase(node); confgraph.adj_table_half_available[node].erase(neighbor); } node->neighbors_half_available.clear(); if (node->neighbors_not_available.size() > 0) { throw std::runtime_error( "something strange happened: neighbors_not_available is not empty in function MergeNodeInto"); } target->degree = target->neighbors.size(); if (!target->is_binded_with_physical_reg) { if (target->degree >= kMaxRegs) { confgraph.high_degree_nodes.insert(target); } else { confgraph.low_degree_and_move_related.insert(target); // it may be wrong, but it is safe } } } 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); confgraph.awful_moves.clear(); } 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]; src_node = ConfGraphNode::FindFather(src_node); auto dest_node = confgraph.id_to_node[dest_id]; dest_node = ConfGraphNode::FindFather(dest_node); 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 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); confgraph.awful_moves.clear(); } else { confgraph.potential_moves.insert(move); confgraph.awful_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); confgraph.awful_moves.clear(); } else { confgraph.potential_moves.insert(move); confgraph.awful_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->original_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); confgraph.awful_moves.clear(); } void GraphCheck(ConfGraph &confgraph) { for (auto node : confgraph.nodes) { if (node->is_merged_into != node.get()) continue; if (node->is_temporarily_removed) { if (node->neighbors.size() > 0) throw std::runtime_error("something strange happened: a temporarily removed node has neighbors"); if (node->neighbors_half_available.size() != confgraph.adj_table_half_available[node.get()].size()) { throw std::runtime_error( "something strange happened: " "node->neighbors_half_available.size()!=confgraph.adj_table_half_available[node].size()"); } for (auto neighbor : node->neighbors_half_available) { if (confgraph.adj_table_half_available[neighbor].find(node.get()) == confgraph.adj_table_half_available[neighbor].end()) { throw std::runtime_error( "something strange happened: neighbor->neighbors_half_available does not contain node"); } } if (node->neighbors_not_available.size() != confgraph.adj_table_not_available[node.get()].size()) { throw std::runtime_error( "something strange happened: " "node->neighbors_not_available.size()!=confgraph.adj_table_not_available[node].size()"); } for (auto neighbor : node->neighbors_not_available) { if (confgraph.adj_table_not_available[neighbor].find(node.get()) == confgraph.adj_table_not_available[neighbor].end()) { throw std::runtime_error( "something strange happened: neighbor->neighbors_not_available does not contain node"); } } } else { if (node->neighbors_not_available.size() > 0) { throw std::runtime_error("something strange happened: a node has neighbors_not_available"); } if (node->neighbors.size() != confgraph.adj_table[node.get()].size()) { throw std::runtime_error( "something strange happened: node->neighbors.size()!=confgraph.adj_table[node].size()"); } for (auto neighbor : node->neighbors) { if (confgraph.adj_table[neighbor].find(node.get()) == confgraph.adj_table[neighbor].end()) { throw std::runtime_error("something strange happened: neighbor->neighbors does not contain node"); } } if (node->neighbors_half_available.size() != confgraph.adj_table_half_available[node.get()].size()) { throw std::runtime_error( "something strange happened: " "node->neighbors_half_available.size()!=confgraph.adj_table_half_available[node].size()"); } for (auto neighbor : node->neighbors_half_available) { if (confgraph.adj_table_half_available[neighbor].find(node.get()) == confgraph.adj_table_half_available[neighbor].end()) { throw std::runtime_error( "something strange happened: neighbor->neighbors_half_available does not contain node"); } } if (node->degree != node->neighbors.size()) { throw std::runtime_error("something strange happened: node->degree!=node->neighbors.size()"); } } } } bool ConductColoring(std::shared_ptr src, CFGType &cfg, ConfGraph &confgraph) { 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"); // } // } 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"); } if (cfg.id_to_var.size() != confgraph.id_to_node.size()) { throw std::runtime_error("something strange happened: id_to_var and confgraph.nodes do not match"); } for (size_t i = 0; i < cfg.id_to_var.size(); i++) { if (confgraph.id_to_node[i]->var_ids.size() != 1) throw std::runtime_error("something strange happened: id_to_node.size()!=1"); if (confgraph.id_to_node[i]->var_ids.front() != i) throw std::runtime_error("something strange happened: id_to_node[0]!=i"); } InitializeBeforeColoring(src, cfg, confgraph); size_t round_counter = 0; do { // std::cerr << std::endl << "\n\na new round begins " << ++round_counter << std::endl; // std::cerr << "confgraph.low_degree_and_not_move_related.size()=" << // confgraph.low_degree_and_not_move_related.size() // << std::endl; // std::cerr << "confgraph.pending_moves.size()=" << confgraph.pending_moves.size() << std::endl; // std::cerr << "confgraph.low_degree_and_move_related.size()=" << confgraph.low_degree_and_move_related.size() // << std::endl; // std::cerr << "confgraph.high_degree_nodes.size()=" << confgraph.high_degree_nodes.size() << std::endl; // std::cerr << "confgraph.potential_moves.size()=" << confgraph.potential_moves.size() << std::endl; // std::cerr << "pending moves" << std::endl; // for (auto mode : confgraph.pending_moves) { // std::cerr << '\t'; // mode->RecursivePrint(std::cerr); // } // std::cerr << std::endl; // std::cerr << "potential moves" << std::endl; // for (auto mode : confgraph.potential_moves) { // std::cerr << '\t'; // mode->RecursivePrint(std::cerr); // } // std::cerr << std::endl; // GraphCheck(confgraph); for (auto node : confgraph.low_degree_and_not_move_related) { if (node->is_binded_with_physical_reg) { throw std::runtime_error("something strange happened: node is binded with physical reg"); } } for (auto node : confgraph.low_degree_and_move_related) { if (node->is_binded_with_physical_reg) { throw std::runtime_error("something strange happened: node is binded with physical reg"); } } for (auto node : confgraph.high_degree_nodes) { if (node->is_binded_with_physical_reg) { throw std::runtime_error("something strange happened: node is binded with physical reg"); } } if (confgraph.low_degree_and_not_move_related.size() > 0) { Simplify(src, cfg, confgraph); } else if (confgraph.pending_moves.size() > 0) { Coalesce(src, cfg, confgraph); } else if (confgraph.low_degree_and_move_related.size() > 0) { bool new_pending_move_available = false; if (confgraph.potential_moves.size() > 0) { std::vector removed; for (auto move : confgraph.potential_moves) { if (confgraph.awful_moves.find(move) != confgraph.awful_moves.end()) { continue; } 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 size_t living_nodes = confgraph.nodes.size(); for (auto node : confgraph.nodes) { if (node->is_merged_into != node.get()) { living_nodes--; } } 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; }