diff --git a/src/codegen/codegen.cpp b/src/codegen/codegen.cpp index 8e522752e5c66b631e2ffe7d0e66eb4a57b03b78..ca2e1063f3b4ca2e093d0925070c4dfcadd71d31 100644 --- a/src/codegen/codegen.cpp +++ b/src/codegen/codegen.cpp @@ -13,11 +13,16 @@ #include "Instruction.h" #include "Type.h" #include "Value.h" +#include "ast.hpp" +#include #include #include +#include #include +#include #include +#include // $r0 $zero constant 0 // $r1 $ra return address @@ -95,6 +100,7 @@ CodeGen::run() { // funtions for (auto &func : m->get_functions()) { if (not func.is_declaration()) { + LRA.run(&func); cur_func = &func; output.push_back(""); output.push_back(".globl " + func.get_name()); @@ -113,6 +119,24 @@ CodeGen::run() { stackMemDealloc(); } } + // read only data + output.push_back(".section .rodata"); + for (auto [constant, name] : ROdata) { + auto int_ = dynamic_cast(constant); + auto float_ = dynamic_cast(constant); + string value; + assert((int_ || float_) && "wrong type"); + if (int_) { + value = to_string(int_->get_value()); + } else { + std::stringstream ss; + float v = (float_->get_value()); + ss << std::hex << *(uint32_t *)&v; + value = "0x" + ss.str(); + } + output.push_back(name + ": "); + output.push_back(".word " + value); + } } void @@ -145,8 +169,23 @@ void CodeGen::value2reg(Value *v, int id) { bool is_float = v->get_type()->is_float_type(); auto reg_name = (is_float ? "$fa" : "$a") + to_string(id); + string tmp_ireg = "$t0"; if (dynamic_cast(v)) { auto constant = static_cast(v); +#ifdef __RO_PART__ + if (ROdata.find(constant) == ROdata.end()) + ROdata[constant] = ".LC" + to_string(ROdata.size()); + string instr_ir, addr = ROdata[constant]; + if (dynamic_cast(constant)) + instr_ir = "ld.w"; + else if (dynamic_cast(constant)) + instr_ir = "fld.s"; + else + assert(false && "wait for completion"); + output.push_back("la.local " + tmp_ireg + ", " + addr); + output.push_back(instr_ir + " " + reg_name + ", " + tmp_ireg + ", 0"); +#else + if (dynamic_cast(constant)) { int k = static_cast(constant)->get_value(); if ((k & 0xfff) != k) { @@ -159,7 +198,6 @@ CodeGen::value2reg(Value *v, int id) { } else if (dynamic_cast(constant)) { // move the binary code to int-reg, then use movgr2fr to move the // value to float-reg - string tmp_ireg = "$t0"; float k = static_cast(constant)->get_value(); int hex_int = *(uint32_t *)&k; if ((hex_int & 0xfff) != hex_int) @@ -173,6 +211,7 @@ CodeGen::value2reg(Value *v, int id) { } else assert(false && "wait for completion"); +#endif } else if (dynamic_cast(v)) { output.push_back("la.local " + reg_name + ", " + v->get_name()); } else if (dynamic_cast(v)) { @@ -218,7 +257,6 @@ void CodeGen::stackMemDealloc() { output.push_back("# epilog"); // 7: return value should be determined already! - // output.push_back("addi.w $a0, $zero, 0"); output.push_back(cur_func->get_name() + "_end:"); output.push_back("ld.d $ra, $fp, -8"); output.push_back("addi.d $sp, $sp, " + to_string(stackN)); @@ -391,6 +429,8 @@ CodeGen::IR2assem(BinaryInst *instr) { value2reg(instr->get_operand(1), 1); 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")); diff --git a/src/codegen/liverange.cpp b/src/codegen/liverange.cpp new file mode 100644 index 0000000000000000000000000000000000000000..797b5a1c1727276cf8c97c3d545fb711218225ad --- /dev/null +++ b/src/codegen/liverange.cpp @@ -0,0 +1,218 @@ +#include "liverange.hpp" + +#include "Function.h" +#include "Instruction.h" + +#include +#include + +void +LiveRangeAnalyzer::clear() { + IN.clear(); + OUT.clear(); + liverange.clear(); + instr_id.clear(); +} + +LiveRangeAnalyzer::LiveSet +LiveRangeAnalyzer::joinFor(BasicBlock *bb) { + LiveSet out; + for (auto succ : bb->get_succ_basic_blocks()) { + auto &irs = succ->get_instructions(); + auto it = irs.begin(); + while (it != irs.end() and it->is_phi()) + ++it; + assert(it != irs.end() && "need to find first_ir from copy-stmt"); + union_ip(out, IN[instr_id.at(&(*it))]); + // std::cout << "# " + it->print() << std::endl; + } + // std::cout << "\tget out: " << print_liveSet(out) << std::endl; + return out; +} + +void +LiveRangeAnalyzer::make_id(Function *func) { + // instruction numbering + // this is also the structure of the IR logically: + // ignore phi, add copy-statement + int ir_cnt = 0; + for (auto &bb : func->get_basic_blocks()) { + for (auto &instr : bb.get_instructions()) { + if (instr.is_phi()) + continue; + if (instr.is_br() or instr.is_ret()) { + // insert copy-stmt in front of the jump ir + auto it = phi_map.find(&bb); + if (it != phi_map.end()) { + for (auto pr : it->second) { + cpstmt_id[pr] = ++ir_cnt; + } + } + } + instr_id[&instr] = ++ir_cnt; + } + } +} + +void +LiveRangeAnalyzer::run(Function *func) { + clear(); + make_id(func); +#ifdef __LRA_PRINT__ + print(func, false); +#endif + bool cont = true; + while (cont) { + cont = false; + // reverse traverse BasicBlocks + for (auto rit_bb = func->get_basic_blocks().rbegin(); + rit_bb != func->get_basic_blocks().rend(); + ++rit_bb) { + auto bb = &(*rit_bb); + + LiveSet bef_in, out; + bool last_ir = true; + + // reverse traverse instructions + for (auto rit_ir = rit_bb->get_instructions().rbegin(); + rit_ir != rit_bb->get_instructions().rend(); + ++rit_ir) { + auto instr = &(*rit_ir); + if (instr->is_phi()) { + assert(not last_ir && "If phi is the last ir, then data " + "flow fails due to ignorance of phi"); + continue; + } + // + // get out-set for this instruction + if (last_ir) { + last_ir = false; + out = joinFor(bb); + } else { + out = bef_in; + } + OUT[instr_id.at(instr)] = out; + // + // get in-set + bef_in = transferFunction(instr); + cont |= bef_in != IN[instr_id.at(instr)]; + IN[instr_id.at(instr)] = bef_in; + + if (instr->is_ret() or instr->is_br()) { + // deal with copy-stmt + auto it = phi_map.find(bb); + if (it != phi_map.end()) { + for (auto rit = it->second.rbegin(); + rit != it->second.rend(); + ++rit) { + auto [lv, rv] = *rit; + if (last_ir) { + last_ir = false; + out = joinFor(bb); + } else + out = bef_in; + + OUT[cpstmt_id.at(*rit)] = out; + // transfer manually + out.erase(lv); + if (dynamic_cast(rv)) + out.insert(rv); + cont |= out != IN[cpstmt_id.at(*rit)]; + bef_in = IN[cpstmt_id.at(*rit)] = out; + } + } + } + } + } + } +#ifdef __LRA_PRINT__ + print(func); +#endif +} + +LiveRangeAnalyzer::LiveSet +LiveRangeAnalyzer::transferFunction(Instruction *instr) { + LiveSet in, out = OUT[instr_id.at(instr)]; + LiveSet use; + + // calculate use for this instruction + for (auto op : instr->get_operands()) { + // op type: + // - global + // - function + // - Constant + // - instruction + // - argument + // - BasicBlock + auto ins = dynamic_cast(op); + if (ins) { + assert(not ins->is_void() && "instr as op should not be void"); + use.insert(op); + } + } + // in = use + (out - def) + auto iter = out.find(instr); + if (iter != out.end()) + out.erase(iter); + std::set_union(out.begin(), + out.end(), + use.begin(), + use.end(), + std::inserter(in, in.begin())); + + return in; +} + +void +LiveRangeAnalyzer::print(Function *func, bool printSet) { // for debug + for (auto &bb : func->get_basic_blocks()) { + for (auto &instr : bb.get_instructions()) { + if (instr.is_phi()) // ignore phi + continue; + // insert copy-stmt + if ((instr.is_br() or instr.is_ret()) and + phi_map.find(&bb) != phi_map.end()) { + for (auto pr : phi_map.find(&bb)->second) { + auto [lv, rv] = pr; + auto idx = cpstmt_id.at(pr); + std::cout + << cpstmt_id[pr] << ". " << lv->get_name() << " = " + << (rv->get_name() == "" ? rv->print() : rv->get_name()) + << std::endl; + if (not printSet) + continue; + auto &in = IN.at(idx); + auto &out = OUT.at(idx); + std::cout << "\tin-set: " + print_liveSet(in) << "\n"; + std::cout << "\tout-set: " + print_liveSet(out) << "\n"; + } + } + // normal ir + std::cout << instr_id[&instr] << ". " << instr.print() << " # " + << &instr << std::endl; + if (not printSet) + continue; + auto idx = instr_id.at(&instr); + auto &in = IN.at(idx); + auto &out = OUT.at(idx); + std::cout << "\tin-set: " + print_liveSet(in) << "\n"; + std::cout << "\tout-set: " + print_liveSet(out) << "\n"; + } + /* if (phi_map.find(&bb) != phi_map.end()) { + * for (auto pr : phi_map.find(&bb)->second) { + * auto [lv, rv] = pr; + * auto idx = cpstmt_id.at(pr); + * std::cout << cpstmt_id[pr] << ". " << lv->get_name() << " = " + * << (rv->get_name() == "" ? rv->print() + * : rv->get_name()) + * << std::endl; + * if (not printSet) + * continue; + * auto &in = IN.at(idx); + * auto &out = OUT.at(idx); + * std::cout << "\tin-set: " + print_liveSet(in) << "\n"; + * std::cout << "\tout-set: " + print_liveSet(out) << "\n"; + * } + * } */ + } +}