remove old ir1 code (#1287)

This commit is contained in:
water111
2022-04-09 11:46:56 -04:00
committed by GitHub
parent 2d32d2aba5
commit f341be65e9
19 changed files with 2 additions and 5025 deletions
-4
View File
@@ -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
-5
View File
@@ -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<int> pred;
-31
View File
@@ -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<IR_Atomic> 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<IR_Atomic> 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<IR_Failed*>(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
-10
View File
@@ -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<IR_Atomic> 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<IR_Atomic> 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> 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<std::shared_ptr<IR_Atomic>> basic_ops;
struct {
bool atomic_ops_attempted = false;
-848
View File
@@ -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 #<my-struct @ #x~X>~%
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_IntegerConstant*>(ir);
return as_int && as_int->value == value;
}
bool is_reg(IR* ir, Register reg) {
auto as_reg = dynamic_cast<IR_Register*>(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_IntMath2*>(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_Load*>(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_Set*>(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<IR_Set*>(load);
ASSERT(as_set);
auto as_load = dynamic_cast<IR_Load*>(as_set->src.get());
ASSERT(as_load);
LoadInfo info;
info.kind = as_load->kind;
info.size = as_load->size;
if (dynamic_cast<IR_Register*>(as_load->location.get())) {
info.offset = 0;
return info;
}
auto as_math = dynamic_cast<IR_IntMath2*>(as_load->location.get());
ASSERT(as_math);
ASSERT(as_math->kind == IR_IntMath2::ADD);
auto as_int = dynamic_cast<IR_IntegerConstant*>(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<IR_Register*>(load->location.get());
if (as_reg) {
return as_reg->reg;
}
auto as_math = dynamic_cast<IR_IntMath2*>(load->location.get());
ASSERT(as_math->kind == IR_IntMath2::ADD);
ASSERT(dynamic_cast<IR_IntegerConstant*>(as_math->arg1.get()));
auto math_reg = dynamic_cast<IR_Register*>(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_Load*>(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_Set*>(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_Set*>(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_SymbolValue*>(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_Symbol*>(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_Set*>(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_Set*>(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_StaticAddress*>(ir);
}
bool is_get_label(IR* ir, Register dst) {
auto as_set = dynamic_cast<IR_Set*>(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<IR_StaticAddress*>(dynamic_cast<IR_Set*>(ir)->src.get())->label_id;
}
bool is_set_shift(IR* ir) {
auto as_set = dynamic_cast<IR_Set*>(ir);
if (as_set) {
auto as_math = dynamic_cast<IR_IntMath2*>(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_AsmOp*>(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<IR_IntegerConstant*>(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_Set*>(ir);
if (!as_set) {
return false;
}
if (!is_reg(as_set->dst.get(), dst)) {
return false;
}
auto as_math = dynamic_cast<IR_IntMath2*>(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<IR_Call*>(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<IR_Call*>(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<IR_Call*>(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
-40
View File
@@ -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 <vector>
#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<Field> 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
File diff suppressed because it is too large Load Diff
-15
View File
@@ -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
-1006
View File
File diff suppressed because it is too large Load Diff
-454
View File
@@ -1,454 +0,0 @@
#pragma once
#ifndef JAK_IR_H
#define JAK_IR_H
#include <utility>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#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<std::shared_ptr<IR>> get_all_ir(LinkedObjectFile& file) const;
std::string print(const LinkedObjectFile& file) const;
virtual void get_children(std::vector<std::shared_ptr<IR>>* output) const = 0;
bool is_basic_op = false;
virtual ~IR() = default;
};
class IR_Atomic : public virtual IR {
public:
std::vector<Register> read_regs, write_regs, clobber_regs;
std::unordered_set<Register, Register::hash> consumed, written_and_unused;
bool reg_info_set = false;
TypeState end_types; // types at the end of this instruction
std::vector<std::string> 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<std::shared_ptr<IR>>* 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<std::shared_ptr<IR>>* 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<IR> _dst, std::shared_ptr<IR> _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<std::shared_ptr<IR>>* output) const override;
std::shared_ptr<IR> dst, src;
std::shared_ptr<IR> clobber = nullptr;
};
// todo
class IR_Set_Atomic : public IR_Set, public IR_Atomic {
public:
IR_Set_Atomic(IR_Set::Kind _kind, std::shared_ptr<IR> _dst, std::shared_ptr<IR> _src)
: IR_Set(_kind, std::move(_dst), std::move(_src)) {}
template <typename T>
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<IR_IntMath2>(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<IR> _dst, std::shared_ptr<IR> _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<IR> _dst, std::shared_ptr<IR> _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<std::shared_ptr<IR>>* 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<std::shared_ptr<IR>>* 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<std::shared_ptr<IR>>* 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<std::shared_ptr<IR>>* 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<IR> _location)
: kind(_kind), size(_size), location(std::move(_location)) {}
int size;
std::shared_ptr<IR> location;
goos::Object to_form(const LinkedObjectFile& file) const override;
void get_children(std::vector<std::shared_ptr<IR>>* 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<IR> load_path_base = nullptr;
bool load_path_set = false;
bool load_path_addr_of = false;
std::vector<std::string> 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<IR> _arg0, std::shared_ptr<IR> _arg1)
: kind(_kind), arg0(std::move(_arg0)), arg1(std::move(_arg1)) {}
std::shared_ptr<IR> arg0, arg1;
goos::Object to_form(const LinkedObjectFile& file) const override;
void get_children(std::vector<std::shared_ptr<IR>>* 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<IR> _arg) : kind(_kind), arg(std::move(_arg)) {}
std::shared_ptr<IR> arg;
goos::Object to_form(const LinkedObjectFile& file) const override;
void get_children(std::vector<std::shared_ptr<IR>>* 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<IR> _arg0, std::shared_ptr<IR> _arg1)
: kind(_kind), arg0(std::move(_arg0)), arg1(std::move(_arg1)) {}
std::shared_ptr<IR> arg0, arg1;
goos::Object to_form(const LinkedObjectFile& file) const override;
void get_children(std::vector<std::shared_ptr<IR>>* output) const override;
};
class IR_IntMath1 : public virtual IR {
public:
enum Kind { NOT, ABS, NEG } kind;
IR_IntMath1(Kind _kind, std::shared_ptr<IR> _arg) : kind(_kind), arg(std::move(_arg)) {}
IR_IntMath1(Kind _kind, std::shared_ptr<IR> _arg, std::shared_ptr<IR_Atomic> _abs_op)
: kind(_kind), arg(std::move(_arg)), abs_op(std::move(_abs_op)) {
ASSERT(abs_op);
}
std::shared_ptr<IR> arg;
std::shared_ptr<IR_Atomic> abs_op = nullptr;
goos::Object to_form(const LinkedObjectFile& file) const override;
void get_children(std::vector<std::shared_ptr<IR>>* 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<std::shared_ptr<IR>>* output) const override;
std::vector<std::shared_ptr<IR>> 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<std::shared_ptr<IR>>* 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<IR> 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<std::shared_ptr<IR>>* output) const;
std::vector<Register> read_regs;
std::vector<Register> write_regs;
std::vector<Register> 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<IR> _src0,
std::shared_ptr<IR> _src1,
std::shared_ptr<IR> _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<IR> src0, src1, clobber;
void get_children(std::vector<std::shared_ptr<IR>>* 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<std::shared_ptr<IR>>* 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<std::shared_ptr<IR>>* 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<std::shared_ptr<IR>>* 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<std::shared_ptr<IR>>* 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<std::shared_ptr<IR>>* output) const override;
};
class IR_AsmOp : public virtual IR {
public:
std::shared_ptr<IR> dst = nullptr;
std::shared_ptr<IR> src0 = nullptr;
std::shared_ptr<IR> src1 = nullptr;
std::shared_ptr<IR> 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<std::shared_ptr<IR>>* 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<IR> src = nullptr;
bool on_zero = false;
explicit IR_CMoveF(std::shared_ptr<IR> _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<std::shared_ptr<IR>>* 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<std::shared_ptr<IR>>* output) const override;
};
} // namespace decompiler
#endif // JAK_IR_H
@@ -6,7 +6,6 @@
#include <algorithm>
#include <cstring>
#include <numeric>
#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;
}
+1 -25
View File
@@ -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<std::string>& _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) {
-1
View File
@@ -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,
@@ -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"
-1
View File
@@ -54,7 +54,6 @@ Config read_config_file(const std::string& path_to_config_file,
}
config.disassemble_code = cfg.at("disassemble_code").get<bool>();
config.decompile_code = cfg.at("decompile_code").get<bool>();
config.regenerate_all_types = cfg.at("regenerate_all_types").get<bool>();
config.write_hex_near_instructions = cfg.at("write_hex_near_instructions").get<bool>();
config.write_scripts = cfg.at("write_scripts").get<bool>();
config.disassemble_data = cfg.at("disassemble_data").get<bool>();
-1
View File
@@ -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;
@@ -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,
-7
View File
@@ -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, {});
+1 -1
View File
@@ -199,7 +199,7 @@ Decompiler setup_decompiler(const std::vector<DecompilerFile>& files,
std::vector<std::string> 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) {