diff --git a/include/IR/IR_basic.h b/include/IR/IR_basic.h index cdcd7ae..50e57e1 100644 --- a/include/IR/IR_basic.h +++ b/include/IR/IR_basic.h @@ -248,7 +248,7 @@ class BlockItem : public LLVMIRItemBase { public: std::string label_full; std::unordered_map> phi_map; // this is used to store phi items when optimizing - std::vector> actions; + std::list> actions; std::shared_ptr exit_action; BlockItem() = default; diff --git a/include/opt/cfg.h b/include/opt/cfg.h index 55d9c63..874bf51 100644 --- a/include/opt/cfg.h +++ b/include/opt/cfg.h @@ -18,10 +18,15 @@ class CFGNodeType { std::vector successors_in_dom_tree; CFGNodeCollection dom_frontier; - std::vector in_active_vars; - std::vector out_active_vars; - std::vector use_vars; - std::vector def_vars; + std::vector block_in_active_vars; + std::vector block_out_active_vars; + std::vector block_use_vars; + std::vector block_def_vars; + + std::unordered_map> action_use_vars; + std::unordered_map> action_def_vars; + std::unordered_map> action_in_active_vars; + std::unordered_map> action_out_active_vars; }; class CFGType { @@ -30,6 +35,9 @@ class CFGType { CFGNodeType *entry; std::unordered_map block_to_node; std::unordered_map label_to_block; + std::vector id_to_var; + std::unordered_map var_to_id; + FunctionDefItem *corresponding_func; }; template > diff --git a/include/opt/liveanalysis.h b/include/opt/liveanalysis.h index 1277896..1b8d375 100644 --- a/include/opt/liveanalysis.h +++ b/include/opt/liveanalysis.h @@ -1,4 +1,36 @@ #pragma once +#include "IR/IR_basic.h" #include "cfg.h" +#include "tools.h" -void LiveAnalysis(CFGType &cfg); \ No newline at end of file +void LiveAnalysis(CFGType &cfg); + +namespace opt { +class ForceDef : public ActionItem { + public: + 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"); + } +}; +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"); + } +}; +class LoadSpilledArgs : public ActionItem { + public: + size_t arg_id; // [8,+inf) + std::string var_full; + LLVMType ty; + LoadSpilledArgs() = default; + void RecursivePrint(std::ostream &os) const { + throw std::runtime_error("LoadSpilledArgs instruction is not an actual LLVM IR instruction"); + } +}; +} // namespace opt \ No newline at end of file diff --git a/include/opt/phieliminate.h b/include/opt/phieliminate.h index 3063924..2215bae 100644 --- a/include/opt/phieliminate.h +++ b/include/opt/phieliminate.h @@ -7,6 +7,7 @@ class MoveInstruct : public ActionItem { public: std::string src_full; std::string dest_full; + 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"); diff --git a/include/tools.h b/include/tools.h index ee7b96c..1be963e 100644 --- a/include/tools.h +++ b/include/tools.h @@ -91,13 +91,13 @@ inline bool operator==(const ExprTypeInfo &l, const ExprTypeInfo &r) { return true; } if (std::holds_alternative(l)) { - bool x = std::holds_alternative(r); + // bool x = std::holds_alternative(r); std::string a = std::get(l); std::string b = std::get(r); return std::holds_alternative(r) && std::get(l) == std::get(r); } if (std::holds_alternative(l)) { - bool x = std::holds_alternative(r); + // bool x = std::holds_alternative(r); return std::holds_alternative(r) && std::get(l) == std::get(r); } throw std::runtime_error("something strange happened"); diff --git a/src/opt/cfg.cpp b/src/opt/cfg.cpp index da64955..1c1a198 100644 --- a/src/opt/cfg.cpp +++ b/src/opt/cfg.cpp @@ -41,5 +41,6 @@ CFGType BuildCFGForFunction(const std::shared_ptr &func) { throw std::runtime_error("Block does not have an exit action"); } } + res.corresponding_func = func.get(); return res; } \ No newline at end of file diff --git a/src/opt/liveanalysis.cpp b/src/opt/liveanalysis.cpp index 5af21b7..80d50b0 100644 --- a/src/opt/liveanalysis.cpp +++ b/src/opt/liveanalysis.cpp @@ -42,8 +42,8 @@ void UseDefCollect(CFGType &cfg, [[maybe_unused]] std::vector &id_t std::vector cur_node_def; bool use_def_init = false; for (auto act : block->actions) { - std::vector cur_act_use; - std::vector cur_act_def; + std::vector &cur_act_use = node->action_use_vars[act.get()]; + std::vector &cur_act_def = node->action_def_vars[act.get()]; if (auto br_act = std::dynamic_pointer_cast(act)) { if (var_to_id.find(br_act->cond) != var_to_id.end()) { cur_act_use.push_back(var_to_id[br_act->cond]); @@ -153,27 +153,50 @@ void UseDefCollect(CFGType &cfg, [[maybe_unused]] std::vector &id_t cur_node_use = cur_act_use; cur_node_def = cur_act_def; } else { - auto use_p = std::move(cur_node_use); - auto def_p = std::move(cur_node_def); - auto use_n = std::move(cur_act_use); - auto def_n = std::move(cur_act_def); + const auto &use_p = cur_node_use; + const auto &def_p = cur_node_def; + const auto &use_n = cur_act_use; + const auto &def_n = cur_act_def; cur_node_use = GetCollectionsUnion(use_p, GetCollectionsDifference(use_n, def_p)); - cur_node_def = GetCollectionsUnion(def_p, use_n); + cur_node_def = GetCollectionsUnion(def_p, def_n); } } - node->use_vars = cur_node_use; - node->def_vars = cur_node_def; + { + auto act = block->exit_action; + std::vector &cur_act_use = node->action_use_vars[act.get()]; + std::vector &cur_act_def = node->action_def_vars[act.get()]; + if (auto br_act = std::dynamic_pointer_cast(act)) { + if (var_to_id.find(br_act->cond) != var_to_id.end()) { + cur_act_use.push_back(var_to_id[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()) { + cur_act_use.push_back(var_to_id[ret_act->value]); + } + } + if (!use_def_init) { + use_def_init = true; + cur_node_use = cur_act_use; + cur_node_def = cur_act_def; + } else { + const auto &use_p = cur_node_use; + const auto &def_p = cur_node_def; + const auto &use_n = cur_act_use; + const auto &def_n = cur_act_def; + cur_node_use = GetCollectionsUnion(use_p, GetCollectionsDifference(use_n, def_p)); + cur_node_def = GetCollectionsUnion(def_p, def_n); + } + } + node->block_use_vars = cur_node_use; + node->block_def_vars = cur_node_def; } } -void LiveAnalysis(CFGType &cfg) { - std::vector id_to_var; - std::unordered_map var_to_id; - VarCollect(cfg, id_to_var, var_to_id); - UseDefCollect(cfg, id_to_var, var_to_id); +void BlockLevelTracking(CFGType &cfg, [[maybe_unused]] std::vector &id_to_var, + [[maybe_unused]] std::unordered_map &var_to_id) { std::vector exists; for (auto node : cfg.nodes) { - node->in_active_vars = node->use_vars; + node->block_in_active_vars = node->block_use_vars; if (node->successors.size() == 0) { exists.push_back(node.get()); } @@ -200,18 +223,56 @@ void LiveAnalysis(CFGType &cfg) { } std::vector out_active_vars; for (auto succ : cur_node->successors) { - out_active_vars = GetCollectionsUnion(out_active_vars, succ->in_active_vars); + out_active_vars = GetCollectionsUnion(out_active_vars, succ->block_in_active_vars); } - if (!GetCollectionsIsSame(cur_node->out_active_vars, out_active_vars)) { + if (!GetCollectionsIsSame(cur_node->block_out_active_vars, out_active_vars)) { all_data_unchanged = false; - cur_node->out_active_vars = std::move(out_active_vars); + cur_node->block_out_active_vars = std::move(out_active_vars); } - std::vector in_active_vars = GetCollectionsUnion( - cur_node->use_vars, GetCollectionsDifference(cur_node->out_active_vars, cur_node->def_vars)); - if (!GetCollectionsIsSame(cur_node->in_active_vars, in_active_vars)) { + std::vector in_active_vars = + GetCollectionsUnion(cur_node->block_use_vars, + GetCollectionsDifference(cur_node->block_out_active_vars, cur_node->block_def_vars)); + if (!GetCollectionsIsSame(cur_node->block_in_active_vars, in_active_vars)) { all_data_unchanged = false; - cur_node->in_active_vars = std::move(in_active_vars); + cur_node->block_in_active_vars = std::move(in_active_vars); } } } while (!all_data_unchanged); +} + +void ActionLevelTracking(CFGType &cfg, CFGNodeType *node) { + if (node->corresponding_block->actions.size() == 0) { + node->action_in_active_vars[node->corresponding_block->exit_action.get()] = node->block_in_active_vars; + node->action_out_active_vars[node->corresponding_block->exit_action.get()] = node->block_out_active_vars; + return; + } + node->action_in_active_vars[node->corresponding_block->actions.front().get()] = node->block_in_active_vars; + node->action_out_active_vars[node->corresponding_block->exit_action.get()] = node->block_out_active_vars; + node->action_in_active_vars[node->corresponding_block->exit_action.get()] = GetCollectionsUnion( + node->action_use_vars[node->corresponding_block->exit_action.get()], + GetCollectionsDifference(node->action_out_active_vars[node->corresponding_block->exit_action.get()], + node->action_def_vars[node->corresponding_block->exit_action.get()])); + node->action_out_active_vars[node->corresponding_block->actions.back().get()] = + node->action_in_active_vars[node->corresponding_block->exit_action.get()]; + if (node->corresponding_block->actions.size() == 1) return; + auto it = node->corresponding_block->actions.end(); + --it; + while (true) { + node->action_in_active_vars[it->get()] = GetCollectionsUnion( + node->action_use_vars[it->get()], + GetCollectionsDifference(node->action_out_active_vars[it->get()], node->action_def_vars[it->get()])); + auto tmp = node->action_in_active_vars[it->get()]; + --it; + if (it == node->corresponding_block->actions.begin()) break; + node->action_out_active_vars[it->get()] = tmp; + } +} + +void LiveAnalysis(CFGType &cfg) { + VarCollect(cfg, cfg.id_to_var, cfg.var_to_id); + UseDefCollect(cfg, cfg.id_to_var, cfg.var_to_id); + BlockLevelTracking(cfg, cfg.id_to_var, cfg.var_to_id); + for (auto node : cfg.nodes) { + ActionLevelTracking(cfg, node.get()); + } } \ No newline at end of file diff --git a/src/opt/mem2reg.cpp b/src/opt/mem2reg.cpp index 442c9f4..6c3b433 100644 --- a/src/opt/mem2reg.cpp +++ b/src/opt/mem2reg.cpp @@ -97,7 +97,7 @@ std::unordered_map InNodeReplace( std::unordered_map> &var_to_name_stk) { std::unordered_map var_to_versions_pushed; BlockItem *cur_block = cur_node->corresponding_block; - std::vector> new_actions; + std::list> new_actions; std::unordered_map is_an_alias_generated_by_load; for (auto [origin_var_name, _] : var_to_version) { if (cur_block->phi_map.find(origin_var_name) != cur_block->phi_map.end()) { diff --git a/src/opt/phieliminate.cpp b/src/opt/phieliminate.cpp index 1cf9879..d021ac8 100644 --- a/src/opt/phieliminate.cpp +++ b/src/opt/phieliminate.cpp @@ -9,7 +9,7 @@ void ConductPhiEliminateForFunction(std::shared_ptr func, CFGTy for (auto cur_node : cfg.nodes) { auto cur_block = cur_node->corresponding_block; if (cur_block->actions.size() > 0) { - if (auto phi_act = std::dynamic_pointer_cast(cur_block->actions[0])) { + if (auto phi_act = std::dynamic_pointer_cast(cur_block->actions.front())) { // simple phi action caused by and, or and ternary operator, no need to insert extra blocks, just remove it and // add phi values to the corresponding blocks cur_block->actions.erase(cur_block->actions.begin()); @@ -18,6 +18,7 @@ void ConductPhiEliminateForFunction(std::shared_ptr func, CFGTy auto new_move = std::make_shared(); new_move->src_full = src_val; new_move->dest_full = phi_act->result_full; + new_move->ty = phi_act->ty; src_block->actions.push_back(new_move); } } @@ -32,6 +33,7 @@ void ConductPhiEliminateForFunction(std::shared_ptr func, CFGTy auto new_move = std::make_shared(); new_move->src_full = src_val; new_move->dest_full = phi_act->result_full; + new_move->ty = phi_act->ty; src_block->actions.push_back(new_move); } else if (src_node->successors.size() > 1 && cur_node->predecessors.size() > 1) { // it is a critical edge, need to insert a new block @@ -59,11 +61,13 @@ void ConductPhiEliminateForFunction(std::shared_ptr func, CFGTy auto new_move = std::make_shared(); new_move->src_full = src_val; new_move->dest_full = phi_act->result_full; + new_move->ty = phi_act->ty; new_block->actions.push_back(new_move); } else { auto new_move = std::make_shared(); new_move->src_full = src_val; new_move->dest_full = phi_act->result_full; + new_move->ty = phi_act->ty; cur_block->actions.push_back(new_move); } } diff --git a/src/opt/regalloc.cpp b/src/opt/regalloc.cpp index ce1d4e3..15a08aa 100644 --- a/src/opt/regalloc.cpp +++ b/src/opt/regalloc.cpp @@ -1,6 +1,77 @@ #include "regalloc.h" +#include "IR/IR_basic.h" +#include "liveanalysis.h" +#include "tools.h" +// RISC-V calling convention compatible +static std::vector held_tmp_regs = {"x28", "x29", "x30", "x31"}; +static std::vector callee_saved_regs = {"x3", "x4", "x9", "x18", "x19", "x20", "x21", + "x22", "x23", "x24", "x25", "x26", "x27"}; +static std::vector caller_saved_regs = {"x5", "x6", "x7", "x10", "x11", "x12", + "x13", "x14", "x15", "x16", "x17"}; +static std::vector arg_regs = {"x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17"}; +static std::string zero = "x0", sp = "x2", ra = "x1", fp = "x8"; +void EnforcePhysicalRegs(CFGType &cfg) { + using namespace opt; + // process callee side + auto entry_node = cfg.entry; + auto func = cfg.corresponding_func; + 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]; + new_def->ty = func->args[i]; + auto new_move = std::make_shared(); + new_move->src_full = "%reg." + arg_regs[i]; + new_move->dest_full = func->args_full_name[i]; + new_move->ty = func->args[i]; + entry_node->corresponding_block->actions.push_front(new_move); + entry_node->corresponding_block->actions.push_front(new_def); + } + for (size_t i = 8; i < func->args_full_name.size(); i++) { + auto arg_load = std::make_shared(); + arg_load->arg_id = i; + arg_load->var_full = func->args_full_name[i]; + arg_load->ty = func->args[i]; + entry_node->corresponding_block->actions.push_front(arg_load); + } + for (auto callee_saved_reg : callee_saved_regs) { + auto new_def = std::make_shared(); + new_def->var_full = "%reg." + callee_saved_reg; + new_def->ty = LLVMIRIntType(32); + auto new_move = std::make_shared(); + new_move->src_full = new_def->var_full; + new_move->dest_full = "%calleesave." + callee_saved_reg; + new_move->ty = LLVMIRIntType(32); + entry_node->corresponding_block->actions.push_front(new_move); + entry_node->corresponding_block->actions.push_front(new_def); + } + for (auto node : cfg.nodes) { + auto block = node->corresponding_block; + if (std::dynamic_pointer_cast(block->exit_action)) { + for (auto callee_saved_reg : callee_saved_regs) { + auto new_move = std::make_shared(); + new_move->src_full = "%calleesave." + callee_saved_reg; + new_move->dest_full = "%reg." + callee_saved_reg; + new_move->ty = LLVMIRIntType(32); + auto new_use = std::make_shared(); + new_use->var_full = "%reg." + callee_saved_reg; + block->actions.push_back(new_move); + block->actions.push_back(new_use); + } + if (!std::holds_alternative(std::dynamic_pointer_cast(block->exit_action)->type)) { + auto new_move = std::make_shared(); + 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; + block->actions.push_back(new_move); + std::dynamic_pointer_cast(block->exit_action)->value = "%reg.x10"; + } + } + } + // TODO: process caller side +} void ConductRegAllocForFunction([[maybe_unused]] std::shared_ptr func, CFGType &cfg) { + EnforcePhysicalRegs(cfg); LiveAnalysis(cfg); }