diff --git a/include/opt/cfg.h b/include/opt/cfg.h index f5e10c2..c142057 100644 --- a/include/opt/cfg.h +++ b/include/opt/cfg.h @@ -38,6 +38,15 @@ class CFGType { std::vector id_to_var; std::unordered_map var_to_id; FunctionDefItem *corresponding_func; + void init() { + nodes.clear(); + entry = nullptr; + block_to_node.clear(); + label_to_block.clear(); + id_to_var.clear(); + var_to_id.clear(); + corresponding_func = nullptr; + } }; namespace opt { @@ -48,7 +57,7 @@ class MoveInstruct : public ActionItem { LLVMType ty; MoveInstruct() = default; void RecursivePrint([[maybe_unused]] std::ostream &os) const { - throw std::runtime_error("Move instruction is not an actual LLVM IR instruction"); + os << "[Persudo] " << dest_full << " <-- " << src_full << "\n"; } }; } // namespace opt @@ -161,4 +170,9 @@ const static std::vector caller_saved_regs = {"x5", "x6", "x7", const static std::vector arg_regs = {"x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17"}; const static std::vector allocating_regs = {"x3", "x4", "x9", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x5", "x6", "x7", - "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17"}; \ No newline at end of file + "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17"}; + +inline bool VRegCheck(const std::string &s) { + if (s[0] != '%') return false; + return true; +} \ No newline at end of file diff --git a/include/opt/confgraph.h b/include/opt/confgraph.h index d509587..f666edf 100644 --- a/include/opt/confgraph.h +++ b/include/opt/confgraph.h @@ -5,12 +5,11 @@ class ConfGraphNode { public: const static size_t kInf = (std::numeric_limits::max()) >> 2; - std::vector var_ids; + std::list var_ids; size_t color; size_t degree; bool is_binded_with_physical_reg; std::list neighbors; - std::list> move_neighbors; // the following are for graph maintenance ConfGraphNode *is_merged_into; @@ -21,6 +20,7 @@ class ConfGraphNode { bool is_temporarily_removed; std::list neighbors_half_available; std::list neighbors_not_available; + std::list> original_move_neighbors; }; class ConfGraph { public: @@ -39,6 +39,24 @@ class ConfGraph { std::unordered_set pending_moves; std::unordered_set potential_moves; + std::unordered_map::iterator>> + adj_table_half_available; + std::unordered_map::iterator>> + adj_table_not_available; + void init() { + id_to_node.clear(); + nodes.clear(); + adj_table.clear(); + stack.clear(); + actual_spills.clear(); + low_degree_and_not_move_related.clear(); + low_degree_and_move_related.clear(); + high_degree_nodes.clear(); + pending_moves.clear(); + potential_moves.clear(); + adj_table_half_available.clear(); + adj_table_not_available.clear(); + } }; ConfGraph BuildConfGraph(CFGType &cfg); diff --git a/include/opt/liveanalysis.h b/include/opt/liveanalysis.h index 4e45a3c..e8ca237 100644 --- a/include/opt/liveanalysis.h +++ b/include/opt/liveanalysis.h @@ -11,17 +11,13 @@ class ForceDef : public ActionItem { std::string var_full; LLVMType ty; ForceDef() = default; - void RecursivePrint(std::ostream &os) const { - throw std::runtime_error("ForceDef instruction is not an actual LLVM IR instruction"); - } + void RecursivePrint(std::ostream &os) const { os << "[Persudo] def " << var_full << "\n"; } }; class ForceUse : public ActionItem { public: std::string var_full; ForceUse() = default; - void RecursivePrint(std::ostream &os) const { - throw std::runtime_error("ForceUse instruction is not an actual LLVM IR instruction"); - } + void RecursivePrint(std::ostream &os) const { os << "[Persudo] use " << var_full << "\n"; } }; class LoadSpilledArgs : public ActionItem { public: @@ -30,7 +26,7 @@ class LoadSpilledArgs : public ActionItem { LLVMType ty; LoadSpilledArgs() = default; void RecursivePrint(std::ostream &os) const { - throw std::runtime_error("LoadSpilledArgs instruction is not an actual LLVM IR instruction"); + os << "[Persudo] load spilled args " << var_full << "with id=" << arg_id << "\n"; } }; @@ -41,7 +37,7 @@ class StoreSpilledArgs : public ActionItem { LLVMType ty; StoreSpilledArgs() = default; void RecursivePrint(std::ostream &os) const { - throw std::runtime_error("StoreSpilledArgs instruction is not an actual LLVM IR instruction"); + os << "[Persudo] store spilled args " << var_full << "with id=" << arg_id << "\n"; } }; } // namespace opt \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 38e8f0f..d070a68 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -48,6 +48,7 @@ int main(int argc, char **argv) { auto IR_with_out_allocas = Mem2Reg(IR); IR_with_out_allocas->RecursivePrint(fout); auto IR_with_out_phis = PhiEliminate(IR_with_out_allocas); + // IR_with_out_phis->RecursivePrint(fout); auto alloced_code = RegAlloc(IR_with_out_phis); } } catch (const SemanticError &err) { diff --git a/src/opt/cfg.cpp b/src/opt/cfg.cpp index 1c1a198..107f3cc 100644 --- a/src/opt/cfg.cpp +++ b/src/opt/cfg.cpp @@ -3,23 +3,20 @@ CFGType BuildCFGForFunction(const std::shared_ptr &func) { CFGType res; - auto init_block = func->init_block; - if (!func->init_block) { - // throw std::runtime_error("Function does not have an init block"); - if (func->basic_blocks.size() == 0) throw std::runtime_error("Function does not have any block"); - init_block = func->basic_blocks[0]; + if (func->init_block) { + res.label_to_block[func->init_block->label_full] = func->init_block.get(); + res.nodes.push_back(std::make_shared()); + res.entry = res.nodes.back().get(); + res.entry->corresponding_block = func->init_block.get(); + res.block_to_node[func->init_block.get()] = res.entry; } - res.label_to_block[init_block->label_full] = init_block.get(); - res.nodes.push_back(std::make_shared()); - res.entry = res.nodes.back().get(); - res.entry->corresponding_block = init_block.get(); - res.block_to_node[init_block.get()] = res.entry; for (auto block_ptr : func->basic_blocks) { res.label_to_block[block_ptr->label_full] = block_ptr.get(); res.nodes.push_back(std::make_shared()); res.nodes.back()->corresponding_block = block_ptr.get(); res.block_to_node[block_ptr.get()] = res.nodes.back().get(); } + res.entry = res.nodes.front().get(); // now add information for successors and predecessors for (auto node : res.nodes) { auto block = node->corresponding_block; diff --git a/src/opt/confgraph.cpp b/src/opt/confgraph.cpp index 966e732..267cbaa 100644 --- a/src/opt/confgraph.cpp +++ b/src/opt/confgraph.cpp @@ -30,6 +30,7 @@ ConfGraph BuildConfGraph(CFGType &cfg) { } 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()); } @@ -42,16 +43,26 @@ 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; 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->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]->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()}); + 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()}); } } } @@ -70,14 +81,19 @@ void InitializeBeforeColoring([[maybe_unused]] std::shared_ptr confgraph.pending_moves.clear(); confgraph.potential_moves.clear(); for (auto confg_node : confgraph.nodes) { - for (auto [move_neighbor, move] : confg_node->move_neighbors) { + 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) + 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); @@ -87,7 +103,7 @@ void InitializeBeforeColoring([[maybe_unused]] std::shared_ptr } } if (confg_node->degree < kMaxRegs) { - if (confg_node->move_neighbors.size() == 0) { + 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()); @@ -98,13 +114,59 @@ void InitializeBeforeColoring([[maybe_unused]] std::shared_ptr } } -void DetachNode(ConfGraphNode *node, ConfGraph &confgraph, bool during_selecting = false) { +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, bool during_selecting = false) { +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 @@ -113,6 +175,74 @@ void JoinNode(ConfGraphNode *node, ConfGraph &confgraph, bool during_selecting = 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) { @@ -128,7 +258,12 @@ void Coalesce(std::shared_ptr src, CFGType &cfg, ConfGraph &con 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 (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 @@ -151,7 +286,7 @@ void Coalesce(std::shared_ptr src, CFGType &cfg, ConfGraph &con if (condition_satisfied) { MergeNodeInto(src_node, dest_node, confgraph); } else { - confgraph.pending_moves.insert(move); + confgraph.potential_moves.insert(move); } } else { // Briggs condition @@ -169,7 +304,7 @@ void Coalesce(std::shared_ptr src, CFGType &cfg, ConfGraph &con if (dangerous_neighbors.size() < kMaxRegs) { MergeNodeInto(src_node, dest_node, confgraph); } else { - confgraph.pending_moves.insert(move); + confgraph.potential_moves.insert(move); } } } @@ -178,7 +313,7 @@ void Freeze(std::shared_ptr src, CFGType &cfg, ConfGraph &confg 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) { + for (auto [_, ins] : u->original_move_neighbors) { confgraph.potential_moves.erase(ins); } } @@ -190,8 +325,52 @@ void PotentailSpill(std::shared_ptr src, CFGType &cfg, ConfGrap confgraph.stack.push_back(u); } 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); do { + // std::cerr << 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; + 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) { @@ -204,6 +383,7 @@ bool ConductColoring(std::shared_ptr src, CFGType &cfg, ConfGra } 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 diff --git a/src/opt/liveanalysis.cpp b/src/opt/liveanalysis.cpp index 67a085d..71cfda2 100644 --- a/src/opt/liveanalysis.cpp +++ b/src/opt/liveanalysis.cpp @@ -7,41 +7,46 @@ using namespace opt; void VarCollect(CFGType &cfg, std::vector &id_to_var, std::unordered_map &var_to_id) { + auto TryAddVar = [&](const std::string &var) { + if (var_to_id.find(var) == var_to_id.end()) { + id_to_var.push_back(var); + var_to_id[var] = id_to_var.size() - 1; + } + }; for (auto node : cfg.nodes) { auto block = node->corresponding_block; for (auto act : block->actions) { if (auto bin_act = std::dynamic_pointer_cast(act)) { - id_to_var.push_back(bin_act->result_full); - var_to_id[bin_act->result_full] = id_to_var.size() - 1; + TryAddVar(bin_act->result_full); } else if (auto load_act = std::dynamic_pointer_cast(act)) { - id_to_var.push_back(load_act->result_full); - var_to_id[load_act->result_full] = id_to_var.size() - 1; + TryAddVar(load_act->result_full); } else if (auto get_act = std::dynamic_pointer_cast(act)) { - id_to_var.push_back(get_act->result_full); - var_to_id[get_act->result_full] = id_to_var.size() - 1; + TryAddVar(get_act->result_full); } else if (auto icmp_act = std::dynamic_pointer_cast(act)) { - id_to_var.push_back(icmp_act->result_full); - var_to_id[icmp_act->result_full] = id_to_var.size() - 1; + TryAddVar(icmp_act->result_full); + ; } else if (auto call_act = std::dynamic_pointer_cast(act)) { if (!std::holds_alternative(call_act->return_type)) { - id_to_var.push_back(call_act->result_full); - var_to_id[call_act->result_full] = id_to_var.size() - 1; + TryAddVar(call_act->result_full); } } else if (auto select_act = std::dynamic_pointer_cast(act)) { - id_to_var.push_back(select_act->result_full); - var_to_id[select_act->result_full] = id_to_var.size() - 1; + TryAddVar(select_act->result_full); } else if (auto move_act = std::dynamic_pointer_cast(act)) { - id_to_var.push_back(move_act->dest_full); - var_to_id[move_act->dest_full] = id_to_var.size() - 1; + TryAddVar(move_act->dest_full); } else if (auto force_def_act = std::dynamic_pointer_cast(act)) { - id_to_var.push_back(force_def_act->var_full); - var_to_id[force_def_act->var_full] = id_to_var.size() - 1; + TryAddVar(force_def_act->var_full); } else if (auto load_spilled_args_act = std::dynamic_pointer_cast(act)) { - id_to_var.push_back(load_spilled_args_act->var_full); - var_to_id[load_spilled_args_act->var_full] = id_to_var.size() - 1; + TryAddVar(load_spilled_args_act->var_full); + } else if (auto alloca_act = std::dynamic_pointer_cast(act)) { + TryAddVar(alloca_act->name_full); } } } + for (size_t i = 0; i < id_to_var.size(); i++) { + if (var_to_id.find(id_to_var[i]) == var_to_id.end()) + throw std::runtime_error("var_to_id.find(id_to_var[i])==var_to_id.end()"); + if (i != var_to_id[id_to_var[i]]) throw std::runtime_error("i!=var_to_id[id_to_var[i]]"); + } } void UseDefCollect(CFGType &cfg, [[maybe_unused]] std::vector &id_to_var, @@ -146,7 +151,7 @@ void UseDefCollect(CFGType &cfg, [[maybe_unused]] std::vector &id_t cur_act_def.push_back(var_to_id[select_act->result_full]); } } else if (auto move_act = std::dynamic_pointer_cast(act)) { - if (var_to_id.find(move_act->src_full) != var_to_id.end()) { + if (VRegCheck(move_act->src_full) && var_to_id.find(move_act->src_full) != var_to_id.end()) { cur_act_use.push_back(var_to_id[move_act->src_full]); } if (var_to_id.find(move_act->dest_full) != var_to_id.end()) { @@ -168,6 +173,8 @@ void UseDefCollect(CFGType &cfg, [[maybe_unused]] std::vector &id_t if (var_to_id.find(store_spilled_args_act->var_full) != var_to_id.end()) { cur_act_use.push_back(var_to_id[store_spilled_args_act->var_full]); } + } else if (auto alloca_act = std::dynamic_pointer_cast(act)) { + cur_act_def.push_back(var_to_id[alloca_act->name_full]); } std::sort(cur_act_use.begin(), cur_act_use.end()); std::sort(cur_act_def.begin(), cur_act_def.end()); diff --git a/src/opt/regalloc.cpp b/src/opt/regalloc.cpp index 1692898..473f5f8 100644 --- a/src/opt/regalloc.cpp +++ b/src/opt/regalloc.cpp @@ -11,6 +11,10 @@ void EnforcePhysicalRegs(CFGType &cfg) { // process callee side auto entry_node = cfg.entry; auto func = cfg.corresponding_func; + std::unordered_set missing_caller_saved_regs; + for (auto reg : caller_saved_regs) { + missing_caller_saved_regs.insert(reg); + } for (size_t i = 0; i < 8 && i < func->args_full_name.size(); i++) { auto new_def = std::make_shared(); new_def->var_full = "%reg." + arg_regs[i]; @@ -21,6 +25,7 @@ void EnforcePhysicalRegs(CFGType &cfg) { new_move->ty = func->args[i]; entry_node->corresponding_block->actions.push_front(new_move); entry_node->corresponding_block->actions.push_front(new_def); + missing_caller_saved_regs.erase(arg_regs[i]); } for (size_t i = 8; i < func->args_full_name.size(); i++) { auto arg_load = std::make_shared(); @@ -58,6 +63,7 @@ void EnforcePhysicalRegs(CFGType &cfg) { new_move->src_full = std::dynamic_pointer_cast(block->exit_action)->value; new_move->dest_full = "%reg.x10"; new_move->ty = std::dynamic_pointer_cast(block->exit_action)->type; + if (new_move->src_full == "%reg.x10" && new_move->dest_full == "%reg.x10") throw std::runtime_error("error"); block->actions.push_back(new_move); std::dynamic_pointer_cast(block->exit_action)->value = "%reg.x10"; } @@ -82,6 +88,7 @@ void EnforcePhysicalRegs(CFGType &cfg) { std::unordered_set caller_saved_regs_to_process; for (auto reg : caller_saved_regs) { caller_saved_regs_to_process.insert(reg); + missing_caller_saved_regs.erase(reg); } for (size_t i = 0; i < call_act->args_val_full.size() & i < 8; i++) { auto new_move = std::make_shared(); @@ -118,6 +125,16 @@ void EnforcePhysicalRegs(CFGType &cfg) { --it_act; } } + // avoid missing some caller saved regs + for (auto reg : missing_caller_saved_regs) { + auto new_def = std::make_shared(); + new_def->var_full = "%reg." + reg; + new_def->ty = LLVMIRIntType(32); + auto new_use = std::make_shared(); + new_use->var_full = "%reg." + reg; + entry_node->corresponding_block->actions.push_front(new_use); + entry_node->corresponding_block->actions.push_front(new_def); + } } void ConductRegAllocForFunction(std::shared_ptr func) { std::cerr << "processing function " << func->func_name_raw << std::endl; @@ -125,9 +142,12 @@ void ConductRegAllocForFunction(std::shared_ptr func) { ConfGraph confgraph; cfg = BuildCFGForFunction(func); EnforcePhysicalRegs(cfg); + func->RecursivePrint(std::cerr); do { + cfg.init(); cfg = BuildCFGForFunction(func); LiveAnalysis(cfg); + confgraph.init(); confgraph = BuildConfGraph(cfg); } while (ConductColoring(func, cfg, confgraph)); }