diff --git a/decompiler/CMakeLists.txt b/decompiler/CMakeLists.txt index 0e326b9bd5..1f64eabc24 100644 --- a/decompiler/CMakeLists.txt +++ b/decompiler/CMakeLists.txt @@ -37,10 +37,6 @@ add_library( Function/BasicBlocks.cpp Function/CfgVtx.cpp Function/Function.cpp - Function/TypeInspector.cpp - - IR/BasicOpBuilder.cpp - IR/IR.cpp IR2/AtomicOp.cpp IR2/AtomicOpForm.cpp diff --git a/decompiler/Function/BasicBlocks.h b/decompiler/Function/BasicBlocks.h index 5f74c65e83..a9be9ecb5a 100644 --- a/decompiler/Function/BasicBlocks.h +++ b/decompiler/Function/BasicBlocks.h @@ -14,11 +14,6 @@ struct BasicBlock { int start_word; int end_word; - // [start, end) - int start_basic_op = -1; - int end_basic_op = -1; - int basic_op_size() const { return end_basic_op - start_basic_op; } - std::string label_name; std::vector pred; diff --git a/decompiler/Function/Function.cpp b/decompiler/Function/Function.cpp index 30ab73b88c..b04a59688d 100644 --- a/decompiler/Function/Function.cpp +++ b/decompiler/Function/Function.cpp @@ -4,8 +4,6 @@ #include "decompiler/Disasm/InstructionMatching.h" #include "decompiler/ObjectFile/LinkedObjectFile.h" #include "decompiler/util/DecompilerTypeSystem.h" -#include "TypeInspector.h" -#include "decompiler/IR/IR.h" #include "decompiler/IR2/Form.h" #include "common/util/BitUtils.h" #include "common/util/Assert.h" @@ -673,17 +671,6 @@ void Function::find_type_defs(LinkedObjectFile& file, DecompilerTypeSystem& dts) } } -void Function::add_basic_op(std::shared_ptr op, int start_instr, int end_instr) { - op->is_basic_op = true; - ASSERT(end_instr > start_instr); - - for (int i = start_instr; i < end_instr; i++) { - instruction_to_basic_op[i] = basic_ops.size(); - } - basic_op_to_instruction[basic_ops.size()] = start_instr; - basic_ops.push_back(op); -} - bool Function::instr_starts_basic_op(int idx) { auto op = instruction_to_basic_op.find(idx); if (op != instruction_to_basic_op.end()) { @@ -693,10 +680,6 @@ bool Function::instr_starts_basic_op(int idx) { return false; } -std::shared_ptr Function::get_basic_op_at_instr(int idx) { - return basic_ops.at(instruction_to_basic_op.at(idx)); -} - bool Function::instr_starts_atomic_op(int idx) { auto op = ir2.atomic_ops->instruction_to_atomic_op.find(idx); if (op != ir2.atomic_ops->instruction_to_atomic_op.end()) { @@ -710,20 +693,6 @@ const AtomicOp& Function::get_atomic_op_at_instr(int idx) { return *ir2.atomic_ops->ops.at(ir2.atomic_ops->instruction_to_atomic_op.at(idx)); } -int Function::get_basic_op_count() { - return basic_ops.size(); -} - -int Function::get_failed_basic_op_count() { - int count = 0; - for (auto& x : basic_ops) { - if (dynamic_cast(x.get())) { - count++; - } - } - return count; -} - /*! * Topological sort of basic blocks. * Returns a valid ordering + a list of blocks that you can't reach and therefore diff --git a/decompiler/Function/Function.h b/decompiler/Function/Function.h index e9cc7bb75b..6d8f37f084 100644 --- a/decompiler/Function/Function.h +++ b/decompiler/Function/Function.h @@ -17,8 +17,6 @@ namespace decompiler { class DecompilerTypeSystem; -class IR_Atomic; -class IR; struct FunctionName { enum class FunctionKind { @@ -104,21 +102,14 @@ class Function { void find_global_function_defs(LinkedObjectFile& file, DecompilerTypeSystem& dts); void find_method_defs(LinkedObjectFile& file, DecompilerTypeSystem& dts); void find_type_defs(LinkedObjectFile& file, DecompilerTypeSystem& dts); - void add_basic_op(std::shared_ptr op, int start_instr, int end_instr); - bool has_basic_ops() { return !basic_ops.empty(); } bool instr_starts_basic_op(int idx); - std::shared_ptr get_basic_op_at_instr(int idx); bool instr_starts_atomic_op(int idx); const AtomicOp& get_atomic_op_at_instr(int idx); - int get_basic_op_count(); - int get_failed_basic_op_count(); BlockTopologicalSort bb_topo_sort(); std::string name() const; TypeSpec type; - std::shared_ptr ir = nullptr; - int segment = -1; int start_word = -1; int end_word = -1; // not inclusive, but does include padding. @@ -175,7 +166,6 @@ class Function { } prologue; bool uses_fp_register = false; - std::vector> basic_ops; struct { bool atomic_ops_attempted = false; diff --git a/decompiler/Function/TypeInspector.cpp b/decompiler/Function/TypeInspector.cpp deleted file mode 100644 index 14063623c2..0000000000 --- a/decompiler/Function/TypeInspector.cpp +++ /dev/null @@ -1,848 +0,0 @@ -#include "decompiler/config.h" -#include "decompiler/Disasm/InstructionMatching.h" -#include "TypeInspector.h" -#include "Function.h" -#include "decompiler/ObjectFile/LinkedObjectFile.h" -#include "third-party/fmt/core.h" -#include "decompiler/util/DecompilerTypeSystem.h" -#include "common/type_system/deftype.h" -#include "decompiler/IR/IR.h" - -namespace decompiler { -namespace { -struct FieldPrint { - char format = '\0'; - std::string field_name; - std::string field_type_name; - bool has_array = false; - int array_size = -1; -}; - -FieldPrint get_field_print(const std::string& str) { - int idx = 0; - auto next = [&]() { return str.at(idx++); }; - - auto peek = [&](int off) { return str.at(idx + off); }; - - FieldPrint field_print; - - // first is ~T - char c0 = next(); - ASSERT(c0 == '~'); - char c1 = next(); - ASSERT(c1 == 'T'); - - // next the name: - char name_char = next(); - while (name_char != ':' && name_char != '[') { - field_print.field_name.push_back(name_char); - name_char = next(); - } - - // possibly array thing - if (name_char == '[') { - int size = 0; - char num_char = next(); - while (num_char >= '0' && num_char <= '9') { - size = size * 10 + (num_char - '0'); - num_char = next(); - } - field_print.has_array = true; - field_print.array_size = size; - - ASSERT(num_char == ']'); - char c = next(); - ASSERT(c == ' '); - c = next(); - ASSERT(c == '@'); - c = next(); - ASSERT(c == ' '); - c = next(); - ASSERT(c == '#'); - c = next(); - ASSERT(c == 'x'); - } else { - // next a space - char space_char = next(); - ASSERT(space_char == ' '); - } - - // next the format - char fmt1 = next(); - if (fmt1 == '~' && peek(0) != '`') { // normal ~_~% - char fmt_code = next(); - field_print.format = fmt_code; - char end1 = next(); - ASSERT(end1 == '~'); - char end2 = next(); - ASSERT(end2 == '%'); - ASSERT(idx == (int)str.size()); - } else if (fmt1 == '#' && peek(0) == '<') { // struct #~% - next(); - char type_name_c = next(); - while (type_name_c != ' ') { - field_print.field_type_name += type_name_c; - type_name_c = next(); - } - - std::string expect_end = "@ #x~X>~%"; - for (char i : expect_end) { - char c = next(); - ASSERT(i == c); - } - field_print.format = 'X'; - - ASSERT(idx == (int)str.size()); - } else if (fmt1 == '#' && peek(0) == 'x') { // #x~X~% - next(); - std::string expect_end = "~X~%"; - for (char i : expect_end) { - char c = next(); - ASSERT(i == c); - } - field_print.format = 'X'; - } else if (fmt1 == '~' && peek(0) == '`') { // ~`my-type-with-overriden-print`P~% - next(); - char type_name_c = next(); - while (type_name_c != '`') { - field_print.field_type_name += type_name_c; - type_name_c = next(); - } - - std::string expect_end = "P~%"; - for (char i : expect_end) { - char c = next(); - ASSERT(i == c); - } - field_print.format = 'P'; - - ASSERT(idx == (int)str.size()); - } else if (str.substr(idx - 1) == "(meters ~m)~%") { - field_print.format = 'm'; - } else if (str.substr(idx - 1) == "(deg ~r)~%") { - field_print.format = 'r'; - } else if (str.substr(idx - 1) == "(seconds ~e)~%") { - field_print.format = 'e'; - } - - else { - throw std::runtime_error("other format nyi in get_field_print " + str.substr(idx)); - } - - return field_print; -} - -bool is_int(IR* ir, s64 value) { - auto as_int = dynamic_cast(ir); - return as_int && as_int->value == value; -} - -bool is_reg(IR* ir, Register reg) { - auto as_reg = dynamic_cast(ir); - return as_reg && as_reg->reg == reg; -} - -bool is_math_reg_constant(IR* ir, IR_IntMath2::Kind kind, Register src0, s64 src1) { - auto as_math = dynamic_cast(ir); - return as_math && as_math->kind == kind && is_reg(as_math->arg0.get(), src0) && - is_int(as_math->arg1.get(), src1); -} - -bool is_load_with_offset(IR* ir, IR_Load::Kind kind, int load_size, Register base, s64 offset) { - auto as_load = dynamic_cast(ir); - return as_load && as_load->kind == kind && as_load->size == load_size && - is_math_reg_constant(as_load->location.get(), IR_IntMath2::ADD, base, offset); -} - -bool is_get_load_with_offset(IR* ir, - Register dst, - IR_Load::Kind kind, - int load_size, - Register base, - s64 offset) { - auto as_set = dynamic_cast(ir); - return as_set && is_reg(as_set->dst.get(), dst) && - is_load_with_offset(as_set->src.get(), kind, load_size, base, offset); -} - -struct LoadInfo { - int offset = 0; - int size = 0; - IR_Load::Kind kind; -}; - -LoadInfo get_load_info_from_set(IR* load) { - auto as_set = dynamic_cast(load); - ASSERT(as_set); - auto as_load = dynamic_cast(as_set->src.get()); - ASSERT(as_load); - LoadInfo info; - info.kind = as_load->kind; - info.size = as_load->size; - if (dynamic_cast(as_load->location.get())) { - info.offset = 0; - return info; - } - - auto as_math = dynamic_cast(as_load->location.get()); - ASSERT(as_math); - ASSERT(as_math->kind == IR_IntMath2::ADD); - auto as_int = dynamic_cast(as_math->arg1.get()); - ASSERT(as_int); - info.offset = as_int->value; - return info; -} - -Register get_base_of_load(IR_Load* load) { - auto as_reg = dynamic_cast(load->location.get()); - if (as_reg) { - return as_reg->reg; - } - - auto as_math = dynamic_cast(load->location.get()); - ASSERT(as_math->kind == IR_IntMath2::ADD); - ASSERT(dynamic_cast(as_math->arg1.get())); - auto math_reg = dynamic_cast(as_math->arg0.get()); - if (math_reg) { - return math_reg->reg; - } else { - ASSERT(false); - } - return {}; -} - -bool is_load_with_base(IR* ir, Register base) { - auto as_load = dynamic_cast(ir); - return as_load && base == get_base_of_load(as_load); -} - -bool is_get_load(IR* ir, Register dst, Register base) { - auto as_set = dynamic_cast(ir); - return as_set && is_reg(as_set->dst.get(), dst) && is_load_with_base(as_set->src.get(), base); -} - -bool is_reg_reg_move(IR* ir, Register dst, Register src) { - auto as_set = dynamic_cast(ir); - return as_set && is_reg(as_set->dst.get(), dst) && is_reg(as_set->src.get(), src); -} - -bool is_sym_value(IR* ir, const std::string& sym_name) { - auto as_sym_value = dynamic_cast(ir); - return as_sym_value && as_sym_value->name == sym_name; -} - -bool is_sym(IR* ir, const std::string& sym_name) { - auto as_sym = dynamic_cast(ir); - return as_sym && as_sym->name == sym_name; -} - -bool is_get_sym_value(IR* ir, Register dst, const std::string& sym_name) { - auto as_set = dynamic_cast(ir); - return as_set && is_reg(as_set->dst.get(), dst) && is_sym_value(as_set->src.get(), sym_name); -} - -bool is_get_sym(IR* ir, Register dst, const std::string& sym_name) { - auto as_set = dynamic_cast(ir); - return as_set && is_reg(as_set->dst.get(), dst) && is_sym(as_set->src.get(), sym_name); -} - -bool is_label(IR* ir) { - return dynamic_cast(ir); -} - -bool is_get_label(IR* ir, Register dst) { - auto as_set = dynamic_cast(ir); - return as_set && is_reg(as_set->dst.get(), dst) && is_label(as_set->src.get()); -} - -int get_label_id_of_set(IR* ir) { - return dynamic_cast(dynamic_cast(ir)->src.get())->label_id; -} - -bool is_set_shift(IR* ir) { - auto as_set = dynamic_cast(ir); - if (as_set) { - auto as_math = dynamic_cast(as_set->src.get()); - if (as_math && (as_math->kind == IR_IntMath2::LEFT_SHIFT || - as_math->kind == IR_IntMath2::RIGHT_SHIFT_LOGIC || - as_math->kind == IR_IntMath2::RIGHT_SHIFT_ARITH)) { - return true; - } - } - - auto as_asm = dynamic_cast(ir); - return as_asm && as_asm->name == "sllv"; -} - -bool get_ptr_offset_constant_nonzero(IR_IntMath2* math, Register base, int* result) { - if (!is_reg(math->arg0.get(), base)) { - return false; - } - - auto as_int = dynamic_cast(math->arg1.get()); - if (!as_int) { - return false; - } - - *result = as_int->value; - return true; -} - -bool get_ptr_offset_zero(IR_IntMath2* math, Register base, int* result) { - if (!is_reg(math->arg0.get(), make_gpr(Reg::R0)) || !is_reg(math->arg1.get(), base)) { - return false; - } - *result = 0; - return true; -} - -bool get_ptr_offset(IR* ir, Register dst, Register base, int* result) { - auto as_set = dynamic_cast(ir); - if (!as_set) { - return false; - } - - if (!is_reg(as_set->dst.get(), dst)) { - return false; - } - - auto as_math = dynamic_cast(as_set->src.get()); - if (!as_math) { - return false; - } - return get_ptr_offset_constant_nonzero(as_math, base, result) || - get_ptr_offset_zero(as_math, base, result); -} - -int get_start_idx(Function& function, - LinkedObjectFile& file, - TypeInspectorResult* result, - const std::string& parent_type) { - if (function.basic_blocks.size() > 1) { - result->warnings += " too many basic blocks"; - return 0; - } - - /* - ;; for a basic - or gp, a0, r0 ;; (set! gp a0) - lw t9, format(s7) ;; (set! t9 format) - daddiu a0, s7, #t ;; (set! a0 '#t) - daddiu a1, fp, L362 ;; (set! a1 L362) "[~8x] ~A~%" - or a2, gp, r0 ;; (set! a2 gp) - lwu a3, -4(gp) ;; (set! a3 (l.wu (+.i gp -4))) - jalr ra, t9 ;; (call!) - sll v0, ra, 0 - ;; for a struct - or gp, a0, r0 ;; (set! gp a0) - lw t9, format(s7) ;; (set! t9 format) - daddiu a0, s7, #t ;; (set! a0 '#t) - daddiu a1, fp, L79 ;; (set! a1 L79) "[~8x] ~A~%" - or a2, gp, r0 ;; (set! a2 gp) - daddiu a3, s7, dead-pool-heap-rec;; (set! a3 'dead-pool-heap-rec) - jalr ra, t9 ;; (call!) - */ - - // check size - if (function.basic_ops.size() < 7) { - result->warnings += " not enough basic ops"; - return 0; - } - - auto& move_op = function.basic_ops.at(0); - if (!is_reg_reg_move(move_op.get(), make_gpr(Reg::GP), make_gpr(Reg::A0))) { - result->warnings += "bad first move"; - return 0; - } - - auto& get_format_op = function.basic_ops.at(1); - - if (is_get_sym_value(get_format_op.get(), make_gpr(Reg::T9), "format")) { - auto& get_true = function.basic_ops.at(2); - if (!is_get_sym(get_true.get(), make_gpr(Reg::A0), "#t")) { - result->warnings += "bad get true"; - return 0; - } - - auto& get_str = function.basic_ops.at(3); - if (!is_get_label(get_str.get(), make_gpr(Reg::A1))) { - result->warnings += "bad get label"; - return 0; - } - - auto str = file.get_goal_string_by_label(file.labels.at(get_label_id_of_set(get_str.get()))); - if (str != "[~8x] ~A~%") { - result->warnings += "bad type dec string: " + str; - return 0; - } - - auto& move2_op = function.basic_ops.at(4); - if (!is_reg_reg_move(move2_op.get(), make_gpr(Reg::A2), make_gpr(Reg::GP))) { - result->warnings += "bad second move"; - return 0; - } - - auto& load_op = function.basic_ops.at(5); - bool is_basic_load = is_get_load_with_offset(load_op.get(), make_gpr(Reg::A3), - IR_Load::UNSIGNED, 4, make_gpr(Reg::GP), -4); - result->is_basic = is_basic_load; - - bool is_struct_load = is_get_sym(load_op.get(), make_gpr(Reg::A3), function.method_of_type); - - if (!is_basic_load && !is_struct_load) { - result->warnings += "bad load"; - return 0; - } - - auto& call = function.basic_ops.at(6); - if (!dynamic_cast(call.get())) { - result->warnings += "bad call"; - return 0; - } - - // okay! - return 7; - } else { - if (is_get_sym_value(get_format_op.get(), make_gpr(Reg::V1), parent_type)) { - // now get the inspect method. - auto& get_method_op = function.basic_ops.at(2); - if (!is_get_load_with_offset(get_method_op.get(), make_gpr(Reg::T9), IR_Load::UNSIGNED, 4, - make_gpr(Reg::V1), 28)) { - result->warnings += "bad get method op " + get_method_op->print(file); - return 0; - } - - auto& move2_op = function.basic_ops.at(3); - if (!is_reg_reg_move(move2_op.get(), make_gpr(Reg::A0), make_gpr(Reg::GP))) { - result->warnings += "bad move2 op " + move2_op->print(file); - return 0; - } - - auto& call_op = function.basic_ops.at(4); - if (!dynamic_cast(call_op.get())) { - result->warnings += "bad call op " + call_op->print(file); - return 0; - } - - result->warnings += "inherited inpspect of " + parent_type; - result->is_basic = true; - return 5; - - } else { - result->warnings += - "unrecognized get op: " + get_format_op->print(file) + " parent was " + parent_type; - return 0; - } - } -} - -int identify_basic_field(int idx, - Function& function, - LinkedObjectFile& file, - TypeInspectorResult* result, - FieldPrint& print_info) { - (void)file; - auto load_info = get_load_info_from_set(function.basic_ops.at(idx++).get()); - ASSERT(load_info.size == 4); - ASSERT(load_info.kind == IR_Load::UNSIGNED || load_info.kind == IR_Load::SIGNED); - - if (load_info.kind == IR_Load::SIGNED) { - result->warnings += "field " + print_info.field_name + " is a basic loaded with a signed load "; - } - - int offset = load_info.offset; - if (result->is_basic) { - offset += BASIC_OFFSET; - } - - Field field(print_info.field_name, TypeSpec("basic"), offset); - result->fields_of_type.push_back(field); - return idx; -} - -int identify_pointer_field(int idx, - Function& function, - LinkedObjectFile& file, - TypeInspectorResult* result, - FieldPrint& print_info) { - (void)file; - auto load_info = get_load_info_from_set(function.basic_ops.at(idx++).get()); - ASSERT(load_info.size == 4); - ASSERT(load_info.kind == IR_Load::UNSIGNED); - - int offset = load_info.offset; - if (result->is_basic) { - offset += BASIC_OFFSET; - } - - Field field(print_info.field_name, TypeSpec("pointer"), offset); - result->fields_of_type.push_back(field); - return idx; -} - -int identify_array_field(int idx, - Function& function, - LinkedObjectFile& file, - TypeInspectorResult* result, - FieldPrint& print_info) { - auto& get_op = function.basic_ops.at(idx++); - int offset = 0; - if (!get_ptr_offset(get_op.get(), make_gpr(Reg::A2), make_gpr(Reg::GP), &offset)) { - printf("bad get ptr offset %s\n", get_op->print(file).c_str()); - ASSERT(false); - } - if (result->is_basic) { - offset += BASIC_OFFSET; - } - - Field field(print_info.field_name, TypeSpec("UNKNOWN"), offset); - if (print_info.array_size) { - field.set_array(print_info.array_size); - } else { - field.set_dynamic(); - } - result->fields_of_type.push_back(field); - return idx; -} - -int identify_float_field(int idx, - Function& function, - LinkedObjectFile& file, - TypeInspectorResult* result, - FieldPrint& print_info) { - auto load_info = get_load_info_from_set(function.basic_ops.at(idx++).get()); - ASSERT(load_info.size == 4); - ASSERT(load_info.kind == IR_Load::FLOAT); - - auto& float_move = function.basic_ops.at(idx++); - if (!is_reg_reg_move(float_move.get(), make_gpr(Reg::A2), make_fpr(0))) { - printf("bad float move: %s\n", float_move->print(file).c_str()); - ASSERT(false); - } - - std::string type; - switch (print_info.format) { - case 'f': - type = "float"; - break; - case 'm': - type = "meters"; - break; - case 'r': - type = "deg"; - break; - case 'X': - type = "float"; - result->warnings += "field " + print_info.field_name + " is a float printed as hex? "; - break; - default: - ASSERT(false); - } - int offset = load_info.offset; - if (result->is_basic) { - offset += BASIC_OFFSET; - } - - Field field(print_info.field_name, TypeSpec(type), offset); - result->fields_of_type.push_back(field); - return idx; -} - -int identify_struct_not_inline_field(int idx, - Function& function, - LinkedObjectFile& file, - TypeInspectorResult* result, - FieldPrint& print_info) { - (void)file; - auto load_info = get_load_info_from_set(function.basic_ops.at(idx++).get()); - - if (!(load_info.size == 4 && load_info.kind == IR_Load::UNSIGNED)) { - result->warnings += "field " + print_info.field_type_name + " is likely a value type"; - } - int offset = load_info.offset; - if (result->is_basic) { - offset += BASIC_OFFSET; - } - - Field field(print_info.field_name, TypeSpec(print_info.field_type_name), offset); - result->fields_of_type.push_back(field); - return idx; -} - -int identify_struct_inline_field(int idx, - Function& function, - LinkedObjectFile& file, - TypeInspectorResult* result, - FieldPrint& print_info) { - auto& get_op = function.basic_ops.at(idx++); - int offset = 0; - if (!get_ptr_offset(get_op.get(), make_gpr(Reg::A2), make_gpr(Reg::GP), &offset)) { - printf("bad get ptr offset %s\n", get_op->print(file).c_str()); - ASSERT(false); - } - if (result->is_basic) { - offset += BASIC_OFFSET; - } - - Field field(print_info.field_name, TypeSpec(print_info.field_type_name), offset); - field.set_inline(); - result->fields_of_type.push_back(field); - return idx; -} - -int identify_int_field(int idx, - Function& function, - LinkedObjectFile& file, - TypeInspectorResult* result, - FieldPrint& print_info) { - (void)file; - auto load_info = get_load_info_from_set(function.basic_ops.at(idx++).get()); - - std::string field_type_name; - if (load_info.kind == IR_Load::UNSIGNED) { - field_type_name += "u"; - } else if (load_info.kind == IR_Load::FLOAT) { - ASSERT(false); // ... - } - field_type_name += "int"; - - switch (load_info.size) { - case 1: - field_type_name += "8"; - break; - case 2: - field_type_name += "16"; - break; - case 4: - field_type_name += "32"; - break; - case 8: - field_type_name += "64"; - break; - case 16: - field_type_name += "128"; - break; - default: - throw std::runtime_error("unknown load op size in identify int field " + - std::to_string((int)load_info.size)); - } - - if (print_info.format == 'e') { - switch (load_info.kind) { - case IR_Load::SIGNED: - field_type_name = "sseconds"; - break; - case IR_Load::UNSIGNED: - field_type_name = "useconds"; - break; - default: - ASSERT(false); - } - ASSERT(load_info.size == 8); - } - - int offset = load_info.offset; - if (result->is_basic) { - offset += BASIC_OFFSET; - } - - Field field(print_info.field_name, TypeSpec(field_type_name), offset); - result->fields_of_type.push_back(field); - - return idx; -} - -int detect(int idx, Function& function, LinkedObjectFile& file, TypeInspectorResult* result) { - auto& get_format_op = function.basic_ops.at(idx++); - if (!is_get_sym_value(get_format_op.get(), make_gpr(Reg::T9), "format")) { - printf("bad get format"); - ASSERT(false); - } - - auto& get_true = function.basic_ops.at(idx++); - if (!is_get_sym(get_true.get(), make_gpr(Reg::A0), "#t")) { - printf("bad get true"); - ASSERT(false); - } - - auto& get_str = function.basic_ops.at(idx++); - if (!is_get_label(get_str.get(), make_gpr(Reg::A1))) { - result->warnings += "bad get label"; - return true; - } - - auto str = file.get_goal_string_by_label(file.labels.at(get_label_id_of_set(get_str.get()))); - auto info = get_field_print(str); - - auto& first_get_op = function.basic_ops.at(idx); - - if (is_get_load(first_get_op.get(), make_gpr(Reg::A2), make_gpr(Reg::GP)) && - (info.format == 'D' || info.format == 'X' || info.format == 'e') && !info.has_array && - info.field_type_name.empty()) { - idx = identify_int_field(idx, function, file, result, info); - // it's a load! - } else if (is_get_load(first_get_op.get(), make_fpr(0), make_gpr(Reg::GP)) && - (info.format == 'f' || info.format == 'm' || info.format == 'r' || - info.format == 'X') && - !info.has_array && info.field_type_name.empty()) { - idx = identify_float_field(idx, function, file, result, info); - } else if (is_get_load(first_get_op.get(), make_gpr(Reg::A2), make_gpr(Reg::GP)) && - info.format == 'A' && !info.has_array && info.field_type_name.empty()) { - idx = identify_basic_field(idx, function, file, result, info); - } else if (is_get_load(first_get_op.get(), make_gpr(Reg::A2), make_gpr(Reg::GP)) && - info.format == 'X' && !info.has_array && info.field_type_name.empty()) { - idx = identify_pointer_field(idx, function, file, result, info); - } else if (info.has_array && (info.format == 'X' || info.format == 'P') && - info.field_type_name.empty()) { - idx = identify_array_field(idx, function, file, result, info); - } else if (!info.has_array && (info.format == 'X' || info.format == 'P') && - !info.field_type_name.empty()) { - // structure. - if (is_get_load(first_get_op.get(), make_gpr(Reg::A2), make_gpr(Reg::GP))) { - // not inline - idx = identify_struct_not_inline_field(idx, function, file, result, info); - } else { - idx = identify_struct_inline_field(idx, function, file, result, info); - } - } - - else if (is_set_shift(first_get_op.get())) { - result->warnings += "likely a bitfield type"; - return -1; - } else { - printf("couldn't do %s, %s\n", str.c_str(), first_get_op->print(file).c_str()); - return -1; - } - - auto& call_op = function.basic_ops.at(idx++); - if (!dynamic_cast(call_op.get())) { - printf("bad call\n"); - ASSERT(false); - } - - return idx; -} -} // namespace - -TypeInspectorResult inspect_inspect_method(Function& inspect, - const std::string& type_name, - DecompilerTypeSystem& dts, - LinkedObjectFile& file, - bool skip_fields) { - TypeInspectorResult result; - TypeFlags flags; - flags.flag = 0; - dts.lookup_flags(type_name, &flags.flag); - result.type_name = type_name; - result.parent_type_name = dts.lookup_parent_from_inspects(type_name); - result.flags = flags.flag; - result.type_size = flags.size; - result.type_method_count = flags.methods; - result.type_heap_base = flags.heap_base; - ASSERT(flags.pad == 0); - - int idx = get_start_idx(inspect, file, &result, result.parent_type_name); - if (idx == 0 || skip_fields) { - // printf("was weird: %s\n", result.warnings.c_str()); - return result; - } - while (idx < int(inspect.basic_ops.size()) - 1 && idx != -1) { - idx = detect(idx, inspect, file, &result); - } - - // todo, continue to identify fields, then identify the return. - - result.success = true; - return result; -} - -std::string TypeInspectorResult::print_as_deftype() { - std::string result; - - result += fmt::format("(deftype {} ({})\n (", type_name, parent_type_name); - - int longest_field_name = 0; - int longest_type_name = 0; - int longest_mods = 0; - - std::string inline_string = ":inline"; - std::string dynamic_string = ":dynamic"; - - for (auto& field : fields_of_type) { - longest_field_name = std::max(longest_field_name, int(field.name().size())); - longest_type_name = std::max(longest_type_name, int(field.type().print().size())); - - int mods = 0; - // mods are array size, :inline, :dynamic - if (field.is_array() && !field.is_dynamic()) { - mods += std::to_string(field.array_size()).size(); - } - - if (field.is_inline()) { - if (mods) { - mods++; // space - } - mods += inline_string.size(); - } - - if (field.is_dynamic()) { - if (mods) { - mods++; // space - } - mods += dynamic_string.size(); - } - longest_mods = std::max(longest_mods, mods); - } - - for (auto& field : fields_of_type) { - result += "("; - result += field.name(); - result.append(1 + (longest_field_name - int(field.name().size())), ' '); - result += field.type().print(); - result.append(1 + (longest_type_name - int(field.type().print().size())), ' '); - - std::string mods; - if (field.is_array() && !field.is_dynamic()) { - mods += std::to_string(field.array_size()); - mods += " "; - } - - if (field.is_inline()) { - mods += inline_string; - mods += " "; - } - - if (field.is_dynamic()) { - mods += dynamic_string; - mods += " "; - } - result.append(mods); - result.append(longest_mods - int(mods.size() - 1), ' '); - - result.append(":offset-assert "); - result.append(std::to_string(field.offset())); - result.append(")\n "); - } - result.append(")\n"); - - result.append(fmt::format(" :method-count-assert {}\n", type_method_count)); - result.append(fmt::format(" :size-assert #x{:x}\n", type_size)); - result.append(fmt::format(" :flag-assert #x{:x}\n ", flags)); - if (!warnings.empty()) { - result.append(";; "); - result.append(warnings); - result.append("\n "); - } - - if (type_method_count > 9) { - result.append("(:methods\n "); - for (int i = 9; i < type_method_count; i++) { - result.append(fmt::format("(dummy-{} () none {})\n ", i, i)); - } - result.append(")\n "); - } - result.append(")\n"); - - return result; -} -} // namespace decompiler \ No newline at end of file diff --git a/decompiler/Function/TypeInspector.h b/decompiler/Function/TypeInspector.h deleted file mode 100644 index cb3bd3c855..0000000000 --- a/decompiler/Function/TypeInspector.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -/*! - * @file TypeInspector.h - * Analyze an auto-generated GOAL inspect method to determine the layout of a type in memory. - */ - -#include -#include "common/common_types.h" - -class Field; - -namespace decompiler { -class Function; -class DecompilerTypeSystem; -class LinkedObjectFile; - -struct TypeInspectorResult { - bool success = false; - int type_size = -1; - int type_method_count = -1; - int type_heap_base = -1; - - std::string warnings; - std::vector fields_of_type; - bool is_basic = false; - - std::string type_name; - std::string parent_type_name; - u64 flags = 0; - - std::string print_as_deftype(); -}; - -TypeInspectorResult inspect_inspect_method(Function& inspect, - const std::string& type_name, - DecompilerTypeSystem& dts, - LinkedObjectFile& file, - bool skip_fields); -} // namespace decompiler \ No newline at end of file diff --git a/decompiler/IR/BasicOpBuilder.cpp b/decompiler/IR/BasicOpBuilder.cpp deleted file mode 100644 index 3fec5e6f1a..0000000000 --- a/decompiler/IR/BasicOpBuilder.cpp +++ /dev/null @@ -1,2549 +0,0 @@ -/*! - * @file BasicOpBuilder.cpp - * Convert a basic block into a sequence of IR operations. - * Build up basic set instructions from GOAL code - * Recognize common GOAL compiler idioms - * Recognize branch delay slot use - * Recognize assembly ops and pass them through as IR_Asm - */ - -#include "BasicOpBuilder.h" -#include "decompiler/Function/Function.h" -#include "decompiler/Function/BasicBlocks.h" -#include "decompiler/Disasm/InstructionMatching.h" -#include "decompiler/ObjectFile/LinkedObjectFile.h" -#include "decompiler/IR/IR.h" -#include "common/symbols.h" - -namespace decompiler { -namespace { - -/////////////////////////////// -// Helpers -/////////////////////////////// - -/*! - * Create a GOAL "set!" form. - * These will later be compacted into more complicated nested expressions. - */ -std::shared_ptr make_set_atomic(IR_Set_Atomic::Kind kind, - const std::shared_ptr& dst, - const std::shared_ptr& src) { - return std::make_shared(kind, dst, src); -} - -/*! - * Create an IR representing a register at a certain point. Idx is the instruction index. - */ -std::shared_ptr make_reg(Register reg, int idx) { - return std::make_shared(reg, idx); -} - -/*! - * Create an IR representing a symbol. The symbol itself ('thing), not the value. - */ -std::shared_ptr make_sym(const std::string& name) { - return std::make_shared(name); -} - -/*! - * Create an IR representing the value of a symbol. Can be read/written. - */ -std::shared_ptr make_sym_value(const std::string& name) { - return std::make_shared(name); -} - -/*! - * Create an integer constant. - */ -std::shared_ptr make_int(int64_t x) { - return std::make_shared(x); -} - -/*! - * 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. 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. Sets register info. - */ -std::shared_ptr to_asm_dst_reg_src_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->set_reg_info(); - return result; -} - -/*! - * Convert an instruction atom to IR. - */ -std::shared_ptr instr_atom_to_ir(const InstructionAtom& ia, int idx) { - switch (ia.kind) { - case InstructionAtom::REGISTER: - return make_reg(ia.get_reg(), idx); - case InstructionAtom::VU_Q: - return std::make_shared(IR_AsmReg::VU_Q); - case InstructionAtom::VU_ACC: - return std::make_shared(IR_AsmReg::VU_ACC); - case InstructionAtom::IMM: - return make_int(ia.get_imm()); - case InstructionAtom::VF_FIELD: - // not supported by IR1 - return std::make_shared(); - default: - ASSERT(false); - return nullptr; - } -} - -/////////////////////////////// -// 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); - if (instr.n_src >= 4) { - // not supported by IR1 - return std::make_shared(); - } - ASSERT(instr.n_dst < 2); - ASSERT(instr.n_src < 4); - if (instr.n_dst >= 1) { - result->dst = instr_atom_to_ir(instr.get_dst(0), idx); - } - - if (instr.n_src >= 1) { - result->src0 = instr_atom_to_ir(instr.get_src(0), idx); - } - - if (instr.n_src >= 2) { - result->src1 = instr_atom_to_ir(instr.get_src(1), idx); - } - - if (instr.n_src >= 3) { - result->src2 = 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); - } - 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); - } - 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))) { - // 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), make_gpr(Reg::R0))) { - auto dest = instr.get_dst(0).get_reg(); - auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dest, idx), - std::make_shared(0)); - 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))) { - // 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 { - // 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()) { - // 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()) { - // 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))) { - // 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) { - 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) { - 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))) { - // 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) { - // 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()) { - // 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; -} - -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))) { - // 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) { - // 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()) { - // 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; -} - -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))) { - // 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) { - // 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()) { - // 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; -} - -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))) { - // 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) { - // 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()) { - // 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; -} - -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))) { - // 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) { - // 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()) { - // 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; -} - -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))) { - // 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) { - // 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()) { - // 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_dst(0).is_reg(make_gpr(Reg::R0)) && - instr.get_src(0).is_imm() && instr.get_src(0).get_imm() == 2 && - instr.get_src(1).is_reg(make_gpr(Reg::R0))) { - auto op = std::make_shared(); - op->reg_info_set = true; - return op; - } else if (instr.kind == InstructionKind::LW && instr.get_src(1).is_reg(make_gpr(Reg::S7)) && - instr.get_src(0).kind == InstructionAtom::IMM_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))) { - // 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) { - // 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()) { - // 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::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; -} - -std::shared_ptr try_lq(Instruction& instr, int idx) { - if (instr.kind == InstructionKind::LQ && instr.get_src(1).is_reg(make_gpr(Reg::S7)) && - instr.get_src(0).kind == InstructionAtom::IMM_SYM) { - 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))) { - // 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) { - // 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()) { - // 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::S7)) && - instr.get_src(1).is_imm() && instr.get_src(1).get_imm() == -10) { - auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared()); - 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::S7)) && - instr.get_src(1).is_imm() && instr.get_src(1).get_imm() == -32768) { - auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared("__START-OF-TABLE__")); - 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::S7)) && - instr.get_src(1).is_imm() && instr.get_src(1).get_imm() == FIX_SYM_TRUE) { - auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(instr.get_dst(0).get_reg(), idx), - std::make_shared("#t")); - 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; -} - -std::shared_ptr try_daddu(Instruction& instr, int idx) { - if (is_gpr_3(instr, InstructionKind::DADDU, {}, make_gpr(Reg::R0), {})) { - 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(1).get_reg(), idx), - std::make_shared(0))); - op->update_reginfo_self(1, 1, 0); - return op; - } else 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))) { - 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); -} - -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))) { - 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))) { - 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; -} - -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))) { - 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; -} - -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))) { - 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; -} - -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))) { - 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) { - 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) { - 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; -} - -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))) { - 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))) { - 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; -} - -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))) { - 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))) { - 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()) { - 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; -} - -std::shared_ptr try_sll(Instruction& instr, int idx) { - (void)idx; - if (is_nop(instr)) { - auto op = std::make_shared(); - op->reg_info_set = true; - return op; - } - return nullptr; -} - -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))) { - 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; -} - -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))) { - 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; -} - -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))) { - 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; -} - -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))) { - 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()) { - if (instr.get_src(1).get_imm() == 0) { - auto op = std::make_shared(IR_Store_Atomic::Kind::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 { - if (instr.get_src(0).is_reg(make_gpr(Reg::S7))) { - // store false - auto op = std::make_shared( - IR_Store_Atomic::Kind::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_sym("#f"), 4); - op->update_reginfo_self(0, 1, 0); - return op; - } else { - auto op = std::make_shared( - IR_Store_Atomic::Kind::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()) { - if (instr.get_src(1).get_imm() == 0) { - if (instr.get_src(0).is_reg(make_gpr(Reg::R0))) { - auto op = std::make_shared(IR_Store_Atomic::Kind::INTEGER, - make_reg(instr.get_src(2).get_reg(), idx), - std::make_shared(0), 1); - op->update_reginfo_self(0, 1, 0); - return op; - } else { - auto op = std::make_shared(IR_Store_Atomic::Kind::INTEGER, - make_reg(instr.get_src(2).get_reg(), idx), - make_reg(instr.get_src(0).get_reg(), idx), 1); - op->update_reginfo_self(0, 2, 0); - return op; - } - - } else { - if (instr.get_src(0).is_reg(make_gpr(Reg::R0))) { - auto op = std::make_shared( - IR_Store_Atomic::Kind::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())), - std::make_shared(0), 1); - op->update_reginfo_self(0, 1, 0); - return op; - } else { - auto op = std::make_shared( - IR_Store_Atomic::Kind::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()) { - auto op = std::make_shared( - IR_Store_Atomic::Kind::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()) { - auto op = std::make_shared( - IR_Store_Atomic::Kind::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()) { - auto op = std::make_shared( - IR_Store_Atomic::Kind::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()) { - auto op = std::make_shared( - IR_Store_Atomic::Kind::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) { - 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) { - 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; -} - -std::shared_ptr try_float_math_1(Instruction& instr, - int idx, - InstructionKind ikind, - IR_FloatMath1::Kind irkind) { - if (instr.kind == ikind) { - 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) { - 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), {})) { - 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 op; - } - return nullptr; -} - -std::shared_ptr try_movz(Instruction& instr, int idx) { - if (is_gpr_3(instr, InstructionKind::MOVZ, {}, make_gpr(Reg::S7), {})) { - 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 op; - } - return nullptr; -} - -// TWO Instructions -std::shared_ptr try_div(Instruction& instr, Instruction& next_instr, int idx) { - 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()) { - 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()) { - 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; -} - -std::shared_ptr try_divu(Instruction& instr, Instruction& next_instr, int idx) { - 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()) { - 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()) { - 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; -} - -std::shared_ptr try_jalr(Instruction& instr, Instruction& next_instr, int idx) { - (void)idx; - 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)) { - 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); - 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); - 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); - 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); - 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); - 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); - 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); - 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); - return b; -} - -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))) { - 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))) { - 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) { - 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))) { - 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))) { - 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), - // make_reg(instr.get_src(1).get_reg(), idx), - // get_branch_delay(next_instr, idx), true); - } - return nullptr; -} - -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))) { - 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))) { - 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); - 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; -} - -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))) { - 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))) { - 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 && instr.get_src(1).is_reg(make_gpr(Reg::R0))) { - 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), false); - op->update_reginfo_self(0, 1, 0); - return op; - } else if (instr.kind == InstructionKind::BEQ) { - 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) { - 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) { - 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) { - 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; -} - -std::shared_ptr try_daddiu(Instruction& i0, Instruction& i1, int idx) { - if (i0.kind == InstructionKind::DADDIU && i1.kind == InstructionKind::MOVN && - i0.get_src(0).get_reg() == make_gpr(Reg::S7)) { - auto dst_reg = i0.get_dst(0).get_reg(); - auto src_reg = i1.get_src(1).get_reg(); - ASSERT(i0.get_src(0).get_reg() == make_gpr(Reg::S7)); - 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)); - 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), 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(); - auto src_reg = i1.get_src(1).get_reg(); - ASSERT(i0.get_src(0).get_reg() == make_gpr(Reg::S7)); - 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)); - 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), nullptr)); - op->write_regs.push_back(dst_reg); - op->read_regs.push_back(src_reg); - op->reg_info_set = true; - return op; - } - return nullptr; -} - -std::shared_ptr try_lui(Instruction& i0, Instruction& i1, int idx) { - if (i0.kind == InstructionKind::LUI && i1.kind == InstructionKind::ORI && - i0.get_src(0).is_label() && i1.get_src(1).is_label()) { - ASSERT(i0.get_dst(0).get_reg() == i1.get_src(0).get_reg()); - ASSERT(i0.get_src(0).get_label() == i1.get_src(1).get_label()); - auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(i1.get_dst(0).get_reg(), 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() && - i0.get_dst(0).get_reg() == i1.get_src(0).get_reg()) { - auto op = make_set_atomic( - IR_Set_Atomic::REG_64, make_reg(i1.get_dst(0).get_reg(), 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(); - auto left = i0.get_src(0).get_reg(); - auto right = i0.get_src(1).get_reg(); - if (is_gpr_3(i1, InstructionKind::MOVZ, left, right, temp)) { - // success! - auto result = - make_set_atomic(IR_Set_Atomic::REG_64, make_reg(left, 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(left); - result->reg_info_set = true; - return result; - } - - if (is_gpr_3(i1, InstructionKind::MOVN, left, right, temp)) { - // success! - auto result = - make_set_atomic(IR_Set_Atomic::REG_64, make_reg(left, 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(left); - result->reg_info_set = true; - return result; - } - } - return nullptr; -} - -// THREE OP -std::shared_ptr try_lui(Instruction& i0, Instruction& i1, Instruction& i2, int idx) { - if (i0.kind == InstructionKind::LUI && i1.kind == InstructionKind::ORI && - i0.get_src(0).is_label() && i1.get_src(1).is_label() && - is_gpr_3(i2, InstructionKind::ADDU, {}, make_gpr(Reg::FP), {})) { - ASSERT(i0.get_dst(0).get_reg() == i1.get_src(0).get_reg()); - ASSERT(i0.get_src(0).get_label() == i1.get_src(1).get_label()); - ASSERT(i2.get_dst(0).get_reg() == i2.get_src(1).get_reg()); - ASSERT(i2.get_dst(0).get_reg() == i1.get_dst(0).get_reg()); - auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(i1.get_dst(0).get_reg(), 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; - } - return nullptr; -} - -std::shared_ptr try_dsubu(Instruction& i0, Instruction& i1, Instruction& i2, int idx) { - if (i0.kind == InstructionKind::DSUBU && i1.kind == InstructionKind::DADDIU && - i2.kind == InstructionKind::MOVN) { - // check for equality - 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(); - auto dst_reg = i1.get_dst(0).get_reg(); - ASSERT(i1.get_src(0).get_reg() == make_gpr(Reg::S7)); - ASSERT(i1.get_src(1).get_imm() == 8); - 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); - 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)), - nullptr)); - 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 - 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(); - auto dst_reg = i1.get_dst(0).get_reg(); - ASSERT(i1.get_src(0).get_reg() == make_gpr(Reg::S7)); - ASSERT(i1.get_src(1).get_imm() == 8); - ASSERT(i2.get_dst(0).get_reg() == dst_reg); - ASSERT(i2.get_src(0).get_reg() == make_gpr(Reg::S7)); - if (i2.get_src(1).get_reg() != clobber_reg) { - return nullptr; // TODO! - } - 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)), - nullptr)); - op->update_reginfo_self(1, 2, 1); - return op; - } - return nullptr; -} - -std::shared_ptr try_slt(Instruction& i0, Instruction& i1, Instruction& i2, int idx) { - if (i0.kind == InstructionKind::SLT && i1.kind == InstructionKind::BNE) { - 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)); - 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(); - auto src0_reg = i0.get_src(0).get_reg(); - auto src1_reg = i0.get_src(1).get_reg(); - auto dst_reg = i1.get_dst(0).get_reg(); - ASSERT(i1.get_src(0).is_reg(make_gpr(Reg::S7))); - ASSERT(i1.get_src(1).get_imm() == 8); - ASSERT(i2.get_dst(0).get_reg() == dst_reg); - ASSERT(i2.get_src(0).get_reg() == make_gpr(Reg::S7)); - if (i2.get_src(1).get_reg() != clobber_reg) { - return nullptr; // TODO! - } - if (src1_reg == make_gpr(Reg::R0)) { - auto op = make_set_atomic( - IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), - std::make_shared(Condition(Condition::LESS_THAN_ZERO, make_reg(src0_reg, idx), - nullptr, make_reg(clobber_reg, idx)), - nullptr)); - op->update_reginfo_self(1, 1, 1); - return op; - } else { - 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)), - nullptr)); - 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)); - 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(); - auto src0_reg = i0.get_src(0).get_reg(); - auto src1_reg = i0.get_src(1).get_reg(); - auto dst_reg = i1.get_dst(0).get_reg(); - ASSERT(i1.get_src(0).is_reg(make_gpr(Reg::S7))); - ASSERT(i1.get_src(1).get_imm() == 8); - ASSERT(i2.get_dst(0).get_reg() == dst_reg); - ASSERT(i2.get_src(0).get_reg() == make_gpr(Reg::S7)); - if (i2.get_src(1).get_reg() != clobber_reg) { - return nullptr; // TODO! - } - if (src1_reg == make_gpr(Reg::R0)) { - auto op = make_set_atomic(IR_Set_Atomic::REG_64, make_reg(dst_reg, idx), - std::make_shared( - Condition(Condition::GEQ_ZERO_SIGNED, make_reg(src0_reg, idx), - nullptr, make_reg(clobber_reg, idx)), - nullptr)); - op->update_reginfo_self(1, 1, 1); - return op; - } else { - 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)), - nullptr)); - op->update_reginfo_self(1, 2, 1); - return op; - } - } - return nullptr; -} - -std::shared_ptr try_slti(Instruction& i0, Instruction& i1, Instruction& i2, int idx) { - auto src1 = make_int(i0.get_src(1).get_imm()); - if (i0.kind == InstructionKind::SLTI && i1.kind == InstructionKind::BNE) { - 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)); - 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(); - auto src0_reg = i0.get_src(0).get_reg(); - auto dst_reg = i1.get_dst(0).get_reg(); - ASSERT(i1.get_src(0).is_reg(make_gpr(Reg::S7))); - ASSERT(i1.get_src(1).get_imm() == 8); - ASSERT(i2.get_dst(0).get_reg() == dst_reg); - ASSERT(i2.get_src(0).get_reg() == make_gpr(Reg::S7)); - if (i2.get_src(1).get_reg() != clobber_reg) { - return nullptr; // TODO! - } - 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)), - nullptr)); - 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)); - 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(); - auto src0_reg = i0.get_src(0).get_reg(); - auto dst_reg = i1.get_dst(0).get_reg(); - ASSERT(i1.get_src(0).is_reg(make_gpr(Reg::S7))); - ASSERT(i1.get_src(1).get_imm() == 8); - ASSERT(i2.get_dst(0).get_reg() == dst_reg); - ASSERT(i2.get_src(0).get_reg() == make_gpr(Reg::S7)); - if (i2.get_src(1).get_reg() != clobber_reg) { - return nullptr; // TODO! - } - 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)), - nullptr)); - op->update_reginfo_self(1, 1, 1); - return op; - } - return nullptr; -} - -std::shared_ptr try_sltiu(Instruction& i0, Instruction& i1, Instruction& i2, int idx) { - auto src1 = make_int(i0.get_src(1).get_imm()); - if (i0.kind == InstructionKind::SLTIU && i1.kind == InstructionKind::BNE) { - 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)); - 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(); - auto src0_reg = i0.get_src(0).get_reg(); - auto dst_reg = i1.get_dst(0).get_reg(); - ASSERT(i1.get_src(0).is_reg(make_gpr(Reg::S7))); - ASSERT(i1.get_src(1).get_imm() == 8); - ASSERT(i2.get_dst(0).get_reg() == dst_reg); - ASSERT(i2.get_src(0).get_reg() == make_gpr(Reg::S7)); - if (i2.get_src(1).get_reg() != clobber_reg) { - return nullptr; // TODO! - } - 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)), - nullptr)); - 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)); - 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(); - auto src0_reg = i0.get_src(0).get_reg(); - auto dst_reg = i1.get_dst(0).get_reg(); - ASSERT(i1.get_src(0).is_reg(make_gpr(Reg::S7))); - ASSERT(i1.get_src(1).get_imm() == 8); - ASSERT(i2.get_dst(0).get_reg() == dst_reg); - ASSERT(i2.get_src(0).get_reg() == make_gpr(Reg::S7)); - if (i2.get_src(1).get_reg() != clobber_reg) { - return nullptr; // TODO! - } - 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)), - nullptr)); - 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) { - 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) { - 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) { - 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) { - 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) { - 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) { - 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; -} - -std::shared_ptr try_sltu(Instruction& i0, Instruction& i1, Instruction& i2, int idx) { - if (i0.kind == InstructionKind::SLTU && i1.kind == InstructionKind::BNE) { - 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)); - 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(); - auto src0_reg = i0.get_src(0).get_reg(); - auto src1_reg = i0.get_src(1).get_reg(); - auto dst_reg = i1.get_dst(0).get_reg(); - ASSERT(i1.get_src(0).is_reg(make_gpr(Reg::S7))); - ASSERT(i1.get_src(1).get_imm() == 8); - ASSERT(i2.get_dst(0).get_reg() == dst_reg); - ASSERT(i2.get_src(0).get_reg() == make_gpr(Reg::S7)); - if (i2.get_src(1).get_reg() != clobber_reg) { - return nullptr; // TODO! - } - 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)), - nullptr)); - 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)); - 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(); - auto src0_reg = i0.get_src(0).get_reg(); - auto src1_reg = i0.get_src(1).get_reg(); - auto dst_reg = i1.get_dst(0).get_reg(); - ASSERT(i1.get_src(0).is_reg(make_gpr(Reg::S7))); - ASSERT(i1.get_src(1).get_imm() == 8); - ASSERT(i2.get_dst(0).get_reg() == dst_reg); - ASSERT(i2.get_src(0).get_reg() == make_gpr(Reg::S7)); - if (i2.get_src(1).get_reg() != clobber_reg) { - return nullptr; // TODO! - } - 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)), - nullptr)); - op->update_reginfo_self(1, 2, 1); - return op; - } - return nullptr; -} - -// five op -std::shared_ptr try_lwu(Instruction& i0, - Instruction& i1, - Instruction& i2, - Instruction& i3, - Instruction& i4, - int idx) { - (void)idx; - auto s6 = make_gpr(Reg::S6); - if (i0.kind == InstructionKind::LWU && i0.get_dst(0).is_reg(s6) && - i0.get_src(0).get_imm() == 44 && i0.get_src(1).is_reg(s6) && - i1.kind == InstructionKind::MTLO1 && i1.get_src(0).is_reg(s6) && - i2.kind == InstructionKind::LWU && i2.get_dst(0).is_reg(s6) && - 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)) { - auto op = std::make_shared(); - op->reg_info_set = true; - return op; - } - return nullptr; -} - -} // namespace - -void add_basic_ops_to_block(Function* func, const BasicBlock& block, LinkedObjectFile* file) { - (void)file; - for (int instr = block.start_word; instr < block.end_word; instr++) { - auto& i = func->instructions.at(instr); - - int length = 0; - - std::shared_ptr result = nullptr; - if (instr + 4 < block.end_word) { - auto& i1 = func->instructions.at(instr + 1); - auto& i2 = func->instructions.at(instr + 2); - auto& i3 = func->instructions.at(instr + 3); - auto& i4 = func->instructions.at(instr + 4); - switch (i.kind) { - case InstructionKind::LWU: - result = try_lwu(i, i1, i2, i3, i4, instr); - break; - default: - result = nullptr; - } - if (result) { - length = 5; - } - } - - if (!result && instr + 2 < block.end_word) { - auto& next = func->instructions.at(instr + 1); - auto& next_next = func->instructions.at(instr + 2); - switch (i.kind) { - case InstructionKind::DSUBU: - result = try_dsubu(i, next, next_next, instr); - break; - case InstructionKind::SLT: - result = try_slt(i, next, next_next, instr); - break; - case InstructionKind::SLTI: - result = try_slti(i, next, next_next, instr); - break; - case InstructionKind::SLTU: - result = try_sltu(i, next, next_next, instr); - break; - case InstructionKind::SLTIU: - result = try_sltiu(i, next, next_next, instr); - break; - case InstructionKind::CEQS: - result = try_ceqs(i, next, next_next, instr); - break; - case InstructionKind::CLTS: - result = try_clts(i, next, next_next, instr); - break; - case InstructionKind::CLES: - result = try_cles(i, next, next_next, instr); - break; - case InstructionKind::LUI: - result = try_lui(i, next, next_next, instr); - break; - default: - result = nullptr; - } - - if (result) { - length = 3; - } - } - - if (!result && instr + 1 < block.end_word) { - auto& next = func->instructions.at(instr + 1); - // single op failed, try double - switch (i.kind) { - case InstructionKind::DIV: - result = try_div(i, next, instr); - break; - case InstructionKind::DIVU: - result = try_divu(i, next, instr); - break; - case InstructionKind::JALR: - result = try_jalr(i, next, instr); - break; - case InstructionKind::BNE: - result = try_bne(i, next, instr); - break; - case InstructionKind::BNEL: - result = try_bnel(i, next, instr); - break; - case InstructionKind::BEQ: - result = try_beq(i, next, instr); - break; - case InstructionKind::BGTZL: - result = try_bgtzl(i, next, instr); - break; - case InstructionKind::BGEZL: - result = try_bgezl(i, next, instr); - break; - case InstructionKind::BLTZL: - result = try_bltzl(i, next, instr); - break; - case InstructionKind::BEQL: - result = try_beql(i, next, instr); - break; - case InstructionKind::DADDIU: - result = try_daddiu(i, next, instr); - break; - case InstructionKind::LUI: - result = try_lui(i, next, instr); - break; - case InstructionKind::SLT: - result = try_slt(i, next, instr); - break; - default: - result = nullptr; - } - - if (result) { - length = 2; - } - } - - if (!result) { - switch (i.kind) { - case InstructionKind::OR: - result = try_or(i, instr); - break; - case InstructionKind::ORI: - result = try_ori(i, instr); - break; - case InstructionKind::DADDIU: - result = try_daddiu(i, instr); - break; - case InstructionKind::AND: - result = try_and(i, instr); - break; - case InstructionKind::ANDI: - result = try_andi(i, instr); - break; - case InstructionKind::XORI: - result = try_xori(i, instr); - break; - case InstructionKind::NOR: - result = try_nor(i, instr); - break; - case InstructionKind::XOR: - result = try_xor(i, instr); - break; - case InstructionKind::LWC1: - result = try_lwc1(i, instr); - break; - case InstructionKind::MTC1: - result = try_mtc1(i, instr); - break; - case InstructionKind::DIVS: - result = try_float_math_2(i, instr, InstructionKind::DIVS, IR_FloatMath2::DIV); - break; - case InstructionKind::SUBS: - result = try_float_math_2(i, instr, InstructionKind::SUBS, IR_FloatMath2::SUB); - break; - case InstructionKind::ADDS: - result = try_float_math_2(i, instr, InstructionKind::ADDS, IR_FloatMath2::ADD); - break; - case InstructionKind::MULS: - result = try_float_math_2(i, instr, InstructionKind::MULS, IR_FloatMath2::MUL); - break; - case InstructionKind::ABSS: - result = try_float_math_1(i, instr, InstructionKind::ABSS, IR_FloatMath1::ABS); - break; - case InstructionKind::NEGS: - result = try_float_math_1(i, instr, InstructionKind::NEGS, IR_FloatMath1::NEG); - break; - case InstructionKind::SQRTS: - result = try_float_math_1(i, instr, InstructionKind::SQRTS, IR_FloatMath1::SQRT); - break; - case InstructionKind::MINS: - result = try_float_math_2(i, instr, InstructionKind::MINS, IR_FloatMath2::MIN); - break; - case InstructionKind::MAXS: - result = try_float_math_2(i, instr, InstructionKind::MAXS, IR_FloatMath2::MAX); - break; - case InstructionKind::MOVS: - result = try_movs(i, instr); - break; - case InstructionKind::MFC1: - result = try_mfc1(i, instr); - break; - case InstructionKind::DADDU: - result = try_daddu(i, instr); - break; - case InstructionKind::DSUBU: - result = try_dsubu(i, instr); - if (!result) { - // fails if it uses s7 register. - result = to_asm_automatic(i.op_name_to_string(), i, instr); - } - break; - case InstructionKind::MULT3: - result = try_mult3(i, instr); - break; - case InstructionKind::MULTU3: - result = try_multu3(i, instr); - break; - case InstructionKind::POR: - result = try_por(i, instr); - if (!result) { - result = to_asm_automatic(i.op_name_to_string(), i, instr); - } - break; - case InstructionKind::LBU: - result = try_lbu(i, instr); - break; - case InstructionKind::LHU: - result = try_lhu(i, instr); - break; - case InstructionKind::LB: - result = try_lb(i, instr); - break; - case InstructionKind::LH: - result = try_lh(i, instr); - break; - case InstructionKind::LW: - result = try_lw(i, instr); - break; - case InstructionKind::LWU: - result = try_lwu(i, instr); - break; - case InstructionKind::LD: - result = try_ld(i, instr); - break; - case InstructionKind::LQ: - result = try_lq(i, instr); - break; - case InstructionKind::DSRA: - result = try_dsra(i, instr); - break; - case InstructionKind::DSRA32: - result = try_dsra32(i, instr); - break; - case InstructionKind::DSRL: - result = try_dsrl(i, instr); - break; - case InstructionKind::DSRL32: - result = try_dsrl32(i, instr); - break; - case InstructionKind::DSLL: - result = try_dsll(i, instr); - break; - case InstructionKind::DSLL32: - result = try_dsll32(i, instr); - break; - case InstructionKind::ADDIU: - result = try_addiu(i, instr); - if (!result) { - result = to_asm_automatic(i.op_name_to_string(), i, instr); - } - break; - case InstructionKind::LUI: - result = try_lui(i, instr); - break; - case InstructionKind::SLL: - result = try_sll(i, instr); - if (!result) { - result = to_asm_automatic(i.op_name_to_string(), i, instr); - } - break; - case InstructionKind::SB: - result = try_sb(i, instr); - break; - case InstructionKind::SH: - result = try_sh(i, instr); - break; - case InstructionKind::SW: - result = try_sw(i, instr); - break; - case InstructionKind::SD: - result = try_sd(i, instr); - break; - case InstructionKind::SQ: - result = try_sq(i, instr); - break; - case InstructionKind::SWC1: - result = try_swc1(i, instr); - break; - case InstructionKind::CVTWS: - result = try_cvtws(i, instr); - break; - case InstructionKind::CVTSW: - result = try_cvtsw(i, instr); - break; - case InstructionKind::DSRAV: - result = try_dsrav(i, instr); - break; - case InstructionKind::DSRLV: - result = try_dsrlv(i, instr); - break; - case InstructionKind::DSLLV: - result = try_dsllv(i, instr); - break; - case InstructionKind::SUBU: - result = try_subu(i, instr); - break; - case InstructionKind::SLLV: - result = try_sllv(i, instr); - break; - case InstructionKind::MOVN: - result = try_movn(i, instr); - if (!result) { - result = to_asm_automatic(i.op_name_to_string(), i, instr); - } - break; - case InstructionKind::MOVZ: - result = try_movz(i, instr); - if (!result) { - result = to_asm_automatic(i.op_name_to_string(), i, instr); - } - break; - - // Everything below here is an "asm passthrough". - case InstructionKind::JR: - result = to_asm_src_reg("jr", i, instr); - break; - - // reg reg - case InstructionKind::QMFC2: - result = to_asm_dst_reg_src_reg(i.op_name_to_string(), i, instr); - break; - - // VU/COP2 - case InstructionKind::VMOVE: - case InstructionKind::VFTOI0: - case InstructionKind::VFTOI4: - case InstructionKind::VFTOI12: - case InstructionKind::VITOF0: - case InstructionKind::VITOF12: - case InstructionKind::VITOF15: - case InstructionKind::VABS: - case InstructionKind::VADD: - case InstructionKind::VSUB: - case InstructionKind::VMUL: - case InstructionKind::VMINI: - case InstructionKind::VMAX: - case InstructionKind::VOPMSUB: - case InstructionKind::VMADD: - case InstructionKind::VMSUB: - case InstructionKind::VADD_BC: - case InstructionKind::VSUB_BC: - case InstructionKind::VMUL_BC: - case InstructionKind::VMULA_BC: - case InstructionKind::VMADD_BC: - case InstructionKind::VADDA_BC: - case InstructionKind::VMADDA_BC: - case InstructionKind::VMSUBA_BC: - case InstructionKind::VMSUB_BC: - case InstructionKind::VMINI_BC: - case InstructionKind::VMAX_BC: - case InstructionKind::VADDQ: - case InstructionKind::VSUBQ: - case InstructionKind::VMULQ: - case InstructionKind::VMSUBQ: - case InstructionKind::VMULA: - case InstructionKind::VADDA: - case InstructionKind::VMADDA: - case InstructionKind::VOPMULA: - case InstructionKind::VDIV: - case InstructionKind::VCLIP: - case InstructionKind::VMULAQ: - case InstructionKind::VMTIR: - case InstructionKind::VIAND: - case InstructionKind::VLQI: - case InstructionKind::VIADDI: - case InstructionKind::VSQI: - case InstructionKind::VRGET: - case InstructionKind::VSQRT: - case InstructionKind::VRSQRT: - case InstructionKind::VRXOR: - case InstructionKind::VRNEXT: - case InstructionKind::VNOP: - case InstructionKind::VWAITQ: - case InstructionKind::VCALLMS: - - // FPU/COP1 - case InstructionKind::MULAS: - case InstructionKind::MADDAS: - case InstructionKind::MADDS: - case InstructionKind::ADDAS: - - // Moves / Loads / Stores - case InstructionKind::CTC2: - case InstructionKind::CFC2: - case InstructionKind::SQC2: - case InstructionKind::LQC2: - case InstructionKind::LDR: - case InstructionKind::LDL: - case InstructionKind::QMTC2: - case InstructionKind::MFC0: - case InstructionKind::MTC0: - case InstructionKind::SYNCL: - case InstructionKind::SYNCP: - case InstructionKind::SYSCALL: - case InstructionKind::CACHE_DXWBIN: - case InstructionKind::MTPC: - case InstructionKind::MFPC: - - // random math - case InstructionKind::ADDU: - case InstructionKind::SRL: // maybe bitfield ops use this? - case InstructionKind::SRA: - case InstructionKind::SLT: - case InstructionKind::SLTI: - - // MMI - case InstructionKind::PSLLW: - case InstructionKind::PSRAW: - case InstructionKind::PSRAH: - case InstructionKind::PLZCW: - case InstructionKind::PMFHL_UW: - case InstructionKind::PMFHL_LW: - case InstructionKind::PMFHL_LH: - case InstructionKind::PSLLH: - case InstructionKind::PSRLH: - case InstructionKind::PEXTLW: - case InstructionKind::PPACH: - case InstructionKind::PSUBW: - case InstructionKind::PCGTW: - case InstructionKind::PEXTLH: - case InstructionKind::PEXTLB: - case InstructionKind::PMAXH: - case InstructionKind::PPACB: - case InstructionKind::PADDW: - case InstructionKind::PADDH: - case InstructionKind::PMAXW: - case InstructionKind::PPACW: - case InstructionKind::PCEQW: - case InstructionKind::PEXTUW: - case InstructionKind::PMINH: - case InstructionKind::PEXTUH: - case InstructionKind::PEXTUB: - case InstructionKind::PCEQB: - case InstructionKind::PMINW: - case InstructionKind::PABSW: - case InstructionKind::PCPYLD: - case InstructionKind::PROT3W: - case InstructionKind::PAND: - case InstructionKind::PMADDH: - case InstructionKind::PMULTH: - case InstructionKind::PEXEW: - case InstructionKind::PCPYUD: - case InstructionKind::PNOR: - case InstructionKind::PCPYH: - case InstructionKind::PINTEH: - - case InstructionKind::MTDAB: - case InstructionKind::MTDABM: - - // 128 bit integer - // case InstructionKind::LQ: - // case InstructionKind::SQ: - - result = to_asm_automatic(i.op_name_to_string(), i, instr); - break; - default: - result = nullptr; - } - - if (result) { - length = 1; - } - } - - // everything failed - if (!result) { - // temp hack for debug: - lg::error("Instruction -> BasicOp failed on {}", i.to_string(file->labels)); - func->add_basic_op(std::make_shared(), instr, instr + 1); - } else { - if (!func->contains_asm_ops && dynamic_cast(result.get())) { - func->warnings.info("Contains asm ops"); - 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); - } - } -} -} // namespace decompiler \ No newline at end of file diff --git a/decompiler/IR/BasicOpBuilder.h b/decompiler/IR/BasicOpBuilder.h deleted file mode 100644 index d20b06c850..0000000000 --- a/decompiler/IR/BasicOpBuilder.h +++ /dev/null @@ -1,15 +0,0 @@ -/*! - * @file BasicOpBuilder.h - * Analyzes a basic block and converts instructions to BasicOps. - * These will be used later to convert the Cfg into the nested IR format. - */ - -#pragma once - -namespace decompiler { -class Function; -struct BasicBlock; -class LinkedObjectFile; - -void add_basic_ops_to_block(Function* func, const BasicBlock& block, LinkedObjectFile* file); -} // namespace decompiler \ No newline at end of file diff --git a/decompiler/IR/IR.cpp b/decompiler/IR/IR.cpp deleted file mode 100644 index ea53180f71..0000000000 --- a/decompiler/IR/IR.cpp +++ /dev/null @@ -1,1006 +0,0 @@ -#include "IR.h" -#include "decompiler/ObjectFile/LinkedObjectFile.h" -#include "common/goos/PrettyPrinter.h" -#include "third-party/fmt/core.h" - -namespace decompiler { -// hack to print out reverse deref paths on loads to help with debugging load stuff. -bool enable_hack_load_path_print = false; -// hack to print (begin x) as x to make debug output easier to read. -bool inline_single_begins = true; - -std::vector> IR::get_all_ir(LinkedObjectFile& file) const { - (void)file; - std::vector> result; - get_children(&result); - size_t last_checked = 0; - size_t last_last_checked = -1; - - while (last_checked != last_last_checked) { - last_last_checked = last_checked; - auto end_of_check = result.size(); - for (size_t i = last_checked; i < end_of_check; i++) { - auto it = result.at(i).get(); - ASSERT(it); - it->get_children(&result); - } - last_checked = end_of_check; - } - - return result; -} - -std::string IR::print(const LinkedObjectFile& file) const { - return pretty_print::to_string(to_form(file)); -} - -namespace { -template -void add_regs_to_str(const T& regs, std::string& str) { - bool first = true; - for (auto& reg : regs) { - if (first) { - first = false; - } else { - str.push_back(' '); - } - str.append(reg.to_charp()); - } -} -} // namespace - -goos::Object IR_Failed::to_form(const LinkedObjectFile& file) const { - (void)file; - return pretty_print::build_list("INVALID-OPERATION"); -} - -void IR_Failed::get_children(std::vector>* output) const { - (void)output; -} - -goos::Object IR_Register::to_form(const LinkedObjectFile& file) const { - (void)file; - return pretty_print::to_symbol(reg.to_charp()); -} - -void IR_Register::get_children(std::vector>* output) const { - (void)output; -} - -goos::Object IR_Set::to_form(const LinkedObjectFile& file) const { - return pretty_print::build_list(pretty_print::to_symbol("set!"), dst->to_form(file), - src->to_form(file)); -} - -void IR_Set::get_children(std::vector>* output) const { - // note that we are not returning clobber here because it shouldn't contain anything that - // the IR simplification code should touch. - output->push_back(dst); - 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) { - case Kind::FLOAT: - store_operator = "s.f"; - break; - case Kind::INTEGER: - switch (size) { - case 1: - store_operator = "s.b"; - break; - case 2: - store_operator = "s.h"; - break; - case 4: - store_operator = "s.w"; - break; - case 8: - store_operator = "s.d"; - break; - case 16: - store_operator = "s.q"; - break; - default: - ASSERT(false); - } - break; - default: - ASSERT(false); - } - - return pretty_print::build_list(pretty_print::to_symbol(store_operator), dst->to_form(file), - src->to_form(file)); -} - -goos::Object IR_Store_Atomic::to_form(const LinkedObjectFile& file) const { - std::string store_operator; - switch (kind) { - case Kind::FLOAT: - store_operator = "s.f"; - break; - case Kind::INTEGER: - switch (size) { - case 1: - store_operator = "s.b"; - break; - case 2: - store_operator = "s.h"; - break; - case 4: - store_operator = "s.w"; - break; - case 8: - store_operator = "s.d"; - break; - case 16: - store_operator = "s.q"; - break; - default: - ASSERT(false); - } - break; - default: - ASSERT(false); - } - - return pretty_print::build_list(pretty_print::to_symbol(store_operator), dst->to_form(file), - 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); -} - -void IR_Symbol::get_children(std::vector>* output) const { - (void)output; -} - -goos::Object IR_SymbolValue::to_form(const LinkedObjectFile& file) const { - (void)file; - return pretty_print::to_symbol(name); -} - -void IR_SymbolValue::get_children(std::vector>* output) const { - (void)output; -} - -goos::Object IR_EmptyPair::to_form(const LinkedObjectFile& file) const { - (void)file; - return pretty_print::to_symbol("'()"); -} - -void IR_EmptyPair::get_children(std::vector>* output) const { - (void)output; -} - -goos::Object IR_StaticAddress::to_form(const LinkedObjectFile& file) const { - // return pretty_print::build_list(pretty_print::to_symbol("&"), file.get_label_name(label_id)); - return pretty_print::to_symbol(file.get_label_name(label_id)); -} - -void IR_StaticAddress::get_children(std::vector>* output) const { - (void)output; -} - -goos::Object IR_Load::to_form(const LinkedObjectFile& file) const { - if (load_path_set && enable_hack_load_path_print) { - std::vector list; - if (load_path_addr_of) { - list.push_back(pretty_print::to_symbol("&->")); - } else { - list.push_back(pretty_print::to_symbol("->")); - } - list.push_back(load_path_base->to_form(file)); - for (auto& x : load_path) { - list.push_back(pretty_print::to_symbol(x)); - } - return pretty_print::build_list(list); - } - std::string load_operator; - switch (kind) { - case FLOAT: - load_operator = "l.f"; - break; - case UNSIGNED: - switch (size) { - case 1: - load_operator = "l.bu"; - break; - case 2: - load_operator = "l.hu"; - break; - case 4: - load_operator = "l.wu"; - break; - case 8: - load_operator = "l.d"; - break; - case 16: - load_operator = "l.q"; - break; - default: - ASSERT(false); - } - break; - case SIGNED: - switch (size) { - case 1: - load_operator = "l.bs"; - break; - case 2: - load_operator = "l.hs"; - break; - case 4: - load_operator = "l.ws"; - break; - default: - ASSERT(false); - } - break; - default: - ASSERT(false); - } - return pretty_print::build_list(pretty_print::to_symbol(load_operator), location->to_form(file)); -} - -void IR_Load::get_children(std::vector>* output) const { - output->push_back(location); -} - -goos::Object IR_FloatMath2::to_form(const LinkedObjectFile& file) const { - std::string math_operator; - switch (kind) { - case DIV: - math_operator = "/.f"; - break; - case MUL: - math_operator = "*.f"; - break; - case ADD: - math_operator = "+.f"; - break; - case SUB: - math_operator = "-.f"; - break; - case MIN: - math_operator = "min.f"; - break; - case MAX: - math_operator = "max.f"; - break; - default: - ASSERT(false); - } - - return pretty_print::build_list(pretty_print::to_symbol(math_operator), arg0->to_form(file), - arg1->to_form(file)); -} - -void IR_FloatMath2::get_children(std::vector>* output) const { - output->push_back(arg0); - output->push_back(arg1); -} - -void IR_FloatMath1::get_children(std::vector>* output) const { - output->push_back(arg); -} - -goos::Object IR_IntMath2::to_form(const LinkedObjectFile& file) const { - std::string math_operator; - switch (kind) { - case ADD: - math_operator = "+.i"; - break; - case SUB: - math_operator = "-.i"; - break; - case MUL_SIGNED: - math_operator = "*.si"; - break; - case MUL_UNSIGNED: - math_operator = "*.ui"; - break; - case DIV_SIGNED: - math_operator = "/.si"; - break; - case MOD_SIGNED: - math_operator = "mod.si"; - break; - case DIV_UNSIGNED: - math_operator = "/.ui"; - break; - case MOD_UNSIGNED: - math_operator = "mod.ui"; - break; - case OR: - math_operator = "logior"; - break; - case AND: - math_operator = "logand"; - break; - case NOR: - math_operator = "lognor"; - break; - case XOR: - math_operator = "logxor"; - break; - case LEFT_SHIFT: - math_operator = "shl"; - break; - case RIGHT_SHIFT_ARITH: - math_operator = "sar"; - break; - case RIGHT_SHIFT_LOGIC: - math_operator = "shr"; - break; - case MIN_SIGNED: - math_operator = "min.si"; - break; - case MAX_SIGNED: - math_operator = "max.si"; - break; - default: - ASSERT(false); - } - return pretty_print::build_list(pretty_print::to_symbol(math_operator), arg0->to_form(file), - arg1->to_form(file)); -} - -void IR_IntMath2::get_children(std::vector>* output) const { - output->push_back(arg0); - output->push_back(arg1); -} - -goos::Object IR_IntMath1::to_form(const LinkedObjectFile& file) const { - std::string math_operator; - switch (kind) { - case NOT: - math_operator = "lognot"; - break; - case ABS: - math_operator = "abs.si"; - break; - case NEG: - math_operator = "-.i"; - break; - default: - ASSERT(false); - } - return pretty_print::build_list(pretty_print::to_symbol(math_operator), arg->to_form(file)); -} - -void IR_IntMath1::get_children(std::vector>* output) const { - output->push_back(arg); -} - -goos::Object IR_FloatMath1::to_form(const LinkedObjectFile& file) const { - std::string math_operator; - switch (kind) { - case FLOAT_TO_INT: - math_operator = "int<-float"; - break; - case INT_TO_FLOAT: - math_operator = "float<-int"; - break; - case ABS: - math_operator = "abs.f"; - break; - case NEG: - math_operator = "neg.f"; - break; - case SQRT: - math_operator = "sqrt.f"; - break; - default: - ASSERT(false); - } - return pretty_print::build_list(pretty_print::to_symbol(math_operator), arg->to_form(file)); -} - -goos::Object IR_Call::to_form(const LinkedObjectFile& file) const { - (void)file; - std::vector result; - result.push_back(pretty_print::to_symbol("call!")); - - if (call_type_set) { - result.push_back(pretty_print::to_symbol(":arg-count")); - result.push_back(pretty_print::to_symbol(std::to_string(call_type.arg_count() - 1))); - } - - for (auto& x : args) { - result.push_back(x->to_form(file)); - } - return pretty_print::build_list(result); -} - -void IR_Call::get_children(std::vector>* output) const { - (void)output; -} - -goos::Object IR_IntegerConstant::to_form(const LinkedObjectFile& file) const { - (void)file; - return pretty_print::to_symbol(std::to_string(value)); -} - -void IR_IntegerConstant::get_children(std::vector>* output) const { - (void)output; -} - -goos::Object BranchDelay::to_form(const LinkedObjectFile& file) const { - (void)file; - switch (kind) { - case NOP: - return pretty_print::build_list("nop"); - case SET_REG_FALSE: - return pretty_print::build_list(pretty_print::to_symbol("set!"), destination->to_form(file), - "'#f"); - case SET_REG_TRUE: - return pretty_print::build_list(pretty_print::to_symbol("set!"), destination->to_form(file), - "'#t"); - case SET_REG_REG: - return pretty_print::build_list(pretty_print::to_symbol("set!"), destination->to_form(file), - source->to_form(file)); - case SET_BINTEGER: - return pretty_print::build_list(pretty_print::to_symbol("set!"), destination->to_form(file), - "binteger"); - case SET_PAIR: - return pretty_print::build_list(pretty_print::to_symbol("set!"), destination->to_form(file), - "pair"); - case DSLLV: - return pretty_print::build_list( - pretty_print::to_symbol("set!"), destination->to_form(file), - pretty_print::build_list(pretty_print::to_symbol("shl"), source->to_form(file), - source2->to_form(file))); - case NEGATE: - return pretty_print::build_list(pretty_print::to_symbol("set!"), destination->to_form(file), - pretty_print::build_list("-", source->to_form(file))); - case UNKNOWN: - return pretty_print::build_list("unknown-branch-delay"); - default: - ASSERT(false); - return {}; - } -} - -void BranchDelay::get_children(std::vector>* output) const { - if (destination) { - output->push_back(destination); - } - - if (source) { - output->push_back(source); - } - - if (source2) { - output->push_back(source2); - } -} - -goos::Object IR_Nop::to_form(const LinkedObjectFile& file) const { - (void)file; - return pretty_print::build_list("nop!"); -} - -int Condition::num_args() const { - switch (kind) { - case NOT_EQUAL: - case EQUAL: - case LESS_THAN_SIGNED: - case LESS_THAN_UNSIGNED: - case GREATER_THAN_SIGNED: - case GREATER_THAN_UNSIGNED: - case LEQ_SIGNED: - case GEQ_SIGNED: - case LEQ_UNSIGNED: - case GEQ_UNSIGNED: - case FLOAT_EQUAL: - case FLOAT_NOT_EQUAL: - case FLOAT_LESS_THAN: - case FLOAT_GEQ: - case FLOAT_GREATER_THAN: - case FLOAT_LEQ: - return 2; - case ZERO: - case NONZERO: - case FALSE: - case TRUTHY: - case GREATER_THAN_ZERO_SIGNED: - case GEQ_ZERO_SIGNED: - case LESS_THAN_ZERO: - case LEQ_ZERO_SIGNED: - return 1; - case ALWAYS: - case NEVER: - return 0; - default: - ASSERT(false); - return -1; - } -} - -void Condition::get_children(std::vector>* output) const { - if (src0) { - output->push_back(src0); - } - - if (src1) { - output->push_back(src1); - } -} - -void Condition::invert() { - switch (kind) { - case NOT_EQUAL: - kind = EQUAL; - break; - case EQUAL: - kind = NOT_EQUAL; - break; - case LESS_THAN_SIGNED: - kind = GEQ_SIGNED; - break; - case GREATER_THAN_SIGNED: - kind = LEQ_SIGNED; - break; - case LEQ_SIGNED: - kind = GREATER_THAN_SIGNED; - break; - case GEQ_SIGNED: - kind = LESS_THAN_SIGNED; - break; - case GREATER_THAN_ZERO_SIGNED: - kind = LEQ_ZERO_SIGNED; - break; - case LEQ_ZERO_SIGNED: - kind = GREATER_THAN_ZERO_SIGNED; - break; - case LESS_THAN_ZERO: - kind = GEQ_ZERO_SIGNED; - break; - case GEQ_ZERO_SIGNED: - kind = LESS_THAN_ZERO; - break; - case LESS_THAN_UNSIGNED: - kind = GEQ_UNSIGNED; - break; - case GREATER_THAN_UNSIGNED: - kind = LEQ_UNSIGNED; - break; - case LEQ_UNSIGNED: - kind = GREATER_THAN_UNSIGNED; - break; - case GEQ_UNSIGNED: - kind = LESS_THAN_UNSIGNED; - break; - case ZERO: - kind = NONZERO; - break; - case NONZERO: - kind = ZERO; - break; - case FALSE: - kind = TRUTHY; - break; - case TRUTHY: - kind = FALSE; - break; - case ALWAYS: - kind = NEVER; - break; - case NEVER: - kind = ALWAYS; - break; - case FLOAT_EQUAL: - kind = FLOAT_NOT_EQUAL; - break; - case FLOAT_NOT_EQUAL: - kind = FLOAT_EQUAL; - break; - case FLOAT_LESS_THAN: - kind = FLOAT_GEQ; - break; - case FLOAT_GEQ: - kind = FLOAT_LESS_THAN; - break; - case FLOAT_GREATER_THAN: - kind = FLOAT_LEQ; - break; - case FLOAT_LEQ: - kind = FLOAT_GREATER_THAN; - break; - default: - ASSERT(false); - } -} - -goos::Object Condition::to_form(const LinkedObjectFile& file) const { - int nargs = num_args(); - std::string condtion_operator; - switch (kind) { - case NOT_EQUAL: - condtion_operator = "!="; - break; - case EQUAL: - condtion_operator = "="; - break; - case LESS_THAN_SIGNED: - condtion_operator = "<.si"; - break; - case LESS_THAN_UNSIGNED: - condtion_operator = "<.ui"; - break; - case GREATER_THAN_SIGNED: - condtion_operator = ">.si"; - break; - case GREATER_THAN_UNSIGNED: - condtion_operator = ">.ui"; - break; - case LEQ_SIGNED: - condtion_operator = "<=.si"; - break; - case GEQ_SIGNED: - condtion_operator = ">=.si"; - break; - case LEQ_UNSIGNED: - condtion_operator = "<=.ui"; - break; - case GEQ_UNSIGNED: - condtion_operator = ">=.ui"; - break; - case ZERO: - condtion_operator = "zero?"; - break; - case NONZERO: - condtion_operator = "nonzero?"; - break; - case FALSE: - condtion_operator = "not"; - break; - case TRUTHY: - condtion_operator = ""; - break; - case ALWAYS: - condtion_operator = "'#t"; - break; - case NEVER: - condtion_operator = "'#f"; - break; - case FLOAT_EQUAL: - condtion_operator = "=.f"; - break; - case FLOAT_NOT_EQUAL: - condtion_operator = "!=.f"; - break; - case FLOAT_LESS_THAN: - condtion_operator = "<.f"; - break; - case FLOAT_GEQ: - condtion_operator = ">=.f"; - break; - case FLOAT_GREATER_THAN: - condtion_operator = ">.f"; - break; - case FLOAT_LEQ: - condtion_operator = "<=.f"; - break; - case GREATER_THAN_ZERO_SIGNED: - condtion_operator = ">0.si"; - break; - case GEQ_ZERO_SIGNED: - condtion_operator = ">=0.si"; - break; - case LESS_THAN_ZERO: - condtion_operator = "<0.si"; - break; - case LEQ_ZERO_SIGNED: - condtion_operator = "<=0.si"; - break; - default: - ASSERT(false); - } - - if (nargs == 2) { - return pretty_print::build_list(pretty_print::to_symbol(condtion_operator), src0->to_form(file), - src1->to_form(file)); - } else if (nargs == 1) { - if (condtion_operator.empty()) { - return src0->to_form(file); - } else { - return pretty_print::build_list(pretty_print::to_symbol(condtion_operator), - src0->to_form(file)); - } - } else if (nargs == 0) { - return pretty_print::to_symbol(condtion_operator); - } else { - ASSERT(false); - return {}; - } -} - -goos::Object IR_Branch::to_form(const LinkedObjectFile& file) const { - return pretty_print::build_list( - pretty_print::to_symbol(likely ? "bl!" : "b!"), condition.to_form(file), - pretty_print::to_symbol(file.get_label_name(dest_label_idx)), branch_delay.to_form(file)); -} - -void IR_Branch::get_children(std::vector>* output) const { - condition.get_children(output); - 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); -} - -void IR_Compare::get_children(std::vector>* output) const { - condition.get_children(output); -} - -goos::Object IR_Suspend_Atomic::to_form(const LinkedObjectFile& file) const { - (void)file; - return pretty_print::build_list("suspend!"); -} - -void IR_Nop::get_children(std::vector>* output) const { - (void)output; -} - -void IR_Suspend_Atomic::get_children(std::vector>* output) const { - (void)output; -} - -goos::Object IR_Breakpoint_Atomic::to_form(const LinkedObjectFile& file) const { - (void)file; - return pretty_print::build_list("breakpoint!"); -} - -void IR_Breakpoint_Atomic::get_children(std::vector>* output) const { - (void)output; -} - -goos::Object IR_AsmOp::to_form(const LinkedObjectFile& file) const { - std::vector forms; - forms.push_back(pretty_print::to_symbol(name)); - for (auto& x : {dst, src0, src1, src2}) { - if (x) { - forms.push_back(x->to_form(file)); - } - } - return pretty_print::build_list(forms); -} - -void IR_AsmOp::get_children(std::vector>* output) const { - for (auto& x : {dst, src0, src1}) { - if (x) { - output->push_back(x); - } - } -} - -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"), - src->to_form(file)); -} - -void IR_CMoveF::get_children(std::vector>* output) const { - output->push_back(src); -} - -goos::Object IR_AsmReg::to_form(const LinkedObjectFile& file) const { - (void)file; - switch (kind) { - case VU_Q: - return pretty_print::to_symbol("Q"); - case VU_ACC: - return pretty_print::to_symbol("ACC"); - default: - ASSERT(false); - return {}; - } -} - -void IR_AsmReg::get_children(std::vector>* output) const { - (void)output; -} - -} // namespace decompiler \ No newline at end of file diff --git a/decompiler/IR/IR.h b/decompiler/IR/IR.h deleted file mode 100644 index a6c30be9d2..0000000000 --- a/decompiler/IR/IR.h +++ /dev/null @@ -1,454 +0,0 @@ -#pragma once - -#ifndef JAK_IR_H -#define JAK_IR_H - -#include -#include -#include -#include -#include "decompiler/Disasm/Register.h" -#include "common/type_system/TypeSpec.h" -#include "decompiler/util/DecompilerTypeSystem.h" -#include "decompiler/util/TP_Type.h" -#include "common/util/Assert.h" - -namespace goos { -class Object; -} - -namespace decompiler { -class LinkedObjectFile; -class DecompilerTypeSystem; -class ExpressionStack; - -class IR { - public: - virtual goos::Object to_form(const LinkedObjectFile& file) const = 0; - std::vector> get_all_ir(LinkedObjectFile& file) const; - std::string print(const LinkedObjectFile& file) const; - virtual void get_children(std::vector>* output) const = 0; - bool is_basic_op = false; - virtual ~IR() = default; -}; - -class IR_Atomic : public virtual IR { - public: - std::vector read_regs, write_regs, clobber_regs; - std::unordered_set consumed, written_and_unused; - bool reg_info_set = false; - - TypeState end_types; // types at the end of this instruction - std::vector warnings; - void warn(const std::string& str) { warnings.emplace_back(str); } -}; - -class IR_Failed : public virtual IR { - public: - IR_Failed() = default; - goos::Object to_form(const LinkedObjectFile& file) const override; - void get_children(std::vector>* output) const override; -}; - -class IR_Failed_Atomic : public IR_Failed, public IR_Atomic { - public: - IR_Failed_Atomic() = default; -}; - -class IR_Register : public virtual IR { - public: - IR_Register(Register _reg, int _instr_idx) : reg(_reg), instr_idx(_instr_idx) {} - goos::Object to_form(const LinkedObjectFile& file) const override; - void get_children(std::vector>* output) const override; - Register reg; - int instr_idx = -1; -}; - -class IR_Set : public virtual IR { - public: - enum Kind { - REG_64, - LOAD, - STORE, - SYM_LOAD, - SYM_STORE, - FPR_TO_GPR64, - GPR_TO_FPR, - REG_FLT, - REG_I128, - EXPR - } kind; - IR_Set(Kind _kind, std::shared_ptr _dst, std::shared_ptr _src) - : kind(_kind), dst(std::move(_dst)), src(std::move(_src)) {} - goos::Object to_form(const LinkedObjectFile& file) const override; - void get_children(std::vector>* output) const override; - - std::shared_ptr dst, src; - std::shared_ptr clobber = nullptr; -}; - -// todo -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 class Kind { INTEGER, FLOAT } kind; - IR_Store(Kind _kind, std::shared_ptr _dst, std::shared_ptr _src, int _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; -}; - -/*! - * Note, IR_Store_Atomic does not appear as a IR_Set_Atomic. - * This is to avoid the "diamond problem". - */ -class IR_Store_Atomic : public IR_Set_Atomic { - public: - enum class Kind { INTEGER, FLOAT } kind; - IR_Store_Atomic(Kind _kind, std::shared_ptr _dst, std::shared_ptr _src, int _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 { - public: - explicit IR_Symbol(std::string _name) : name(std::move(_name)) {} - std::string name; - goos::Object to_form(const LinkedObjectFile& file) const override; - void get_children(std::vector>* output) const override; -}; - -class IR_SymbolValue : public virtual IR { - public: - explicit IR_SymbolValue(std::string _name) : name(std::move(_name)) {} - std::string name; - goos::Object to_form(const LinkedObjectFile& file) const override; - void get_children(std::vector>* output) const override; -}; - -class IR_EmptyPair : public virtual IR { - public: - explicit IR_EmptyPair() = default; - goos::Object to_form(const LinkedObjectFile& file) const override; - void get_children(std::vector>* output) const override; -}; - -class IR_StaticAddress : public virtual IR { - public: - explicit IR_StaticAddress(int _label_id) : label_id(_label_id) {} - int label_id = -1; - goos::Object to_form(const LinkedObjectFile& file) const override; - void get_children(std::vector>* output) const override; -}; - -class IR_Load : public virtual IR { - public: - enum Kind { UNSIGNED, SIGNED, FLOAT } kind; - - IR_Load(Kind _kind, int _size, std::shared_ptr _location) - : kind(_kind), size(_size), location(std::move(_location)) {} - int size; - std::shared_ptr location; - goos::Object to_form(const LinkedObjectFile& file) const override; - void get_children(std::vector>* output) const override; - - // this load_path stuff is just for debugging and shouldn't be used as part of the real - // decompilation. - void clear_load_path() { - load_path_set = false; - load_path_addr_of = false; - load_path.clear(); - load_path_base = nullptr; - } - std::shared_ptr load_path_base = nullptr; - bool load_path_set = false; - bool load_path_addr_of = false; - std::vector load_path; -}; - -class IR_FloatMath2 : public virtual IR { - public: - enum Kind { DIV, MUL, ADD, SUB, MIN, MAX } kind; - IR_FloatMath2(Kind _kind, std::shared_ptr _arg0, std::shared_ptr _arg1) - : kind(_kind), arg0(std::move(_arg0)), arg1(std::move(_arg1)) {} - std::shared_ptr arg0, arg1; - goos::Object to_form(const LinkedObjectFile& file) const override; - void get_children(std::vector>* output) const override; -}; - -class IR_FloatMath1 : public virtual IR { - public: - enum Kind { FLOAT_TO_INT, INT_TO_FLOAT, ABS, NEG, SQRT } kind; - IR_FloatMath1(Kind _kind, std::shared_ptr _arg) : kind(_kind), arg(std::move(_arg)) {} - std::shared_ptr arg; - goos::Object to_form(const LinkedObjectFile& file) const override; - void get_children(std::vector>* output) const override; -}; - -class IR_IntMath2 : public virtual IR { - public: - enum Kind { - ADD, - SUB, - MUL_SIGNED, - DIV_SIGNED, - MOD_SIGNED, - DIV_UNSIGNED, - MOD_UNSIGNED, - OR, - AND, - NOR, - XOR, - LEFT_SHIFT, - RIGHT_SHIFT_ARITH, - RIGHT_SHIFT_LOGIC, - MUL_UNSIGNED, - MIN_SIGNED, - MAX_SIGNED - } kind; - IR_IntMath2(Kind _kind, std::shared_ptr _arg0, std::shared_ptr _arg1) - : kind(_kind), arg0(std::move(_arg0)), arg1(std::move(_arg1)) {} - std::shared_ptr arg0, arg1; - goos::Object to_form(const LinkedObjectFile& file) const override; - void get_children(std::vector>* output) const override; -}; - -class IR_IntMath1 : public virtual IR { - public: - enum Kind { NOT, ABS, NEG } kind; - IR_IntMath1(Kind _kind, std::shared_ptr _arg) : kind(_kind), arg(std::move(_arg)) {} - IR_IntMath1(Kind _kind, std::shared_ptr _arg, std::shared_ptr _abs_op) - : kind(_kind), arg(std::move(_arg)), abs_op(std::move(_abs_op)) { - ASSERT(abs_op); - } - std::shared_ptr arg; - std::shared_ptr abs_op = nullptr; - goos::Object to_form(const LinkedObjectFile& file) const override; - void get_children(std::vector>* output) const override; -}; - -class IR_Call : public virtual IR { - public: - IR_Call() = default; - goos::Object to_form(const LinkedObjectFile& file) const override; - void get_children(std::vector>* output) const override; - std::vector> args; - TypeSpec call_type; - bool call_type_set = false; -}; - -// todo -class IR_Call_Atomic : public virtual IR_Call, public IR_Atomic { - public: - IR_Call_Atomic() = default; -}; - -class IR_IntegerConstant : public virtual IR { - public: - int64_t value; - explicit IR_IntegerConstant(int64_t _value) : value(_value) {} - goos::Object to_form(const LinkedObjectFile& file) const override; - void get_children(std::vector>* output) const override; -}; - -struct BranchDelay { - enum Kind { - NOP, - SET_REG_FALSE, - SET_REG_TRUE, - SET_REG_REG, - SET_BINTEGER, - SET_PAIR, - DSLLV, - NEGATE, - UNKNOWN - } kind; - std::shared_ptr destination = nullptr, source = nullptr, source2 = nullptr; - 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; - - void type_prop(TypeState& output, const LinkedObjectFile& file, DecompilerTypeSystem& dts); -}; - -struct Condition { - enum Kind { - NOT_EQUAL, - EQUAL, - LESS_THAN_SIGNED, - GREATER_THAN_SIGNED, - LEQ_SIGNED, - GEQ_SIGNED, - GREATER_THAN_ZERO_SIGNED, - LEQ_ZERO_SIGNED, - LESS_THAN_ZERO, - GEQ_ZERO_SIGNED, - LESS_THAN_UNSIGNED, - GREATER_THAN_UNSIGNED, - LEQ_UNSIGNED, - GEQ_UNSIGNED, - ZERO, - NONZERO, - FALSE, - TRUTHY, - ALWAYS, - NEVER, - FLOAT_EQUAL, - FLOAT_NOT_EQUAL, - FLOAT_LESS_THAN, - FLOAT_GEQ, - FLOAT_LEQ, - FLOAT_GREATER_THAN, - } kind; - - Condition(Kind _kind, - std::shared_ptr _src0, - std::shared_ptr _src1, - std::shared_ptr _clobber) - : kind(_kind), src0(std::move(_src0)), src1(std::move(_src1)), clobber(std::move(_clobber)) { - int nargs = num_args(); - if (nargs == 2) { - ASSERT(src0 && src1); - } else if (nargs == 1) { - ASSERT(src0 && !src1); - } else if (nargs == 0) { - ASSERT(!src0 && !src1); - } - } - - int num_args() const; - goos::Object to_form(const LinkedObjectFile& file) const; - std::shared_ptr src0, src1, clobber; - void get_children(std::vector>* output) const; - void invert(); -}; - -class IR_Branch : public virtual IR { - public: - IR_Branch(Condition _condition, int _dest_label_idx, BranchDelay _branch_delay, bool _likely) - : condition(std::move(_condition)), - dest_label_idx(_dest_label_idx), - branch_delay(std::move(_branch_delay)), - likely(_likely) {} - - Condition condition; - int dest_label_idx; - BranchDelay branch_delay; - bool likely; - - goos::Object to_form(const LinkedObjectFile& file) const override; - void get_children(std::vector>* output) const override; -}; - -// todo -class IR_Branch_Atomic : public virtual IR_Branch, public IR_Atomic { - public: - IR_Branch_Atomic(Condition _condition, - int _dest_label_idx, - 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 { - public: - explicit IR_Compare(Condition _condition, IR_Atomic* _root_op) - : condition(std::move(_condition)), root_op(_root_op) {} - - Condition condition; - - // the basic op that the comparison comes from. If the condition is "ALWAYS", this may be null. - // if this is the source of an IR_Set_Atomic, this may also be null. This should only be used - // from IR_Compare's expression_stack, when the IR_Compare is being used as a branch condition, - // and not as a literal #f/#t that's being assigned. - IR_Atomic* root_op = nullptr; - - goos::Object to_form(const LinkedObjectFile& file) const override; - void get_children(std::vector>* output) const override; -}; - -class IR_Nop : public virtual IR { - public: - IR_Nop() = default; - goos::Object to_form(const LinkedObjectFile& file) const override; - void get_children(std::vector>* output) const override; -}; - -class IR_Nop_Atomic : public IR_Nop, public IR_Atomic { - public: - IR_Nop_Atomic() = default; -}; - -class IR_Suspend_Atomic : public virtual IR, public IR_Atomic { - public: - IR_Suspend_Atomic() = default; - goos::Object to_form(const LinkedObjectFile& file) const override; - void get_children(std::vector>* output) const override; -}; - -class IR_Breakpoint_Atomic : public virtual IR_Atomic { - public: - IR_Breakpoint_Atomic() = default; - goos::Object to_form(const LinkedObjectFile& file) const override; - void get_children(std::vector>* output) const override; -}; - -class IR_AsmOp : public virtual IR { - public: - std::shared_ptr dst = nullptr; - std::shared_ptr src0 = nullptr; - std::shared_ptr src1 = nullptr; - std::shared_ptr src2 = nullptr; - std::string name; - IR_AsmOp(std::string _name) : name(std::move(_name)) {} - goos::Object to_form(const LinkedObjectFile& file) const override; - void get_children(std::vector>* output) const override; -}; - -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 { - public: - std::shared_ptr src = nullptr; - bool on_zero = false; - explicit IR_CMoveF(std::shared_ptr _src, bool _on_zero) - : src(std::move(_src)), on_zero(_on_zero) {} - goos::Object to_form(const LinkedObjectFile& file) const override; - void get_children(std::vector>* output) const override; -}; - -class IR_AsmReg : public virtual IR { - public: - enum Kind { VU_Q, VU_ACC } kind; - explicit IR_AsmReg(Kind _kind) : kind(_kind) {} - goos::Object to_form(const LinkedObjectFile& file) const override; - void get_children(std::vector>* output) const override; -}; - -} // namespace decompiler -#endif // JAK_IR_H diff --git a/decompiler/ObjectFile/LinkedObjectFile.cpp b/decompiler/ObjectFile/LinkedObjectFile.cpp index 486fc366a6..ccd043958b 100644 --- a/decompiler/ObjectFile/LinkedObjectFile.cpp +++ b/decompiler/ObjectFile/LinkedObjectFile.cpp @@ -6,7 +6,6 @@ #include #include #include -#include "decompiler/IR/IR.h" #include "third-party/fmt/core.h" #include "LinkedObjectFile.h" #include "decompiler/Disasm/InstructionDecode.h" @@ -583,23 +582,6 @@ std::string LinkedObjectFile::print_function_disassembly(Function& func, result += " ;;"; auto& word = words_by_seg[seg].at(func.start_word + i); append_word_to_string(result, word); - } else { - // print basic op stuff - if (func.has_basic_ops() && func.instr_starts_basic_op(i)) { - if (line.length() < 30) { - line.append(30 - line.length(), ' '); - } - line += ";; " + func.get_basic_op_at_instr(i)->print(*this); - for (int iidx = 0; iidx < instr.n_src; iidx++) { - if (instr.get_src(iidx).is_label()) { - auto lab = labels.at(instr.get_src(iidx).get_label()); - if (is_string(lab.target_segment, lab.offset)) { - line += " " + get_goal_string(lab.target_segment, lab.offset / 4 - 1); - } - } - } - } - result += line + "\n"; } if (in_delay_slot) { @@ -659,11 +641,6 @@ std::string LinkedObjectFile::print_function_disassembly(Function& func, */ } - if (func.ir) { - result += ";; ir\n"; - result += func.ir->print(*this); - } - result += "\n\n\n"; return result; } diff --git a/decompiler/ObjectFile/ObjectFileDB.cpp b/decompiler/ObjectFile/ObjectFileDB.cpp index a25cc16040..9ed02e414a 100644 --- a/decompiler/ObjectFile/ObjectFileDB.cpp +++ b/decompiler/ObjectFile/ObjectFileDB.cpp @@ -24,8 +24,6 @@ #include "common/util/Timer.h" #include "common/util/FileUtil.h" #include "decompiler/Function/BasicBlocks.h" -#include "decompiler/IR/BasicOpBuilder.h" -#include "decompiler/Function/TypeInspector.h" #include "common/log/log.h" #include "common/util/json_util.h" @@ -134,7 +132,7 @@ ObjectFileDB::ObjectFileDB(const std::vector& _dgos, try { get_objs_from_dgo(dgo, config); } catch (std::runtime_error& e) { - lg::warn("Error when reading DGOs: {}", e.what()); + lg::warn("Error when reading DGOs: {} on {}", e.what(), dgo); } } @@ -735,8 +733,6 @@ void ObjectFileDB::analyze_functions_ir1(const Config& config) { int total_trivial_cfg_functions = 0; int total_named_functions = 0; - int total_basic_ops = 0; - int total_failed_basic_ops = 0; int asm_funcs = 0; @@ -774,24 +770,8 @@ void ObjectFileDB::analyze_functions_ir1(const Config& config) { if (label_id != -1) { block.label_name = data.linked_data.get_label_name(label_id); } - - block.start_basic_op = func.basic_ops.size(); - add_basic_ops_to_block(&func, block, &data.linked_data); - block.end_basic_op = func.basic_ops.size(); } } - total_basic_ops += func.get_basic_op_count(); - total_failed_basic_ops += func.get_failed_basic_op_count(); - - // if we got an inspect method, inspect it. - if (func.is_inspect_method) { - auto result = inspect_inspect_method( - func, func.method_of_type, dts, data.linked_data, - config.hacks.types_with_bad_inspect_methods.find(func.method_of_type) != - config.hacks.types_with_bad_inspect_methods.end()); - all_type_defs += ";; " + data.to_unique_name() + "\n"; - all_type_defs += result.print_as_deftype() + "\n"; - } } else { asm_funcs++; } @@ -802,10 +782,6 @@ void ObjectFileDB::analyze_functions_ir1(const Config& config) { lg::info("Named {}/{} functions ({:.3f}%)", total_named_functions, total_functions, 100.f * float(total_named_functions) / float(total_functions)); lg::info("Excluding {} asm functions", asm_funcs); - lg::info("Found {} basic blocks in {:.3f} ms", total_basic_blocks, timer.getMs()); - int successful_basic_ops = total_basic_ops - total_failed_basic_ops; - lg::info(" {}/{} basic ops converted successfully ({:.3f}%)", successful_basic_ops, - total_basic_ops, 100.f * float(successful_basic_ops) / float(total_basic_ops)); } void ObjectFileDB::dump_raw_objects(const std::string& output_dir) { diff --git a/decompiler/ObjectFile/ObjectFileDB.h b/decompiler/ObjectFile/ObjectFileDB.h index a9851fb6e1..51a2e5f5ec 100644 --- a/decompiler/ObjectFile/ObjectFileDB.h +++ b/decompiler/ObjectFile/ObjectFileDB.h @@ -103,7 +103,6 @@ class ObjectFileDB { ObjectFileData& lookup_record(const ObjectFileRecord& rec); DecompilerTypeSystem dts; - std::string all_type_defs; bool lookup_function_type(const FunctionName& name, const std::string& obj_name, diff --git a/decompiler/ObjectFile/ObjectFileDB_IR2.cpp b/decompiler/ObjectFile/ObjectFileDB_IR2.cpp index 6605c74a7a..e45cc63132 100644 --- a/decompiler/ObjectFile/ObjectFileDB_IR2.cpp +++ b/decompiler/ObjectFile/ObjectFileDB_IR2.cpp @@ -8,7 +8,6 @@ #include "common/log/log.h" #include "common/util/Timer.h" #include "common/util/FileUtil.h" -#include "decompiler/Function/TypeInspector.h" #include "decompiler/analysis/type_analysis.h" #include "decompiler/analysis/reg_usage.h" #include "decompiler/analysis/insert_lets.h" diff --git a/decompiler/config.cpp b/decompiler/config.cpp index 183b88dd38..c5b6b724a6 100644 --- a/decompiler/config.cpp +++ b/decompiler/config.cpp @@ -54,7 +54,6 @@ Config read_config_file(const std::string& path_to_config_file, } config.disassemble_code = cfg.at("disassemble_code").get(); config.decompile_code = cfg.at("decompile_code").get(); - config.regenerate_all_types = cfg.at("regenerate_all_types").get(); config.write_hex_near_instructions = cfg.at("write_hex_near_instructions").get(); config.write_scripts = cfg.at("write_scripts").get(); config.disassemble_data = cfg.at("disassemble_data").get(); diff --git a/decompiler/config.h b/decompiler/config.h index 40c62f6ed1..9cf1eb26f5 100644 --- a/decompiler/config.h +++ b/decompiler/config.h @@ -101,7 +101,6 @@ struct Config { bool process_game_count = false; bool rip_levels = false; - bool regenerate_all_types = false; bool write_hex_near_instructions = false; bool hexdump_code = false; bool hexdump_data = false; diff --git a/decompiler/config/jak1_ntsc_black_label.jsonc b/decompiler/config/jak1_ntsc_black_label.jsonc index d35033104a..5682405412 100644 --- a/decompiler/config/jak1_ntsc_black_label.jsonc +++ b/decompiler/config/jak1_ntsc_black_label.jsonc @@ -42,9 +42,6 @@ // these options are used rarely and should usually be left at false - // output a file type_defs.gc which is used for the types part of all-types.gc - "regenerate_all_types": false, - // generate the symbol_map.json file. // this is a guess at where each symbol is first defined/used. "generate_symbol_definition_map": false, diff --git a/decompiler/main.cpp b/decompiler/main.cpp index 46240f0129..67d1c144be 100644 --- a/decompiler/main.cpp +++ b/decompiler/main.cpp @@ -155,13 +155,6 @@ int main(int argc, char** argv) { config.write_hex_near_instructions); } - // regenerate all-types if needed - if (config.regenerate_all_types) { - db.analyze_functions_ir1(config); - file_util::write_text_file(file_util::combine_path(out_folder, "type_defs.gc"), - db.all_type_defs); - } - // main decompile. if (config.decompile_code) { db.analyze_functions_ir2(out_folder, config, {}); diff --git a/test/offline/offline_test_main.cpp b/test/offline/offline_test_main.cpp index 2641731d2f..27bb5e5e61 100644 --- a/test/offline/offline_test_main.cpp +++ b/test/offline/offline_test_main.cpp @@ -199,7 +199,7 @@ Decompiler setup_decompiler(const std::vector& files, std::vector dgo_paths; if (args.iso_data_path.empty()) { for (auto& x : offline_config.dgos) { - dgo_paths.push_back((file_util::get_jak_project_dir() / "iso_data" / "jak1").string()); + dgo_paths.push_back((file_util::get_jak_project_dir() / "iso_data" / "jak1" / x).string()); } } else { for (auto& x : offline_config.dgos) {