From 169a7e86e7d6f71d67df7aa719ca806f1ec243b8 Mon Sep 17 00:00:00 2001 From: JYJS Date: Mon, 2 Dec 2024 15:00:57 +0800 Subject: [PATCH] lab4 init --- CMakeLists.txt | 1 + include/lightir/Instruction.hpp | 11 + include/passes/DeadCode.hpp | 30 ++ include/passes/Dominators.hpp | 88 +++++ include/passes/FuncInfo.hpp | 35 ++ include/passes/LICM.hpp | 24 ++ include/passes/LoopDetection.hpp | 64 ++++ include/passes/Mem2Reg.hpp | 41 +++ include/passes/PassManager.hpp | 36 ++ src/CMakeLists.txt | 3 +- src/cminusfc/CMakeLists.txt | 1 + src/cminusfc/main.cpp | 47 ++- src/passes/CMakeLists.txt | 9 + src/passes/DeadCode.cpp | 128 +++++++ src/passes/Dominators.cpp | 337 ++++++++++++++++++ src/passes/FuncInfo.cpp | 110 ++++++ src/passes/LICM.cpp | 132 +++++++ src/passes/LoopDetection.cpp | 135 +++++++ src/passes/Mem2Reg.cpp | 119 +++++++ tests/4-opt/cleanup.sh | 2 + tests/4-opt/eval_lab4.sh | 116 ++++++ tests/4-opt/test_perf.sh | 106 ++++++ .../testcases/functional-cases/0-io.cminus | 4 + .../4-opt/testcases/functional-cases/0-io.in | 1 + .../4-opt/testcases/functional-cases/0-io.out | 2 + .../functional-cases/1-return.cminus | 4 + .../testcases/functional-cases/1-return.out | 2 + .../functional-cases/10-float.cminus | 19 + .../testcases/functional-cases/10-float.out | 2 + .../functional-cases/11-floatcall.cminus | 18 + .../functional-cases/11-floatcall.out | 2 + .../functional-cases/12-global.cminus | 47 +++ .../testcases/functional-cases/12-global.out | 21 ++ .../functional-cases/13-complex.cminus | 67 ++++ .../testcases/functional-cases/13-complex.out | 2 + .../functional-cases/2-calculate.cminus | 11 + .../functional-cases/2-calculate.out | 1 + .../functional-cases/3-output.cminus | 5 + .../testcases/functional-cases/3-output.out | 3 + .../testcases/functional-cases/4-if.cminus | 23 ++ .../4-opt/testcases/functional-cases/4-if.out | 2 + .../testcases/functional-cases/5-while.cminus | 14 + .../testcases/functional-cases/5-while.out | 11 + .../testcases/functional-cases/6-array.cminus | 15 + .../testcases/functional-cases/6-array.out | 4 + .../functional-cases/7-function.cminus | 21 ++ .../testcases/functional-cases/7-function.out | 4 + .../testcases/functional-cases/8-store.cminus | 26 ++ .../testcases/functional-cases/8-store.out | 2 + .../functional-cases/9-fibonacci.cminus | 23 ++ .../functional-cases/9-fibonacci.out | 11 + tests/4-opt/testcases/loop/baseline/loop-1.ll | 60 ++++ tests/4-opt/testcases/loop/baseline/loop-2.ll | 60 ++++ tests/4-opt/testcases/loop/baseline/loop-3.ll | 119 +++++++ tests/4-opt/testcases/loop/baseline/loop-4.ll | 132 +++++++ tests/4-opt/testcases/loop/loop-1.cminus | 20 ++ tests/4-opt/testcases/loop/loop-1.out | 1 + tests/4-opt/testcases/loop/loop-2.cminus | 23 ++ tests/4-opt/testcases/loop/loop-2.out | 1 + tests/4-opt/testcases/loop/loop-3.cminus | 46 +++ tests/4-opt/testcases/loop/loop-3.out | 1 + tests/4-opt/testcases/loop/loop-4.cminus | 50 +++ tests/4-opt/testcases/loop/loop-4.out | 1 + .../testcases/mem2reg/baseline/mem2reg-1 | Bin 0 -> 34168 bytes .../testcases/mem2reg/baseline/mem2reg-1.ll | 54 +++ .../testcases/mem2reg/baseline/mem2reg-2 | Bin 0 -> 16840 bytes .../testcases/mem2reg/baseline/mem2reg-2.ll | 26 ++ .../testcases/mem2reg/baseline/mem2reg-3 | Bin 0 -> 34360 bytes .../testcases/mem2reg/baseline/mem2reg-3.ll | 201 +++++++++++ tests/4-opt/testcases/mem2reg/mem2reg-1 | Bin 0 -> 34168 bytes .../4-opt/testcases/mem2reg/mem2reg-1.cminus | 23 ++ tests/4-opt/testcases/mem2reg/mem2reg-1.in | 1 + tests/4-opt/testcases/mem2reg/mem2reg-1.out | 2 + tests/4-opt/testcases/mem2reg/mem2reg-2 | Bin 0 -> 16840 bytes .../4-opt/testcases/mem2reg/mem2reg-2.cminus | 9 + tests/4-opt/testcases/mem2reg/mem2reg-2.out | 1 + tests/4-opt/testcases/mem2reg/mem2reg-3 | Bin 0 -> 34360 bytes .../4-opt/testcases/mem2reg/mem2reg-3.cminus | 70 ++++ tests/4-opt/testcases/mem2reg/mem2reg-3.in | 32 ++ tests/4-opt/testcases/mem2reg/mem2reg-3.out | 2 + 80 files changed, 2872 insertions(+), 5 deletions(-) create mode 100644 include/passes/DeadCode.hpp create mode 100644 include/passes/Dominators.hpp create mode 100644 include/passes/FuncInfo.hpp create mode 100644 include/passes/LICM.hpp create mode 100644 include/passes/LoopDetection.hpp create mode 100644 include/passes/Mem2Reg.hpp create mode 100644 include/passes/PassManager.hpp create mode 100644 src/passes/CMakeLists.txt create mode 100644 src/passes/DeadCode.cpp create mode 100644 src/passes/Dominators.cpp create mode 100644 src/passes/FuncInfo.cpp create mode 100644 src/passes/LICM.cpp create mode 100644 src/passes/LoopDetection.cpp create mode 100644 src/passes/Mem2Reg.cpp create mode 100755 tests/4-opt/cleanup.sh create mode 100755 tests/4-opt/eval_lab4.sh create mode 100755 tests/4-opt/test_perf.sh create mode 100644 tests/4-opt/testcases/functional-cases/0-io.cminus create mode 100644 tests/4-opt/testcases/functional-cases/0-io.in create mode 100644 tests/4-opt/testcases/functional-cases/0-io.out create mode 100644 tests/4-opt/testcases/functional-cases/1-return.cminus create mode 100644 tests/4-opt/testcases/functional-cases/1-return.out create mode 100644 tests/4-opt/testcases/functional-cases/10-float.cminus create mode 100644 tests/4-opt/testcases/functional-cases/10-float.out create mode 100644 tests/4-opt/testcases/functional-cases/11-floatcall.cminus create mode 100644 tests/4-opt/testcases/functional-cases/11-floatcall.out create mode 100644 tests/4-opt/testcases/functional-cases/12-global.cminus create mode 100644 tests/4-opt/testcases/functional-cases/12-global.out create mode 100644 tests/4-opt/testcases/functional-cases/13-complex.cminus create mode 100644 tests/4-opt/testcases/functional-cases/13-complex.out create mode 100644 tests/4-opt/testcases/functional-cases/2-calculate.cminus create mode 100644 tests/4-opt/testcases/functional-cases/2-calculate.out create mode 100644 tests/4-opt/testcases/functional-cases/3-output.cminus create mode 100644 tests/4-opt/testcases/functional-cases/3-output.out create mode 100644 tests/4-opt/testcases/functional-cases/4-if.cminus create mode 100644 tests/4-opt/testcases/functional-cases/4-if.out create mode 100644 tests/4-opt/testcases/functional-cases/5-while.cminus create mode 100644 tests/4-opt/testcases/functional-cases/5-while.out create mode 100644 tests/4-opt/testcases/functional-cases/6-array.cminus create mode 100644 tests/4-opt/testcases/functional-cases/6-array.out create mode 100644 tests/4-opt/testcases/functional-cases/7-function.cminus create mode 100644 tests/4-opt/testcases/functional-cases/7-function.out create mode 100644 tests/4-opt/testcases/functional-cases/8-store.cminus create mode 100644 tests/4-opt/testcases/functional-cases/8-store.out create mode 100644 tests/4-opt/testcases/functional-cases/9-fibonacci.cminus create mode 100644 tests/4-opt/testcases/functional-cases/9-fibonacci.out create mode 100644 tests/4-opt/testcases/loop/baseline/loop-1.ll create mode 100644 tests/4-opt/testcases/loop/baseline/loop-2.ll create mode 100644 tests/4-opt/testcases/loop/baseline/loop-3.ll create mode 100644 tests/4-opt/testcases/loop/baseline/loop-4.ll create mode 100644 tests/4-opt/testcases/loop/loop-1.cminus create mode 100644 tests/4-opt/testcases/loop/loop-1.out create mode 100644 tests/4-opt/testcases/loop/loop-2.cminus create mode 100644 tests/4-opt/testcases/loop/loop-2.out create mode 100644 tests/4-opt/testcases/loop/loop-3.cminus create mode 100644 tests/4-opt/testcases/loop/loop-3.out create mode 100644 tests/4-opt/testcases/loop/loop-4.cminus create mode 100644 tests/4-opt/testcases/loop/loop-4.out create mode 100755 tests/4-opt/testcases/mem2reg/baseline/mem2reg-1 create mode 100644 tests/4-opt/testcases/mem2reg/baseline/mem2reg-1.ll create mode 100755 tests/4-opt/testcases/mem2reg/baseline/mem2reg-2 create mode 100644 tests/4-opt/testcases/mem2reg/baseline/mem2reg-2.ll create mode 100755 tests/4-opt/testcases/mem2reg/baseline/mem2reg-3 create mode 100644 tests/4-opt/testcases/mem2reg/baseline/mem2reg-3.ll create mode 100755 tests/4-opt/testcases/mem2reg/mem2reg-1 create mode 100644 tests/4-opt/testcases/mem2reg/mem2reg-1.cminus create mode 100644 tests/4-opt/testcases/mem2reg/mem2reg-1.in create mode 100644 tests/4-opt/testcases/mem2reg/mem2reg-1.out create mode 100755 tests/4-opt/testcases/mem2reg/mem2reg-2 create mode 100644 tests/4-opt/testcases/mem2reg/mem2reg-2.cminus create mode 100644 tests/4-opt/testcases/mem2reg/mem2reg-2.out create mode 100755 tests/4-opt/testcases/mem2reg/mem2reg-3 create mode 100644 tests/4-opt/testcases/mem2reg/mem2reg-3.cminus create mode 100644 tests/4-opt/testcases/mem2reg/mem2reg-3.in create mode 100644 tests/4-opt/testcases/mem2reg/mem2reg-3.out diff --git a/CMakeLists.txt b/CMakeLists.txt index 236bc64..7fc88d0 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 184ebd5..54d4b34 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 0000000..8a88009 --- /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 0000000..398d0e5 --- /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 0000000..e8a8c13 --- /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 0000000..4ae0efb --- /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 0000000..b55246c --- /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 0000000..867810e --- /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 0000000..d7cd50b --- /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 17a2f66..8c66d6b 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 77342fc..e8df6c5 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 511ad1e..b9ee2aa 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 0000000..b22ccea --- /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 0000000..468e37f --- /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 0000000..5b4de78 --- /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 0000000..8cf92ed --- /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 0000000..345aa03 --- /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 0000000..c7d8b74 --- /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 0000000..d6b4985 --- /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 0000000..78fecdf --- /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 0000000..7f58c5f --- /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 0000000..3563fd7 --- /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 0000000..b73460e --- /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 0000000..81c545e --- /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 0000000..2b8eb81 --- /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 0000000..91e77f2 --- /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 0000000..2bbe845 --- /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 0000000..8de09f6 --- /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 0000000..28c52e7 --- /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 0000000..23f73d7 --- /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 0000000..e176519 --- /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 0000000..63bddbb --- /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 0000000..66bb323 --- /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 0000000..22232fb --- /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 0000000..227eae2 --- /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 0000000..fa4c9a1 --- /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 0000000..190a180 --- /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 0000000..abe3222 --- /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 0000000..1983173 --- /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 0000000..a4ba887 --- /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 0000000..54a647c --- /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 0000000..da3313b --- /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 0000000..c9f2be1 --- /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 0000000..3383fca --- /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 0000000..d7fcd8c --- /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 0000000..2eb2620 --- /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 0000000..38ea323 --- /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 0000000..15a438d --- /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 0000000..d2044a0 --- /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 0000000..df0ee72 --- /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 0000000..f53d098 --- /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 0000000..5b37e40 --- /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 0000000..d0983dd --- /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 0000000..257f877 --- /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 0000000..838371a --- /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 0000000..82ce6d3 --- /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 0000000..573541a --- /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 0000000..920c1ad --- /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 0000000..d00491f --- /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 0000000..8858c83 --- /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 0000000..d00491f --- /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 0000000..287098a --- /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 0000000..d00491f --- /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 GIT binary patch literal 34168 zcmeI5Z)_Ar6u@V%t+Yp_#a2r#wuiP*2)%>S#wJj_0+lvkA*Gl`CByY@+b;C>>fN3k zw8#OHpfsju8U)iSDuy0PB!om75lcu+;}@tO(D*Os7t5Lsq()F>za~u z7M^NDgY$qAYzs_vrN*24loqd4pMkbHUZx%o7^=d#JD~U_xns&sUawP+SEi4nZ5DHE z?B_fv?~r5xBFdQ(Xf-_jp^}fbSJdaOaW%X zBTS~cKaM~L=WFU(>iFsnO`Ej0>(n37 zhB~&7u|J>&PHZD6%EP*1jzys6Ji$zoG4RKEsWJ;XY@oQ$9KnF!(IvGxJUhEQV54AM z%)_db|N0E8j+}b&gR@6JS@udL^w~hQHRV7nM{TS8XFQ+22zu1@L5)%l>%%zs-IxWR zTLX$?+WuM##DwWwAfHV;1B&Riud+j4Qk&*IA1aI=3p17p^+Mf7UMP=&s^j|^J7NZ} zj#5DchyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+SpM1Tko z0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvzQ|ChkzB{rVuu|(m_ z=0L1~jbyTLb385cWW0!tOq8$@I3AgQt-v`lQREznmq48Za|G-5i4*TU8qb3{X{-w8 z#B-b@2d@q_AM73WGhsoomDLnC?6wwVn$!yI`|ZOx3p3bkBd_l!CktYE&Jj2}K9J~H z6@_&~M$`D!$^Ez@Mn>NDroM&KMRuUN;*~-sXd%T!E1J+EL`uLgk8-{2o(#t*(J;dJ$PPsI5DXT_-N8FYsuTfkQPYo$qi$E5GAa4hE>Y5g-CYfCvx)B0vO) z01+SpM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CY;6Ec^gC}hS z-3p5L3}|-&Km$a*TtI88cM0fCt?h){5}Zbl<|n`f0s>sJAmGo?QMeeA6vn&#lB~2d z9&o$lcI+28tH2sB97to|_d?Ov14Z~{D8_a}(Z5@Gy36NM;NFA`?(Kv?qC2RFyi;^} zL_f=t~`tAch@$~gM>>;CW`dDY*r4S)Q{ zI*Q?M9!LK%-G4dE!RH(H-Tckt=+EGO39O#b{SDjjH}0lD8}m1hoB82u%Mr9&CvY0_ z$bp8z2mkAiHr{Q4U>nef#gk8lV0Cj-D+)4HjK~L++C=SS@G8{#O@XU-;OVsd2w*h k4?|C`xE`Bxqh`TZN6+m2c>Uf#-xF6ZeyifsmGCkA4Q}^OasU7T literal 0 HcmV?d00001 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 0000000..00b6e15 --- /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 GIT binary patch literal 16840 zcmeI3T}V@L6u|%cuo=!~F|5?!_JOPqKTsd+MX%LRQFF~vqZt3R-RW?fH7Cs&WgkLi zMNy=^6eVSZfru}AD1^YI!We`_MEJNp_z?BvgX^4o?{Lc~=rPWLbI-^Bp0o4+-Myao zON+}!#xx8>3z`QS2WOB8;4!utv;mZJTV1{NsMX$z*-Vj(GgGS~>=Os&++lS(GLPkY zF*C>1I1AFKI2#J*At@YEd?n88=d4vOV^d$jI8`gB^lU&qk`3p5fz#fAn|lME9?1MU z-&3`pQ!THy&)V9%xM6Ra7B^l|{9)Dm*ml9IF@`z;A&Zs=-vMaW%x{ z5aSG+Ku^LabU-2FZ`#3+TJIEU-f z&`{~S%2U^jHrHFXWk&_%1W@HpCh$zMuLDnKIHunPR=yut6bsxB`{4IV7yMnkKb|Rf zsE5CUW@Q$br>(y?B>7ACmBL)!4yC#n4EFC58OsK{Q;m@q$`(*OpAez9G9*MKM1Tko z0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+SpM1Tko z0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfC&7L1d{t%%)$ojaTANe zda*fS5~B$Ni^gm3*&BMtf)-77cYN$YK_Z7mXBn%)cj5*ynw`bgW6h6ba^pgd7==E! zrgeNCSCorXQ0W$TqH$+h1dEFM=_sQ7TzTN$wGsBF^VE%OaIjPs0iNZmVj_JV8tZ;5 z8qPN00d~=`PiMj7{w^+sr4xN2iFZluZYjvt`rEw$mdoT9Qm>md%H}uzPClp!oYdaF z02}zL+ik&f|{{UmsrdyqVf|f46aA*fqM<@T}AK&2>Ka^7C`!lg^%*glAg+ zF&69AwmP$tk*Ua;!Ot&-8m{aa``dZ=$syOHCUbGoa@aTd&~oSX!jX~umYIup_c}^G pw6?`+JS~xe(V3Sw>_+qaT!gQ=Q2EMu)pC2jrf_`w+?Nr?egZF^(!>A& literal 0 HcmV?d00001 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 0000000..0fcadf5 --- /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 GIT binary patch literal 34360 zcmeI5Yiv}<701urHL!k!N9@)CH?TZo*Wiu7)TBmXT}*;W0u~R&rBN?y?=`;0yX)*D zSpqIg0}_xnjVoHx52UDx6r7i=s%pJb3T|oBD9{#EDXkky4NBErNUEw|icwtmf9_*_ zcX663mHO!%Y3`jfGv~~i-<-SOX7;zYKKxf1kwOp`%AF{lX+(#~iyF~fl#M8=+S>Hs zhMgO>ZsFE^F^uz@ZqwM$A23i=w{K|Mp5JZQ`}5n#(h&;Tg-57rTua8eW=f&I3-?)z zVIv6Zysn%SQ7TtQMO9<*M0+gPbeq5XO@B+Q5f`94{dp{ZU}%V{cEsXQJ-j=o=dbtg zmcOM|KkH6$`sQ|3O@yD+!$DOKcSa07-``#9%=mgOC#)Cxu)2(ws%l+oXEYGf%+|v7 z9quSeTEL6&IZ^a%R7#Z$$OHhrw$>H%pkd0L^DFYr#ZOzQ0G>$D*WM=u(nNmt0)m(!$2RElZO7Wh|%io`uA*$zow?fA=rT+Bj z3`(D-n++bcjqht3fUo{xxBBi9^gDGPo1NiLA8U6#w@I1Z-!f7?g!7_vc)q_(OjJ&+ zR}e$dz|~3`yVgKyPub7sWg7A3nAVvwWg8LGI+T0RZpCxjipLnYn9?}JRe>X4caHCC z9)M3HmTUuT7NabfwDTzDIx_blt_A*_zqg52<7`+3w;S7hGb8=kQ!Nu@VZu!8TA=Lqi7EG(bD&_4GvLd)Rt%UYf%?&@V!~LQ%^R#ysK46IHSA@E_i`1u`EJi`JC`y(^kW{JZ#3q~x;?LCk#m_^ zO5>b!MQDoovalJ&J{&=QdywC*5q)SO=11vo!5Z18kw1uelyipnt`-H1vdGJ0;IYa0 z&Pt5$EQ{RASh<}+t`+xrs4V08oJlp-fps0ndCkGuF8>(07QAcJ zr#tE;W_@XpmIg~`X=e$AwcUZZ{)Fbm@oFvU)sh`rZ(NUrOZdkZ{s=J};(YTNQ$ADf z$D0eE2WRmc&&da$V=bd1_%Kfc;~1&3%SA4K5xFaH#1&^&-EHP^S7QL;HAH!8D=EqO z%IvZQ&O1?41%V#LTtVvks3E_2{48)vri7>@lhl;)32AEO2R zJQOEgQ)ct*l;IRVaz?W}gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnMr{ zAs_^VfDjM@LO=)z0U;m+gn$qb0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnMr{ zAs_^VfDjM@LO=)zf&Uu;FJ@{**@eRQ7T8w=ph~!hB`16rfh|VekJ}ggc8h7J-~s^! zmo_N#t#(yQ>Tyzgqk1^rNouSk5boqIMWsji%@+<#qg3YjGR*yr{aio!I@e!I;_8GH zUr6B6!{m)e^&~BI(_kO^Ztllpc)#*MPb3hhwQjl)L&HT}NK&kZx-g~Ik%((*mlgIn}}0Ij~1r6p#at5_6JoDCNY+;eV~R&BF+PvqOb`>qk+BjNIV({$9f|% zjkaQfL&|0MsJnj68jjjv6m)>%yBUH;kNG%PpyNIo>V(y^2U>RX2sW+5qYU>)aD5&M z?%K)e+_nUz9)*SV%?15z@3-um(a-j_&g0qMjCRuA+0XV#%l=`@-qt_P-r3LggO)wV z$@AN~ZExS5!8*t9?053xG?=BBw_xzt&$2!PkNRI0vCe#Ep>jz%@VO!*_Z0B&%?=M~2YXvL04>(0)*p6Ok8`9#~bs*>#|zx}6IUwkh*GkfA6(*}m- zHkH?1|JgeS-@Y{XYDG)sOLLd~vp9R~%;+ci|6luScU^m5S6&)g`-_GvSGym0vGrGf VK0p1+&hp<)|K5Ag9$r6(=-=;@{F?v( literal 0 HcmV?d00001 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 0000000..c92c71e --- /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 GIT binary patch literal 34168 zcmeI5Z){XW5Wx3cTl$B}6$``E~G(@Gw7_KBHM1u3?_x3*S-e*^TzLv?D#6V1-vq3wO8QaAy&|+*JXe}t`YpPb)tgmToz}|Qf z!SP+!S(xV=aOAwHrnxD8Sj5}o`0#q0J7J3e2VmTx0EgP@(5Lmg2|&gC}l_B%YXZpY^v(ehPjL1-r#63m1t z45m0A`=EpKl~qkuyt<)&t@?HC+M$A4NJ5P{QSmcnfpXsJGkn&Y=9>$?LhSMDngN~0 zbxxhzN9yVyu31^9pSeiFy1+&W;~@jV^=L;&*yW5xaD8}c!cg6#*-$}H%xfZ{o`g#vzCyV7EFZEbgfje>b` z9qV>o{%OPP<(Ky#9saZW(WO6>L7xRw-IEzwX3-Y>Q=dp)3O!CRE+OrY@ZRl z7^Q*;5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+SpM1Tko0U|&IhyW2F z0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Spe@|fIG#ia|nFbzW ztZyup4NVk)=7G*+LvVF5Ct6@18c($krAg_Vqeotw-ywr zt>Ay?G(QpRsu}>_>tYU_E;um&;r{ZE=9}dLO2iH_w*$a1X```*}BYd|$xR*MZWwKvkrh>DgJ;Tt>P}_wr zR_MxLh3*XIm0KM_t@2u+Z<4oQi(}9>Q&-ov|)Whq|Qbrh4ZDX%mQYC9=xwx8=DXUF{;$gDm^G2 zP!oxstcW_47125)nkQ96fCvx)B0vO)01+SpM1Tko0U|&IhyW2F0z`la5CI}U1c(3; zAOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+SpM1Tko0U|&IhyW2F0z`la5CI}U1c(3; zAOb{y2oM1xKm>@u|3tt7^Q-~g2#W6v=+6W|lZnR#umOT^3Fso)c6cqpuJ@>M5Kri^rjO*&KL$fh(>sIN_@cEY}wb;^@L- zor9+GiVCqOmtkWYU|RjZ({UO56YRrayCLeu?RBj7xQ7faUA1EwD{#(yl&qt-Z+l&4BnT(>P{_QxAl1a zZ3?t;e&e{2AAUBoq`o?VZpgz74V@4EuRGfKwgrykd}!_N&4{TgJ&TDL27{9^U;p*Ap;_UE*v%|Hsqt)seyx}pntqaKhfNj&(O#$0V zpEKl4N@oi@d1V~Wq}WdAZp zOGs&V+1iyBr$_OI0vvKV7GpxIZwVlnl&jxo4go$pBU<-^l zYeDIZ?Hse1;JJ~1B+@0#P4dW|GQZqfayOfC<~MKheV5x_-ICw%M$e~}Znn4M*`~ce z&YkmR`6~Nv^YQJ+-fs4NGVUHu{(5wDv#FsuWup6??#^B3-rrOEeDRU##*;5za~7R1 zetco^;lWG&dCeEzT6X*;`yOw}dvlA5f=%!GXN|w|OUl5Bc~#lgiyxhNW@L2mXii=3 z>+_0!Pal8bgR$xI|JU)*sb%w@b9aBf?Ea5!U*&yq@2WZbf3>8Y@6TO-&V2Af#dnPT E1q*I{^Z)<= literal 0 HcmV?d00001 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 0000000..93d726f --- /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 0000000..ea600cb --- /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 0000000..f422395 --- /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 GIT binary patch literal 16840 zcmeI4Ur3Wt6u|GdO;a*wA(ff&J(!r~AJhjQDnHBNMxmlc9~InO`=&!TWt*iXC6ZJG zk&=W@QV=Fgkm$ug+LIYZA<`dw5TOTW&{HHS(K_e*!?uiq9^)K1_ndR@J!j|sw%4;a z8=rrqF(xn&6KDo#1e^gTg2z}Es2!B^`l=e+8Cydg?k0+woVc|q!a5O9&YNs4oM;?{6<)DSHNG~?r|2odfHtOqhy0(A9FKn z>!*^B+_@Pz`q5rpvQ`RvBB=HzD|lAbH-l&1a@JA+R(&5>lzey}*1_*9Uhs4A{dlIm zp$2{qLaZ0)r?DpxRJ=vUil8r#Q_Ic+gY{b_#!|o@&|~CX{nuLgi2oM1x zKm>>Y5g-CYfCvx)B0vO)01+SpM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1x zKm>>Y5g-CYfCvx)B0vO)01+SpM1Tko0U|&IhyW2F0z`la5P|=hK=e49&u4uN5i6U5 zG2_gLRhn9@9BFU_#{4NlYFlJ%bk8hf<;Gb`65Eb<*P_u~%WxO+2g7Fm4o8&t>Y(B+ z&P3zPv;-Cv=hIOnb&V}Jcbx`v(;50iHaM87iU@0ouDB6D4vl%g6@jxIcz{*RZ22m9 z+}p~PZskH(P~ojgvrF-_RByA#$F?!`f^pp{Xp`UgIXgkE;23lJB23_KF2mI_n7^@< z7KRQn&1f?d_Mi*F#7q|K2Rm|t%AhDPFD^}rCUt~e+xhcq{B?lfRlKEsrKPZxy;{ia z{~`>IM;m)?xSRvYW!Il)b=bduyTAX_*Wv2%2NTyqPvnl7Rd?9(ety2qR3|4zd!P1R z9$1{dZNGJB>~H6Dp^O{H8w^y{{o4=jFYGq$1BGp5>j;JNg-57rLQ5sMW=XNX zS3hknhS$KtItLzc1JN=d0{=m=_RqcrVpKO1Pc0cP*ar)+VRZT`7(IX*MkMu@Oz0lunTdnv8Z6~Z3`>?yrm#S+0YHutU z)~wdz^$y$qQnnH6ZijJ=EpbDpsF41``guRySw&TyBn~R3U5=2-t3bL?|m(b zs`f=4+j>KPw_&U)fx@_MLZdTI&bRrvObhFgw&SA99!Kk3)fpEzVn3tda5R!1V68K+ z;hnbpoqF^2Ie&8%bQgac9GCSy-M6#rv)em%=D&sXWlzC(0KY7od0`OlbNXt<%*>7F z=e^o!>nZ4C&^ZT~)#j5#EAdW0M&yG7>>uqxVflnzxXp*+%*I+2}@uY!ZXOG@93O^$gZuPA-7~|B9nn31SWgvT|+x0}VQajQ#bjLW)fispj8<_L= zxm;atn}QfTqf=Wc^SgS=zT?LnTLYPCKgKP(wA5HjncNzbm3EA4(6<(Sc6`HR#mD_P zz~#kpuUlr1c8tQW8I!Tn_EoeVgZ-c{@8=@XT??53+RgYd=X;2c?M>aD{{wDgTaNE| zMZN8#(x^w=H1jED^&Zh##Ie^I$8>!lW7G$-gIj?s+5m9hY#KhUK_LE zI5=*lqS9DA@8d!VALgDch8<#Qx?=5zQ3jh*@l?+H8Y|_i%-r93Uk+A3cI<5mw!FU& z<2{W0qLbB`U@rG$uFc-lHpGKH&+kP(=M1zP*axF6oiXYtJ8b71+u`J&_wiCOVI9}% z0$H5P8*5g`$~pKk_YijGo5cW9d>#iYvd<9}a8QFog@>=pSOmPmCh+)|N){ISv!ObziC);6v%{^icWt2spZNk}0 zFOLJOFY$Le?4rAHmeG4}iP#J`{9v!%FAHRGK5}dqxa=A_GTwZAVZE6%SerAxD~NBJ zeItj>JwZR`^%UB${*UB#?lJxyQATIC(a5x$MxI+tlT8X`@niG^O|*@)z~FYI1|-F&qrr@49E0A+X&92n(M&2&f>i0Sgk9NC0D~+X8k5deW6uv3{hifAvN|cq=?oR zOz015J{+&sQa&x!qYWnXXaqkW*11%~Y>M;EXH5A_c>r%Nd>))7U_R#`e2%q>JhTjj z1;0{O1zOo0zeI;+=z zM|p}vfq$YcC~14lRe&(1vw9DY;r=h6Z28dgVHEXSgKN`Pb8Xsm3U^k!JcWP|5CTF# z2nYcoAOwVf5D)@FKnMr{As_^VfDjM@LO=)z0U;m+gn$qb0zyCt2mv7=1cZPP5CTF# z2nYcoAOwVf5D)@FKnMr{As_^VfDjM@LO=)z0U;m+gn$qb0zyCt2!a0>0UsvXgK`Lk z?=8q*5r8V;E|xjry9n}P)&sbGA&_se>=axepy1L5Wx3t1YAHQI>R?QdBzj4W_XH!o z+@+}W0KfUdfd!N{&aTGXUp>b4r=I8fGbvo1kmd^sTzZ6jiI|?EMmLQeN8ijbJSL7Q z_YOpZ3EJYOSL0~7m>{Z9!~K|2>q#awwOug9nd1QBpjr*xcx!Z zLn(~qYaeJ+G@0N5?J?K{W3k{6-JggBBk{p#T%*01;FNOJZMa)EZ|0~?Mj;0%zMCOr z_E-bqasT0=!*PE{v?m$XB8j;Fz`p(4Hngnw zZ&<&fH5pIztUIg+BjMz_o@jVbAJAg{c&x{-NByKnTYBif^wFKv2SWYPo{APNhv`8jpY=fd?X|CTJk z^;f1SVJ*BNruD7cNE=r!d*Q{*)sZAYwdvjo&#xyZkGOUpT#!5V;;~0hzx}hvJI~zt?8o&Vc=zJFtI8*gs}=Q+^nF#Q*>R literal 0 HcmV?d00001 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 0000000..0aff64f --- /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 0000000..f37548b --- /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 0000000..72f8a54 --- /dev/null +++ b/tests/4-opt/testcases/mem2reg/mem2reg-3.out @@ -0,0 +1,2 @@ +1042523985 +0 -- GitLab