half way of coloring
This commit is contained in:
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <cstddef>
|
||||||
#include "IR/IR_basic.h"
|
#include "IR/IR_basic.h"
|
||||||
#include "cfg.h"
|
#include "cfg.h"
|
||||||
class ConfGraphNode {
|
class ConfGraphNode {
|
||||||
@ -9,8 +10,17 @@ class ConfGraphNode {
|
|||||||
size_t degree;
|
size_t degree;
|
||||||
bool is_binded_with_physical_reg;
|
bool is_binded_with_physical_reg;
|
||||||
std::list<ConfGraphNode *> neighbors;
|
std::list<ConfGraphNode *> neighbors;
|
||||||
std::list<opt::MoveInstruct *> move_neighbors;
|
std::list<std::pair<ConfGraphNode *, opt::MoveInstruct *>> move_neighbors;
|
||||||
ConfGraphNode() = default;
|
|
||||||
|
// 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<ConfGraphNode *> neighbors_half_available;
|
||||||
|
std::list<ConfGraphNode *> neighbors_not_available;
|
||||||
};
|
};
|
||||||
class ConfGraph {
|
class ConfGraph {
|
||||||
public:
|
public:
|
||||||
@ -27,6 +37,7 @@ class ConfGraph {
|
|||||||
std::unordered_set<ConfGraphNode *> low_degree_and_move_related;
|
std::unordered_set<ConfGraphNode *> low_degree_and_move_related;
|
||||||
std::unordered_set<ConfGraphNode *> high_degree_nodes;
|
std::unordered_set<ConfGraphNode *> high_degree_nodes;
|
||||||
std::unordered_set<opt::MoveInstruct *> pending_moves;
|
std::unordered_set<opt::MoveInstruct *> pending_moves;
|
||||||
|
|
||||||
std::unordered_set<opt::MoveInstruct *> potential_moves;
|
std::unordered_set<opt::MoveInstruct *> potential_moves;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@ ConfGraph BuildConfGraph(CFGType &cfg) {
|
|||||||
res.id_to_node[id] = node.get();
|
res.id_to_node[id] = node.get();
|
||||||
res.nodes.push_back(node);
|
res.nodes.push_back(node);
|
||||||
node->is_binded_with_physical_reg = false;
|
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 (auto cfg_node : cfg.nodes) {
|
||||||
for (const auto &[act, out_active] : cfg_node->action_out_active_vars) {
|
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]->color = std::stoi(reg.substr(1));
|
||||||
res.id_to_node[reg_id]->degree = ConfGraphNode::kInf;
|
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<opt::MoveInstruct>(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;
|
return res;
|
||||||
}
|
}
|
||||||
const static size_t kMaxRegs = allocating_regs.size();
|
const static size_t kMaxRegs = allocating_regs.size();
|
||||||
void InitializeBeforeColoring(std::shared_ptr<FunctionDefItem> src, CFGType &cfg, ConfGraph &confgraph) {
|
void InitializeBeforeColoring([[maybe_unused]] std::shared_ptr<FunctionDefItem> src, [[maybe_unused]] CFGType &cfg,
|
||||||
|
ConfGraph &confgraph) {
|
||||||
confgraph.stack.clear();
|
confgraph.stack.clear();
|
||||||
confgraph.actual_spills.clear();
|
confgraph.actual_spills.clear();
|
||||||
|
|
||||||
@ -55,18 +69,137 @@ void InitializeBeforeColoring(std::shared_ptr<FunctionDefItem> src, CFGType &cfg
|
|||||||
|
|
||||||
confgraph.pending_moves.clear();
|
confgraph.pending_moves.clear();
|
||||||
confgraph.potential_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<FunctionDefItem> 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<FunctionDefItem> 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<ConfGraphNode *> 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<FunctionDefItem> 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<FunctionDefItem> 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<FunctionDefItem> src, CFGType &cfg, ConfGraph &confgraph) {
|
bool ConductColoring(std::shared_ptr<FunctionDefItem> src, CFGType &cfg, ConfGraph &confgraph) {
|
||||||
InitializeBeforeColoring(src, cfg, confgraph);
|
InitializeBeforeColoring(src, cfg, confgraph);
|
||||||
do {
|
do {
|
||||||
if (confgraph.low_degree_and_not_move_related.size() > 0) {
|
if (confgraph.low_degree_and_not_move_related.size() > 0) {
|
||||||
// simplify
|
Simplify(src, cfg, confgraph);
|
||||||
} else if (confgraph.pending_moves.size() > 0) {
|
} else if (confgraph.pending_moves.size() > 0) {
|
||||||
// coalesce
|
Coalesce(src, cfg, confgraph);
|
||||||
} else if (confgraph.low_degree_and_move_related.size() > 0) {
|
} else if (confgraph.low_degree_and_move_related.size() > 0) {
|
||||||
// freeze
|
Freeze(src, cfg, confgraph);
|
||||||
} else if (confgraph.high_degree_nodes.size() > 0) {
|
} 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 ||
|
} 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);
|
confgraph.low_degree_and_move_related.size() > 0 || confgraph.high_degree_nodes.size() > 0);
|
||||||
@ -74,6 +207,7 @@ bool ConductColoring(std::shared_ptr<FunctionDefItem> src, CFGType &cfg, ConfGra
|
|||||||
if (confgraph.actual_spills.size() > 0) {
|
if (confgraph.actual_spills.size() > 0) {
|
||||||
std::cerr << "spilled " << confgraph.actual_spills.size() << " nodes" << std::endl;
|
std::cerr << "spilled " << confgraph.actual_spills.size() << " nodes" << std::endl;
|
||||||
// allocate memory for spilled nodes
|
// allocate memory for spilled nodes
|
||||||
|
// rewrite the spilled nodes
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
Reference in New Issue
Block a user