diff --git a/CMakeLists.txt b/CMakeLists.txt index 236bc647b8a94882f865cd22e23ae370392620d8..7fc88d01382c17b37b00132ed099a84f4601d1d0 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,7 @@ INCLUDE_DIRECTORIES( include/common include/lightir include/codegen + include/passes ${LLVM_INCLUDE_DIRS} ) diff --git a/include/lightir/Instruction.hpp b/include/lightir/Instruction.hpp index 184ebd5d8f1e81093ccc81cf1049a3cd65fddf02..54d4b340ae3a995dc7f9b480d8550f487fce8ec7 100755 --- a/include/lightir/Instruction.hpp +++ b/include/lightir/Instruction.hpp @@ -357,6 +357,17 @@ class PhiInst : public BaseInst { this->add_operand(val); this->add_operand(pre_bb); } + + void remove_phi_operand(Value *pre_bb) { + for (unsigned i = 0; i < this->get_num_operand(); i += 2) { + if (this->get_operand(i + 1) == pre_bb) { + this->remove_operand(i); + this->remove_operand(i); + return; + } + } + } + std::vector> get_phi_pairs() { std::vector> res; for (size_t i = 0; i < get_num_operand(); i += 2) { diff --git a/include/passes/DeadCode.hpp b/include/passes/DeadCode.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8a880097cfcf28dc755b188c4e627796ef8d5978 --- /dev/null +++ b/include/passes/DeadCode.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "FuncInfo.hpp" +#include "PassManager.hpp" + +#include + +/** + * 死代码消除:参见 + *https://www.clear.rice.edu/comp512/Lectures/10Dead-Clean-SCCP.pdf + **/ +class DeadCode : public Pass { + public: + DeadCode(Module *m) : Pass(m), func_info(std::make_shared(m)) {} + + void run(); + + private: + std::shared_ptr func_info; + int ins_count{0}; // 用以衡量死代码消除的性能 + std::deque work_list{}; + std::unordered_map marked{}; + + void mark(Function *func); + void mark(Instruction *ins); + bool sweep(Function *func); + bool clear_basic_blocks(Function *func); + bool is_critical(Instruction *ins); + void sweep_globally(); +}; diff --git a/include/passes/Dominators.hpp b/include/passes/Dominators.hpp new file mode 100644 index 0000000000000000000000000000000000000000..398d0e5b2805f17b47a77ad4b2ae948e32e3f11c --- /dev/null +++ b/include/passes/Dominators.hpp @@ -0,0 +1,88 @@ +#pragma once + +#include "BasicBlock.hpp" +#include "PassManager.hpp" + +#include +#include + +class Dominators : public Pass { + public: + using BBSet = std::set; + + explicit Dominators(Module *m) : Pass(m) {} + ~Dominators() = default; + void run() override; + void run_on_func(Function *f); + + // functions for getting information + BasicBlock *get_idom(BasicBlock *bb) { return idom_.at(bb); } + const BBSet &get_dominance_frontier(BasicBlock *bb) { + return dom_frontier_.at(bb); + } + const BBSet &get_dom_tree_succ_blocks(BasicBlock *bb) { + return dom_tree_succ_blocks_.at(bb); + } + + // print cfg or dominance tree + void dump_cfg(Function *f); + void dump_dominator_tree(Function *f); + + // functions for dominance tree + const bool is_dominate(BasicBlock *bb1, BasicBlock *bb2) { + return dom_tree_L_.at(bb1) <= dom_tree_L_.at(bb2) && + dom_tree_R_.at(bb1) >= dom_tree_L_.at(bb2); + } + + const std::vector &get_dom_dfs_order() { + return dom_dfs_order_; + } + + const std::vector &get_dom_post_order() { + return dom_post_order_; + } + + private: + + void dfs(BasicBlock *bb, std::set &visited); + void create_idom(Function *f); + void create_dominance_frontier(Function *f); + void create_dom_tree_succ(Function *f); + void create_dom_dfs_order(Function *f); + + BasicBlock * intersect(BasicBlock *b1, BasicBlock *b2); + + void create_reverse_post_order(Function *f); + void set_idom(BasicBlock *bb, BasicBlock *idom) { idom_[bb] = idom; } + void set_dominance_frontier(BasicBlock *bb, BBSet &df) { + dom_frontier_[bb].clear(); + dom_frontier_[bb].insert(df.begin(), df.end()); + } + void add_dom_tree_succ_block(BasicBlock *bb, BasicBlock *dom_tree_succ_bb) { + dom_tree_succ_blocks_[bb].insert(dom_tree_succ_bb); + } + unsigned int get_post_order(BasicBlock *bb) { + return post_order_.at(bb); + } + // for debug + void print_idom(Function *f); + void print_dominance_frontier(Function *f); + + // TODO 补充需要的函数 + std::list reverse_post_order_{}; + std::map post_order_id_{}; // the root has highest ID + + std::vector post_order_vec_{}; // 逆后序 + std::map post_order_{}; // 逆后序 + std::map idom_{}; // 直接支配 + std::map dom_frontier_{}; // 支配边界集合 + std::map dom_tree_succ_blocks_{}; // 支配树中的后继节点 + + // 支配树上的dfs序L,R + std::map dom_tree_L_; + std::map dom_tree_R_; + + std::vector dom_dfs_order_; + std::vector dom_post_order_; + +}; diff --git a/include/passes/FuncInfo.hpp b/include/passes/FuncInfo.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e8a8c13d0eb55d4e956d5cd98b92e763f862e0b2 --- /dev/null +++ b/include/passes/FuncInfo.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include "PassManager.hpp" +#include "logging.hpp" + +#include +#include + +/** + * 计算哪些函数是纯函数 + * WARN: + * 假定所有函数都是纯函数,除非他写入了全局变量、修改了传入的数组、或者直接间接调用了非纯函数 + */ +class FuncInfo : public Pass { + public: + FuncInfo(Module *m) : Pass(m) {} + + void run(); + + bool is_pure_function(Function *func) const { return is_pure.at(func); } + + private: + std::deque worklist; + std::unordered_map is_pure; + + void trivial_mark(Function *func); + void process(Function *func); + Value *get_first_addr(Value *val); + + bool is_side_effect_inst(Instruction *inst); + bool is_local_load(LoadInst *inst); + bool is_local_store(StoreInst *inst); + + void log(); +}; diff --git a/include/passes/LICM.hpp b/include/passes/LICM.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4ae0efb167b1fece4eba08043db1357e2c2b03a7 --- /dev/null +++ b/include/passes/LICM.hpp @@ -0,0 +1,24 @@ +#include "FuncInfo.hpp" +#include "LoopDetection.hpp" +#include "PassManager.hpp" +#include +#include + +class LoopInvariantCodeMotion : public Pass { + public: + LoopInvariantCodeMotion(Module *m) : Pass(m) {} + ~LoopInvariantCodeMotion() = default; + + void run() override; + + private: + std::unordered_map, bool> is_loop_done_; + std::unique_ptr loop_detection_; + std::unique_ptr func_info_; + void traverse_loop(std::shared_ptr loop); + void run_on_loop(std::shared_ptr loop); + void collect_loop_info(std::shared_ptr loop, + std::set &loop_instructions, + std::set &updated_global, + bool &contains_impure_call); +}; \ No newline at end of file diff --git a/include/passes/LoopDetection.hpp b/include/passes/LoopDetection.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b55246ced22cd5b1b562f02317442912c1f364b9 --- /dev/null +++ b/include/passes/LoopDetection.hpp @@ -0,0 +1,64 @@ +#pragma once +#include "Dominators.hpp" +#include "PassManager.hpp" +#include +#include +#include +#include + +class BasicBlock; +class Dominators; +class Function; +class Module; + +using BBset = std::set; +using BBvec = std::vector; +class Loop { + private: + // attribute: + // preheader, header, blocks, parent, sub_loops, latches + BasicBlock *preheader_ = nullptr; + BasicBlock *header_; + + std::shared_ptr parent_ = nullptr; + BBvec blocks_; + std::vector> sub_loops_; + + std::unordered_set latches_; + public: + Loop(BasicBlock *header) : header_(header) { + blocks_.push_back(header); + } + ~Loop() = default; + void add_block(BasicBlock *bb) { blocks_.push_back(bb); } + BasicBlock *get_header() { return header_; } + BasicBlock *get_preheader() { return preheader_; } + std::shared_ptr get_parent() { return parent_; } + void set_parent(std::shared_ptr parent) { parent_ = parent; } + void set_preheader(BasicBlock *bb) { preheader_ = bb; } + void add_sub_loop(std::shared_ptr loop) { sub_loops_.push_back(loop); } + const BBvec& get_blocks() { return blocks_; } + const std::vector>& get_sub_loops() { return sub_loops_; } + const std::unordered_set& get_latches() { return latches_; } + void add_latch(BasicBlock *bb) { latches_.insert(bb); } +}; + +class LoopDetection : public Pass { + private: + Function *func_; + std::unique_ptr dominators_; + std::vector> loops_; + // map from header to loop + std::unordered_map> bb_to_loop_; + void discover_loop_and_sub_loops(BasicBlock *bb, BBset &latches, + std::shared_ptr loop); + + public: + LoopDetection(Module *m) : Pass(m) {} + ~LoopDetection() = default; + + void run() override; + void run_on_func(Function *f); + void print() ; + std::vector> &get_loops() { return loops_; } +}; diff --git a/include/passes/Mem2Reg.hpp b/include/passes/Mem2Reg.hpp new file mode 100644 index 0000000000000000000000000000000000000000..867810ec83a19ae7c9667c27e8a80c9bcef038e9 --- /dev/null +++ b/include/passes/Mem2Reg.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include "Dominators.hpp" +#include "Instruction.hpp" +#include "Value.hpp" + +#include +#include + +class Mem2Reg : public Pass { + private: + Function *func_; + std::unique_ptr dominators_; + std::map phi_map; + // TODO 添加需要的变量 + + // 变量定值栈 + std::map> var_val_stack; + // phi指令对应的左值(地址) + std::map phi_lval; + + public: + Mem2Reg(Module *m) : Pass(m) {} + ~Mem2Reg() = default; + + void run() override; + + void generate_phi(); + void rename(BasicBlock *bb); + + static inline bool is_global_variable(Value *l_val) { + return dynamic_cast(l_val) != nullptr; + } + static inline bool is_gep_instr(Value *l_val) { + return dynamic_cast(l_val) != nullptr; + } + + static inline bool is_valid_ptr(Value *l_val) { + return not is_global_variable(l_val) and not is_gep_instr(l_val); + } +}; diff --git a/include/passes/PassManager.hpp b/include/passes/PassManager.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d7cd50baa0cd4681a1f521a2ea8d5beda1d75a7a --- /dev/null +++ b/include/passes/PassManager.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include "Module.hpp" + +#include +#include + +class Pass { + public: + Pass(Module *m) : m_(m) {} + virtual ~Pass() = default; + virtual void run() = 0; + + protected: + Module *m_; +}; + +class PassManager { + public: + PassManager(Module *m) : m_(m) {} + + template + void add_pass(Args &&...args) { + passes_.emplace_back(new PassType(m_, std::forward(args)...)); + } + + void run() { + for (auto &pass : passes_) { + pass->run(); + } + } + + private: + std::vector> passes_; + Module *m_; +}; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 17a2f6642dd81c6016da48f7b637737475eb2d20..8c66d6b4b0f6a6aefa2031445e88bc4d480563c5 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,4 +4,5 @@ add_subdirectory(logging) add_subdirectory(cminusfc) add_subdirectory(lightir) add_subdirectory(io) -add_subdirectory(codegen) \ No newline at end of file +add_subdirectory(codegen) +add_subdirectory(passes) \ No newline at end of file diff --git a/src/cminusfc/CMakeLists.txt b/src/cminusfc/CMakeLists.txt index 77342fc778fa91b5e49cc6bb73258de55d9787f9..e8df6c5408b57d01ecaa93c807d5886da0f7217c 100755 --- a/src/cminusfc/CMakeLists.txt +++ b/src/cminusfc/CMakeLists.txt @@ -11,6 +11,7 @@ target_link_libraries( codegen syntax stdc++fs + passes ) install( diff --git a/src/cminusfc/main.cpp b/src/cminusfc/main.cpp index 511ad1e72f5543f1d10626f5167e98aed133efeb..b9ee2aa2fd440de09659ba5b16bb4ee62cafe4e8 100755 --- a/src/cminusfc/main.cpp +++ b/src/cminusfc/main.cpp @@ -1,7 +1,14 @@ + #include "Module.hpp" +#include "PassManager.hpp" #include "ast.hpp" #include "cminusf_builder.hpp" #include "CodeGen.hpp" +#include "PassManager.hpp" +#include "DeadCode.hpp" +#include "Mem2Reg.hpp" +#include "LoopDetection.hpp" +#include "LICM.hpp" #include #include @@ -19,6 +26,9 @@ struct Config { bool emitast{false}; bool emitasm{false}; bool emitllvm{false}; + // optization conifg + bool mem2reg{false}; + bool licm{false}; Config(int argc, char **argv) : argc(argc), argv(argv) { parse_cmd_line(); @@ -51,6 +61,18 @@ int main(int argc, char **argv) { ast.run_visitor(builder); m = builder.getModule(); + PassManager PM(m.get()); + // optimization + if(config.mem2reg) { + PM.add_pass(); + PM.add_pass(); + } + if(config.licm) { + PM.add_pass(); + PM.add_pass(); + } + PM.run(); + std::ofstream output_stream(config.output_file); if (config.emitllvm) { auto abs_path = std::filesystem::canonical(config.input_file); @@ -62,8 +84,6 @@ int main(int argc, char **argv) { codegen.run(); output_stream << codegen.print(); } - - // TODO: lab4 (IR optimization or codegen) } return 0; @@ -87,7 +107,11 @@ void Config::parse_cmd_line() { emitasm = true; } else if (argv[i] == "-emit-llvm"s) { emitllvm = true; - } else { + } else if (argv[i] == "-mem2reg"s) { + mem2reg = true; + } else if (argv[i] == "-licm"s) { + licm = true; + }else { if (input_file.empty()) { input_file = argv[i]; } else { @@ -106,14 +130,29 @@ void Config::check() { if (input_file.extension() != ".cminus") { print_err("file format not recognized"); } + if (emitllvm and emitasm) { + print_err("emit llvm and emit asm both set"); + } + if (not emitllvm and not emitasm and not emitast) { + print_err("not supported: generate executable file directly"); + } + if (licm and not mem2reg) { + print_err("licm must be used with mem2reg"); + } if (output_file.empty()) { output_file = input_file.stem(); + if (emitllvm) { + output_file.replace_extension(".ll"); + } else if (emitasm) { + output_file.replace_extension(".s"); + } } } void Config::print_help() const { std::cout << "Usage: " << exe_name - << " [-h|--help] [-o ] [-emit-ast] [-emit-llvm] [-S] " + << " [-h|--help] [-o ] [-emit-llvm] [-S] [-dump-json]" + "[-mem2reg] [-licm]" "" << std::endl; exit(0); diff --git a/src/passes/CMakeLists.txt b/src/passes/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..b22ccea803b4fefa4e4907120b4e7795f73bcb48 --- /dev/null +++ b/src/passes/CMakeLists.txt @@ -0,0 +1,9 @@ +add_library( + passes STATIC + DeadCode.cpp + Dominators.cpp + FuncInfo.cpp + LoopDetection.cpp + LICM.cpp + Mem2Reg.cpp +) \ No newline at end of file diff --git a/src/passes/DeadCode.cpp b/src/passes/DeadCode.cpp new file mode 100644 index 0000000000000000000000000000000000000000..468e37f5b1564f4d8be96f749a041e4d1b4ef6b7 --- /dev/null +++ b/src/passes/DeadCode.cpp @@ -0,0 +1,128 @@ +#include "DeadCode.hpp" +#include "logging.hpp" +#include + +// 处理流程:两趟处理,mark 标记有用变量,sweep 删除无用指令 +void DeadCode::run() { + bool changed{}; + func_info->run(); + do { + changed = false; + for (auto &F : m_->get_functions()) { + auto func = &F; + changed |= clear_basic_blocks(func); + mark(func); + changed |= sweep(func); + } + } while (changed); + LOG_INFO << "dead code pass erased " << ins_count << " instructions"; +} + +bool DeadCode::clear_basic_blocks(Function *func) { + bool changed = 0; + std::vector to_erase; + for (auto &bb1 : func->get_basic_blocks()) { + auto bb = &bb1; + if(bb->get_pre_basic_blocks().empty() && bb != func->get_entry_block()) { + to_erase.push_back(bb); + changed = 1; + } + } + for (auto &bb : to_erase) { + bb->erase_from_parent(); + delete bb; + } + return changed; +} + +void DeadCode::mark(Function *func) { + work_list.clear(); + marked.clear(); + + for (auto &bb : func->get_basic_blocks()) { + for (auto &ins : bb.get_instructions()) { + if (is_critical(&ins)) { + marked[&ins] = true; + work_list.push_back(&ins); + } + } + } + + while (work_list.empty() == false) { + auto now = work_list.front(); + work_list.pop_front(); + + mark(now); + } +} + +void DeadCode::mark(Instruction *ins) { + for (auto op : ins->get_operands()) { + auto def = dynamic_cast(op); + if (def == nullptr) + continue; + if (marked[def]) + continue; + if (def->get_function() != ins->get_function()) + continue; + marked[def] = true; + work_list.push_back(def); + } +} + +bool DeadCode::sweep(Function *func) { + std::unordered_set wait_del{}; + for (auto &bb : func->get_basic_blocks()) { + for (auto it = bb.get_instructions().begin(); + it != bb.get_instructions().end();) { + if (marked[&*it]) { + ++it; + continue; + } else { + auto tmp = &*it; + wait_del.insert(tmp); + it++; + } + } + } + for (auto inst : wait_del) + inst->remove_all_operands(); + for (auto inst : wait_del) + inst->get_parent()->get_instructions().erase(inst); + ins_count += wait_del.size(); + return not wait_del.empty(); // changed +} + +bool DeadCode::is_critical(Instruction *ins) { + // 对纯函数的无用调用也可以在删除之列 + if (ins->is_call()) { + auto call_inst = dynamic_cast(ins); + auto callee = dynamic_cast(call_inst->get_operand(0)); + if (func_info->is_pure_function(callee)) + return false; + return true; + } + if (ins->is_br() || ins->is_ret()) + return true; + if (ins->is_store()) + return true; + return false; +} + +void DeadCode::sweep_globally() { + std::vector unused_funcs; + std::vector unused_globals; + for (auto &f_r : m_->get_functions()) { + if (f_r.get_use_list().size() == 0 and f_r.get_name() != "main") + unused_funcs.push_back(&f_r); + } + for (auto &glob_var_r : m_->get_global_variable()) { + if (glob_var_r.get_use_list().size() == 0) + unused_globals.push_back(&glob_var_r); + } + // changed |= unused_funcs.size() or unused_globals.size(); + for (auto func : unused_funcs) + m_->get_functions().erase(func); + for (auto glob : unused_globals) + m_->get_global_variable().erase(glob); +} diff --git a/src/passes/Dominators.cpp b/src/passes/Dominators.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5b4de78d7610827c0707ed8796e6a0ed579a2703 --- /dev/null +++ b/src/passes/Dominators.cpp @@ -0,0 +1,337 @@ +#include "Dominators.hpp" +#include "Function.hpp" +#include +#include + +/** + * @brief 支配器分析的入口函数 + * + * 遍历模块中的所有函数,对每个非声明的函数执行支配关系分析。 + */ +void Dominators::run() { + for(auto &f1 : m_->get_functions()) { + auto f = &f1; + if(f->is_declaration()) + continue; + run_on_func(f); + } +} + +/** + * @brief 对单个函数执行支配关系分析 + * @param f 要分析的函数 + * + * 该函数执行完整的支配关系分析流程: + * 1. 初始化数据结构 + * 2. 创建反向后序遍历序列 + * 3. 计算直接支配者(idom) + * 4. 计算支配边界 + * 5. 构建支配树的后继关系 + * 6. 创建支配树的DFS序 + */ +void Dominators::run_on_func(Function *f) { + dom_post_order_.clear(); + dom_dfs_order_.clear(); + for(auto &bb1 : f->get_basic_blocks()) { + auto bb = &bb1; + idom_.insert({bb, nullptr}); + dom_frontier_.insert({bb, {}}); + dom_tree_succ_blocks_.insert({bb, {}}); + } + create_reverse_post_order(f); + create_idom(f); + create_dominance_frontier(f); + create_dom_tree_succ(f); + create_dom_dfs_order(f); +} + +/** + * @brief 计算两个基本块的支配关系交集 + * @param b1 第一个基本块 + * @param b2 第二个基本块 + * @return 返回在支配树上最深的同时支配b1和b2的节点 + * + * 该函数使用后序号来查找两个节点的最近公共支配者。 + * 通过在支配树上向上遍历直到找到交点。 + */ +BasicBlock *Dominators::intersect(BasicBlock *b1, BasicBlock *b2) { + while (b1 != b2) { + while (get_post_order(b1) < get_post_order(b2)) { + b1 = get_idom(b1); + } + while (get_post_order(b2) < get_post_order(b1)) { + b2 = get_idom(b2); + } + } + return b1; +} + +/** + * @brief 创建函数的反向后序遍历序列 + * @param f 要处理的函数 + * + * 通过DFS遍历CFG来构建基本块的后序遍历序列。 + * 这个序列用于后续的支配关系分析。 + */ +void Dominators::create_reverse_post_order(Function *f) { + BBSet visited; + dfs(f->get_entry_block(), visited); +} + +/** + * @brief 深度优先搜索辅助函数 + * @param bb 当前遍历的基本块 + * @param visited 已访问的基本块集合 + * + * 执行DFS遍历,维护后序遍历序列和每个基本块的后序号。 + */ +void Dominators::dfs(BasicBlock *bb, std::set &visited) { + visited.insert(bb); + for (auto &succ : bb->get_succ_basic_blocks()) { + if (visited.find(succ) == visited.end()) { + dfs(succ, visited); + } + } + post_order_vec_.push_back(bb); + post_order_.insert({bb, post_order_.size()}); +} + +/** + * @brief 计算所有基本块的直接支配者(immediate dominator) + * @param f 要分析的函数 + * + * 使用迭代算法计算每个基本块的直接支配者: + * 1. 将入口块的直接支配者设置为自身 + * 2. 重复遍历所有基本块,更新它们的直接支配者 + * 3. 当没有变化时算法终止 + */ +void Dominators::create_idom(Function *f) { + // TODO 分析得到 f 中各个基本块的 idom + throw "Unimplemented create_idom"; +} + +/** + * @brief 计算所有基本块的支配边界(dominance frontier) + * @param f 要分析的函数 + * + * 对于每个有多个前驱的基本块B: + * 从每个前驱P开始,沿着支配树向上遍历直到遇到B的直接支配者, + * 将B加入路径上所有节点的支配边界中。 + */ +void Dominators::create_dominance_frontier(Function *f) { + // TODO 分析得到 f 中各个基本块的支配边界集合 + throw "Unimplemented create_dominance_frontier"; + +} + +/** + * @brief 构建支配树的后继关系 + * @param f 要处理的函数 + * + * 基于已计算的直接支配者关系,构建支配树的子节点关系。 + * 如果A是B的直接支配者,则B是A在支配树上的后继。 + */ +void Dominators::create_dom_tree_succ(Function *f) { + // TODO 分析得到 f 中各个基本块的支配树后继 + throw "Unimplemented create_dom_tree_succ"; +} + +/** + * @brief 为支配树创建深度优先搜索序 + * @param f 要处理的函数 + * + * 该函数通过深度优先搜索遍历支配树,为每个基本块分配两个序号: + * 1. dom_tree_L_:记录DFS首次访问该节点的时间戳 + * 2. dom_tree_R_:记录DFS完成访问该节点子树的时间戳 + * + * 同时维护: + * - dom_dfs_order_:按DFS访问顺序记录基本块 + * - dom_post_order_:dom_dfs_order_的逆序 + * + * 这些序号和顺序可用于快速判断支配关系: + * 如果节点A支配节点B,则A的L值小于B的L值,且A的R值大于B的R值 + */ +void Dominators::create_dom_dfs_order(Function *f) { + // 分析得到 f 中各个基本块的支配树上的dfs序L,R + unsigned int order = 0; + std::function dfs = [&](BasicBlock *bb) { + dom_tree_L_[bb] = ++ order; + dom_dfs_order_.push_back(bb); + for (auto &succ : dom_tree_succ_blocks_[bb]) { + dfs(succ); + } + dom_tree_R_[bb] = order; + }; + dfs(f->get_entry_block()); + dom_post_order_ = + std::vector(dom_dfs_order_.rbegin(), dom_dfs_order_.rend()); +} + +/** + * @brief 打印函数的直接支配关系 + * @param f 要打印的函数 + * + * 该函数以可读格式打印函数中所有基本块的直接支配者(immediate dominator)。 + * 输出格式为: + * 基本块名: 其直接支配者名 + * 如果基本块没有直接支配者(如入口块),则显示"null"。 + */ +void Dominators::print_idom(Function *f) { + f->get_parent()->set_print_name(); + int counter = 0; + std::map bb_id; + for (auto &bb1 : f->get_basic_blocks()) { + auto bb = &bb1; + if (bb->get_name().empty()) + bb_id[bb] = "bb" + std::to_string(counter); + else + bb_id[bb] = bb->get_name(); + counter++; + } + printf("Immediate dominance of function %s:\n", f->get_name().c_str()); + for (auto &bb1 : f->get_basic_blocks()) { + auto bb = &bb1; + std::string output; + output = bb_id[bb] + ": "; + if (get_idom(bb)) { + output += bb_id[get_idom(bb)]; + } else { + output += "null"; + } + printf("%s\n", output.c_str()); + } +} + +/** + * @brief 打印函数的支配边界信息 + * @param f 要打印的函数 + * + * 该函数以可读格式打印函数中所有基本块的支配边界(dominance frontier)。 + * 输出格式为: + * 基本块名: 支配边界中的基本块列表 + * 如果基本块没有支配边界,则显示"null"。 + */ +void Dominators::print_dominance_frontier(Function *f) { + f->get_parent()->set_print_name(); + int counter = 0; + std::map bb_id; + for (auto &bb1 : f->get_basic_blocks()) { + auto bb = &bb1; + if (bb->get_name().empty()) + bb_id[bb] = "bb" + std::to_string(counter); + else + bb_id[bb] = bb->get_name(); + counter++; + } + printf("Dominance Frontier of function %s:\n", f->get_name().c_str()); + for (auto &bb1 : f->get_basic_blocks()) { + auto bb = &bb1; + std::string output; + output = bb_id[bb] + ": "; + if (get_dominance_frontier(bb).empty()) { + output += "null"; + } else { + bool first = true; + for (auto df : get_dominance_frontier(bb)) { + if (first) { + first = false; + } else { + output += ", "; + } + output += bb_id[df]; + } + } + printf("%s\n", output.c_str()); + } +} + +/** + * @brief 将函数的控制流图(CFG)导出为图形文件 + * @param f 要导出的函数 + * + * 该函数生成函数的控制流图的DOT格式描述,并使用graphviz将其转换为PNG图像。 + * 生成两个文件: + * - {函数名}_cfg.dot:DOT格式的图形描述 + * - {函数名}_cfg.png:可视化的控制流图 + */ +void Dominators::dump_cfg(Function *f) +{ + f->get_parent()->set_print_name(); + if(f->is_declaration()) + return; + std::vector edge_set; + bool has_edges = false; + for (auto &bb : f->get_basic_blocks()) { + auto succ_blocks = bb.get_succ_basic_blocks(); + if(!succ_blocks.empty()) + has_edges = true; + for (auto succ : succ_blocks) { + edge_set.push_back('\t' + bb.get_name() + "->" + succ->get_name() + ";\n"); + } + } + std::string digraph = "digraph G {\n"; + if (!has_edges && !f->get_basic_blocks().empty()) { + // 如果没有边且至少有一个基本块,添加一个自环以显示唯一的基本块 + auto &bb = f->get_basic_blocks().front(); + digraph += '\t' + bb.get_name() + ";\n"; + } else { + for (auto &edge : edge_set) { + digraph += edge; + } + } + digraph += "}\n"; + std::ofstream file_output; + file_output.open(f->get_name() + "_cfg.dot", std::ios::out); + file_output << digraph; + file_output.close(); + std::string dot_cmd = "dot -Tpng " + f->get_name() + "_cfg.dot" + " -o " + f->get_name() + "_cfg.png"; + std::system(dot_cmd.c_str()); +} + +/** + * @brief 将函数的支配树导出为图形文件 + * @param f 要导出的函数 + * + * 该函数生成函数的支配树的DOT格式描述,并使用graphviz将其转换为PNG图像。 + * 生成两个文件: + * - {函数名}_dom_tree.dot:DOT格式的图形描述 + * - {函数名}_dom_tree.png:可视化的支配树 + */ +void Dominators::dump_dominator_tree(Function *f) +{ + f->get_parent()->set_print_name(); + if(f->is_declaration()) + return; + + std::vector edge_set; + bool has_edges = false; // 用于检查是否有边存在 + + for (auto &b : f->get_basic_blocks()) { + if (idom_.find(&b) != idom_.end() && idom_[&b] != &b) { + edge_set.push_back('\t' + idom_[&b]->get_name() + "->" + b.get_name() + ";\n"); + has_edges = true; // 如果存在支配边,标记为 true + } + } + + std::string digraph = "digraph G {\n"; + + if (!has_edges && !f->get_basic_blocks().empty()) { + // 如果没有边且至少有一个基本块,直接添加该块以显示它 + auto &b = f->get_basic_blocks().front(); + digraph += '\t' + b.get_name() + ";\n"; + } else { + for (auto &edge : edge_set) { + digraph += edge; + } + } + + digraph += "}\n"; + + std::ofstream file_output; + file_output.open(f->get_name() + "_dom_tree.dot", std::ios::out); + file_output << digraph; + file_output.close(); + + std::string dot_cmd = "dot -Tpng " + f->get_name() + "_dom_tree.dot" + " -o " + f->get_name() + "_dom_tree.png"; + std::system(dot_cmd.c_str()); +} \ No newline at end of file diff --git a/src/passes/FuncInfo.cpp b/src/passes/FuncInfo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8cf92ed4d2bbb55bf2b489c79a1b3dcb5465dbed --- /dev/null +++ b/src/passes/FuncInfo.cpp @@ -0,0 +1,110 @@ +#include "FuncInfo.hpp" +#include "Function.hpp" + +void FuncInfo::run() { + for (auto &f : m_->get_functions()) { + auto func = &f; + trivial_mark(func); + if (not is_pure[func]) + worklist.push_back(func); + } + while (worklist.empty() == false) { + auto now = worklist.front(); + worklist.pop_front(); + process(now); + } + log(); +} + +void FuncInfo::log() { + for (auto it : is_pure) { + LOG_INFO << it.first->get_name() << " is pure? " << it.second; + } +} + +// 有 store 操作的函数非纯函数来处理 +void FuncInfo::trivial_mark(Function *func) { + if (func->is_declaration() or func->get_name() == "main") { + is_pure[func] = false; + return; + } + // 只要传入数组,都作为非纯函数处理 + for (auto it = func->get_function_type()->param_begin(); + it != func->get_function_type()->param_end(); ++it) { + auto arg_type = *it; + if (arg_type->is_integer_type() == false and + arg_type->is_float_type() == false) { + is_pure[func] = false; + return; + } + } + for (auto &bb : func->get_basic_blocks()) + for (auto &inst : bb.get_instructions()) { + if (is_side_effect_inst(&inst)) { + is_pure[func] = false; + return; + } + } + is_pure[func] = true; +} + +void FuncInfo::process(Function *func) { + for (auto &use : func->get_use_list()) { + LOG_INFO << use.val_->print() << " uses func: " << func->get_name(); + if (auto inst = dynamic_cast(use.val_)) { + auto func = (inst->get_parent()->get_parent()); + if (is_pure[func]) { + is_pure[func] = false; + worklist.push_back(func); + } + } else + LOG_WARNING << "Value besides instruction uses a function"; + } +} + +// 对局部变量进行 store 没有副作用 +bool FuncInfo::is_side_effect_inst(Instruction *inst) { + if (inst->is_store()) { + if (is_local_store(dynamic_cast(inst))) + return false; + return true; + } + if (inst->is_load()) { + if (is_local_load(dynamic_cast(inst))) + return false; + return true; + } + // call 指令的副作用会在后续 bfs 中计算 + return false; +} + +bool FuncInfo::is_local_load(LoadInst *inst) { + auto addr = + dynamic_cast(get_first_addr(inst->get_operand(0))); + if (addr and addr->is_alloca()) + return true; + return false; +} + +bool FuncInfo::is_local_store(StoreInst *inst) { + auto addr = dynamic_cast(get_first_addr(inst->get_lval())); + if (addr and addr->is_alloca()) + return true; + return false; +} +Value *FuncInfo::get_first_addr(Value *val) { + if (auto inst = dynamic_cast(val)) { + if (inst->is_alloca()) + return inst; + if (inst->is_gep()) + return get_first_addr(inst->get_operand(0)); + if (inst->is_load()) + return val; + LOG_WARNING << "FuncInfo: try to determine addr in operands"; + for (auto op : inst->get_operands()) { + if (op->get_type()->is_pointer_type()) + return get_first_addr(op); + } + } + return val; +} diff --git a/src/passes/LICM.cpp b/src/passes/LICM.cpp new file mode 100644 index 0000000000000000000000000000000000000000..345aa03d4726844e04621adb99e95935ecb6cb68 --- /dev/null +++ b/src/passes/LICM.cpp @@ -0,0 +1,132 @@ +#include "BasicBlock.hpp" +#include "Constant.hpp" +#include "Function.hpp" +#include "GlobalVariable.hpp" +#include "Instruction.hpp" +#include "LICM.hpp" +#include "PassManager.hpp" +#include +#include +#include + +/** + * @brief 循环不变式外提Pass的主入口函数 + * + */ +void LoopInvariantCodeMotion::run() { + + loop_detection_ = std::make_unique(m_); + loop_detection_->run(); + func_info_ = std::make_unique(m_); + func_info_->run(); + for (auto &loop : loop_detection_->get_loops()) { + is_loop_done_[loop] = false; + } + + for (auto &loop : loop_detection_->get_loops()) { + traverse_loop(loop); + } +} + +/** + * @brief 遍历循环及其子循环 + * @param loop 当前要处理的循环 + * + */ +void LoopInvariantCodeMotion::traverse_loop(std::shared_ptr loop) { + if (is_loop_done_[loop]) { + return; + } + is_loop_done_[loop] = true; + for (auto &sub_loop : loop->get_sub_loops()) { + traverse_loop(sub_loop); + } + run_on_loop(loop); +} + // 1. 遍历当前循环及其子循环的所有指令 + // 2. 收集所有指令到loop_instructions中 + // 3. 检查store指令是否修改了全局变量,如果是则添加到updated_global中 + // 4. 检查是否包含非纯函数调用,如果有则设置contains_impure_call为true +void LoopInvariantCodeMotion::collect_loop_info( + std::shared_ptr loop, + std::set &loop_instructions, + std::set &updated_global, + bool &contains_impure_call) { + + throw std::runtime_error("Lab4: 你有一个TODO需要完成!"); +} + +/** + * @brief 对单个循环执行不变式外提优化 + * @param loop 要优化的循环 + * + */ +void LoopInvariantCodeMotion::run_on_loop(std::shared_ptr loop) { + std::set loop_instructions; + std::set updated_global; + bool contains_impure_call = false; + collect_loop_info(loop, loop_instructions, updated_global, contains_impure_call); + + std::vector loop_invariant; + + + // TODO: 识别循环不变式指令 + // + // - 如果指令已被标记为不变式则跳过 + // - 跳过 store、ret、br、phi 等指令与非纯函数调用 + // - 特殊处理全局变量的 load 指令 + // - 检查指令的所有操作数是否都是循环不变的 + // - 如果有新的不变式被添加则注意更新 changed 标志,继续迭代 + + bool changed; + do { + changed = false; + + throw std::runtime_error("Lab4: 你有一个TODO需要完成!"); + + } while (changed); + + if (loop->get_preheader() == nullptr) { + loop->set_preheader( + BasicBlock::create(m_, "", loop->get_header()->get_parent())); + } + + if (loop_invariant.empty()) + return; + + // insert preheader + auto preheader = loop->get_preheader(); + + // TODO: 更新 phi 指令 + for (auto &phi_inst_ : loop->get_header()->get_instructions()) { + if (phi_inst_.get_instr_type() != Instruction::phi) + break; + + throw std::runtime_error("Lab4: 你有一个TODO需要完成!"); + } + + // TODO: 用跳转指令重构控制流图 + // 将所有非 latch 的 header 前驱块的跳转指向 preheader + // 并将 preheader 的跳转指向 header + // 注意这里需要更新前驱块的后继和后继的前驱 + std::vector pred_to_remove; + for (auto &pred : loop->get_header()->get_pre_basic_blocks()) { + throw std::runtime_error("Lab4: 你有一个TODO需要完成!"); + } + + for (auto &pred : pred_to_remove) { + loop->get_header()->remove_pre_basic_block(pred); + } + + // TODO: 外提循环不变指令 + throw std::runtime_error("Lab4: 你有一个TODO需要完成!"); + + // insert preheader br to header + BranchInst::create_br(loop->get_header(), preheader); + + // insert preheader to parent loop + if (loop->get_parent() != nullptr) { + loop->get_parent()->add_block(preheader); + } +} + diff --git a/src/passes/LoopDetection.cpp b/src/passes/LoopDetection.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c7d8b7436b6804a54c7aa0978412c4665f13f5c3 --- /dev/null +++ b/src/passes/LoopDetection.cpp @@ -0,0 +1,135 @@ +#include "LoopDetection.hpp" +#include "Dominators.hpp" +#include + +/** + * @brief 循环检测Pass的主入口函数 + * + * 该函数执行以下步骤: + * 1. 创建支配树分析实例 + * 2. 遍历模块中的所有函数 + * 3. 对每个非声明函数执行循环检测 + * 4. 最后打印检测结果 + */ +void LoopDetection::run() { + dominators_ = std::make_unique(m_); + for (auto &f1 : m_->get_functions()) { + auto f = &f1; + if (f->is_declaration()) + continue; + func_ = f; + run_on_func(f); + } + print(); +} + +/** + * @brief 发现循环及其子循环 + * @param bb 循环的header块 + * @param latches 循环的回边终点(latch)集合 + * @param loop 当前正在处理的循环对象 + */ +void LoopDetection::discover_loop_and_sub_loops(BasicBlock *bb, BBset &latches, + std::shared_ptr loop) { + // TODO List: + // 1. 初始化工作表,将所有latch块加入 + // 2. 实现主循环逻辑 + // 3. 处理未分配给任何循环的节点 + // 4. 处理已属于其他循环的节点 + // 5. 建立正确的循环嵌套关系 + + BBvec work_list = {latches.begin(), latches.end()}; // 初始化工作表 + + while (!work_list.empty()) { // 当工作表非空时继续处理 + auto bb = work_list.back(); + work_list.pop_back(); + + // TODO-1: 处理未分配给任何循环的节点 + if (bb_to_loop_.find(bb) == bb_to_loop_.end()) { + /* 在此添加代码: + * 1. 使用loop->add_block将bb加入当前循环 + * 2. 更新bb_to_loop_映射 + * 3. 将bb的所有前驱加入工作表 + */ + } + // TODO-2: 处理已属于其他循环的节点 + else if (bb_to_loop_[bb] != loop) { + /* 在此添加代码: + * 1. 获取bb当前所属的循环sub_loop + * 2. 找到sub_loop的最顶层父循环 + * 3. 检查是否需要继续处理 + * 4. 建立循环嵌套关系: + * - 设置父循环 + * - 添加子循环 + * 5. 将子循环header的前驱加入工作表 + */ + } + } +} + +/** + * @brief 对单个函数执行循环检测 + * @param f 要分析的函数 + * + * 该函数通过以下步骤检测循环: + * 1. 运行支配树分析 + * 2. 按支配树后序遍历所有基本块 + * 3. 对每个块,检查其前驱是否存在回边 + * 4. 如果存在回边,创建新的循环并: + * - 设置循环header + * - 添加latch节点 + * - 发现循环体和子循环 + */ +void LoopDetection::run_on_func(Function *f) { + dominators_->run_on_func(f); + for (auto &bb1 : dominators_->get_dom_post_order()) { + auto bb = bb1; + BBset latches; + for (auto &pred : bb->get_pre_basic_blocks()) { + if (dominators_->is_dominate(bb, pred)) { + // pred is a back edge + // pred -> bb , pred is the latch node + latches.insert(pred); + } + } + if (latches.empty()) { + continue; + } + // create loop + auto loop = std::make_shared(bb); + bb_to_loop_[bb] = loop; + // add latch nodes + for (auto &latch : latches) { + loop->add_latch(latch); + } + loops_.push_back(loop); + discover_loop_and_sub_loops(bb, latches, loop); + } +} + +/** + * @brief 打印循环检测的结果 + * + * 为每个检测到的循环打印: + * 1. 循环的header块 + * 2. 循环包含的所有基本块 + * 3. 循环的所有子循环 + */ +void LoopDetection::print() { + m_->set_print_name(); + std::cerr << "Loop Detection Result:" << std::endl; + for (auto &loop : loops_) { + std::cerr << "Loop header: " << loop->get_header()->get_name() + << std::endl; + std::cerr << "Loop blocks: "; + for (auto &bb : loop->get_blocks()) { + std::cerr << bb->get_name() << " "; + } + std::cerr << std::endl; + std::cerr << "Sub loops: "; + for (auto &sub_loop : loop->get_sub_loops()) { + std::cerr << sub_loop->get_header()->get_name() << " "; + } + std::cerr << std::endl; + } +} \ No newline at end of file diff --git a/src/passes/Mem2Reg.cpp b/src/passes/Mem2Reg.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d6b498586a428fbd1703d6cc22caf6c2c5a211de --- /dev/null +++ b/src/passes/Mem2Reg.cpp @@ -0,0 +1,119 @@ +#include "Mem2Reg.hpp" +#include "IRBuilder.hpp" +#include "Value.hpp" + +#include + +/** + * @brief Mem2Reg Pass的主入口函数 + * + * 该函数执行内存到寄存器的提升过程,将栈上的局部变量提升到SSA格式。 + * 主要步骤: + * 1. 创建并运行支配树分析 + * 2. 对每个非声明函数: + * - 清空相关数据结构 + * - 插入必要的phi指令 + * - 执行变量重命名 + * + * 注意:函数执行后,冗余的局部变量分配指令将由后续的死代码删除Pass处理 + */ +void Mem2Reg::run() { + // 创建支配树分析 Pass 的实例 + dominators_ = std::make_unique(m_); + // 建立支配树 + dominators_->run(); + // 以函数为单元遍历实现 Mem2Reg 算法 + for (auto &f : m_->get_functions()) { + if (f.is_declaration()) + continue; + func_ = &f; + var_val_stack.clear(); + phi_lval.clear(); + if (func_->get_basic_blocks().size() >= 1) { + // 对应伪代码中 phi 指令插入的阶段 + generate_phi(); + // 对应伪代码中重命名阶段 + rename(func_->get_entry_block()); + } + // 后续 DeadCode 将移除冗余的局部变量的分配空间 + } +} + +/** + * @brief 在必要的位置插入phi指令 + * + * 该函数实现了经典的phi节点插入算法: + * 1. 收集全局活跃变量: + * - 扫描所有store指令 + * - 识别在多个基本块中被赋值的变量 + * + * 2. 插入phi指令: + * - 对每个全局活跃变量 + * - 在其定值点的支配边界处插入phi指令 + * - 使用工作表法处理迭代式的phi插入 + * + * phi指令的插入遵循最小化原则,只在必要的位置插入phi节点 + */ +void Mem2Reg::generate_phi() { + // global_live_var_name 是全局名字集合,以 alloca 出的局部变量来统计。 + // 步骤一:找到活跃在多个 block 的全局名字集合,以及它们所属的 bb 块 + std::set global_live_var_name; + std::map> live_var_2blocks; + for (auto &bb : func_->get_basic_blocks()) { + std::set var_is_killed; + for (auto &instr : bb.get_instructions()) { + if (instr.is_store()) { + // store i32 a, i32 *b + // a is r_val, b is l_val + auto l_val = static_cast(&instr)->get_lval(); + if (is_valid_ptr(l_val)) { + global_live_var_name.insert(l_val); + live_var_2blocks[l_val].insert(&bb); + } + } + } + } + + // 步骤二:从支配树获取支配边界信息,并在对应位置插入 phi 指令 + std::map, bool> + bb_has_var_phi; // bb has phi for var + for (auto var : global_live_var_name) { + std::vector work_list; + work_list.assign(live_var_2blocks[var].begin(), + live_var_2blocks[var].end()); + for (unsigned i = 0; i < work_list.size(); i++) { + auto bb = work_list[i]; + for (auto bb_dominance_frontier_bb : + dominators_->get_dominance_frontier(bb)) { + if (bb_has_var_phi.find({bb_dominance_frontier_bb, var}) == + bb_has_var_phi.end()) { + // generate phi for bb_dominance_frontier_bb & add + // bb_dominance_frontier_bb to work list + auto phi = PhiInst::create_phi( + var->get_type()->get_pointer_element_type(), + bb_dominance_frontier_bb); + phi_lval.emplace(phi, var); + bb_dominance_frontier_bb->add_instr_begin(phi); + work_list.push_back(bb_dominance_frontier_bb); + bb_has_var_phi[{bb_dominance_frontier_bb, var}] = true; + } + } + } + } +} + +void Mem2Reg::rename(BasicBlock *bb) { + std::vector wait_delete; + // TODO + // 步骤一:将 phi 指令作为 lval 的最新定值,lval 即是为局部变量 alloca 出的地址空间 + // 步骤二:用 lval 最新的定值替代对应的load指令 + // 步骤三:将 store 指令的 rval,也即被存入内存的值,作为 lval 的最新定值 + // 步骤四:为 lval 对应的 phi 指令参数补充完整 + // 步骤五:对 bb 在支配树上的所有后继节点,递归执行 re_name 操作 + // 步骤六:pop出 lval 的最新定值 + + // 步骤七:清除冗余的指令 + for (auto instr : wait_delete) { + bb->erase_instr(instr); + } +} diff --git a/tests/4-opt/cleanup.sh b/tests/4-opt/cleanup.sh new file mode 100755 index 0000000000000000000000000000000000000000..78fecdf3ce08ec95e2f7a2b0db9093dedb5ee19e --- /dev/null +++ b/tests/4-opt/cleanup.sh @@ -0,0 +1,2 @@ +#!/bin/bash +rm -rf output log.txt diff --git a/tests/4-opt/eval_lab4.sh b/tests/4-opt/eval_lab4.sh new file mode 100755 index 0000000000000000000000000000000000000000..7f58c5f9523e81f21f2e07f015fc0fe03886f050 --- /dev/null +++ b/tests/4-opt/eval_lab4.sh @@ -0,0 +1,116 @@ +#!/bin/bash + +project_dir=$(realpath ../../) +io_dir=$(realpath "$project_dir"/src/io) +output_dir=output +suffix=cminus + +LOG=log.txt + +usage() { + cat </dev/null + +mkdir -p $output_dir + +truncate -s 0 $LOG + +if [ $debug_mode = false ]; then + exec 3>/dev/null 4>&1 5>&2 1>&3 2>&3 +else + exec 3>&1 +fi + +if [ $debug_mode = false ]; then + exec 1>&4 2>&5 +fi + +echo "[info] Start testing, using testcase dir: $test_dir" +# asm +for case in $testcases; do + echo "==========$case==========" >>$LOG + case_base_name=$(basename -s .$suffix "$case") + std_out_file=$test_dir/$case_base_name.out + in_file=$test_dir/$case_base_name.in + asm_file=$output_dir/$case_base_name.s + exe_file=$output_dir/$case_base_name + out_file=$output_dir/$case_base_name.out + ll_file=$output_dir/$case_base_name.ll + + echo -n "$case_base_name..." + # if debug mode on, generate .ll also + if [ $debug_mode = true ]; then + bash -c "cminusfc -mem2reg -emit-llvm $case -o $ll_file" >>$LOG 2>&1 + fi + # cminusfc compile to .s + bash -c "cminusfc -S -mem2reg $case -o $asm_file" >>$LOG 2>&1 + check_return_value $? 0 "CE" "cminusfc compiler error" || continue + + # gcc compile asm to executable + + if [ $debug_mode = true ]; then + loongarch64-unknown-linux-gnu-gcc -g -static \ + "$asm_file" "$io_dir"/io.c -o "$exe_file" \ + >>$LOG + else + loongarch64-unknown-linux-gnu-gcc -static \ + "$asm_file" "$io_dir"/io.c -o "$exe_file" \ + >>$LOG + fi + check_return_value $? 0 "CE" "gcc compiler error" || continue + + # qemu run + if [ -e "$in_file" ]; then + exec_cmd="qemu-loongarch64 $exe_file >$out_file <$in_file" + else + exec_cmd="qemu-loongarch64 $exe_file >$out_file" + fi + bash -c "$exec_cmd" + ret=$? + # remove trailing null byte in the end line + sed -i "\$s/\x00*$//" "$out_file" + # append return value + echo $ret >>"$out_file" + + # compare output + diff --strip-trailing-cr "$std_out_file" "$out_file" -y >>$LOG + check_return_value $? 0 "WA" "output differ, check $std_out_file and $out_file" || continue + + # ok + printf "\033[1;32mOK\033[0m\n" +done diff --git a/tests/4-opt/test_perf.sh b/tests/4-opt/test_perf.sh new file mode 100755 index 0000000000000000000000000000000000000000..3563fd7b536a912b16b5ecc647e65c3433d6fdba --- /dev/null +++ b/tests/4-opt/test_perf.sh @@ -0,0 +1,106 @@ +#!/bin/bash + +project_dir=$(realpath ../../) +io_dir=$(realpath "$project_dir"/src/io) +output_dir=output +suffix=cminus +flag = "" +LOG=log.txt + +check_return_value() { + rv=$1 + expected_rv=$2 + fail_msg=$3 + detail=$4 + if [ "$rv" -eq "$expected_rv" ]; then + return 0 + else + printf "\033[1;31m%s: \033[0m%s\n" "$fail_msg" "$detail" + return 1 + fi +} + +usage() { + cat </dev/null + +mkdir -p $output_dir + +truncate -s 0 $LOG + +echo "[info] Start testing, using testcase dir: $test_dir" +# asm +for case in $testcases; do + echo "==========$case==========" >>$LOG + case_base_name=$(basename -s .$suffix "$case") + in_file=$test_dir/$case_base_name.in + asm_mem2reg_on=$output_dir/${case_base_name}-$1-on.s + asm_mem2reg_off=$output_dir/${case_base_name}-$1-off.s + exe_mem2reg_on=$output_dir/${case_base_name}-$1-on + exe_mem2reg_off=$output_dir/${case_base_name}-$1-off + + echo "==========$case==========" + #### mem2reg off + # cminusfc compile to .s + bash -c "cminusfc -S $nflag $case -o $asm_mem2reg_off" >>$LOG 2>&1 + check_return_value $? 0 "CE" "cminusfc compiler error" || continue + # gcc compile asm to executable + loongarch64-unknown-linux-gnu-gcc -static \ + "$asm_mem2reg_off" "$io_dir"/io.c -o "$exe_mem2reg_off" \ + >>$LOG + check_return_value $? 0 "CE" "gcc compiler error" || continue + + #### mem2reg on + # cminusfc compile to .s + bash -c "cminusfc -S $flag $case -o $asm_mem2reg_on" >>$LOG 2>&1 + check_return_value $? 0 "CE" "cminusfc compiler error" || continue + # gcc compile asm to executable + loongarch64-unknown-linux-gnu-gcc -static \ + "$asm_mem2reg_on" "$io_dir"/io.c -o "$exe_mem2reg_on" \ + >>$LOG + check_return_value $? 0 "CE" "gcc compiler error" || continue + + echo "==========$1 off" + if [ -e "$in_file" ]; then + exec_cmd="qemu-loongarch64 $exe_mem2reg_off >/dev/null <$in_file" + else + exec_cmd="qemu-loongarch64 $exe_mem2reg_off >/dev/null" + fi + time bash -c "$exec_cmd" + echo "==========$1 on" + if [ -e "$in_file" ]; then + exec_cmd="qemu-loongarch64 $exe_mem2reg_on >/dev/null <$in_file" + else + exec_cmd="qemu-loongarch64 $exe_mem2reg_on >/dev/null" + fi + time bash -c "$exec_cmd" + +done diff --git a/tests/4-opt/testcases/functional-cases/0-io.cminus b/tests/4-opt/testcases/functional-cases/0-io.cminus new file mode 100644 index 0000000000000000000000000000000000000000..b73460e6f70228dfa1ce758f5b9182131c7d46dc --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/0-io.cminus @@ -0,0 +1,4 @@ +int main(void) { + output(input()); + return 0; +} diff --git a/tests/4-opt/testcases/functional-cases/0-io.in b/tests/4-opt/testcases/functional-cases/0-io.in new file mode 100644 index 0000000000000000000000000000000000000000..81c545efebe5f57d4cab2ba9ec294c4b0cadf672 --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/0-io.in @@ -0,0 +1 @@ +1234 diff --git a/tests/4-opt/testcases/functional-cases/0-io.out b/tests/4-opt/testcases/functional-cases/0-io.out new file mode 100644 index 0000000000000000000000000000000000000000..2b8eb81b54b5e42caf8d751595e576f6aebe7a42 --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/0-io.out @@ -0,0 +1,2 @@ +1234 +0 diff --git a/tests/4-opt/testcases/functional-cases/1-return.cminus b/tests/4-opt/testcases/functional-cases/1-return.cminus new file mode 100644 index 0000000000000000000000000000000000000000..91e77f24ebc661dcf7fb22883bb8ef52ccddae93 --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/1-return.cminus @@ -0,0 +1,4 @@ +int main(void) { + output(111); + return 111; +} diff --git a/tests/4-opt/testcases/functional-cases/1-return.out b/tests/4-opt/testcases/functional-cases/1-return.out new file mode 100644 index 0000000000000000000000000000000000000000..2bbe845f4ef76194eda16eaad3b846e7ba014516 --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/1-return.out @@ -0,0 +1,2 @@ +111 +111 diff --git a/tests/4-opt/testcases/functional-cases/10-float.cminus b/tests/4-opt/testcases/functional-cases/10-float.cminus new file mode 100644 index 0000000000000000000000000000000000000000..8de09f6119d7244a7df03187440e8469ef66dc96 --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/10-float.cminus @@ -0,0 +1,19 @@ +int main(void) { + float a; + float b; + float c; + + a = 1.1; + b = 1.5; + c = 1.2; + + outputFloat(a * b + c); + return 0; +} + +/* + 用 gcc 编译此文件生成汇编代码时,命令为 gcc -include io.h -S 10-float.c + 其中 io.h 位于 src/io/io.h, + + 也可以在本文件开头加上 void outputFloat(float x); +*/ diff --git a/tests/4-opt/testcases/functional-cases/10-float.out b/tests/4-opt/testcases/functional-cases/10-float.out new file mode 100644 index 0000000000000000000000000000000000000000..28c52e755c337283648fc20a7ade4ac29a98574f --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/10-float.out @@ -0,0 +1,2 @@ +2.850000 +0 diff --git a/tests/4-opt/testcases/functional-cases/11-floatcall.cminus b/tests/4-opt/testcases/functional-cases/11-floatcall.cminus new file mode 100644 index 0000000000000000000000000000000000000000..23f73d7efb499b59c207c6730c8d4f3e356b3c1c --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/11-floatcall.cminus @@ -0,0 +1,18 @@ +/* float function call */ + +float mod(float x, float y) { + int div; + div = x / y; + return x - div * y; +} + +int main(void) { + float a; + float b; + + a = 11.2; + b = 2.2; + + outputFloat(mod(a, b)); + return 0; +} diff --git a/tests/4-opt/testcases/functional-cases/11-floatcall.out b/tests/4-opt/testcases/functional-cases/11-floatcall.out new file mode 100644 index 0000000000000000000000000000000000000000..e1765193609cecdd1a26474b060effe9b0d36b69 --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/11-floatcall.out @@ -0,0 +1,2 @@ +0.200000 +0 diff --git a/tests/4-opt/testcases/functional-cases/12-global.cminus b/tests/4-opt/testcases/functional-cases/12-global.cminus new file mode 100644 index 0000000000000000000000000000000000000000..63bddbbd3feeca9e8abdedab92c3ef9bcf31b88f --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/12-global.cminus @@ -0,0 +1,47 @@ +int seed; + +int randomLCG(void) { + seed = seed * 1103515245 + 12345; + return seed; +} + +int randBin(void) { + if (randomLCG() > 0) + return 1; + else + return 0; +} + +/* random walk */ +int returnToZeroSteps(void) { + int x; + int steps; + + x = 0; + steps = 0; + + while (steps < 20) { + if (randBin()) + x = x + 1; + else + x = x - 1; + + steps = steps + 1; + if (x == 0) + return steps; + } + return 20; +} + +int main(void) { + int i; + i = 0; + + seed = 3407; + + while (i < 20) { + output(returnToZeroSteps()); + i = i + 1; + } + return 0; +} diff --git a/tests/4-opt/testcases/functional-cases/12-global.out b/tests/4-opt/testcases/functional-cases/12-global.out new file mode 100644 index 0000000000000000000000000000000000000000..66bb32318d81ec4cac480a518a337e5c7aa5c632 --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/12-global.out @@ -0,0 +1,21 @@ +4 +2 +2 +4 +8 +2 +2 +2 +2 +2 +6 +2 +10 +8 +4 +2 +20 +2 +2 +8 +0 diff --git a/tests/4-opt/testcases/functional-cases/13-complex.cminus b/tests/4-opt/testcases/functional-cases/13-complex.cminus new file mode 100644 index 0000000000000000000000000000000000000000..22232fb669dadf8765c62b62df913bbe657817c0 --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/13-complex.cminus @@ -0,0 +1,67 @@ +/* 01 背包问题 */ + +int n; +int m; + +int w[5]; +int v[5]; + +int dp[66]; /* dp[n * 11 + size] 表示前 n 个物品放入容量为 size 的背包中的最大价值,初始化为 -1 */ + +int max(int a, int b) { + if (a > b) + return a; + else + return b; +} + +/* 状态转移方程: + dp[n][size] = max(dp[n - 1][size], dp[n - 1][size - w[n]] + v[n]) + 边界条件: + dp[n][size <= 0] = 0 + dp[0][size] = 0 */ + +int knapsack(int n, int size) { + int result; + if (size <= 0) + return 0; + if (n == 0) + return 0; + if (dp[n * 11 + size] >= 0) + return dp[n * 11 + size]; + + if (size < w[n - 1]) + result = knapsack(n - 1, size); + else + result = max(knapsack(n - 1, size), knapsack(n - 1, size - w[n - 1]) + v[n - 1]); + + dp[n * 11 + size] = result; + return result; +} + +int main(void) { + int i; + i = 0; + + n = 5; + m = 10; + w[0] = 2; + w[1] = 2; + w[2] = 6; + w[3] = 5; + w[4] = 4; + + v[0] = 6; + v[1] = 3; + v[2] = 5; + v[3] = 4; + v[4] = 6; + + while (i < 66) { + dp[i] = 0 - 1; + i = i + 1; + } + + output(knapsack(n, m)); + return 0; +} diff --git a/tests/4-opt/testcases/functional-cases/13-complex.out b/tests/4-opt/testcases/functional-cases/13-complex.out new file mode 100644 index 0000000000000000000000000000000000000000..227eae2e84c4aa04d74e2afd977a8c52936dfaec --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/13-complex.out @@ -0,0 +1,2 @@ +15 +0 diff --git a/tests/4-opt/testcases/functional-cases/2-calculate.cminus b/tests/4-opt/testcases/functional-cases/2-calculate.cminus new file mode 100644 index 0000000000000000000000000000000000000000..fa4c9a1f341e58aff1d0f07e3f67ff26388c2415 --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/2-calculate.cminus @@ -0,0 +1,11 @@ +int main(void) { + int a; + int b; + int c; + + a = 23; + b = 25; + c = 4; + + return a + b * c; +} diff --git a/tests/4-opt/testcases/functional-cases/2-calculate.out b/tests/4-opt/testcases/functional-cases/2-calculate.out new file mode 100644 index 0000000000000000000000000000000000000000..190a18037c64c43e6b11489df4bf0b9eb6d2c9bf --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/2-calculate.out @@ -0,0 +1 @@ +123 diff --git a/tests/4-opt/testcases/functional-cases/3-output.cminus b/tests/4-opt/testcases/functional-cases/3-output.cminus new file mode 100644 index 0000000000000000000000000000000000000000..abe3222400d6ff8d1ac2e7e589011d97f2e23b06 --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/3-output.cminus @@ -0,0 +1,5 @@ +int main(void) { + output(11); + output(22222); + return 0; +} diff --git a/tests/4-opt/testcases/functional-cases/3-output.out b/tests/4-opt/testcases/functional-cases/3-output.out new file mode 100644 index 0000000000000000000000000000000000000000..1983173f37dfac419ee2c5b5997f62d240be0d65 --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/3-output.out @@ -0,0 +1,3 @@ +11 +22222 +0 diff --git a/tests/4-opt/testcases/functional-cases/4-if.cminus b/tests/4-opt/testcases/functional-cases/4-if.cminus new file mode 100644 index 0000000000000000000000000000000000000000..a4ba887f31161281363c4da0a69cc88a263de299 --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/4-if.cminus @@ -0,0 +1,23 @@ +int main(void) { + int a; + int b; + int c; + + a = 11; + b = 22; + c = 33; + + /* max value */ + if (a > b) { + if (a > c) + output(a); + else + output(c); + } else { + if (c < b) + output(b); + else + output(c); + } + return 0; +} diff --git a/tests/4-opt/testcases/functional-cases/4-if.out b/tests/4-opt/testcases/functional-cases/4-if.out new file mode 100644 index 0000000000000000000000000000000000000000..54a647cf204067321a9819d900b92ee655f99428 --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/4-if.out @@ -0,0 +1,2 @@ +33 +0 diff --git a/tests/4-opt/testcases/functional-cases/5-while.cminus b/tests/4-opt/testcases/functional-cases/5-while.cminus new file mode 100644 index 0000000000000000000000000000000000000000..da3313b91c0c519a1af8c0aa98e7127fe400436c --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/5-while.cminus @@ -0,0 +1,14 @@ +int main(void) { + int n; + int i; + + n = 10; + i = 0; + + while (i < n) { + output(i); + i = i + 1; + } + + return 0; +} diff --git a/tests/4-opt/testcases/functional-cases/5-while.out b/tests/4-opt/testcases/functional-cases/5-while.out new file mode 100644 index 0000000000000000000000000000000000000000..c9f2be1a9611927baea84bbe3b819b5a7a328401 --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/5-while.out @@ -0,0 +1,11 @@ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +0 diff --git a/tests/4-opt/testcases/functional-cases/6-array.cminus b/tests/4-opt/testcases/functional-cases/6-array.cminus new file mode 100644 index 0000000000000000000000000000000000000000..3383fcafa1c07a12cf3d3780fc4509e781ef0022 --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/6-array.cminus @@ -0,0 +1,15 @@ +int main(void) { + int a[10]; + int i; + + i = 0; + a[0] = 11; + a[4] = 22; + a[9] = 33; + + output(a[0]); + output(a[4]); + output(a[9]); + + return 0; +} diff --git a/tests/4-opt/testcases/functional-cases/6-array.out b/tests/4-opt/testcases/functional-cases/6-array.out new file mode 100644 index 0000000000000000000000000000000000000000..d7fcd8c808df07b274ae64b8754e1617b37003aa --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/6-array.out @@ -0,0 +1,4 @@ +11 +22 +33 +0 diff --git a/tests/4-opt/testcases/functional-cases/7-function.cminus b/tests/4-opt/testcases/functional-cases/7-function.cminus new file mode 100644 index 0000000000000000000000000000000000000000..2eb2620d1110b06d1f07ab51fbff8343e41b510c --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/7-function.cminus @@ -0,0 +1,21 @@ +int min(int a, int b) { + if (a <= b) + return a; + else + return b; +} + +int main(void) { + int a; + int b; + int c; + + a = 11; + b = 22; + c = 33; + + output(min(a, b)); + output(min(b, c)); + output(min(c, a)); + return 0; +} diff --git a/tests/4-opt/testcases/functional-cases/7-function.out b/tests/4-opt/testcases/functional-cases/7-function.out new file mode 100644 index 0000000000000000000000000000000000000000..38ea32361a25780c6da08b24aead9a02d32c3f0c --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/7-function.out @@ -0,0 +1,4 @@ +11 +22 +11 +0 diff --git a/tests/4-opt/testcases/functional-cases/8-store.cminus b/tests/4-opt/testcases/functional-cases/8-store.cminus new file mode 100644 index 0000000000000000000000000000000000000000..15a438d24d427ad15ce892d4ce25102e6154113f --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/8-store.cminus @@ -0,0 +1,26 @@ +int store(int arr[], int index, int value) { + arr[index] = value; + return value; +} + +int main(void) { + int a[10]; + int i; + int sum; + + i = 0; + while (i < 10) { + store(a, i, i * 2); + i = i + 1; + } + + sum = 0; + i = 0; + while (i < 10) { + sum = sum + a[i]; + i = i + 1; + } + + output(sum); + return 0; +} diff --git a/tests/4-opt/testcases/functional-cases/8-store.out b/tests/4-opt/testcases/functional-cases/8-store.out new file mode 100644 index 0000000000000000000000000000000000000000..d2044a0e5daa8e8d2ed3a54a15127b6c919eb4f4 --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/8-store.out @@ -0,0 +1,2 @@ +90 +0 diff --git a/tests/4-opt/testcases/functional-cases/9-fibonacci.cminus b/tests/4-opt/testcases/functional-cases/9-fibonacci.cminus new file mode 100644 index 0000000000000000000000000000000000000000..df0ee724c115a1339d59ae260be5519ea3b41c14 --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/9-fibonacci.cminus @@ -0,0 +1,23 @@ +int fibonacci(int n) { + if (n == 0) + return 0; + else if (n == 1) + return 1; + else + return fibonacci(n - 1) + fibonacci(n - 2); +} + +int main(void) { + int n; + int i; + + n = 10; + i = 0; + + while (i < n) { + output(fibonacci(i)); + i = i + 1; + } + + return 0; +} diff --git a/tests/4-opt/testcases/functional-cases/9-fibonacci.out b/tests/4-opt/testcases/functional-cases/9-fibonacci.out new file mode 100644 index 0000000000000000000000000000000000000000..f53d098dcdc78d4553b72ce722b2d7e0b055435e --- /dev/null +++ b/tests/4-opt/testcases/functional-cases/9-fibonacci.out @@ -0,0 +1,11 @@ +0 +1 +1 +2 +3 +5 +8 +13 +21 +34 +0 diff --git a/tests/4-opt/testcases/loop/baseline/loop-1.ll b/tests/4-opt/testcases/loop/baseline/loop-1.ll new file mode 100644 index 0000000000000000000000000000000000000000..5b37e400aa0b0018405a8f950dc5d72192ebcee6 --- /dev/null +++ b/tests/4-opt/testcases/loop/baseline/loop-1.ll @@ -0,0 +1,60 @@ +; ModuleID = 'cminus' +source_filename = "/home/haiqwa/2020fall-compiler_cminus/tests/lab5/./testcases/LoopInvHoist/testcase-5.cminus" + +declare i32 @input() + +declare void @output(i32) + +declare void @outputFloat(float) + +declare void @neg_idx_except() + +define void @main() { +label_entry: + br label %label3 +label3: ; preds = %label_entry, %label58 + %op61 = phi i32 [ %op64, %label58 ], [ undef, %label_entry ] + %op62 = phi i32 [ 1, %label_entry ], [ %op60, %label58 ] + %op63 = phi i32 [ %op65, %label58 ], [ undef, %label_entry ] + %op5 = icmp slt i32 %op62, 10000 + %op6 = zext i1 %op5 to i32 + %op7 = icmp ne i32 %op6, 0 + br i1 %op7, label %label8, label %label9 +label8: ; preds = %label3 + %op19 = mul i32 %op62, %op62 + %op21 = mul i32 %op19, %op62 + %op23 = mul i32 %op21, %op62 + %op25 = mul i32 %op23, %op62 + %op27 = mul i32 %op25, %op62 + %op29 = mul i32 %op27, %op62 + %op31 = mul i32 %op29, %op62 + %op33 = mul i32 %op31, %op62 + %op35 = mul i32 %op33, %op62 + %op37 = sdiv i32 %op35, %op62 + %op39 = sdiv i32 %op37, %op62 + %op41 = sdiv i32 %op39, %op62 + %op43 = sdiv i32 %op41, %op62 + %op45 = sdiv i32 %op43, %op62 + %op47 = sdiv i32 %op45, %op62 + %op49 = sdiv i32 %op47, %op62 + %op51 = sdiv i32 %op49, %op62 + %op53 = sdiv i32 %op51, %op62 + %op55 = sdiv i32 %op53, %op62 + br label %label11 +label9: ; preds = %label3 + call void @output(i32 %op61) + ret void +label11: ; preds = %label8, %label16 + %op64 = phi i32 [ %op61, %label8 ], [ %op55, %label16 ] + %op65 = phi i32 [ 0, %label8 ], [ %op57, %label16 ] + %op13 = icmp slt i32 %op65, 10000 + %op14 = zext i1 %op13 to i32 + %op15 = icmp ne i32 %op14, 0 + br i1 %op15, label %label16, label %label58 +label16: ; preds = %label11 + %op57 = add i32 %op65, 1 + br label %label11 +label58: ; preds = %label11 + %op60 = add i32 %op62, 1 + br label %label3 +} diff --git a/tests/4-opt/testcases/loop/baseline/loop-2.ll b/tests/4-opt/testcases/loop/baseline/loop-2.ll new file mode 100644 index 0000000000000000000000000000000000000000..d0983dd2ce7149344170278b5aebc7f09fd44e49 --- /dev/null +++ b/tests/4-opt/testcases/loop/baseline/loop-2.ll @@ -0,0 +1,60 @@ +; ModuleID = 'cminus' +source_filename = "/home/haiqwa/2020fall-compiler_cminus/tests/lab5/./testcases/LoopInvHoist/testcase-6.cminus" + +declare i32 @input() + +declare void @output(i32) + +declare void @outputFloat(float) + +declare void @neg_idx_except() + +define void @main() { +label_entry: + %op20 = mul i32 2, 2 + %op22 = mul i32 %op20, 2 + %op24 = mul i32 %op22, 2 + %op26 = mul i32 %op24, 2 + %op28 = mul i32 %op26, 2 + %op30 = mul i32 %op28, 2 + %op32 = mul i32 %op30, 2 + %op34 = mul i32 %op32, 2 + %op36 = mul i32 %op34, 2 + %op38 = sdiv i32 %op36, 2 + %op40 = sdiv i32 %op38, 2 + %op42 = sdiv i32 %op40, 2 + %op44 = sdiv i32 %op42, 2 + %op46 = sdiv i32 %op44, 2 + %op48 = sdiv i32 %op46, 2 + %op50 = sdiv i32 %op48, 2 + %op52 = sdiv i32 %op50, 2 + %op54 = sdiv i32 %op52, 2 + %op56 = sdiv i32 %op54, 2 + br label %label4 +label4: ; preds = %label_entry, %label59 + %op62 = phi i32 [ %op65, %label59 ], [ undef, %label_entry ] + %op63 = phi i32 [ 0, %label_entry ], [ %op61, %label59 ] + %op64 = phi i32 [ %op66, %label59 ], [ undef, %label_entry ] + %op6 = icmp slt i32 %op63, 10000000 + %op7 = zext i1 %op6 to i32 + %op8 = icmp ne i32 %op7, 0 + br i1 %op8, label %label9, label %label10 +label9: ; preds = %label4 + br label %label12 +label10: ; preds = %label4 + call void @output(i32 %op62) + ret void +label12: ; preds = %label9, %label17 + %op65 = phi i32 [ %op62, %label9 ], [ %op56, %label17 ] + %op66 = phi i32 [ 0, %label9 ], [ %op58, %label17 ] + %op14 = icmp slt i32 %op66, 2 + %op15 = zext i1 %op14 to i32 + %op16 = icmp ne i32 %op15, 0 + br i1 %op16, label %label17, label %label59 +label17: ; preds = %label12 + %op58 = add i32 %op66, 1 + br label %label12 +label59: ; preds = %label12 + %op61 = add i32 %op63, 1 + br label %label4 +} diff --git a/tests/4-opt/testcases/loop/baseline/loop-3.ll b/tests/4-opt/testcases/loop/baseline/loop-3.ll new file mode 100644 index 0000000000000000000000000000000000000000..257f877af5010ff1fa2fa4e51082c0e0cec6c6f6 --- /dev/null +++ b/tests/4-opt/testcases/loop/baseline/loop-3.ll @@ -0,0 +1,119 @@ +declare i32 @input() + +declare void @output(i32) + +declare void @outputFloat(float) + +declare void @neg_idx_except() + +define void @main() { +label_entry: + %op60 = mul i32 2, 2 + %op62 = mul i32 %op60, 2 + %op64 = mul i32 %op62, 2 + %op66 = mul i32 %op64, 2 + %op68 = mul i32 %op66, 2 + %op70 = mul i32 %op68, 2 + %op72 = mul i32 %op70, 2 + %op74 = mul i32 %op72, 2 + %op76 = mul i32 %op74, 2 + %op78 = sdiv i32 %op76, 2 + %op80 = sdiv i32 %op78, 2 + %op82 = sdiv i32 %op80, 2 + %op84 = sdiv i32 %op82, 2 + %op86 = sdiv i32 %op84, 2 + %op88 = sdiv i32 %op86, 2 + %op90 = sdiv i32 %op88, 2 + %op92 = sdiv i32 %op90, 2 + %op94 = sdiv i32 %op92, 2 + %op96 = sdiv i32 %op94, 2 + br label %label8 +label8: ; preds = %label_entry, %label22 + %op102 = phi i32 [ %op109, %label22 ], [ undef, %label_entry ] + %op103 = phi i32 [ %op110, %label22 ], [ undef, %label_entry ] + %op104 = phi i32 [ %op111, %label22 ], [ undef, %label_entry ] + %op105 = phi i32 [ %op112, %label22 ], [ undef, %label_entry ] + %op106 = phi i32 [ %op113, %label22 ], [ undef, %label_entry ] + %op107 = phi i32 [ 0, %label_entry ], [ %op24, %label22 ] + %op108 = phi i32 [ %op114, %label22 ], [ undef, %label_entry ] + %op10 = icmp slt i32 %op107, 1000000 + %op11 = zext i1 %op10 to i32 + %op12 = icmp ne i32 %op11, 0 + br i1 %op12, label %label13, label %label14 +label13: ; preds = %label8 + br label %label16 +label14: ; preds = %label8 + call void @output(i32 %op102) + ret void +label16: ; preds = %label13, %label31 + %op109 = phi i32 [ %op102, %label13 ], [ %op115, %label31 ] + %op110 = phi i32 [ %op103, %label13 ], [ %op116, %label31 ] + %op111 = phi i32 [ %op104, %label13 ], [ %op117, %label31 ] + %op112 = phi i32 [ %op105, %label13 ], [ %op118, %label31 ] + %op113 = phi i32 [ %op106, %label13 ], [ %op119, %label31 ] + %op114 = phi i32 [ 0, %label13 ], [ %op33, %label31 ] + %op18 = icmp slt i32 %op114, 2 + %op19 = zext i1 %op18 to i32 + %op20 = icmp ne i32 %op19, 0 + br i1 %op20, label %label21, label %label22 +label21: ; preds = %label16 + br label %label25 +label22: ; preds = %label16 + %op24 = add i32 %op107, 1 + br label %label8 +label25: ; preds = %label21, %label40 + %op115 = phi i32 [ %op109, %label21 ], [ %op120, %label40 ] + %op116 = phi i32 [ %op110, %label21 ], [ %op121, %label40 ] + %op117 = phi i32 [ %op111, %label21 ], [ %op122, %label40 ] + %op118 = phi i32 [ %op112, %label21 ], [ %op123, %label40 ] + %op119 = phi i32 [ 0, %label21 ], [ %op42, %label40 ] + %op27 = icmp slt i32 %op119, 2 + %op28 = zext i1 %op27 to i32 + %op29 = icmp ne i32 %op28, 0 + br i1 %op29, label %label30, label %label31 +label30: ; preds = %label25 + br label %label34 +label31: ; preds = %label25 + %op33 = add i32 %op114, 1 + br label %label16 +label34: ; preds = %label30, %label49 + %op120 = phi i32 [ %op115, %label30 ], [ %op124, %label49 ] + %op121 = phi i32 [ %op116, %label30 ], [ %op125, %label49 ] + %op122 = phi i32 [ %op117, %label30 ], [ %op126, %label49 ] + %op123 = phi i32 [ 0, %label30 ], [ %op51, %label49 ] + %op36 = icmp slt i32 %op123, 2 + %op37 = zext i1 %op36 to i32 + %op38 = icmp ne i32 %op37, 0 + br i1 %op38, label %label39, label %label40 +label39: ; preds = %label34 + br label %label43 +label40: ; preds = %label34 + %op42 = add i32 %op119, 1 + br label %label25 +label43: ; preds = %label39, %label99 + %op124 = phi i32 [ %op120, %label39 ], [ %op127, %label99 ] + %op125 = phi i32 [ %op121, %label39 ], [ %op128, %label99 ] + %op126 = phi i32 [ 0, %label39 ], [ %op101, %label99 ] + %op45 = icmp slt i32 %op126, 2 + %op46 = zext i1 %op45 to i32 + %op47 = icmp ne i32 %op46, 0 + br i1 %op47, label %label48, label %label49 +label48: ; preds = %label43 + br label %label52 +label49: ; preds = %label43 + %op51 = add i32 %op123, 1 + br label %label34 +label52: ; preds = %label48, %label57 + %op127 = phi i32 [ %op124, %label48 ], [ %op96, %label57 ] + %op128 = phi i32 [ 0, %label48 ], [ %op98, %label57 ] + %op54 = icmp slt i32 %op128, 2 + %op55 = zext i1 %op54 to i32 + %op56 = icmp ne i32 %op55, 0 + br i1 %op56, label %label57, label %label99 +label57: ; preds = %label52 + %op98 = add i32 %op128, 1 + br label %label52 +label99: ; preds = %label52 + %op101 = add i32 %op126, 1 + br label %label43 +} diff --git a/tests/4-opt/testcases/loop/baseline/loop-4.ll b/tests/4-opt/testcases/loop/baseline/loop-4.ll new file mode 100644 index 0000000000000000000000000000000000000000..838371ae861c0f3a234f7a1c95f085e2509e639a --- /dev/null +++ b/tests/4-opt/testcases/loop/baseline/loop-4.ll @@ -0,0 +1,132 @@ +declare i32 @input() + +declare void @output(i32) + +declare void @outputFloat(float) + +declare void @neg_idx_except() + +define void @main() { +label_entry: + %op71 = mul i32 2, 2 + %op73 = mul i32 %op71, 2 + %op75 = mul i32 %op73, 2 + %op77 = mul i32 %op75, 2 + %op79 = mul i32 %op77, 2 + %op81 = mul i32 %op79, 2 + %op83 = mul i32 %op81, 2 + %op85 = mul i32 %op83, 2 + %op87 = mul i32 %op85, 2 + %op89 = sdiv i32 %op87, 2 + %op91 = sdiv i32 %op89, 2 + %op93 = sdiv i32 %op91, 2 + %op95 = sdiv i32 %op93, 2 + %op97 = sdiv i32 %op95, 2 + %op99 = sdiv i32 %op97, 2 + %op101 = sdiv i32 %op99, 2 + %op103 = sdiv i32 %op101, 2 + %op105 = sdiv i32 %op103, 2 + %op107 = sdiv i32 %op105, 2 + %op59 = icmp sgt i32 2, 1 + %op60 = zext i1 %op59 to i32 + %op61 = icmp ne i32 %op60, 0 + br label %label8 +label8: ; preds = %label_entry, %label22 + %op110 = phi i32 [ %op117, %label22 ], [ undef, %label_entry ] + %op111 = phi i32 [ %op118, %label22 ], [ undef, %label_entry ] + %op112 = phi i32 [ %op119, %label22 ], [ undef, %label_entry ] + %op113 = phi i32 [ %op120, %label22 ], [ undef, %label_entry ] + %op114 = phi i32 [ %op121, %label22 ], [ undef, %label_entry ] + %op115 = phi i32 [ 0, %label_entry ], [ %op24, %label22 ] + %op116 = phi i32 [ %op122, %label22 ], [ undef, %label_entry ] + %op10 = icmp slt i32 %op115, 1000000 + %op11 = zext i1 %op10 to i32 + %op12 = icmp ne i32 %op11, 0 + br i1 %op12, label %label13, label %label14 +label13: ; preds = %label8 + br label %label16 +label14: ; preds = %label8 + call void @output(i32 %op110) + ret void +label16: ; preds = %label13, %label31 + %op117 = phi i32 [ %op110, %label13 ], [ %op123, %label31 ] + %op118 = phi i32 [ %op111, %label13 ], [ %op124, %label31 ] + %op119 = phi i32 [ %op112, %label13 ], [ %op125, %label31 ] + %op120 = phi i32 [ %op113, %label13 ], [ %op126, %label31 ] + %op121 = phi i32 [ %op114, %label13 ], [ %op127, %label31 ] + %op122 = phi i32 [ 0, %label13 ], [ %op33, %label31 ] + %op18 = icmp slt i32 %op122, 2 + %op19 = zext i1 %op18 to i32 + %op20 = icmp ne i32 %op19, 0 + br i1 %op20, label %label21, label %label22 +label21: ; preds = %label16 + br label %label25 +label22: ; preds = %label16 + %op24 = add i32 %op115, 1 + br label %label8 +label25: ; preds = %label21, %label40 + %op123 = phi i32 [ %op117, %label21 ], [ %op129, %label40 ] + %op124 = phi i32 [ %op118, %label21 ], [ %op130, %label40 ] + %op125 = phi i32 [ %op119, %label21 ], [ %op131, %label40 ] + %op126 = phi i32 [ %op120, %label21 ], [ %op132, %label40 ] + %op127 = phi i32 [ 0, %label21 ], [ %op42, %label40 ] + %op128 = phi i32 [ %op122, %label21 ], [ %op133, %label40 ] + %op27 = icmp slt i32 %op127, 2 + %op28 = zext i1 %op27 to i32 + %op29 = icmp ne i32 %op28, 0 + br i1 %op29, label %label30, label %label31 +label30: ; preds = %label25 + br label %label34 +label31: ; preds = %label25 + %op33 = add i32 %op128, 1 + br label %label16 +label34: ; preds = %label30, %label49 + %op129 = phi i32 [ %op123, %label30 ], [ %op134, %label49 ] + %op130 = phi i32 [ %op124, %label30 ], [ %op135, %label49 ] + %op131 = phi i32 [ %op125, %label30 ], [ %op136, %label49 ] + %op132 = phi i32 [ 0, %label30 ], [ %op51, %label49 ] + %op133 = phi i32 [ %op128, %label30 ], [ %op137, %label49 ] + %op36 = icmp slt i32 %op132, 2 + %op37 = zext i1 %op36 to i32 + %op38 = icmp ne i32 %op37, 0 + br i1 %op38, label %label39, label %label40 +label39: ; preds = %label34 + br label %label43 +label40: ; preds = %label34 + %op42 = add i32 %op127, 1 + br label %label25 +label43: ; preds = %label39, %label62 + %op134 = phi i32 [ %op129, %label39 ], [ %op138, %label62 ] + %op135 = phi i32 [ %op130, %label39 ], [ %op139, %label62 ] + %op136 = phi i32 [ 0, %label39 ], [ %op64, %label62 ] + %op137 = phi i32 [ %op133, %label39 ], [ %op140, %label62 ] + %op45 = icmp slt i32 %op136, 2 + %op46 = zext i1 %op45 to i32 + %op47 = icmp ne i32 %op46, 0 + br i1 %op47, label %label48, label %label49 +label48: ; preds = %label43 + br label %label52 +label49: ; preds = %label43 + %op51 = add i32 %op132, 1 + br label %label34 +label52: ; preds = %label48, %label68 + %op138 = phi i32 [ %op134, %label48 ], [ %op107, %label68 ] + %op139 = phi i32 [ 0, %label48 ], [ %op109, %label68 ] + %op140 = phi i32 [ %op137, %label48 ], [ %op141, %label68 ] + %op54 = icmp slt i32 %op139, 2 + %op55 = zext i1 %op54 to i32 + %op56 = icmp ne i32 %op55, 0 + br i1 %op56, label %label57, label %label62 +label57: ; preds = %label52 + br i1 %op61, label %label65, label %label68 +label62: ; preds = %label52 + %op64 = add i32 %op136, 1 + br label %label43 +label65: ; preds = %label57 + %op67 = add i32 %op140, 1 + br label %label68 +label68: ; preds = %label57, %label65 + %op141 = phi i32 [ %op140, %label57 ], [ %op67, %label65 ] + %op109 = add i32 %op139, 1 + br label %label52 +} diff --git a/tests/4-opt/testcases/loop/loop-1.cminus b/tests/4-opt/testcases/loop/loop-1.cminus new file mode 100644 index 0000000000000000000000000000000000000000..82ce6d3cb5f2f55956ebef35dc340924a577255e --- /dev/null +++ b/tests/4-opt/testcases/loop/loop-1.cminus @@ -0,0 +1,20 @@ +void main(void){ + int i; + int j; + int ret; + + i = 1; + + while(i<10000) + { + j = 0; + while(j<10000) + { + ret = (i*i*i*i*i*i*i*i*i*i)/i/i/i/i/i/i/i/i/i/i; + j=j+1; + } + i=i+1; + } + output(ret); + return ; +} \ No newline at end of file diff --git a/tests/4-opt/testcases/loop/loop-1.out b/tests/4-opt/testcases/loop/loop-1.out new file mode 100644 index 0000000000000000000000000000000000000000..573541ac9702dd3969c9bc859d2b91ec1f7e6e56 --- /dev/null +++ b/tests/4-opt/testcases/loop/loop-1.out @@ -0,0 +1 @@ +0 diff --git a/tests/4-opt/testcases/loop/loop-2.cminus b/tests/4-opt/testcases/loop/loop-2.cminus new file mode 100644 index 0000000000000000000000000000000000000000..920c1ad9c6dd630df4a9916a723a80383c4f81a1 --- /dev/null +++ b/tests/4-opt/testcases/loop/loop-2.cminus @@ -0,0 +1,23 @@ +void main(void){ + int i; + int j; + int a; + int ret; + + i = 0; + a = 2; + + while(i<10000000) + { + j = 0; + + while(j<2) + { + ret = (a*a*a*a*a*a*a*a*a*a)/a/a/a/a/a/a/a/a/a/a; + j=j+1; + } + i=i+1; + } + output(ret); + return ; +} \ No newline at end of file diff --git a/tests/4-opt/testcases/loop/loop-2.out b/tests/4-opt/testcases/loop/loop-2.out new file mode 100644 index 0000000000000000000000000000000000000000..d00491fd7e5bb6fa28c517a0bb32b8b506539d4d --- /dev/null +++ b/tests/4-opt/testcases/loop/loop-2.out @@ -0,0 +1 @@ +1 diff --git a/tests/4-opt/testcases/loop/loop-3.cminus b/tests/4-opt/testcases/loop/loop-3.cminus new file mode 100644 index 0000000000000000000000000000000000000000..8858c838c076a23df9b577485bd0a4114b108169 --- /dev/null +++ b/tests/4-opt/testcases/loop/loop-3.cminus @@ -0,0 +1,46 @@ +void main(void){ + int i; + int j; + int k; + int o; + int p; + int q; + int a; + int ret; + + a = 2; + + i = 0; + while(i<1000000) + { + j = 0; + while(j<2) + { + k = 0; + while(k<2) + { + o = 0; + while(o<2) + { + p = 0; + while(p<2) + { + q = 0; + while(q<2) + { + ret = (a*a*a*a*a*a*a*a*a*a)/a/a/a/a/a/a/a/a/a/a; + q=q+1; + } + p=p+1; + } + o=o+1; + } + k=k+1; + } + j=j+1; + } + i=i+1; + } + output(ret); + return ; +} \ No newline at end of file diff --git a/tests/4-opt/testcases/loop/loop-3.out b/tests/4-opt/testcases/loop/loop-3.out new file mode 100644 index 0000000000000000000000000000000000000000..d00491fd7e5bb6fa28c517a0bb32b8b506539d4d --- /dev/null +++ b/tests/4-opt/testcases/loop/loop-3.out @@ -0,0 +1 @@ +1 diff --git a/tests/4-opt/testcases/loop/loop-4.cminus b/tests/4-opt/testcases/loop/loop-4.cminus new file mode 100644 index 0000000000000000000000000000000000000000..287098a7e602c453e0208584c5edc9aceb26139a --- /dev/null +++ b/tests/4-opt/testcases/loop/loop-4.cminus @@ -0,0 +1,50 @@ +void main(void){ + int i; + int j; + int k; + int o; + int p; + int q; + int a; + int ret; + + a = 2; + + i = 0; + while(i<1000000) + { + j = 0; + while(j<2) + { + k = 0; + while(k<2) + { + o = 0; + while(o<2) + { + p = 0; + while(p<2) + { + q = 0; + while(q<2) + { + if( a > 1 ) + { + j = j+1; + } + ret = (a*a*a*a*a*a*a*a*a*a)/a/a/a/a/a/a/a/a/a/a; + q=q+1; + } + p=p+1; + } + o=o+1; + } + k=k+1; + } + j=j+1; + } + i=i+1; + } + output(ret); + return ; +} \ No newline at end of file diff --git a/tests/4-opt/testcases/loop/loop-4.out b/tests/4-opt/testcases/loop/loop-4.out new file mode 100644 index 0000000000000000000000000000000000000000..d00491fd7e5bb6fa28c517a0bb32b8b506539d4d --- /dev/null +++ b/tests/4-opt/testcases/loop/loop-4.out @@ -0,0 +1 @@ +1 diff --git a/tests/4-opt/testcases/mem2reg/baseline/mem2reg-1 b/tests/4-opt/testcases/mem2reg/baseline/mem2reg-1 new file mode 100755 index 0000000000000000000000000000000000000000..60e63e1726a9637f28dca2ff7a88d79bc99ba30e Binary files /dev/null and b/tests/4-opt/testcases/mem2reg/baseline/mem2reg-1 differ diff --git a/tests/4-opt/testcases/mem2reg/baseline/mem2reg-1.ll b/tests/4-opt/testcases/mem2reg/baseline/mem2reg-1.ll new file mode 100644 index 0000000000000000000000000000000000000000..00b6e15560fc5d4037c4ffb6dd2f8fb1639a3ace --- /dev/null +++ b/tests/4-opt/testcases/mem2reg/baseline/mem2reg-1.ll @@ -0,0 +1,54 @@ +; ModuleID = 'cminus' +source_filename = "/home/zox/compiler/2024ustc-jianmu-compiler-ta/tests/4-mem2reg/performance-cases/testcase-1.cminus" + +declare i32 @input() + +declare void @output(i32) + +declare void @outputFloat(float) + +declare void @neg_idx_except() + +define void @main() { +label_entry: + %op0 = call i32 @input() + br label %label1 +label1: ; preds = %label_entry, %label7 + %op2 = phi i32 [ 0, %label_entry ], [ %op33, %label7 ] + %op3 = phi i32 [ 0, %label_entry ], [ %op32, %label7 ] + %op4 = icmp slt i32 %op2, %op0 + %op5 = zext i1 %op4 to i32 + %op6 = icmp ne i32 %op5, 0 + br i1 %op6, label %label7, label %label34 +label7: ; preds = %label1 + %op8 = fmul float 0x3ff3c0c200000000, 0x4016f06a20000000 + %op9 = fmul float %op8, 0x4002aa9940000000 + %op10 = fmul float %op9, 0x4011781d80000000 + %op11 = fmul float %op10, 0x401962ac40000000 + %op12 = fptosi float %op11 to i32 + %op13 = mul i32 %op12, %op12 + %op14 = mul i32 %op13, %op12 + %op15 = mul i32 %op14, %op12 + %op16 = mul i32 %op15, %op12 + %op17 = mul i32 %op16, %op12 + %op18 = mul i32 %op17, %op17 + %op19 = mul i32 %op18, %op17 + %op20 = mul i32 %op19, %op17 + %op21 = mul i32 %op20, %op17 + %op22 = mul i32 %op21, %op17 + %op23 = mul i32 %op22, %op22 + %op24 = mul i32 %op23, %op22 + %op25 = mul i32 %op24, %op22 + %op26 = mul i32 %op25, %op22 + %op27 = mul i32 %op26, %op22 + %op28 = mul i32 %op27, %op27 + %op29 = mul i32 %op28, %op27 + %op30 = mul i32 %op29, %op27 + %op31 = mul i32 %op30, %op27 + %op32 = mul i32 %op31, %op27 + %op33 = add i32 %op2, 1 + br label %label1 +label34: ; preds = %label1 + call void @output(i32 %op3) + ret void +} diff --git a/tests/4-opt/testcases/mem2reg/baseline/mem2reg-2 b/tests/4-opt/testcases/mem2reg/baseline/mem2reg-2 new file mode 100755 index 0000000000000000000000000000000000000000..4a905ff6e89117910fab4c7a5bba89c800190b55 Binary files /dev/null and b/tests/4-opt/testcases/mem2reg/baseline/mem2reg-2 differ diff --git a/tests/4-opt/testcases/mem2reg/baseline/mem2reg-2.ll b/tests/4-opt/testcases/mem2reg/baseline/mem2reg-2.ll new file mode 100644 index 0000000000000000000000000000000000000000..0fcadf5d42c3e4b27d7cbe1e9c0ce9c64fa611a2 --- /dev/null +++ b/tests/4-opt/testcases/mem2reg/baseline/mem2reg-2.ll @@ -0,0 +1,26 @@ +; ModuleID = 'cminus' +source_filename = "/home/zox/compiler/2024ustc-jianmu-compiler-ta/tests/4-mem2reg/performance-cases/testcase-2.cminus" + +declare i32 @input() + +declare void @output(i32) + +declare void @outputFloat(float) + +declare void @neg_idx_except() + +define i32 @main() { +label_entry: + br label %label0 +label0: ; preds = %label_entry, %label5 + %op1 = phi i32 [ 1, %label_entry ], [ %op6, %label5 ] + %op2 = icmp slt i32 %op1, 999999999 + %op3 = zext i1 %op2 to i32 + %op4 = icmp ne i32 %op3, 0 + br i1 %op4, label %label5, label %label7 +label5: ; preds = %label0 + %op6 = add i32 %op1, 1 + br label %label0 +label7: ; preds = %label0 + ret i32 %op1 +} diff --git a/tests/4-opt/testcases/mem2reg/baseline/mem2reg-3 b/tests/4-opt/testcases/mem2reg/baseline/mem2reg-3 new file mode 100755 index 0000000000000000000000000000000000000000..477a8f55a2a2daf6bf8b2bb3b313aae93c139582 Binary files /dev/null and b/tests/4-opt/testcases/mem2reg/baseline/mem2reg-3 differ diff --git a/tests/4-opt/testcases/mem2reg/baseline/mem2reg-3.ll b/tests/4-opt/testcases/mem2reg/baseline/mem2reg-3.ll new file mode 100644 index 0000000000000000000000000000000000000000..c92c71efb104ce9ff13bae587173bf63e0d286c1 --- /dev/null +++ b/tests/4-opt/testcases/mem2reg/baseline/mem2reg-3.ll @@ -0,0 +1,201 @@ +; ModuleID = 'cminus' +source_filename = "/home/zox/compiler/2024ustc-jianmu-compiler-ta/tests/4-mem2reg/performance-cases/testcase-3.cminus" + +@matrix = global [20000000 x i32] zeroinitializer +@ad = global [100000 x i32] zeroinitializer +@len = global i32 zeroinitializer +declare i32 @input() + +declare void @output(i32) + +declare void @outputFloat(float) + +declare void @neg_idx_except() + +define void @readarray() { +label_entry: + br label %label0 +label0: ; preds = %label_entry, %label11 + %op1 = phi i32 [ 0, %label_entry ], [ %op13, %label11 ] + %op2 = load i32, i32* @len + %op3 = icmp slt i32 %op1, %op2 + %op4 = zext i1 %op3 to i32 + %op5 = icmp ne i32 %op4, 0 + br i1 %op5, label %label6, label %label9 +label6: ; preds = %label0 + %op7 = call i32 @input() + %op8 = icmp slt i32 %op1, 0 + br i1 %op8, label %label10, label %label11 +label9: ; preds = %label0 + ret void +label10: ; preds = %label6 + call void @neg_idx_except() + ret void +label11: ; preds = %label6 + %op12 = getelementptr [100000 x i32], [100000 x i32]* @ad, i32 0, i32 %op1 + store i32 %op7, i32* %op12 + %op13 = add i32 %op1, 1 + br label %label0 +} +define i32 @transpose(i32 %arg0, i32* %arg1, i32 %arg2) { +label_entry: + %op3 = sdiv i32 %arg0, %arg2 + br label %label4 +label4: ; preds = %label_entry, %label21 + %op5 = phi i32 [ 0, %label_entry ], [ %op22, %label21 ] + %op6 = icmp slt i32 %op5, %op3 + %op7 = zext i1 %op6 to i32 + %op8 = icmp ne i32 %op7, 0 + br i1 %op8, label %label9, label %label10 +label9: ; preds = %label4 + br label %label12 +label10: ; preds = %label4 + %op11 = sub i32 0, 1 + ret i32 %op11 +label12: ; preds = %label9, %label25 + %op13 = phi i32 [ 0, %label9 ], [ %op26, %label25 ] + %op14 = icmp slt i32 %op13, %arg2 + %op15 = zext i1 %op14 to i32 + %op16 = icmp ne i32 %op15, 0 + br i1 %op16, label %label17, label %label21 +label17: ; preds = %label12 + %op18 = icmp slt i32 %op5, %op13 + %op19 = zext i1 %op18 to i32 + %op20 = icmp ne i32 %op19, 0 + br i1 %op20, label %label23, label %label27 +label21: ; preds = %label12 + %op22 = add i32 %op5, 1 + br label %label4 +label23: ; preds = %label17 + %op24 = add i32 %op13, 1 + br label %label25 +label25: ; preds = %label23, %label52 + %op26 = phi i32 [ %op24, %label23 ], [ %op54, %label52 ] + br label %label12 +label27: ; preds = %label17 + %op28 = mul i32 %op5, %arg2 + %op29 = add i32 %op28, %op13 + %op30 = icmp slt i32 %op29, 0 + br i1 %op30, label %label31, label %label32 +label31: ; preds = %label27 + call void @neg_idx_except() + ret i32 0 +label32: ; preds = %label27 + %op33 = getelementptr i32, i32* %arg1, i32 %op29 + %op34 = load i32, i32* %op33 + %op35 = mul i32 %op5, %arg2 + %op36 = add i32 %op35, %op13 + %op37 = icmp slt i32 %op36, 0 + br i1 %op37, label %label38, label %label39 +label38: ; preds = %label32 + call void @neg_idx_except() + ret i32 0 +label39: ; preds = %label32 + %op40 = getelementptr i32, i32* %arg1, i32 %op36 + %op41 = load i32, i32* %op40 + %op42 = mul i32 %op13, %op3 + %op43 = add i32 %op42, %op5 + %op44 = icmp slt i32 %op43, 0 + br i1 %op44, label %label45, label %label46 +label45: ; preds = %label39 + call void @neg_idx_except() + ret i32 0 +label46: ; preds = %label39 + %op47 = getelementptr i32, i32* %arg1, i32 %op43 + store i32 %op41, i32* %op47 + %op48 = mul i32 %op5, %arg2 + %op49 = add i32 %op48, %op13 + %op50 = icmp slt i32 %op49, 0 + br i1 %op50, label %label51, label %label52 +label51: ; preds = %label46 + call void @neg_idx_except() + ret i32 0 +label52: ; preds = %label46 + %op53 = getelementptr i32, i32* %arg1, i32 %op49 + store i32 %op34, i32* %op53 + %op54 = add i32 %op13, 1 + br label %label25 +} +define i32 @main() { +label_entry: + %op0 = call i32 @input() + %op1 = call i32 @input() + store i32 %op1, i32* @len + call void @readarray() + br label %label2 +label2: ; preds = %label_entry, %label11 + %op3 = phi i32 [ 0, %label_entry ], [ %op13, %label11 ] + %op4 = icmp slt i32 %op3, %op0 + %op5 = zext i1 %op4 to i32 + %op6 = icmp ne i32 %op5, 0 + br i1 %op6, label %label7, label %label9 +label7: ; preds = %label2 + %op8 = icmp slt i32 %op3, 0 + br i1 %op8, label %label10, label %label11 +label9: ; preds = %label2 + br label %label14 +label10: ; preds = %label7 + call void @neg_idx_except() + ret i32 0 +label11: ; preds = %label7 + %op12 = getelementptr [20000000 x i32], [20000000 x i32]* @matrix, i32 0, i32 %op3 + store i32 %op3, i32* %op12 + %op13 = add i32 %op3, 1 + br label %label2 +label14: ; preds = %label9, %label25 + %op15 = phi i32 [ 0, %label9 ], [ %op29, %label25 ] + %op16 = load i32, i32* @len + %op17 = icmp slt i32 %op15, %op16 + %op18 = zext i1 %op17 to i32 + %op19 = icmp ne i32 %op18, 0 + br i1 %op19, label %label20, label %label23 +label20: ; preds = %label14 + %op21 = getelementptr [20000000 x i32], [20000000 x i32]* @matrix, i32 0, i32 0 + %op22 = icmp slt i32 %op15, 0 + br i1 %op22, label %label24, label %label25 +label23: ; preds = %label14 + br label %label30 +label24: ; preds = %label20 + call void @neg_idx_except() + ret i32 0 +label25: ; preds = %label20 + %op26 = getelementptr [100000 x i32], [100000 x i32]* @ad, i32 0, i32 %op15 + %op27 = load i32, i32* %op26 + %op28 = call i32 @transpose(i32 %op0, i32* %op21, i32 %op27) + %op29 = add i32 %op15, 1 + br label %label14 +label30: ; preds = %label23, %label45 + %op31 = phi i32 [ 0, %label23 ], [ %op49, %label45 ] + %op32 = phi i32 [ 0, %label23 ], [ %op50, %label45 ] + %op33 = load i32, i32* @len + %op34 = icmp slt i32 %op32, %op33 + %op35 = zext i1 %op34 to i32 + %op36 = icmp ne i32 %op35, 0 + br i1 %op36, label %label37, label %label40 +label37: ; preds = %label30 + %op38 = mul i32 %op32, %op32 + %op39 = icmp slt i32 %op32, 0 + br i1 %op39, label %label44, label %label45 +label40: ; preds = %label30 + %op41 = icmp slt i32 %op31, 0 + %op42 = zext i1 %op41 to i32 + %op43 = icmp ne i32 %op42, 0 + br i1 %op43, label %label51, label %label53 +label44: ; preds = %label37 + call void @neg_idx_except() + ret i32 0 +label45: ; preds = %label37 + %op46 = getelementptr [20000000 x i32], [20000000 x i32]* @matrix, i32 0, i32 %op32 + %op47 = load i32, i32* %op46 + %op48 = mul i32 %op38, %op47 + %op49 = add i32 %op31, %op48 + %op50 = add i32 %op32, 1 + br label %label30 +label51: ; preds = %label40 + %op52 = sub i32 0, %op31 + br label %label53 +label53: ; preds = %label40, %label51 + %op54 = phi i32 [ %op31, %label40 ], [ %op52, %label51 ] + call void @output(i32 %op54) + ret i32 0 +} diff --git a/tests/4-opt/testcases/mem2reg/mem2reg-1 b/tests/4-opt/testcases/mem2reg/mem2reg-1 new file mode 100755 index 0000000000000000000000000000000000000000..ce0bb68c231d0534080201a8f6809d8aedc6194b Binary files /dev/null and b/tests/4-opt/testcases/mem2reg/mem2reg-1 differ diff --git a/tests/4-opt/testcases/mem2reg/mem2reg-1.cminus b/tests/4-opt/testcases/mem2reg/mem2reg-1.cminus new file mode 100644 index 0000000000000000000000000000000000000000..93d726f539fbb965d46b3c44f17ac8b1755740d7 --- /dev/null +++ b/tests/4-opt/testcases/mem2reg/mem2reg-1.cminus @@ -0,0 +1,23 @@ +void main(void) { + int c; + int a; + int b; + int d; + int f; + int g; + int loopCnt; + loopCnt = input(); + c = 0; + a = 0; + g = 0; + while (c < loopCnt) { + a = 1.23456 * 5.73478 * 2.3333 * 4.3673 * 6.34636; + b = a * a * a * a * a * a; + d = b * b * b * b * b * b; + f = d * d * d * d * d * d; + g = f * f * f * f * f * f; + c = c + 1; + } + output(g); + return; +} \ No newline at end of file diff --git a/tests/4-opt/testcases/mem2reg/mem2reg-1.in b/tests/4-opt/testcases/mem2reg/mem2reg-1.in new file mode 100644 index 0000000000000000000000000000000000000000..ea600cb61b366b723c6e331e118865642391327f --- /dev/null +++ b/tests/4-opt/testcases/mem2reg/mem2reg-1.in @@ -0,0 +1 @@ +100000000 diff --git a/tests/4-opt/testcases/mem2reg/mem2reg-1.out b/tests/4-opt/testcases/mem2reg/mem2reg-1.out new file mode 100644 index 0000000000000000000000000000000000000000..f422395e55bfcb38cf4fa905452d5662b53d582c --- /dev/null +++ b/tests/4-opt/testcases/mem2reg/mem2reg-1.out @@ -0,0 +1,2 @@ +711082625 +0 diff --git a/tests/4-opt/testcases/mem2reg/mem2reg-2 b/tests/4-opt/testcases/mem2reg/mem2reg-2 new file mode 100755 index 0000000000000000000000000000000000000000..a3e30a3b90c21e6680b087bc7d9fa0d26656e7c5 Binary files /dev/null and b/tests/4-opt/testcases/mem2reg/mem2reg-2 differ diff --git a/tests/4-opt/testcases/mem2reg/mem2reg-2.cminus b/tests/4-opt/testcases/mem2reg/mem2reg-2.cminus new file mode 100644 index 0000000000000000000000000000000000000000..7d85bd67dce4775296ab502924207af02539e02f --- /dev/null +++ b/tests/4-opt/testcases/mem2reg/mem2reg-2.cminus @@ -0,0 +1,9 @@ +int main(void) { + int a; + a = 1; + + while (a < 999999999) { + a = a + 1; + } + return a; +} diff --git a/tests/4-opt/testcases/mem2reg/mem2reg-2.out b/tests/4-opt/testcases/mem2reg/mem2reg-2.out new file mode 100644 index 0000000000000000000000000000000000000000..ace9d0362138cfabef3b6feb959808748e4263b4 --- /dev/null +++ b/tests/4-opt/testcases/mem2reg/mem2reg-2.out @@ -0,0 +1 @@ +255 diff --git a/tests/4-opt/testcases/mem2reg/mem2reg-3 b/tests/4-opt/testcases/mem2reg/mem2reg-3 new file mode 100755 index 0000000000000000000000000000000000000000..46b7cc4142e8c369e8673c2b5aa10fedb4ce2fcf Binary files /dev/null and b/tests/4-opt/testcases/mem2reg/mem2reg-3 differ diff --git a/tests/4-opt/testcases/mem2reg/mem2reg-3.cminus b/tests/4-opt/testcases/mem2reg/mem2reg-3.cminus new file mode 100644 index 0000000000000000000000000000000000000000..0aff64fd0996534f1612c3203c41dbf26b9a9812 --- /dev/null +++ b/tests/4-opt/testcases/mem2reg/mem2reg-3.cminus @@ -0,0 +1,70 @@ +int matrix[20000000]; +int ad[100000]; + +int len; + +void readarray(void) { + int cnt; + cnt = 0; + while (cnt < len) { + ad[cnt] = input(); + cnt = cnt + 1; + } +} + +int transpose(int n, int matrix[], int rowsize) { + int colsize; + int i; + int j; + int curr; + colsize = n / rowsize; + i = 0; + j = 0; + while (i < colsize) { + j = 0; + while (j < rowsize) { + if (i < j) { + j = j + 1; + } else { + curr = matrix[i * rowsize + j]; + matrix[j * colsize + i] = matrix[i * rowsize + j]; + matrix[i * rowsize + j] = curr; + j = j + 1; + } + } + i = i + 1; + } + return 0 - 1; +} + +int main(void) { + int n; + int i; + int ans; + n = input(); + len = input(); + readarray(); + i = 0; + + while (i < n) { + matrix[i] = i; + i = i + 1; + } + i = 0; + while (i < len) { + transpose(n, matrix, ad[i]); + i = i + 1; + } + + ans = 0; + i = 0; + while (i < len) { + ans = ans + i * i * matrix[i]; + i = i + 1; + } + if (ans < 0) { + ans = 0 - ans; + } + output(ans); + return 0; +} diff --git a/tests/4-opt/testcases/mem2reg/mem2reg-3.in b/tests/4-opt/testcases/mem2reg/mem2reg-3.in new file mode 100644 index 0000000000000000000000000000000000000000..f37548b30c57768e9549667d431165587c834a8e --- /dev/null +++ b/tests/4-opt/testcases/mem2reg/mem2reg-3.in @@ -0,0 +1,32 @@ +10000000 +30 +2 +5 +4 +25 +8 +125 +16 +625 +32 +3125 +2 +5 +4 +25 +8 +125 +16 +625 +32 +3125 +2 +5 +4 +25 +8 +125 +16 +625 +32 +3125 diff --git a/tests/4-opt/testcases/mem2reg/mem2reg-3.out b/tests/4-opt/testcases/mem2reg/mem2reg-3.out new file mode 100644 index 0000000000000000000000000000000000000000..72f8a546d2a64e4847b5000bbd767c00dd274238 --- /dev/null +++ b/tests/4-opt/testcases/mem2reg/mem2reg-3.out @@ -0,0 +1,2 @@ +1042523985 +0