From 0454682c0db862d5a1c5edf4bc0f4c6fce50816e Mon Sep 17 00:00:00 2001 From: lxq <877250099@qq.com> Date: Sun, 5 Feb 2023 00:42:45 +0800 Subject: [PATCH] write reg-alloca for int values --- Reports/5-bonus/report.md | 70 ++++++--- include/codegen/codegen.hpp | 152 +++++++++++++------- include/codegen/liverange.hpp | 21 ++- include/codegen/regalloc.hpp | 22 ++- src/codegen/codegen.cpp | 264 ++++++++++++++++++++++------------ src/codegen/liverange.cpp | 16 +-- src/codegen/regalloc.cpp | 16 ++- 7 files changed, 373 insertions(+), 188 deletions(-) diff --git a/Reports/5-bonus/report.md b/Reports/5-bonus/report.md index 3ff497b..7419a31 100644 --- a/Reports/5-bonus/report.md +++ b/Reports/5-bonus/report.md @@ -59,38 +59,38 @@ label7: ; preds = %label0 ```llvm 1. op1 = 0 - in-set: [ ] - out-set: [ op1 ] + in-set: [ ] + out-set: [ op1 ] 2. br label %label0 - in-set: [ op1 ] - out-set: [ op1 ] + in-set: [ op1 ] + out-set: [ op1 ] 3. %op2 = icmp slt i32 %op1, 10 - in-set: [ op1 ] - out-set: [ op2 op1 ] + in-set: [ op1 ] + out-set: [ op2 op1 ] 4. %op3 = zext i1 %op2 to i32 - in-set: [ op2 op1 ] - out-set: [ op3 op1 ] + in-set: [ op2 op1 ] + out-set: [ op3 op1 ] 5. %op4 = icmp ne i32 %op3, 0 - in-set: [ op3 op1 ] - out-set: [ op4 op1 ] + in-set: [ op3 op1 ] + out-set: [ op4 op1 ] 6. br i1 %op4, label %label5, label %label7 - in-set: [ op4 op1 ] - out-set: [ op1 ] + in-set: [ op4 op1 ] + out-set: [ op1 ] 7. call void @output(i32 %op1) - in-set: [ op1 ] - out-set: [ op1 ] + in-set: [ op1 ] + out-set: [ op1 ] 8. %op6 = add i32 %op1, 1 - in-set: [ op1 ] - out-set: [ op6 ] + in-set: [ op1 ] + out-set: [ op6 ] 9. op1 = op6 - in-set: [ op6 ] - out-set: [ op1 ] + in-set: [ op6 ] + out-set: [ op1 ] 10. br label %label0 - in-set: [ op1 ] - out-set: [ op1 ] + in-set: [ op1 ] + out-set: [ op1 ] 11. ret i32 0 - in-set: [ ] - out-set: [ ] + in-set: [ ] + out-set: [ ] ``` 获得活跃区间:编号为i的指令,涉及两个端点:i-1和i,分别对应IN和OUT。由此得到各个变量的活跃区间是: @@ -111,4 +111,28 @@ op6: <8, 8> - [Documentations/5-bonus/寄存器分配.md · master · compiler_staff / 2022fall-Compiler_CMinus · GitLab](https://cscourse.ustc.edu.cn/vdir/Gitlab/compiler_staff/2022fall-compiler_cminus/-/blob/master/Documentations/5-bonus/%E5%AF%84%E5%AD%98%E5%99%A8%E5%88%86%E9%85%8D.md#poletto) -i +程序有`$a`系列寄存器8个,`$t`系列9个,拿出`$t0`、`$t1`做IR生成汇编过程中的临时寄存器(这个方案仅在cminus下成立),所以可以自由分配的寄存器一共15个。 + +首先完成对于局部变量的寄存器分配,即全局变量、传参依旧通过栈进行。 + +程序分配寄存器时会对部分指令做特殊处理,具体如下: + +- `phi`指令:还原为`copy-stmt`,所以寄存器照样分配,如果没分到使用栈内存 + +- `alloca`指令:这里忽略对于`alloca`指令的寄存器分配,`alloca`仍然使用栈存储,原因如下: + + - 对于int|float的`alloca`,使用寄存器可以正常进行,只需将相关指令`load`和`store`分别成赋值即可。 + + - 但是对于数组的`alloca`,使用寄存器就很难模拟了。 + + 即寄存器不能完成`alloca`的内存逻辑,同时经过`mem2reg`优化过后,不再有局部变量的声明,所以忽略对于`alloca`指令的寄存器分配。 + +- `cmp`、`fcmp`和`zext`指令:不做寄存器分配,也不做栈分配。 + + 这实际是指令选择部分的内容: + + 因为在cminus中并没有bool变量,这些IR指令用到的i1类型都是临时的:只为分支指令服务,所以直接将这些指令集成到分支跳转的判断中。 + +- `call`指令:使用栈传参,caller保存自己用到的寄存器,被保存的寄存器的活跃区间覆盖`call`指令的程序点。 + + diff --git a/include/codegen/codegen.hpp b/include/codegen/codegen.hpp index baeb370..ec53326 100644 --- a/include/codegen/codegen.hpp +++ b/include/codegen/codegen.hpp @@ -9,15 +9,17 @@ #include "Module.h" #include "Value.h" #include "liverange.hpp" -#include "logging.hpp" +#include "regalloc.hpp" #define __RO_PART__ +// #a = 8, #t = 9, reserve $t0, $t1 for temporary +#define R_USABLE 17 - 2 #include #include #include -#define ALIGN(x, align) (((x / align) + (x % align ? 1 : 0)) * align) +#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) @@ -27,7 +29,7 @@ using std::vector; class CodeGen { public: - CodeGen(Module *m_) : m(m_), LRA(m_, phi_map) {} + CodeGen(Module *m_) : m(m_), LRA(m_, phi_map), RA(R_USABLE) {} string print() { string result; @@ -42,35 +44,41 @@ class CodeGen { 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 *) {} + // + // data member + // + std::map off; // stack offset to $fp + std::map> func_arg_off; // to $sp + // total space for args, NOTE: not aligned + std::map func_arg_N; + std::map>> phi_map; + std::map ROdata; + unsigned int stackN; // function local vars and so on + Function *cur_func; + + Module *m; + vector output; + // register allocation + LRA::LiveRangeAnalyzer LRA; + RA::RegAllocator RA; + // some instruction has lvalue, but is stack-allocated, + // we need this variable to track the reg name which has rvalue. + // this variable is maintain by gencopy() and LoadInst. + string last_reg; + + // + // function member + // 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); + // In the case of register allocation, this function will return the + // allocated register for that value, if the value possesses no register, + // choose from from $t0 or $t1 based on id + + __attribute__((warn_unused_result)) string value2reg(Value *, int i = 0); // load the content in ptr to specified register. - // only use register a_id and t_ - void ptrContent2reg(Value *, int id = 0); + void ptrContent2reg(Value *, string); void compute_arg_info(Function *); string bool2branch(Instruction *); void getPhiMap(); @@ -80,15 +88,35 @@ class CodeGen { 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); + auto src_reg = value2reg(copy.second); + if (gencopy(lvalue, src_reg) == false) + back2stack(lvalue); + } + } + + // if reg-allocation, store to the specific register + // or is stack-allocation, set last_reg for back2stack() + bool gencopy(Value *lhs, string rhs_reg) { + auto [lhs_reg, find] = getRegName(lhs); + if (not find) { + // wait for back2stack() to store back + last_reg = rhs_reg; + return false; + } + auto is_float = lhs->get_type()->is_float_type(); + if (rhs_reg != lhs_reg) { + if (is_float) + output.push_back("fmov.s " + lhs_reg + ", " + rhs_reg); + else + output.push_back("or " + lhs_reg + ", $zero, " + rhs_reg); } + return true; } - string label_in_assem(BasicBlock *bb) { + string label_in_assem(BasicBlock *bb) const { return cur_func->get_name() + bb->get_name().substr(5); } - int typeLen(Type *type) { + int typeLen(Type *type) const { if (type->is_float_type()) return 4; else if (type->is_integer_type()) { @@ -107,19 +135,19 @@ class CodeGen { } } - // assert the value needed to store back is in $a0 or $f0, according to the + // assert the value needed to store back is in `last_reg`, 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 reg = type->is_float_type() ? "$fa0" : "$a0"; + string addr = "$fp, -" + std::to_string(off.at(instr)); + output.push_back(instr_ir + suff + " " + last_reg + ", " + addr); } - string suffix(Type *type) { + string suffix(Type *type) const { int len = typeLen(type); switch (len) { case 1: @@ -134,29 +162,53 @@ class CodeGen { assert(false && "no such suffix"); } - bool no_stack_alloca(Instruction *instr) { + bool no_stack_alloca(Instruction *instr) const { if (instr->is_void()) return true; if (instr->is_fcmp() or instr->is_cmp() or instr->is_zext()) return true; + if (RA.get().find(instr) != RA.get().end()) + return true; return false; } + string tmpregname(int i, bool is_float) const { + assert(i == 0 or i == 1); + return (is_float ? "$ft" : "$t") + to_string(i); + } - 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; - std::map ROdata; - unsigned int stackN; // function local vars and so on - - Function *cur_func; + static string regname(int i, bool is_float = false) { + string name; + if (is_float) { + assert(false && "not implemented!"); + } else { + if (1 <= i and i <= 8) + name = "$a" + to_string(i - 1); + else if (9 <= i and i <= R_USABLE) + name = "$t" + to_string(i - 9 + 2); + } + return name; + } - Module *m; - vector output; + pair getRegName(Value *, int = 0) const; - // register allocation - LRA::LiveRangeAnalyzer LRA; + 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 *) {} }; #endif diff --git a/include/codegen/liverange.hpp b/include/codegen/liverange.hpp index baba00b..7b0c9a6 100644 --- a/include/codegen/liverange.hpp +++ b/include/codegen/liverange.hpp @@ -2,6 +2,7 @@ #define LIVERANGE_HPP #include "Module.h" +#include "Value.h" #include #include @@ -27,7 +28,6 @@ struct Interval { using LiveSet = set; using PhiMap = map>>; using LiveInterval = pair; - struct LiveIntervalCMP { bool operator()(LiveInterval const &lhs, LiveInterval const &rhs) const { if (lhs.first.i != rhs.first.i) @@ -36,29 +36,31 @@ struct LiveIntervalCMP { return lhs.second < rhs.second; } }; +using LVITS = set; class LiveRangeAnalyzer { - public: friend class CodeGen; + public: LiveRangeAnalyzer(Module *m_, PhiMap &phi_map_) : m(m_), phi_map(phi_map_) {} LiveRangeAnalyzer() = delete; - void run(); + // void run(); void run(Function *); void clear(); - void print(Function *func, bool printSet = true); - string print_liveSet(const LiveSet &ls) { + void print(Function *func, bool printSet = true) const; + string print_liveSet(const LiveSet &ls) const { string s = "[ "; for (auto k : ls) s += k->get_name() + " "; s += "]"; return s; } - string print_interval(Interval &i) { + string print_interval(Interval &i) const { return "<" + to_string(i.i) + ", " + to_string(i.j) + ">"; } + const LVITS &get() { return liveIntervals; } private: Module *m; @@ -68,7 +70,8 @@ class LiveRangeAnalyzer { map instr_id; map, int> cpstmt_id; const PhiMap &phi_map; - set liveIntervals; + LVITS liveIntervals; + map intervalmap; void make_id(Function *); void make_interval(Function *); @@ -86,6 +89,10 @@ class LiveRangeAnalyzer { // Require: out-set is already set // Return: the in-set(will not set IN-map) LiveSet transferFunction(Instruction *); + + public: + const decltype(instr_id) &get_instr_id() { return instr_id; } + const decltype(intervalmap) &get_interval_map() { return intervalmap; } }; } // namespace LRA #endif diff --git a/include/codegen/regalloc.hpp b/include/codegen/regalloc.hpp index 108472f..db6d280 100644 --- a/include/codegen/regalloc.hpp +++ b/include/codegen/regalloc.hpp @@ -1,12 +1,21 @@ +#include "Value.h" #include "liverange.hpp" -// using std::transform; +#include +#include + +using std::cout; +using std::endl; +using std::to_string; using namespace LRA; namespace RA { + #define MAXR 32 +bool no_reg_alloca(Value *v); + struct ActiveCMP { bool operator()(LiveInterval const &lhs, LiveInterval const &rhs) const { if (lhs.first.j != rhs.first.j) @@ -18,15 +27,20 @@ struct ActiveCMP { class RegAllocator { public: - RegAllocator(const uint R_) : R(R_), used{false} {} + RegAllocator(const uint R_) : R(R_), used{false} { assert(R <= MAXR); } RegAllocator() = delete; // input set is sorted by increasing start point - void LinearScan(set &liveints); + void LinearScan(const LVITS &liveints); void reset(); + const map &get() const { return regmap; } + void print(string (*regname)(int)) { + for (auto [op, reg] : regmap) + cout << op->get_name() << " ~ " << regname(reg) << endl; + } private: const uint R; - bool used[MAXR]; + bool used[MAXR + 1]; // index range: 1 ~ R map regmap; // sorted by increasing end point set active; diff --git a/src/codegen/codegen.cpp b/src/codegen/codegen.cpp index 43a8673..611cb68 100644 --- a/src/codegen/codegen.cpp +++ b/src/codegen/codegen.cpp @@ -1,9 +1,3 @@ - -// 局部变量究竟保存在哪里? -// alloca会返回一个指针,这个指针指向一块可用的内存区域 -// 这个该如何体现在assemb上? -// NOTE: 参数类型需要额外考虑! - #include "codegen.hpp" #include "BasicBlock.h" @@ -21,6 +15,7 @@ #include #include #include +#include #include #include @@ -37,30 +32,23 @@ using std::to_string; -class Reg { - public: - Reg(int index) : id(index) {} - - int id; - - string print() { - if (id == 0) - return "$zero"; - if (id == 1) - return "$ra"; - if (id == 2) - return "$tp"; - if (id == 3) - return "$sp"; - if (4 <= id and id <= 11) - return "$a" + to_string(id - 4); - if (12 <= id and id <= 20) - return "$t" + to_string(id - 12); - if (id == 22) - return "$fp"; - assert(false); +pair +CodeGen::getRegName(Value *v, int i) const { + assert(i == 0 or i == 1); + bool find; + string name; + bool is_float = v->get_type()->is_float_type(); + auto regmap = RA.get(); + if (regmap.find(v) == regmap.end()) { + name = tmpregname(i, is_float); + find = false; + } else { + auto regid = regmap.find(v)->second; + name = regname(regid, is_float); + find = true; } -}; + return {name, find}; +} void CodeGen::getPhiMap() { @@ -95,12 +83,25 @@ CodeGen::run() { } // arguments: stack transfer for (auto &func : m->get_functions()) - if (not func.is_declaration()) - compute_arg_info(&func); + // if (not func.is_declaration()) + compute_arg_info(&func); // funtions for (auto &func : m->get_functions()) { if (not func.is_declaration()) { LRA.run(&func); + RA.LinearScan(LRA.get()); + + std::cout << "register map for function: " << func.get_name() + << std::endl; + RA.print([](int i) { return regname(i); }); + + auto regmap = RA.get(); + for (auto [_, op] : LRA.get()) { + if (regmap.find(op) == regmap.end()) + std::cout << "no reg belongs to " << op->get_name() + << std::endl; + } + cur_func = &func; output.push_back(""); output.push_back(".globl " + func.get_name()); @@ -140,37 +141,49 @@ CodeGen::run() { } void -CodeGen::ptrContent2reg(Value *ptr, int id) { +CodeGen::ptrContent2reg(Value *ptr, string reg_name) { auto ele_tp = ptr->get_type()->get_pointer_element_type(); assert(ele_tp); bool is_float = ele_tp->is_float_type(); string instr_ir = (is_float ? "fld" : "ld"); - string reg_name = (is_float ? "$fa" : "$a") + to_string(id); string suff = suffix(ele_tp); + + auto [addr_reg, find] = getRegName(ptr, 1); + if (not find) + addr_reg = "$t1"; + if (dynamic_cast(ptr)) { - output.push_back("la.local " + reg_name + ", " + ptr->get_name()); - output.push_back(instr_ir + suff + " " + reg_name + ", " + reg_name + + output.push_back("la.local " + addr_reg + ", " + ptr->get_name()); + output.push_back(instr_ir + suff + " " + reg_name + ", " + addr_reg + ", 0"); } else if (dynamic_cast(ptr)) { /* auto alloc_instr = static_cast(ptr); * string suff = suffix(alloc_instr->get_alloca_type()); */ output.push_back(instr_ir + suff + " " + reg_name + ", $fp, -" + - to_string(off[ptr])); + to_string(off.at(ptr))); } else if (dynamic_cast(ptr)) { // auto GEP_instr = static_cast(ptr); - output.push_back("ld.d " + reg_name + ", $fp, -" + to_string(off[ptr])); - output.push_back(instr_ir + suff + " " + reg_name + ", " + reg_name + + if (not find) { + output.push_back("ld.d " + addr_reg + ", $fp, -" + + to_string(off.at(ptr))); + } + output.push_back(instr_ir + suff + " " + reg_name + ", " + addr_reg + ", 0"); } else assert(false && "unknown type"); } -void -CodeGen::value2reg(Value *v, int id) { +string +CodeGen::value2reg(Value *v, int i) { bool is_float = v->get_type()->is_float_type(); - auto reg_name = (is_float ? "$fa" : "$a") + to_string(id); - string tmp_ireg = "$t0"; + string tmp_ireg = "$t" + to_string(i); + auto [reg_name, find] = getRegName(v, i); + if (find) + return reg_name; + // now is the stack allocation case if (dynamic_cast(v)) { + if (v == ConstantInt::get(0, m)) + return "$zero"; auto constant = static_cast(v); #ifdef __RO_PART__ if (ROdata.find(constant) == ROdata.end()) @@ -182,6 +195,7 @@ CodeGen::value2reg(Value *v, int id) { instr_ir = "fld.s"; else assert(false && "wait for completion"); + // bug here: maybe output.push_back("la.local " + tmp_ireg + ", " + addr); output.push_back(instr_ir + " " + reg_name + ", " + tmp_ireg + ", 0"); #else @@ -217,7 +231,8 @@ CodeGen::value2reg(Value *v, int id) { } else if (dynamic_cast(v)) { // auto alloc_instr = dynamic_cast(v); // give the stack address - output.push_back("addi.d " + reg_name + ", $fp, -" + to_string(off[v])); + output.push_back("addi.d " + reg_name + ", $fp, -" + + to_string(off.at(v))); } else if (dynamic_cast(v)) { auto args = cur_func->get_args(); int id = 1; @@ -226,12 +241,14 @@ CodeGen::value2reg(Value *v, int id) { break; string instr_ir = is_float ? "fld" : "ld"; output.push_back(instr_ir + suffix(v->get_type()) + " " + reg_name + - ", $fp, " + to_string(func_arg_off[cur_func][id])); + ", $fp, " + + to_string(func_arg_off.at(cur_func).at(id))); } else { string instr_ir = is_float ? "fld" : "ld"; output.push_back(instr_ir + suffix(v->get_type()) + " " + reg_name + - ", $fp, -" + to_string(off[v])); + ", $fp, -" + to_string(off.at(v))); } + return reg_name; } void @@ -250,20 +267,7 @@ CodeGen::compute_arg_info(Function *func) { } for (arg_id = 1; arg_id <= func->get_num_of_args(); ++arg_id) arg_off[arg_id] = argN - arg_off[arg_id]; - func_arg_N[func] = STACK_ALIGN(argN); -} - -void -CodeGen::stackMemDealloc() { - // 7: return value should be determined already! - output.push_back(cur_func->get_name() + "_end:"); - output.push_back("# epilog"); - output.push_back("ld.d $ra, $sp, " + to_string(stackN - 8)); - output.push_back("ld.d $fp, $sp, " + to_string(stackN - 16)); - /* output.push_back("ld.d $ra, $fp, -8"); - * output.push_back("ld.d $fp, $fp, -16"); */ - output.push_back("addi.d $sp, $sp, " + to_string(stackN)); - output.push_back("jr $ra"); + func_arg_N[func] = argN; } // the addr for opk is: fp - off[opk] @@ -294,20 +298,39 @@ CodeGen::stackMemAlloc() { output.push_back("st.d $fp, $sp, " + to_string(stackN - 16)); output.push_back("addi.d $fp, $sp, " + to_string(stackN)); } + +void +CodeGen::stackMemDealloc() { + // 7: return value should be determined already! + output.push_back(cur_func->get_name() + "_end:"); + output.push_back("# epilog"); + output.push_back("ld.d $ra, $sp, " + to_string(stackN - 8)); + output.push_back("ld.d $fp, $sp, " + to_string(stackN - 16)); + /* output.push_back("ld.d $ra, $fp, -8"); + * output.push_back("ld.d $fp, $fp, -16"); */ + output.push_back("addi.d $sp, $sp, " + to_string(stackN)); + output.push_back("jr $ra"); +} + void CodeGen::IR2assem(FpToSiInst *instr) { assert(instr->get_operand(0)->get_type() == m->get_float_type()); assert(instr->get_dest_type() == m->get_int32_type()); - value2reg(instr->get_operand(0)); - output.push_back("ftintrz.w.s $fa0, $fa0"); - output.push_back("movfr2gr.s $a0, $fa0"); + string f_reg = value2reg(instr->get_operand(0)); + auto [i_reg, _] = getRegName(instr); + output.push_back("ftintrz.w.s " + f_reg + ", " + f_reg); + output.push_back("movfr2gr.s " + i_reg + ", " + f_reg); + gencopy(instr, i_reg); } void CodeGen::IR2assem(SiToFpInst *instr) { assert(instr->get_operand(0)->get_type() == m->get_int32_type()); assert(instr->get_dest_type() == m->get_float_type()); - output.push_back("movgr2fr.w $fa0, $a0"); - output.push_back("ffint.s.w $fa0, $fa0"); + string i_reg = value2reg(instr->get_operand(0)); + auto [f_reg, _] = getRegName(instr); + output.push_back("movgr2fr.w " + f_reg + ", " + i_reg); + output.push_back("ffint.s.w " + f_reg + ", " + f_reg); + gencopy(instr, f_reg); } string @@ -355,10 +378,12 @@ CodeGen::bool2branch(Instruction *instr) { reverse = true; break; } - value2reg(instr->get_operand(0), 0); - value2reg(instr->get_operand(1), 1); - return instr_ir + (reverse ? " $a1, $a0," : " $a0, $a1,"); + auto reg1 = value2reg(instr->get_operand(0), 0); + auto reg2 = value2reg(instr->get_operand(1), 1); + return instr_ir + " " + + (reverse ? (reg2 + ", " + reg1) : (reg1 + ", " + reg2)) + ","; } else { + assert(false && "not implemented"); switch (fcmp_instr->get_cmp_op()) { case FCmpInst::EQ: instr_ir = "fcmp.ceq.s $fcc0"; @@ -381,9 +406,9 @@ CodeGen::bool2branch(Instruction *instr) { instr_ir = "fcmp.cle.s $fcc0"; break; } - value2reg(instr->get_operand(0), 0); - value2reg(instr->get_operand(1), 1); - output.push_back(instr_ir + ", " + "$fa0, $fa1"); + auto reg1 = value2reg(instr->get_operand(0), 0); + auto reg2 = value2reg(instr->get_operand(1), 1); + output.push_back(instr_ir + ", " + reg1 + ", " + reg2); return (reverse ? "bceqz $fcc0," : "bcnez $fcc0,"); } } @@ -407,42 +432,79 @@ CodeGen::IR2assem(BranchInst *instr) { void CodeGen::IR2assem(CallInst *instr) { auto func = static_cast(instr->get_operand(0)); + auto func_argN = func_arg_N.at(func); + // analyze the registers that need to be stored + int cur_i = LRA.get_instr_id().at(instr); + auto regmap = RA.get(); + // + int storeN = 0; + vector> store_record; + for (auto [op, interval] : LRA.get_interval_map()) { + if (RA::no_reg_alloca(op)) + continue; + if (interval.i <= cur_i and cur_i <= interval.j) { + int tplen = typeLen(op->get_type()); + storeN = ALIGN(storeN, tplen) + tplen; + auto name = regname(regmap.at(op), op->get_type()->is_float_type()); + store_record.push_back({op, name, storeN}); + } + } + int totalN = STACK_ALIGN(ALIGN(storeN, 8) + func_argN); + // cout << "debug: " << STACK_ALIGN(12) << endl; // stack space allocation - output.push_back("addi.d $sp, $sp, -" + to_string(func_arg_N[func])); + output.push_back("addi.d $sp, $sp, -" + to_string(totalN)); string instr_ir, suff, reg; + // place the reserved regs + for (auto [op, reg, off] : store_record) { + instr_ir = (op->get_type()->is_float_type() ? "fst" : "st"); + suff = suffix(op->get_type()); + output.push_back(instr_ir + suff + " " + reg + ", $sp, " + + to_string(totalN - off)); + } // place the arguments for (int i = 1; i < instr->get_num_operand(); i++) { auto arg = instr->get_operand(i); // auto tplen = typeLen(arg->get_type()); instr_ir = (arg->get_type()->is_float_type() ? "fst" : "st"); suff = suffix(arg->get_type()); - reg = (arg->get_type()->is_float_type() ? "$fa0" : "$a0"); - value2reg(arg); + reg = value2reg(arg); output.push_back(instr_ir + suff + " " + reg + ", $sp, " + - to_string(func_arg_off[func][i])); + to_string(func_arg_off.at(func).at(i))); } output.push_back("bl " + func->get_name()); - output.push_back("addi.d $sp, $sp, " + to_string(func_arg_N[func])); + // bug here: maybe + gencopy(instr, instr->get_type()->is_float_type() ? "$fa0" : "$a0"); + // restore the reserved regs + for (auto [op, reg, off] : store_record) { + instr_ir = (op->get_type()->is_float_type() ? "fld" : "ld"); + suff = suffix(op->get_type()); + output.push_back(instr_ir + suff + " " + reg + ", $sp, " + + to_string(totalN - off)); + } + output.push_back("addi.d $sp, $sp, " + to_string(totalN)); // output.push_back("addi.d $fp, $sp, " + to_string(stackN)); } void CodeGen::IR2assem(BinaryInst *instr) { - auto is_float = instr->get_type()->is_float_type(); - value2reg(instr->get_operand(0), 0); - value2reg(instr->get_operand(1), 1); + auto reg1 = value2reg(instr->get_operand(0), 0); + auto reg2 = value2reg(instr->get_operand(1), 1); + auto [reg, _] = getRegName(instr); string instr_ir = instr->get_instr_op_name(); if (instr_ir == "sdiv") instr_ir = "div"; string suff = suffix(instr->get_type()); - output.push_back(instr_ir + suff + - (is_float ? " $fa0, $fa0, $fa1" : " $a0, $a0, $a1")); + output.push_back(instr_ir + suff + " " + reg + ", " + reg1 + ", " + reg2); + gencopy(instr, reg); } void CodeGen::IR2assem(GetElementPtrInst *instr) { - value2reg(instr->get_operand(0), 0); + assert(instr->get_num_operand() <= 3); + auto addr_reg = value2reg(instr->get_operand(0), 0); + assert(addr_reg == "$t0"); + Type *type = instr->get_operand(0)->get_type(); for (int i = 1; i < instr->get_num_operand(); i++) { int size; @@ -454,38 +516,52 @@ CodeGen::IR2assem(GetElementPtrInst *instr) { type = type->get_pointer_element_type(); } else assert(false && "GEP translation error"); - value2reg(instr->get_operand(i), 1); - value2reg(ConstantInt::get(size, m), 2); - output.push_back("mul.w $a1, $a1, $a2"); - output.push_back("add.d $a0, $a0, $a1"); + if (size != 4) { + // getelementptr [5 x i32], [5 x i32]* @w, i32 0, i32 4 + assert(instr->get_operand(i) == ConstantInt::get(0, m) && + "cminus support only 1 dimension array, so first offset is " + "must 0"); + continue; + } + auto off_reg = value2reg(instr->get_operand(i), 1); + // value2reg(ConstantInt::get(size, m), 2); + output.push_back("slli.d " + off_reg + ", " + off_reg + ", 2"); + output.push_back("add.d " + addr_reg + ", " + addr_reg + ", " + + off_reg); } + gencopy(instr, addr_reg); } void CodeGen::IR2assem(LoadInst *instr) { - // move the address to a0 - ptrContent2reg(instr->get_lval()); - - assert(instr->get_type() == instr->get_load_type()); + auto [reg, find] = getRegName(instr); + ptrContent2reg(instr->get_lval(), reg); + if (not find) // this if is just for logically clear + last_reg = reg; } void CodeGen::IR2assem(StoreInst *instr) { - value2reg(instr->get_rval(), 0); - value2reg(instr->get_lval(), 1); + auto reg1 = value2reg(instr->get_rval(), 0); + auto reg2 = value2reg(instr->get_lval(), 1); bool is_float = instr->get_rval()->get_type()->is_float_type(); string instr_ir = (is_float ? "fst" : "st"); string suff = suffix(instr->get_rval()->get_type()); - string reg = (is_float ? "$fa0" : "$a0"); - output.push_back(instr_ir + suff + " " + reg + ", $a1, 0"); + output.push_back(instr_ir + suff + " " + reg1 + ", " + reg2 + ", 0"); } void CodeGen::IR2assem(ReturnInst *instr) { if (not instr->is_void_ret()) { auto value = instr->get_operand(0); - value2reg(value); + auto is_float = value->get_type()->is_float_type(); + auto reg = value2reg(value); + if (is_float and reg != "$fa0") + output.push_back("fmov.s $fa0, " + reg); + else if (not is_float and reg != "$a0") + output.push_back("or $a0, $zero " + reg); } + output.push_back("b " + cur_func->get_name() + "_end"); } diff --git a/src/codegen/liverange.cpp b/src/codegen/liverange.cpp index 75c4626..a5cc7fd 100644 --- a/src/codegen/liverange.cpp +++ b/src/codegen/liverange.cpp @@ -11,6 +11,7 @@ LiveRangeAnalyzer::clear() { OUT.clear(); instr_id.clear(); cpstmt_id.clear(); + intervalmap.clear(); liveIntervals.clear(); } @@ -133,24 +134,23 @@ LiveRangeAnalyzer::run(Function *func) { void LiveRangeAnalyzer::make_interval(Function *) { - map liverange; for (int time = 1; time <= ir_cnt; ++time) { for (auto op : IN.at(time)) { - auto &interval = liverange[op]; + auto &interval = intervalmap[op]; if (interval.i == 0) // uninitialized interval.i = time - 1; else interval.j = time - 1; } for (auto op : OUT.at(time)) { - auto &interval = liverange[op]; + auto &interval = intervalmap[op]; if (interval.i == 0) // uninitialized interval.i = time; else interval.j = time; } } - for (auto [op, interval] : liverange) + for (auto [op, interval] : intervalmap) liveIntervals.insert({interval, op}); } @@ -188,7 +188,7 @@ LiveRangeAnalyzer::transferFunction(Instruction *instr) { } void -LiveRangeAnalyzer::print(Function *func, bool printSet) { // for debug +LiveRangeAnalyzer::print(Function *func, bool printSet) const { // for debug cout << "Function " << func->get_name() << endl; for (auto &bb : func->get_basic_blocks()) { for (auto &instr : bb.get_instructions()) { @@ -200,7 +200,7 @@ LiveRangeAnalyzer::print(Function *func, bool printSet) { // for debug for (auto pr : phi_map.find(&bb)->second) { auto [lv, rv] = pr; auto idx = cpstmt_id.at(pr); - cout << cpstmt_id[pr] << ". " << lv->get_name() << " = " + cout << cpstmt_id.at(pr) << ". " << lv->get_name() << " = " << (rv->get_name() == "" ? rv->print() : rv->get_name()) << endl; @@ -213,8 +213,8 @@ LiveRangeAnalyzer::print(Function *func, bool printSet) { // for debug } } // normal ir - cout << instr_id[&instr] << ". " << instr.print() << " # " << &instr - << endl; + cout << instr_id.at(&instr) << ". " << instr.print() << " # " + << &instr << endl; if (not printSet) continue; auto idx = instr_id.at(&instr); diff --git a/src/codegen/regalloc.cpp b/src/codegen/regalloc.cpp index 52113c5..d484dc3 100644 --- a/src/codegen/regalloc.cpp +++ b/src/codegen/regalloc.cpp @@ -1,23 +1,35 @@ #include "regalloc.hpp" +#include "Instruction.h" +#include "liverange.hpp" + #include using std::for_each; using namespace RA; +bool +RA::no_reg_alloca(Value *v) { + auto instr = static_cast(v); + return instr->is_alloca() or instr->is_cmp() or instr->is_fcmp() or + instr->is_zext(); +} + void RegAllocator::reset() { regmap.clear(); active.clear(); - for_each(used, used + R, [](bool &u) { u = false; }); + for_each(used, used + R + 1, [](bool &u) { u = false; }); } void -RegAllocator::LinearScan(set &liveints) { +RegAllocator::LinearScan(const LVITS &liveints) { reset(); int reg; for (auto liveint : liveints) { + if (no_reg_alloca(liveint.second)) + continue; ExpireOldIntervals(liveint); if (active.size() == R) SpillAtInterval(liveint); -- GitLab