From b4870a7393437769412abadcd9264f0c97f7b081 Mon Sep 17 00:00:00 2001 From: lxq <877250099@qq.com> Date: Sun, 5 Feb 2023 23:12:06 +0800 Subject: [PATCH] have too many bugs now, use lab3 testcases to debug --- Reports/5-bonus/report.md | 26 ++++- include/codegen/codegen.hpp | 18 ++- include/codegen/liverange.hpp | 2 +- include/codegen/regalloc.hpp | 22 ++-- src/codegen/codegen.cpp | 123 ++++++++++++--------- src/codegen/liverange.cpp | 18 +-- src/codegen/regalloc.cpp | 59 ++++++++-- tests/5-bonus/testcases/16-argparse.cminus | 29 +++++ tests/5-bonus/testcases/16-argparse.in | 10 ++ tests/5-bonus/testcases/16-argparse.out | 10 ++ 10 files changed, 234 insertions(+), 83 deletions(-) create mode 100644 tests/5-bonus/testcases/16-argparse.cminus create mode 100644 tests/5-bonus/testcases/16-argparse.in create mode 100644 tests/5-bonus/testcases/16-argparse.out diff --git a/Reports/5-bonus/report.md b/Reports/5-bonus/report.md index 7419a31..315de46 100644 --- a/Reports/5-bonus/report.md +++ b/Reports/5-bonus/report.md @@ -113,7 +113,7 @@ op6: <8, 8> 程序有`$a`系列寄存器8个,`$t`系列9个,拿出`$t0`、`$t1`做IR生成汇编过程中的临时寄存器(这个方案仅在cminus下成立),所以可以自由分配的寄存器一共15个。 -首先完成对于局部变量的寄存器分配,即全局变量、传参依旧通过栈进行。 +首先完成对于局部变量和参数的整形寄存器分配。 程序分配寄存器时会对部分指令做特殊处理,具体如下: @@ -135,4 +135,28 @@ op6: <8, 8> - `call`指令:使用栈传参,caller保存自己用到的寄存器,被保存的寄存器的活跃区间覆盖`call`指令的程序点。 +参数传递:固定为前8个参数分配`$a0`\~`$a7`,超过8个使用栈传递。 +#### 4. 局部优化 + +- 基于跳转的bool变量翻译。 + +- GEP取值的优化:两个0的情况 + +- 常量取值的优化 + +- + +#### 5. 测试样例 + +功能正确性由以下几部分测试样例作为证明: + +- `/tests/5-bonus/testcases` + +- `tests/3-ir-gen/testcases` + +而性能主要向gcc看齐,主要测试样例为 + +- `tests/4-ir-opt/testcases/GVN/performance` + +- diff --git a/include/codegen/codegen.hpp b/include/codegen/codegen.hpp index ec53326..73ea351 100644 --- a/include/codegen/codegen.hpp +++ b/include/codegen/codegen.hpp @@ -11,9 +11,13 @@ #include "liverange.hpp" #include "regalloc.hpp" +#include + +#define __PRINT_ORI__ #define __RO_PART__ // #a = 8, #t = 9, reserve $t0, $t1 for temporary #define R_USABLE 17 - 2 +#define ARG_R 8 #include #include @@ -29,7 +33,7 @@ using std::vector; class CodeGen { public: - CodeGen(Module *m_) : m(m_), LRA(m_, phi_map), RA(R_USABLE) {} + CodeGen(Module *m_) : m(m_), LRA(m_, phi_map), RA(R_USABLE, ARG_R) {} string print() { string result; @@ -74,9 +78,8 @@ class CodeGen { void stackMemDealloc(); // 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); + // choose from from $t0 or $t1 based on id, or the input string(not "") + __attribute__((warn_unused_result)) string value2reg(Value *, int i = 0, string = ""); // load the content in ptr to specified register. void ptrContent2reg(Value *, string); void compute_arg_info(Function *); @@ -104,13 +107,16 @@ class CodeGen { return false; } auto is_float = lhs->get_type()->is_float_type(); + gencopy(lhs_reg, rhs_reg, is_float); + return true; + } + void gencopy(string lhs_reg, string rhs_reg, bool is_float = false) { 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) const { @@ -186,6 +192,8 @@ class CodeGen { name = "$a" + to_string(i - 1); else if (9 <= i and i <= R_USABLE) name = "$t" + to_string(i - 9 + 2); + else + name = "WRONG_REG" + to_string(i); } return name; } diff --git a/include/codegen/liverange.hpp b/include/codegen/liverange.hpp index 7b0c9a6..9a6f562 100644 --- a/include/codegen/liverange.hpp +++ b/include/codegen/liverange.hpp @@ -49,7 +49,7 @@ class LiveRangeAnalyzer { // void run(); void run(Function *); void clear(); - void print(Function *func, bool printSet = true) const; + void print(Function *func, bool printSet = false, bool printInt = false) const; string print_liveSet(const LiveSet &ls) const { string s = "[ "; for (auto k : ls) diff --git a/include/codegen/regalloc.hpp b/include/codegen/regalloc.hpp index db6d280..c67b70d 100644 --- a/include/codegen/regalloc.hpp +++ b/include/codegen/regalloc.hpp @@ -1,3 +1,6 @@ +#ifndef REGALLOCA_HPP +#define REGALLOCA_HPP +#include "Function.h" #include "Value.h" #include "liverange.hpp" @@ -6,16 +9,12 @@ 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) @@ -27,11 +26,14 @@ struct ActiveCMP { class RegAllocator { public: - RegAllocator(const uint R_) : R(R_), used{false} { assert(R <= MAXR); } + RegAllocator(const uint R_, const uint ARG_R_) + : R(R_), ARG_MAX_R(ARG_R_), used{false} { + assert(R <= MAXR); + } RegAllocator() = delete; + bool no_reg_alloca(Value *v) const; // input set is sorted by increasing start point - void LinearScan(const LVITS &liveints); - void reset(); + void LinearScan(const LVITS &, Function *); const map &get() const { return regmap; } void print(string (*regname)(int)) { for (auto [op, reg] : regmap) @@ -39,13 +41,19 @@ class RegAllocator { } private: + Function *cur_func; const uint R; + const uint ARG_MAX_R; bool used[MAXR + 1]; // index range: 1 ~ R map regmap; // sorted by increasing end point set active; + void reset(Function * = nullptr); + + int ReserveForArg(const LVITS &); void ExpireOldIntervals(LiveInterval); void SpillAtInterval(LiveInterval); }; } // namespace RA +#endif diff --git a/src/codegen/codegen.cpp b/src/codegen/codegen.cpp index 611cb68..a7fa6d5 100644 --- a/src/codegen/codegen.cpp +++ b/src/codegen/codegen.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -19,6 +20,8 @@ #include #include +#define CONST_0 ConstantInt::get(0, m) + // $r0 $zero constant 0 // $r1 $ra return address // $r2 $tp thread pointer @@ -31,6 +34,7 @@ // $r23 - $r31 $s0 - $s8 static using std::to_string; +using std::operator""s; pair CodeGen::getRegName(Value *v, int i) const { @@ -89,7 +93,7 @@ CodeGen::run() { for (auto &func : m->get_functions()) { if (not func.is_declaration()) { LRA.run(&func); - RA.LinearScan(LRA.get()); + RA.LinearScan(LRA.get(), &func); std::cout << "register map for function: " << func.get_name() << std::endl; @@ -149,8 +153,8 @@ CodeGen::ptrContent2reg(Value *ptr, string reg_name) { string suff = suffix(ele_tp); auto [addr_reg, find] = getRegName(ptr, 1); - if (not find) - addr_reg = "$t1"; + /* if (not find) + * addr_reg = "$t1"; */ if (dynamic_cast(ptr)) { output.push_back("la.local " + addr_reg + ", " + ptr->get_name()); @@ -174,15 +178,17 @@ CodeGen::ptrContent2reg(Value *ptr, string reg_name) { } string -CodeGen::value2reg(Value *v, int i) { +CodeGen::value2reg(Value *v, int i, string recommend) { bool is_float = v->get_type()->is_float_type(); string tmp_ireg = "$t" + to_string(i); auto [reg_name, find] = getRegName(v, i); if (find) return reg_name; + else if (recommend != "") + reg_name = recommend; // now is the stack allocation case if (dynamic_cast(v)) { - if (v == ConstantInt::get(0, m)) + if (v == CONST_0) return "$zero"; auto constant = static_cast(v); #ifdef __RO_PART__ @@ -239,10 +245,14 @@ CodeGen::value2reg(Value *v, int i) { for (auto iter = args.begin(); id <= args.size(); ++iter, ++id) if (*iter == v) 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.at(cur_func).at(id))); + if (id <= ARG_R) + return regname(ARG_R); + else { + string instr_ir = is_float ? "fld" : "ld"; + output.push_back(instr_ir + suffix(v->get_type()) + " " + reg_name + + ", $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 + @@ -258,15 +268,19 @@ CodeGen::compute_arg_info(Function *func) { auto func_tp = func->get_function_type(); auto &arg_off = func_arg_off[func]; int argN = 0, arg_id = func->get_num_of_args(); + // only alloca stack memory for argk, k >= 8; + auto rend = func_tp->param_begin(); + for (int i = 0; i < ARG_R and rend != func_tp->param_end(); ++i, ++rend) + ; // reserve space - for (auto iter = func_tp->param_end(); iter != func_tp->param_begin();) { + for (auto iter = func_tp->param_end(); iter != rend;) { --iter; auto tplen = typeLen(*iter); argN = ALIGN(argN, tplen) + tplen; arg_off[arg_id--] = argN; } - for (arg_id = 1; arg_id <= func->get_num_of_args(); ++arg_id) - arg_off[arg_id] = argN - arg_off[arg_id]; + for (arg_id = ARG_R + 1; arg_id <= func->get_num_of_args(); ++arg_id) + arg_off.at(arg_id) = argN - arg_off.at(arg_id); func_arg_N[func] = argN; } @@ -349,7 +363,7 @@ CodeGen::bool2branch(Instruction *instr) { break; case CmpInst::NE: { instr_ir = "bne"; - if (instr->get_operand(1) == ConstantInt::get(0, m) and + if (instr->get_operand(1) == CONST_0 and dynamic_cast(instr->get_operand(0)) ->is_zext()) { // something like: @@ -440,7 +454,7 @@ CodeGen::IR2assem(CallInst *instr) { int storeN = 0; vector> store_record; for (auto [op, interval] : LRA.get_interval_map()) { - if (RA::no_reg_alloca(op)) + if (RA.no_reg_alloca(op) or regmap.at(op) == 1) continue; if (interval.i <= cur_i and cur_i <= interval.j) { int tplen = typeLen(op->get_type()); @@ -452,8 +466,9 @@ CodeGen::IR2assem(CallInst *instr) { 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(totalN)); - string instr_ir, suff, reg; + if (totalN) + output.push_back("addi.d $sp, $sp, -" + to_string(totalN)); + string instr_ir, suff, v_reg; // place the reserved regs for (auto [op, reg, off] : store_record) { instr_ir = (op->get_type()->is_float_type() ? "fst" : "st"); @@ -461,15 +476,18 @@ CodeGen::IR2assem(CallInst *instr) { 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 = value2reg(arg); - output.push_back(instr_ir + suff + " " + reg + ", $sp, " + - to_string(func_arg_off.at(func).at(i))); + // pass arguments + for (int arg_i = 1; arg_i < instr->get_num_operand(); arg_i++) { + auto arg_value = instr->get_operand(arg_i); + v_reg = value2reg(arg_value); + if (arg_i <= ARG_R) { // pass by register + gencopy(regname(arg_i), v_reg); + } else { // pass by stack + instr_ir = (arg_value->get_type()->is_float_type() ? "fst" : "st"); + suff = suffix(arg_value->get_type()); + output.push_back(instr_ir + suff + " " + v_reg + ", $sp, " + + to_string(func_arg_off.at(func).at(arg_i))); + } } output.push_back("bl " + func->get_name()); // bug here: maybe @@ -481,8 +499,8 @@ CodeGen::IR2assem(CallInst *instr) { 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)); + if (totalN) + output.push_back("addi.d $sp, $sp, " + to_string(totalN)); } void @@ -502,34 +520,27 @@ CodeGen::IR2assem(BinaryInst *instr) { void CodeGen::IR2assem(GetElementPtrInst *instr) { 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; - if (type->is_array_type()) { - size = type->get_array_element_type()->get_size(); - type = type->get_array_element_type(); - } else if (type->is_pointer_type()) { - size = type->get_size(); - type = type->get_pointer_element_type(); - } else - assert(false && "GEP translation error"); - 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); + auto [dest_reg, _] = getRegName(instr); + + auto off = instr->get_operand(instr->get_num_operand() == 3 ? 2 : 1); + if (off == CONST_0) { + auto final_reg = value2reg(instr->get_operand(0), 0, dest_reg); + gencopy(instr, final_reg); + return; + } + if (instr->get_num_operand() == 3) { + // %op54 = getelementptr [66 x i32], [66 x i32]* @dp, i32 0, i32 %op41 + assert(instr->get_operand(1) == CONST_0); + } else { // %op38 = getelementptr i32, i32* %arg1, i32 %op34 } - gencopy(instr, addr_reg); + auto addr_reg = value2reg(instr->get_operand(0), 0); + auto off_reg = value2reg(off, 1); + auto tmp_reg = "$t1"s; + + output.push_back("slli.d " + tmp_reg + ", " + off_reg + ", 2"); + output.push_back("add.d " + dest_reg + ", " + addr_reg + ", " + tmp_reg); + + gencopy(instr, dest_reg); } void @@ -559,7 +570,7 @@ CodeGen::IR2assem(ReturnInst *instr) { 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("or $a0, $zero, " + reg); } output.push_back("b " + cur_func->get_name() + "_end"); @@ -569,7 +580,9 @@ void CodeGen::IR2assem(Instruction &instr, BasicBlock &bb) { if (instr.is_br() or instr.is_ret()) copystmt(&bb); +#ifdef __PRINT_ORI__ output.push_back("# " + instr.print()); +#endif switch (instr.get_instr_type()) { case Instruction::ret: IR2assem(static_cast(&instr)); diff --git a/src/codegen/liverange.cpp b/src/codegen/liverange.cpp index a5cc7fd..5ae3c99 100644 --- a/src/codegen/liverange.cpp +++ b/src/codegen/liverange.cpp @@ -1,5 +1,7 @@ #include "liverange.hpp" +#include "Function.h" + using std::cout; using std::endl; using namespace LRA; @@ -58,9 +60,6 @@ void LiveRangeAnalyzer::run(Function *func) { clear(); make_id(func); -#ifdef __LRA_PRINT__ - print(func, false); -#endif bool cont = true; while (cont) { cont = false; @@ -128,7 +127,7 @@ LiveRangeAnalyzer::run(Function *func) { make_interval(func); #ifdef __LRA_PRINT__ - print(func); + print(func, false, true); #endif } @@ -166,12 +165,15 @@ LiveRangeAnalyzer::transferFunction(Instruction *instr) { // - function // - Constant // - instruction - // - argument + // - argument* // - BasicBlock auto ins = dynamic_cast(op); + auto arg = dynamic_cast(op); if (ins) { assert(not ins->is_void() && "instr as op should not be void"); use.insert(op); + } else if (arg) { + use.insert(op); } } // in = use + (out - def) @@ -188,7 +190,9 @@ LiveRangeAnalyzer::transferFunction(Instruction *instr) { } void -LiveRangeAnalyzer::print(Function *func, bool printSet) const { // for debug +LiveRangeAnalyzer::print(Function *func, + bool printSet, + bool printInt) const { // for debug cout << "Function " << func->get_name() << endl; for (auto &bb : func->get_basic_blocks()) { for (auto &instr : bb.get_instructions()) { @@ -225,7 +229,7 @@ LiveRangeAnalyzer::print(Function *func, bool printSet) const { // for debug } } - if (printSet) { + if (printInt) { for (auto [interval, op] : liveIntervals) cout << op->get_name() << ": " << print_interval(interval) << endl; } diff --git a/src/codegen/regalloc.cpp b/src/codegen/regalloc.cpp index d484dc3..40a043e 100644 --- a/src/codegen/regalloc.cpp +++ b/src/codegen/regalloc.cpp @@ -1,5 +1,6 @@ #include "regalloc.hpp" +#include "Function.h" #include "Instruction.h" #include "liverange.hpp" @@ -9,25 +10,67 @@ using std::for_each; using namespace RA; +int +get_arg_id(Argument *arg) { + auto args = arg->get_parent()->get_args(); + int id = 1; + for (auto a : args) { + if (a == arg) + break; + ++id; + } + return id; +} + 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(); +RegAllocator::no_reg_alloca(Value *v) const { + auto instr = dynamic_cast(v); + auto arg = dynamic_cast(v); + if (instr) + return instr->is_alloca() or instr->is_cmp() or instr->is_fcmp() or + instr->is_zext(); + if (arg) { + return get_arg_id(arg) > ARG_MAX_R; + } else + assert(false && "only instruction and argument's LiveInterval exits"); } void -RegAllocator::reset() { +RegAllocator::reset(Function *func) { + cur_func = func; regmap.clear(); active.clear(); for_each(used, used + R + 1, [](bool &u) { u = false; }); } +int +RegAllocator::ReserveForArg(const LVITS &Liveints) { + auto args = cur_func->get_args(); + auto it_int = Liveints.begin(); + auto it_arg = args.begin(); + int reg; + for (reg = 1; reg <= args.size() and reg <= ARG_MAX_R; ++reg) { + auto arg = *it_arg; + auto liveint = *it_int; + assert(arg == liveint.second && "arg should be in order in liveints"); + + used[reg] = true; + regmap[arg] = reg; + active.insert(liveint); + ++it_arg, ++it_int; + } + return reg; +} + void -RegAllocator::LinearScan(const LVITS &liveints) { - reset(); +RegAllocator::LinearScan(const LVITS &liveints, Function *func) { + reset(func); + ReserveForArg(liveints); int reg; for (auto liveint : liveints) { + if (dynamic_cast(liveint.second)) { + continue; + } if (no_reg_alloca(liveint.second)) continue; ExpireOldIntervals(liveint); @@ -54,6 +97,8 @@ RegAllocator::ExpireOldIntervals(LiveInterval liveint) { void RegAllocator::SpillAtInterval(LiveInterval liveint) { auto spill = *active.rbegin(); + if (dynamic_cast(spill.second)) + return; if (spill.first.j > liveint.first.j) { // cancel reg allocation for spill regmap[liveint.second] = regmap.at(spill.second); diff --git a/tests/5-bonus/testcases/16-argparse.cminus b/tests/5-bonus/testcases/16-argparse.cminus new file mode 100644 index 0000000..62b954f --- /dev/null +++ b/tests/5-bonus/testcases/16-argparse.cminus @@ -0,0 +1,29 @@ +int getarg(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) +{ + output(a); + output(b); + output(c); + output(d); + output(e); + output(f); + output(g); + output(h); + output(i); + output(j); +} +int main(void) +{ + int arr[100]; + arr[0] = input(); + arr[1] = input(); + arr[2] = input(); + arr[3] = input(); + arr[4] = input(); + arr[5] = input(); + arr[6] = input(); + arr[7] = input(); + arr[8] = input(); + arr[9] = input(); + getarg(arr[0], arr[1], arr[2], arr[3], arr[4], arr[5], arr[6], arr[7], arr[8], arr[9]); + return 0; +} diff --git a/tests/5-bonus/testcases/16-argparse.in b/tests/5-bonus/testcases/16-argparse.in new file mode 100644 index 0000000..6b4c18b --- /dev/null +++ b/tests/5-bonus/testcases/16-argparse.in @@ -0,0 +1,10 @@ +826 +-652 +-395 +146 +704 +859 +728 +556 +609 +-822 diff --git a/tests/5-bonus/testcases/16-argparse.out b/tests/5-bonus/testcases/16-argparse.out new file mode 100644 index 0000000..6b4c18b --- /dev/null +++ b/tests/5-bonus/testcases/16-argparse.out @@ -0,0 +1,10 @@ +826 +-652 +-395 +146 +704 +859 +728 +556 +609 +-822 -- GitLab