diff --git a/decompiler/Function/Function.cpp b/decompiler/Function/Function.cpp index e21aa6a877..11b2def19d 100644 --- a/decompiler/Function/Function.cpp +++ b/decompiler/Function/Function.cpp @@ -699,4 +699,14 @@ int Function::get_failed_basic_op_count() { } } return count; +} + +int Function::get_reginfo_basic_op_count() { + int count = 0; + for (auto& x : basic_ops) { + if (x->reg_info_set) { + count++; + } + } + return count; } \ No newline at end of file diff --git a/decompiler/Function/Function.h b/decompiler/Function/Function.h index 071b252c46..1455a957a4 100644 --- a/decompiler/Function/Function.h +++ b/decompiler/Function/Function.h @@ -85,6 +85,7 @@ class Function { const TypeMap& get_typemap_by_instr_idx(int idx); int get_basic_op_count(); int get_failed_basic_op_count(); + int get_reginfo_basic_op_count(); void run_type_analysis(const TypeSpec& my_type, DecompilerTypeSystem& dts, LinkedObjectFile& file); diff --git a/decompiler/IR/BasicOpBuilder.cpp b/decompiler/IR/BasicOpBuilder.cpp index 1aca50bea0..02696b3928 100644 --- a/decompiler/IR/BasicOpBuilder.cpp +++ b/decompiler/IR/BasicOpBuilder.cpp @@ -15,6 +15,10 @@ namespace { +/////////////////////////////// +// Helpers +/////////////////////////////// + /*! * Create a GOAL "set!" form. * These will later be compacted into more complicated nested expressions. @@ -54,27 +58,29 @@ std::shared_ptr make_int(int64_t x) { } /*! - * Create an assembly passthrough in the form op dst, src, src + * Create an assembly passthrough in the form op dst, src, src. Sets register info. */ std::shared_ptr to_asm_reg_reg_reg(const std::string& str, Instruction& instr, int idx) { auto result = std::make_shared(str); result->dst = make_reg(instr.get_dst(0).get_reg(), idx); result->src0 = make_reg(instr.get_src(0).get_reg(), idx); result->src1 = make_reg(instr.get_src(1).get_reg(), idx); + result->set_reg_info(); return result; } /*! - * Create an assembly passthrough for op src + * Create an assembly passthrough for op src. Sets register info. */ std::shared_ptr to_asm_src_reg(const std::string& str, Instruction& instr, int idx) { auto result = std::make_shared(str); result->src0 = make_reg(instr.get_src(0).get_reg(), idx); + result->set_reg_info(); return result; } /*! - * Create an assembly passthrough for op dst src + * Create an assembly passthrough for op dst src. Sets register info. */ std::shared_ptr to_asm_dst_reg_src_reg(const std::string& str, Instruction& instr, @@ -82,6 +88,7 @@ std::shared_ptr to_asm_dst_reg_src_reg(const std::string& str, auto result = std::make_shared(str); result->dst = make_reg(instr.get_dst(0).get_reg(), idx); result->src0 = make_reg(instr.get_src(0).get_reg(), idx); + result->set_reg_info(); return result; } @@ -103,6 +110,13 @@ std::shared_ptr instr_atom_to_ir(const InstructionAtom& ia, int idx) { } } +/////////////////////////////// +// Assembly +/////////////////////////////// + +/*! + * Convert an assembly operation to a IR. Sets register info. + */ std::shared_ptr to_asm_automatic(const std::string& str, Instruction& instr, int idx) { auto result = std::make_shared(str); assert(instr.n_dst < 2); @@ -123,9 +137,13 @@ std::shared_ptr to_asm_automatic(const std::string& str, Instruction& result->src1 = instr_atom_to_ir(instr.get_src(2), idx); } + result->set_reg_info(); return result; } +/*! + * Convert subu instruction to assembly op. GOAL doesn't generate subu's without inline assembly. + */ std::shared_ptr try_subu(Instruction& instr, int idx) { if (is_gpr_3(instr, InstructionKind::SUBU, {}, {}, {})) { return to_asm_reg_reg_reg("subu", instr, idx); @@ -133,6 +151,9 @@ std::shared_ptr try_subu(Instruction& instr, int idx) { return nullptr; } +/*! + * Convert sllv instruction to assembly op. GOAL doesn't generate sllv's without inline assembly. + */ std::shared_ptr try_sllv(Instruction& instr, int idx) { if (is_gpr_3(instr, InstructionKind::SLLV, {}, {}, make_gpr(Reg::R0))) { return to_asm_reg_reg_reg("sllv", instr, idx); @@ -140,81 +161,171 @@ std::shared_ptr try_sllv(Instruction& instr, int idx) { return nullptr; } +/////////////////////////////// +// Logical +/////////////////////////////// + +/*! + * OR (logical or of registers) is used three ways: + * 1. set a register to #f + * 2. set a register to the value of another register + * 3. logical OR + */ std::shared_ptr try_or(Instruction& instr, int idx) { if (is_gpr_3(instr, InstructionKind::OR, {}, make_gpr(Reg::S7), make_gpr(Reg::R0))) { - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - make_sym("#f")); + // set value to #f : or dest, s7, r0 + auto dest = instr.get_dst(0).get_reg(); + auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dest, idx), make_sym("#f")); + op->write_regs.push_back(dest); + op->reg_info_set = true; + return op; } else if (is_gpr_3(instr, InstructionKind::OR, {}, {}, make_gpr(Reg::R0))) { - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - make_reg(instr.get_src(0).get_reg(), idx)); + // set register from register : or dest, source, r0 + auto dest = instr.get_dst(0).get_reg(); + auto src = instr.get_src(0).get_reg(); + auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dest, idx), make_reg(src, idx)); + op->write_regs.push_back(dest); + op->read_regs.push_back(src); + op->reg_info_set = true; + return op; } else { - return make_set_atomic( + // actually do a logical OR of two registers. + auto op = make_set_atomic( IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), std::make_shared(IR_IntMath2::OR, make_reg(instr.get_src(0).get_reg(), idx), make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 2, 0); + return op; } return nullptr; } +/*! + * ORI (logical OR of register and 16-bit immediate) is used two ways: + * 1. Set a register to a 16-bit constant + * 2. logical OR with constant + */ std::shared_ptr try_ori(Instruction& instr, int idx) { if (instr.kind == InstructionKind::ORI && instr.get_src(0).is_reg(make_gpr(Reg::R0)) && instr.get_src(1).is_imm()) { - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - make_int(instr.get_src(1).get_imm())); + // load a constant. + auto dst = instr.get_dst(0).get_reg(); + auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dst, idx), + make_int(instr.get_src(1).get_imm())); + op->write_regs.push_back(dst); + op->reg_info_set = true; + return op; } else if (instr.kind == InstructionKind::ORI && instr.get_src(1).is_imm()) { - return make_set_atomic( - IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), + // do logical OR with a constant. + auto dst = instr.get_dst(0).get_reg(); + auto op = make_set_atomic( + IR_Set_Atomic::REG_64, make_reg(dst, idx), std::make_shared(IR_IntMath2::OR, make_reg(instr.get_src(0).get_reg(), idx), make_int(instr.get_src(1).get_imm()))); + op->write_regs.push_back(dst); + op->reg_info_set = true; + return op; } return nullptr; } +/*! + * POR - recognize POR as a move between 128-bit registers. + */ std::shared_ptr try_por(Instruction& instr, int idx) { if (is_gpr_3(instr, InstructionKind::POR, {}, {}, make_gpr(Reg::R0))) { - return make_set_atomic(IR_Set_Atomic::REG_I128, make_reg(instr.get_dst(0).get_reg(), idx), - make_reg(instr.get_src(0).get_reg(), idx)); + // move a 128-bit integer. + auto dst = instr.get_dst(0).get_reg(); + auto src = instr.get_src(0).get_reg(); + auto op = make_set_atomic(IR_Set_Atomic::REG_I128, make_reg(dst, idx), make_reg(src, idx)); + op->write_regs.push_back(dst); + op->read_regs.push_back(src); + op->reg_info_set = true; + return op; } return nullptr; } +/////////////////////////////// +// Moves +/////////////////////////////// + +/*! + * MTC1 (move to coprocessor 1) move from GPR to FPR. + */ std::shared_ptr try_mtc1(Instruction& instr, int idx) { if (instr.kind == InstructionKind::MTC1) { - return make_set_atomic(IR_Set_Atomic::GPR_TO_FPR, make_reg(instr.get_dst(0).get_reg(), idx), - make_reg(instr.get_src(0).get_reg(), idx)); + auto op = make_set_atomic(IR_Set_Atomic::GPR_TO_FPR, make_reg(instr.get_dst(0).get_reg(), idx), + make_reg(instr.get_src(0).get_reg(), idx)); + op->update_reginfo_regreg(); + return op; } return nullptr; } +/*! + * MFC1 (move from coprocessor 1) move from FPR to GPR. + */ std::shared_ptr try_mfc1(Instruction& instr, int idx) { if (instr.kind == InstructionKind::MFC1) { - return make_set_atomic(IR_Set_Atomic::FPR_TO_GPR64, make_reg(instr.get_dst(0).get_reg(), idx), - make_reg(instr.get_src(0).get_reg(), idx)); + auto op = + make_set_atomic(IR_Set_Atomic::FPR_TO_GPR64, make_reg(instr.get_dst(0).get_reg(), idx), + make_reg(instr.get_src(0).get_reg(), idx)); + op->update_reginfo_regreg(); + return op; } return nullptr; } +/////////////////////////////// +// Loads +/////////////////////////////// + +/*! + * LWC1 : load value into FPR. + * 1. load static float (FP relative) + * 2. load from address + * 3. load at offset from address. + */ std::shared_ptr try_lwc1(Instruction& instr, int idx) { if (instr.kind == InstructionKind::LWC1 && instr.get_dst(0).is_reg() && instr.get_src(0).is_link_or_label() && instr.get_src(1).is_reg(make_gpr(Reg::FP))) { - return make_set_atomic( - IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), + // fp relative, use an IR_StaticAddress. + auto dst = instr.get_dst(0).get_reg(); + auto op = make_set_atomic( + IR_Set_Atomic::LOAD, make_reg(dst, idx), std::make_shared( IR_Load::FLOAT, 4, std::make_shared(instr.get_src(0).get_label()))); + op->write_regs.push_back(dst); + op->reg_info_set = true; + return op; } else if (instr.kind == InstructionKind::LWC1 && instr.get_dst(0).is_reg() && instr.get_src(0).is_imm() && instr.get_src(0).get_imm() == 0) { - return make_set_atomic( - IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared(IR_Load::FLOAT, 4, make_reg(instr.get_src(1).get_reg(), idx))); + // offset is zero, so eliminate it. + auto dst = instr.get_dst(0).get_reg(); + auto src = instr.get_src(1).get_reg(); + auto op = make_set_atomic(IR_Set_Atomic::LOAD, make_reg(dst, idx), + std::make_shared(IR_Load::FLOAT, 4, make_reg(src, idx))); + op->write_regs.push_back(dst); + op->read_regs.push_back(src); + op->reg_info_set = true; + return op; } else if (instr.kind == InstructionKind::LWC1 && instr.get_dst(0).is_reg() && instr.get_src(0).is_imm()) { - return make_set_atomic( - IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared( - IR_Load::FLOAT, 4, - std::make_shared( - IR_IntMath2::ADD, make_reg(instr.get_src(1).get_reg(), idx), - std::make_shared(instr.get_src(0).get_imm())))); + // nonzero offset, create compound expression to add the offset. + auto dst = instr.get_dst(0).get_reg(); + auto src = instr.get_src(1).get_reg(); + auto op = + make_set_atomic(IR_Set_Atomic::LOAD, make_reg(dst, idx), + std::make_shared( + IR_Load::FLOAT, 4, + std::make_shared( + IR_IntMath2::ADD, make_reg(src, idx), + std::make_shared(instr.get_src(0).get_imm())))); + op->write_regs.push_back(dst); + op->read_regs.push_back(src); + op->reg_info_set = true; + return op; } return nullptr; } @@ -222,24 +333,34 @@ std::shared_ptr try_lwc1(Instruction& instr, int idx) { std::shared_ptr try_lhu(Instruction& instr, int idx) { if (instr.kind == InstructionKind::LHU && instr.get_dst(0).is_reg() && instr.get_src(0).is_link_or_label() && instr.get_src(1).is_reg(make_gpr(Reg::FP))) { - return make_set_atomic(IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared( - IR_Load::UNSIGNED, 2, - std::make_shared(instr.get_src(0).get_label()))); + // static load + auto op = + make_set_atomic(IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared( + IR_Load::UNSIGNED, 2, + std::make_shared(instr.get_src(0).get_label()))); + op->update_reginfo_self(1, 0, 0); + return op; } else if (instr.kind == InstructionKind::LHU && instr.get_dst(0).is_reg() && instr.get_src(0).is_imm() && instr.get_src(0).get_imm() == 0) { - return make_set_atomic( + // no offset load + auto op = make_set_atomic( IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), std::make_shared(IR_Load::UNSIGNED, 2, make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 1, 0); + return op; } else if (instr.kind == InstructionKind::LHU && instr.get_dst(0).is_reg() && instr.get_src(0).is_imm()) { - return make_set_atomic( - IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared( - IR_Load::UNSIGNED, 2, - std::make_shared( - IR_IntMath2::ADD, make_reg(instr.get_src(1).get_reg(), idx), - std::make_shared(instr.get_src(0).get_imm())))); + // load with offset + auto op = + make_set_atomic(IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared( + IR_Load::UNSIGNED, 2, + std::make_shared( + IR_IntMath2::ADD, make_reg(instr.get_src(1).get_reg(), idx), + std::make_shared(instr.get_src(0).get_imm())))); + op->update_reginfo_self(1, 1, 0); + return op; } return nullptr; } @@ -247,24 +368,33 @@ std::shared_ptr try_lhu(Instruction& instr, int idx) { std::shared_ptr try_lh(Instruction& instr, int idx) { if (instr.kind == InstructionKind::LH && instr.get_dst(0).is_reg() && instr.get_src(0).is_link_or_label() && instr.get_src(1).is_reg(make_gpr(Reg::FP))) { - return make_set_atomic( + // static load + auto op = make_set_atomic( IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), std::make_shared( IR_Load::SIGNED, 2, std::make_shared(instr.get_src(0).get_label()))); + op->update_reginfo_self(1, 0, 0); + return op; } else if (instr.kind == InstructionKind::LH && instr.get_dst(0).is_reg() && instr.get_src(0).is_imm() && instr.get_src(0).get_imm() == 0) { - return make_set_atomic( + // no offset load + auto op = make_set_atomic( IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), std::make_shared(IR_Load::SIGNED, 2, make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 1, 0); + return op; } else if (instr.kind == InstructionKind::LH && instr.get_dst(0).is_reg() && instr.get_src(0).is_imm()) { - return make_set_atomic( - IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared( - IR_Load::SIGNED, 2, - std::make_shared( - IR_IntMath2::ADD, make_reg(instr.get_src(1).get_reg(), idx), - std::make_shared(instr.get_src(0).get_imm())))); + // offset load + auto op = + make_set_atomic(IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared( + IR_Load::SIGNED, 2, + std::make_shared( + IR_IntMath2::ADD, make_reg(instr.get_src(1).get_reg(), idx), + std::make_shared(instr.get_src(0).get_imm())))); + op->update_reginfo_self(1, 1, 0); + return op; } return nullptr; } @@ -272,24 +402,33 @@ std::shared_ptr try_lh(Instruction& instr, int idx) { std::shared_ptr try_lb(Instruction& instr, int idx) { if (instr.kind == InstructionKind::LB && instr.get_dst(0).is_reg() && instr.get_src(0).is_link_or_label() && instr.get_src(1).is_reg(make_gpr(Reg::FP))) { - return make_set_atomic( + // static load + auto op = make_set_atomic( IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), std::make_shared( IR_Load::SIGNED, 1, std::make_shared(instr.get_src(0).get_label()))); + op->update_reginfo_self(1, 0, 0); + return op; } else if (instr.kind == InstructionKind::LB && instr.get_dst(0).is_reg() && instr.get_src(0).is_imm() && instr.get_src(0).get_imm() == 0) { - return make_set_atomic( + // no offset load + auto op = make_set_atomic( IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), std::make_shared(IR_Load::SIGNED, 1, make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 1, 0); + return op; } else if (instr.kind == InstructionKind::LB && instr.get_dst(0).is_reg() && instr.get_src(0).is_imm()) { - return make_set_atomic( - IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared( - IR_Load::SIGNED, 1, - std::make_shared( - IR_IntMath2::ADD, make_reg(instr.get_src(1).get_reg(), idx), - std::make_shared(instr.get_src(0).get_imm())))); + // offset load + auto op = + make_set_atomic(IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared( + IR_Load::SIGNED, 1, + std::make_shared( + IR_IntMath2::ADD, make_reg(instr.get_src(1).get_reg(), idx), + std::make_shared(instr.get_src(0).get_imm())))); + op->update_reginfo_self(1, 1, 0); + return op; } return nullptr; } @@ -297,49 +436,34 @@ std::shared_ptr try_lb(Instruction& instr, int idx) { std::shared_ptr try_lbu(Instruction& instr, int idx) { if (instr.kind == InstructionKind::LBU && instr.get_dst(0).is_reg() && instr.get_src(0).is_link_or_label() && instr.get_src(1).is_reg(make_gpr(Reg::FP))) { - return make_set_atomic(IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared( - IR_Load::UNSIGNED, 1, - std::make_shared(instr.get_src(0).get_label()))); + // static load + auto op = + make_set_atomic(IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared( + IR_Load::UNSIGNED, 1, + std::make_shared(instr.get_src(0).get_label()))); + op->update_reginfo_self(1, 0, 0); + return op; } else if (instr.kind == InstructionKind::LBU && instr.get_dst(0).is_reg() && instr.get_src(0).is_imm() && instr.get_src(0).get_imm() == 0) { - return make_set_atomic( + // no offset load + auto op = make_set_atomic( IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), std::make_shared(IR_Load::UNSIGNED, 1, make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 1, 0); + return op; } else if (instr.kind == InstructionKind::LBU && instr.get_dst(0).is_reg() && instr.get_src(0).is_imm()) { - return make_set_atomic( - IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared( - IR_Load::UNSIGNED, 1, - std::make_shared( - IR_IntMath2::ADD, make_reg(instr.get_src(1).get_reg(), idx), - std::make_shared(instr.get_src(0).get_imm())))); - } - return nullptr; -} - -std::shared_ptr try_lwu(Instruction& instr, int idx) { - if (instr.kind == InstructionKind::LWU && instr.get_dst(0).is_reg() && - instr.get_src(0).is_link_or_label() && instr.get_src(1).is_reg(make_gpr(Reg::FP))) { - return make_set_atomic(IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared( - IR_Load::UNSIGNED, 4, - std::make_shared(instr.get_src(0).get_label()))); - } else if (instr.kind == InstructionKind::LWU && instr.get_dst(0).is_reg() && - instr.get_src(0).is_imm() && instr.get_src(0).get_imm() == 0) { - return make_set_atomic( - IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared(IR_Load::UNSIGNED, 4, make_reg(instr.get_src(1).get_reg(), idx))); - } else if (instr.kind == InstructionKind::LWU && instr.get_dst(0).is_reg() && - instr.get_src(0).is_imm()) { - return make_set_atomic( - IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared( - IR_Load::UNSIGNED, 4, - std::make_shared( - IR_IntMath2::ADD, make_reg(instr.get_src(1).get_reg(), idx), - std::make_shared(instr.get_src(0).get_imm())))); + // offset load + auto op = + make_set_atomic(IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared( + IR_Load::UNSIGNED, 1, + std::make_shared( + IR_IntMath2::ADD, make_reg(instr.get_src(1).get_reg(), idx), + std::make_shared(instr.get_src(0).get_imm())))); + op->update_reginfo_self(1, 1, 0); + return op; } return nullptr; } @@ -347,146 +471,113 @@ std::shared_ptr try_lwu(Instruction& instr, int idx) { std::shared_ptr try_ld(Instruction& instr, int idx) { if (instr.kind == InstructionKind::LD && instr.get_dst(0).is_reg() && instr.get_src(0).is_link_or_label() && instr.get_src(1).is_reg(make_gpr(Reg::FP))) { - return make_set_atomic(IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared( - IR_Load::UNSIGNED, 8, - std::make_shared(instr.get_src(0).get_label()))); + // static load + auto op = + make_set_atomic(IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared( + IR_Load::UNSIGNED, 8, + std::make_shared(instr.get_src(0).get_label()))); + op->update_reginfo_self(1, 0, 0); + return op; } else if (instr.kind == InstructionKind::LD && instr.get_dst(0).is_reg() && instr.get_src(0).is_imm() && instr.get_src(0).get_imm() == 0) { - return make_set_atomic( + // no offset load + auto op = make_set_atomic( IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), std::make_shared(IR_Load::UNSIGNED, 8, make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 1, 0); + return op; } else if (instr.kind == InstructionKind::LD && instr.get_dst(0).is_reg() && instr.get_src(0).is_imm()) { - return make_set_atomic( - IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared( - IR_Load::UNSIGNED, 8, - std::make_shared( - IR_IntMath2::ADD, make_reg(instr.get_src(1).get_reg(), idx), - std::make_shared(instr.get_src(0).get_imm())))); - } - return nullptr; -} - -std::shared_ptr try_dsll(Instruction& instr, int idx) { - if (is_gpr_2_imm_int(instr, InstructionKind::DSLL, {}, {}, {})) { - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared(IR_IntMath2::LEFT_SHIFT, - make_reg(instr.get_src(0).get_reg(), idx), - make_int(instr.get_src(1).get_imm()))); - } - return nullptr; -} - -std::shared_ptr try_dsll32(Instruction& instr, int idx) { - if (is_gpr_2_imm_int(instr, InstructionKind::DSLL32, {}, {}, {})) { - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared( - IR_IntMath2::LEFT_SHIFT, make_reg(instr.get_src(0).get_reg(), idx), - make_int(32 + instr.get_src(1).get_imm()))); - } - return nullptr; -} - -std::shared_ptr try_dsra(Instruction& instr, int idx) { - if (is_gpr_2_imm_int(instr, InstructionKind::DSRA, {}, {}, {})) { - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared(IR_IntMath2::RIGHT_SHIFT_ARITH, - make_reg(instr.get_src(0).get_reg(), idx), - make_int(instr.get_src(1).get_imm()))); - } - return nullptr; -} - -std::shared_ptr try_dsra32(Instruction& instr, int idx) { - if (is_gpr_2_imm_int(instr, InstructionKind::DSRA32, {}, {}, {})) { - return make_set_atomic( - IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared(IR_IntMath2::RIGHT_SHIFT_ARITH, - make_reg(instr.get_src(0).get_reg(), idx), - make_int(32 + instr.get_src(1).get_imm()))); - } - return nullptr; -} - -std::shared_ptr try_dsrl(Instruction& instr, int idx) { - if (is_gpr_2_imm_int(instr, InstructionKind::DSRL, {}, {}, {})) { - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared(IR_IntMath2::RIGHT_SHIFT_LOGIC, - make_reg(instr.get_src(0).get_reg(), idx), - make_int(instr.get_src(1).get_imm()))); - } - return nullptr; -} - -std::shared_ptr try_dsrl32(Instruction& instr, int idx) { - if (is_gpr_2_imm_int(instr, InstructionKind::DSRL32, {}, {}, {})) { - return make_set_atomic( - IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared(IR_IntMath2::RIGHT_SHIFT_LOGIC, - make_reg(instr.get_src(0).get_reg(), idx), - make_int(32 + instr.get_src(1).get_imm()))); - } - return nullptr; -} - -std::shared_ptr try_float_math_2(Instruction& instr, - int idx, - InstructionKind instr_kind, - IR_FloatMath2::Kind ir_kind) { - if (is_gpr_3(instr, instr_kind, {}, {}, {})) { - return make_set_atomic( - IR_Set_Atomic::REG_FLT, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared(ir_kind, make_reg(instr.get_src(0).get_reg(), idx), - make_reg(instr.get_src(1).get_reg(), idx))); - } - return nullptr; -} - -std::shared_ptr try_daddiu(Instruction& instr, int idx) { - if (instr.kind == InstructionKind::DADDIU && instr.get_src(0).is_reg(make_gpr(Reg::S7)) && - instr.get_src(1).kind == InstructionAtom::IMM_SYM) { - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - make_sym(instr.get_src(1).get_sym())); - } else if (instr.kind == InstructionKind::DADDIU && instr.get_src(0).is_reg(make_gpr(Reg::FP)) && - instr.get_src(1).kind == InstructionAtom::LABEL) { - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared(instr.get_src(1).get_label())); - } else if (instr.kind == InstructionKind::DADDIU) { - return make_set_atomic( - IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared(IR_IntMath2::ADD, make_reg(instr.get_src(0).get_reg(), idx), - make_int(instr.get_src(1).get_imm()))); + // offset load + auto op = + make_set_atomic(IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared( + IR_Load::UNSIGNED, 8, + std::make_shared( + IR_IntMath2::ADD, make_reg(instr.get_src(1).get_reg(), idx), + std::make_shared(instr.get_src(0).get_imm())))); + op->update_reginfo_self(1, 1, 0); + return op; } return nullptr; } +// TODO SPECIAL std::shared_ptr try_lw(Instruction& instr, int idx) { if (instr.kind == InstructionKind::LW && instr.get_src(1).is_reg(make_gpr(Reg::S7)) && instr.get_src(0).kind == InstructionAtom::IMM_SYM) { - return make_set_atomic(IR_Set_Atomic::SYM_LOAD, make_reg(instr.get_dst(0).get_reg(), idx), - make_sym_value(instr.get_src(0).get_sym())); + // symbol load + auto dst = instr.get_dst(0).get_reg(); + auto op = make_set_atomic(IR_Set_Atomic::SYM_LOAD, make_reg(dst, idx), + make_sym_value(instr.get_src(0).get_sym())); + op->write_regs.push_back(dst); + op->reg_info_set = true; + return op; } else if (instr.kind == InstructionKind::LW && instr.get_dst(0).is_reg() && instr.get_src(0).is_link_or_label() && instr.get_src(1).is_reg(make_gpr(Reg::FP))) { - return make_set_atomic( + // static load + auto op = make_set_atomic( IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), std::make_shared( IR_Load::SIGNED, 4, std::make_shared(instr.get_src(0).get_label()))); + op->update_reginfo_self(1, 0, 0); + return op; } else if (instr.kind == InstructionKind::LW && instr.get_dst(0).is_reg() && instr.get_src(0).is_imm() && instr.get_src(0).get_imm() == 0) { - return make_set_atomic( + // no offset load + auto op = make_set_atomic( IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), std::make_shared(IR_Load::SIGNED, 4, make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 1, 0); + return op; } else if (instr.kind == InstructionKind::LW && instr.get_dst(0).is_reg() && instr.get_src(0).is_imm()) { - return make_set_atomic( + // offset load + auto op = + make_set_atomic(IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared( + IR_Load::SIGNED, 4, + std::make_shared( + IR_IntMath2::ADD, make_reg(instr.get_src(1).get_reg(), idx), + std::make_shared(instr.get_src(0).get_imm())))); + op->update_reginfo_self(1, 1, 0); + return op; + } + return nullptr; +} + +std::shared_ptr try_lwu(Instruction& instr, int idx) { + if (instr.kind == InstructionKind::LWU && instr.get_dst(0).is_reg() && + instr.get_src(0).is_link_or_label() && instr.get_src(1).is_reg(make_gpr(Reg::FP))) { + // static load + auto op = + make_set_atomic(IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared( + IR_Load::UNSIGNED, 4, + std::make_shared(instr.get_src(0).get_label()))); + op->update_reginfo_self(1, 0, 0); + return op; + } else if (instr.kind == InstructionKind::LWU && instr.get_dst(0).is_reg() && + instr.get_src(0).is_imm() && instr.get_src(0).get_imm() == 0) { + // no offset load + auto op = make_set_atomic( IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared( - IR_Load::SIGNED, 4, - std::make_shared( - IR_IntMath2::ADD, make_reg(instr.get_src(1).get_reg(), idx), - std::make_shared(instr.get_src(0).get_imm())))); + std::make_shared(IR_Load::UNSIGNED, 4, make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 1, 0); + return op; + } else if (instr.kind == InstructionKind::LWU && instr.get_dst(0).is_reg() && + instr.get_src(0).is_imm()) { + // offset load + auto op = + make_set_atomic(IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared( + IR_Load::UNSIGNED, 4, + std::make_shared( + IR_IntMath2::ADD, make_reg(instr.get_src(1).get_reg(), idx), + std::make_shared(instr.get_src(0).get_imm())))); + op->update_reginfo_self(1, 1, 0); + return op; } return nullptr; } @@ -497,24 +588,158 @@ std::shared_ptr try_lq(Instruction& instr, int idx) { assert(false); } else if (instr.kind == InstructionKind::LQ && instr.get_dst(0).is_reg() && instr.get_src(0).is_link_or_label() && instr.get_src(1).is_reg(make_gpr(Reg::FP))) { - return make_set_atomic(IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared( - IR_Load::UNSIGNED, 16, - std::make_shared(instr.get_src(0).get_label()))); + // static + auto op = + make_set_atomic(IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared( + IR_Load::UNSIGNED, 16, + std::make_shared(instr.get_src(0).get_label()))); + op->update_reginfo_self(1, 0, 0); + return op; } else if (instr.kind == InstructionKind::LQ && instr.get_dst(0).is_reg() && instr.get_src(0).is_imm() && instr.get_src(0).get_imm() == 0) { - return make_set_atomic(IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared(IR_Load::UNSIGNED, 16, - make_reg(instr.get_src(1).get_reg(), idx))); + // no offset + auto op = make_set_atomic(IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared(IR_Load::UNSIGNED, 16, + make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 1, 0); + return op; } else if (instr.kind == InstructionKind::LQ && instr.get_dst(0).is_reg() && instr.get_src(0).is_imm()) { - return make_set_atomic( - IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared( - IR_Load::UNSIGNED, 16, - std::make_shared( - IR_IntMath2::ADD, make_reg(instr.get_src(1).get_reg(), idx), - std::make_shared(instr.get_src(0).get_imm())))); + // offset + auto op = + make_set_atomic(IR_Set_Atomic::LOAD, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared( + IR_Load::UNSIGNED, 16, + std::make_shared( + IR_IntMath2::ADD, make_reg(instr.get_src(1).get_reg(), idx), + std::make_shared(instr.get_src(0).get_imm())))); + op->update_reginfo_self(1, 1, 0); + return op; + } + return nullptr; +} + +std::shared_ptr try_dsll(Instruction& instr, int idx) { + if (is_gpr_2_imm_int(instr, InstructionKind::DSLL, {}, {}, {})) { + auto op = + make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared(IR_IntMath2::LEFT_SHIFT, + make_reg(instr.get_src(0).get_reg(), idx), + make_int(instr.get_src(1).get_imm()))); + op->update_reginfo_self(1, 1, 0); + return op; + } + return nullptr; +} + +std::shared_ptr try_dsll32(Instruction& instr, int idx) { + if (is_gpr_2_imm_int(instr, InstructionKind::DSLL32, {}, {}, {})) { + auto op = + make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared(IR_IntMath2::LEFT_SHIFT, + make_reg(instr.get_src(0).get_reg(), idx), + make_int(32 + instr.get_src(1).get_imm()))); + op->update_reginfo_self(1, 1, 0); + return op; + } + return nullptr; +} + +std::shared_ptr try_dsra(Instruction& instr, int idx) { + if (is_gpr_2_imm_int(instr, InstructionKind::DSRA, {}, {}, {})) { + auto op = + make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared(IR_IntMath2::RIGHT_SHIFT_ARITH, + make_reg(instr.get_src(0).get_reg(), idx), + make_int(instr.get_src(1).get_imm()))); + op->update_reginfo_self(1, 1, 0); + return op; + } + return nullptr; +} + +std::shared_ptr try_dsra32(Instruction& instr, int idx) { + if (is_gpr_2_imm_int(instr, InstructionKind::DSRA32, {}, {}, {})) { + auto op = + make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared(IR_IntMath2::RIGHT_SHIFT_ARITH, + make_reg(instr.get_src(0).get_reg(), idx), + make_int(32 + instr.get_src(1).get_imm()))); + op->update_reginfo_self(1, 1, 0); + return op; + } + return nullptr; +} + +std::shared_ptr try_dsrl(Instruction& instr, int idx) { + if (is_gpr_2_imm_int(instr, InstructionKind::DSRL, {}, {}, {})) { + auto op = + make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared(IR_IntMath2::RIGHT_SHIFT_LOGIC, + make_reg(instr.get_src(0).get_reg(), idx), + make_int(instr.get_src(1).get_imm()))); + op->update_reginfo_self(1, 1, 0); + return op; + } + return nullptr; +} + +std::shared_ptr try_dsrl32(Instruction& instr, int idx) { + if (is_gpr_2_imm_int(instr, InstructionKind::DSRL32, {}, {}, {})) { + auto op = + make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared(IR_IntMath2::RIGHT_SHIFT_LOGIC, + make_reg(instr.get_src(0).get_reg(), idx), + make_int(32 + instr.get_src(1).get_imm()))); + op->update_reginfo_self(1, 1, 0); + return op; + } + return nullptr; +} + +std::shared_ptr try_float_math_2(Instruction& instr, + int idx, + InstructionKind instr_kind, + IR_FloatMath2::Kind ir_kind) { + if (is_gpr_3(instr, instr_kind, {}, {}, {})) { + auto dst = instr.get_dst(0).get_reg(); + auto src0 = instr.get_src(0).get_reg(); + auto src1 = instr.get_src(1).get_reg(); + auto op = make_set_atomic( + IR_Set_Atomic::REG_FLT, make_reg(dst, idx), + std::make_shared(ir_kind, make_reg(src0, idx), make_reg(src1, idx))); + op->write_regs.push_back(dst); + op->read_regs.push_back(src0); + op->read_regs.push_back(src1); + op->reg_info_set = true; + return op; + } + return nullptr; +} + +std::shared_ptr try_daddiu(Instruction& instr, int idx) { + if (instr.kind == InstructionKind::DADDIU && instr.get_src(0).is_reg(make_gpr(Reg::S7)) && + instr.get_src(1).kind == InstructionAtom::IMM_SYM) { + auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), + make_sym(instr.get_src(1).get_sym())); + op->write_regs.push_back(instr.get_dst(0).get_reg()); + op->reg_info_set = true; + return op; + } else if (instr.kind == InstructionKind::DADDIU && instr.get_src(0).is_reg(make_gpr(Reg::FP)) && + instr.get_src(1).kind == InstructionAtom::LABEL) { + auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared(instr.get_src(1).get_label())); + op->write_regs.push_back(instr.get_dst(0).get_reg()); + op->reg_info_set = true; + return op; + } else if (instr.kind == InstructionKind::DADDIU) { + auto op = make_set_atomic( + IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared(IR_IntMath2::ADD, make_reg(instr.get_src(0).get_reg(), idx), + make_int(instr.get_src(1).get_imm()))); + op->update_reginfo_self(1, 1, 0); + return op; } return nullptr; } @@ -522,10 +747,12 @@ std::shared_ptr try_lq(Instruction& instr, int idx) { std::shared_ptr try_daddu(Instruction& instr, int idx) { if (is_gpr_3(instr, InstructionKind::DADDU, {}, {}, {}) && !instr.get_src(0).is_reg(make_gpr(Reg::S7)) && !instr.get_src(1).is_reg(make_gpr(Reg::S7))) { - return make_set_atomic( + auto op = make_set_atomic( IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), std::make_shared(IR_IntMath2::ADD, make_reg(instr.get_src(0).get_reg(), idx), make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 2, 0); + return op; } return to_asm_reg_reg_reg("daddu", instr, idx); } @@ -533,16 +760,20 @@ std::shared_ptr try_daddu(Instruction& instr, int idx) { std::shared_ptr try_dsubu(Instruction& instr, int idx) { if (is_gpr_3(instr, InstructionKind::DSUBU, {}, make_gpr(Reg::R0), {}) && !instr.get_src(0).is_reg(make_gpr(Reg::S7)) && !instr.get_src(1).is_reg(make_gpr(Reg::S7))) { - return make_set_atomic( + auto op = make_set_atomic( IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), std::make_shared(IR_IntMath1::NEG, make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 1, 0); + return op; } else if (is_gpr_3(instr, InstructionKind::DSUBU, {}, {}, {}) && !instr.get_src(0).is_reg(make_gpr(Reg::S7)) && !instr.get_src(1).is_reg(make_gpr(Reg::S7))) { - return make_set_atomic( + auto op = make_set_atomic( IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), std::make_shared(IR_IntMath2::SUB, make_reg(instr.get_src(0).get_reg(), idx), make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 2, 0); + return op; } return nullptr; } @@ -550,10 +781,13 @@ std::shared_ptr try_dsubu(Instruction& instr, int idx) { std::shared_ptr try_mult3(Instruction& instr, int idx) { if (is_gpr_3(instr, InstructionKind::MULT3, {}, {}, {}) && !instr.get_src(0).is_reg(make_gpr(Reg::S7)) && !instr.get_src(1).is_reg(make_gpr(Reg::S7))) { - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared( - IR_IntMath2::MUL_SIGNED, make_reg(instr.get_src(0).get_reg(), idx), - make_reg(instr.get_src(1).get_reg(), idx))); + auto op = + make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared(IR_IntMath2::MUL_SIGNED, + make_reg(instr.get_src(0).get_reg(), idx), + make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 2, 0); + return op; } return nullptr; } @@ -561,10 +795,13 @@ std::shared_ptr try_mult3(Instruction& instr, int idx) { std::shared_ptr try_multu3(Instruction& instr, int idx) { if (is_gpr_3(instr, InstructionKind::MULTU3, {}, {}, {}) && !instr.get_src(0).is_reg(make_gpr(Reg::S7)) && !instr.get_src(1).is_reg(make_gpr(Reg::S7))) { - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared( - IR_IntMath2::MUL_UNSIGNED, make_reg(instr.get_src(0).get_reg(), idx), - make_reg(instr.get_src(1).get_reg(), idx))); + auto op = + make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared(IR_IntMath2::MUL_UNSIGNED, + make_reg(instr.get_src(0).get_reg(), idx), + make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 2, 0); + return op; } return nullptr; } @@ -572,30 +809,36 @@ std::shared_ptr try_multu3(Instruction& instr, int idx) { std::shared_ptr try_and(Instruction& instr, int idx) { if (is_gpr_3(instr, InstructionKind::AND, {}, {}, {}) && !instr.get_src(0).is_reg(make_gpr(Reg::S7)) && !instr.get_src(1).is_reg(make_gpr(Reg::S7))) { - return make_set_atomic( + auto op = make_set_atomic( IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), std::make_shared(IR_IntMath2::AND, make_reg(instr.get_src(0).get_reg(), idx), make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 2, 0); + return op; } return nullptr; } std::shared_ptr try_andi(Instruction& instr, int idx) { if (instr.kind == InstructionKind::ANDI) { - return make_set_atomic( + auto op = make_set_atomic( IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), std::make_shared(IR_IntMath2::AND, make_reg(instr.get_src(0).get_reg(), idx), make_int(instr.get_src(1).get_imm()))); + op->update_reginfo_self(1, 1, 0); + return op; } return nullptr; } std::shared_ptr try_xori(Instruction& instr, int idx) { if (instr.kind == InstructionKind::XORI) { - return make_set_atomic( + auto op = make_set_atomic( IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), std::make_shared(IR_IntMath2::XOR, make_reg(instr.get_src(0).get_reg(), idx), make_int(instr.get_src(1).get_imm()))); + op->update_reginfo_self(1, 1, 0); + return op; } return nullptr; } @@ -603,16 +846,20 @@ std::shared_ptr try_xori(Instruction& instr, int idx) { std::shared_ptr try_nor(Instruction& instr, int idx) { if (is_gpr_3(instr, InstructionKind::NOR, {}, {}, {}) && !instr.get_src(0).is_reg(make_gpr(Reg::S7)) && instr.get_src(1).is_reg(make_gpr(Reg::R0))) { - return make_set_atomic( + auto op = make_set_atomic( IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), std::make_shared(IR_IntMath1::NOT, make_reg(instr.get_src(0).get_reg(), idx))); + op->update_reginfo_self(1, 1, 0); + return op; } else if (is_gpr_3(instr, InstructionKind::NOR, {}, {}, {}) && !instr.get_src(0).is_reg(make_gpr(Reg::S7)) && !instr.get_src(1).is_reg(make_gpr(Reg::S7))) { - return make_set_atomic( + auto op = make_set_atomic( IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), std::make_shared(IR_IntMath2::NOR, make_reg(instr.get_src(0).get_reg(), idx), make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 2, 0); + return op; } return nullptr; } @@ -620,26 +867,36 @@ std::shared_ptr try_nor(Instruction& instr, int idx) { std::shared_ptr try_xor(Instruction& instr, int idx) { if (is_gpr_3(instr, InstructionKind::XOR, {}, {}, {}) && !instr.get_src(0).is_reg(make_gpr(Reg::S7)) && !instr.get_src(1).is_reg(make_gpr(Reg::S7))) { - return make_set_atomic( + auto op = make_set_atomic( IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), std::make_shared(IR_IntMath2::XOR, make_reg(instr.get_src(0).get_reg(), idx), make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 2, 0); + return op; } return nullptr; } std::shared_ptr try_addiu(Instruction& instr, int idx) { if (instr.kind == InstructionKind::ADDIU && instr.get_src(0).is_reg(make_gpr(Reg::R0))) { - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - make_int(instr.get_src(1).get_imm())); + auto dest = instr.get_dst(0).get_reg(); + auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dest, idx), + make_int(instr.get_src(1).get_imm())); + op->write_regs.push_back(dest); + op->reg_info_set = true; + return op; } return nullptr; } std::shared_ptr try_lui(Instruction& instr, int idx) { if (instr.kind == InstructionKind::LUI && instr.get_src(0).is_imm()) { - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - make_int(instr.get_src(0).get_imm() << 16)); + auto dest = instr.get_dst(0).get_reg(); + auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dest, idx), + make_int(instr.get_src(0).get_imm() << 16)); + op->write_regs.push_back(dest); + op->reg_info_set = true; + return op; } return nullptr; } @@ -647,7 +904,9 @@ std::shared_ptr try_lui(Instruction& instr, int idx) { std::shared_ptr try_sll(Instruction& instr, int idx) { (void)idx; if (is_nop(instr)) { - return std::make_shared(); + auto op = std::make_shared(); + op->reg_info_set = true; + return op; } return nullptr; } @@ -655,11 +914,13 @@ std::shared_ptr try_sll(Instruction& instr, int idx) { std::shared_ptr try_dsrav(Instruction& instr, int idx) { if (is_gpr_3(instr, InstructionKind::DSRAV, {}, {}, {}) && !instr.get_src(0).is_reg(make_gpr(Reg::S7)) && !instr.get_src(1).is_reg(make_gpr(Reg::S7))) { - return make_set_atomic( - IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared(IR_IntMath2::RIGHT_SHIFT_ARITH, - make_reg(instr.get_src(0).get_reg(), idx), - make_reg(instr.get_src(1).get_reg(), idx))); + auto op = + make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared(IR_IntMath2::RIGHT_SHIFT_ARITH, + make_reg(instr.get_src(0).get_reg(), idx), + make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 2, 0); + return op; } return nullptr; } @@ -667,11 +928,13 @@ std::shared_ptr try_dsrav(Instruction& instr, int idx) { std::shared_ptr try_dsrlv(Instruction& instr, int idx) { if (is_gpr_3(instr, InstructionKind::DSRLV, {}, {}, {}) && !instr.get_src(0).is_reg(make_gpr(Reg::S7)) && !instr.get_src(1).is_reg(make_gpr(Reg::S7))) { - return make_set_atomic( - IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared(IR_IntMath2::RIGHT_SHIFT_LOGIC, - make_reg(instr.get_src(0).get_reg(), idx), - make_reg(instr.get_src(1).get_reg(), idx))); + auto op = + make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared(IR_IntMath2::RIGHT_SHIFT_LOGIC, + make_reg(instr.get_src(0).get_reg(), idx), + make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 2, 0); + return op; } return nullptr; } @@ -679,10 +942,13 @@ std::shared_ptr try_dsrlv(Instruction& instr, int idx) { std::shared_ptr try_dsllv(Instruction& instr, int idx) { if (is_gpr_3(instr, InstructionKind::DSLLV, {}, {}, {}) && !instr.get_src(0).is_reg(make_gpr(Reg::S7)) && !instr.get_src(1).is_reg(make_gpr(Reg::S7))) { - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared( - IR_IntMath2::LEFT_SHIFT, make_reg(instr.get_src(0).get_reg(), idx), - make_reg(instr.get_src(1).get_reg(), idx))); + auto op = + make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), + std::make_shared(IR_IntMath2::LEFT_SHIFT, + make_reg(instr.get_src(0).get_reg(), idx), + make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 2, 0); + return op; } return nullptr; } @@ -690,96 +956,129 @@ std::shared_ptr try_dsllv(Instruction& instr, int idx) { std::shared_ptr try_sw(Instruction& instr, int idx) { if (instr.kind == InstructionKind::SW && instr.get_src(1).is_sym() && instr.get_src(2).is_reg(make_gpr(Reg::S7))) { - return std::make_shared(IR_Set_Atomic::SYM_STORE, - make_sym_value(instr.get_src(1).get_sym()), - make_reg(instr.get_src(0).get_reg(), idx)); + auto src = instr.get_src(0).get_reg(); + auto op = std::make_shared( + IR_Set_Atomic::SYM_STORE, make_sym_value(instr.get_src(1).get_sym()), make_reg(src, idx)); + op->read_regs.push_back(src); + op->reg_info_set = true; + return op; } else if (instr.kind == InstructionKind::SW && instr.get_src(1).is_imm()) { - return std::make_shared( - IR_Store_Atomic::INTEGER, - std::make_shared( - IR_IntMath2::ADD, make_reg(instr.get_src(2).get_reg(), idx), - std::make_shared(instr.get_src(1).get_imm())), - make_reg(instr.get_src(0).get_reg(), idx), 4); + if (instr.get_src(1).get_imm() == 0) { + auto op = std::make_shared(IR_Store_Atomic::INTEGER, + make_reg(instr.get_src(2).get_reg(), idx), + make_reg(instr.get_src(0).get_reg(), idx), 4); + op->update_reginfo_self(0, 2, 0); + return op; + } else { + auto op = std::make_shared( + IR_Store_Atomic::INTEGER, + std::make_shared( + IR_IntMath2::ADD, make_reg(instr.get_src(2).get_reg(), idx), + std::make_shared(instr.get_src(1).get_imm())), + make_reg(instr.get_src(0).get_reg(), idx), 4); + op->update_reginfo_self(0, 2, 0); + return op; + } } return nullptr; } std::shared_ptr try_sb(Instruction& instr, int idx) { if (instr.kind == InstructionKind::SB && instr.get_src(1).is_imm()) { - return std::make_shared( + auto op = std::make_shared( IR_Store_Atomic::INTEGER, std::make_shared( IR_IntMath2::ADD, make_reg(instr.get_src(2).get_reg(), idx), std::make_shared(instr.get_src(1).get_imm())), make_reg(instr.get_src(0).get_reg(), idx), 1); + op->update_reginfo_self(0, 2, 0); + return op; } return nullptr; } std::shared_ptr try_sh(Instruction& instr, int idx) { if (instr.kind == InstructionKind::SH && instr.get_src(1).is_imm()) { - return std::make_shared( + auto op = std::make_shared( IR_Store_Atomic::INTEGER, std::make_shared( IR_IntMath2::ADD, make_reg(instr.get_src(2).get_reg(), idx), std::make_shared(instr.get_src(1).get_imm())), make_reg(instr.get_src(0).get_reg(), idx), 2); + op->update_reginfo_self(0, 2, 0); + return op; } return nullptr; } std::shared_ptr try_sd(Instruction& instr, int idx) { if (instr.kind == InstructionKind::SD && instr.get_src(1).is_imm()) { - return std::make_shared( + auto op = std::make_shared( IR_Store_Atomic::INTEGER, std::make_shared( IR_IntMath2::ADD, make_reg(instr.get_src(2).get_reg(), idx), std::make_shared(instr.get_src(1).get_imm())), make_reg(instr.get_src(0).get_reg(), idx), 8); + op->update_reginfo_self(0, 2, 0); + return op; } return nullptr; } std::shared_ptr try_sq(Instruction& instr, int idx) { if (instr.kind == InstructionKind::SQ && instr.get_src(1).is_imm()) { - return std::make_shared( + auto op = std::make_shared( IR_Store_Atomic::INTEGER, std::make_shared( IR_IntMath2::ADD, make_reg(instr.get_src(2).get_reg(), idx), std::make_shared(instr.get_src(1).get_imm())), make_reg(instr.get_src(0).get_reg(), idx), 16); + op->update_reginfo_self(0, 2, 0); + return op; } return nullptr; } std::shared_ptr try_swc1(Instruction& instr, int idx) { if (instr.kind == InstructionKind::SWC1 && instr.get_src(1).is_imm()) { - return std::make_shared( + auto op = std::make_shared( IR_Store_Atomic::FLOAT, std::make_shared( IR_IntMath2::ADD, make_reg(instr.get_src(2).get_reg(), idx), std::make_shared(instr.get_src(1).get_imm())), make_reg(instr.get_src(0).get_reg(), idx), 4); + op->update_reginfo_self(0, 2, 0); + return op; } return nullptr; } std::shared_ptr try_cvtws(Instruction& instr, int idx) { if (instr.kind == InstructionKind::CVTWS) { - return make_set_atomic( - IR_Set_Atomic::REG_FLT, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared(IR_FloatMath1::FLOAT_TO_INT, - make_reg(instr.get_src(0).get_reg(), idx))); + auto dst = instr.get_dst(0).get_reg(); + auto src = instr.get_src(0).get_reg(); + auto op = make_set_atomic( + IR_Set_Atomic::REG_FLT, make_reg(dst, idx), + std::make_shared(IR_FloatMath1::FLOAT_TO_INT, make_reg(src, idx))); + op->write_regs.push_back(dst); + op->read_regs.push_back(src); + op->reg_info_set = true; + return op; } return nullptr; } std::shared_ptr try_cvtsw(Instruction& instr, int idx) { if (instr.kind == InstructionKind::CVTSW) { - return make_set_atomic( - IR_Set_Atomic::REG_FLT, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared(IR_FloatMath1::INT_TO_FLOAT, - make_reg(instr.get_src(0).get_reg(), idx))); + auto dst = instr.get_dst(0).get_reg(); + auto src = instr.get_src(0).get_reg(); + auto op = make_set_atomic( + IR_Set_Atomic::REG_FLT, make_reg(dst, idx), + std::make_shared(IR_FloatMath1::INT_TO_FLOAT, make_reg(src, idx))); + op->write_regs.push_back(dst); + op->read_regs.push_back(src); + op->reg_info_set = true; + return op; } return nullptr; } @@ -789,35 +1088,53 @@ std::shared_ptr try_float_math_1(Instruction& instr, InstructionKind ikind, IR_FloatMath1::Kind irkind) { if (instr.kind == ikind) { - return make_set_atomic( - IR_Set_Atomic::REG_FLT, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared(irkind, make_reg(instr.get_src(0).get_reg(), idx))); + auto dst = instr.get_dst(0).get_reg(); + auto src = instr.get_src(0).get_reg(); + auto op = make_set_atomic(IR_Set_Atomic::REG_FLT, make_reg(dst, idx), + std::make_shared(irkind, make_reg(src, idx))); + op->write_regs.push_back(dst); + op->read_regs.push_back(src); + op->reg_info_set = true; + return op; } return nullptr; } std::shared_ptr try_movs(Instruction& instr, int idx) { if (instr.kind == InstructionKind::MOVS) { - return make_set_atomic(IR_Set_Atomic::REG_FLT, make_reg(instr.get_dst(0).get_reg(), idx), - make_reg(instr.get_src(0).get_reg(), idx)); + auto dst = instr.get_dst(0).get_reg(); + auto src = instr.get_src(0).get_reg(); + auto op = make_set_atomic(IR_Set_Atomic::REG_FLT, make_reg(dst, idx), make_reg(src, idx)); + op->write_regs.push_back(dst); + op->read_regs.push_back(src); + op->reg_info_set = true; + return op; } return nullptr; } std::shared_ptr try_movn(Instruction& instr, int idx) { if (is_gpr_3(instr, InstructionKind::MOVN, {}, make_gpr(Reg::S7), {})) { - return make_set_atomic( - IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared(make_reg(instr.get_src(1).get_reg(), idx), false)); + auto dst = instr.get_dst(0).get_reg(); + auto src = instr.get_src(1).get_reg(); + auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dst, idx), + std::make_shared(make_reg(src, idx), false)); + op->write_regs.push_back(dst); + op->read_regs.push_back(src); + op->reg_info_set = true; } return nullptr; } std::shared_ptr try_movz(Instruction& instr, int idx) { if (is_gpr_3(instr, InstructionKind::MOVZ, {}, make_gpr(Reg::S7), {})) { - return make_set_atomic( - IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared(make_reg(instr.get_src(1).get_reg(), idx), true)); + auto dst = instr.get_dst(0).get_reg(); + auto src = instr.get_src(1).get_reg(); + auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dst, idx), + std::make_shared(make_reg(src, idx), true)); + op->write_regs.push_back(dst); + op->read_regs.push_back(src); + op->reg_info_set = true; } return nullptr; } @@ -827,17 +1144,23 @@ std::shared_ptr try_div(Instruction& instr, Instruction& next_instr, if (instr.kind == InstructionKind::DIV && instr.get_src(0).is_reg() && instr.get_src(1).is_reg() && next_instr.kind == InstructionKind::MFLO && next_instr.get_dst(0).is_reg()) { - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(next_instr.get_dst(0).get_reg(), idx), - std::make_shared( - IR_IntMath2::DIV_SIGNED, make_reg(instr.get_src(0).get_reg(), idx), - make_reg(instr.get_src(1).get_reg(), idx))); + auto op = + make_set_atomic(IR_Set_Atomic::REG_64, make_reg(next_instr.get_dst(0).get_reg(), idx), + std::make_shared(IR_IntMath2::DIV_SIGNED, + make_reg(instr.get_src(0).get_reg(), idx), + make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 2, 0); + return op; } else if (instr.kind == InstructionKind::DIV && instr.get_src(0).is_reg() && instr.get_src(1).is_reg() && next_instr.kind == InstructionKind::MFHI && next_instr.get_dst(0).is_reg()) { - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(next_instr.get_dst(0).get_reg(), idx), - std::make_shared( - IR_IntMath2::MOD_SIGNED, make_reg(instr.get_src(0).get_reg(), idx), - make_reg(instr.get_src(1).get_reg(), idx))); + auto op = + make_set_atomic(IR_Set_Atomic::REG_64, make_reg(next_instr.get_dst(0).get_reg(), idx), + std::make_shared(IR_IntMath2::MOD_SIGNED, + make_reg(instr.get_src(0).get_reg(), idx), + make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 2, 0); + return op; } return nullptr; } @@ -846,17 +1169,23 @@ std::shared_ptr try_divu(Instruction& instr, Instruction& next_instr, if (instr.kind == InstructionKind::DIVU && instr.get_src(0).is_reg() && instr.get_src(1).is_reg() && next_instr.kind == InstructionKind::MFLO && next_instr.get_dst(0).is_reg()) { - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(next_instr.get_dst(0).get_reg(), idx), - std::make_shared( - IR_IntMath2::DIV_UNSIGNED, make_reg(instr.get_src(0).get_reg(), idx), - make_reg(instr.get_src(1).get_reg(), idx))); + auto op = + make_set_atomic(IR_Set_Atomic::REG_64, make_reg(next_instr.get_dst(0).get_reg(), idx), + std::make_shared(IR_IntMath2::DIV_UNSIGNED, + make_reg(instr.get_src(0).get_reg(), idx), + make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 2, 0); + return op; } else if (instr.kind == InstructionKind::DIVU && instr.get_src(0).is_reg() && instr.get_src(1).is_reg() && next_instr.kind == InstructionKind::MFHI && next_instr.get_dst(0).is_reg()) { - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(next_instr.get_dst(0).get_reg(), idx), - std::make_shared( - IR_IntMath2::MOD_UNSIGNED, make_reg(instr.get_src(0).get_reg(), idx), - make_reg(instr.get_src(1).get_reg(), idx))); + auto op = + make_set_atomic(IR_Set_Atomic::REG_64, make_reg(next_instr.get_dst(0).get_reg(), idx), + std::make_shared(IR_IntMath2::MOD_UNSIGNED, + make_reg(instr.get_src(0).get_reg(), idx), + make_reg(instr.get_src(1).get_reg(), idx))); + op->update_reginfo_self(1, 2, 0); + return op; } return nullptr; } @@ -866,49 +1195,89 @@ std::shared_ptr try_jalr(Instruction& instr, Instruction& next_instr, if (instr.kind == InstructionKind::JALR && instr.get_dst(0).is_reg(make_gpr(Reg::RA)) && instr.get_src(0).is_reg(make_gpr(Reg::T9)) && is_gpr_2_imm_int(next_instr, InstructionKind::SLL, make_gpr(Reg::V0), make_gpr(Reg::RA), 0)) { - return std::make_shared(); + auto op = std::make_shared(); + + // for now, we assume no arguments, but a return. + // todo - clobber fprs + auto temps = {Reg::V1, Reg::A0, Reg::A1, Reg::A2, Reg::A3, Reg::T0, Reg::T1, Reg::T2, + Reg::T3, Reg::T4, Reg::T5, Reg::T6, Reg::T7, Reg::T8, Reg::T9}; + for (auto& r : temps) { + op->clobber_regs.emplace_back(Reg::GPR, r); + } + + op->read_regs.emplace_back(Reg::GPR, Reg::T9); + op->write_regs.emplace_back(Reg::GPR, Reg::V0); // may "write" a none. + op->reg_info_set = true; + return op; } return nullptr; } BranchDelay get_branch_delay(Instruction& i, int idx) { if (is_nop(i)) { + // no read, write, clobber return BranchDelay(BranchDelay::NOP); } else if (is_gpr_3(i, InstructionKind::OR, {}, make_gpr(Reg::S7), make_gpr(Reg::R0))) { BranchDelay b(BranchDelay::SET_REG_FALSE); - b.destination = make_reg(i.get_dst(0).get_reg(), idx); + auto dst = i.get_dst(0).get_reg(); + b.destination = make_reg(dst, idx); + b.write_regs.push_back(dst); return b; } else if (is_gpr_3(i, InstructionKind::OR, {}, {}, make_gpr(Reg::R0))) { BranchDelay b(BranchDelay::SET_REG_REG); - b.destination = make_reg(i.get_dst(0).get_reg(), idx); - b.source = make_reg(i.get_src(0).get_reg(), idx); + auto dst = i.get_dst(0).get_reg(); + auto src = i.get_src(0).get_reg(); + b.destination = make_reg(dst, idx); + b.source = make_reg(src, idx); + b.write_regs.push_back(dst); + b.read_regs.push_back(src); return b; } else if (i.kind == InstructionKind::DADDIU && i.get_src(0).is_reg(make_gpr(Reg::S7)) && i.get_src(1).is_imm() && i.get_src(1).get_imm() == 8) { BranchDelay b(BranchDelay::SET_REG_TRUE); - b.destination = make_reg(i.get_dst(0).get_reg(), idx); + auto dst = i.get_dst(0).get_reg(); + b.destination = make_reg(dst, idx); + b.write_regs.push_back(dst); return b; } else if (i.kind == InstructionKind::LW && i.get_src(1).is_reg(make_gpr(Reg::S7)) && i.get_src(0).is_sym()) { if (i.get_src(0).get_sym() == "binteger") { BranchDelay b(BranchDelay::SET_BINTEGER); - b.destination = make_reg(i.get_dst(0).get_reg(), idx); + auto dst = i.get_dst(0).get_reg(); + b.destination = make_reg(dst, idx); + b.write_regs.push_back(dst); return b; } else if (i.get_src(0).get_sym() == "pair") { BranchDelay b(BranchDelay::SET_PAIR); - b.destination = make_reg(i.get_dst(0).get_reg(), idx); + auto dst = i.get_dst(0).get_reg(); + b.destination = make_reg(dst, idx); + b.write_regs.push_back(dst); return b; + } else { + assert(false); } } else if (i.kind == InstructionKind::DSLLV) { + // this is used for ash? BranchDelay b(BranchDelay::DSLLV); - b.destination = make_reg(i.get_dst(0).get_reg(), idx); - b.source = make_reg(i.get_src(0).get_reg(), idx); - b.source2 = make_reg(i.get_src(1).get_reg(), idx); + auto dst = i.get_dst(0).get_reg(); + auto src0 = i.get_src(0).get_reg(); + auto src2 = i.get_src(1).get_reg(); + b.destination = make_reg(dst, idx); + b.source = make_reg(src0, idx); + b.source2 = make_reg(src2, idx); + b.write_regs.push_back(dst); + b.read_regs.push_back(src0); + b.read_regs.push_back(src2); return b; } else if (is_gpr_3(i, InstructionKind::DSUBU, {}, make_gpr(Reg::R0), {})) { + // this is used for abs? BranchDelay b(BranchDelay::NEGATE); - b.destination = make_reg(i.get_dst(0).get_reg(), idx); - b.source = make_reg(i.get_src(1).get_reg(), idx); + auto dst = i.get_dst(0).get_reg(); + auto src = i.get_src(1).get_reg(); + b.destination = make_reg(dst, idx); + b.source = make_reg(src, idx); + b.write_regs.push_back(dst); + b.read_regs.push_back(src); return b; } BranchDelay b(BranchDelay::UNKNOWN); @@ -917,31 +1286,41 @@ BranchDelay get_branch_delay(Instruction& i, int idx) { std::shared_ptr try_bne(Instruction& instr, Instruction& next_instr, int idx) { if (instr.kind == InstructionKind::BNE && instr.get_src(1).is_reg(make_gpr(Reg::R0))) { - return std::make_shared( + auto op = std::make_shared( Condition(Condition::NONZERO, make_reg(instr.get_src(0).get_reg(), idx), nullptr, nullptr), instr.get_src(2).get_label(), get_branch_delay(next_instr, idx), false); + op->update_reginfo_self(0, 1, 0); + return op; } else if (instr.kind == InstructionKind::BNE && instr.get_src(0).is_reg(make_gpr(Reg::S7))) { - return std::make_shared( + auto op = std::make_shared( Condition(Condition::TRUTHY, make_reg(instr.get_src(1).get_reg(), idx), nullptr, nullptr), instr.get_src(2).get_label(), get_branch_delay(next_instr, idx), false); + op->update_reginfo_self(0, 1, 0); + return op; } else if (instr.kind == InstructionKind::BNE) { - return std::make_shared( + auto op = std::make_shared( Condition(Condition::NOT_EQUAL, make_reg(instr.get_src(0).get_reg(), idx), make_reg(instr.get_src(1).get_reg(), idx), nullptr), instr.get_src(2).get_label(), get_branch_delay(next_instr, idx), false); + op->update_reginfo_self(0, 2, 0); + return op; } return nullptr; } std::shared_ptr try_bnel(Instruction& instr, Instruction& next_instr, int idx) { if (instr.kind == InstructionKind::BNEL && instr.get_src(0).is_reg(make_gpr(Reg::S7))) { - return std::make_shared( + auto op = std::make_shared( Condition(Condition::TRUTHY, make_reg(instr.get_src(1).get_reg(), idx), nullptr, nullptr), instr.get_src(2).get_label(), get_branch_delay(next_instr, idx), true); + op->update_reginfo_self(0, 1, 0); + return op; } else if (instr.kind == InstructionKind::BNEL && instr.get_src(1).is_reg(make_gpr(Reg::R0))) { - return std::make_shared( + auto op = std::make_shared( Condition(Condition::NONZERO, make_reg(instr.get_src(0).get_reg(), idx), nullptr, nullptr), instr.get_src(2).get_label(), get_branch_delay(next_instr, idx), true); + op->update_reginfo_self(0, 1, 0); + return op; } else if (instr.kind == InstructionKind::BNEL) { // return std::make_shared(IR_Branch2::NOT_EQUAL, instr.get_src(2).get_label(), // make_reg(instr.get_src(0).get_reg(), idx), @@ -953,20 +1332,24 @@ std::shared_ptr try_bnel(Instruction& instr, Instruction& next_instr, std::shared_ptr try_beql(Instruction& instr, Instruction& next_instr, int idx) { if (instr.kind == InstructionKind::BEQL && instr.get_src(0).is_reg(make_gpr(Reg::S7))) { - return std::make_shared( + auto op = std::make_shared( Condition(Condition::FALSE, make_reg(instr.get_src(1).get_reg(), idx), nullptr, nullptr), instr.get_src(2).get_label(), get_branch_delay(next_instr, idx), true); + op->update_reginfo_self(0, 1, 0); + return op; } else if (instr.kind == InstructionKind::BEQL && instr.get_src(1).is_reg(make_gpr(Reg::R0))) { - return std::make_shared( + auto op = std::make_shared( Condition(Condition::ZERO, make_reg(instr.get_src(0).get_reg(), idx), nullptr, nullptr), instr.get_src(2).get_label(), get_branch_delay(next_instr, idx), true); - } - - else if (instr.kind == InstructionKind::BEQL) { - return std::make_shared( + op->update_reginfo_self(0, 1, 0); + return op; + } else if (instr.kind == InstructionKind::BEQL) { + auto op = std::make_shared( Condition(Condition::EQUAL, make_reg(instr.get_src(0).get_reg(), idx), make_reg(instr.get_src(1).get_reg(), idx), nullptr), instr.get_src(2).get_label(), get_branch_delay(next_instr, idx), true); + op->update_reginfo_self(0, 2, 0); + return op; } return nullptr; } @@ -974,48 +1357,60 @@ std::shared_ptr try_beql(Instruction& instr, Instruction& next_instr, std::shared_ptr try_beq(Instruction& instr, Instruction& next_instr, int idx) { if (instr.kind == InstructionKind::BEQ && instr.get_src(0).is_reg(make_gpr(Reg::R0)) && instr.get_src(1).is_reg(make_gpr(Reg::R0))) { - return std::make_shared( + auto op = std::make_shared( Condition(Condition::ALWAYS, nullptr, nullptr, nullptr), instr.get_src(2).get_label(), get_branch_delay(next_instr, idx), false); + op->update_reginfo_self(0, 0, 0); + return op; } else if (instr.kind == InstructionKind::BEQ && instr.get_src(0).is_reg(make_gpr(Reg::S7))) { - return std::make_shared( + auto op = std::make_shared( Condition(Condition::FALSE, make_reg(instr.get_src(1).get_reg(), idx), nullptr, nullptr), instr.get_src(2).get_label(), get_branch_delay(next_instr, idx), false); + op->update_reginfo_self(0, 1, 0); + return op; } else if (instr.kind == InstructionKind::BEQ) { - return std::make_shared( + auto op = std::make_shared( Condition(Condition::EQUAL, make_reg(instr.get_src(0).get_reg(), idx), make_reg(instr.get_src(1).get_reg(), idx), nullptr), instr.get_src(2).get_label(), get_branch_delay(next_instr, idx), false); + op->update_reginfo_self(0, 2, 0); + return op; } return nullptr; } std::shared_ptr try_bgtzl(Instruction& instr, Instruction& next_instr, int idx) { if (instr.kind == InstructionKind::BGTZL) { - return std::make_shared( + auto op = std::make_shared( Condition(Condition::GREATER_THAN_ZERO_SIGNED, make_reg(instr.get_src(0).get_reg(), idx), nullptr, nullptr), instr.get_src(1).get_label(), get_branch_delay(next_instr, idx), true); + op->update_reginfo_self(0, 1, 0); + return op; } return nullptr; } std::shared_ptr try_bgezl(Instruction& instr, Instruction& next_instr, int idx) { if (instr.kind == InstructionKind::BGEZL) { - return std::make_shared( + auto op = std::make_shared( Condition(Condition::GEQ_ZERO_SIGNED, make_reg(instr.get_src(0).get_reg(), idx), nullptr, nullptr), instr.get_src(1).get_label(), get_branch_delay(next_instr, idx), true); + op->update_reginfo_self(0, 1, 0); + return op; } return nullptr; } std::shared_ptr try_bltzl(Instruction& instr, Instruction& next_instr, int idx) { if (instr.kind == InstructionKind::BLTZL) { - return std::make_shared( + auto op = std::make_shared( Condition(Condition::LESS_THAN_ZERO, make_reg(instr.get_src(0).get_reg(), idx), nullptr, nullptr), instr.get_src(1).get_label(), get_branch_delay(next_instr, idx), true); + op->update_reginfo_self(0, 1, 0); + return op; } return nullptr; } @@ -1029,9 +1424,13 @@ std::shared_ptr try_daddiu(Instruction& i0, Instruction& i1, int idx) assert(i0.get_src(1).get_imm() == 8); assert(i1.get_dst(0).get_reg() == dst_reg); assert(i1.get_src(0).get_reg() == make_gpr(Reg::S7)); - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), - std::make_shared(Condition( - Condition::ZERO, make_reg(src_reg, idx), nullptr, nullptr))); + auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), + std::make_shared(Condition( + Condition::ZERO, make_reg(src_reg, idx), nullptr, nullptr))); + op->write_regs.push_back(dst_reg); + op->read_regs.push_back(src_reg); + op->reg_info_set = true; + return op; } else if (i0.kind == InstructionKind::DADDIU && i1.kind == InstructionKind::MOVZ && i0.get_src(0).get_reg() == make_gpr(Reg::S7)) { auto dst_reg = i0.get_dst(0).get_reg(); @@ -1040,9 +1439,13 @@ std::shared_ptr try_daddiu(Instruction& i0, Instruction& i1, int idx) assert(i0.get_src(1).get_imm() == 8); assert(i1.get_dst(0).get_reg() == dst_reg); assert(i1.get_src(0).get_reg() == make_gpr(Reg::S7)); - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), - std::make_shared(Condition( - Condition::NONZERO, make_reg(src_reg, idx), nullptr, nullptr))); + auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), + std::make_shared(Condition( + Condition::NONZERO, make_reg(src_reg, idx), nullptr, nullptr))); + op->write_regs.push_back(dst_reg); + op->read_regs.push_back(src_reg); + op->reg_info_set = true; + return op; } return nullptr; } @@ -1056,7 +1459,10 @@ std::shared_ptr try_lui(Instruction& i0, Instruction& i1, int idx) { std::make_shared(i0.get_src(0).get_label())); if (i0.get_dst(0).get_reg() != i1.get_dst(0).get_reg()) { op->clobber = make_reg(i0.get_dst(0).get_reg(), idx); + op->clobber_regs.push_back(i0.get_dst(0).get_reg()); } + op->write_regs.push_back(i1.get_dst(0).get_reg()); + op->reg_info_set = true; return op; } else if (i0.kind == InstructionKind::LUI && i1.kind == InstructionKind::ORI && i0.get_src(0).is_imm() && i1.get_src(1).is_imm() && @@ -1066,12 +1472,16 @@ std::shared_ptr try_lui(Instruction& i0, Instruction& i1, int idx) { make_int((int64_t(i1.get_src(1).get_imm()) + int64_t(i0.get_src(0).get_imm() << 16)))); if (i0.get_dst(0).get_reg() != i1.get_dst(0).get_reg()) { op->clobber = make_reg(i0.get_dst(0).get_reg(), idx); + op->clobber_regs.push_back(i0.get_dst(0).get_reg()); } + op->write_regs.push_back(i1.get_dst(0).get_reg()); + op->reg_info_set = true; return op; } return nullptr; } +// note - this one is a little bit strange in how it's colored. std::shared_ptr try_slt(Instruction& i0, Instruction& i1, int idx) { if (is_gpr_3(i0, InstructionKind::SLT, {}, {}, {})) { auto temp = i0.get_dst(0).get_reg(); @@ -1084,6 +1494,11 @@ std::shared_ptr try_slt(Instruction& i0, Instruction& i1, int idx) { std::make_shared(IR_IntMath2::MIN_SIGNED, make_reg(left, idx), make_reg(right, idx))); result->clobber = make_reg(temp, idx); + result->clobber_regs.push_back(temp); + result->write_regs.push_back(left); + result->read_regs.push_back(right); + result->read_regs.push_back(right); + result->reg_info_set = true; return result; } @@ -1094,6 +1509,11 @@ std::shared_ptr try_slt(Instruction& i0, Instruction& i1, int idx) { std::make_shared(IR_IntMath2::MAX_SIGNED, make_reg(left, idx), make_reg(right, idx))); result->clobber = make_reg(temp, idx); + result->clobber_regs.push_back(temp); + result->write_regs.push_back(left); + result->read_regs.push_back(right); + result->read_regs.push_back(right); + result->reg_info_set = true; return result; } } @@ -1113,7 +1533,10 @@ std::shared_ptr try_lui(Instruction& i0, Instruction& i1, Instruction std::make_shared(i0.get_src(0).get_label())); if (i0.get_dst(0).get_reg() != i1.get_dst(0).get_reg()) { op->clobber = make_reg(i0.get_dst(0).get_reg(), idx); + op->clobber_regs.push_back(i0.get_dst(0).get_reg()); } + op->write_regs.push_back(i1.get_dst(0).get_reg()); + op->reg_info_set = true; return op; } return nullptr; @@ -1132,10 +1555,12 @@ std::shared_ptr try_dsubu(Instruction& i0, Instruction& i1, Instructi assert(i2.get_dst(0).get_reg() == dst_reg); assert(i2.get_src(0).get_reg() == make_gpr(Reg::S7)); assert(i2.get_src(1).get_reg() == clobber_reg); - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), - std::make_shared( - Condition(Condition::EQUAL, make_reg(src0_reg, idx), - make_reg(src1_reg, idx), make_reg(clobber_reg, idx)))); + auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), + std::make_shared( + Condition(Condition::EQUAL, make_reg(src0_reg, idx), + make_reg(src1_reg, idx), make_reg(clobber_reg, idx)))); + op->update_reginfo_self(1, 2, 1); + return op; } else if (i0.kind == InstructionKind::DSUBU && i1.kind == InstructionKind::DADDIU && i2.kind == InstructionKind::MOVZ) { // check for equality @@ -1150,10 +1575,12 @@ std::shared_ptr try_dsubu(Instruction& i0, Instruction& i1, Instructi if (i2.get_src(1).get_reg() != clobber_reg) { return nullptr; // TODO! } - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), - std::make_shared( - Condition(Condition::NOT_EQUAL, make_reg(src0_reg, idx), - make_reg(src1_reg, idx), make_reg(clobber_reg, idx)))); + auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), + std::make_shared( + Condition(Condition::NOT_EQUAL, make_reg(src0_reg, idx), + make_reg(src1_reg, idx), make_reg(clobber_reg, idx)))); + op->update_reginfo_self(1, 2, 1); + return op; } return nullptr; } @@ -1165,10 +1592,12 @@ std::shared_ptr try_slt(Instruction& i0, Instruction& i1, Instruction auto src1_reg = i0.get_src(1).get_reg(); assert(i1.get_src(0).get_reg() == clobber_reg); assert(i1.get_src(1).get_reg() == make_gpr(Reg::R0)); - return std::make_shared( + auto op = std::make_shared( Condition(Condition::LESS_THAN_SIGNED, make_reg(src0_reg, idx), make_reg(src1_reg, idx), make_reg(clobber_reg, idx)), i1.get_src(2).get_label(), get_branch_delay(i2, idx), false); + op->update_reginfo_self(0, 2, 1); + return op; } else if (i0.kind == InstructionKind::SLT && i1.kind == InstructionKind::DADDIU && i2.kind == InstructionKind::MOVZ) { auto clobber_reg = i0.get_dst(0).get_reg(); @@ -1182,20 +1611,24 @@ std::shared_ptr try_slt(Instruction& i0, Instruction& i1, Instruction if (i2.get_src(1).get_reg() != clobber_reg) { return nullptr; // TODO! } - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), - std::make_shared( - Condition(Condition::LESS_THAN_SIGNED, make_reg(src0_reg, idx), - make_reg(src1_reg, idx), make_reg(clobber_reg, idx)))); + auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), + std::make_shared( + Condition(Condition::LESS_THAN_SIGNED, make_reg(src0_reg, idx), + make_reg(src1_reg, idx), make_reg(clobber_reg, idx)))); + op->update_reginfo_self(1, 2, 1); + return op; } else if (i0.kind == InstructionKind::SLT && i1.kind == InstructionKind::BEQ) { auto clobber_reg = i0.get_dst(0).get_reg(); auto src0_reg = i0.get_src(0).get_reg(); auto src1_reg = i0.get_src(1).get_reg(); assert(i1.get_src(0).get_reg() == clobber_reg); assert(i1.get_src(1).get_reg() == make_gpr(Reg::R0)); - return std::make_shared( + auto op = std::make_shared( Condition(Condition::GEQ_SIGNED, make_reg(src0_reg, idx), make_reg(src1_reg, idx), make_reg(clobber_reg, idx)), i1.get_src(2).get_label(), get_branch_delay(i2, idx), false); + op->update_reginfo_self(0, 2, 1); + return op; } else if (i0.kind == InstructionKind::SLT && i1.kind == InstructionKind::DADDIU && i2.kind == InstructionKind::MOVN) { auto clobber_reg = i0.get_dst(0).get_reg(); @@ -1209,10 +1642,12 @@ std::shared_ptr try_slt(Instruction& i0, Instruction& i1, Instruction if (i2.get_src(1).get_reg() != clobber_reg) { return nullptr; // TODO! } - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), - std::make_shared( - Condition(Condition::GEQ_SIGNED, make_reg(src0_reg, idx), - make_reg(src1_reg, idx), make_reg(clobber_reg, idx)))); + auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), + std::make_shared( + Condition(Condition::GEQ_SIGNED, make_reg(src0_reg, idx), + make_reg(src1_reg, idx), make_reg(clobber_reg, idx)))); + op->update_reginfo_self(1, 2, 1); + return op; } return nullptr; } @@ -1224,10 +1659,12 @@ std::shared_ptr try_slti(Instruction& i0, Instruction& i1, Instructio auto src0_reg = i0.get_src(0).get_reg(); assert(i1.get_src(0).get_reg() == clobber_reg); assert(i1.get_src(1).get_reg() == make_gpr(Reg::R0)); - return std::make_shared( + auto op = std::make_shared( Condition(Condition::LESS_THAN_SIGNED, make_reg(src0_reg, idx), src1, make_reg(clobber_reg, idx)), i1.get_src(2).get_label(), get_branch_delay(i2, idx), false); + op->update_reginfo_self(0, 1, 1); + return op; } else if (i0.kind == InstructionKind::SLTI && i1.kind == InstructionKind::DADDIU && i2.kind == InstructionKind::MOVZ) { auto clobber_reg = i0.get_dst(0).get_reg(); @@ -1240,18 +1677,22 @@ std::shared_ptr try_slti(Instruction& i0, Instruction& i1, Instructio if (i2.get_src(1).get_reg() != clobber_reg) { return nullptr; // TODO! } - return make_set_atomic( + auto op = make_set_atomic( IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), std::make_shared(Condition(Condition::LESS_THAN_SIGNED, make_reg(src0_reg, idx), src1, make_reg(clobber_reg, idx)))); + op->update_reginfo_self(1, 1, 1); + return op; } else if (i0.kind == InstructionKind::SLTI && i1.kind == InstructionKind::BEQ) { auto clobber_reg = i0.get_dst(0).get_reg(); auto src0_reg = i0.get_src(0).get_reg(); assert(i1.get_src(0).get_reg() == clobber_reg); assert(i1.get_src(1).get_reg() == make_gpr(Reg::R0)); - return std::make_shared( + auto op = std::make_shared( Condition(Condition::GEQ_SIGNED, make_reg(src0_reg, idx), src1, make_reg(clobber_reg, idx)), i1.get_src(2).get_label(), get_branch_delay(i2, idx), false); + op->update_reginfo_self(0, 1, 1); + return op; } else if (i0.kind == InstructionKind::SLTI && i1.kind == InstructionKind::DADDIU && i2.kind == InstructionKind::MOVN) { auto clobber_reg = i0.get_dst(0).get_reg(); @@ -1264,10 +1705,12 @@ std::shared_ptr try_slti(Instruction& i0, Instruction& i1, Instructio if (i2.get_src(1).get_reg() != clobber_reg) { return nullptr; // TODO! } - return make_set_atomic( + auto op = make_set_atomic( IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), std::make_shared(Condition(Condition::GEQ_SIGNED, make_reg(src0_reg, idx), src1, make_reg(clobber_reg, idx)))); + op->update_reginfo_self(1, 1, 1); + return op; } return nullptr; } @@ -1279,10 +1722,12 @@ std::shared_ptr try_sltiu(Instruction& i0, Instruction& i1, Instructi auto src0_reg = i0.get_src(0).get_reg(); assert(i1.get_src(0).get_reg() == clobber_reg); assert(i1.get_src(1).get_reg() == make_gpr(Reg::R0)); - return std::make_shared( + auto op = std::make_shared( Condition(Condition::LESS_THAN_UNSIGNED, make_reg(src0_reg, idx), src1, make_reg(clobber_reg, idx)), i1.get_src(2).get_label(), get_branch_delay(i2, idx), false); + op->update_reginfo_self(0, 1, 1); + return op; } else if (i0.kind == InstructionKind::SLTIU && i1.kind == InstructionKind::DADDIU && i2.kind == InstructionKind::MOVZ) { auto clobber_reg = i0.get_dst(0).get_reg(); @@ -1295,19 +1740,23 @@ std::shared_ptr try_sltiu(Instruction& i0, Instruction& i1, Instructi if (i2.get_src(1).get_reg() != clobber_reg) { return nullptr; // TODO! } - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), - std::make_shared(Condition(Condition::LESS_THAN_UNSIGNED, - make_reg(src0_reg, idx), src1, - make_reg(clobber_reg, idx)))); + auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), + std::make_shared(Condition(Condition::LESS_THAN_UNSIGNED, + make_reg(src0_reg, idx), src1, + make_reg(clobber_reg, idx)))); + op->update_reginfo_self(1, 1, 1); + return op; } else if (i0.kind == InstructionKind::SLTIU && i1.kind == InstructionKind::BEQ) { auto clobber_reg = i0.get_dst(0).get_reg(); auto src0_reg = i0.get_src(0).get_reg(); assert(i1.get_src(0).get_reg() == clobber_reg); assert(i1.get_src(1).get_reg() == make_gpr(Reg::R0)); - return std::make_shared( + auto op = std::make_shared( Condition(Condition::GEQ_UNSIGNED, make_reg(src0_reg, idx), src1, make_reg(clobber_reg, idx)), i1.get_src(2).get_label(), get_branch_delay(i2, idx), false); + op->update_reginfo_self(0, 1, 1); + return op; } else if (i0.kind == InstructionKind::SLTIU && i1.kind == InstructionKind::DADDIU && i2.kind == InstructionKind::MOVN) { auto clobber_reg = i0.get_dst(0).get_reg(); @@ -1320,55 +1769,69 @@ std::shared_ptr try_sltiu(Instruction& i0, Instruction& i1, Instructi if (i2.get_src(1).get_reg() != clobber_reg) { return nullptr; // TODO! } - return make_set_atomic( + auto op = make_set_atomic( IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), std::make_shared(Condition(Condition::GEQ_UNSIGNED, make_reg(src0_reg, idx), src1, make_reg(clobber_reg, idx)))); + op->update_reginfo_self(1, 1, 1); + return op; } return nullptr; } std::shared_ptr try_ceqs(Instruction& i0, Instruction& i1, Instruction& i2, int idx) { if (i0.kind == InstructionKind::CEQS && i1.kind == InstructionKind::BC1T) { - return std::make_shared( + auto op = std::make_shared( Condition(Condition::FLOAT_EQUAL, make_reg(i0.get_src(0).get_reg(), idx), make_reg(i0.get_src(1).get_reg(), idx), nullptr), i1.get_src(0).get_label(), get_branch_delay(i2, idx), false); + op->update_reginfo_self(0, 2, 0); + return op; } else if (i0.kind == InstructionKind::CEQS && i1.kind == InstructionKind::BC1F) { - return std::make_shared( + auto op = std::make_shared( Condition(Condition::FLOAT_NOT_EQUAL, make_reg(i0.get_src(0).get_reg(), idx), make_reg(i0.get_src(1).get_reg(), idx), nullptr), i1.get_src(0).get_label(), get_branch_delay(i2, idx), false); + op->update_reginfo_self(0, 2, 0); + return op; } return nullptr; } std::shared_ptr try_clts(Instruction& i0, Instruction& i1, Instruction& i2, int idx) { if (i0.kind == InstructionKind::CLTS && i1.kind == InstructionKind::BC1T) { - return std::make_shared( + auto op = std::make_shared( Condition(Condition::FLOAT_LESS_THAN, make_reg(i0.get_src(0).get_reg(), idx), make_reg(i0.get_src(1).get_reg(), idx), nullptr), i1.get_src(0).get_label(), get_branch_delay(i2, idx), false); + op->update_reginfo_self(0, 2, 0); + return op; } else if (i0.kind == InstructionKind::CLTS && i1.kind == InstructionKind::BC1F) { - return std::make_shared( + auto op = std::make_shared( Condition(Condition::FLOAT_GEQ, make_reg(i0.get_src(0).get_reg(), idx), make_reg(i0.get_src(1).get_reg(), idx), nullptr), i1.get_src(0).get_label(), get_branch_delay(i2, idx), false); + op->update_reginfo_self(0, 2, 0); + return op; } return nullptr; } std::shared_ptr try_cles(Instruction& i0, Instruction& i1, Instruction& i2, int idx) { if (i0.kind == InstructionKind::CLES && i1.kind == InstructionKind::BC1T) { - return std::make_shared( + auto op = std::make_shared( Condition(Condition::FLOAT_LEQ, make_reg(i0.get_src(0).get_reg(), idx), make_reg(i0.get_src(1).get_reg(), idx), nullptr), i1.get_src(0).get_label(), get_branch_delay(i2, idx), false); + op->update_reginfo_self(0, 2, 0); + return op; } else if (i0.kind == InstructionKind::CLES && i1.kind == InstructionKind::BC1F) { - return std::make_shared( + auto op = std::make_shared( Condition(Condition::FLOAT_GREATER_THAN, make_reg(i0.get_src(0).get_reg(), idx), make_reg(i0.get_src(1).get_reg(), idx), nullptr), i1.get_src(0).get_label(), get_branch_delay(i2, idx), false); + op->update_reginfo_self(0, 2, 0); + return op; } return nullptr; } @@ -1380,10 +1843,12 @@ std::shared_ptr try_sltu(Instruction& i0, Instruction& i1, Instructio auto src1_reg = i0.get_src(1).get_reg(); assert(i1.get_src(0).get_reg() == clobber_reg); assert(i1.get_src(1).get_reg() == make_gpr(Reg::R0)); - return std::make_shared( + auto op = std::make_shared( Condition(Condition::LESS_THAN_UNSIGNED, make_reg(src0_reg, idx), make_reg(src1_reg, idx), make_reg(clobber_reg, idx)), i1.get_src(2).get_label(), get_branch_delay(i2, idx), false); + op->update_reginfo_self(0, 2, 1); + return op; } else if (i0.kind == InstructionKind::SLTU && i1.kind == InstructionKind::DADDIU && i2.kind == InstructionKind::MOVZ) { auto clobber_reg = i0.get_dst(0).get_reg(); @@ -1397,20 +1862,24 @@ std::shared_ptr try_sltu(Instruction& i0, Instruction& i1, Instructio if (i2.get_src(1).get_reg() != clobber_reg) { return nullptr; // TODO! } - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), - std::make_shared( - Condition(Condition::LESS_THAN_UNSIGNED, make_reg(src0_reg, idx), - make_reg(src1_reg, idx), make_reg(clobber_reg, idx)))); + auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), + std::make_shared( + Condition(Condition::LESS_THAN_UNSIGNED, make_reg(src0_reg, idx), + make_reg(src1_reg, idx), make_reg(clobber_reg, idx)))); + op->update_reginfo_self(1, 2, 1); + return op; } else if (i0.kind == InstructionKind::SLTU && i1.kind == InstructionKind::BEQ) { auto clobber_reg = i0.get_dst(0).get_reg(); auto src0_reg = i0.get_src(0).get_reg(); auto src1_reg = i0.get_src(1).get_reg(); assert(i1.get_src(0).get_reg() == clobber_reg); assert(i1.get_src(1).get_reg() == make_gpr(Reg::R0)); - return std::make_shared( + auto op = std::make_shared( Condition(Condition::GEQ_UNSIGNED, make_reg(src0_reg, idx), make_reg(src1_reg, idx), make_reg(clobber_reg, idx)), i1.get_src(2).get_label(), get_branch_delay(i2, idx), false); + op->update_reginfo_self(0, 2, 1); + return op; } else if (i0.kind == InstructionKind::SLTU && i1.kind == InstructionKind::DADDIU && i2.kind == InstructionKind::MOVN) { auto clobber_reg = i0.get_dst(0).get_reg(); @@ -1424,10 +1893,12 @@ std::shared_ptr try_sltu(Instruction& i0, Instruction& i1, Instructio if (i2.get_src(1).get_reg() != clobber_reg) { return nullptr; // TODO! } - return make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), - std::make_shared( - Condition(Condition::GEQ_UNSIGNED, make_reg(src0_reg, idx), - make_reg(src1_reg, idx), make_reg(clobber_reg, idx)))); + auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), + std::make_shared( + Condition(Condition::GEQ_UNSIGNED, make_reg(src0_reg, idx), + make_reg(src1_reg, idx), make_reg(clobber_reg, idx)))); + op->update_reginfo_self(1, 2, 1); + return op; } return nullptr; } @@ -1448,7 +1919,9 @@ std::shared_ptr try_lwu(Instruction& i0, i2.get_src(0).get_imm() == 12 && i2.get_src(1).is_reg(s6) && i3.kind == InstructionKind::JALR && i3.get_dst(0).is_reg(make_gpr(Reg::RA)) && i3.get_src(0).is_reg(s6) && i4.kind == InstructionKind::MFLO1 && i4.get_dst(0).is_reg(s6)) { - return std::make_shared(); + auto op = std::make_shared(); + op->reg_info_set = true; + return op; } return nullptr; } @@ -1930,6 +2403,10 @@ void add_basic_ops_to_block(Function* func, const BasicBlock& block, LinkedObjec func->warnings += "Function contains asm op"; func->contains_asm_ops = true; } + + if (!result->reg_info_set) { + printf("Failed reg info %s\n", result->print(*file).c_str()); + } func->add_basic_op(result, instr, instr + length); instr += (length - 1); } diff --git a/decompiler/IR/IR.cpp b/decompiler/IR/IR.cpp index 32a677bf9a..071d5f42ff 100644 --- a/decompiler/IR/IR.cpp +++ b/decompiler/IR/IR.cpp @@ -64,6 +64,131 @@ void IR_Set::get_children(std::vector>* output) const { output->push_back(src); } +template <> +void IR_Set_Atomic::update_reginfo_self(int n_dest, int n_src, int n_clobber) { + auto dst_as_reg = dynamic_cast(dst.get()); + if (dst_as_reg) { + write_regs.push_back(dst_as_reg->reg); + } + + auto src_as = dynamic_cast(src.get()); + assert(src_as); + + for (auto& x : {src_as->arg0, src_as->arg1}) { + auto reg = dynamic_cast(x.get()); + if (reg) { + read_regs.push_back(reg->reg); + } + } + + assert(int(write_regs.size()) == n_dest); + assert(int(read_regs.size()) == n_src); + assert(int(clobber_regs.size()) == n_clobber); + reg_info_set = true; +} + +template <> +void IR_Set_Atomic::update_reginfo_self(int n_dest, int n_src, int n_clobber) { + auto dst_as_reg = dynamic_cast(dst.get()); + if (dst_as_reg) { + write_regs.push_back(dst_as_reg->reg); + } + + auto src_as = dynamic_cast(src.get()); + assert(src_as); + + auto reg = dynamic_cast(src_as->arg.get()); + if (reg) { + read_regs.push_back(reg->reg); + } + + assert(int(write_regs.size()) == n_dest); + assert(int(read_regs.size()) == n_src); + assert(int(clobber_regs.size()) == n_clobber); + reg_info_set = true; +} + +template <> +void IR_Set_Atomic::update_reginfo_self(int n_dest, int n_src, int n_clobber) { + auto dst_as_reg = dynamic_cast(dst.get()); + if (dst_as_reg) { + write_regs.push_back(dst_as_reg->reg); + } + + auto src_as = dynamic_cast(src.get()); + assert(src_as); + + // try to get the source as a register + auto reg = dynamic_cast(src_as->location.get()); + if (reg) { + read_regs.push_back(reg->reg); + } + + // or as math with a register + auto math = dynamic_cast(src_as->location.get()); + if (math) { + for (auto& x : {math->arg0, math->arg1}) { + auto math_reg = dynamic_cast(x.get()); + if (math_reg) { + read_regs.push_back(math_reg->reg); + } + } + } + + assert(int(write_regs.size()) == n_dest); + assert(int(read_regs.size()) == n_src); + assert(int(clobber_regs.size()) == n_clobber); + reg_info_set = true; +} + +template <> +void IR_Set_Atomic::update_reginfo_self(int n_dest, int n_src, int n_clobber) { + auto dst_as_reg = dynamic_cast(dst.get()); + if (dst_as_reg) { + write_regs.push_back(dst_as_reg->reg); + } + + auto src_as_cmp = dynamic_cast(src.get()); + assert(src_as_cmp); + for (auto& x : {src_as_cmp->condition.src0, src_as_cmp->condition.src1}) { + auto as_reg = dynamic_cast(x.get()); + if (as_reg) { + read_regs.push_back(as_reg->reg); + } + } + + auto as_reg = dynamic_cast(src_as_cmp->condition.clobber.get()); + if (as_reg) { + clobber_regs.push_back(as_reg->reg); + } + + assert(int(write_regs.size()) == n_dest); + assert(int(read_regs.size()) == n_src); + assert(int(clobber_regs.size()) == n_clobber); + reg_info_set = true; +} + +/*! + * Set the register info, assuming this is a register to register set. + */ +void IR_Set_Atomic::update_reginfo_regreg() { + auto dst_as_reg = dynamic_cast(dst.get()); + if (dst_as_reg) { + write_regs.push_back(dst_as_reg->reg); + } + + auto src_as = dynamic_cast(src.get()); + + if (src_as) { + read_regs.push_back(src_as->reg); + } + + assert(int(write_regs.size()) == 1); + assert(int(read_regs.size()) == 1); + assert(int(clobber_regs.size()) == 0); + reg_info_set = true; +} + goos::Object IR_Store::to_form(const LinkedObjectFile& file) const { std::string store_operator; switch (kind) { @@ -134,6 +259,34 @@ goos::Object IR_Store_Atomic::to_form(const LinkedObjectFile& file) const { src->to_form(file)); } +void IR_Store_Atomic::update_reginfo_self(int n_dest, int n_src, int n_clobber) { + auto src_reg = dynamic_cast(src.get()); + if (src_reg) { + read_regs.push_back(src_reg->reg); + } + + auto dst_reg = dynamic_cast(dst.get()); + if (dst_reg) { + read_regs.push_back(dst_reg->reg); + } + + // or as math with a register + auto math = dynamic_cast(dst.get()); + if (math) { + for (auto& x : {math->arg0, math->arg1}) { + auto math_reg = dynamic_cast(x.get()); + if (math_reg) { + read_regs.push_back(math_reg->reg); + } + } + } + + assert(int(write_regs.size()) == n_dest); + assert(int(read_regs.size()) == n_src); + assert(int(clobber_regs.size()) == n_clobber); + reg_info_set = true; +} + goos::Object IR_Symbol::to_form(const LinkedObjectFile& file) const { (void)file; return pretty_print::to_symbol("'" + name); @@ -680,6 +833,33 @@ void IR_Branch::get_children(std::vector>* output) const { branch_delay.get_children(output); } +void IR_Branch_Atomic::update_reginfo_self(int n_dest, int n_src, int n_clobber) { + // first, grab from condition + for (auto& x : {condition.src0, condition.src1}) { + auto as_reg = dynamic_cast(x.get()); + if (as_reg) { + read_regs.push_back(as_reg->reg); + } + } + + auto as_reg = dynamic_cast(condition.clobber.get()); + if (as_reg) { + clobber_regs.push_back(as_reg->reg); + } + assert(int(write_regs.size()) == n_dest); + assert(int(read_regs.size()) == n_src); + assert(int(clobber_regs.size()) == n_clobber); + + // copy from branch delay + read_regs.insert(read_regs.end(), branch_delay.read_regs.begin(), branch_delay.read_regs.end()); + write_regs.insert(write_regs.end(), branch_delay.write_regs.begin(), + branch_delay.write_regs.end()); + clobber_regs.insert(clobber_regs.end(), branch_delay.clobber_regs.begin(), + branch_delay.clobber_regs.end()); + + reg_info_set = true; +} + goos::Object IR_Compare::to_form(const LinkedObjectFile& file) const { return condition.to_form(file); } @@ -900,6 +1080,22 @@ void IR_AsmOp::get_children(std::vector>* output) const { } } +void IR_AsmOp_Atomic::set_reg_info() { + auto dst_as_reg = dynamic_cast(dst.get()); + if (dst_as_reg) { + write_regs.push_back(dst_as_reg->reg); + } + + for (auto& x : {src0, src1, src2}) { + auto src_as_reg = dynamic_cast(x.get()); + if (src_as_reg) { + read_regs.push_back(src_as_reg->reg); + } + } + + reg_info_set = true; +} + goos::Object IR_CMoveF::to_form(const LinkedObjectFile& file) const { return pretty_print::build_list( pretty_print::to_symbol(on_zero ? "cmove-false-on-zero" : "cmove-false-on-nonzero"), diff --git a/decompiler/IR/IR.h b/decompiler/IR/IR.h index 50d3039116..4c9ddf03f0 100644 --- a/decompiler/IR/IR.h +++ b/decompiler/IR/IR.h @@ -37,6 +37,8 @@ class IR { class IR_Atomic : public virtual IR { public: + std::vector read_regs, write_regs, clobber_regs; + bool reg_info_set = false; }; class IR_Failed : public virtual IR { @@ -93,13 +95,22 @@ class IR_Set_Atomic : public IR_Set, public IR_Atomic { public: IR_Set_Atomic(IR_Set::Kind _kind, std::shared_ptr _dst, std::shared_ptr _src) : IR_Set(_kind, std::move(_dst), std::move(_src)) {} + + template + void update_reginfo_self(int n_dest, int n_src, int n_clobber); + + void update_reginfo_regreg(); }; +class IR_IntMath2; +template <> +void IR_Set_Atomic::update_reginfo_self(int n_dest, int n_src, int n_clobber); + class IR_Store : public virtual IR_Set { public: enum Kind { INTEGER, FLOAT } kind; IR_Store(Kind _kind, std::shared_ptr _dst, std::shared_ptr _src, int _size) - : IR_Set(IR_Set::LOAD, std::move(_dst), std::move(_src)), kind(_kind), size(_size) {} + : IR_Set(IR_Set::STORE, std::move(_dst), std::move(_src)), kind(_kind), size(_size) {} int size; goos::Object to_form(const LinkedObjectFile& file) const override; }; @@ -112,9 +123,10 @@ class IR_Store_Atomic : public IR_Set_Atomic { public: enum Kind { INTEGER, FLOAT } kind; IR_Store_Atomic(Kind _kind, std::shared_ptr _dst, std::shared_ptr _src, int _size) - : IR_Set_Atomic(IR_Set::LOAD, std::move(_dst), std::move(_src)), kind(_kind), size(_size) {} + : IR_Set_Atomic(IR_Set::STORE, std::move(_dst), std::move(_src)), kind(_kind), size(_size) {} int size; goos::Object to_form(const LinkedObjectFile& file) const override; + void update_reginfo_self(int n_dest, int n_src, int n_clobber); }; class IR_Symbol : public virtual IR { @@ -274,6 +286,10 @@ struct BranchDelay { explicit BranchDelay(Kind _kind) : kind(_kind) {} goos::Object to_form(const LinkedObjectFile& file) const; void get_children(std::vector>* output) const; + + std::vector read_regs; + std::vector write_regs; + std::vector clobber_regs; }; struct Condition { @@ -356,6 +372,8 @@ class IR_Branch_Atomic : public virtual IR_Branch, public IR_Atomic { BranchDelay _branch_delay, bool _likely) : IR_Branch(std::move(_condition), _dest_label_idx, std::move(_branch_delay), _likely) {} + // note - counts only for the condition. + void update_reginfo_self(int n_dst, int n_src, int n_clobber); }; class IR_Compare : public virtual IR { @@ -508,6 +526,7 @@ class IR_AsmOp : public virtual IR { class IR_AsmOp_Atomic : public virtual IR_AsmOp, public IR_Atomic { public: IR_AsmOp_Atomic(std::string _name) : IR_AsmOp(std::move(_name)) {} + void set_reg_info(); }; class IR_CMoveF : public virtual IR { diff --git a/decompiler/ObjectFile/ObjectFileDB.cpp b/decompiler/ObjectFile/ObjectFileDB.cpp index b8f91d2285..9d05d073bb 100644 --- a/decompiler/ObjectFile/ObjectFileDB.cpp +++ b/decompiler/ObjectFile/ObjectFileDB.cpp @@ -811,6 +811,7 @@ void ObjectFileDB::analyze_functions() { int total_named_functions = 0; int total_basic_ops = 0; int total_failed_basic_ops = 0; + int total_reginfo_ops = 0; int asm_funcs = 0; int non_asm_funcs = 0; @@ -848,6 +849,7 @@ void ObjectFileDB::analyze_functions() { } total_basic_ops += func.get_basic_op_count(); total_failed_basic_ops += func.get_failed_basic_op_count(); + total_reginfo_ops += func.get_reginfo_basic_op_count(); if (func.is_inspect_method) { auto result = inspect_inspect_method(func, func.method_of_type, dts, data.linked_data); @@ -925,6 +927,8 @@ void ObjectFileDB::analyze_functions() { int successful_basic_ops = total_basic_ops - total_failed_basic_ops; spdlog::info(" {}/{} basic ops converted successfully ({:.3f}%)", successful_basic_ops, total_basic_ops, 100.f * float(successful_basic_ops) / float(total_basic_ops)); + spdlog::info(" {}/{} basic ops with reginfo ({:.3f}%)", total_reginfo_ops, total_basic_ops, + 100.f * float(total_reginfo_ops) / float(total_basic_ops)); spdlog::info(" {}/{} cfgs converted to ir ({:.3f}%)", successful_cfg_irs, non_asm_funcs, 100.f * float(successful_cfg_irs) / float(non_asm_funcs)); spdlog::info(" {}/{} functions passed type analysis ({:.2f}%)\n", successful_type_analysis,