#include "codegen.hpp" #include "BasicBlock.h" #include "Constant.h" #include "Function.h" #include "GlobalVariable.h" #include "Instruction.h" #include "Type.h" #include "Value.h" #include "ast.hpp" #include "regalloc.hpp" #include "syntax_analyzer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include // $r0 $zero constant 0 // $r1 $ra return address // $r2 $tp thread pointer // $r3 $sp stack pointer // $r4 - $r5 $a0 - $a1 argument, return value // $r6 - $r11 $a2 - $a7 argument // $r12 - $r20 $t0 - $t8 temporary // $r21 saved // $r22 $fp frame pointer // $r23 - $r31 $s0 - $s8 static using std::deque; using std::to_string; using std::operator""s; 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 = (is_float ? RA_float.get() : RA_int.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() { phi_map.clear(); for (auto &func : m->get_functions()) for (auto &bb : func.get_basic_blocks()) for (auto &instr : bb.get_instructions()) { if (not instr.is_phi()) continue; for (int i = 0; i < instr.get_num_operand() / 2; i++) { auto key = static_cast(instr.get_operand(2 * i + 1)); auto value = std::make_pair(&instr, instr.get_operand(2 * i)); phi_map[key].push_back(value); } } } void CodeGen::run() { // 以下内容生成 int main() { return 0; } 的汇编代码 getPhiMap(); output.push_back(".text"); // global variables for (auto &globl : m->get_global_variable()) { auto type = globl.get_type()->get_pointer_element_type(); output.push_back(".comm " + globl.get_name() + ", " + to_string(typeLen(type))); } // arguments: stack transfer for (auto &func : m->get_functions()) // 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_int.LinearScan(LRA.get(), &func); RA_float.LinearScan(LRA.get(), &func); std::cout << "integer register map for function: " << func.get_name() << std::endl; RA_int.print([](int i) { return regname(i, false); }); std::cout << "float register map for function: " << func.get_name() << std::endl; RA_float.print([](int i) { return regname(i, true); }); for (auto [_, op] : LRA.get()) { auto regmap = op->get_type()->is_float_type() ? RA_float.get() : RA_int.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()); output.push_back(".type " + func.get_name() + ", @function"); output.push_back(func.get_name() + ":"); // sp and fp balabala stackMemAlloc(); for (auto &bb : func.get_basic_blocks()) { output.push_back(label_in_assem(&bb) + ":"); for (auto &instr : bb.get_instructions()) { IR2assem(instr, bb); } } // restore the stack 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 CodeGen::ptrContent2reg(Value *ptr, string dest_reg) { 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 suff = suffix(ele_tp); auto [addr_reg, find] = getRegName(ptr, 0); if (dynamic_cast(ptr)) { output.push_back("la.local " + addr_reg + ", " + ptr->get_name()); output.push_back(instr_ir + suff + " " + dest_reg + ", " + addr_reg + ", 0"); } else if (dynamic_cast(ptr)) { makeSureInRange( instr_ir + suff, dest_reg, FP, -off.at(ptr), instr_ir + "x" + suff); /* output.push_back(instr_ir + suff + " " + reg_name + ", $fp, -" + * to_string(off.at(ptr))); */ } else if (dynamic_cast(ptr)) { // auto GEP_instr = static_cast(ptr); if (not find) { makeSureInRange("ld.d", addr_reg, FP, -off.at(ptr), "ldx.d"); /* output.push_back("ld.d " + addr_reg + ", $fp, -" + * to_string(off.at(ptr))); */ } output.push_back(instr_ir + suff + " " + dest_reg + ", " + addr_reg + ", 0"); } else assert(false && "unknown type"); } string 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 == CONST_0) return "$zero"; if (dynamic_cast(v)) { auto const_int_v = static_cast(v)->get_value(); auto [l, h] = immRange(12, false); if (l <= const_int_v and const_int_v <= h) { output.push_back("addi.d " + reg_name + ", $zero, " + to_string(const_int_v)); return reg_name; } } auto constant = static_cast(v); 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"); // bug here: maybe output.push_back("la.local " + tmp_ireg + ", " + addr); output.push_back(instr_ir + " " + reg_name + ", " + tmp_ireg + ", 0"); } else if (dynamic_cast(v)) { output.push_back("la.local " + reg_name + ", " + v->get_name()); } else if (dynamic_cast(v)) { // auto alloc_instr = dynamic_cast(v); // give the stack address makeSureInRange("addi.d", reg_name, FP, -off.at(v), "add.d", i); /* 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; for (auto iter = args.begin(); id <= args.size(); ++iter, ++id) if (*iter == v) break; if (id <= ARG_R) return regname(ARG_R, is_float); else { string instr_ir = is_float ? "fld" : "ld"; auto suff = suffix(v->get_type()); makeSureInRange(instr_ir + suff, reg_name, FP, func_arg_off.at(cur_func).at(id), instr_ir + "x" + suff, i); /* output.push_back(instr_ir + suff + " " + reg_name + ", $fp, " + * to_string(func_arg_off.at(cur_func).at(id))); */ } } else { string instr_ir = is_float ? "fld" : "ld"; auto suff = suffix(v->get_type()); makeSureInRange(instr_ir + suff, reg_name, FP, -off.at(v), instr_ir + "x" + suff, i); /* output.push_back(instr_ir + suff + " " + reg_name + * ", $fp, -" + to_string(off.at(v))); */ } return reg_name; } void CodeGen::compute_arg_info(Function *func) { if (func_arg_off.find(func) != func_arg_off.end()) return; 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 != rend;) { --iter; auto tplen = typeLen(*iter); argN = ALIGN(argN, tplen) + tplen; arg_off[arg_id--] = argN; } 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; } // the addr for opk is: fp - off[opk] void CodeGen::stackMemAlloc() { // preserved for $ra and $fp stackN = 16; off.clear(); for (auto &bb : cur_func->get_basic_blocks()) for (auto &instr : bb.get_instructions()) { if (no_stack_alloca(&instr)) continue; int tplen; if (instr.is_alloca()) { auto alloc_instr = static_cast(&instr); tplen = typeLen(alloc_instr->get_alloca_type()); } else { auto type = instr.get_type(); tplen = typeLen(type); } stackN = ALIGN(stackN, tplen) + tplen; off[&instr] = stackN; } stackN = STACK_ALIGN(stackN); output.push_back("# prolog"); makeSureInRange("addi.d", SP, SP, -stackN, "add.d"); makeSureInRange("st.d", RA_reg, SP, stackN - 8, "stx.d"); makeSureInRange("st.d", FP, SP, stackN - 16, "stx.d"); makeSureInRange("addi.d", FP, SP, stackN, "add.d"); /* output.push_back("addi.d $sp, $sp, -" + to_string(stackN)); * output.push_back("st.d $ra, $sp," + to_string(stackN - 8)); * 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"); makeSureInRange("ld.d", RA_reg, SP, stackN - 8, "ldx.d"); makeSureInRange("ld.d", FP, SP, stackN - 16, "ldx.d"); makeSureInRange("addi.d", SP, SP, stackN, "add.d"); /* 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("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()); string f_reg = value2reg(instr->get_operand(0)); string f_treg = "$ft0"; auto [i_reg, _] = getRegName(instr); output.push_back("ftintrz.w.s " + f_treg + ", " + f_reg); output.push_back("movfr2gr.s " + i_reg + ", " + f_treg); 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()); 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 CodeGen::bool2branch(Instruction *cond) { assert(cond->get_type() == m->get_int1_type()); auto icmp_instr = dynamic_cast(cond); auto fcmp_instr = dynamic_cast(cond); assert(icmp_instr or fcmp_instr); string instr_ir; bool reverse = false; if (icmp_instr) { switch (icmp_instr->get_cmp_op()) { case CmpInst::EQ: instr_ir = "beq"; break; case CmpInst::NE: { instr_ir = "bne"; if (cond->get_operand(1) == CONST_0 and dynamic_cast(cond->get_operand(0)) and dynamic_cast(cond->get_operand(0)) ->is_zext()) { // something like: // %op0 = icmp slt i32 1, 2 # deepest // %op1 = zext i1 %op0 to i32 # this zext has no register // %op2 = icmp ne i32 %op1, 0 // br i1 %op2, label %label3, label %label5 auto deepest = static_cast( static_cast(cond->get_operand(0)) ->get_operand(0)); return bool2branch(deepest); } } break; case CmpInst::GT: instr_ir = "blt"; reverse = true; break; case CmpInst::GE: instr_ir = "bge"; break; case CmpInst::LT: instr_ir = "blt"; break; case CmpInst::LE: instr_ir = "bge"; reverse = true; break; } auto reg1 = value2reg(cond->get_operand(0), 0); auto reg2 = value2reg(cond->get_operand(1), 1); return instr_ir + " " + (reverse ? (reg2 + ", " + reg1) : (reg1 + ", " + reg2)) + ","; } else if (fcmp_instr) { switch (fcmp_instr->get_cmp_op()) { case FCmpInst::EQ: instr_ir = "fcmp.ceq.s $fcc0"; break; case FCmpInst::NE: instr_ir = "fcmp.cne.s $fcc0"; break; case FCmpInst::GT: instr_ir = "fcmp.cle.s $fcc0"; reverse = true; break; case FCmpInst::GE: instr_ir = "fcmp.clt.s $fcc0"; reverse = true; break; case FCmpInst::LT: instr_ir = "fcmp.clt.s $fcc0"; break; case FCmpInst::LE: instr_ir = "fcmp.cle.s $fcc0"; break; } auto reg1 = value2reg(cond->get_operand(0), 0); auto reg2 = value2reg(cond->get_operand(1), 1); output.push_back(instr_ir + ", " + reg1 + ", " + reg2); return (reverse ? "bceqz $fcc0," : "bcnez $fcc0,"); } else assert(false); } void CodeGen::IR2assem(BranchInst *instr) { if (instr->is_cond_br()) { auto TBB = static_cast(instr->get_operand(1)); auto FBB = static_cast(instr->get_operand(2)); // value2reg(instr->get_operand(0)); auto cond = instr->get_operand(0); if (dynamic_cast(cond)) { auto const_bool = static_cast(cond); assert(const_bool->get_type()->is_integer_type() and static_cast(const_bool->get_type()) ->get_num_bits() == 1); bool cond_value = const_bool->get_value(); output.push_back("b " + label_in_assem(cond_value ? TBB : FBB)); } else { string instr_ir = bool2branch(static_cast(instr->get_operand(0))); output.push_back(instr_ir + " " + label_in_assem(TBB)); output.push_back("b " + label_in_assem(FBB)); } } else { auto bb = static_cast(instr->get_operand(0)); output.push_back("b " + label_in_assem(bb)); } } void CodeGen::pass_arguments(CallInst *instr) { /* cannot use the arg order simply, example leading to error: * a0<-..., a1<-a0 * so we need an suitable order and use at most 1 tmp reg to pass arguments */ // ASSERT: use index start from 1 const int N = 8; auto func = static_cast(instr->get_operand(0)); string v_reg, instr_ir, suff; // 1. get rely graph for $a regs // for example, $a1 is need by needby[1], which is a set vector needby[N + 1]; for (int arg_id = 1; arg_id < instr->get_num_operand(); arg_id++) { auto arg_value = instr->get_operand(arg_id); v_reg = getRegName(arg_value).first; if (v_reg.substr(0, 2) != "$a") continue; else { int v_id = std::stoi(to_string(v_reg[2])) - 47; if (v_id != arg_id) needby[v_id].push_back(arg_id); } } // 2. get traverse order: an enhanced topological order // key: if there is a cycle, should give out an order rather than endless // loop, and the order should statisfy: vector order; deque queue; bool vis[N + 1]{false}; map backup; for (int arg_id = 1; arg_id < instr->get_num_operand(); arg_id++) queue.push_back(arg_id); // initialize while (not queue.empty()) { int i = queue.front(); queue.pop_front(); if (find(order.begin(), order.end(), i) != order.end()) continue; // already has order bool assign; if (needby[i].size() == 0) { // there is no argument relying on $a_i or is self rely assign = true; } else if (vis[i]) { // cycle detected backup[i] = true; assign = true; } else assign = false; if (assign) { order.push_back(i); for (int j = 1; j <= N; ++j) { // remove $a_i 's rely auto &need_vec = needby[j]; auto iter = find(need_vec.begin(), need_vec.end(), i); if (iter != need_vec.end()) { // $a_i has at most one rely on $a_ need_vec.erase(iter); if (needby[j].size() == 0) { queue.push_front(j); } break; } } } else queue.push_back(i); vis[i] = true; } // 3. pass arguments' value int passed = 0; // assert(order.size() >= func->get_num_of_args()); map changed; // bool assigned[8] = {false}; string t0_contained; for (auto arg_id : order) { if (arg_id > func->get_num_of_args()) continue; auto arg_value = instr->get_operand(arg_id); auto arg_is_float = arg_value->get_type()->is_float_type(); auto arg_reg_aid = regname(arg_id, arg_is_float); auto t_reg = arg_is_float ? "$ft0" : "$t0"; // the value is actually in v_reg, and the arg corresponds to // arg_reg_aid(only right when arg_id <= 8) v_reg = value2reg(arg_value, 1); if (backup[arg_id]) { // a_id still relied by some argument due to cycle assert(not changed[arg_reg_aid]); gencopy(t_reg, arg_reg_aid, arg_is_float); t0_contained = arg_reg_aid; } // in case that the src register has been wroten if (changed[v_reg]) { assert(t0_contained == v_reg); v_reg = arg_value->get_type()->is_float_type() ? "$ft0" : "$t0"; } if (arg_id <= ARG_R) { // pass by register gencopy(arg_reg_aid, v_reg, arg_is_float); } else { // pass by stack instr_ir = (arg_value->get_type()->is_float_type() ? "fst" : "st"); suff = suffix(arg_value->get_type()); makeSureInRange(instr_ir + suff, v_reg, SP, func_arg_off.at(func).at(arg_id), instr_ir + "x" + suff); /* output.push_back(instr_ir + suff + " " + v_reg + ", * $sp, " + to_string(func_arg_off.at(func).at(arg_id))); */ } if (arg_reg_aid != v_reg) { changed[arg_reg_aid] = true; } passed++; } assert(passed == func->get_num_of_args()); } 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_int = RA_int.get(); auto regmap_float = RA_float.get(); // int storeN = 0; vector> store_record; for (auto [op, interval] : LRA.get_interval_map()) { if (RA::RegAllocator::no_reg_alloca(op)) continue; auto [name, find] = getRegName(op); if (not find) continue; auto op_type = op->get_type(); auto op_is_float = op_type->is_float_type(); if (not instr->get_function_type()->get_return_type()->is_void_type()) { // if the called function return a value, and the mapped register is // just $a0/$fa0, there is no need for restore bool ret_float = instr->get_function_type()->get_return_type()->is_float_type(); auto ®map_ret = (ret_float ? regmap_float : regmap_int); if (regmap_ret.find(instr) != regmap_ret.end() and regmap_ret.at(instr) == 1) if (name == (ret_float ? "$fa0" : "a0")) continue; } bool restore = false; if (interval.i == interval.j) ; else if (interval.i < cur_i and cur_i < interval.j) restore = true; else if (interval.i == cur_i) { auto inset = LRA.get_in_set().at(cur_i); restore = inset.find(op) != inset.end(); } else ; if (restore) { cout << "At point " << cur_i << ", restore for " << op->get_name() << ", interval " << LRA.print_interval(interval) << endl; int tplen = typeLen(op_type); storeN = ALIGN(storeN, tplen) + tplen; auto name = regname( (op_is_float ? regmap_float : regmap_int).at(op), op_is_float); store_record.push_back({op, name, storeN}); } } int totalN = STACK_ALIGN(ALIGN(storeN, 8) + func_argN); // stack space allocation if (totalN) { makeSureInRange("addi.d", SP, SP, -totalN, "add.d"); // 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"); suff = suffix(op->get_type()); makeSureInRange( instr_ir + suff, reg, SP, totalN - off, instr_ir + "x" + suff); /* output.push_back(instr_ir + suff + " " + reg + ", $sp, " + * to_string(totalN - off)); */ } // pass arguments pass_arguments(instr); output.push_back("bl " + func->get_name()); // 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()); makeSureInRange( instr_ir + suff, reg, SP, totalN - off, instr_ir + "x" + suff); /* output.push_back(instr_ir + suff + " " + reg + ", $sp, " + * to_string(totalN - off)); */ } if (totalN) { makeSureInRange("addi.d", SP, SP, totalN, "add.d"); // output.push_back("addi.d $sp, $sp, " + to_string(totalN)); } } void CodeGen::IR2assem(BinaryInst *instr) { 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 + " " + reg + ", " + reg1 + ", " + reg2); gencopy(instr, reg); } void CodeGen::IR2assem(GetElementPtrInst *instr) { assert(instr->get_num_operand() <= 3); 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 } 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 CodeGen::IR2assem(LoadInst *instr) { auto [reg, find] = getRegName(instr); ptrContent2reg(instr->get_lval(), reg); gencopy(instr, reg); } void CodeGen::IR2assem(StoreInst *instr) { 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()); 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); 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"); } void CodeGen::IR2assem(ZextInst *instr) { if (RA::RegAllocator::no_reg_alloca(instr)) return; assert(instr->get_num_operand() == 1); auto cmp_instr = instr->get_operand(0); auto icmp_instr = dynamic_cast(cmp_instr); auto fcmp_instr = dynamic_cast(cmp_instr); assert(icmp_instr or fcmp_instr); auto [dest_reg, _] = getRegName(instr); string instr_ir; bool reverse = false, flip = false, check = false; if (icmp_instr) { switch (icmp_instr->get_cmp_op()) { case CmpInst::EQ: instr_ir = "xor"; check = flip = true; break; case CmpInst::NE: instr_ir = "xor"; check = true; break; case CmpInst::GT: instr_ir = "slt"; reverse = true; break; case CmpInst::GE: instr_ir = "slt"; flip = true; break; case CmpInst::LT: instr_ir = "slt"; break; case CmpInst::LE: instr_ir = "slt"; reverse = true; flip = true; break; } auto reg1 = value2reg(icmp_instr->get_operand(0), 0); auto reg2 = value2reg(icmp_instr->get_operand(1), 1); output.push_back( instr_ir + " " + dest_reg + ", " + (reverse ? (reg2 + ", " + reg1) : (reg1 + ", " + reg2))); if (check) { if (flip) output.push_back("sltui " + dest_reg + ", " + dest_reg + ", 1"); else output.push_back("sltu " + dest_reg + ", $zero, " + dest_reg); } else if (flip) // check && flip can be solved in a single // instruction output.push_back("sltui " + dest_reg + ", " + dest_reg + ", 1"); } else { switch (fcmp_instr->get_cmp_op()) { case FCmpInst::EQ: instr_ir = "fcmp.ceq.s"; break; case FCmpInst::NE: instr_ir = "fcmp.cne.s"; break; case FCmpInst::GT: instr_ir = "fcmp.cle.s"; reverse = true; break; case FCmpInst::GE: instr_ir = "fcmp.clt.s"; reverse = true; break; case FCmpInst::LT: instr_ir = "fcmp.clt.s"; break; case FCmpInst::LE: instr_ir = "fcmp.cle.s"; break; } auto reg1 = value2reg(fcmp_instr->get_operand(0), 0); auto reg2 = value2reg(fcmp_instr->get_operand(1), 1); string cmp_reg = "$fcc0"; auto label = "cmp_zext_" + to_string(++cmp_zext_cnt); output.push_back(instr_ir + " " + cmp_reg + ", " + reg1 + ", " + reg2); output.push_back("or " + dest_reg + ", $zero, $zero"); output.push_back((reverse ? "bcnez " : "bceqz ") + cmp_reg + ", " + label); output.push_back("addi.w " + dest_reg + ", $zero, 1"); output.push_back(label + ":"); } gencopy(instr, dest_reg); } 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)); break; case Instruction::br: IR2assem(static_cast(&instr)); break; // Standard binary operators case Instruction::add: case Instruction::sub: case Instruction::mul: case Instruction::sdiv: // float binary operators case Instruction::fadd: case Instruction::fsub: case Instruction::fmul: case Instruction::fdiv: IR2assem(static_cast(&instr)); break; // Memory operators case Instruction::alloca: IR2assem(static_cast(&instr)); break; case Instruction::load: IR2assem(static_cast(&instr)); break; case Instruction::store: IR2assem(static_cast(&instr)); break; // Other operators case Instruction::cmp: IR2assem(static_cast(&instr)); break; case Instruction::fcmp: IR2assem(static_cast(&instr)); break; case Instruction::phi: IR2assem(static_cast(&instr)); break; case Instruction::call: IR2assem(static_cast(&instr)); break; case Instruction::getelementptr: IR2assem(static_cast(&instr)); break; case Instruction::zext: IR2assem(static_cast(&instr)); break; case Instruction::fptosi: IR2assem(static_cast(&instr)); break; case Instruction::sitofp: IR2assem(static_cast(&instr)); break; } // assert(false && "This ") if (not instr.is_void() and not no_stack_alloca(&instr) and not instr.is_alloca() and not instr.is_phi()) back2stack(&instr); }