├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── README.md ├── example ├── error.cy ├── example.cy ├── func_call.cy ├── import.cy ├── localvar.cy ├── new.cy ├── print_str.cy ├── quicksort.cy ├── quicksort_bench.cy └── test.cy ├── lib ├── CMakeLists.txt ├── codegen.cpp ├── codegen.hpp ├── codegen_x64.cpp ├── codegen_x64.hpp ├── cyan.cpp ├── cyan.hpp ├── dead_code_eliminater.cpp ├── dead_code_eliminater.hpp ├── dep_analyzer.cpp ├── dep_analyzer.hpp ├── error_collector.cpp ├── error_collector.hpp ├── inliner.cpp ├── inliner.hpp ├── inst_rewriter.cpp ├── inst_rewriter.hpp ├── instruction.cpp ├── instruction.hpp ├── ir.cpp ├── ir.hpp ├── ir_builder.cpp ├── ir_builder.hpp ├── libcyan.hpp ├── location.hpp ├── loop_marker.cpp ├── loop_marker.hpp ├── mem2reg.cpp ├── mem2reg.hpp ├── optimizer.hpp ├── optimizer_group.cpp ├── optimizer_group.hpp ├── parse.cpp ├── parse.hpp ├── phi_eliminator.cpp ├── phi_eliminator.hpp ├── symbols.cpp ├── symbols.hpp ├── type.cpp ├── type.hpp ├── unreachable_code_eliminater.cpp ├── unreachable_code_eliminater.hpp ├── vm.cpp └── vm.hpp ├── runtime ├── Makefile ├── runtime.c └── runtime.o ├── src ├── CMakeLists.txt ├── lib_functions.cpp ├── lib_functions.hpp └── main.cpp └── test ├── CMakeLists.txt ├── codegen_x64_test.cpp ├── combined_test.cpp ├── dead_code_eliminater_test.cpp ├── dep_analyzer_test.cpp ├── inliner_test.cpp ├── inst_rewriter_test.cpp ├── loop_marker_test.cpp ├── mem2reg_test.cpp ├── parser_test.cpp ├── phi_eliminator_test.cpp └── unreachable_code_elimimater.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | build 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libback"] 2 | path = libback 3 | url = git@bitbucket.org:clarkok/libback.git 4 | [submodule "test/googletest"] 5 | path = test/googletest 6 | url = https://github.com/google/googletest.git 7 | [submodule "third-party/rlutil"] 8 | path = third-party/rlutil 9 | url = https://github.com/tapio/rlutil 10 | [submodule "third-party/xbyak"] 11 | path = third-party/xbyak 12 | url = https://github.com/herumi/xbyak 13 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.4) 2 | project(cyan) 3 | 4 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O0 -std=c++11 -g -Wno-unused-variable -Wno-unused-parameter -Wno-return-type -fno-operator-names") 5 | 6 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 7 | 8 | include_directories(third-party) 9 | 10 | add_subdirectory(lib) 11 | add_subdirectory(src) 12 | add_subdirectory(test) 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cyan 2 | 3 | Cyan is a programming language like Rust, but much simpler. 4 | 5 | Cyanc is the optimizing compiler of Cyan language, it can product pretty fast X64 code. 6 | 7 | This project is now under heavy development. For some examples, you can go to `example/`. 8 | -------------------------------------------------------------------------------- /example/error.cy: -------------------------------------------------------------------------------- 1 | let a = 0; 2 | 3 | functio () { } // global error 4 | 5 | function max (a : i64, b : i64) : i64 { 6 | return (a > b) ? a : b; 7 | } 8 | 9 | function a () { 10 | let t; 11 | } // dup name 12 | 13 | function main() { 14 | } 15 | -------------------------------------------------------------------------------- /example/example.cy: -------------------------------------------------------------------------------- 1 | function print_str(str: i8[]); 2 | 3 | concept Person { 4 | function getID() : i32; 5 | function getAge() : i32; 6 | function getName() : i8[]; 7 | } 8 | 9 | struct Student { 10 | name: i8[], 11 | id: i32, 12 | age: i32 13 | } 14 | 15 | impl Student : Person { 16 | function getID() : i32 { 17 | return this.id; 18 | } 19 | 20 | function getAge() : i32 { 21 | return this.age; 22 | } 23 | 24 | function getName() : i8[] { 25 | return this.name; 26 | } 27 | } 28 | 29 | function newStudent(name : i8[], id : i32, age : i32) : Student { 30 | let ret = new Student; 31 | ret.name = name; 32 | ret.id = id; 33 | ret.age = age; 34 | 35 | return ret; 36 | } 37 | 38 | function deletePerson(target : Person) { 39 | delete target; 40 | } 41 | 42 | function main() { 43 | let student = newStudent("test", 1, 2); 44 | print_str(student.Person.getName()); 45 | } 46 | -------------------------------------------------------------------------------- /example/func_call.cy: -------------------------------------------------------------------------------- 1 | function print_int(value : i64); 2 | function print_str(str : i8[]); 3 | 4 | function fact(n : i64) : i64 { 5 | if (n == 0) { 6 | return 0; 7 | } 8 | 9 | if (n == 1) { 10 | return 1; 11 | } 12 | 13 | return fact(n - 1) * n; 14 | } 15 | 16 | function main() { 17 | let i = 0; 18 | while (i < 10) { 19 | print_int(fact(i)); 20 | print_str("\n"); 21 | i = i + 1; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/import.cy: -------------------------------------------------------------------------------- 1 | function print_str(str : i8[]); 2 | function print_int(value : i64); 3 | function rand() : i32; 4 | 5 | function main() { 6 | print_str("The random number is: "); 7 | print_int(rand()); 8 | print_str("\n"); 9 | } 10 | -------------------------------------------------------------------------------- /example/localvar.cy: -------------------------------------------------------------------------------- 1 | function main() : i32 { 2 | let i = 0; 3 | while (i < 10) { i = i + 1; } 4 | return i; 5 | } 6 | -------------------------------------------------------------------------------- /example/new.cy: -------------------------------------------------------------------------------- 1 | struct Student { 2 | id : u64 3 | } 4 | 5 | function main() : u64 { 6 | let student = new Student; 7 | student.id = 10; 8 | delete student; 9 | 10 | return 1; 11 | } 12 | -------------------------------------------------------------------------------- /example/print_str.cy: -------------------------------------------------------------------------------- 1 | function print_str(str : i8[]); 2 | 3 | function main() : i64 { 4 | print_str("lalala\n"); 5 | } 6 | -------------------------------------------------------------------------------- /example/quicksort.cy: -------------------------------------------------------------------------------- 1 | function rand() : i64; 2 | function print_int(value : i64); 3 | function print_str(str : i8[]); 4 | 5 | function swap(a : &i64, b : &i64) { 6 | let t = a; 7 | a = b; 8 | b = t; 9 | } 10 | 11 | function partition(a : i64[], lo : i64, hi : i64) : i64 { 12 | let pivot = a[hi]; 13 | let i = lo; 14 | let j = lo; 15 | while (j < hi) { 16 | if (a[j] < pivot) { 17 | swap(a[i], a[j]); 18 | i = i + 1; 19 | } 20 | j = j + 1; 21 | } 22 | swap(a[i], a[j]); 23 | return i; 24 | } 25 | 26 | function quicksort(a : i64[], lo : i64, hi : i64) { 27 | if (lo < hi) { 28 | let p = partition(a, lo, hi); 29 | quicksort(a, lo, p - 1); 30 | quicksort(a, p + 1, hi); 31 | } 32 | } 33 | 34 | function main() { 35 | let n = 100; 36 | let a = new i64[n + 1]; 37 | let i = 0; 38 | while (i < n) { 39 | a[i] = rand() % 1000; 40 | print_int(a[i]); 41 | print_str(" "); 42 | i = i + 1; 43 | } 44 | print_str("\n"); 45 | 46 | quicksort(a, 0, n - 1); 47 | 48 | i = 0; 49 | while (i < n) { 50 | print_int(a[i]); 51 | print_str(" "); 52 | i = i + 1; 53 | } 54 | print_str("\n"); 55 | } 56 | -------------------------------------------------------------------------------- /example/quicksort_bench.cy: -------------------------------------------------------------------------------- 1 | function rand() : i64; 2 | function print_int(value : i64); 3 | function print_str(str : i8[]); 4 | 5 | function swap(a : &i32, b : &i32) { 6 | let t = a; 7 | a = b; 8 | b = t; 9 | } 10 | 11 | function partition(a : i32[], lo : i32, hi : i32) : i32 { 12 | let pivot = a[hi]; 13 | let i = lo; 14 | let j = lo; 15 | while (j < hi) { 16 | if (a[j] < pivot) { 17 | swap(a[i], a[j]); 18 | i = i + 1; 19 | } 20 | j = j + 1; 21 | } 22 | swap(a[i], a[j]); 23 | return i; 24 | } 25 | 26 | function quicksort(a : i32[], lo : i32, hi : i32) { 27 | if (lo < hi) { 28 | let p = partition(a, lo, hi); 29 | quicksort(a, lo, p - 1); 30 | quicksort(a, p + 1, hi); 31 | } 32 | } 33 | 34 | function main() { 35 | let n = 1000000; 36 | let a = new i32[n + 1]; 37 | let i = 0; 38 | while (i < n) { 39 | a[i] = rand() % 1000; 40 | i = i + 1; 41 | } 42 | quicksort(a, 0, n - 1); 43 | } 44 | -------------------------------------------------------------------------------- /example/test.cy: -------------------------------------------------------------------------------- 1 | function main() : i64 { 2 | return 10; 3 | } 4 | -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(LIBRARY_FILES cyan.hpp cyan.cpp parse.cpp parse.hpp symbols.cpp symbols.hpp location.hpp type.hpp type.cpp error_collector.cpp error_collector.hpp instruction.cpp instruction.hpp ir.cpp ir.hpp ir_builder.cpp ir_builder.hpp codegen.hpp codegen_x64.cpp codegen_x64.hpp codegen.cpp inliner.cpp dep_analyzer.cpp dep_analyzer.hpp mem2reg.cpp mem2reg.hpp loop_marker.cpp loop_marker.hpp inst_rewriter.cpp inst_rewriter.hpp phi_eliminator.cpp phi_eliminator.hpp dead_code_eliminater.cpp dead_code_eliminater.hpp unreachable_code_eliminater.cpp unreachable_code_eliminater.hpp optimizer_group.cpp optimizer_group.hpp vm.cpp vm.hpp) 2 | add_library(cyan ${LIBRARY_FILES}) 3 | -------------------------------------------------------------------------------- /lib/codegen.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/10/16. 3 | // 4 | 5 | #include "codegen.hpp" 6 | 7 | using namespace cyan; 8 | 9 | std::ostream & 10 | CodeGen::generate(std::ostream &os) 11 | { 12 | ir->output(os); 13 | return os; 14 | } 15 | 16 | #define impl_gen(type) \ 17 | void \ 18 | CodeGen::gen(type *) \ 19 | { } 20 | 21 | inst_foreach(impl_gen) 22 | -------------------------------------------------------------------------------- /lib/codegen.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/10/16. 3 | // 4 | 5 | #ifndef CYAN_CODEGEN_HPP 6 | #define CYAN_CODEGEN_HPP 7 | 8 | #include 9 | #include 10 | 11 | #include "ir.hpp" 12 | 13 | namespace cyan { 14 | 15 | #define define_gen(type) \ 16 | virtual void gen(type *inst); 17 | 18 | class CodeGen 19 | { 20 | protected: 21 | std::unique_ptr ir; 22 | 23 | public: 24 | CodeGen(IR *ir) 25 | : ir(ir) 26 | { } 27 | 28 | virtual ~CodeGen() = default; 29 | 30 | inline IR * 31 | release() 32 | { return ir.release(); } 33 | 34 | inline IR* 35 | get() const 36 | { return ir.get(); } 37 | 38 | virtual std::ostream &generate(std::ostream &os); 39 | 40 | inst_foreach(define_gen) 41 | }; 42 | 43 | } 44 | 45 | #endif //CYAN_CODEGEN_HPP 46 | -------------------------------------------------------------------------------- /lib/codegen_x64.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/10/16. 3 | // 4 | 5 | #ifndef CYAN_CODEGEN_X64_HPP 6 | #define CYAN_CODEGEN_X64_HPP 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "codegen.hpp" 13 | 14 | #define x64_inst_foreach(macro) \ 15 | macro(Label) \ 16 | macro(Mov) \ 17 | macro(Add) \ 18 | macro(And) \ 19 | macro(Call) \ 20 | macro(CallPreserve) \ 21 | macro(CallRestore) \ 22 | macro(Cmp) \ 23 | macro(Idiv) \ 24 | macro(Imod) \ 25 | macro(Imul) \ 26 | macro(Jmp) \ 27 | macro(Je) \ 28 | macro(Jne) \ 29 | macro(Jg) \ 30 | macro(Jge) \ 31 | macro(Jl) \ 32 | macro(Jle) \ 33 | macro(LeaOffset) \ 34 | macro(LeaGlobal) \ 35 | macro(Neg) \ 36 | macro(Not) \ 37 | macro(Or) \ 38 | macro(Pop) \ 39 | macro(Push) \ 40 | macro(Ret) \ 41 | macro(Sal) \ 42 | macro(Sar) \ 43 | macro(SetE) \ 44 | macro(SetL) \ 45 | macro(SetLe) \ 46 | macro(Shr) \ 47 | macro(Sub) \ 48 | macro(Xor) 49 | 50 | namespace cyan { 51 | class CodeGenX64; 52 | } 53 | 54 | namespace X64 { 55 | 56 | typedef std::list > InstList; 57 | typedef InstList::iterator InstIterator; 58 | typedef std::shared_ptr SharedOperand; 59 | 60 | struct Instruction 61 | { 62 | virtual ~Instruction() = default; 63 | virtual std::string to_string() const = 0; 64 | 65 | template 66 | const T* to() const 67 | { return dynamic_cast(this); } 68 | 69 | template 70 | T* to() 71 | { return dynamic_cast(this); } 72 | 73 | template 74 | bool is() const 75 | { return to() != nullptr; } 76 | 77 | virtual void registerAllocate(cyan::CodeGenX64 *codegen) = 0; 78 | virtual void resolveTooManyMemoryLocations( 79 | InstList &list, 80 | InstIterator iter, 81 | std::shared_ptr &temp_reg 82 | ) = 0; 83 | }; 84 | 85 | #define forward_define_inst(inst) \ 86 | struct inst; 87 | 88 | x64_inst_foreach(forward_define_inst) 89 | 90 | #undef forward_define_inst 91 | 92 | struct Block 93 | { 94 | std::string name; 95 | cyan::BasicBlock *ir_block; 96 | std::list > inst_list; 97 | 98 | Block(std::string name, cyan::BasicBlock *ir_block) 99 | : name(name), ir_block(ir_block) 100 | { } 101 | }; 102 | 103 | enum class Register; 104 | struct Operand; 105 | } 106 | 107 | namespace cyan { 108 | 109 | class CodeGenX64 : public CodeGen 110 | { 111 | public: 112 | static const int GENERAL_PURPOSE_REGISTER_NR = 14; 113 | static const int MEMORY_OPERATION_COST = 10; 114 | 115 | typedef size_t Position; 116 | typedef std::pair LiveRange; 117 | 118 | static std::string escapeAsmName(std::string original); 119 | 120 | private: 121 | std::map inst_used; 122 | std::vector > block_list; 123 | std::map block_map; 124 | std::map > inst_result; 125 | std::map allocate_map; 126 | int stack_allocate_counter = 0; 127 | 128 | std::list > inst_list; 129 | std::map live_range; 130 | std::map live_range_r; 131 | std::map operand_swap_out_cost; 132 | Function *current_func; 133 | 134 | size_t current_inst_index; 135 | std::set available_registers; 136 | std::set available_slots; 137 | std::map current_mapped_register; 138 | std::set used_registers; 139 | 140 | void registerValueLiveRange(X64::Operand *value, int loop_depth); 141 | 142 | void generateFunc(Function *func); 143 | void writeFunctionHeader(Function *func, std::ostream &os); 144 | void writeFunctionFooter(Function *func, std::ostream &os); 145 | void registerValueLiveRangeOfInst(X64::Instruction *inst, int loop_depth); 146 | void allocateRegisters(); 147 | 148 | X64::Operand *allocateAll(const std::set &skip_list, X64::Operand *operand); 149 | void freeAll(X64::Operand *operand); 150 | void requestRegister(X64::Register, X64::Operand *operand); 151 | void allocateFor(X64::Operand *operand); 152 | 153 | int allocateStackSlot(int size); 154 | int stackSlotOffset(int slot); 155 | int getAllocInstOffset(AllocaInst *inst); 156 | int calculateArgumentOffset(int argument); 157 | std::shared_ptr resolveOperand(Instruction *inst); 158 | std::shared_ptr resolveMemory(Instruction *inst); 159 | void setOrMoveOperand(Instruction *, std::shared_ptr); 160 | std::shared_ptr newValue(); 161 | 162 | public: 163 | CodeGenX64(IR *ir) 164 | : CodeGen(ir) 165 | { } 166 | 167 | virtual std::ostream &generate(std::ostream &os); 168 | 169 | #define register_alloc_decl(inst) \ 170 | void registerAllocate(X64::inst *); 171 | 172 | x64_inst_foreach(register_alloc_decl) 173 | 174 | #undef register_alloc_decl 175 | 176 | inst_foreach(define_gen) 177 | }; 178 | 179 | } 180 | 181 | #endif //CYAN_CODEGEN_X64_HPP 182 | -------------------------------------------------------------------------------- /lib/cyan.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clarkok/cyan/7e80c4266159c4e75c591cf31821207d6019d7e6/lib/cyan.cpp -------------------------------------------------------------------------------- /lib/cyan.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CYAN_CYAN_HPP 2 | #define CYAN_CYAN_HPP 3 | 4 | #include 5 | 6 | #if __x86_64__ || __ppc64__ 7 | #define __CYAN_64__ 1 8 | #else 9 | #define __CYAN_64__ 0 10 | #endif 11 | 12 | static const char CYAN_VERSION[] = "v0.0.1"; 13 | #if __CYAN_64__ 14 | static const size_t CYAN_PRODUCT_BITS = 64; 15 | #else 16 | static const size_t CYAN_PRODUCT_BITS = 32; 17 | #endif 18 | static const size_t CYAN_CHAR_BITS = 8; 19 | static const size_t CYAN_PRODUCT_BYTES = CYAN_PRODUCT_BITS / CYAN_CHAR_BITS; 20 | static const size_t CYAN_PRODUCT_ALIGN = CYAN_PRODUCT_BYTES; 21 | 22 | #endif //CYAN_CYAN_HPP 23 | -------------------------------------------------------------------------------- /lib/dead_code_eliminater.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/19/16. 3 | // 4 | 5 | #include "dead_code_eliminater.hpp" 6 | 7 | using namespace cyan; 8 | 9 | void 10 | DeadCodeEliminater::clearInstReference(Function *func) 11 | { 12 | for (auto &block_ptr : func->block_list) { 13 | for (auto &inst_ptr : block_ptr->inst_list) { 14 | inst_ptr->clearReferences(); 15 | } 16 | } 17 | } 18 | 19 | void 20 | DeadCodeEliminater::scanInstReference(Function *func) 21 | { 22 | for (auto &block_ptr : func->block_list) { 23 | for (auto &inst_ptr : block_ptr->inst_list) { 24 | if ( 25 | inst_ptr->is() || 26 | inst_ptr->is() || 27 | inst_ptr->is() || 28 | inst_ptr->is() 29 | ) { 30 | _scanner(inst_ptr.get()); 31 | } 32 | } 33 | if (block_ptr->condition) { 34 | _scanner(block_ptr->condition); 35 | } 36 | } 37 | } 38 | 39 | void 40 | DeadCodeEliminater::removeInst(Function *func) 41 | { 42 | for (auto &block_ptr : func->block_list) { 43 | block_ptr->inst_list.remove_if( 44 | [](const std::unique_ptr &inst_ptr) { 45 | return (inst_ptr->getReferencedCount() == 0); 46 | } 47 | ); 48 | } 49 | } 50 | 51 | void 52 | DeadCodeEliminater::_scanner(Instruction *inst) 53 | { 54 | if (scanned.find(inst) != scanned.end()) { return; } 55 | scanned.emplace(inst); 56 | 57 | inst->reference(); 58 | if (inst->is()) { 59 | _scanner(inst->to()->getLeft()); 60 | _scanner(inst->to()->getRight()); 61 | } 62 | else if (inst->is()) { 63 | _scanner(inst->to()->getAddress()); 64 | } 65 | else if (inst->is()) { 66 | _scanner(inst->to()->getAddress()); 67 | _scanner(inst->to()->getValue()); 68 | } 69 | else if (inst->is()) { 70 | _scanner(inst->to()->getSpace()); 71 | } 72 | else if (inst->is()) { 73 | _scanner(inst->to()->getFunction()); 74 | for (auto &arg : *(inst->to())) { 75 | _scanner(arg); 76 | } 77 | } 78 | else if (inst->is()) { 79 | if (inst->to()->getReturnValue()) { 80 | _scanner(inst->to()->getReturnValue()); 81 | } 82 | } 83 | else if (inst->is()) { 84 | for (auto &branch : *(inst->to())) { 85 | _scanner(branch.value); 86 | } 87 | } 88 | else if (inst->is()) { 89 | _scanner(inst->to()->getTarget()); 90 | } 91 | else if (inst->is()) { 92 | _scanner(inst->to()->getSpace()); 93 | } 94 | else if (inst->is()) { 95 | } 96 | else { 97 | assert(false); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /lib/dead_code_eliminater.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/19/16. 3 | // 4 | 5 | #ifndef CYAN_DEAD_CODE_ELIMINATER_HPP 6 | #define CYAN_DEAD_CODE_ELIMINATER_HPP 7 | 8 | #include "optimizer.hpp" 9 | 10 | namespace cyan { 11 | 12 | class DeadCodeEliminater : public Optimizer 13 | { 14 | void clearInstReference(Function *func); 15 | void scanInstReference(Function *func); 16 | void removeInst(Function *func); 17 | 18 | void _scanner(Instruction *inst); 19 | 20 | std::set scanned; 21 | public: 22 | DeadCodeEliminater(IR *ir) 23 | : Optimizer(ir) 24 | { 25 | for (auto &func_pair : ir->function_table) { 26 | scanned.clear(); 27 | clearInstReference(func_pair.second.get()); 28 | scanInstReference(func_pair.second.get()); 29 | removeInst(func_pair.second.get()); 30 | } 31 | } 32 | }; 33 | 34 | } 35 | 36 | #endif //CYAN_DEAD_CODE_ELIMINATER_HPP 37 | -------------------------------------------------------------------------------- /lib/dep_analyzer.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/16/16. 3 | // 4 | 5 | #include "dep_analyzer.hpp" 6 | 7 | using namespace cyan; 8 | 9 | BasicBlock * 10 | DepAnalyzer::findDominator(BasicBlock *p1, BasicBlock *p2) 11 | { 12 | std::set dominators; 13 | 14 | while (p1) { 15 | dominators.emplace(p1); 16 | p1 = p1->dominator; 17 | } 18 | 19 | while (p2) { 20 | if (dominators.find(p2) != dominators.end()) { return p2; } 21 | p2 = p2->dominator; 22 | } 23 | 24 | assert(false); 25 | return nullptr; 26 | } 27 | 28 | void 29 | DepAnalyzer::scanDep(BasicBlock *block) 30 | { 31 | if (scanned.find(block) != scanned.end()) { 32 | return; 33 | } 34 | scanned.emplace(block); 35 | 36 | if (block->condition) { 37 | assert(block->then_block); 38 | assert(block->else_block); 39 | 40 | setPreceder(block->then_block, block); 41 | scanDep(block->then_block); 42 | setPreceder(block->else_block, block); 43 | scanDep(block->else_block); 44 | } 45 | else if (block->then_block) { 46 | setPreceder(block->then_block, block); 47 | scanDep(block->then_block); 48 | } 49 | } 50 | 51 | void 52 | DepAnalyzer::setPreceder(BasicBlock *block, BasicBlock *preceder) 53 | { 54 | if (block->dominator) { 55 | block->dominator = findDominator(block->dominator, preceder); 56 | } 57 | else { 58 | block->dominator = preceder; 59 | } 60 | block->preceders.emplace(preceder); 61 | } 62 | 63 | void 64 | DepAnalyzer::outputResult(std::ostream &os) const 65 | { 66 | for (auto &func : ir->function_table) { 67 | os << func.first << ":" << std::endl; 68 | for (auto &block : func.second->block_list) { 69 | os << "\t" << block->getName() << ":" << std::endl; 70 | os << "\tdominator: " << (block->dominator ? block->dominator->getName() : "(null)") 71 | << std::endl; 72 | os << "\tpreceders:" << std::endl; 73 | for (auto &preceder : block->preceders) { 74 | os << "\t\t" << preceder->getName() << std::endl; 75 | } 76 | os << std::endl; 77 | } 78 | os << std::endl; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /lib/dep_analyzer.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/16/16. 3 | // 4 | 5 | #ifndef CYAN_DEP_ANALYZER_HPP 6 | #define CYAN_DEP_ANALYZER_HPP 7 | 8 | #include "optimizer.hpp" 9 | 10 | namespace cyan { 11 | 12 | class DepAnalyzer : public Optimizer 13 | { 14 | std::set scanned; 15 | 16 | void scanDep(BasicBlock *block); 17 | void setPreceder(BasicBlock *block, BasicBlock *preceder); 18 | 19 | BasicBlock *findDominator(BasicBlock *p1, BasicBlock *p2); 20 | 21 | public: 22 | DepAnalyzer(IR *ir) 23 | : Optimizer(ir) 24 | { 25 | for (auto &func : ir->function_table) { 26 | if (func.second->block_list.size()) { 27 | for (auto &block_ptr : func.second->block_list) { 28 | block_ptr->depth = 0; 29 | block_ptr->dominator = nullptr; 30 | block_ptr->preceders.clear(); 31 | } 32 | scanned.clear(); 33 | scanDep(func.second->block_list.front().get()); 34 | } 35 | } 36 | } 37 | 38 | void outputResult(std::ostream &os) const; 39 | }; 40 | 41 | } 42 | 43 | #endif //CYAN_DEP_ANALYZER_HPP 44 | -------------------------------------------------------------------------------- /lib/error_collector.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Clarkok on 16/5/3. 3 | // 4 | 5 | #include 6 | #include "rlutil/rlutil.h" 7 | 8 | #include "error_collector.hpp" 9 | 10 | using namespace cyan; 11 | 12 | void EmptyErrorCollector::error(const std::exception &) { } 13 | void EmptyErrorCollector::warn(const std::exception &) { } 14 | void EmptyErrorCollector::info(const std::exception &) { } 15 | 16 | void 17 | ChainErrorCollector::error(const std::exception &e) 18 | { 19 | for(auto &collector : collectors) { 20 | collector->error(e); 21 | } 22 | } 23 | 24 | void 25 | ChainErrorCollector::warn(const std::exception &e) 26 | { 27 | for(auto &collector : collectors) { 28 | collector->warn(e); 29 | } 30 | } 31 | 32 | void 33 | ChainErrorCollector::info(const std::exception &e) 34 | { 35 | for(auto &collector : collectors) { 36 | collector->info(e); 37 | } 38 | } 39 | 40 | void 41 | FilterErrorCollector::error(const std::exception &e) 42 | { error_collector->error(e); } 43 | 44 | void 45 | FilterErrorCollector::warn(const std::exception &e) 46 | { warn_collector->warn(e); } 47 | 48 | void 49 | FilterErrorCollector::info(const std::exception &e) 50 | { info_collector->info(e); } 51 | 52 | void 53 | CounterErrorCollector::error(const std::exception &) 54 | { ++error_counter; } 55 | 56 | void 57 | CounterErrorCollector::warn(const std::exception &) 58 | { ++warn_counter; } 59 | 60 | void 61 | CounterErrorCollector::info(const std::exception &) 62 | { ++info_counter; } 63 | 64 | void 65 | LimitErrorCollector::error(const std::exception &e) 66 | { 67 | CounterErrorCollector::error(e); 68 | if (getErrorCount() > error_limit) { 69 | throw TooManyMessagesException("error", error_limit); 70 | } 71 | } 72 | 73 | void 74 | LimitErrorCollector::warn(const std::exception &e) 75 | { 76 | dynamic_cast(this)->warn(e); 77 | if (getWarnCount() > warn_limit) { 78 | throw TooManyMessagesException("warning", warn_limit); 79 | } 80 | } 81 | 82 | void 83 | LimitErrorCollector::info(const std::exception &e) 84 | { 85 | dynamic_cast(this)->info(e); 86 | if (getInfoCount() > info_limit) { 87 | throw TooManyMessagesException("info", info_limit); 88 | } 89 | } 90 | 91 | void 92 | ScreenOutputErrorCollector::error(const std::exception &e) 93 | { 94 | rlutil::saveDefaultColor(); 95 | rlutil::setColor(rlutil::RED); 96 | std::cout << "ERR!"; 97 | rlutil::resetColor(); 98 | 99 | rlutil::setColor(rlutil::WHITE); 100 | std::cout << ": " << e.what() << std::endl; 101 | rlutil::resetColor(); 102 | } 103 | 104 | void 105 | ScreenOutputErrorCollector::warn(const std::exception &e) 106 | { 107 | rlutil::saveDefaultColor(); 108 | rlutil::setColor(rlutil::YELLOW); 109 | std::cout << "WARN"; 110 | rlutil::resetColor(); 111 | 112 | rlutil::setColor(rlutil::WHITE); 113 | std::cout << ": " << e.what() << std::endl; 114 | rlutil::resetColor(); 115 | } 116 | 117 | void 118 | ScreenOutputErrorCollector::info(const std::exception &e) 119 | { 120 | rlutil::saveDefaultColor(); 121 | rlutil::setColor(rlutil::GREEN); 122 | std::cout << "INFO"; 123 | rlutil::resetColor(); 124 | 125 | rlutil::setColor(rlutil::WHITE); 126 | std::cout << ": " << e.what() << std::endl; 127 | rlutil::resetColor(); 128 | } 129 | -------------------------------------------------------------------------------- /lib/error_collector.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Clarkok on 16/5/3. 3 | // 4 | 5 | #ifndef CYAN_ERROR_COLLECTOR_HPP 6 | #define CYAN_ERROR_COLLECTOR_HPP 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace cyan { 15 | 16 | class ErrorCollector 17 | { 18 | public: 19 | ErrorCollector() = default; 20 | virtual ~ErrorCollector() = default; 21 | 22 | virtual void error(const std::exception &) = 0; 23 | virtual void warn(const std::exception &) = 0; 24 | virtual void info(const std::exception &) = 0; 25 | }; 26 | 27 | class EmptyErrorCollector : public ErrorCollector 28 | { 29 | public: 30 | EmptyErrorCollector() = default; 31 | 32 | virtual void error(const std::exception &); 33 | virtual void warn(const std::exception &); 34 | virtual void info(const std::exception &); 35 | }; 36 | 37 | class ChainErrorCollector : public ErrorCollector 38 | { 39 | std::vector > collectors; 40 | 41 | ChainErrorCollector() { } 42 | 43 | public: 44 | struct Builder 45 | { 46 | std::unique_ptr product; 47 | 48 | Builder() 49 | : product(new ChainErrorCollector()) 50 | { } 51 | 52 | inline ChainErrorCollector * 53 | release() 54 | { return product.release(); } 55 | 56 | inline Builder & 57 | addCollector(ErrorCollector *collector) 58 | { 59 | product->collectors.emplace_back(collector); 60 | return *this; 61 | } 62 | }; 63 | 64 | virtual void error(const std::exception &); 65 | virtual void warn(const std::exception &); 66 | virtual void info(const std::exception &); 67 | }; 68 | 69 | class FilterErrorCollector : public ErrorCollector 70 | { 71 | std::unique_ptr error_collector; 72 | std::unique_ptr warn_collector; 73 | std::unique_ptr info_collector; 74 | 75 | public: 76 | FilterErrorCollector(ErrorCollector *error, ErrorCollector *warn, ErrorCollector *info) 77 | : error_collector(error), warn_collector(warn), info_collector(info) 78 | { } 79 | 80 | virtual void error(const std::exception &); 81 | virtual void warn(const std::exception &); 82 | virtual void info(const std::exception &); 83 | }; 84 | 85 | class CounterErrorCollector : public ErrorCollector 86 | { 87 | size_t error_counter; 88 | size_t warn_counter; 89 | size_t info_counter; 90 | 91 | public: 92 | CounterErrorCollector() 93 | : error_counter(0), 94 | warn_counter(0), 95 | info_counter(0) 96 | { } 97 | 98 | inline size_t 99 | getErrorCount() const 100 | { return error_counter; } 101 | 102 | inline size_t 103 | getWarnCount() const 104 | { return warn_counter; } 105 | 106 | inline size_t 107 | getInfoCount() const 108 | { return info_counter; } 109 | 110 | virtual void error(const std::exception &); 111 | virtual void warn(const std::exception &); 112 | virtual void info(const std::exception &); 113 | }; 114 | 115 | class LimitErrorCollector : public CounterErrorCollector 116 | { 117 | size_t error_limit; 118 | size_t warn_limit; 119 | size_t info_limit; 120 | 121 | public: 122 | struct TooManyMessagesException : std::exception 123 | { 124 | std::string _what; 125 | 126 | TooManyMessagesException(std::string type, size_t limit) 127 | : _what("too many " + type + " reaching limit " + std::to_string(limit)) 128 | { } 129 | 130 | virtual const char * 131 | what() const noexcept 132 | { return _what.c_str(); } 133 | }; 134 | 135 | LimitErrorCollector( 136 | size_t error_limit = std::numeric_limits::max(), 137 | size_t warn_limit = std::numeric_limits::max(), 138 | size_t info_limit = std::numeric_limits::max() 139 | ) : error_limit(error_limit), 140 | warn_limit(warn_limit), 141 | info_limit(info_limit) 142 | { } 143 | 144 | virtual void error(const std::exception &); 145 | virtual void warn(const std::exception &); 146 | virtual void info(const std::exception &); 147 | }; 148 | 149 | class ScreenOutputErrorCollector : public ErrorCollector 150 | { 151 | public: 152 | ScreenOutputErrorCollector() = default; 153 | 154 | virtual void error(const std::exception &); 155 | virtual void warn(const std::exception &); 156 | virtual void info(const std::exception &); 157 | }; 158 | 159 | } 160 | 161 | #endif //CYAN_ERROR_COLLECTOR_HPP 162 | -------------------------------------------------------------------------------- /lib/inliner.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/15/16. 3 | // 4 | 5 | #include "inliner.hpp" 6 | #include "ir.hpp" 7 | 8 | using namespace cyan; 9 | 10 | void 11 | Inliner::constructCallingGraph() 12 | { 13 | calling_graph.clear(); 14 | for (auto &func_pair : ir->function_table) { 15 | calling_graph.emplace( 16 | func_pair.second.get(), 17 | std::unique_ptr(new FunctionNode()) 18 | ); 19 | } 20 | 21 | for (auto &func_pair : ir->function_table) { 22 | for (auto &block_ptr : func_pair.second->block_list) { 23 | for (auto &inst_ptr : block_ptr->inst_list) { 24 | if (inst_ptr->is()) { 25 | auto *callee = tryPrecalculateFunction(inst_ptr->to()); 26 | if (callee) { 27 | calling_graph[callee]->callers.emplace(func_pair.second.get()); 28 | calling_graph[func_pair.second.get()]->callees.emplace(callee); 29 | } 30 | } 31 | } 32 | } 33 | } 34 | } 35 | 36 | Function * 37 | Inliner::tryPrecalculateFunction(CallInst *inst) 38 | { 39 | if (inst->getFunction()->is()) { 40 | auto global_inst = inst->getFunction()->to(); 41 | if (ir->function_table.find(global_inst->getValue()) != ir->function_table.end()) { 42 | return ir->function_table[global_inst->getValue()].get(); 43 | } 44 | } 45 | else if (inst->getFunction()->is()) { 46 | auto load_inst = inst->getFunction()->to(); 47 | if (!load_inst->getAddress()->is()) { return nullptr; } 48 | 49 | auto add_inst = load_inst->getAddress()->to(); 50 | if (!add_inst->getLeft()->getType()->is()) { return nullptr; } 51 | if (!add_inst->getRight()->is()) { return nullptr; } 52 | 53 | auto vtable_type = add_inst->getLeft()->getType()->to(); 54 | if (!vtable_type->getOwner()->is()) { return nullptr; } 55 | 56 | auto casted_struct_type = vtable_type->getOwner()->to(); 57 | auto offset = add_inst->getRight()->to()->getValue(); 58 | 59 | return casted_struct_type->getMethodByOffset(static_cast(offset)).impl; 60 | } 61 | return nullptr; 62 | } 63 | 64 | void 65 | Inliner::performInline( 66 | Function *caller, 67 | BasicBlock *block, 68 | std::list >::iterator inst_iter, 69 | Function *callee 70 | ) { 71 | std::map value_map; 72 | std::map block_map; 73 | std::vector argument_alloc; 74 | 75 | assert((*inst_iter)->is()); 76 | auto call_inst = (*inst_iter)->to(); 77 | 78 | auto new_bb = block->split( 79 | inst_iter, 80 | block->getName() + ".split." + std::to_string(caller->countLocalTemp()) 81 | ); 82 | caller->block_list.emplace_back(new_bb); 83 | 84 | auto result_phi_builder = PhiInst::Builder( 85 | (*inst_iter)->getType(), 86 | new_bb, 87 | (*inst_iter)->getName() 88 | ); 89 | 90 | for (auto &arg : *call_inst) { 91 | auto imm_inst = new UnsignedImmInst( 92 | ir->type_pool->getUnsignedIntegerType(CYAN_PRODUCT_BITS), 93 | 1, 94 | block, 95 | "_" + std::to_string(caller->countLocalTemp()) 96 | ); 97 | auto alloc_inst = new AllocaInst( 98 | ir->type_pool->getPointerType(arg->getType()), 99 | imm_inst, 100 | block, 101 | "_" + std::to_string(caller->countLocalTemp()) 102 | ); 103 | auto store_inst = new StoreInst( 104 | arg->getType(), 105 | alloc_inst, 106 | arg, 107 | block, 108 | "" 109 | ); 110 | block->inst_list.emplace_back(imm_inst); 111 | block->inst_list.emplace_back(alloc_inst); 112 | block->inst_list.emplace_back(store_inst); 113 | argument_alloc.emplace_back(alloc_inst); 114 | } 115 | 116 | for (auto &block_ptr : callee->block_list) { 117 | caller->block_list.emplace_back(new BasicBlock( 118 | callee->getName() + "." + block_ptr->name + "." + std::to_string(caller->countLocalTemp()), 119 | block_ptr->getDepth() 120 | )); 121 | 122 | block_map.emplace(block_ptr.get(), caller->block_list.back().get()); 123 | } 124 | 125 | for (auto &block_ptr : callee->block_list) { 126 | auto new_block = block_map[block_ptr.get()]; 127 | bool return_block = false; 128 | 129 | for (auto &inst : block_ptr->inst_list) { 130 | if (inst->is()) { 131 | auto arg_inst = inst->to(); 132 | if (value_map.find(arg_inst) == value_map.end()) { 133 | value_map.emplace(arg_inst, argument_alloc[arg_inst->getValue()]); 134 | } 135 | } 136 | else if (inst->is()) { 137 | auto phi_inst = inst->to(); 138 | new_block->inst_list.emplace_back(phi_inst->cloneBranch( 139 | block_map, 140 | value_map, 141 | callee->getName() + "." + inst->getName() + "." + std::to_string(caller->countLocalTemp()) 142 | )); 143 | } 144 | else if (inst->is()) { 145 | auto ret_inst = inst->to(); 146 | return_block = true; 147 | if (ret_inst->getReturnValue()) { 148 | result_phi_builder.addBranch( 149 | value_map.at(ret_inst->getReturnValue()), 150 | new_block 151 | ); 152 | } 153 | break; 154 | } 155 | else { 156 | new_block->inst_list.emplace_back(inst->clone( 157 | new_block, 158 | value_map, 159 | callee->getName() + "." + inst->getName() + "." + std::to_string(caller->countLocalTemp()) 160 | )); 161 | } 162 | } 163 | 164 | if ( 165 | return_block || 166 | (!block_ptr->condition && !block_ptr->then_block) 167 | ) { new_block->then_block = new_bb; } 168 | else { 169 | new_block->condition = block_ptr->condition; 170 | new_block->then_block = block_ptr->then_block ? block_map.at(block_ptr->then_block) : nullptr; 171 | new_block->else_block = block_ptr->else_block ? block_map.at(block_ptr->else_block) : nullptr; 172 | } 173 | } 174 | 175 | for (auto &block_ptr : callee->block_list) { 176 | auto new_block = block_map[block_ptr.get()]; 177 | for (auto &inst_ptr : new_block->inst_list) { 178 | inst_ptr->resolve(value_map); 179 | } 180 | if (new_block->condition) { 181 | new_block->condition = value_map.at(new_block->condition); 182 | } 183 | } 184 | 185 | block->condition = nullptr; 186 | block->then_block = block_map.at(callee->block_list.front().get()); 187 | block->else_block = nullptr; 188 | 189 | Instruction *result_inst = nullptr; 190 | 191 | if (result_phi_builder.get()->branches_size() == 1) { 192 | result_inst = result_phi_builder.get()->begin()->value; 193 | } 194 | else if (result_phi_builder.get()->branches_size()) { 195 | new_bb->inst_list.emplace_front(result_inst = result_phi_builder.release()); 196 | } 197 | else { 198 | new_bb->inst_list.emplace_front(result_inst = new UnsignedImmInst( 199 | ir->type_pool->getUnsignedIntegerType(CYAN_PRODUCT_BITS), 200 | 0, 201 | new_bb, 202 | call_inst->getName() 203 | )); 204 | } 205 | 206 | for (auto &block_ptr : caller->block_list) { 207 | for (auto &inst_ptr : block_ptr->inst_list) { 208 | if (inst_ptr->is()) { 209 | inst_ptr->to()->replaceBranch(call_inst, result_inst, new_bb); 210 | } 211 | else { 212 | inst_ptr->replaceUsage(call_inst, result_inst); 213 | } 214 | } 215 | } 216 | block->inst_list.erase(inst_iter); 217 | } 218 | 219 | void 220 | Inliner::resortFunctions() 221 | { 222 | while (calling_graph.size()) { 223 | auto func_iter = calling_graph.begin(); 224 | auto callee_nr = func_iter->second->callees.size(); 225 | 226 | for ( 227 | auto iter = calling_graph.begin(); 228 | iter != calling_graph.end(); 229 | ++iter 230 | ) { 231 | if (iter->second->callees.size() < callee_nr) { 232 | func_iter = iter; 233 | callee_nr = iter->second->callees.size(); 234 | } 235 | } 236 | 237 | if ( 238 | func_iter->first->inst_size() <= INLINE_INST_NR_LIMIT || 239 | func_iter->second->callers.size() <= INLINE_CALLER_NR_LIMIT 240 | ) { 241 | for (auto &caller : func_iter->second->callers) { 242 | if (caller == func_iter->first) { continue; } 243 | 244 | std::list >::iterator> call_inst_list; 245 | std::list owner_block_list; 246 | 247 | for (auto &block_ptr : caller->block_list) { 248 | for ( 249 | auto inst_iter = block_ptr->inst_list.begin(); 250 | inst_iter != block_ptr->inst_list.end(); 251 | ++inst_iter 252 | ) { 253 | if ( 254 | (*inst_iter)->is() && 255 | tryPrecalculateFunction((*inst_iter)->to()) == func_iter->first 256 | ) { 257 | call_inst_list.emplace_back(inst_iter); 258 | owner_block_list.emplace_back(block_ptr.get()); 259 | } 260 | } 261 | } 262 | 263 | while (call_inst_list.size()) { 264 | performInline( 265 | caller, 266 | owner_block_list.back(), 267 | call_inst_list.back(), 268 | func_iter->first 269 | ); 270 | call_inst_list.pop_back(); 271 | owner_block_list.pop_back(); 272 | } 273 | } 274 | } 275 | 276 | for (auto &caller : func_iter->second->callers) { 277 | calling_graph[caller]->callees.erase(func_iter->first); 278 | } 279 | 280 | calling_graph.erase(func_iter); 281 | } 282 | } 283 | 284 | void 285 | Inliner::unusedFunctionEliminate() 286 | { 287 | std::set used_func({ ir->function_table["_init_"].get() }); 288 | 289 | if (ir->function_table.find("main") != ir->function_table.end()) { 290 | used_func.emplace(ir->function_table["main"].get()); 291 | } 292 | 293 | ir->type_pool->foreachCastedStructType( 294 | [&used_func](CastedStructType *casted) { 295 | for (auto &member : *casted) { 296 | assert(member.impl); 297 | used_func.emplace(member.impl); 298 | } 299 | } 300 | ); 301 | 302 | for (auto &func_pair : calling_graph) { 303 | if (used_func.find(func_pair.first) == used_func.end()) { 304 | if (!func_pair.second->callers.size()) { 305 | ir->function_table.erase(func_pair.first->getName()); 306 | } 307 | } 308 | } 309 | } 310 | 311 | void 312 | Inliner::outputCallingGraph(std::ostream &os) 313 | { 314 | for (auto &func_pair : calling_graph) { 315 | os << func_pair.first->getName() << std::endl;; 316 | 317 | os << "callers" << std::endl; 318 | for (auto &callers : func_pair.second->callers) { 319 | os << " > " << callers->getName() << std::endl; 320 | } 321 | 322 | os << "callees" << std::endl; 323 | for (auto &callees : func_pair.second->callees) { 324 | os << " < " << callees->getName() << std::endl; 325 | } 326 | 327 | os << std::endl; 328 | } 329 | } 330 | -------------------------------------------------------------------------------- /lib/inliner.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/15/16 3 | // 4 | 5 | #ifndef CYAN_INLINER_HPP 6 | #define CYAN_INLINER_HPP 7 | 8 | #include 9 | #include 10 | 11 | #include "optimizer.hpp" 12 | 13 | namespace cyan { 14 | 15 | class Inliner : public Optimizer 16 | { 17 | public: 18 | static const int INLINE_INST_NR_LIMIT = 112; 19 | static const int INLINE_CALLER_NR_LIMIT = 2; 20 | 21 | private: 22 | struct FunctionNode 23 | { 24 | std::set callers; 25 | std::set callees; 26 | 27 | FunctionNode() = default; 28 | ~FunctionNode() = default; 29 | 30 | FunctionNode(FunctionNode &&node) 31 | : callers(std::move(node.callers)), callees(std::move(node.callees)) 32 | { } 33 | }; 34 | 35 | std::map > calling_graph; 36 | 37 | void constructCallingGraph(); 38 | Function *tryPrecalculateFunction(CallInst *inst); 39 | void performInline( 40 | Function *caller, 41 | BasicBlock *block, 42 | std::list >::iterator inst_iter, 43 | Function *callee 44 | ); 45 | void resortFunctions(); 46 | void unusedFunctionEliminate(); 47 | 48 | public: 49 | Inliner(IR *ir) 50 | : Optimizer(ir) 51 | { 52 | constructCallingGraph(); 53 | resortFunctions(); 54 | constructCallingGraph(); 55 | unusedFunctionEliminate(); 56 | } 57 | 58 | void outputCallingGraph(std::ostream &os); 59 | }; 60 | 61 | } 62 | 63 | #endif // CYAN_INLINER_HPP 64 | -------------------------------------------------------------------------------- /lib/inst_rewriter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/17/16. 3 | // 4 | 5 | #include "inst_rewriter.hpp" 6 | 7 | using namespace cyan; 8 | 9 | void 10 | InstRewriter::rewriteFunction(Function *func) 11 | { 12 | block_result.clear(); 13 | value_map.clear(); 14 | imm_map.clear(); 15 | for (auto &block_ptr : func->block_list) { 16 | rewriteBlock(func, block_ptr.get()); 17 | } 18 | 19 | for (auto &block_ptr : func->block_list) { 20 | for (auto &inst_ptr : block_ptr->inst_list) { 21 | inst_ptr->resolve(value_map); 22 | } 23 | if (value_map.find(block_ptr->condition) != value_map.end()) { 24 | block_ptr->condition = value_map.at(block_ptr->condition); 25 | } 26 | } 27 | } 28 | 29 | void 30 | InstRewriter::rewriteBlock(Function *func, BasicBlock *block) 31 | { 32 | if (block_result.find(block) != block_result.end()) { return; } 33 | if (block->dominator) { rewriteBlock(func, block->dominator); } 34 | 35 | block_result.emplace( 36 | block, 37 | std::unique_ptr(new InternalResultSet()) 38 | ); 39 | 40 | for ( 41 | auto inst_iter = block->inst_list.begin(); 42 | inst_iter != block->inst_list.end(); 43 | ) { 44 | if ((*inst_iter)->is()) { 45 | auto value = (*inst_iter)->to()->getValue(); 46 | if (imm_map.find(value) == imm_map.end()) { 47 | imm_map.emplace(value, inst_iter->get()); 48 | if (block != func->block_list.front().get()) { 49 | (*inst_iter)->setOwnerBlock(func->block_list.front().get()); 50 | func->block_list.front()->inst_list.emplace_front(inst_iter->release()); 51 | removed.push_back(std::move(*inst_iter)); 52 | inst_iter = block->inst_list.erase(inst_iter); 53 | } 54 | else { 55 | inst_iter++; 56 | } 57 | } 58 | else { 59 | value_map.emplace(inst_iter->get(), imm_map.at(value)); 60 | removed.push_back(std::move(*inst_iter)); 61 | inst_iter = block->inst_list.erase(inst_iter); 62 | } 63 | continue; 64 | } 65 | else if ((*inst_iter)->is()) { 66 | auto value = static_cast( 67 | (*inst_iter)->to()->getValue() 68 | ); 69 | if (imm_map.find(value) == imm_map.end()) { 70 | imm_map.emplace(value, inst_iter->get()); 71 | if (block != func->block_list.front().get()) { 72 | (*inst_iter)->setOwnerBlock(func->block_list.front().get()); 73 | func->block_list.front()->inst_list.emplace_front(inst_iter->release()); 74 | removed.push_back(std::move(*inst_iter)); 75 | inst_iter = block->inst_list.erase(inst_iter); 76 | } 77 | else { 78 | inst_iter++; 79 | } 80 | } 81 | else { 82 | value_map.emplace(inst_iter->get(), imm_map.at(value)); 83 | removed.push_back(std::move(*inst_iter)); 84 | inst_iter = block->inst_list.erase(inst_iter); 85 | } 86 | continue; 87 | } 88 | else if ((*inst_iter)->is()) { 89 | auto binary_inst = (*inst_iter)->to(); 90 | binary_inst->resolve(value_map); 91 | if ( 92 | (binary_inst->getLeft()->is() || 93 | binary_inst->getLeft()->is()) && 94 | (binary_inst->getRight()->is() || 95 | binary_inst->getRight()->is()) 96 | ) { 97 | Instruction *result_inst = calculateConstant(func, binary_inst); 98 | value_map.emplace(binary_inst, result_inst); 99 | removed.push_back(std::move(*inst_iter)); 100 | inst_iter = block->inst_list.erase(inst_iter); 101 | continue; 102 | } 103 | 104 | auto calculated = findCalculated(block, binary_inst); 105 | if (calculated) { 106 | value_map.emplace(binary_inst, calculated); 107 | removed.push_back(std::move(*inst_iter)); 108 | inst_iter = block->inst_list.erase(inst_iter); 109 | continue; 110 | } 111 | 112 | if ( 113 | binary_inst->getLeft()->getOwnerBlock()->loop_header 114 | != block->loop_header && 115 | binary_inst->getRight()->getOwnerBlock()->loop_header 116 | != block->loop_header 117 | ) { 118 | auto loop_header = binary_inst->getOwnerBlock()->loop_header; 119 | while ( 120 | loop_header->getDepth() > 1 && 121 | binary_inst->getLeft()->getOwnerBlock()->loop_header != 122 | loop_header->dominator->loop_header && 123 | binary_inst->getRight()->getOwnerBlock()->loop_header != 124 | loop_header->dominator->loop_header 125 | ) { 126 | loop_header = loop_header->dominator->loop_header; 127 | } 128 | assert(loop_header); 129 | auto dst = loop_header->dominator; 130 | (*inst_iter)->setOwnerBlock(dst); 131 | dst->inst_list.emplace_back(inst_iter->release()); 132 | removed.push_back(std::move(*inst_iter)); 133 | inst_iter = block->inst_list.erase(inst_iter); 134 | registerResult(dst, binary_inst); 135 | continue; 136 | } 137 | 138 | registerResult(block, binary_inst); 139 | ++inst_iter; 140 | continue; 141 | } 142 | 143 | (*inst_iter)->resolve(value_map); 144 | ++inst_iter; 145 | } 146 | } 147 | 148 | Instruction * 149 | InstRewriter::calculateConstant(Function *func, BinaryInst *inst) 150 | { 151 | if (inst->getLeft()->is() && inst->getRight()->is()) { 152 | uintptr_t left = inst->getLeft()->to()->getValue(); 153 | uintptr_t right = inst->getRight()->to()->getValue(); 154 | 155 | uintptr_t result = 0; 156 | if (inst->is()) { 157 | result = left + right; 158 | } 159 | else if (inst->is()) { 160 | result = left - right; 161 | } 162 | else if (inst->is()) { 163 | result = left * right; 164 | } 165 | else if (inst->is()) { 166 | result = left / right; 167 | } 168 | else if (inst->is()) { 169 | result = left % right; 170 | } 171 | else if (inst->is()) { 172 | result = left << right; 173 | } 174 | else if (inst->is()) { 175 | result = left >> right; 176 | } 177 | else if (inst->is()) { 178 | result = left | right; 179 | } 180 | else if (inst->is()) { 181 | result = left & right; 182 | } 183 | else if (inst->is()) { 184 | result = ~(left | right); 185 | } 186 | else if (inst->is()) { 187 | result = left ^ right; 188 | } 189 | else if (inst->is()) { 190 | result = (left == right) ? 1 : 0; 191 | } 192 | else if (inst->is()) { 193 | result = (left < right) ? 1 : 0; 194 | } 195 | else if (inst->is()) { 196 | result = (left <= right) ? 1 : 0; 197 | } 198 | else { 199 | assert(false); 200 | } 201 | if (imm_map.find(static_cast(result)) == imm_map.end()) { 202 | auto imm_inst = new UnsignedImmInst( 203 | ir->type_pool->getUnsignedIntegerType(CYAN_PRODUCT_BITS), 204 | result, 205 | func->block_list.front().get(), 206 | "_" + std::to_string(func->countLocalTemp()) 207 | ); 208 | func->block_list.front()->inst_list.emplace_front(imm_inst); 209 | imm_map.emplace(static_cast(result), imm_inst); 210 | } 211 | return imm_map.at(static_cast(result)); 212 | } 213 | else { 214 | intptr_t left = inst->getLeft()->is() 215 | ? inst->getLeft()->to()->getValue() 216 | : static_cast(inst->getLeft()->to()->getValue()); 217 | intptr_t right = inst->getRight()->is() 218 | ? inst->getRight()->to()->getValue() 219 | : static_cast(inst->getRight()->to()->getValue()); 220 | 221 | intptr_t result = 0; 222 | if (inst->is()) { 223 | result = left + right; 224 | } 225 | else if (inst->is()) { 226 | result = left - right; 227 | } 228 | else if (inst->is()) { 229 | result = left * right; 230 | } 231 | else if (inst->is()) { 232 | result = left / right; 233 | } 234 | else if (inst->is()) { 235 | result = left % right; 236 | } 237 | else if (inst->is()) { 238 | result = left << right; 239 | } 240 | else if (inst->is()) { 241 | result = left >> right; 242 | } 243 | else if (inst->is()) { 244 | result = left | right; 245 | } 246 | else if (inst->is()) { 247 | result = left & right; 248 | } 249 | else if (inst->is()) { 250 | result = ~(left | right); 251 | } 252 | else if (inst->is()) { 253 | result = left ^ right; 254 | } 255 | else if (inst->is()) { 256 | result = (left == right); 257 | } 258 | else if (inst->is()) { 259 | result = (left < right); 260 | } 261 | else if (inst->is()) { 262 | result = (left <= right); 263 | } 264 | else { 265 | assert(false); 266 | } 267 | if (imm_map.find(result) == imm_map.end()) { 268 | auto imm_inst = new SignedImmInst( 269 | ir->type_pool->getSignedIntegerType(CYAN_PRODUCT_BITS), 270 | result, 271 | func->block_list.front().get(), 272 | "_" + std::to_string(func->countLocalTemp()) 273 | ); 274 | func->block_list.front()->inst_list.emplace_front(imm_inst); 275 | imm_map.emplace(result, imm_inst); 276 | } 277 | return imm_map.at(result); 278 | } 279 | } 280 | 281 | Instruction * 282 | InstRewriter::findCalculated(BasicBlock *block, BinaryInst *inst) 283 | { 284 | #define find(Op) \ 285 | find##Op##Result(block, inst->getLeft(), inst->getRight()) 286 | 287 | if (inst->is()) { return find(Add); } 288 | else if (inst->is()) { return find(Sub); } 289 | else if (inst->is()) { return find(Mul); } 290 | else if (inst->is()) { return find(Div); } 291 | else if (inst->is()) { return find(Mod); } 292 | else if (inst->is()) { return find(Shl); } 293 | else if (inst->is()) { return find(Shr); } 294 | else if (inst->is()) { return find(Or) ; } 295 | else if (inst->is()) { return find(And); } 296 | else if (inst->is()) { return find(Nor); } 297 | else if (inst->is()) { return find(Xor); } 298 | else if (inst->is()) { return find(Seq); } 299 | else if (inst->is()) { return find(Slt); } 300 | else if (inst->is()) { return find(Sle); } 301 | else { assert(false); } 302 | 303 | #undef find 304 | } 305 | 306 | void 307 | InstRewriter::registerResult(BasicBlock *block, BinaryInst *inst) 308 | { 309 | #define result(result_set) \ 310 | block_result.at(block)->result_set.emplace( \ 311 | std::make_pair(inst->getLeft(), inst->getRight()), \ 312 | inst \ 313 | ) 314 | 315 | if (inst->is()) { result(add_results); } 316 | else if (inst->is()) { result(sub_results); } 317 | else if (inst->is()) { result(mul_results); } 318 | else if (inst->is()) { result(div_results); } 319 | else if (inst->is()) { result(mod_results); } 320 | else if (inst->is()) { result(shl_results); } 321 | else if (inst->is()) { result(shr_results); } 322 | else if (inst->is()) { result(or_results ); } 323 | else if (inst->is()) { result(and_results); } 324 | else if (inst->is()) { result(nor_results); } 325 | else if (inst->is()) { result(xor_results); } 326 | else if (inst->is()) { result(seq_results); } 327 | else if (inst->is()) { result(slt_results); } 328 | else if (inst->is()) { result(sle_results); } 329 | else { assert(false); } 330 | 331 | #undef result 332 | } 333 | 334 | #define impl_find_method(method, result) \ 335 | Instruction * \ 336 | InstRewriter::method(BasicBlock *block, Instruction *left, Instruction *right) const \ 337 | { \ 338 | auto original = block; \ 339 | auto value = std::make_pair(left, right); \ 340 | Instruction *ret = nullptr; \ 341 | while (block) { \ 342 | auto internal_result_set = block_result.at(block).get(); \ 343 | if (internal_result_set->result.find(value) != internal_result_set->result.end()) { \ 344 | ret = internal_result_set->result.at(value); \ 345 | break; \ 346 | } \ 347 | block = block->dominator; \ 348 | } \ 349 | if (!ret) return nullptr; \ 350 | while (original != block) { \ 351 | block_result.at(original)->result.emplace(value, ret); \ 352 | original = original->dominator; \ 353 | } \ 354 | return ret; \ 355 | } 356 | 357 | impl_find_method(findAddResult, add_results) 358 | impl_find_method(findSubResult, sub_results) 359 | impl_find_method(findMulResult, mul_results) 360 | impl_find_method(findDivResult, div_results) 361 | impl_find_method(findModResult, mod_results) 362 | impl_find_method(findShlResult, shl_results) 363 | impl_find_method(findShrResult, shr_results) 364 | impl_find_method(findOrResult, or_results ) 365 | impl_find_method(findAndResult, and_results) 366 | impl_find_method(findNorResult, nor_results) 367 | impl_find_method(findXorResult, xor_results) 368 | impl_find_method(findSeqResult, seq_results) 369 | impl_find_method(findSltResult, slt_results) 370 | impl_find_method(findSleResult, sle_results) 371 | 372 | #undef impl_find_method 373 | -------------------------------------------------------------------------------- /lib/inst_rewriter.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/17/16. 3 | // 4 | 5 | #ifndef CYAN_INST_REWRITER_HPP 6 | #define CYAN_INST_REWRITER_HPP 7 | 8 | #include "optimizer.hpp" 9 | 10 | namespace cyan { 11 | 12 | class InstRewriter : public Optimizer 13 | { 14 | typedef std::pair OperandPair; 15 | typedef std::map BinaryResultMap; 16 | typedef std::map ImmediateMap; 17 | typedef std::map GlobalMap; 18 | 19 | struct InternalResultSet 20 | { 21 | BinaryResultMap add_results; 22 | BinaryResultMap sub_results; 23 | BinaryResultMap mul_results; 24 | BinaryResultMap div_results; 25 | BinaryResultMap mod_results; 26 | BinaryResultMap shl_results; 27 | BinaryResultMap shr_results; 28 | BinaryResultMap or_results; 29 | BinaryResultMap and_results; 30 | BinaryResultMap nor_results; 31 | BinaryResultMap xor_results; 32 | BinaryResultMap seq_results; 33 | BinaryResultMap slt_results; 34 | BinaryResultMap sle_results; 35 | }; 36 | 37 | std::map > block_result; 38 | std::map value_map; 39 | std::map imm_map; 40 | 41 | void rewriteFunction(Function *func); 42 | void rewriteBlock(Function *func, BasicBlock *block); 43 | 44 | Instruction *calculateConstant(Function *func, BinaryInst *inst); 45 | Instruction *findCalculated(BasicBlock *block, BinaryInst *inst); 46 | void registerResult(BasicBlock *block, BinaryInst *inst); 47 | 48 | Instruction *findAddResult(BasicBlock *block, Instruction *left, Instruction *right) const; 49 | Instruction *findSubResult(BasicBlock *block, Instruction *left, Instruction *right) const; 50 | Instruction *findMulResult(BasicBlock *block, Instruction *left, Instruction *right) const; 51 | Instruction *findDivResult(BasicBlock *block, Instruction *left, Instruction *right) const; 52 | Instruction *findModResult(BasicBlock *block, Instruction *left, Instruction *right) const; 53 | Instruction *findShlResult(BasicBlock *block, Instruction *left, Instruction *right) const; 54 | Instruction *findShrResult(BasicBlock *block, Instruction *left, Instruction *right) const; 55 | Instruction *findOrResult(BasicBlock *block, Instruction *left, Instruction *right) const; 56 | Instruction *findAndResult(BasicBlock *block, Instruction *left, Instruction *right) const; 57 | Instruction *findNorResult(BasicBlock *block, Instruction *left, Instruction *right) const; 58 | Instruction *findXorResult(BasicBlock *block, Instruction *left, Instruction *right) const; 59 | Instruction *findSeqResult(BasicBlock *block, Instruction *left, Instruction *right) const; 60 | Instruction *findSltResult(BasicBlock *block, Instruction *left, Instruction *right) const; 61 | Instruction *findSleResult(BasicBlock *block, Instruction *left, Instruction *right) const; 62 | 63 | std::list > removed; 64 | 65 | public: 66 | InstRewriter(IR *ir) 67 | : Optimizer(ir) 68 | { 69 | for (auto &func_iter : ir->function_table) { 70 | rewriteFunction(func_iter.second.get()); 71 | } 72 | } 73 | }; 74 | 75 | } 76 | 77 | #endif //CYAN_INST_REWRITER_HPP 78 | -------------------------------------------------------------------------------- /lib/instruction.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Clarkok on 16/5/3. 3 | // 4 | 5 | #include "ir.hpp" 6 | #include "instruction.hpp" 7 | #include "codegen.hpp" 8 | 9 | using namespace cyan; 10 | 11 | namespace std { 12 | 13 | std::string 14 | to_string(std::string s) 15 | { return s; } 16 | 17 | } 18 | 19 | #define inst_header(asm_name) \ 20 | ("(" + getType()->to_string() + ")\t" asm_name "\t") 21 | 22 | #define value_header(asm_name) \ 23 | (getName() + " =\t" + inst_header(asm_name)) 24 | 25 | #define imm_inst_to_string(Inst, asm_name) \ 26 | std::string \ 27 | Inst::to_string() const \ 28 | { return value_header(asm_name) + std::to_string(value); } 29 | 30 | imm_inst_to_string(SignedImmInst, "sli") 31 | imm_inst_to_string(UnsignedImmInst, "uli") 32 | imm_inst_to_string(GlobalInst, "glob") 33 | imm_inst_to_string(ArgInst, "arg") 34 | 35 | #undef imm_inst_to_string 36 | 37 | #define binary_inst_to_string(Inst, asm_name) \ 38 | std::string \ 39 | Inst::to_string() const \ 40 | { return value_header(asm_name) + left->getName() + ",\t" + right->getName(); } 41 | 42 | binary_inst_to_string(AddInst, "add") 43 | binary_inst_to_string(SubInst, "sub") 44 | binary_inst_to_string(MulInst, "mul") 45 | binary_inst_to_string(DivInst, "div") 46 | binary_inst_to_string(ModInst, "mod") 47 | 48 | binary_inst_to_string(ShlInst, "shl") 49 | binary_inst_to_string(ShrInst, "shr") 50 | binary_inst_to_string(OrInst, "or") 51 | binary_inst_to_string(AndInst, "and") 52 | binary_inst_to_string(NorInst, "nor") 53 | binary_inst_to_string(XorInst, "xor") 54 | 55 | binary_inst_to_string(SeqInst, "seq") 56 | binary_inst_to_string(SltInst, "slt") 57 | binary_inst_to_string(SleInst, "sle") 58 | 59 | #undef binary_inst_to_string 60 | 61 | std::string 62 | LoadInst::to_string() const 63 | { return value_header("load") + address->getName(); } 64 | 65 | std::string 66 | StoreInst::to_string() const 67 | { return "\t" + inst_header("store") + address->getName() + ",\t" + value->getName(); } 68 | 69 | std::string 70 | AllocaInst::to_string() const 71 | { return value_header("alloc") + space->getName(); } 72 | 73 | std::string 74 | CallInst::to_string() const 75 | { 76 | std::string ret(value_header("call") + function->getName() + "("); 77 | if (arguments.size()) { 78 | for (auto iter = cbegin(); iter != cend(); ++iter) { 79 | ret += (*iter)->getName() + ", "; 80 | } 81 | 82 | ret.pop_back(); 83 | ret.pop_back(); 84 | } 85 | ret += ")"; 86 | return ret; 87 | } 88 | 89 | std::string 90 | RetInst::to_string() const 91 | { return "\t" + inst_header("ret") + (return_value ? return_value->getName() : ""); } 92 | 93 | std::string 94 | NewInst::to_string() const 95 | { return value_header("new") + space->getName(); } 96 | 97 | std::string 98 | DeleteInst::to_string() const 99 | { return "\t" + inst_header("delete") + target->getName(); } 100 | 101 | std::string 102 | PhiInst::to_string() const 103 | { 104 | std::string ret(value_header("phi")); 105 | 106 | if (branches_size()) { 107 | for (auto iter = cbegin(); iter != cend(); ++iter) { 108 | ret += "[" + iter->preceder->getName() + "," + iter->value->getName() + "], "; 109 | } 110 | ret.pop_back(); 111 | ret.pop_back(); 112 | } 113 | 114 | return ret; 115 | } 116 | 117 | #define define_codegen(type) \ 118 | void \ 119 | type::codegen(CodeGen *code_gen) \ 120 | { code_gen->gen(this); } 121 | 122 | inst_foreach(define_codegen) 123 | -------------------------------------------------------------------------------- /lib/ir.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Clarkok on 16/5/3. 3 | // 4 | 5 | #include "ir.hpp" 6 | 7 | using namespace cyan; 8 | 9 | std::ostream & 10 | BasicBlock::output(std::ostream &os) const 11 | { 12 | os << getName() << ":" << std::endl; 13 | os << "{\n" 14 | << "\tdominator: " << (dominator ? dominator->getName() : "(null)") << ",\n" 15 | << "\tdepth: " << depth << ",\n" 16 | << "\tloop_header: " << (loop_header ? loop_header->getName() : "(null)") << ",\n" 17 | << "\tpreceders: ["; 18 | for (auto &preceder : preceders) { 19 | os << preceder->getName() << ","; 20 | } 21 | os << "]\n}\n"; 22 | 23 | for (auto &inst : inst_list) { 24 | os << "\t" << inst->to_string() << std::endl; 25 | } 26 | 27 | if (condition) { 28 | os << "\t\t\tbr\t" << condition->getName() 29 | << "\t" << then_block->getName() 30 | << ",\t" << else_block->getName() 31 | << std::endl; 32 | } 33 | else if (then_block) { 34 | os << "\t\t\tj\t" << then_block->getName() << std::endl; 35 | } 36 | 37 | return os; 38 | } 39 | 40 | std::ostream & 41 | Function::output(std::ostream &os) const 42 | { 43 | os << getName() << " {"; 44 | 45 | for (auto &block : block_list) { 46 | block->output(os << std::endl); 47 | } 48 | 49 | os << "} // " << getName() << std::endl; 50 | 51 | return os; 52 | } 53 | 54 | std::ostream & 55 | IR::output(std::ostream &os) const 56 | { 57 | for (auto &global : global_defines) { 58 | os << "global " << global.first << "\t: " << global.second->to_string() << std::endl; 59 | } 60 | 61 | for (auto &string_pair : string_pool) { 62 | os << "string " << string_pair.second << "\t: \"" << string_pair.first << "\"" << std::endl; 63 | } 64 | 65 | os << std::endl; 66 | 67 | for (auto &func : function_table) { 68 | func.second->output(os) << std::endl; 69 | } 70 | 71 | return os; 72 | } 73 | -------------------------------------------------------------------------------- /lib/ir.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Clarkok on 16/5/3. 3 | // 4 | 5 | #ifndef CYAN_IR_HPP 6 | #define CYAN_IR_HPP 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "instruction.hpp" 14 | #include "type.hpp" 15 | 16 | namespace cyan { 17 | 18 | struct BasicBlock 19 | { 20 | std::list > inst_list; 21 | std::string name; 22 | Instruction *condition; 23 | BasicBlock *then_block; 24 | BasicBlock *else_block; 25 | 26 | BasicBlock *dominator; 27 | std::set preceders; 28 | BasicBlock *loop_header; 29 | int depth; 30 | 31 | BasicBlock(std::string name, int depth = 0) 32 | : name(name), 33 | condition(nullptr), 34 | then_block(nullptr), 35 | else_block(nullptr), 36 | dominator(nullptr), 37 | loop_header(nullptr), 38 | depth(depth) 39 | { } 40 | 41 | ~BasicBlock() = default; 42 | 43 | inline auto 44 | begin() -> decltype(inst_list.begin()) 45 | { return inst_list.begin(); } 46 | 47 | inline auto 48 | end() -> decltype(inst_list.end()) 49 | { return inst_list.end(); } 50 | 51 | inline auto 52 | cbegin() const -> decltype(inst_list.cbegin()) 53 | { return inst_list.cbegin(); } 54 | 55 | inline auto 56 | cend() const -> decltype(inst_list.cend()) 57 | { return inst_list.cend(); } 58 | 59 | inline auto 60 | size() const -> decltype(inst_list.size()) 61 | { return inst_list.size(); } 62 | 63 | inline BasicBlock * 64 | getDominator() const 65 | { return dominator; } 66 | 67 | inline Instruction * 68 | getCondition() const 69 | { return condition; } 70 | 71 | inline BasicBlock * 72 | getThenBlock() const 73 | { return then_block; } 74 | 75 | inline BasicBlock * 76 | getElseBlock() const 77 | { return else_block; } 78 | 79 | inline std::string 80 | getName() const 81 | { return name; } 82 | 83 | inline int 84 | getDepth() const 85 | { return depth; } 86 | 87 | inline BasicBlock * 88 | split(std::list >::iterator iterator, std::string name = "") 89 | { 90 | BasicBlock *new_bb = new BasicBlock(name.size() ? name : getName() + ".split", depth); 91 | 92 | for ( 93 | auto iter = iterator; 94 | iter != inst_list.end(); 95 | ++iter 96 | ) { 97 | (*iter)->setOwnerBlock(new_bb); 98 | } 99 | 100 | new_bb->inst_list.splice( 101 | new_bb->inst_list.begin(), 102 | inst_list, 103 | std::next(iterator), 104 | inst_list.cend() 105 | ); 106 | 107 | new_bb->condition = condition; 108 | new_bb->then_block = then_block; 109 | new_bb->else_block = else_block; 110 | 111 | condition = nullptr; 112 | then_block = new_bb; 113 | else_block = nullptr; 114 | 115 | return new_bb; 116 | } 117 | 118 | inline void 119 | append(BasicBlock *other) 120 | { 121 | for (auto &inst_iter : other->inst_list) { 122 | inst_iter->setOwnerBlock(this); 123 | } 124 | inst_list.splice(inst_list.end(), other->inst_list); 125 | condition = other->condition; 126 | then_block = other->then_block; 127 | else_block = other->else_block; 128 | } 129 | 130 | inline bool 131 | isDominatedBy(BasicBlock *block) 132 | { 133 | auto ptr = dominator; 134 | while (ptr) { 135 | if (ptr == block) { 136 | return true; 137 | } 138 | ptr = ptr->dominator; 139 | } 140 | return false; 141 | } 142 | 143 | std::ostream &output(std::ostream &os) const; 144 | }; 145 | 146 | struct Function 147 | { 148 | std::list > block_list; 149 | std::string name; 150 | FunctionType *prototype; 151 | int local_temp_counter; 152 | std::set local_names; 153 | 154 | Function(std::string name, FunctionType *prototype) 155 | : name(name), prototype(prototype), local_temp_counter(0) 156 | { } 157 | 158 | ~Function() = default; 159 | 160 | inline auto 161 | begin() -> decltype(block_list.begin()) 162 | { return block_list.begin(); } 163 | 164 | inline auto 165 | end() -> decltype(block_list.end()) 166 | { return block_list.end(); } 167 | 168 | inline auto 169 | begin() const -> decltype(block_list.begin()) 170 | { return block_list.begin(); } 171 | 172 | inline auto 173 | end() const -> decltype(block_list.end()) 174 | { return block_list.end(); } 175 | 176 | inline auto 177 | cbegin() const -> decltype(block_list.cbegin()) 178 | { return block_list.cbegin(); } 179 | 180 | inline auto 181 | cend() const -> decltype(block_list.cend()) 182 | { return block_list.cend(); } 183 | 184 | inline auto 185 | size() const -> decltype(block_list.size()) 186 | { return block_list.size(); } 187 | 188 | inline std::string 189 | getName() const 190 | { return name; } 191 | 192 | inline FunctionType * 193 | getPrototype() const 194 | { return prototype; } 195 | 196 | inline int 197 | countLocalTemp() 198 | { return local_temp_counter++; } 199 | 200 | inline std::string 201 | makeName(std::string variable_name) 202 | { 203 | if (local_names.find(variable_name) != local_names.end()) { 204 | variable_name += "_" + std::to_string(countLocalTemp()); 205 | } 206 | local_names.insert(variable_name); 207 | return variable_name; 208 | } 209 | 210 | inline size_t 211 | inst_size() const 212 | { 213 | size_t ret = 0; 214 | for (auto &block : *this) { 215 | ret += block->size(); 216 | } 217 | return ret; 218 | } 219 | 220 | std::ostream &output(std::ostream &os) const; 221 | }; 222 | 223 | struct IR 224 | { 225 | std::map > function_table; 226 | std::map global_defines; 227 | std::map string_pool; 228 | std::unique_ptr type_pool; 229 | 230 | IR() = default; 231 | ~IR() = default; 232 | 233 | std::ostream &output(std::ostream &os) const; 234 | }; 235 | 236 | } 237 | 238 | #endif //CYAN_IR_HPP 239 | -------------------------------------------------------------------------------- /lib/ir_builder.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Clarkok on 16/5/3. 3 | // 4 | 5 | #include 6 | 7 | #include "ir.hpp" 8 | #include "ir_builder.hpp" 9 | 10 | using namespace cyan; 11 | 12 | Instruction * 13 | IRBuilder::BlockBuilder::SignedImmInst(SignedIntegerType *type, intptr_t value, std::string name) 14 | { 15 | assert(!productEnded()); 16 | Instruction *ret; 17 | product->inst_list.emplace_back(ret = new class SignedImmInst(type, value, product, tempName(name))); 18 | return ret; 19 | } 20 | 21 | Instruction * 22 | IRBuilder::BlockBuilder::UnsignedImmInst(UnsignedIntegerType *type, uintptr_t value, std::string name) 23 | { 24 | assert(!productEnded()); 25 | Instruction *ret; 26 | product->inst_list.emplace_back(ret = new class UnsignedImmInst(type, value, product, tempName(name))); 27 | return ret; 28 | } 29 | 30 | Instruction * 31 | IRBuilder::BlockBuilder::GlobalInst(PointerType *type, std::string value, std::string name) 32 | { 33 | assert(!productEnded()); 34 | Instruction *ret; 35 | product->inst_list.emplace_back(ret = new class GlobalInst(type, value, product, tempName(name))); 36 | return ret; 37 | } 38 | 39 | Instruction * 40 | IRBuilder::BlockBuilder::ArgInst(PointerType *type, intptr_t value, std::string name) 41 | { 42 | assert(!productEnded()); 43 | Instruction *ret; 44 | product->inst_list.emplace_back(ret = new class ArgInst(type, value, product, tempName(name))); 45 | return ret; 46 | } 47 | 48 | Instruction * 49 | IRBuilder::BlockBuilder::AddInst(Type *type, Instruction *left, Instruction *right, std::string name) 50 | { 51 | assert(!productEnded()); 52 | Instruction *ret; 53 | product->inst_list.emplace_back(ret = new class AddInst(type, left, right, product, tempName(name))); 54 | left->reference(); 55 | right->reference(); 56 | return ret; 57 | } 58 | 59 | Instruction * 60 | IRBuilder::BlockBuilder::SubInst(Type *type, Instruction *left, Instruction *right, std::string name) 61 | { 62 | assert(!productEnded()); 63 | Instruction *ret; 64 | product->inst_list.emplace_back(ret = new class SubInst(type, left, right, product, tempName(name))); 65 | left->reference(); 66 | right->reference(); 67 | return ret; 68 | } 69 | 70 | Instruction * 71 | IRBuilder::BlockBuilder::MulInst(Type *type, Instruction *left, Instruction *right, std::string name) 72 | { 73 | assert(!productEnded()); 74 | Instruction *ret; 75 | product->inst_list.emplace_back(ret = new class MulInst(type, left, right, product, tempName(name))); 76 | left->reference(); 77 | right->reference(); 78 | return ret; 79 | } 80 | 81 | Instruction * 82 | IRBuilder::BlockBuilder::DivInst(Type *type, Instruction *left, Instruction *right, std::string name) 83 | { 84 | assert(!productEnded()); 85 | Instruction *ret; 86 | product->inst_list.emplace_back(ret = new class DivInst(type, left, right, product, tempName(name))); 87 | left->reference(); 88 | right->reference(); 89 | return ret; 90 | } 91 | 92 | Instruction * 93 | IRBuilder::BlockBuilder::ModInst(Type *type, Instruction *left, Instruction *right, std::string name) 94 | { 95 | assert(!productEnded()); 96 | Instruction *ret; 97 | product->inst_list.emplace_back(ret = new class ModInst(type, left, right, product, tempName(name))); 98 | left->reference(); 99 | right->reference(); 100 | return ret; 101 | } 102 | 103 | Instruction * 104 | IRBuilder::BlockBuilder::ShlInst(Type *type, Instruction *left, Instruction *right, std::string name) 105 | { 106 | assert(!productEnded()); 107 | Instruction *ret; 108 | product->inst_list.emplace_back(ret = new class ShlInst(type, left, right, product, tempName(name))); 109 | left->reference(); 110 | right->reference(); 111 | return ret; 112 | } 113 | 114 | Instruction * 115 | IRBuilder::BlockBuilder::ShrInst(Type *type, Instruction *left, Instruction *right, std::string name) 116 | { 117 | assert(!productEnded()); 118 | Instruction *ret; 119 | product->inst_list.emplace_back(ret = new class ShrInst(type, left, right, product, tempName(name))); 120 | left->reference(); 121 | right->reference(); 122 | return ret; 123 | } 124 | 125 | Instruction * 126 | IRBuilder::BlockBuilder::OrInst(Type *type, Instruction *left, Instruction *right, std::string name) 127 | { 128 | assert(!productEnded()); 129 | Instruction *ret; 130 | product->inst_list.emplace_back(ret = new class OrInst(type, left, right, product, tempName(name))); 131 | left->reference(); 132 | right->reference(); 133 | return ret; 134 | } 135 | 136 | Instruction * 137 | IRBuilder::BlockBuilder::AndInst(Type *type, Instruction *left, Instruction *right, std::string name) 138 | { 139 | assert(!productEnded()); 140 | Instruction *ret; 141 | product->inst_list.emplace_back(ret = new class AndInst(type, left, right, product, tempName(name))); 142 | left->reference(); 143 | right->reference(); 144 | return ret; 145 | } 146 | 147 | Instruction * 148 | IRBuilder::BlockBuilder::NorInst(Type *type, Instruction *left, Instruction *right, std::string name) 149 | { 150 | assert(!productEnded()); 151 | Instruction *ret; 152 | product->inst_list.emplace_back(ret = new class NorInst(type, left, right, product, tempName(name))); 153 | left->reference(); 154 | right->reference(); 155 | return ret; 156 | } 157 | 158 | Instruction * 159 | IRBuilder::BlockBuilder::XorInst(Type *type, Instruction *left, Instruction *right, std::string name) 160 | { 161 | assert(!productEnded()); 162 | Instruction *ret; 163 | product->inst_list.emplace_back(ret = new class XorInst(type, left, right, product, tempName(name))); 164 | left->reference(); 165 | right->reference(); 166 | return ret; 167 | } 168 | 169 | Instruction * 170 | IRBuilder::BlockBuilder::SeqInst(Type *type, Instruction *left, Instruction *right, std::string name) 171 | { 172 | assert(!productEnded()); 173 | Instruction *ret; 174 | product->inst_list.emplace_back(ret = new class SeqInst(type, left, right, product, tempName(name))); 175 | left->reference(); 176 | right->reference(); 177 | return ret; 178 | } 179 | 180 | Instruction * 181 | IRBuilder::BlockBuilder::SltInst(Type *type, Instruction *left, Instruction *right, std::string name) 182 | { 183 | assert(!productEnded()); 184 | Instruction *ret; 185 | product->inst_list.emplace_back(ret = new class SltInst(type, left, right, product, tempName(name))); 186 | left->reference(); 187 | right->reference(); 188 | return ret; 189 | } 190 | 191 | Instruction * 192 | IRBuilder::BlockBuilder::SleInst(Type *type, Instruction *left, Instruction *right, std::string name) 193 | { 194 | assert(!productEnded()); 195 | Instruction *ret; 196 | product->inst_list.emplace_back(ret = new class SleInst(type, left, right, product, tempName(name))); 197 | left->reference(); 198 | right->reference(); 199 | return ret; 200 | } 201 | 202 | Instruction * 203 | IRBuilder::BlockBuilder::LoadInst(Type *type, Instruction *address, std::string name) 204 | { 205 | assert(!productEnded()); 206 | Instruction *ret; 207 | product->inst_list.emplace_back(ret = new class LoadInst(type, address, product, tempName(name))); 208 | address->reference(); 209 | return ret; 210 | } 211 | 212 | Instruction * 213 | IRBuilder::BlockBuilder::StoreInst(Type *type, Instruction *address, Instruction *value, std::string name) 214 | { 215 | assert(!productEnded()); 216 | Instruction *ret; 217 | product->inst_list.emplace_back(ret = new class StoreInst(type, address, value, product, tempName(name))); 218 | address->reference(); 219 | value->reference(); 220 | return ret; 221 | } 222 | 223 | Instruction * 224 | IRBuilder::BlockBuilder::AllocaInst(Type *type, Instruction *space, std::string name) 225 | { 226 | assert(!productEnded()); 227 | Instruction *ret; 228 | product->inst_list.emplace_back(ret = new class AllocaInst(type, space, product, tempName(name))); 229 | space->reference(); 230 | return ret; 231 | } 232 | 233 | Instruction * 234 | IRBuilder::BlockBuilder::RetInst(Type *type, Instruction *return_value) 235 | { 236 | assert(!productEnded()); 237 | Instruction *ret; 238 | product->inst_list.emplace_back(ret = new class RetInst(type, product, return_value)); 239 | if (return_value) { 240 | return_value->reference(); 241 | } 242 | return ret; 243 | } 244 | 245 | Instruction * 246 | IRBuilder::BlockBuilder::NewInst(Type *type, Instruction *space, std::string name) 247 | { 248 | assert(!productEnded()); 249 | Instruction *ret; 250 | product->inst_list.emplace_back(ret = new class NewInst(type, product, space, tempName(name))); 251 | space->reference(); 252 | return ret; 253 | } 254 | 255 | Instruction * 256 | IRBuilder::BlockBuilder::DeleteInst(Type *type, Instruction *target, std::string name) 257 | { 258 | assert(!productEnded()); 259 | Instruction *ret; 260 | product->inst_list.emplace_back(ret = new class DeleteInst(type, product, target, tempName(name))); 261 | target->reference(); 262 | return ret; 263 | } 264 | 265 | void 266 | IRBuilder::BlockBuilder::JumpInst(BasicBlock *block) 267 | { 268 | assert(!productEnded()); 269 | product->then_block = block; 270 | } 271 | 272 | void 273 | IRBuilder::BlockBuilder::BrInst(Instruction *condition, BasicBlock *then_block, BasicBlock *else_block) 274 | { 275 | assert(!productEnded()); 276 | product->condition = condition; 277 | product->then_block = then_block; 278 | product->else_block = else_block; 279 | condition->reference(); 280 | } 281 | 282 | Instruction * 283 | IRBuilder::BlockBuilder::PhiInst(class PhiInst *inst) 284 | { 285 | assert(!productEnded()); 286 | 287 | for (auto &branch : *inst) { 288 | branch.value->reference(); 289 | } 290 | 291 | product->inst_list.emplace_back(inst); 292 | return inst; 293 | } 294 | 295 | Instruction * 296 | IRBuilder::BlockBuilder::PhiBuilder::commit() 297 | { return owner->PhiInst(builder.release()); } 298 | 299 | Instruction * 300 | IRBuilder::BlockBuilder::CallInst(class CallInst *inst) 301 | { 302 | assert(!productEnded()); 303 | 304 | for (auto &argument : *inst) { 305 | argument->reference(); 306 | } 307 | 308 | product->inst_list.emplace_back(inst); 309 | return inst; 310 | } 311 | 312 | Instruction * 313 | IRBuilder::BlockBuilder::CallBuilder::commit() 314 | { return owner->CallInst(builder.release()); } 315 | 316 | std::unique_ptr 317 | IRBuilder::FunctionBuilder::newBasicBlock(size_t depth, std::string name) 318 | { 319 | product->block_list.emplace_back( 320 | std::unique_ptr(new BasicBlock(tempName(name), static_cast(depth))) 321 | ); 322 | return std::unique_ptr(new BlockBuilder(owner, this, product->block_list.back().get())); 323 | } 324 | 325 | std::unique_ptr 326 | IRBuilder::newFunction(std::string name, FunctionType *prototype) 327 | { 328 | Function *func; 329 | product->function_table.emplace(name, std::unique_ptr(func = new Function(name, prototype))); 330 | return std::unique_ptr(new FunctionBuilder(this, func)); 331 | } 332 | 333 | std::unique_ptr 334 | IRBuilder::findFunction(std::string name) 335 | { 336 | assert(product->function_table.find(name) != product->function_table.end()); 337 | return std::unique_ptr( 338 | new FunctionBuilder(this, product->function_table[name].get()) 339 | ); 340 | } 341 | -------------------------------------------------------------------------------- /lib/ir_builder.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Clarkok on 16/5/3. 3 | // 4 | 5 | #ifndef CYAN_IR_BUILDER_HPP 6 | #define CYAN_IR_BUILDER_HPP 7 | 8 | #include "ir.hpp" 9 | 10 | namespace cyan { 11 | 12 | class IRBuilder 13 | { 14 | std::unique_ptr product; 15 | 16 | public: 17 | class FunctionBuilder; 18 | 19 | class BlockBuilder 20 | { 21 | IRBuilder *owner; 22 | FunctionBuilder *function; 23 | BasicBlock *product; 24 | 25 | BlockBuilder(IRBuilder *owner, FunctionBuilder *function, BasicBlock *basic_block) 26 | : owner(owner), function(function), product(basic_block) 27 | { } 28 | public: 29 | class PhiBuilder 30 | { 31 | BlockBuilder *owner; 32 | PhiInst::Builder builder; 33 | 34 | PhiBuilder(BlockBuilder *owner, Type *type, std::string name) 35 | : owner(owner), builder(type, owner->product, name) 36 | { } 37 | 38 | public: 39 | PhiBuilder(PhiBuilder &&builder) 40 | : owner(builder.owner), builder(std::move(builder.builder)) 41 | { } 42 | 43 | ~PhiBuilder() = default; 44 | 45 | Instruction *commit(); 46 | 47 | inline PhiBuilder & 48 | addBranch(Instruction *value, BasicBlock *preceder) 49 | { 50 | builder.addBranch(value, preceder); 51 | return *this; 52 | } 53 | 54 | friend class BlockBuilder; 55 | }; 56 | 57 | class CallBuilder 58 | { 59 | BlockBuilder *owner; 60 | CallInst::Builder builder; 61 | 62 | CallBuilder(BlockBuilder *owner, Type *type, Instruction *function, std::string name) 63 | : owner(owner), builder(type, function, owner->product, name) 64 | { } 65 | public: 66 | CallBuilder(CallBuilder &&builder) 67 | : owner(builder.owner), builder(std::move(builder.builder)) 68 | { } 69 | 70 | ~CallBuilder() = default; 71 | 72 | Instruction *commit(); 73 | 74 | inline CallBuilder & 75 | addArgument(Instruction *value) 76 | { 77 | builder.addArgument(value); 78 | return *this; 79 | } 80 | 81 | friend class BlockBuilder; 82 | }; 83 | 84 | BlockBuilder(BlockBuilder &&builder) 85 | : owner(builder.owner), product(builder.product) 86 | { } 87 | 88 | ~BlockBuilder() = default; 89 | 90 | inline std::string 91 | tempName(std::string name) 92 | { 93 | return name.length() 94 | ? function->product->makeName(name) 95 | : "_" + std::to_string(function->product->countLocalTemp()); 96 | } 97 | 98 | inline BasicBlock * 99 | get() const 100 | { return product; } 101 | 102 | inline bool 103 | productEnded() const 104 | { return product->then_block || product->else_block; } 105 | 106 | inline PhiBuilder 107 | newPhiBuilder(Type *type, std::string name = "") 108 | { return PhiBuilder(this, type, tempName(name)); } 109 | 110 | inline CallBuilder 111 | newCallBuilder(Type *type, Instruction *function, std::string name = "") 112 | { return CallBuilder(this, type, function, tempName(name)); } 113 | 114 | Instruction *SignedImmInst(SignedIntegerType *type, intptr_t value, std::string name = ""); 115 | Instruction *UnsignedImmInst(UnsignedIntegerType *type, uintptr_t value, std::string name = ""); 116 | Instruction *GlobalInst(PointerType *type, std::string value, std::string name = ""); 117 | Instruction *ArgInst(PointerType *type, intptr_t value, std::string name = ""); 118 | 119 | Instruction *AddInst(Type *type, Instruction *left, Instruction *right, std::string name = ""); 120 | Instruction *SubInst(Type *type, Instruction *left, Instruction *right, std::string name = ""); 121 | Instruction *MulInst(Type *type, Instruction *left, Instruction *right, std::string name = ""); 122 | Instruction *DivInst(Type *type, Instruction *left, Instruction *right, std::string name = ""); 123 | Instruction *ModInst(Type *type, Instruction *left, Instruction *right, std::string name = ""); 124 | 125 | Instruction *ShlInst(Type *type, Instruction *left, Instruction *right, std::string name = ""); 126 | Instruction *ShrInst(Type *type, Instruction *left, Instruction *right, std::string name = ""); 127 | Instruction *OrInst(Type *type, Instruction *left, Instruction *right, std::string name = ""); 128 | Instruction *AndInst(Type *type, Instruction *left, Instruction *right, std::string name = ""); 129 | Instruction *NorInst(Type *type, Instruction *left, Instruction *right, std::string name = ""); 130 | Instruction *XorInst(Type *type, Instruction *left, Instruction *right, std::string name = ""); 131 | 132 | Instruction *SeqInst(Type *type, Instruction *left, Instruction *right, std::string name = ""); 133 | Instruction *SltInst(Type *type, Instruction *left, Instruction *right, std::string name = ""); 134 | Instruction *SleInst(Type *type, Instruction *left, Instruction *right, std::string name = ""); 135 | 136 | Instruction *LoadInst(Type *type, Instruction *address, std::string name = ""); 137 | Instruction *StoreInst(Type *type, Instruction *address, Instruction *value, std::string name = ""); 138 | Instruction *AllocaInst(Type *type, Instruction *space, std::string name = ""); 139 | 140 | Instruction *RetInst(Type *type, Instruction *return_value); 141 | 142 | Instruction *NewInst(Type *type, Instruction *space, std::string name = ""); 143 | Instruction *DeleteInst(Type *type, Instruction *target, std::string name = ""); 144 | 145 | void JumpInst(BasicBlock *block); 146 | void BrInst(Instruction *condition, BasicBlock *then_block, BasicBlock *else_block); 147 | 148 | friend class FunctionBuilder; 149 | protected: 150 | Instruction *CallInst(class CallInst *inst); 151 | Instruction *PhiInst(class PhiInst *inst); 152 | }; 153 | 154 | class FunctionBuilder 155 | { 156 | IRBuilder *owner; 157 | Function *product; 158 | 159 | FunctionBuilder(IRBuilder *owner, Function *function) 160 | : owner(owner), product(function) 161 | { } 162 | public: 163 | FunctionBuilder(FunctionBuilder &&builder) 164 | : owner(builder.owner), product(builder.product) 165 | { } 166 | 167 | ~FunctionBuilder() = default; 168 | 169 | inline Function * 170 | get() const 171 | { return product; } 172 | 173 | inline std::string 174 | tempName(std::string name) 175 | { return name.length() ? name : "BB_" + std::to_string(product->countLocalTemp()); } 176 | 177 | std::unique_ptr newBasicBlock(size_t depth, std::string name = ""); 178 | 179 | friend class IRBuilder; 180 | }; 181 | 182 | IRBuilder() 183 | : product(new IR()) 184 | { } 185 | 186 | std::unique_ptr newFunction(std::string name, FunctionType *prototype); 187 | std::unique_ptr findFunction(std::string name); 188 | 189 | inline IR * 190 | get() const 191 | { return product.get(); } 192 | 193 | inline IR * 194 | release(TypePool *type_pool) 195 | { 196 | product->type_pool.reset(type_pool); 197 | return product.release(); 198 | } 199 | 200 | inline void 201 | defineGlobal(std::string name, Type *type) 202 | { product->global_defines.emplace(name, type); } 203 | }; 204 | 205 | } 206 | 207 | #endif //CYAN_IR_BUILDER_HPP 208 | -------------------------------------------------------------------------------- /lib/libcyan.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CYAN_LIBCYAN_HPP 2 | #define CYAN_LIBCYAN_HPP 3 | 4 | #include "cyan.hpp" 5 | #include "parse.hpp" 6 | #include "optimizer_group.hpp" 7 | 8 | #endif //CYAN_LIBCYAN_HPP 9 | -------------------------------------------------------------------------------- /lib/location.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Clarkok on 16/4/29. 3 | // 4 | 5 | #ifndef CYAN_LOCATION_HPP 6 | #define CYAN_LOCATION_HPP 7 | 8 | #include 9 | 10 | namespace cyan { 11 | 12 | struct Location 13 | { 14 | std::string filename; 15 | int line = 0; 16 | int column = 0; 17 | 18 | Location(std::string filename) 19 | : filename(filename) 20 | { } 21 | }; 22 | 23 | } 24 | 25 | namespace std { 26 | 27 | static inline std::string 28 | to_string(cyan::Location location) 29 | { 30 | return location.filename + ":" + std::to_string(location.line + 1) + 31 | " " + std::to_string(location.column + 1); 32 | } 33 | 34 | } 35 | 36 | #endif //CYAN_LOCATION_HPP 37 | -------------------------------------------------------------------------------- /lib/loop_marker.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/17/16. 3 | // 4 | 5 | #include "loop_marker.hpp" 6 | 7 | using namespace cyan; 8 | 9 | bool 10 | LoopMarker::isDominating(BasicBlock *child, BasicBlock *parent) 11 | { 12 | while (child) { 13 | if (child == parent) return true; 14 | child = child->dominator; 15 | } 16 | return false; 17 | } 18 | 19 | void 20 | LoopMarker::scan(BasicBlock *block) 21 | { 22 | if (scanned.find(block) != scanned.end()) return; 23 | scanned.emplace(block); 24 | 25 | if (block->then_block) { 26 | if (isDominating(block, block->then_block)) { 27 | marked.clear(); 28 | mark(block, block->then_block); 29 | } 30 | else { 31 | scan(block->then_block); 32 | } 33 | } 34 | 35 | if (block->condition) { 36 | if (block->else_block) { 37 | if (isDominating(block, block->else_block)) { 38 | marked.clear(); 39 | mark(block, block->else_block); 40 | } 41 | else { 42 | scan(block->else_block); 43 | } 44 | } 45 | } 46 | } 47 | 48 | void 49 | LoopMarker::mark(BasicBlock *block, BasicBlock *loop_header) 50 | { 51 | if (marked.find(block) != marked.end()) { return; } 52 | marked.emplace(block); 53 | 54 | if (!block->loop_header) { 55 | block->loop_header = loop_header; 56 | } 57 | block->depth ++; 58 | if (block == loop_header) { return; } 59 | 60 | for (auto &preceder : block->preceders) { 61 | mark(preceder, loop_header); 62 | } 63 | } 64 | 65 | void 66 | LoopMarker::outputResult(std::ostream &os) const 67 | { 68 | for (auto &func_iter : ir->function_table) { 69 | os << func_iter.first << ":\n"; 70 | for (auto &block_ptr : func_iter.second->block_list) { 71 | os << "\t" << block_ptr->getName() << ":\n"; 72 | os << "\t loop_header: " << ( 73 | block_ptr->loop_header 74 | ? block_ptr->loop_header->getName() 75 | : "(null)" 76 | )<< "\n"; 77 | os << "\t depth: " << block_ptr->depth << "\n"; 78 | os << std::endl; 79 | } 80 | os << std::endl; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /lib/loop_marker.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/17/16. 3 | // 4 | 5 | #ifndef CYAN_LOOP_MARKER_HPP 6 | #define CYAN_LOOP_MARKER_HPP 7 | 8 | #include 9 | #include 10 | 11 | #include "optimizer.hpp" 12 | 13 | namespace cyan { 14 | 15 | class LoopMarker : public Optimizer 16 | { 17 | std::set scanned; 18 | std::set marked; 19 | 20 | bool isDominating(BasicBlock *child, BasicBlock *parent); 21 | void scan(BasicBlock *block); 22 | void mark(BasicBlock *block, BasicBlock *loop_header); 23 | 24 | public: 25 | LoopMarker(IR *ir) 26 | : Optimizer(ir) 27 | { 28 | for (auto &func_iter : ir->function_table) { 29 | if (!func_iter.second->block_list.size()) { continue; } 30 | scanned.clear(); 31 | 32 | for (auto &block_ptr : func_iter.second->block_list) { 33 | block_ptr->loop_header = nullptr; 34 | block_ptr->depth = 0; 35 | } 36 | scan(func_iter.second->block_list.front().get()); 37 | } 38 | } 39 | 40 | void outputResult(std::ostream &os) const; 41 | }; 42 | 43 | } 44 | 45 | #endif //CYAN_LOOP_MARKER_HPP 46 | -------------------------------------------------------------------------------- /lib/mem2reg.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/16/16. 3 | // 4 | 5 | #include 6 | 7 | #include "mem2reg.hpp" 8 | 9 | using namespace cyan; 10 | 11 | std::stringstream Mem2Reg::trash_out; 12 | 13 | void 14 | Mem2Reg::allocaForArgument(Function *func) 15 | { 16 | ir->output(debug_out); 17 | argument_map.clear(); 18 | value_map.clear(); 19 | 20 | std::list > buffer; 21 | 22 | auto entry_block = func->block_list.begin()->get(); 23 | for (auto &block_ptr : func->block_list) { 24 | for ( 25 | auto inst_iter = block_ptr->inst_list.begin(); 26 | inst_iter != block_ptr->inst_list.end(); 27 | ) { 28 | if ((*inst_iter)->is()) { 29 | auto arg_inst = (*inst_iter)->to(); 30 | Instruction *alloc_inst = nullptr; 31 | if (argument_map.find(arg_inst->getValue()) == argument_map.end()) { 32 | auto new_arg_inst = new ArgInst( 33 | arg_inst->getType()->to(), 34 | arg_inst->getValue(), 35 | entry_block, 36 | arg_inst->getName() + "_" 37 | ); 38 | auto imm_inst = new UnsignedImmInst( 39 | ir->type_pool->getUnsignedIntegerType(CYAN_PRODUCT_BITS), 40 | 1, 41 | entry_block, 42 | "_" + std::to_string(func->countLocalTemp()) 43 | ); 44 | alloc_inst = new AllocaInst( 45 | arg_inst->getType(), 46 | imm_inst, 47 | entry_block, 48 | "_" + arg_inst->getName() 49 | ); 50 | auto load_inst = new LoadInst( 51 | arg_inst->getType()->to()->getBaseType(), 52 | new_arg_inst, 53 | entry_block, 54 | "_" + std::to_string(func->countLocalTemp()) 55 | ); 56 | auto store_inst = new StoreInst( 57 | arg_inst->getType()->to()->getBaseType(), 58 | alloc_inst, 59 | load_inst, 60 | entry_block, 61 | "_" + std::to_string(func->countLocalTemp()) 62 | ); 63 | buffer.emplace_back(new_arg_inst); 64 | buffer.emplace_back(imm_inst); 65 | buffer.emplace_back(alloc_inst); 66 | buffer.emplace_back(load_inst); 67 | buffer.emplace_back(store_inst); 68 | argument_map.emplace(arg_inst->getValue(), alloc_inst); 69 | } 70 | else { 71 | alloc_inst = argument_map.at(arg_inst->getValue()); 72 | } 73 | value_map.emplace(arg_inst, alloc_inst); 74 | inst_iter = block_ptr->inst_list.erase(inst_iter); 75 | } 76 | else { 77 | inst_iter++; 78 | } 79 | } 80 | } 81 | 82 | for (auto &block_ptr : func->block_list) { 83 | for (auto &inst_ptr : block_ptr->inst_list) { 84 | inst_ptr->resolve(value_map); 85 | } 86 | if (block_ptr->condition) { 87 | if (value_map.find(block_ptr->condition) != value_map.end()) { 88 | block_ptr->condition = value_map.at(block_ptr->condition); 89 | } 90 | } 91 | } 92 | 93 | if (func->block_list.size()) { 94 | entry_block->inst_list.splice(entry_block->inst_list.begin(), buffer); 95 | } 96 | 97 | value_map.clear(); 98 | } 99 | 100 | void 101 | Mem2Reg::scanAllAllocInst(Function *func) 102 | { 103 | alloc_insts.clear(); 104 | defined_block.clear(); 105 | 106 | for (auto &block_ptr : func->block_list) { 107 | for (auto &iter_ptr : block_ptr->inst_list) { 108 | if (iter_ptr->is()) { 109 | alloc_insts.emplace(iter_ptr.get()); 110 | defined_block.emplace(iter_ptr.get(), block_ptr.get()); 111 | } 112 | } 113 | } 114 | } 115 | 116 | void 117 | Mem2Reg::filterAllocInst(Function *func) 118 | { 119 | for (auto &block_ptr : func->block_list) { 120 | for (auto &inst_ptr : block_ptr->inst_list) { 121 | if (inst_ptr->is()) { } 122 | else if (inst_ptr->is()) { 123 | if (alloc_insts.find(inst_ptr->to()->getValue()) != alloc_insts.end()) { 124 | alloc_insts.erase(inst_ptr->to()->getValue()); 125 | } 126 | } 127 | else { 128 | for ( 129 | auto alloc_iter = alloc_insts.begin(); 130 | alloc_iter != alloc_insts.end(); 131 | ) { 132 | if (inst_ptr->usedInstruction(*alloc_iter)) { 133 | defined_block.erase(*alloc_iter); 134 | alloc_iter = alloc_insts.erase(alloc_iter); 135 | } 136 | else { 137 | ++alloc_iter; 138 | } 139 | } 140 | } 141 | } 142 | } 143 | } 144 | 145 | void 146 | Mem2Reg::performReplace(Function *func) 147 | { 148 | for (auto alloc_inst : alloc_insts) { 149 | ir->output(debug_out); 150 | debug_out << "========================================" << std::endl; 151 | debug_out << func->getName() << " " << alloc_inst->getName() << std::endl; 152 | debug_out << "========================================" << std::endl; 153 | 154 | version_map.clear(); 155 | value_map.clear(); 156 | for (auto &block_ptr : func->block_list) { 157 | replaceInBlock(func, block_ptr.get(), alloc_inst); 158 | } 159 | resolveMultipleReplace(); 160 | replaceUsage(func); 161 | } 162 | } 163 | 164 | void 165 | Mem2Reg::replaceInBlock(Function *func, BasicBlock *block_ptr, Instruction *inst) 166 | { 167 | if (block_ptr != defined_block[inst] && !block_ptr->isDominatedBy(defined_block[inst])) { return; } 168 | if (version_map.find(block_ptr) != version_map.end()) { return; } 169 | 170 | #define saveAndRemove(inst_iter) \ 171 | insts_to_remove.emplace_back(inst_iter->release()); \ 172 | inst_iter = block_ptr->inst_list.erase(inst_iter); 173 | 174 | if (block_ptr == defined_block[inst]) { 175 | for ( 176 | auto inst_iter = block_ptr->inst_list.begin(); 177 | inst_iter != block_ptr->inst_list.end(); 178 | ) { 179 | if (inst_iter->get() == inst) { 180 | saveAndRemove(inst_iter); 181 | continue; 182 | } 183 | 184 | if ((*inst_iter)->is() && (*inst_iter)->to()->getAddress() == inst) { 185 | assert(version_map.find(block_ptr) != version_map.end()); 186 | 187 | value_map.emplace(inst_iter->get(), version_map.at(block_ptr)); 188 | saveAndRemove(inst_iter); 189 | continue; 190 | } 191 | 192 | if ((*inst_iter)->is() && (*inst_iter)->to()->getAddress() == inst) { 193 | version_map[block_ptr] = (*inst_iter)->to()->getValue(); 194 | saveAndRemove(inst_iter); 195 | continue; 196 | } 197 | 198 | ++inst_iter; 199 | } 200 | 201 | assert(version_map.find(block_ptr) != version_map.end()); 202 | } 203 | else { 204 | assert(block_ptr->preceders.size()); 205 | auto builder = PhiInst::Builder( 206 | inst->getType()->to()->getBaseType(), 207 | block_ptr, 208 | inst->getName() + "." + std::to_string(func->countLocalTemp()) 209 | ); 210 | 211 | if (block_ptr->preceders.size() == 1) { 212 | auto preceder = *block_ptr->preceders.begin(); 213 | assert(preceder == defined_block[inst] || preceder->isDominatedBy(defined_block[inst])); 214 | 215 | replaceInBlock(func, preceder, inst); 216 | assert(version_map.find(preceder) != version_map.end()); 217 | 218 | version_map.emplace(block_ptr, version_map.at(preceder)); 219 | } 220 | else { 221 | version_map.emplace(block_ptr, builder.get()); 222 | } 223 | 224 | for ( 225 | auto inst_iter = block_ptr->inst_list.begin(); 226 | inst_iter != block_ptr->inst_list.end(); 227 | ) { 228 | assert(inst_iter->get() != inst); 229 | 230 | if ((*inst_iter)->is() && (*inst_iter)->to()->getAddress() == inst) { 231 | assert(version_map.find(block_ptr) != version_map.end()); 232 | 233 | value_map.emplace(inst_iter->get(), version_map.at(block_ptr)); 234 | saveAndRemove(inst_iter); 235 | continue; 236 | } 237 | 238 | if ((*inst_iter)->is() && (*inst_iter)->to()->getAddress() == inst) { 239 | version_map[block_ptr] = (*inst_iter)->to()->getValue(); 240 | saveAndRemove(inst_iter); 241 | continue; 242 | } 243 | 244 | ++inst_iter; 245 | } 246 | 247 | if (block_ptr->preceders.size() != 1) { 248 | std::set prev_value; 249 | for (auto &preceder : block_ptr->preceders) { 250 | assert(preceder == defined_block[inst] || preceder->isDominatedBy(defined_block[inst])); 251 | 252 | replaceInBlock(func, preceder, inst); 253 | prev_value.emplace(version_map.at(preceder)); 254 | builder.addBranch(version_map.at(preceder), preceder); 255 | } 256 | 257 | prev_value.erase(builder.get()); 258 | if (prev_value.size() == 1) { 259 | value_map.emplace(builder.get(), *prev_value.begin()); 260 | if (version_map.at(block_ptr) == builder.get()) { 261 | version_map[block_ptr] = *prev_value.begin(); 262 | } 263 | insts_to_remove.emplace_back(builder.release()); 264 | } 265 | else { 266 | block_ptr->inst_list.emplace_front(builder.release()); 267 | } 268 | } 269 | } 270 | 271 | #undef saveAndRemove 272 | } 273 | 274 | void 275 | Mem2Reg::resolveMultipleReplace() 276 | { 277 | for (auto &value_pair : value_map) { 278 | auto replace = value_pair.second; 279 | while (value_map.find(replace) != value_map.end()) { 280 | replace = value_map.at(replace); 281 | } 282 | value_pair.second = replace; 283 | } 284 | } 285 | 286 | void 287 | Mem2Reg::replaceUsage(Function *func) 288 | { 289 | for (auto &block_ptr : func->block_list) { 290 | for (auto &inst_ptr : block_ptr->inst_list) { 291 | inst_ptr->resolve(value_map); 292 | } 293 | if (block_ptr->condition) { 294 | if (value_map.find(block_ptr->condition) != value_map.end()) { 295 | block_ptr->condition = value_map.at(block_ptr->condition); 296 | } 297 | } 298 | } 299 | } 300 | 301 | void 302 | Mem2Reg::outputReplacableAllocInst(Function *func, std::ostream &os) 303 | { 304 | os << func->getName() << "\n"; 305 | for (auto &alloc : alloc_insts) { 306 | os << "\t" << alloc->getName() << "\n"; 307 | } 308 | os << std::endl; 309 | } 310 | -------------------------------------------------------------------------------- /lib/mem2reg.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/16/16. 3 | // 4 | 5 | #ifndef CYAN_MEM2REG_HPP 6 | #define CYAN_MEM2REG_HPP 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "optimizer.hpp" 13 | #include "phi_eliminator.hpp" 14 | 15 | namespace cyan { 16 | 17 | class Mem2Reg : public Optimizer 18 | { 19 | std::map argument_map; 20 | std::set alloc_insts; 21 | std::map defined_block; 22 | std::map version_map; 23 | std::map value_map; 24 | std::list > insts_to_remove; 25 | 26 | void allocaForArgument(Function *func); 27 | void scanAllAllocInst(Function *func); 28 | void filterAllocInst(Function *func); 29 | void performReplace(Function *func); 30 | void replaceInBlock(Function *func, BasicBlock *block_ptr, Instruction *inst); 31 | void resolveMultipleReplace(); 32 | void replaceUsage(Function *func); 33 | 34 | void outputReplacableAllocInst(Function *func, std::ostream &os); 35 | 36 | std::ostream &debug_out; 37 | 38 | public: 39 | static std::stringstream trash_out; 40 | 41 | Mem2Reg(IR *_ir, std::ostream &os = trash_out) 42 | : Optimizer(_ir), debug_out(os) 43 | { 44 | for (auto &func_iter : _ir->function_table) { 45 | allocaForArgument(func_iter.second.get()); 46 | while (true) { 47 | scanAllAllocInst(func_iter.second.get()); 48 | filterAllocInst(func_iter.second.get()); 49 | if (!alloc_insts.size()) break; 50 | 51 | outputReplacableAllocInst(func_iter.second.get(), os); 52 | performReplace(func_iter.second.get()); 53 | } 54 | } 55 | } 56 | }; 57 | 58 | } 59 | 60 | #endif //CYAN_MEM2REG_HPP 61 | -------------------------------------------------------------------------------- /lib/optimizer.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/15/16 3 | // 4 | 5 | #ifndef CYAN_OPTIMIZER_HPP 6 | #define CYAN_OPTIMIZER_HPP 7 | 8 | #include 9 | #include 10 | 11 | #include "ir.hpp" 12 | 13 | namespace cyan { 14 | 15 | class Optimizer 16 | { 17 | protected: 18 | std::unique_ptr ir; 19 | 20 | public: 21 | Optimizer(IR *ir) 22 | : ir(ir) 23 | { } 24 | 25 | inline IR * 26 | release() 27 | { return ir.release(); } 28 | 29 | inline IR * 30 | get() const 31 | { return ir.get(); } 32 | }; 33 | 34 | class OutputOptimizer : public Optimizer 35 | { 36 | public: 37 | OutputOptimizer(IR *ir) 38 | : Optimizer(ir) 39 | { 40 | ir->output(std::cerr); 41 | std::cerr << "================" << std::endl; 42 | } 43 | }; 44 | 45 | } 46 | 47 | #endif // CYAN_OPTIMIZER_HPP 48 | -------------------------------------------------------------------------------- /lib/optimizer_group.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/24/16. 3 | // 4 | 5 | #include "optimizer_group.hpp" 6 | 7 | #include "inliner.hpp" 8 | 9 | using namespace cyan; 10 | -------------------------------------------------------------------------------- /lib/optimizer_group.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/24/16. 3 | // 4 | 5 | #ifndef CYAN_OPTIMIZER_GROUP_HPP 6 | #define CYAN_OPTIMIZER_GROUP_HPP 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "optimizer.hpp" 13 | #include "dep_analyzer.hpp" 14 | #include "loop_marker.hpp" 15 | #include "mem2reg.hpp" 16 | #include "unreachable_code_eliminater.hpp" 17 | #include "dead_code_eliminater.hpp" 18 | #include "inst_rewriter.hpp" 19 | #include "inliner.hpp" 20 | 21 | namespace cyan { 22 | 23 | typedef std::function OptimizerWrapper; 24 | 25 | template ::value> > 27 | IR * 28 | optimize_with(IR *ir) 29 | { return T(ir).release(); } 30 | 31 | template 32 | class OptimizerGroup : public Optimizer 33 | { 34 | static OptimizerWrapper wrappers[]; 35 | public: 36 | OptimizerGroup(IR *_ir) 37 | : Optimizer(_ir) 38 | { 39 | for (auto &wrapper : wrappers) { 40 | ir.reset(wrapper(ir.release())); 41 | } 42 | } 43 | }; 44 | 45 | template 46 | OptimizerWrapper OptimizerGroup::wrappers[] = { optimize_with... }; 47 | 48 | typedef OptimizerGroup< 49 | DeadCodeEliminater 50 | > OptimizerLevel0; 51 | 52 | typedef OptimizerGroup< 53 | DepAnalyzer, 54 | LoopMarker, 55 | Mem2Reg, 56 | PhiEliminator, 57 | UnreachableCodeEliminater, 58 | DepAnalyzer, 59 | LoopMarker, 60 | PhiEliminator, 61 | DeadCodeEliminater 62 | > OptimizerLevel1; 63 | 64 | typedef OptimizerGroup< 65 | DepAnalyzer, 66 | LoopMarker, 67 | Mem2Reg, 68 | PhiEliminator, 69 | InstRewriter, 70 | UnreachableCodeEliminater, 71 | DepAnalyzer, 72 | LoopMarker, 73 | PhiEliminator, 74 | DeadCodeEliminater 75 | > OptimizerLevel2; 76 | 77 | typedef OptimizerGroup< 78 | Inliner, 79 | DepAnalyzer, 80 | LoopMarker, 81 | Mem2Reg, 82 | PhiEliminator, 83 | InstRewriter, 84 | UnreachableCodeEliminater, 85 | DepAnalyzer, 86 | LoopMarker, 87 | PhiEliminator, 88 | DeadCodeEliminater 89 | > OptimizerLevel3; 90 | 91 | typedef OptimizerGroup< 92 | DeadCodeEliminater, 93 | OutputOptimizer 94 | > DebugOptimizerLevel0; 95 | 96 | typedef OptimizerGroup< 97 | DepAnalyzer, 98 | LoopMarker, 99 | OutputOptimizer, 100 | Mem2Reg, 101 | OutputOptimizer, 102 | PhiEliminator, 103 | OutputOptimizer, 104 | UnreachableCodeEliminater, 105 | DepAnalyzer, 106 | LoopMarker, 107 | OutputOptimizer, 108 | PhiEliminator, 109 | OutputOptimizer, 110 | DeadCodeEliminater, 111 | OutputOptimizer 112 | > DebugOptimizerLevel1; 113 | 114 | typedef OptimizerGroup< 115 | DepAnalyzer, 116 | LoopMarker, 117 | OutputOptimizer, 118 | Mem2Reg, 119 | OutputOptimizer, 120 | PhiEliminator, 121 | OutputOptimizer, 122 | InstRewriter, 123 | OutputOptimizer, 124 | UnreachableCodeEliminater, 125 | DepAnalyzer, 126 | LoopMarker, 127 | OutputOptimizer, 128 | PhiEliminator, 129 | OutputOptimizer, 130 | DeadCodeEliminater, 131 | OutputOptimizer 132 | > DebugOptimizerLevel2; 133 | 134 | typedef OptimizerGroup< 135 | Inliner, 136 | OutputOptimizer, 137 | DepAnalyzer, 138 | LoopMarker, 139 | OutputOptimizer, 140 | Mem2Reg, 141 | OutputOptimizer, 142 | PhiEliminator, 143 | OutputOptimizer, 144 | InstRewriter, 145 | OutputOptimizer, 146 | UnreachableCodeEliminater, 147 | DepAnalyzer, 148 | LoopMarker, 149 | OutputOptimizer, 150 | PhiEliminator, 151 | OutputOptimizer, 152 | DeadCodeEliminater, 153 | OutputOptimizer 154 | > DebugOptimizerLevel3; 155 | } 156 | 157 | #endif //CYAN_OPTIMIZERGROUP_HPP 158 | -------------------------------------------------------------------------------- /lib/parse.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Clarkok on 16/4/29. 3 | // 4 | 5 | #ifndef CYAN_PARSE_HPP 6 | #define CYAN_PARSE_HPP 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "location.hpp" 15 | #include "symbols.hpp" 16 | #include "type.hpp" 17 | #include "error_collector.hpp" 18 | #include "ir_builder.hpp" 19 | 20 | namespace cyan { 21 | 22 | class Parser 23 | { 24 | public: 25 | static constexpr int ERROR_NR_LIMIT = 10; 26 | 27 | typedef char TChar; 28 | 29 | struct Buffer 30 | { 31 | size_t size; 32 | TChar *content; 33 | 34 | Buffer(size_t size, const TChar *content) 35 | : size(size), content(new TChar[size]) 36 | { std::memcpy(this->content, content, size); } 37 | 38 | Buffer(Buffer &&buffer) 39 | : size(buffer.size), content(buffer.content) 40 | { buffer.content = nullptr; } 41 | 42 | Buffer(const Buffer &) = delete; 43 | 44 | ~Buffer() 45 | { if (content) delete[] content; } 46 | 47 | inline TChar *begin() { return content; } 48 | inline TChar *end() { return content + size; } 49 | inline const TChar *cbegin() const { return content; } 50 | inline const TChar *cend() const { return content + size; } 51 | }; 52 | 53 | struct LoopDesc 54 | { 55 | BasicBlock *continue_block; 56 | BasicBlock *follow_block; 57 | 58 | LoopDesc(BasicBlock *continue_block, BasicBlock *follow_block) 59 | : continue_block(continue_block), follow_block(follow_block) 60 | { } 61 | }; 62 | 63 | struct ParseErrorException : std::exception 64 | { 65 | std::string _what; 66 | 67 | ParseErrorException(Location location, std::string message) 68 | : _what(message + "\n " + std::to_string(location) + "\n") 69 | { } 70 | 71 | const char * 72 | what() const noexcept 73 | { return _what.c_str(); } 74 | }; 75 | 76 | struct ParseIOException : std::exception 77 | { 78 | std::string _what; 79 | 80 | ParseIOException(const char *filename) 81 | : _what(std::string("file ") + filename + "cannot be openned") 82 | { } 83 | 84 | const char * 85 | what() const noexcept 86 | { return _what.c_str(); } 87 | }; 88 | 89 | struct ParseExpectErrorException : ParseErrorException 90 | { 91 | ParseExpectErrorException(Location location, std::string expected, std::string actual) 92 | : ParseErrorException(location, "Expected " + expected + ", but met '" + actual + "'") 93 | { } 94 | }; 95 | 96 | struct ParseRedefinedErrorException : ParseErrorException 97 | { 98 | ParseRedefinedErrorException(Location location, std::string name, Location original) 99 | : ParseErrorException( 100 | location, 101 | "Symbol `" + name + "` redefined, originally defined at " + std::to_string(original) 102 | ) 103 | { } 104 | }; 105 | 106 | struct ParseInvalidVariableNameException : ParseErrorException 107 | { 108 | ParseInvalidVariableNameException(Location location, std::string name) 109 | : ParseErrorException( 110 | location, 111 | "`" + name + "` is not a valid variable name" 112 | ) 113 | { } 114 | }; 115 | 116 | struct ParseUndefinedErrorException : ParseErrorException 117 | { 118 | ParseUndefinedErrorException(Location location, std::string name) 119 | : ParseErrorException( 120 | location, 121 | "Symbol `" + name + "` undefined" 122 | ) 123 | { } 124 | }; 125 | 126 | struct ParseTypeErrorException : ParseErrorException 127 | { 128 | ParseTypeErrorException(Location location, std::string msg) 129 | : ParseErrorException(location, msg) 130 | { } 131 | }; 132 | 133 | enum Token : TChar 134 | { 135 | T_UNPEAKED = 0, 136 | T_EOF = -1, 137 | T_ID = -2, 138 | T_INTEGER = -3, 139 | T_STRING = -4, 140 | 141 | T_LOGIC_OR = -5, 142 | T_LOGIC_AND = -6, 143 | 144 | T_EQ = -7, 145 | T_NE = -8, 146 | 147 | T_GE = -9, 148 | T_LE = -10, 149 | 150 | T_SHL = -11, 151 | T_SHR = -12, 152 | 153 | T_INC = -13, 154 | T_DEC = -14, 155 | 156 | T_ADD_ASSIGN = -15, 157 | T_SUB_ASSIGN = -16, 158 | T_MUL_ASSIGN = -17, 159 | T_DIV_ASSIGN = -18, 160 | T_MOD_ASSIGN = -19, 161 | T_SHL_ASSIGN = -20, 162 | T_SHR_ASSIGN = -21, 163 | T_AND_ASSIGN = -22, 164 | T_XOR_ASSIGN = -23, 165 | T_OR_ASSIGN = -24, 166 | }; 167 | 168 | enum Reserved : intptr_t 169 | { 170 | R_BREAK, 171 | R_CONCEPT, 172 | R_CONTINUE, 173 | R_DELETE, 174 | R_ELSE, 175 | R_FUNCTION, 176 | R_IF, 177 | R_IMPL, 178 | R_LET, 179 | R_NEW, 180 | R_RETURN, 181 | R_STRUCT, 182 | R_WHILE, 183 | }; 184 | 185 | protected: 186 | Location location; 187 | std::unique_ptr buffer; 188 | decltype(buffer->cbegin()) current; 189 | decltype(buffer->cbegin()) token_start; 190 | int peaking_token; 191 | intptr_t peaking_int; 192 | std::string peaking_string; 193 | std::unique_ptr symbol_table; 194 | std::unique_ptr type_pool; 195 | CounterErrorCollector *error_counter; 196 | std::unique_ptr error_collector; 197 | std::unique_ptr ir_builder; 198 | std::unique_ptr current_function; 199 | std::unique_ptr current_block; 200 | 201 | Type *last_type = nullptr; 202 | bool is_left_value = false; 203 | Instruction *result_inst; 204 | std::stack loop_stack; 205 | 206 | private: 207 | inline TChar 208 | _current(int offset = 0) 209 | { return current[offset]; } 210 | 211 | inline TChar 212 | _forward() 213 | { 214 | if (*current++ == '\n') { 215 | location.column = 0; 216 | ++location.line; 217 | } 218 | else { 219 | ++location.column; 220 | } 221 | return _current(); 222 | } 223 | 224 | inline bool 225 | _endOfInput(int offset = 0) 226 | { return buffer->cend() - current <= offset; } 227 | 228 | inline std::string 229 | _tokenLiteral() const 230 | { return std::string(token_start, current); } 231 | 232 | Token _parseId(); 233 | Token _parseNumber(); 234 | Token _parseString(); 235 | 236 | void _parseBlockComment(); 237 | void _parseLineComment(); 238 | 239 | int _peak(); 240 | int _next(); 241 | 242 | void _registerReserved(); 243 | 244 | protected: 245 | void checkVariableDefined(std::string name); 246 | Symbol *checkFunctionDefined(std::string name, FunctionType *type); 247 | Symbol *checkConceptDefined(std::string name); 248 | Symbol *checkStructDefined(std::string name); 249 | Type *checkTypeName(std::string name); 250 | Type *parseType(); 251 | Type *parseLeftHandType(bool &use_left_hand); 252 | Type *resolveForwardType(Type *type); 253 | 254 | void parseGlobalLetStmt(); 255 | void parseFunctionDefine(); 256 | void parseConceptDefine(); 257 | void parseStructDefine(); 258 | void parseImplDefine(); 259 | 260 | void parsePrototype(); 261 | void parseFunctionBody(); 262 | 263 | void parseStatement(); 264 | void parseLetStmt(); 265 | void parseReturnStmt(); 266 | void parseBlockStmt(); 267 | void parseExpressionStmt(); 268 | void parseIfStmt(); 269 | void parseWhileStmt(); 270 | void parseBreakStmt(); 271 | void parseContinueStmt(); 272 | void parseDeleteStmt(); 273 | 274 | void parseExpression(); 275 | void parseAssignmentExpr(); 276 | void parseConditionalExpr(); 277 | void parseLogicOrExpr(); 278 | void parseLogicAndExpr(); 279 | void parseBitwiseOrExpr(); 280 | void parseBitwiseXorExpr(); 281 | void parseBitwiseAndExpr(); 282 | void parseEqualityExpr(); 283 | void parseCompareExpr(); 284 | void parseShiftExpr(); 285 | void parseAdditiveExpr(); 286 | void parseMultiplitiveExpr(); 287 | void parsePrefixExpr(); 288 | void parsePostfixExpr(); 289 | void parseUnaryExpr(); 290 | void parseNewExpr(); 291 | 292 | bool _parse(); 293 | 294 | public: 295 | Parser(ErrorCollector *error_collector) 296 | : location(""), 297 | peaking_token(T_UNPEAKED), 298 | peaking_int(0), 299 | peaking_string(""), 300 | symbol_table(new SymbolTable()), 301 | type_pool(new TypePool()), 302 | error_counter(new CounterErrorCollector()), 303 | error_collector( 304 | dynamic_cast( 305 | ChainErrorCollector::Builder() 306 | .addCollector(error_collector) 307 | .addCollector(error_counter) 308 | .release() 309 | ) 310 | ), 311 | ir_builder(new IRBuilder()) 312 | { ir_builder->newFunction("_init_", nullptr); } 313 | 314 | virtual ~Parser() = default; 315 | 316 | bool parse(const char *content); 317 | bool parseFile(const char *filename); 318 | 319 | std::unique_ptr release(); 320 | }; 321 | 322 | } 323 | 324 | #endif //CYAN_PARSE_HPP 325 | -------------------------------------------------------------------------------- /lib/phi_eliminator.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/19/16. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | #include "phi_eliminator.hpp" 9 | 10 | using namespace cyan; 11 | 12 | void 13 | PhiEliminator::eliminateInFunction(Function *func) 14 | { 15 | std::map value_map; 16 | 17 | for (auto &block_ptr : func->block_list) { 18 | for ( 19 | auto inst_iter = block_ptr->inst_list.begin(); 20 | inst_iter != block_ptr->inst_list.end(); 21 | ) { 22 | if ((*inst_iter)->is()) { 23 | auto phi_inst = (*inst_iter)->to(); 24 | 25 | std::set branch_values; 26 | for (auto &branch : *phi_inst) { 27 | branch_values.emplace(branch.value); 28 | } 29 | 30 | if (branch_values.size() == 1) { 31 | value_map.emplace(phi_inst, *branch_values.begin()); 32 | inst_iter = block_ptr->inst_list.erase(inst_iter); 33 | } 34 | else if ( 35 | branch_values.size() == 2 && 36 | branch_values.find(phi_inst) != branch_values.end() 37 | ) { 38 | branch_values.erase(phi_inst); 39 | value_map.emplace(phi_inst, *branch_values.begin()); 40 | inst_iter = block_ptr->inst_list.erase(inst_iter); 41 | } 42 | else { 43 | inst_iter++; 44 | } 45 | } 46 | else { 47 | inst_iter++; 48 | } 49 | } 50 | } 51 | 52 | for (auto &block_ptr : func->block_list) { 53 | for (auto &inst_ptr : block_ptr->inst_list) { 54 | inst_ptr->resolve(value_map); 55 | } 56 | if (value_map.find(block_ptr->condition) != value_map.end()) { 57 | block_ptr->condition = value_map.at(block_ptr->condition); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/phi_eliminator.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/19/16. 3 | // 4 | 5 | #ifndef CYAN_PHI_ELIMINATOR_HPP 6 | #define CYAN_PHI_ELIMINATOR_HPP 7 | 8 | #include "optimizer.hpp" 9 | 10 | namespace cyan { 11 | 12 | class PhiEliminator : public Optimizer 13 | { 14 | void eliminateInFunction(Function *func); 15 | 16 | public: 17 | PhiEliminator(IR *ir) 18 | : Optimizer(ir) 19 | { 20 | for (auto &func_pair : ir->function_table) { 21 | eliminateInFunction(func_pair.second.get()); 22 | } 23 | } 24 | }; 25 | 26 | } 27 | 28 | #endif //CYAN_PHI_ELIMINATOR_HPP 29 | -------------------------------------------------------------------------------- /lib/symbols.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Clarkok on 16/4/29. 3 | // 4 | 5 | #include "symbols.hpp" 6 | 7 | using namespace cyan; 8 | -------------------------------------------------------------------------------- /lib/symbols.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Clarkok on 16/4/29. 3 | // 4 | 5 | #ifndef CYAN_SYMBOLS_HPP 6 | #define CYAN_SYMBOLS_HPP 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "location.hpp" 14 | #include "type.hpp" 15 | 16 | namespace cyan { 17 | 18 | struct Symbol 19 | { 20 | public: 21 | enum Klass 22 | { 23 | K_RESERVED, 24 | K_VARIABLE, 25 | K_ARGUMENT, 26 | K_GLOBAL, 27 | K_STRUCT, 28 | K_CONCEPT, 29 | K_FUNCTION, 30 | K_IMPORTED, 31 | K_TEMPLATE_ARG, 32 | K_PRIMITIVE, 33 | }; 34 | 35 | Location location; 36 | std::string name; 37 | Klass klass; 38 | intptr_t token_value; 39 | bool is_template; 40 | Type *type; 41 | 42 | ~Symbol() = default; 43 | friend class SymbolScope; 44 | 45 | private: 46 | Symbol( 47 | Location location, 48 | std::string name, 49 | Klass klass, 50 | intptr_t token_value, 51 | bool is_template, 52 | Type *type 53 | ) 54 | : location(location), 55 | name(name), 56 | klass(klass), 57 | token_value(token_value), 58 | is_template(is_template), 59 | type(type) 60 | { } 61 | }; 62 | 63 | class SymbolScope 64 | { 65 | std::map > table; 66 | std::vector > children; 67 | SymbolScope *parent; 68 | 69 | SymbolScope(SymbolScope *parent) 70 | : parent(parent) 71 | { } 72 | 73 | template Symbol * 74 | defineSymbol(std::string name, T_Args ...args) 75 | { 76 | Symbol *ret; 77 | table.emplace(name, std::unique_ptr(ret = (new Symbol(args...)))); 78 | return ret; 79 | } 80 | 81 | inline SymbolScope * 82 | createChildScope() 83 | { 84 | children.emplace_back(std::unique_ptr(new SymbolScope(this))); 85 | return children.back().get(); 86 | } 87 | 88 | inline Symbol * 89 | lookup(std::string name) const 90 | { 91 | if (table.find(name) != table.end()) { return table.at(name).get(); } 92 | if (isRootScope()) { return nullptr; } 93 | return parent->lookup(name); 94 | } 95 | 96 | inline SymbolScope * 97 | lookupDefineScope(std::string name) 98 | { 99 | if (table.find(name) != table.end()) { return this; } 100 | if (isRootScope()) { return nullptr; } 101 | return parent->lookupDefineScope(name); 102 | } 103 | 104 | public: 105 | ~SymbolScope() = default; 106 | 107 | inline auto 108 | begin() -> decltype(table.begin()) 109 | { return table.begin(); } 110 | 111 | inline auto 112 | end() -> decltype(table.end()) 113 | { return table.end(); } 114 | 115 | inline auto 116 | cbegin() const -> decltype(table.cbegin()) 117 | { return table.cbegin(); } 118 | 119 | inline auto 120 | cend() const -> decltype(table.cend()) 121 | { return table.cend(); } 122 | 123 | inline auto 124 | size() const -> decltype(table.size()) 125 | { return table.size(); } 126 | 127 | inline bool 128 | isRootScope() const 129 | { return parent == nullptr; } 130 | 131 | friend class SymbolTable; 132 | }; 133 | 134 | class SymbolTable 135 | { 136 | std::unique_ptr root_scope; 137 | SymbolScope *current_scope; 138 | 139 | public: 140 | SymbolTable() 141 | : root_scope(new SymbolScope(nullptr)), 142 | current_scope(root_scope.get()) 143 | { } 144 | 145 | ~SymbolTable() = default; 146 | 147 | inline void 148 | pushScope() 149 | { current_scope = current_scope->createChildScope(); } 150 | 151 | inline void 152 | popScope() 153 | { 154 | assert(!current_scope->isRootScope()); 155 | current_scope = current_scope->parent; 156 | } 157 | 158 | inline SymbolScope * 159 | currentScope() const 160 | { return current_scope; } 161 | 162 | inline SymbolScope * 163 | rootScope() const 164 | { return root_scope.get(); } 165 | 166 | inline Symbol * 167 | lookup(std::string name) const 168 | { return current_scope->lookup(name); } 169 | 170 | inline SymbolScope * 171 | lookupDefineScope(std::string name) const 172 | { return current_scope->lookupDefineScope(name); } 173 | 174 | template Symbol * 175 | defineSymbol(std::string name, T_Args ...args) 176 | { return current_scope->defineSymbol(name, args...); } 177 | 178 | template Symbol * 179 | defineSymbolInRoot(std::string name, T_Args ...args) 180 | { return root_scope->defineSymbol(name, args...); } 181 | }; 182 | 183 | } 184 | 185 | #endif //CYAN_SYMBOLS_HPP 186 | -------------------------------------------------------------------------------- /lib/type.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Clarkok on 16/5/2. 3 | // 4 | 5 | #include 6 | #include "type.hpp" 7 | 8 | using namespace cyan; 9 | 10 | bool 11 | Type::equalTo(Type *type) const 12 | { 13 | if (is()) { 14 | return type->is(); 15 | } 16 | else if (is()) { 17 | return type->is() && 18 | to()->size() == 19 | type->to()->size(); 20 | } 21 | else if (is()) { 22 | return type->is() && 23 | to()->size() == 24 | type->to()->size(); 25 | } 26 | else if (is()) { 27 | return type->is() && 28 | to()->getBaseType()->equalTo(type->to()->getBaseType()); 29 | } 30 | else if (is()) { 31 | if (!type->is()) { 32 | return false; 33 | } 34 | 35 | auto this_method = to(); 36 | auto type_method = to(); 37 | if (!this_method->getReturnType()->equalTo(type_method->getReturnType())) { 38 | return false; 39 | } 40 | if (!this_method->getOwnerType()->equalTo(type_method->getOwnerType())) { 41 | return false; 42 | } 43 | if (this_method->arguments_size() != type_method->arguments_size()) { 44 | return false; 45 | } 46 | 47 | for ( 48 | auto this_iter = this_method->cbegin(), 49 | type_iter = type_method->cbegin(); 50 | this_iter != this_method->cend(); 51 | ++this_iter, ++type_iter 52 | ) { 53 | if (!(*this_iter)->equalTo(*type_iter)) { 54 | return false; 55 | } 56 | } 57 | return true; 58 | } 59 | else if (is()) { 60 | if (!type->is()) { 61 | return false; 62 | } 63 | 64 | auto this_func = to(); 65 | auto type_func = type->to(); 66 | if (!this_func->getReturnType()->equalTo(type_func->getReturnType())) { 67 | return false; 68 | } 69 | if (this_func->arguments_size() != type_func->arguments_size()) { 70 | return false; 71 | } 72 | 73 | for ( 74 | auto this_iter = this_func->cbegin(), 75 | type_iter = type_func->cbegin(); 76 | this_iter != this_func->cend(); 77 | ++this_iter, ++type_iter 78 | ) { 79 | if (!(*this_iter)->equalTo(*type_iter)) { 80 | return false; 81 | } 82 | } 83 | return true; 84 | } 85 | else if (is()) { 86 | return type->is() && 87 | to()->getBaseType()->equalTo(type->to()->getBaseType()); 88 | } 89 | else if (is()) { 90 | if (type->is()) { 91 | return to()->getName() == type->to()->getName(); 92 | } 93 | else if (type->is()) { 94 | return to()->getName() == type->to()->getName(); 95 | } 96 | else if (type->is()) { 97 | return to()->getName() == type->to()->getName(); 98 | } 99 | else { 100 | return false; 101 | } 102 | } 103 | else if (is()) { 104 | if (type->is()) { 105 | return to()->getName() == type->to()->getName(); 106 | } 107 | 108 | return type->is() && 109 | to()->getName() == 110 | type->to()->getName(); 111 | } 112 | else if (is()) { 113 | if (type->is()) { 114 | return to()->getName() == type->to()->getName(); 115 | } 116 | 117 | return type->is() && 118 | to()->getName() == 119 | type->to()->getName(); 120 | } 121 | else { 122 | assert(false); 123 | } 124 | } 125 | 126 | size_t 127 | VoidType::size() const 128 | { return 0; } 129 | 130 | std::string 131 | VoidType::to_string() const 132 | { return "void"; } 133 | 134 | size_t 135 | ForwardType::size() const 136 | { return 0; } 137 | 138 | std::string 139 | ForwardType::to_string() const 140 | { return "forward " + getName(); } 141 | 142 | size_t 143 | IntegeralType::size() const 144 | { return bitwise_width / 8; } 145 | 146 | bool 147 | SignedIntegerType::isSigned() const 148 | { return true; } 149 | 150 | std::string 151 | SignedIntegerType::to_string() const 152 | { return "i" + std::to_string(bitwise_width); } 153 | 154 | bool 155 | UnsignedIntegerType::isSigned() const 156 | { return false; } 157 | 158 | std::string 159 | UnsignedIntegerType::to_string() const 160 | { return "u" + std::to_string(bitwise_width); } 161 | 162 | bool 163 | PointerType::isSigned() const 164 | { return false; } 165 | 166 | std::string 167 | PointerType::to_string() const 168 | { return base_type->to_string() + "*"; } 169 | 170 | size_t 171 | ArrayType::size() const 172 | { return CYAN_PRODUCT_BITS / 8; } 173 | 174 | std::string 175 | ArrayType::to_string() const 176 | { 177 | return base_type->to_string() + "[]"; 178 | } 179 | 180 | std::string 181 | FunctionType::to_string() const 182 | { 183 | std::string ret("("); 184 | if (arguments.size()) { 185 | for (auto &arg : arguments) { 186 | ret += arg->to_string() + ","; 187 | } 188 | ret.pop_back(); 189 | } 190 | ret += "):" + return_type->to_string(); 191 | return ret; 192 | } 193 | 194 | MethodType * 195 | MethodType::fromFunction(Type *owner, FunctionType *function) 196 | { 197 | auto ret = new MethodType(owner); 198 | std::copy(function->cbegin(), function->cend(), ret->arguments.begin()); 199 | ret->return_type = function->getReturnType(); 200 | return ret; 201 | } 202 | 203 | std::string 204 | MethodType::to_string() const 205 | { return owner->to_string() + "::" + FunctionType::to_string() + ""; } 206 | 207 | size_t 208 | ConceptType::size() const 209 | { return methods.size() * CYAN_PRODUCT_BITS; } 210 | 211 | std::string 212 | ConceptType::to_string() const 213 | { return "concept " + getName(); } 214 | 215 | size_t 216 | StructType::size() const 217 | { return (members.size() + concepts.size()) * (CYAN_PRODUCT_BITS / 8); } 218 | 219 | std::string 220 | StructType::to_string() const 221 | { return "struct " + getName(); } 222 | 223 | std::string 224 | CastedStructType::to_string() const 225 | { return "struct " + original_struct->getName() + "::" + base_concept->getName(); } 226 | 227 | size_t 228 | VTableType::size() const 229 | { return owner->size(); } 230 | 231 | std::string 232 | VTableType::to_string() const 233 | { return "vtable for " + owner->to_string(); } 234 | 235 | size_t 236 | TemplateArgumentType::size() const 237 | { return 0; } 238 | 239 | std::string 240 | TemplateArgumentType::to_string() const 241 | { return "(" + getName() + ":" + concept->getName() + ")"; } 242 | 243 | size_t 244 | TemplateType::size() const 245 | { return base_type->size(); } 246 | 247 | std::string 248 | TemplateType::to_string() const 249 | { 250 | std::string ret("template<"); 251 | 252 | for (auto &arg : arguments) { 253 | ret += arg.type->to_string() + ","; 254 | } 255 | ret.pop_back(); 256 | ret += "> " + base_type->to_string(); 257 | 258 | return ret; 259 | } 260 | 261 | VoidType * 262 | TypePool::getVoidType() 263 | { 264 | if (!void_type) { void_type.reset(new VoidType()); } 265 | return void_type.get(); 266 | } 267 | 268 | ForwardType * 269 | TypePool::getForwardType(std::string name) 270 | { 271 | if (forward_type.find(name) == forward_type.end()) { 272 | forward_type.emplace( 273 | name, 274 | std::unique_ptr(new ForwardType(name)) 275 | ); 276 | } 277 | return forward_type[name].get(); 278 | } 279 | 280 | SignedIntegerType * 281 | TypePool::getSignedIntegerType(size_t bitwise_width) 282 | { 283 | if (signed_integer_type.find(bitwise_width) == signed_integer_type.end()) { 284 | signed_integer_type.emplace( 285 | bitwise_width, 286 | std::unique_ptr(new SignedIntegerType(bitwise_width)) 287 | ); 288 | } 289 | return signed_integer_type[bitwise_width].get(); 290 | } 291 | 292 | UnsignedIntegerType * 293 | TypePool::getUnsignedIntegerType(size_t bitwise_width) 294 | { 295 | if (unsigned_integer_type.find(bitwise_width) == unsigned_integer_type.end()) { 296 | unsigned_integer_type.emplace( 297 | bitwise_width, 298 | std::unique_ptr(new UnsignedIntegerType(bitwise_width)) 299 | ); 300 | } 301 | return unsigned_integer_type[bitwise_width].get(); 302 | } 303 | 304 | PointerType * 305 | TypePool::getPointerType(Type *base_type) 306 | { 307 | if (pointer_type.find(base_type) == pointer_type.end()) { 308 | pointer_type.emplace( 309 | base_type, 310 | std::unique_ptr(new PointerType(base_type)) 311 | ); 312 | } 313 | return pointer_type[base_type].get(); 314 | } 315 | 316 | ArrayType * 317 | TypePool::getArrayType(Type *base_type) 318 | { 319 | if (array_type.find(base_type) == array_type.end()) { 320 | array_type.emplace( 321 | base_type, 322 | std::unique_ptr(new ArrayType(base_type)) 323 | ); 324 | } 325 | return array_type.at(base_type).get(); 326 | } 327 | 328 | MethodType * 329 | TypePool::getMethodType(ConceptType *owner, FunctionType *function) 330 | { 331 | method_type.emplace_back(std::unique_ptr(MethodType::fromFunction(owner, function))); 332 | return method_type.back().get(); 333 | } 334 | 335 | CastedStructType * 336 | TypePool::getCastedStructType(StructType *original_struct, ConceptType *concept) 337 | { 338 | auto key = std::pair(original_struct, concept); 339 | if (casted_struct_type.find(key) == casted_struct_type.end()) { 340 | CastedStructType *ret = new CastedStructType(original_struct, concept); 341 | casted_struct_type.emplace( 342 | key, 343 | std::unique_ptr(ret) 344 | ); 345 | } 346 | return casted_struct_type[key].get(); 347 | } 348 | 349 | VTableType * 350 | TypePool::getVTableType(ConceptType *owner) 351 | { 352 | if (vtable_type.find(owner) == vtable_type.end()) { 353 | vtable_type.emplace( 354 | owner, 355 | std::unique_ptr(new VTableType(owner)) 356 | ); 357 | } 358 | return vtable_type[owner].get(); 359 | } 360 | -------------------------------------------------------------------------------- /lib/unreachable_code_eliminater.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/19/16. 3 | // 4 | 5 | #include 6 | 7 | #include "unreachable_code_eliminater.hpp" 8 | 9 | using namespace cyan; 10 | 11 | void 12 | UnreachableCodeEliminater::markUnreachableBlocks(Function *func) 13 | { 14 | for (auto &block_ptr : func->block_list) { 15 | if (block_ptr->condition) { 16 | auto replaced_condition = block_ptr->condition; 17 | while (value_map.find(replaced_condition) != value_map.end()) { 18 | replaced_condition = value_map.at(replaced_condition); 19 | } 20 | block_ptr->condition = replaced_condition; 21 | if (block_ptr->condition->is()) { 22 | auto value = block_ptr->condition->to()->getValue(); 23 | if (value) { 24 | unregisterPhiInBlock(block_ptr->else_block, block_ptr.get()); 25 | } 26 | else { 27 | unregisterPhiInBlock(block_ptr->then_block, block_ptr.get()); 28 | block_ptr->then_block = block_ptr->else_block; 29 | } 30 | block_ptr->else_block = nullptr; 31 | block_ptr->condition = nullptr; 32 | } 33 | else if (block_ptr->condition->is()) { 34 | auto value = block_ptr->condition->to()->getValue(); 35 | if (value) { 36 | unregisterPhiInBlock(block_ptr->else_block, block_ptr.get()); 37 | } 38 | else { 39 | unregisterPhiInBlock(block_ptr->then_block, block_ptr.get()); 40 | block_ptr->then_block = block_ptr->else_block; 41 | } 42 | block_ptr->else_block = nullptr; 43 | block_ptr->condition = nullptr; 44 | } 45 | } 46 | } 47 | } 48 | 49 | void 50 | UnreachableCodeEliminater::combineSplitBlocks(Function *func) 51 | { 52 | for (auto &block_ptr : func->block_list) { 53 | if (block_ptr->preceders.size() == 1) { 54 | auto preceder = *(block_ptr->preceders.begin()); 55 | while (block_map.find(preceder) != block_map.end()) { 56 | preceder = block_map.at(preceder); 57 | } 58 | if (preceder->condition) { continue; } 59 | assert(preceder->then_block == block_ptr.get()); 60 | assert(preceder != block_ptr.get()); 61 | 62 | unregisterPhiInBlock(block_ptr.get(), *(block_ptr->preceders.begin())); 63 | 64 | preceder->append(block_ptr.get()); 65 | block_map.emplace(block_ptr.get(), preceder); 66 | } 67 | } 68 | 69 | for (auto &value_pair : value_map) { 70 | auto replaced = value_pair.second; 71 | while (value_map.find(replaced) != value_map.end()) { 72 | replaced = value_map.at(replaced); 73 | } 74 | value_pair.second = replaced; 75 | } 76 | 77 | for (auto &block_ptr : func->block_list) { 78 | for (auto &inst_ptr : block_ptr->inst_list) { 79 | inst_ptr->resolve(value_map); 80 | } 81 | if (value_map.find(block_ptr->condition) != value_map.end()) { 82 | block_ptr->condition = value_map.at(block_ptr->condition); 83 | } 84 | } 85 | } 86 | 87 | void 88 | UnreachableCodeEliminater::unregisterPhiInBlock(BasicBlock *block, BasicBlock *preceder) 89 | { 90 | assert(block->preceders.find(preceder) != block->preceders.end()); 91 | block->preceders.erase(preceder); 92 | 93 | for (auto &inst_ptr : block->inst_list) { 94 | if (inst_ptr->is()) { 95 | auto phi_inst = inst_ptr->to(); 96 | phi_inst->remove_branch(preceder); 97 | 98 | if (phi_inst->branches_size() == 1) { 99 | value_map.emplace(phi_inst, phi_inst->begin()->value); 100 | } 101 | } 102 | } 103 | } 104 | 105 | void 106 | UnreachableCodeEliminater::resolvePhiPreceders(Function *func) 107 | { 108 | for (auto &block_ptr : func->block_list) { 109 | for (auto &inst_ptr : block_ptr->inst_list) { 110 | if (inst_ptr->is()) { 111 | for (auto &branch : *(inst_ptr->to())) { 112 | while (block_map.find(branch.preceder) != block_map.end()) { 113 | branch.preceder = block_map.at(branch.preceder); 114 | } 115 | } 116 | } 117 | } 118 | } 119 | } 120 | 121 | void 122 | UnreachableCodeEliminater::clearUnreachableBlocks(Function *func) 123 | { 124 | func->block_list.remove_if( 125 | [func](const std::unique_ptr &block_ptr) { 126 | if (block_ptr.get() == func->block_list.front().get()) { return false; } 127 | return block_ptr->preceders.size() == 0; 128 | } 129 | ); 130 | } 131 | -------------------------------------------------------------------------------- /lib/unreachable_code_eliminater.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/19/16. 3 | // 4 | 5 | #ifndef CYAN_UNREACHABLE_CODE_ELIMINATER_HPP 6 | #define CYAN_UNREACHABLE_CODE_ELIMINATER_HPP 7 | 8 | #include "optimizer.hpp" 9 | 10 | #include "dep_analyzer.hpp" 11 | 12 | namespace cyan { 13 | 14 | class UnreachableCodeEliminater : public Optimizer 15 | { 16 | std::map block_map; 17 | std::map value_map; 18 | 19 | void markUnreachableBlocks(Function *func); 20 | void combineSplitBlocks(Function *func); 21 | void unregisterPhiInBlock(BasicBlock *block, BasicBlock *preceder); 22 | void resolvePhiPreceders(Function *func); 23 | void clearUnreachableBlocks(Function *func); 24 | public: 25 | UnreachableCodeEliminater(IR *ir_) 26 | : Optimizer(ir_) 27 | { 28 | for (auto &func_pair : ir->function_table) { 29 | block_map.clear(); 30 | value_map.clear(); 31 | markUnreachableBlocks(func_pair.second.get()); 32 | combineSplitBlocks(func_pair.second.get()); 33 | resolvePhiPreceders(func_pair.second.get()); 34 | clearUnreachableBlocks(func_pair.second.get()); 35 | } 36 | } 37 | }; 38 | 39 | } 40 | 41 | #endif //CYAN_UNREACHABLE_CODE_ELIMINATER_HPP 42 | -------------------------------------------------------------------------------- /lib/vm.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _CYAN_VM_HPP_ 2 | #define _CYAN_VM_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "cyan.hpp" 11 | #include "codegen.hpp" 12 | 13 | #define XBYAK_VARIADIC_TEMPLATE 14 | #include 15 | 16 | #define CYAN_USE_COMPUTED_GOTO 1 17 | 18 | namespace cyan { 19 | 20 | namespace vm { 21 | 22 | #if __CYAN_64__ 23 | using OperatorT = uint16_t; 24 | using ShiftT = uint16_t; 25 | using RegisterT = uint32_t; 26 | using ImmediateT = uint64_t; 27 | #else 28 | using OperatorT = uint8_t; 29 | using ShiftT = uint8_t; 30 | using RegisterT = uint16_t; 31 | using ImmediateT = uint32_t; 32 | #endif 33 | 34 | static_assert(sizeof(ImmediateT) == sizeof(uintptr_t), "ImmdiateT should be large enough"); 35 | 36 | enum InstOperator 37 | { 38 | I_UNKNOWN = 0, 39 | 40 | I_ARG, 41 | I_BR, 42 | I_BNR, 43 | I_GLOB, 44 | I_JUMP, 45 | I_LI, 46 | 47 | InstOperator_ImmediateInst = I_LI, 48 | 49 | I_ADD, 50 | I_ALLOC, 51 | I_AND, 52 | I_CALL, 53 | I_DELETE, 54 | I_DIV, 55 | I_DIVU, 56 | I_LOAD8, 57 | I_LOAD8U, 58 | I_LOAD16, 59 | I_LOAD16U, 60 | I_LOAD32, 61 | I_LOAD32U, 62 | I_LOAD64, 63 | I_LOAD64U, 64 | I_MOD, 65 | I_MODU, 66 | I_MOV, 67 | I_MUL, 68 | I_MULU, 69 | I_NEW, 70 | I_NOR, 71 | I_OR, 72 | I_POP, 73 | I_PUSH, 74 | I_RET, 75 | I_SEQ, 76 | I_SHL, 77 | I_SHLU, 78 | I_SHR, 79 | I_SHRU, 80 | I_SLE, 81 | I_SLEU, 82 | I_SLT, 83 | I_SLTU, 84 | I_STORE8, 85 | I_STORE8U, 86 | I_STORE16, 87 | I_STORE16U, 88 | I_STORE32, 89 | I_STORE32U, 90 | I_STORE64, 91 | I_STORE64U, 92 | I_SUB, 93 | I_XOR, 94 | 95 | InstOperator_NR 96 | }; 97 | 98 | struct Instruction 99 | { 100 | OperatorT i_op; 101 | ShiftT i_shift; 102 | RegisterT i_rd; 103 | union { 104 | ImmediateT _imm; 105 | struct { 106 | RegisterT _rs; 107 | RegisterT _rt; 108 | } _regs; 109 | } _info; 110 | 111 | Instruction(OperatorT op, ShiftT shift, RegisterT rd, ImmediateT imm) 112 | : i_op(op), i_shift(shift), i_rd(rd) 113 | { _info._imm = imm; } 114 | 115 | Instruction(OperatorT op, ShiftT shift, RegisterT rd, RegisterT rs, RegisterT rt) 116 | : i_op(op), i_shift(shift), i_rd(rd) 117 | { 118 | _info._regs._rs = rs; 119 | _info._regs._rt = rt; 120 | } 121 | }; 122 | 123 | #define i_imm _info._imm 124 | #define i_rt _info._regs._rt 125 | #define i_rs _info._regs._rs 126 | 127 | static_assert(sizeof(Instruction) == 2 * sizeof(ImmediateT), "Instruction should be 2 in sizeof ImmediateT"); 128 | 129 | using Slot = uintptr_t; 130 | using SignedSlot = intptr_t; 131 | using GlobalSegment = std::vector; 132 | 133 | class VirtualMachine; 134 | class MovInst; 135 | 136 | using JITFunction = Slot(VirtualMachine *, Slot *, char *, Slot *); 137 | 138 | struct Function 139 | { 140 | virtual ~Function() = default; 141 | }; 142 | 143 | struct VMFunction : Function 144 | { 145 | std::vector inst_list; 146 | size_t register_nr = 1; 147 | std::string name; 148 | 149 | VMFunction(std::string name) 150 | : name(name) 151 | { } 152 | }; 153 | 154 | struct LibFunction : Function 155 | { 156 | virtual Slot call(const Slot *argument) = 0; 157 | }; 158 | 159 | struct Frame 160 | { 161 | VMFunction *func; 162 | std::vector regs; 163 | size_t frame_pointer; 164 | const Instruction *pc; 165 | 166 | Frame(VMFunction *func, size_t frame_pointer) 167 | : func(func), regs(func->register_nr, 0), frame_pointer(frame_pointer), pc(func->inst_list.data()) 168 | { } 169 | 170 | inline Slot & 171 | operator [] (size_t index) 172 | { return regs[index]; } 173 | }; 174 | 175 | Slot call_func(VirtualMachine *vm, Slot *arguments, Function *function); 176 | 177 | class VirtualMachine 178 | { 179 | public: 180 | constexpr static size_t STACK_SIZE = 1024 * 512; // 512K stack 181 | 182 | private: 183 | GlobalSegment globals; 184 | std::vector string_pool; 185 | std::stack > frame_stack; 186 | std::array stack; 187 | size_t stack_pointer = STACK_SIZE; 188 | std::map > functions; 189 | std::map > jit_results; 190 | 191 | Slot run(); 192 | void functionJIT(VMFunction *vm_func); 193 | 194 | VirtualMachine() = default; 195 | public: 196 | ~VirtualMachine() = default; 197 | 198 | struct Generate : public ::cyan::CodeGen 199 | { 200 | private: 201 | std::unique_ptr _product; 202 | VMFunction *current_func; 203 | std::map global_map; 204 | std::map block_map; 205 | std::map<::cyan::Instruction *, RegisterT> value_map; 206 | std::list > phi_ref; 207 | 208 | Generate(VirtualMachine *product, IR *ir) 209 | : CodeGen(ir), _product(product) 210 | { } 211 | 212 | void generateFunc(::cyan::Function *func); 213 | public: 214 | virtual std::ostream &generate(std::ostream &os); 215 | void generate(); 216 | inst_foreach(define_gen); 217 | void gen(MovInst *); 218 | 219 | inline std::unique_ptr 220 | release() 221 | { return std::move(_product); } 222 | 223 | inline void 224 | registerLibFunction(std::string name, LibFunction *func) 225 | { _product->functions.emplace(name, std::unique_ptr(func)); } 226 | 227 | friend class VirtualMachine; 228 | }; 229 | 230 | Slot start(); 231 | Slot startJIT(); 232 | 233 | static std::unique_ptr GenerateFactory(IR *ir); 234 | friend Slot ::cyan::vm::call_func(VirtualMachine *, Slot *, Function *); 235 | }; 236 | 237 | } 238 | 239 | } 240 | 241 | #endif 242 | -------------------------------------------------------------------------------- /runtime/Makefile: -------------------------------------------------------------------------------- 1 | runtime.o : runtime.c 2 | gcc -O3 -g -c -o $@ $^ 3 | -------------------------------------------------------------------------------- /runtime/runtime.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void 5 | print_str(const char *str) 6 | { printf("%s", str); } 7 | 8 | void 9 | print_int(int64_t value) 10 | { printf("%ld", value); } 11 | -------------------------------------------------------------------------------- /runtime/runtime.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clarkok/cyan/7e80c4266159c4e75c591cf31821207d6019d7e6/runtime/runtime.o -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories(${PROJECT_SOURCE_DIR}/lib) 2 | 3 | set(PROJECT_SRCS main.cpp lib_functions.cpp) 4 | add_executable(cyanc ${PROJECT_SRCS}) 5 | 6 | target_link_libraries(cyanc cyan) 7 | -------------------------------------------------------------------------------- /src/lib_functions.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "lib_functions.hpp" 5 | 6 | using namespace cyan; 7 | 8 | using Slot = vm::Slot; 9 | 10 | namespace { 11 | 12 | struct PrintStr : public vm::LibFunction 13 | { 14 | virtual Slot 15 | call(const Slot *arguments) 16 | { 17 | std::cout << reinterpret_cast(arguments[0]); 18 | std::cout.flush(); 19 | return 0; 20 | } 21 | }; 22 | 23 | struct PrintInt : public vm::LibFunction 24 | { 25 | virtual Slot 26 | call(const Slot *arguments) 27 | { 28 | std::cout << arguments[0]; 29 | return 0; 30 | } 31 | }; 32 | 33 | struct Rand : public vm::LibFunction 34 | { 35 | virtual Slot 36 | call(const Slot *arguments) 37 | { return std::rand(); } 38 | }; 39 | 40 | } 41 | 42 | void 43 | cyan::registerLibFunctions(vm::VirtualMachine::Generate *gen) 44 | { 45 | gen->registerLibFunction("print_str", new PrintStr()); 46 | gen->registerLibFunction("print_int", new PrintInt()); 47 | gen->registerLibFunction("rand", new Rand()); 48 | } 49 | -------------------------------------------------------------------------------- /src/lib_functions.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _CYAN_LIB_FUNCTIONS_HPP_ 2 | #define _CYAN_LIB_FUNCTIONS_HPP_ 3 | 4 | #include "vm.hpp" 5 | 6 | namespace cyan { 7 | 8 | void registerLibFunctions(vm::VirtualMachine::Generate *gen); 9 | 10 | } 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "rlutil/rlutil.h" 5 | #include "libcyan.hpp" 6 | #include "codegen_x64.hpp" 7 | #include "vm.hpp" 8 | #include "lib_functions.hpp" 9 | 10 | using namespace cyan; 11 | 12 | struct Exception : public std::exception 13 | { 14 | std::string _what; 15 | 16 | Exception(std::string what) 17 | : _what(what) 18 | { } 19 | 20 | virtual const char * 21 | what() const noexcept 22 | { return _what.c_str(); } 23 | }; 24 | 25 | void 26 | print_help() 27 | { 28 | static const int OPTIONS_COLUMN_SIZE = 16; 29 | static const char *OPTIONS_PAIR[][2] = { 30 | {"-d", "output debug info to stderr"}, 31 | {"-e ", "pass to GCC or emitting IR code or assembly"}, 32 | {"-h", "print this help"}, 33 | {"-j", "run the code with JIT engine"}, 34 | {"-o ", "define output file"}, 35 | {"-O0", "no optimization"}, 36 | {"-O1", "basic optimization"}, 37 | {"-O2", "normal optimization"}, 38 | {"-O3", "full optimization"}, 39 | {"-r", "run the code"}, 40 | {"-v", "show version"}, 41 | }; 42 | 43 | rlutil::saveDefaultColor(); 44 | rlutil::setColor(rlutil::WHITE); 45 | std::cout << "cyanc: cyan compiler\n" 46 | " By Clarkok Zhang (mail@clarkok.com)" << std::endl; 47 | rlutil::resetColor(); 48 | std::cout << "Usage: cyanc [options] file..." << std::endl; 49 | std::cout << "Options:" << std::endl; 50 | for (auto &option_pair : OPTIONS_PAIR) { 51 | rlutil::setColor(rlutil::WHITE); 52 | std::cout << " " << option_pair[0]; 53 | for (auto i = std::strlen(option_pair[0]); i < OPTIONS_COLUMN_SIZE; ++i) { 54 | std::cout << " "; 55 | } 56 | rlutil::resetColor(); 57 | std::cout << option_pair[1] << std::endl; 58 | } 59 | } 60 | 61 | struct Config 62 | { 63 | ~Config() = default; 64 | 65 | ErrorCollector *error_collector; 66 | std::string output_file; 67 | int optimize_level; 68 | std::string emit_code; 69 | std::vector input_files; 70 | std::unique_ptr parser; 71 | bool run; 72 | bool jit; 73 | bool debug_out; 74 | 75 | private: 76 | Config() 77 | : error_collector(dynamic_cast( 78 | ChainErrorCollector::Builder() 79 | .addCollector(new LimitErrorCollector(10)) 80 | .addCollector(new ScreenOutputErrorCollector()) 81 | .release() 82 | )), 83 | output_file(), 84 | optimize_level(2), 85 | emit_code("GCC"), 86 | parser(new Parser(error_collector)), 87 | run(false), 88 | jit(false), 89 | debug_out(false) 90 | { } 91 | 92 | public: 93 | static std::unique_ptr 94 | factory(int argc, const char **argv) 95 | { 96 | std::unique_ptr ret(new Config()); 97 | 98 | --argc; ++argv; 99 | while (argc) { 100 | if ((*argv)[0] == '-') { 101 | switch ((*argv)[1]) { 102 | case 'o': 103 | --argc; ++argv; 104 | ret->output_file = *argv; 105 | break; 106 | case 'e': 107 | --argc; ++argv; 108 | ret->emit_code = *argv; 109 | for (auto &ch : ret->emit_code) { 110 | ch = std::toupper(ch); 111 | } 112 | break; 113 | case 'O': 114 | { 115 | switch ((*argv)[2]) { 116 | case '0': 117 | ret->optimize_level = 0; 118 | break; 119 | case '1': 120 | ret->optimize_level = 1; 121 | break; 122 | case '2': 123 | ret->optimize_level = 2; 124 | break; 125 | case '3': 126 | ret->optimize_level = 3; 127 | break; 128 | default: 129 | ret->error_collector->error( 130 | Exception(std::string("unknown optimization level: ") + *argv) 131 | ); 132 | print_help(); 133 | exit(-1); 134 | } 135 | break; 136 | } 137 | case 'h': 138 | print_help(); 139 | exit(0); 140 | case 'v': 141 | std::cout << CYAN_VERSION << std::endl; 142 | exit(0); 143 | case 'r': 144 | ret->run = true; 145 | break; 146 | case 'j': 147 | ret->jit = true; 148 | break; 149 | case 'd': 150 | ret->debug_out = true; 151 | break; 152 | default: 153 | ret->error_collector->error( 154 | Exception(std::string("unknown option: ") + *argv) 155 | ); 156 | print_help(); 157 | exit(-1); 158 | } 159 | } 160 | else { 161 | ret->input_files.emplace_back(*argv); 162 | } 163 | --argc; ++argv; 164 | } 165 | 166 | if (ret->input_files.empty()) { 167 | ret->error_collector->error( 168 | Exception(std::string("no input files")) 169 | ); 170 | print_help(); 171 | exit(-1); 172 | } 173 | 174 | if (ret->output_file.length() == 0) { 175 | if (ret->emit_code == "X64") { 176 | ret->output_file = "a.s"; 177 | } 178 | else if (ret->emit_code == "IR") { 179 | ret->output_file = "a.ir"; 180 | } 181 | else if (ret->emit_code == "GCC") { 182 | ret->output_file = "a.out"; 183 | } 184 | else { 185 | assert(false); 186 | } 187 | } 188 | 189 | return ret; 190 | } 191 | }; 192 | 193 | std::string 194 | get_env(std::string name) 195 | { 196 | auto var = std::getenv(name.c_str()); 197 | return var ? var : ""; 198 | } 199 | 200 | int 201 | main(int argc, const char **argv) 202 | { 203 | auto config = Config::factory(argc, argv); 204 | 205 | for (auto &input_file : config->input_files) { 206 | if (!config->parser->parseFile(input_file.c_str())) { 207 | exit(-1); 208 | } 209 | } 210 | 211 | auto ir = config->parser->release(); 212 | if (config->debug_out) { 213 | switch (config->optimize_level) { 214 | case 0: ir.reset(DebugOptimizerLevel0(ir.release()).release()); break; 215 | case 1: ir.reset(DebugOptimizerLevel1(ir.release()).release()); break; 216 | case 2: ir.reset(DebugOptimizerLevel2(ir.release()).release()); break; 217 | case 3: ir.reset(DebugOptimizerLevel3(ir.release()).release()); break; 218 | default: 219 | assert(false); 220 | } 221 | } 222 | else { 223 | switch (config->optimize_level) { 224 | case 0: ir.reset(OptimizerLevel0(ir.release()).release()); break; 225 | case 1: ir.reset(OptimizerLevel1(ir.release()).release()); break; 226 | case 2: ir.reset(OptimizerLevel2(ir.release()).release()); break; 227 | case 3: ir.reset(OptimizerLevel3(ir.release()).release()); break; 228 | default: 229 | assert(false); 230 | } 231 | } 232 | 233 | if (config->run) { 234 | auto gen = vm::VirtualMachine::GenerateFactory(ir.release()); 235 | registerLibFunctions(gen.get()); 236 | gen->generate(); 237 | auto vm = gen->release(); 238 | auto ret_val = vm->start(); 239 | 240 | std::cout << "exit with code " << ret_val << std::endl; 241 | return ret_val; 242 | } 243 | 244 | if (config->jit) { 245 | auto gen = vm::VirtualMachine::GenerateFactory(ir.release()); 246 | registerLibFunctions(gen.get()); 247 | gen->generate(); 248 | auto vm = gen->release(); 249 | auto ret_val = vm->startJIT(); 250 | 251 | std::cout << "exit with code " << ret_val << std::endl; 252 | return ret_val; 253 | } 254 | 255 | if (config->emit_code == "IR") { 256 | std::ofstream output(config->output_file); 257 | ir->output(output); 258 | } 259 | else if (config->emit_code == "X64") { 260 | std::ofstream output(config->output_file); 261 | CodeGenX64 codegen(ir.release()); 262 | codegen.generate(output); 263 | } 264 | else if (config->emit_code == "GCC") { 265 | auto temp_name = ".__temp_asm__" + config->output_file + ".s"; 266 | auto runtime_path = get_env("CYAN_RUNTIME_DIR"); 267 | if (!runtime_path.length()) { 268 | config->error_collector->error(Exception("Cannot find runtime lib in $CYAN_RUNTIME_DIR")); 269 | exit(-1); 270 | } 271 | 272 | std::ofstream output(temp_name); 273 | CodeGenX64 codegen(ir.release()); 274 | codegen.generate(output); 275 | 276 | std::system(("gcc -m64 -o " + config->output_file + " " + temp_name + " " + runtime_path).c_str()); 277 | std::system(("rm " + temp_name).c_str()); 278 | } 279 | else { 280 | config->error_collector->error(Exception("unknown emitting: " + config->emit_code)); 281 | } 282 | 283 | return 0; 284 | } 285 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(googletest) 2 | 3 | include_directories(${gtest_SOURCE_DIR}/include) 4 | include_directories(${gtest_SOURCE_DIR}) 5 | 6 | add_definitions(-D__PROJECT_DIR__="${PROJECT_SOURCE_DIR}") 7 | 8 | add_executable(test_all googletest/src/gtest-all.cc parser_test.cpp codegen_x64_test.cpp inliner_test.cpp dep_analyzer_test.cpp mem2reg_test.cpp loop_marker_test.cpp inst_rewriter_test.cpp phi_eliminator_test.cpp dead_code_eliminater_test.cpp unreachable_code_elimimater.cpp combined_test.cpp) 9 | target_link_libraries(test_all gtest_main cyan) 10 | 11 | -------------------------------------------------------------------------------- /test/codegen_x64_test.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/12/16. 3 | // 4 | 5 | #include 6 | 7 | #include "gtest/gtest.h" 8 | 9 | #include "../lib/parse.hpp" 10 | #include "../lib/codegen_x64.hpp" 11 | 12 | using namespace cyan; 13 | 14 | #define define_codegen_x64_test(name, source) \ 15 | TEST(codegen_x64_test, name) \ 16 | { \ 17 | Parser *parser = new Parser(new ScreenOutputErrorCollector()); \ 18 | ASSERT_TRUE(parser->parse(source)); \ 19 | CodeGenX64 *uut = new CodeGenX64(parser->release().release()); \ 20 | std::ofstream ir_out("codegen_x64_" #name ".ir"); \ 21 | uut->get()->output(ir_out) << std::endl; \ 22 | std::ofstream as_out("codegen_x64_" #name ".s"); \ 23 | uut->generate(as_out); \ 24 | } 25 | 26 | define_codegen_x64_test(basic_test, 27 | "let a = 1 + 2;" 28 | ) 29 | 30 | define_codegen_x64_test(multi_func_test, 31 | "let a = 1 + 2;\n" 32 | "function main() : i32 {\n" 33 | " let b = 1;\n" 34 | " if (a == 2) {\n" 35 | " return b;\n" 36 | " }\n" 37 | " return a;\n" 38 | "}\n" 39 | ) 40 | 41 | define_codegen_x64_test(phi_node_test, 42 | "let a = 1 && 2 || 3 && 4;" 43 | ) 44 | 45 | define_codegen_x64_test(loop_test, 46 | "function main() {\n" 47 | " let i = 0;\n" 48 | " while (i < 10) {\n" 49 | " i = i + 1;\n" 50 | " }\n" 51 | "}\n" 52 | ) 53 | 54 | define_codegen_x64_test(register_collect_test, 55 | "function main() {\n" 56 | " let a = (1 + 2) * (1 - 2);\n" 57 | " let b = 3 * a + 4;\n" 58 | " let c = a + b;\n" 59 | "}\n" 60 | ) 61 | 62 | define_codegen_x64_test(function_call_test, 63 | "function max(a : i32, b : i32) : i32 {\n" 64 | " return a > b ? a : b;\n" 65 | "}\n" 66 | "function main() : i32 {\n" 67 | " let a = 10;\n" 68 | " let b = 5;\n" 69 | " max(a, b);\n" 70 | " return max(a, b);\n" 71 | "}\n" 72 | ) 73 | 74 | define_codegen_x64_test(too_many_registers, 75 | "let a = 1 * (2 + (3 * (4 + (5 * (6 + (7 * (8 + (9 * (10 + (11 * (12 + (13 * (14 + (15 * 15))))))))))))));" 76 | ) 77 | 78 | define_codegen_x64_test(too_many_arguments, 79 | "function callee(a : i32, b : i32, c : i32, d : i32, e : i32, f : i32, g : i32, h : i32, i : i32, j : i32) {\n" 80 | "}\n" 81 | "function main() {\n" 82 | " callee(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);\n" 83 | "}\n" 84 | ) 85 | -------------------------------------------------------------------------------- /test/combined_test.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/19/16. 3 | // 4 | 5 | #include 6 | 7 | #include "gtest/gtest.h" 8 | 9 | #include "../lib/parse.hpp" 10 | #include "../lib/inliner.hpp" 11 | #include "../lib/dep_analyzer.hpp" 12 | #include "../lib/loop_marker.hpp" 13 | #include "../lib/mem2reg.hpp" 14 | #include "../lib/inst_rewriter.hpp" 15 | #include "../lib/unreachable_code_eliminater.hpp" 16 | #include "../lib/dead_code_eliminater.hpp" 17 | 18 | using namespace cyan; 19 | 20 | TEST(combined_test, case1) 21 | { 22 | static const char SOURCE[] = 23 | "let ga = 0, gb = 0;" 24 | "function max(a : i64, b : i64) : i64 {\n" 25 | " return (a > b) ? a : b;\n" 26 | "}\n" 27 | "function min(a : i64, b : i64) : i64 {\n" 28 | " return (a < b) ? a : b;\n" 29 | "}\n" 30 | "function compare_and_swap(a : &i64, b : &i64) {\n" 31 | " let max_num = max(a, b);\n" 32 | " let min_num = min(a, b);\n" 33 | " a = max_num;\n" 34 | " b = min_num;\n" 35 | "}\n" 36 | "function main() {\n" 37 | " let a = 10, b = 15;\n" 38 | " if (1) {\n" 39 | " compare_and_swap(a, b);\n" 40 | " }\n" 41 | " else {\n" 42 | " a = 0;\n" 43 | " }\n" 44 | " ga = a;\n" 45 | " gb = b;\n" 46 | "}\n" 47 | ; 48 | 49 | Parser *parser = new Parser(new ScreenOutputErrorCollector()); 50 | ASSERT_TRUE(parser->parse(SOURCE)); 51 | 52 | auto ir = parser->release().release(); 53 | { 54 | std::ofstream parsed_out("combined_case1_parsed.ir"); 55 | ir->output(parsed_out); 56 | } 57 | 58 | ir = Inliner(ir).release(); 59 | { 60 | std::ofstream inlined_out("combined_case1_inlined.ir"); 61 | ir->output(inlined_out); 62 | } 63 | 64 | ir = DepAnalyzer(ir).release(); 65 | ir = LoopMarker(ir).release(); 66 | 67 | { 68 | std::ofstream mem2reg_out("combined_case1_mem2reg.ir"); 69 | std::ofstream mem2reg_debug_out("combined_case1_mem2reg_debug.ir"); 70 | ir = Mem2Reg(ir, mem2reg_debug_out).release(); 71 | ir->output(mem2reg_out); 72 | } 73 | 74 | ir = PhiEliminator(ir).release(); 75 | { 76 | std::ofstream phi_eliminated_out("combined_case1_phi_eliminated.ir"); 77 | ir->output(phi_eliminated_out); 78 | } 79 | 80 | ir = InstRewriter(ir).release(); 81 | { 82 | std::ofstream inst_rewriten_out("combined_case1_inst_rewriten.ir"); 83 | ir->output(inst_rewriten_out); 84 | } 85 | 86 | ir = UnreachableCodeEliminater(ir).release(); 87 | { 88 | std::ofstream unreachable_eliminated_out("combined_case1_unreachable_eliminated.ir"); 89 | ir->output(unreachable_eliminated_out); 90 | } 91 | 92 | ir = DepAnalyzer(ir).release(); 93 | ir = LoopMarker(ir).release(); 94 | ir = PhiEliminator(ir).release(); 95 | { 96 | std::ofstream phi_eliminated_2_out("combined_case1_phi_eliminated_2.ir"); 97 | ir->output(phi_eliminated_2_out); 98 | } 99 | 100 | ir = DeadCodeEliminater(ir).release(); 101 | { 102 | std::ofstream dead_code_eliminated("combined_case1_dead_code_eliminated.ir"); 103 | ir->output(dead_code_eliminated); 104 | } 105 | } 106 | 107 | TEST(combined_test, case2) 108 | { 109 | static const char SOURCE[] = 110 | "function partition(a : i64[], lo : i64, hi : i64) : i64 {\n" 111 | " let pivot = a[hi];\n" 112 | " let i = lo;\n" 113 | " let j = lo;\n" 114 | " while (j < hi) {\n" 115 | " if (a[j] < pivot) {\n" 116 | " let t = a[i];\n" 117 | " a[i] = a[j];\n" 118 | " a[j] = t;\n" 119 | " i = i + 1;\n" 120 | " }\n" 121 | " j = j + 1;\n" 122 | " }\n" 123 | " let t = a[i];\n" 124 | " a[i] = a[j];\n" 125 | " a[j] = t;\n" 126 | " return i;\n" 127 | "}\n" 128 | "function quicksort(a : i64[], lo : i64, hi : i64) {\n" 129 | " if (lo < hi) {\n" 130 | " let p = partition(a, lo, hi);\n" 131 | " quicksort(a, lo, p - 1);\n" 132 | " quicksort(a, p + 1, hi);\n" 133 | " }\n" 134 | "}\n" 135 | "function main(a : i64[], n : i64) {\n" 136 | " quicksort(a, 0, n - 1);\n" 137 | "}\n" 138 | ; 139 | 140 | Parser *parser = new Parser(new ScreenOutputErrorCollector()); 141 | ASSERT_TRUE(parser->parse(SOURCE)); 142 | 143 | auto ir = parser->release().release(); 144 | { 145 | std::ofstream parsed_out("combined_case2_parsed.ir"); 146 | ir->output(parsed_out); 147 | } 148 | 149 | ir = Inliner(ir).release(); 150 | { 151 | std::ofstream inlined_out("combined_case2_inlined.ir"); 152 | ir->output(inlined_out); 153 | } 154 | 155 | ir = DepAnalyzer(ir).release(); 156 | ir = LoopMarker(ir).release(); 157 | 158 | { 159 | std::ofstream mem2reg_out("combined_case2_mem2reg.ir"); 160 | std::ofstream mem2reg_debug_out("combined_case2_mem2reg_debug.ir"); 161 | ir = Mem2Reg(ir, mem2reg_debug_out).release(); 162 | ir->output(mem2reg_out); 163 | } 164 | 165 | ir = PhiEliminator(ir).release(); 166 | { 167 | std::ofstream phi_eliminated_out("combined_case2_phi_eliminated.ir"); 168 | ir->output(phi_eliminated_out); 169 | } 170 | 171 | ir = InstRewriter(ir).release(); 172 | { 173 | std::ofstream inst_rewriten_out("combined_case2_inst_rewriten.ir"); 174 | ir->output(inst_rewriten_out); 175 | } 176 | 177 | ir = UnreachableCodeEliminater(ir).release(); 178 | { 179 | std::ofstream unreachable_eliminated_out("combined_case2_unreachable_eliminated.ir"); 180 | ir->output(unreachable_eliminated_out); 181 | } 182 | 183 | ir = DepAnalyzer(ir).release(); 184 | ir = LoopMarker(ir).release(); 185 | ir = PhiEliminator(ir).release(); 186 | { 187 | std::ofstream phi_eliminated_2_out("combined_case2_phi_eliminated_2.ir"); 188 | ir->output(phi_eliminated_2_out); 189 | } 190 | 191 | ir = DeadCodeEliminater(ir).release(); 192 | { 193 | std::ofstream dead_code_eliminated("combined_case2_dead_code_eliminated.ir"); 194 | ir->output(dead_code_eliminated); 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /test/dead_code_eliminater_test.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/19/16. 3 | // 4 | 5 | #include 6 | 7 | #include "gtest/gtest.h" 8 | 9 | #include "../lib/parse.hpp" 10 | #include "../lib/dep_analyzer.hpp" 11 | #include "../lib/inst_rewriter.hpp" 12 | #include "../lib/dead_code_eliminater.hpp" 13 | 14 | using namespace cyan; 15 | 16 | TEST(dead_code_eliminater_test, basic_test) 17 | { 18 | static const char SOURCE[] = 19 | "let a = 1 + 2 * 3 / 4;" 20 | ; 21 | 22 | Parser *parser = new Parser(new ScreenOutputErrorCollector()); 23 | ASSERT_TRUE(parser->parse(SOURCE)); 24 | 25 | std::ofstream original_out("dead_code_eliminater_basic_original.ir"); 26 | auto ir = parser->release().release(); 27 | ir = InstRewriter(ir).release(); 28 | ir->output(original_out); 29 | 30 | std::ofstream optimized_out("dead_code_eliminater_basic_optimized.ir"); 31 | ir = DeadCodeEliminater(ir).release(); 32 | ir->output(optimized_out); 33 | } 34 | -------------------------------------------------------------------------------- /test/dep_analyzer_test.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/16/16. 3 | // 4 | 5 | #include 6 | #include "gtest/gtest.h" 7 | 8 | #include "../lib/parse.hpp" 9 | #include "../lib/dep_analyzer.hpp" 10 | 11 | using namespace cyan; 12 | 13 | TEST(dep_analyzer_test, basic_test) 14 | { 15 | static const char SOURCE[] = 16 | "let a = (1 && 2) || (3 && 4);" 17 | ; 18 | 19 | Parser *parser = new Parser(new ScreenOutputErrorCollector()); 20 | ASSERT_TRUE(parser->parse(SOURCE)); 21 | 22 | std::ofstream original_out("dep_analyzer_basic_test.ir"); 23 | auto ir = parser->release().release(); 24 | ir->output(original_out); 25 | 26 | std::ofstream analyzed_out("dep_analyzer_basic_test_analyze_result.txt"); 27 | DepAnalyzer(ir).outputResult(analyzed_out); 28 | } 29 | 30 | TEST(dep_analyzer_test, loop_test) 31 | { 32 | static const char SOURCE[] = 33 | "function main() {\n" 34 | " let i = 0;\n" 35 | " while (i < 10) {\n" 36 | " if (i > 5) break;\n" 37 | " i = i + 1;\n" 38 | " }\n" 39 | "}\n" 40 | ; 41 | 42 | Parser *parser = new Parser(new ScreenOutputErrorCollector()); 43 | ASSERT_TRUE(parser->parse(SOURCE)); 44 | 45 | std::ofstream original_out("dep_analyzer_loop_test.ir"); 46 | auto ir = parser->release().release(); 47 | ir->output(original_out); 48 | 49 | std::ofstream analyzed_out("dep_analyzer_loop_test_analyze_result.txt"); 50 | DepAnalyzer(ir).outputResult(analyzed_out); 51 | } 52 | -------------------------------------------------------------------------------- /test/inliner_test.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Clarkok on 5/15/16 3 | // 4 | 5 | #include 6 | 7 | #include "gtest/gtest.h" 8 | 9 | #include "../lib/parse.hpp" 10 | #include "../lib/inliner.hpp" 11 | 12 | using namespace cyan; 13 | 14 | TEST(inliner_test, function_test) 15 | { 16 | static const char SOURCE[] = 17 | "function max(a : i64, b : i64) : i64 {\n" 18 | " return (a > b) ? a : b;\n" 19 | "}\n" 20 | "function min(a : i64, b : i64) : i64 {\n" 21 | " return (a < b) ? a : b;\n" 22 | "}\n" 23 | "function compare_and_swap(a : &i64, b : &i64) {\n" 24 | " let max_num = max(a, b);\n" 25 | " let min_num = min(a, b);\n" 26 | " a = max_num;\n" 27 | " b = min_num;\n" 28 | "}\n" 29 | "function main() {\n" 30 | " let a = 10, b = 15;\n" 31 | " compare_and_swap(a, b);\n" 32 | "}\n"; 33 | 34 | Parser *parser = new Parser(new ScreenOutputErrorCollector()); 35 | ASSERT_TRUE(parser->parse(SOURCE)); 36 | 37 | std::ofstream original_out("inliner_function_test_original.ir"); 38 | auto ir = parser->release().release(); 39 | ir->output(original_out); 40 | 41 | Inliner *uut = new Inliner(ir); 42 | 43 | std::ofstream call_graph_out("inliner_function_test_call_graph.txt"); 44 | uut->outputCallingGraph(call_graph_out); 45 | 46 | std::ofstream optimized_out("inliner_function_test_optimized.ir"); 47 | uut->release()->output(optimized_out); 48 | } 49 | 50 | TEST(inliner_test, method_test) 51 | { 52 | static const char SOURCE[] = 53 | "concept Person {\n" 54 | " function getAge() : i32;\n" 55 | "}\n" 56 | "struct Student {\n" 57 | " age : i32\n" 58 | "}\n" 59 | "impl Student : Person {\n" 60 | " function getAge() : i32{\n" 61 | " return this.age;\n" 62 | " }\n" 63 | "}\n" 64 | "function main(p : Student) {\n" 65 | " p.Person.getAge();\n" 66 | "}\n" 67 | ; 68 | 69 | Parser *parser = new Parser(new ScreenOutputErrorCollector()); 70 | ASSERT_TRUE(parser->parse(SOURCE)); 71 | 72 | std::ofstream original_out("inliner_method_test_original.ir"); 73 | auto ir = parser->release().release(); 74 | ir->output(original_out); 75 | 76 | Inliner *uut = new Inliner(ir); 77 | 78 | std::ofstream call_graph_out("inliner_method_test_call_graph.txt"); 79 | uut->outputCallingGraph(call_graph_out); 80 | 81 | std::ofstream optimized_out("inliner_method_test_optimized.ir"); 82 | uut->release()->output(optimized_out); 83 | } 84 | -------------------------------------------------------------------------------- /test/inst_rewriter_test.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/19/16 3 | // 4 | 5 | #include 6 | 7 | #include "gtest/gtest.h" 8 | 9 | #include "../lib/parse.hpp" 10 | #include "../lib/dep_analyzer.hpp" 11 | #include "../lib/loop_marker.hpp" 12 | #include "../lib/mem2reg.hpp" 13 | #include "../lib/inst_rewriter.hpp" 14 | #include "../lib/phi_eliminator.hpp" 15 | 16 | using namespace cyan; 17 | 18 | TEST(inst_rewriter_test, constant_prop) 19 | { 20 | static const char SOURCE[] = 21 | "let a = 1 + 2 * 3 / 4;" 22 | ; 23 | 24 | Parser *parser = new Parser(new ScreenOutputErrorCollector()); 25 | ASSERT_TRUE(parser->parse(SOURCE)); 26 | 27 | std::ofstream original_out("inst_rewriter_constant_prop_original.ir"); 28 | auto ir = parser->release().release(); 29 | ir->output(original_out); 30 | 31 | std::ofstream optimized_out("inst_rewriter_constant_prop_optimized.ir"); 32 | ir = InstRewriter(ir).release(); 33 | ir->output(optimized_out); 34 | } 35 | 36 | TEST(inst_rewriter_test, common_expression) 37 | { 38 | static const char SOURCE[] = 39 | "function main(a : i64, b : i64) {\n" 40 | " let t1 = a;\n" 41 | " let t2 = b;\n" 42 | " let t3 = (t1 + t2) * (t1 + t2);\n" 43 | "}\n" 44 | ; 45 | 46 | Parser *parser = new Parser(new ScreenOutputErrorCollector()); 47 | ASSERT_TRUE(parser->parse(SOURCE)); 48 | 49 | std::ofstream original_out("inst_rewriter_common_expression_original.ir"); 50 | auto ir = Mem2Reg( 51 | DepAnalyzer( 52 | parser->release().release() 53 | ).release() 54 | ).release(); 55 | ir->output(original_out); 56 | 57 | std::ofstream optimized_out("inst_rewriter_common_expression_optimized.ir"); 58 | ir = InstRewriter(ir).release(); 59 | ir->output(optimized_out); 60 | } 61 | 62 | TEST(inst_rewriter_test, loop_invariant) 63 | { 64 | static const char SOURCE[] = 65 | "function main(a : i64, b : i64) {\n" 66 | " let i = 0;\n" 67 | " let ta = a, tb = b;\n" 68 | " while (i < 10) {\n" 69 | " i = i + ta * tb;\n" 70 | " }\n" 71 | "}\n" 72 | ; 73 | 74 | Parser *parser = new Parser(new ScreenOutputErrorCollector()); 75 | ASSERT_TRUE(parser->parse(SOURCE)); 76 | 77 | std::ofstream original_out("inst_rewriter_loop_invariant_original.ir"); 78 | auto ir = LoopMarker( 79 | PhiEliminator( 80 | Mem2Reg( 81 | DepAnalyzer( 82 | parser->release().release() 83 | ).release() 84 | ).release() 85 | ).release() 86 | ).release(); 87 | ir->output(original_out); 88 | 89 | std::ofstream optimized_out("inst_rewriter_loop_invariant_optimized.ir"); 90 | ir = InstRewriter(ir).release(); 91 | ir->output(optimized_out); 92 | } -------------------------------------------------------------------------------- /test/loop_marker_test.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/17/16 3 | // 4 | 5 | #include 6 | #include "gtest/gtest.h" 7 | 8 | #include "../lib/parse.hpp" 9 | #include "../lib/dep_analyzer.hpp" 10 | #include "../lib/loop_marker.hpp" 11 | 12 | using namespace cyan; 13 | 14 | TEST(loop_marker_test, basic_test) 15 | { 16 | static const char SOURCE[] = 17 | "function main() {\n" 18 | " let i = 0;\n" 19 | " while (i < 10) {\n" 20 | " if (i > 5) break;\n" 21 | " i = i + 1;\n" 22 | " }\n" 23 | "}\n" 24 | ; 25 | 26 | Parser *parser = new Parser(new ScreenOutputErrorCollector()); 27 | ASSERT_TRUE(parser->parse(SOURCE)); 28 | 29 | std::ofstream original_out("loop_marker_basic_test.ir"); 30 | auto ir = parser->release().release(); 31 | ir->output(original_out); 32 | 33 | std::ofstream analyzed_out("loop_marker_basic_test_analyze_result.txt"); 34 | auto dep_analyzer = new DepAnalyzer(ir); 35 | dep_analyzer->outputResult(analyzed_out); 36 | 37 | LoopMarker(dep_analyzer->release()).outputResult(analyzed_out); 38 | } 39 | 40 | TEST(loop_marker_test, nested_loop_test) 41 | { 42 | static const char SOURCE[] = 43 | "function main() {\n" 44 | " let i = 0;\n" 45 | " while (i < 10) {\n" 46 | " if (i > 5) break;\n" 47 | " i = i + 1;\n" 48 | " let j = 0;\n" 49 | " while (j < i) {\n" 50 | " j = j + i;\n" 51 | " }\n" 52 | " }\n" 53 | "}\n" 54 | ; 55 | 56 | Parser *parser = new Parser(new ScreenOutputErrorCollector()); 57 | ASSERT_TRUE(parser->parse(SOURCE)); 58 | 59 | std::ofstream original_out("loop_marker_nested_loop_test.ir"); 60 | auto ir = parser->release().release(); 61 | ir->output(original_out); 62 | 63 | std::ofstream analyzed_out("loop_marker_nested_loop_test_analyze_result.txt"); 64 | auto dep_analyzer = new DepAnalyzer(ir); 65 | dep_analyzer->outputResult(analyzed_out); 66 | 67 | LoopMarker(dep_analyzer->release()).outputResult(analyzed_out); 68 | } 69 | -------------------------------------------------------------------------------- /test/mem2reg_test.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/16/16. 3 | // 4 | 5 | #include 6 | #include "gtest/gtest.h" 7 | 8 | #include "../lib/parse.hpp" 9 | #include "../lib/inliner.hpp" 10 | #include "../lib/dep_analyzer.hpp" 11 | #include "../lib/mem2reg.hpp" 12 | 13 | using namespace cyan; 14 | 15 | TEST(mem2reg_test, basic_test) 16 | { 17 | static const char SOURCE[] = 18 | "function main() {\n" 19 | " let i = 0;\n" 20 | " while (i < 10) {\n" 21 | " i = i + 1;\n" 22 | " }\n" 23 | "}\n" 24 | ; 25 | 26 | Parser *parser = new Parser(new ScreenOutputErrorCollector()); 27 | ASSERT_TRUE(parser->parse(SOURCE)); 28 | 29 | std::ofstream original_out("mem2reg_basic_test_original.ir"); 30 | auto ir = parser->release().release(); 31 | ir->output(original_out); 32 | 33 | std::ofstream analyzed_out("mem2reg_basic_test_analyze_result.ir"); 34 | std::ofstream optimized_out("mem2reg_basic_test_optimized.ir"); 35 | Mem2Reg(DepAnalyzer(ir).release(), analyzed_out).release()->output(optimized_out); 36 | } 37 | 38 | TEST(mem2reg_test, branch_in_loop) 39 | { 40 | static const char SOURCE[] = 41 | "function main() {\n" 42 | " let i = 0;\n" 43 | " let a = 0;\n" 44 | " while (i < 10) {\n" 45 | " if (i < 5) {\n" 46 | " a = a + 1;\n" 47 | " }\n" 48 | " else {\n" 49 | " a = a - 1;\n" 50 | " }\n" 51 | " }\n" 52 | "}\n" 53 | ; 54 | 55 | Parser *parser = new Parser(new ScreenOutputErrorCollector()); 56 | ASSERT_TRUE(parser->parse(SOURCE)); 57 | 58 | std::ofstream original_out("mem2reg_branch_in_loop_original.ir"); 59 | auto ir = parser->release().release(); 60 | ir->output(original_out); 61 | 62 | std::ofstream analyzed_out("mem2reg_branch_in_loop_analyze_result.ir"); 63 | std::ofstream optimized_out("mem2reg_branch_in_loop_optimized.ir"); 64 | Mem2Reg(DepAnalyzer(ir).release(), analyzed_out).release()->output(optimized_out); 65 | } 66 | 67 | TEST(mem2reg_test, scope_in_branch) 68 | { 69 | static const char SOURCE[] = 70 | "function main() {\n" 71 | " let t = 1;" 72 | " if (1) {\n" 73 | " let a = 2;\n" 74 | " t = a;\n" 75 | " }\n" 76 | " else {\n" 77 | " let b = 3;\n" 78 | " t = b;\n" 79 | " }\n" 80 | " let l = t;\n" 81 | "}\n" 82 | ; 83 | 84 | Parser *parser = new Parser(new ScreenOutputErrorCollector()); 85 | ASSERT_TRUE(parser->parse(SOURCE)); 86 | 87 | std::ofstream original_out("mem2reg_scope_in_branch_original.ir"); 88 | auto ir = parser->release().release(); 89 | ir->output(original_out); 90 | 91 | std::ofstream analyzed_out("mem2reg_scope_in_branch_analyze_result.ir"); 92 | std::ofstream optimized_out("mem2reg_scope_in_branch_optimized.ir"); 93 | Mem2Reg(DepAnalyzer(ir).release(), analyzed_out).release()->output(optimized_out); 94 | } 95 | 96 | TEST(mem2reg_test, scope_in_loop) 97 | { 98 | static const char SOURCE[] = 99 | "function main() {\n" 100 | "let a = 1, b = 2;\n" 101 | " while (1) {\n" 102 | " if (1) {\n" 103 | " let t = a;\n" 104 | " a = b;\n" 105 | " b = t;\n" 106 | " }\n" 107 | " }\n" 108 | "}\n" 109 | ; 110 | 111 | Parser *parser = new Parser(new ScreenOutputErrorCollector()); 112 | ASSERT_TRUE(parser->parse(SOURCE)); 113 | 114 | std::ofstream original_out("mem2reg_scope_in_loop_original.ir"); 115 | auto ir = parser->release().release(); 116 | ir->output(original_out); 117 | 118 | std::ofstream analyzed_out("mem2reg_scope_in_loop_analyze_result.ir"); 119 | std::ofstream optimized_out("mem2reg_scope_in_loop_optimized.ir"); 120 | Mem2Reg(DepAnalyzer(ir).release(), analyzed_out).release()->output(optimized_out); 121 | } 122 | 123 | TEST(mem2reg_test, after_inline) 124 | { 125 | static const char SOURCE[] = 126 | "let a = 10, b = 15;\n" 127 | "function max(a : i64, b : i64) : i64 {\n" 128 | " return (a > b) ? a : b;\n" 129 | "}\n" 130 | "function min(a : i64, b : i64) : i64 {\n" 131 | " return (a < b) ? a : b;\n" 132 | "}\n" 133 | "function compare_and_swap(a : &i64, b : &i64) {\n" 134 | " let max_num = max(a, b);\n" 135 | " let min_num = min(a, b);\n" 136 | " a = max_num;\n" 137 | " b = min_num;\n" 138 | "}\n" 139 | "function main() {\n" 140 | " compare_and_swap(a, b);\n" 141 | "}\n"; 142 | 143 | Parser *parser = new Parser(new ScreenOutputErrorCollector()); 144 | ASSERT_TRUE(parser->parse(SOURCE)); 145 | 146 | std::ofstream original_out("mem2reg_after_inline_test_original.ir"); 147 | auto ir = parser->release().release(); 148 | ir->output(original_out); 149 | 150 | ir = Inliner(ir).release(); 151 | std::ofstream after_inliner_out("mem2reg_after_inline_test_inlined.ir"); 152 | ir->output(after_inliner_out); 153 | 154 | std::ofstream analyzed_out("mem2reg_after_inline_test_analyze_result.ir"); 155 | 156 | auto dep_analyzer = new DepAnalyzer(ir); 157 | dep_analyzer->outputResult(analyzed_out); 158 | 159 | std::ofstream optimized_out("mem2reg_after_inline_test_optimized.ir"); 160 | Mem2Reg(dep_analyzer->release(), analyzed_out).release()->output(optimized_out); 161 | } 162 | -------------------------------------------------------------------------------- /test/parser_test.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Clarkok on 16/5/3. 3 | // 4 | 5 | #include "gtest/gtest.h" 6 | 7 | #include "../lib/parse.hpp" 8 | 9 | using namespace cyan; 10 | 11 | TEST(parser_test, let_stmt) 12 | { 13 | static const char SOURCE[] = 14 | "let a = 1 + 2;"; 15 | 16 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 17 | ASSERT_TRUE(uut->parse(SOURCE)); 18 | 19 | // uut->release()->output(std::cout); 20 | } 21 | 22 | TEST(parser_test, let_define_stmt) 23 | { 24 | static const char SOURCE[] = 25 | "let a = 1 + 2, b = a, c = a + b;"; 26 | 27 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 28 | ASSERT_TRUE(uut->parse(SOURCE)); 29 | 30 | // uut->release()->output(std::cout); 31 | } 32 | 33 | TEST(parser_test, logic_and_test) 34 | { 35 | static const char SOURCE[] = 36 | "let a = 1 && 2 && 0;"; 37 | 38 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 39 | ASSERT_TRUE(uut->parse(SOURCE)); 40 | 41 | // uut->release()->output(std::cout); 42 | } 43 | 44 | TEST(parser_test, logic_or_test) 45 | { 46 | static const char SOURCE[] = 47 | "let a = 1 || 2 || 3;"; 48 | 49 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 50 | ASSERT_TRUE(uut->parse(SOURCE)); 51 | 52 | // uut->release()->output(std::cout); 53 | } 54 | 55 | TEST(parser_test, multiple_let_test) 56 | { 57 | static const char SOURCE[] = 58 | "let a = 1;\n" 59 | "let b = a + 1;\n" 60 | "let c = a + b;\n" 61 | ; 62 | 63 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 64 | ASSERT_TRUE(uut->parse(SOURCE)); 65 | 66 | // uut->release()->output(std::cout); 67 | } 68 | 69 | TEST(parser_test, function_test) 70 | { 71 | static const char SOURCE[] = 72 | "function test(a : i32, b : i32) : i32 {\n" 73 | " let t0 = 1;\n" 74 | " let t1 = t0 + a * b;\n" 75 | "}\n" 76 | ; 77 | 78 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 79 | ASSERT_TRUE(uut->parse(SOURCE)); 80 | 81 | // uut->release()->output(std::cout); 82 | } 83 | 84 | TEST(parser_test, multiple_functions_test) 85 | { 86 | static const char SOURCE[] = 87 | "function func1(a : i32, b : i32) {\n" 88 | " let t = a;\n" 89 | "}\n" 90 | "function func2() : i32 {\n" 91 | " let t = 1;\n" 92 | "}\n" 93 | "function func3() {}\n" 94 | ; 95 | 96 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 97 | ASSERT_TRUE(uut->parse(SOURCE)); 98 | 99 | // uut->release()->output(std::cout); 100 | } 101 | 102 | TEST(parser_test, function_forward_decl_test) 103 | { 104 | static const char SOURCE[] = 105 | "function test1(a : i32, b : i32);\n" 106 | "function test2() { }\n" 107 | "function test1(a : i32, b : i32) {\n" 108 | "}\n" 109 | ; 110 | 111 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 112 | ASSERT_TRUE(uut->parse(SOURCE)); 113 | 114 | // uut->release()->output(std::cout); 115 | } 116 | 117 | TEST(parser_test, return_test) 118 | { 119 | static const char SOURCE[] = 120 | "function test_i32(a : i32, b : i32) : i32 {\n" 121 | " return a;\n" 122 | "}\n" 123 | "function test(a : i32, b : i32) {\n" 124 | " return;\n" 125 | "}\n" 126 | ; 127 | 128 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 129 | ASSERT_TRUE(uut->parse(SOURCE)); 130 | 131 | // uut->release()->output(std::cout); 132 | } 133 | 134 | TEST(parser_test, block_test) 135 | { 136 | static const char SOURCE[] = 137 | "function main() {\n" 138 | " let a = 0;\n" 139 | " let b = a;\n" 140 | " {\n" 141 | " let a = 1;\n" 142 | " b = a;\n" 143 | " }\n" 144 | " b = a;\n" 145 | "}\n" 146 | ; 147 | 148 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 149 | ASSERT_TRUE(uut->parse(SOURCE)); 150 | 151 | // uut->release()->output(std::cout); 152 | } 153 | 154 | TEST(parser_test, if_else_test) 155 | { 156 | static const char SOURCE[] = 157 | "function main() {\n" 158 | " let a = 1,\n" 159 | " b = 2,\n" 160 | " c = 0;\n" 161 | " if (1) {\n" 162 | " c = a + b;\n" 163 | " }\n" 164 | " else {\n" 165 | " c = a - b;\n" 166 | " }\n" 167 | "}\n" 168 | ; 169 | 170 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 171 | ASSERT_TRUE(uut->parse(SOURCE)); 172 | 173 | // uut->release()->output(std::cout); 174 | } 175 | 176 | TEST(parser_test, single_if_test) 177 | { 178 | static const char SOURCE[] = 179 | "function main() {\n" 180 | " let a = 1;\n" 181 | " if (a)\n" 182 | " a = 0;\n" 183 | " if (a) {\n" 184 | " a = 1;\n" 185 | " }\n" 186 | "}\n" 187 | ; 188 | 189 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 190 | ASSERT_TRUE(uut->parse(SOURCE)); 191 | 192 | // uut->release()->output(std::cout); 193 | } 194 | 195 | TEST(parser_test, nested_if_test) 196 | { 197 | static const char SOURCE[] = 198 | "function main() {\n" 199 | " let a = 0;\n" 200 | " if (1)\n" 201 | " if (2)\n" 202 | " a = 1;\n" 203 | " else\n" 204 | " a = 2;\n" 205 | " else\n" 206 | " if (3)\n" 207 | " a = 3;\n" 208 | " else\n" 209 | " a = 4;\n" 210 | "}\n" 211 | ; 212 | 213 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 214 | ASSERT_TRUE(uut->parse(SOURCE)); 215 | 216 | // uut->release()->output(std::cout); 217 | } 218 | 219 | TEST(parser_test, while_test) 220 | { 221 | static const char SOURCE[] = 222 | "function main() {\n" 223 | " let i = 0;\n" 224 | " while (i < 10) {\n" 225 | " i = i + 1;\n" 226 | " }\n" 227 | "}" 228 | ; 229 | 230 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 231 | ASSERT_TRUE(uut->parse(SOURCE)); 232 | 233 | // uut->release()->output(std::cout); 234 | } 235 | 236 | TEST(parser_test, continue_test) 237 | { 238 | static const char SOURCE[] = 239 | "function main() {\n" 240 | " let i = 0;\n" 241 | " while (i < 10) {\n" 242 | " i = i + 1;\n" 243 | " if (i < 5)\n" 244 | " continue;\n" 245 | " else\n" 246 | " i = i + 1;\n" 247 | " }\n" 248 | "}" 249 | ; 250 | 251 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 252 | ASSERT_TRUE(uut->parse(SOURCE)); 253 | 254 | // uut->release()->output(std::cout); 255 | } 256 | 257 | TEST(parser_test, break_test) 258 | { 259 | static const char SOURCE[] = 260 | "function main() {\n" 261 | " let i = 0;\n" 262 | " while (i < 10) {\n" 263 | " i = i + 1;\n" 264 | " if (i < 5)\n" 265 | " break;\n" 266 | " else\n" 267 | " i = i + 1;\n" 268 | " }\n" 269 | "}" 270 | ; 271 | 272 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 273 | ASSERT_TRUE(uut->parse(SOURCE)); 274 | 275 | // uut->release()->output(std::cout); 276 | } 277 | 278 | TEST(parser_test, nested_loop_test) 279 | { 280 | static const char SOURCE[] = 281 | "function main() {\n" 282 | " let i = 0;\n" 283 | " while (i < 10) {\n" 284 | " i = i + 1;\n" 285 | " let j = i - 1;\n" 286 | " while (1) {\n" 287 | " if (j == 0) break;\n" 288 | " }\n" 289 | " if (j == 0) continue;\n" 290 | " }\n" 291 | "}" 292 | ; 293 | 294 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 295 | ASSERT_TRUE(uut->parse(SOURCE)); 296 | 297 | // uut->release()->output(std::cout); 298 | } 299 | 300 | TEST(parser_test, concept_test) 301 | { 302 | static const char SOURCE[] = 303 | "concept Person {\n" 304 | " function getID() : u32;\n" 305 | " function getAge() : u32;\n" 306 | "}\n" 307 | "concept Student : Person {\n" 308 | " function getID() : u32 { return 0; }\n" 309 | "}\n" 310 | ; 311 | 312 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 313 | ASSERT_TRUE(uut->parse(SOURCE)); 314 | 315 | // uut->release()->output(std::cout); 316 | } 317 | 318 | TEST(parser_test, struct_test) 319 | { 320 | static const char SOURCE[] = 321 | "struct Student {\n" 322 | " id : i32,\n" 323 | " age : i32\n" 324 | "}\n" 325 | ; 326 | 327 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 328 | ASSERT_TRUE(uut->parse(SOURCE)); 329 | 330 | // uut->release()->output(std::cout); 331 | } 332 | 333 | TEST(parser_test, struct_member_test) 334 | { 335 | static const char SOURCE[] = 336 | "struct Student {\n" 337 | " id : i32,\n" 338 | " age : i32\n" 339 | "}\n" 340 | "function main(st : Student) : i32 {\n" 341 | " return st.id;\n" 342 | "}\n" 343 | ; 344 | 345 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 346 | ASSERT_TRUE(uut->parse(SOURCE)); 347 | 348 | // uut->release()->output(std::cout); 349 | } 350 | 351 | TEST(parser_test, struct_member_struct_test) 352 | { 353 | static const char SOURCE[] = 354 | "struct LinkedList {\n" 355 | " next : LinkedList,\n" 356 | " value : i32\n" 357 | "}\n" 358 | "function main(list : LinkedList) : i32 {\n" 359 | " return list.next.next.value;\n" 360 | "}\n" 361 | ; 362 | 363 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 364 | ASSERT_TRUE(uut->parse(SOURCE)); 365 | 366 | // uut->release()->output(std::cout); 367 | } 368 | 369 | TEST(parser_test, function_call_test) 370 | { 371 | static const char SOURCE[] = 372 | "function test(a : i32, b : i32) : i32{\n" 373 | " if (a > b) return a;\n" 374 | " else return b;\n" 375 | "}\n" 376 | "function main() {\n" 377 | " test(1, 2);\n" 378 | " main();\n" 379 | "}\n" 380 | ; 381 | 382 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 383 | ASSERT_TRUE(uut->parse(SOURCE)); 384 | 385 | // uut->release()->output(std::cout); 386 | } 387 | 388 | TEST(parser_test, method_call_test) 389 | { 390 | static const char SOURCE[] = 391 | "concept Person {\n" 392 | " function getID() : u32;\n" 393 | "}\n" 394 | "function main(st : Person) : u32 {\n" 395 | " return st.getID();\n" 396 | "}\n" 397 | ; 398 | 399 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 400 | ASSERT_TRUE(uut->parse(SOURCE)); 401 | 402 | // uut->release()->output(std::cout); 403 | } 404 | 405 | TEST(parser_test, impl_test) 406 | { 407 | static const char SOURCE[] = 408 | "concept Person {\n" 409 | " function getID() : u32;\n" 410 | "}\n" 411 | "struct Student {\n" 412 | " id : u32\n" 413 | "}\n" 414 | "impl Student : Person {\n" 415 | " function getID() : u32 {\n" 416 | " return this.id;\n" 417 | " }\n" 418 | "}\n" 419 | "function main(st : Person) : u32 {\n" 420 | " return st.getID();\n" 421 | "}\n" 422 | ; 423 | 424 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 425 | ASSERT_TRUE(uut->parse(SOURCE)); 426 | 427 | // uut->release()->output(std::cout); 428 | } 429 | 430 | TEST(parser_test, call_concept_method_on_struct_test) 431 | { 432 | static const char SOURCE[] = 433 | "concept Person {\n" 434 | " function getID() : u32;\n" 435 | "}\n" 436 | "struct Student {\n" 437 | " id : u32\n" 438 | "}\n" 439 | "impl Student : Person {\n" 440 | " function getID() : u32 {\n" 441 | " return this.id;\n" 442 | " }\n" 443 | "}\n" 444 | "function main(st : Student) : u32 {\n" 445 | " return st.Person.getID();\n" 446 | "}\n" 447 | ; 448 | 449 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 450 | ASSERT_TRUE(uut->parse(SOURCE)); 451 | 452 | // uut->release()->output(std::cout); 453 | } 454 | 455 | TEST(parser_test, left_value_argument_test) 456 | { 457 | static const char SOURCE[] = 458 | "function swap(a : &i32, b : &i32) {\n" 459 | " let t = a;\n" 460 | " a = b;\n" 461 | " b = t;\n" 462 | "}\n" 463 | "function main() {\n" 464 | " let a = 1, b = 2;\n" 465 | " swap(a, b);\n" 466 | "}\n" 467 | ; 468 | 469 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 470 | ASSERT_TRUE(uut->parse(SOURCE)); 471 | 472 | // uut->release()->output(std::cout); 473 | } 474 | 475 | TEST(parser_test, array_index_test) 476 | { 477 | static const char SOURCE[] = 478 | "function test(a : i64[], b : i64) : i64 {\n" 479 | " return a[b];\n" 480 | "}\n" 481 | ; 482 | 483 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 484 | ASSERT_TRUE(uut->parse(SOURCE)); 485 | 486 | // uut->release()->output(std::cout); 487 | } 488 | 489 | 490 | TEST(parser_test, new_delete_test) 491 | { 492 | static const char SOURCE[] = 493 | "struct Student {\n" 494 | " id : i32,\n" 495 | " age : i32\n" 496 | "}\n" 497 | "function main() {\n" 498 | " let t = new Student;\n" 499 | " delete t;\n" 500 | " let b = new Student[10];\n" 501 | " delete b;\n" 502 | " let s = new i8[10];\n" 503 | " delete s;\n" 504 | " let m = new Student[][20];\n" 505 | " delete m;\n" 506 | "}\n" 507 | ; 508 | 509 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 510 | ASSERT_TRUE(uut->parse(SOURCE)); 511 | 512 | // uut->release()->output(std::cout); 513 | } 514 | 515 | TEST(parser_test, parse_file_test) 516 | { 517 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 518 | ASSERT_TRUE(uut->parseFile(__PROJECT_DIR__ "/example/example.cy")); 519 | 520 | // uut->release()->output(std::cout); 521 | } 522 | 523 | TEST(parser_test, parse_string_literal_test) 524 | { 525 | static const char SOURCE[] = 526 | "function main() : i8[] {\n" 527 | " return \"test\";\n" 528 | "}\n" 529 | ; 530 | 531 | Parser *uut = new Parser(new ScreenOutputErrorCollector()); 532 | ASSERT_TRUE(uut->parse(SOURCE)); 533 | 534 | // uut->release()->output(std::cout); 535 | } 536 | -------------------------------------------------------------------------------- /test/phi_eliminator_test.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/19/16. 3 | // 4 | 5 | #include 6 | 7 | #include "gtest/gtest.h" 8 | 9 | #include "../lib/parse.hpp" 10 | #include "../lib/dep_analyzer.hpp" 11 | #include "../lib/loop_marker.hpp" 12 | #include "../lib/mem2reg.hpp" 13 | #include "../lib/phi_eliminator.hpp" 14 | 15 | using namespace cyan; 16 | 17 | TEST(phi_eliminator_test, basic_test) 18 | { 19 | static const char SOURCE[] = 20 | "function main(a : i64, b : i64) {\n" 21 | " let i = 0;\n" 22 | " let ta = a, tb = b;\n" 23 | " while (i < 10) {\n" 24 | " i = i + ta + tb;\n" 25 | " }\n" 26 | "}\n" 27 | ; 28 | 29 | Parser *parser = new Parser(new ScreenOutputErrorCollector()); 30 | ASSERT_TRUE(parser->parse(SOURCE)); 31 | 32 | std::ofstream original_out("phi_eliminator_basic_test_original.ir"); 33 | auto ir = Mem2Reg( 34 | DepAnalyzer( 35 | parser->release().release() 36 | ).release() 37 | ).release(); 38 | ir->output(original_out); 39 | 40 | std::ofstream optimized_out("phi_eliminator_basic_test_optimized.ir"); 41 | ir = PhiEliminator(ir).release(); 42 | ir->output(optimized_out); 43 | } 44 | -------------------------------------------------------------------------------- /test/unreachable_code_elimimater.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by c on 5/19/16. 3 | // 4 | 5 | #include 6 | 7 | #include "gtest/gtest.h" 8 | 9 | #include "../lib/parse.hpp" 10 | #include "../lib/dep_analyzer.hpp" 11 | #include "../lib/inst_rewriter.hpp" 12 | #include "../lib/dead_code_eliminater.hpp" 13 | #include "../lib/inliner.hpp" 14 | #include "../lib/unreachable_code_eliminater.hpp" 15 | 16 | using namespace cyan; 17 | 18 | TEST(unreachable_code_elimimater, basic_test) 19 | { 20 | static const char SOURCE[] = 21 | "function max(a : i64, b : i64) : i64 {\n" 22 | " return (a > b) ? a : b;\n" 23 | "}\n" 24 | "function min(a : i64, b : i64) : i64 {\n" 25 | " return (a < b) ? a : b;\n" 26 | "}\n" 27 | "function compare_and_swap(a : &i64, b : &i64) {\n" 28 | " let max_num = max(a, b);\n" 29 | " let min_num = min(a, b);\n" 30 | " a = max_num;\n" 31 | " b = min_num;\n" 32 | "}\n" 33 | "function main() {\n" 34 | " let a = 10, b = 15;\n" 35 | " if (1) {\n" 36 | " compare_and_swap(a, b);\n" 37 | " }\n" 38 | " else {\n" 39 | " a = 0;\n" 40 | " }\n" 41 | "}\n" 42 | ; 43 | 44 | Parser *parser = new Parser(new ScreenOutputErrorCollector()); 45 | ASSERT_TRUE(parser->parse(SOURCE)); 46 | 47 | std::ofstream original_out("unreachable_code_eliminater_basic_original.ir"); 48 | auto ir = parser->release().release(); 49 | ir = Inliner(ir).release(); 50 | ir = DepAnalyzer(ir).release(); 51 | ir->output(original_out); 52 | 53 | std::ofstream optimized_out("unreachable_code_eliminater_basic_optimized.ir"); 54 | ir = UnreachableCodeEliminater(ir).release(); 55 | ir->output(optimized_out); 56 | } 57 | --------------------------------------------------------------------------------