#ifndef CODEGEN_HPP #define CODEGEN_HPP #include "BasicBlock.h" #include "Function.h" #include "IRprinter.h" #include "Instruction.h" #include "Module.h" #include "Value.h" #include "logging.hpp" #include #include #include #define ALIGN(x, align) (((x / align) + (x % align ? 1 : 0)) * align) // #define STACK_ALIGN(x) (((x / 16) + (x % 16 ? 1 : 0)) * 16) #define STACK_ALIGN(x) ALIGN(x, 16) using std::map; using std::string; using std::vector; class CodeGen { public: CodeGen(Module *module) : m(module) {} string print() { string result; for (auto line : output) { if (line.find(":") == string::npos and line != "") result += "\t"; // 添加缩进 result += line + "\n"; } return result; } void run(); private: void IR2assem(Instruction &, BasicBlock &); void IR2assem(LoadInst *); void IR2assem(StoreInst *); void IR2assem(ReturnInst *); void IR2assem(GetElementPtrInst *); void IR2assem(CallInst *); void IR2assem(BranchInst *); void IR2assem(BinaryInst *); void IR2assem(FpToSiInst *); void IR2assem(SiToFpInst *); void IR2assem(PhiInst *) {} // The Instructions below will do nothing void IR2assem(AllocaInst *) {} // integration with BranchInst void IR2assem(CmpInst *) {} void IR2assem(FCmpInst *) {} void IR2assem(ZextInst *) {} void stackMemAlloc(); void stackMemDealloc(); // load value `opk` to the specified register // - for constant number, just load into reg // - for global variables and pointers from alloca and GEP, read through // address // only use register a_id and t_ void value2reg(Value *, int id = 0); // load the content in ptr to specified register. // only use register a_id and t_ void ptrContent2reg(Value *, int id = 0); void compute_arg_info(Function *); string bool2branch(Instruction *); void getPhiMap(); void copystmt(BasicBlock *bb) { // all the phi instruction is transformed to copy-stmt for (auto © : phi_map[bb]) { output.push_back("# " + print_as_op(copy.first, false) + " = " + print_as_op(copy.second, false)); auto lvalue = static_cast(copy.first); value2reg(copy.second); back2stack(lvalue); } } string label_in_assem(BasicBlock *bb) { return cur_func->get_name() + bb->get_name().substr(5); } int typeLen(Type *type) { if (type->is_float_type()) return 4; else if (type->is_integer_type()) { if (static_cast(type)->get_num_bits() == 32) return 4; else return 1; } else if (type->is_pointer_type()) return 8; else if (type->is_array_type()) { auto arr_tp = static_cast(type); int n = arr_tp->get_num_of_elements(); return n * typeLen(arr_tp->get_element_type()); } else { assert(false && "unexpected case while computing type-length"); } } // assert the value needed to store back is in $a0 or $f0, according to the // value type void back2stack(Instruction *instr) { // std::cerr << instr->print() << std::endl; auto type = instr->get_type(); string instr_ir = type->is_float_type() ? "fst" : "st"; string suff = suffix(type); string reg = type->is_float_type() ? "$fa0" : "$a0"; string addr = "$fp, -" + std::to_string(off[instr]); output.push_back(instr_ir + suff + " " + reg + ", " + addr); } string suffix(Type *type) { int len = typeLen(type); switch (len) { case 1: return ".b"; case 2: return ".h"; case 4: return type->is_float_type() ? ".s" : ".w"; case 8: return ".d"; } assert(false && "no such suffix"); } bool no_stack_alloca(Instruction *instr) { if (instr->is_void()) return true; if (instr->is_fcmp() or instr->is_cmp() or instr->is_zext()) return true; return false; } std::map off; // stack offset to $fp std::map> func_arg_off; // to $sp std::map func_arg_N; // total space for args std::map>> phi_map; unsigned int stackN; // function local vars and so on Function *cur_func; Module *m; vector output; }; #endif