#pragma once #include #include #include #include #include #include "IR/IR_basic.h" 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; std::vector successors_in_dom_tree; CFGNodeCollection dom_frontier; 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 { public: std::vector> nodes; 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; 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 { 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 { os << "[Persudo] " << dest_full << " <-- " << src_full << "\n"; } }; } // namespace opt template > Container GetCollectionsIntersection(const Container &a, const Container &b, Compare comp = Compare()) { Container result; auto ita = a.begin(); auto itb = b.begin(); while (ita != a.end() && itb != b.end()) { if (comp(*ita, *itb)) { ++ita; } else if (comp(*itb, *ita)) { ++itb; } else { result.push_back(*ita); ++ita; ++itb; } } return result; } template > Container GetCollectionsUnion(const Container &a, const Container &b, Compare comp = Compare()) { Container result; auto ita = a.begin(); auto itb = b.begin(); while (ita != a.end() && itb != b.end()) { if (comp(*ita, *itb)) { result.push_back(*ita); ++ita; } else if (comp(*itb, *ita)) { result.push_back(*itb); ++itb; } else { result.push_back(*ita); ++ita; ++itb; } } while (ita != a.end()) { result.push_back(*ita); ++ita; } while (itb != b.end()) { result.push_back(*itb); ++itb; } return result; } template > Container GetCollectionsDifference(const Container &a, const Container &b, Compare comp = Compare()) { Container result; auto ita = a.begin(); auto itb = b.begin(); while (ita != a.end() && itb != b.end()) { if (comp(*ita, *itb)) { result.push_back(*ita); ++ita; } else if (comp(*itb, *ita)) { ++itb; } else { ++ita; ++itb; } } while (ita != a.end()) { result.push_back(*ita); ++ita; } return result; } template > bool GetCollectionsIsSame(const Container &a, const Container &b, Compare comp = Compare()) { auto ita = a.begin(); auto itb = b.begin(); while (ita != a.end() && itb != b.end()) { if (comp(*ita, *itb) || comp(*itb, *ita)) { return false; } ++ita; ++itb; } return ita == a.end() && itb == b.end(); } CFGType BuildCFGForFunction(const std::shared_ptr &func); // RISC-V calling convention compatible const static std::vector held_tmp_regs = {"x28", "x29", "x30", "x31"}; const static std::string zero = "x0", sp = "x2", ra = "x1", fp = "x8"; const static std::vector callee_saved_regs = {"x3", "x4", "x9", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27"}; const static std::vector caller_saved_regs = {"x5", "x6", "x7", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17"}; 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"}; inline bool VRegCheck(const std::string &s) { if (s[0] != '%') return false; return true; }