From 2e94fba65372ec53b2f3e698ca972ce2753f5d23 Mon Sep 17 00:00:00 2001 From: ZhuangYumin Date: Sat, 19 Oct 2024 02:47:51 +0000 Subject: [PATCH] write phi elimination --- include/IR/IR_basic.h | 16 ++------- include/opt/cfg.h | 2 ++ include/opt/opt.h | 3 +- include/opt/phieliminate.h | 18 ++++++++++ include/opt/regalloc.h | 2 ++ src/main.cpp | 3 +- src/opt/phieliminate.cpp | 72 ++++++++++++++++++++++++++++++++++++++ src/opt/regalloc.cpp | 1 + 8 files changed, 101 insertions(+), 16 deletions(-) create mode 100644 include/opt/phieliminate.h create mode 100644 include/opt/regalloc.h create mode 100644 src/opt/phieliminate.cpp create mode 100644 src/opt/regalloc.cpp diff --git a/include/IR/IR_basic.h b/include/IR/IR_basic.h index 98848a1..b40fe62 100644 --- a/include/IR/IR_basic.h +++ b/include/IR/IR_basic.h @@ -89,17 +89,9 @@ class BRAction : public JMPActionItem { } }; class UNConditionJMPAction : public JMPActionItem { - friend class IRBuilder; - friend class FunctionDefItem; - friend void GenerateNaiveASM(std::ostream &os, std::shared_ptr prog); - friend void NaiveBackend::GenerateASM(std::shared_ptr act, std::vector &code_lines, - NaiveBackend::FuncLayout &layout, - const std::unordered_map &low_level_class_info, - bool process_phi); - friend class CFGType BuildCFGForFunction(const std::shared_ptr &func); + public: std::string label_full; - public: UNConditionJMPAction() = default; void RecursivePrint(std::ostream &os) const { os << "br label %" << label_full << "\n"; } }; @@ -492,10 +484,7 @@ class ConstStrItem : public LLVMIRItemBase { } }; class ModuleItem : public LLVMIRItemBase { - friend class IRBuilder; - friend std::shared_ptr BuildIR(std::shared_ptr src); - friend void GenerateNaiveASM(std::ostream &os, std::shared_ptr prog); - friend std::shared_ptr Mem2Reg(std::shared_ptr src); + public: std::vector> const_strs; std::vector> function_declares; std::vector> type_defs; @@ -503,7 +492,6 @@ class ModuleItem : public LLVMIRItemBase { std::vector> function_defs; std::unordered_map low_level_class_info; - public: ModuleItem() = default; void RecursivePrint(std::ostream &os) const { for (auto &item : const_strs) { diff --git a/include/opt/cfg.h b/include/opt/cfg.h index 3a6f47a..fd8918b 100644 --- a/include/opt/cfg.h +++ b/include/opt/cfg.h @@ -8,8 +8,10 @@ using CFGNodeCollection = std::list; class CFGNodeType { public: + // successors, predecessors, corresponding_block is provided by BuildCFGForFunction std::vector successors, predecessors; BlockItem *corresponding_block; + // the following fields are provided by user CFGNodeCollection dom; bool visited; CFGNodeType *idom; diff --git a/include/opt/opt.h b/include/opt/opt.h index 4f57210..503f478 100644 --- a/include/opt/opt.h +++ b/include/opt/opt.h @@ -1,2 +1,3 @@ +#include "cfg.h" #include "mem2reg.h" -#include "cfg.h" \ No newline at end of file +#include "regalloc.h" \ No newline at end of file diff --git a/include/opt/phieliminate.h b/include/opt/phieliminate.h new file mode 100644 index 0000000..b66b9e6 --- /dev/null +++ b/include/opt/phieliminate.h @@ -0,0 +1,18 @@ +#pragma once +#include "IR/IR_basic.h" +#include "cfg.h" + +namespace opt { +class MoveInstruct : public ActionItem { + public: + std::string src_full; + std::string dest_full; + MoveInstruct() = default; + void RecursivePrint(std::ostream &os) const { + throw std::runtime_error("Move instruction is not an actual LLVM IR instruction"); + } +}; +} // namespace opt + + +std::shared_ptr PhiEliminate(std::shared_ptr src); \ No newline at end of file diff --git a/include/opt/regalloc.h b/include/opt/regalloc.h new file mode 100644 index 0000000..070c2c7 --- /dev/null +++ b/include/opt/regalloc.h @@ -0,0 +1,2 @@ +#pragma once +#include "phieliminate.h" \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 91c5d3a..a3571c2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -46,7 +46,8 @@ int main(int argc, char **argv) { GenerateNaiveASM(fout, IR); } else { auto IR_with_out_allocas = Mem2Reg(IR); - IR_with_out_allocas->RecursivePrint(fout); + // IR_with_out_allocas->RecursivePrint(fout); + auto IR_with_out_phis = PhiEliminate(IR_with_out_allocas); } } catch (const SemanticError &err) { std::cout << err.what() << std::endl; diff --git a/src/opt/phieliminate.cpp b/src/opt/phieliminate.cpp new file mode 100644 index 0000000..26e7306 --- /dev/null +++ b/src/opt/phieliminate.cpp @@ -0,0 +1,72 @@ +#include "phieliminate.h" +#include +#include "IR/IR_basic.h" + +using namespace opt; + +void ConductPhiEliminateForFunction([[maybe_unused]] std::shared_ptr func, CFGType &cfg) { + size_t new_block_cnt = 0; + 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])) { + // 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()); + for (auto [src_val, src_label] : phi_act->values) { + auto src_block = cfg.label_to_block[src_label]; + auto new_move = std::make_shared(); + new_move->src_full = src_val; + new_move->dest_full = phi_act->result_full; + src_block->actions.push_back(new_move); + } + } + } + for (auto [_, phi_act] : cur_block->phi_map) { + for (auto [src_val, src_label] : phi_act->values) { + auto src_block = cfg.label_to_block[src_label]; + auto src_node = cfg.block_to_node[src_block]; + if (src_node->successors.size() > 1 && cur_node->predecessors.size() > 1) { + // it is a critical edge, need to insert a new block + auto new_block = std::make_shared(); + new_block->label_full = cur_block->label_full + ".phieliminate." + std::to_string(new_block_cnt++); + new_block->exit_action = std::make_shared(); + std::dynamic_pointer_cast(new_block->exit_action)->label_full = cur_block->label_full; + auto src_block_exit_action = std::dynamic_pointer_cast(src_block->exit_action); + if (!src_block_exit_action) { + throw std::runtime_error( + "something strange happened: src block of a critical edge does not have a BRAction"); + } + if (src_block_exit_action->true_label_full == cur_block->label_full) { + src_block_exit_action->true_label_full = new_block->label_full; + } else if (src_block_exit_action->false_label_full == cur_block->label_full) { + src_block_exit_action->false_label_full = new_block->label_full; + } else { + throw std::runtime_error( + "something strange happened: src block of a critical edge cannot find the corresponding label"); + } + auto new_move = std::make_shared(); + new_move->src_full = src_val; + new_move->dest_full = phi_act->result_full; + 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; + cur_block->actions.push_back(new_move); + } + } + } + cur_block->phi_map.clear(); + } +} + +std::shared_ptr PhiEliminate(std::shared_ptr src) { + auto res = src; + for (auto &func : res->function_defs) { + // func = std::make_shared(*func); + auto cfg = BuildCFGForFunction(func); + ConductPhiEliminateForFunction(func, cfg); + } + return res; +} \ No newline at end of file diff --git a/src/opt/regalloc.cpp b/src/opt/regalloc.cpp new file mode 100644 index 0000000..901c92c --- /dev/null +++ b/src/opt/regalloc.cpp @@ -0,0 +1 @@ +#include "regalloc.h" \ No newline at end of file