Skip to content

Commit

Permalink
Add decompiler IR, basic operations, all-types file (#57)
Browse files Browse the repository at this point in the history
* framework for basic op

* started IR framework

* check in type info file

* add some basic operations to the first pass ir conversion

* use a single condition system

* add more basic op decoding

* more ir
  • Loading branch information
water111 authored Sep 30, 2020
1 parent c9b53d5 commit 376c273
Show file tree
Hide file tree
Showing 37 changed files with 10,346 additions and 392 deletions.
36 changes: 18 additions & 18 deletions common/type_system/deftype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,24 +78,6 @@ int64_t get_int(const goos::Object& obj) {
throw std::runtime_error(obj.print() + " was supposed to be an integer, but isn't");
}

TypeSpec parse_typespec(TypeSystem* type_system, const goos::Object& src) {
if (src.is_symbol()) {
return type_system->make_typespec(symbol_string(src));
} else if (src.is_pair()) {
TypeSpec ts = type_system->make_typespec(symbol_string(car(&src)));
const auto& rest = *cdr(&src);

for_each_in_list(rest,
[&](const goos::Object& o) { ts.add_arg(parse_typespec(type_system, o)); });

return ts;
} else {
throw std::runtime_error("invalid typespec: " + src.print());
}
assert(false);
return {};
}

void add_field(StructureType* structure, TypeSystem* ts, const goos::Object& def) {
auto rest = &def;

Expand Down Expand Up @@ -278,6 +260,24 @@ TypeFlags parse_structure_def(StructureType* type,

} // namespace

TypeSpec parse_typespec(TypeSystem* type_system, const goos::Object& src) {
if (src.is_symbol()) {
return type_system->make_typespec(symbol_string(src));
} else if (src.is_pair()) {
TypeSpec ts = type_system->make_typespec(symbol_string(car(&src)));
const auto& rest = *cdr(&src);

for_each_in_list(rest,
[&](const goos::Object& o) { ts.add_arg(parse_typespec(type_system, o)); });

return ts;
} else {
throw std::runtime_error("invalid typespec: " + src.print());
}
assert(false);
return {};
}

DeftypeResult parse_deftype(const goos::Object& deftype, TypeSystem* ts) {
auto iter = &deftype;

Expand Down
1 change: 1 addition & 0 deletions common/type_system/deftype.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ struct DeftypeResult {
};

DeftypeResult parse_deftype(const goos::Object& deftype, TypeSystem* ts);
TypeSpec parse_typespec(TypeSystem* type_system, const goos::Object& src);
2 changes: 1 addition & 1 deletion decomp.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
# Directory of this script
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

$DIR/build/decompiler/decompiler $DIR/decompiler/config/jak1_ntsc_black_label.jsonc $DIR/iso_data $DIR/decompiler_out
$DIR/build/decompiler/decompiler $DIR/decompiler/config/jak1_ntsc_black_label.jsonc $DIR/iso_data $DIR/decompiler_out
13 changes: 7 additions & 6 deletions decompiler/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ add_executable(decompiler
util/FileIO.cpp
config.cpp
util/LispPrint.cpp
util/DecompilerTypeSystem.cpp
Function/BasicBlocks.cpp
Disasm/InstructionMatching.cpp
TypeSystem/GoalType.cpp
TypeSystem/GoalFunction.cpp
TypeSystem/GoalSymbol.cpp
TypeSystem/TypeInfo.cpp
TypeSystem/TypeSpec.cpp Function/CfgVtx.cpp Function/CfgVtx.h)
Function/CfgVtx.cpp Function/CfgVtx.h
IR/BasicOpBuilder.cpp
IR/IR.cpp)

target_link_libraries(decompiler
minilzo
common_util)
common_util
type_system
fmt)
6 changes: 6 additions & 0 deletions decompiler/Disasm/Instruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ struct InstructionAtom {
std::string to_string(const LinkedObjectFile& file) const;

bool is_link_or_label() const;
bool is_reg() const { return kind == REGISTER; }
bool is_imm() const { return kind == IMM; }
bool is_label() const { return kind == LABEL; }
bool is_sym() const { return kind == IMM_SYM; }

bool is_reg(Register r) const { return kind == REGISTER && reg == r; }

private:
int32_t imm;
Expand Down
5 changes: 5 additions & 0 deletions decompiler/Disasm/InstructionMatching.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
#pragma once

/*!
* @file InstructionMatching.h
* Utilities for checking if an instruction matches some criteria.
*/

#ifndef JAK_DISASSEMBLER_INSTRUCTIONMATCHING_H
#define JAK_DISASSEMBLER_INSTRUCTIONMATCHING_H

Expand Down
5 changes: 5 additions & 0 deletions decompiler/Disasm/OpcodeInfo.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/*!
* @file OpcodeInfo.cpp
* Decoding info for each opcode.
*/

#include "OpcodeInfo.h"
#include <cassert>

Expand Down
5 changes: 0 additions & 5 deletions decompiler/Function/BasicBlocks.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
#pragma once

#ifndef JAK_DISASSEMBLER_BASICBLOCKS_H
#define JAK_DISASSEMBLER_BASICBLOCKS_H

#include <vector>
#include <memory>

Expand All @@ -21,5 +18,3 @@ struct BasicBlock {
std::vector<BasicBlock> find_blocks_in_function(const LinkedObjectFile& file,
int seg,
const Function& func);

#endif // JAK_DISASSEMBLER_BASICBLOCKS_H
14 changes: 2 additions & 12 deletions decompiler/Function/CfgVtx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1637,7 +1637,6 @@ void ControlFlowGraph::flag_early_exit(const std::vector<BasicBlock>& blocks) {
* Build and resolve a Control Flow Graph as much as possible.
*/
std::shared_ptr<ControlFlowGraph> build_cfg(const LinkedObjectFile& file, int seg, Function& func) {
printf("build cfg : %s\n", func.guessed_name.to_string().c_str());
auto cfg = std::make_shared<ControlFlowGraph>();

const auto& blocks = cfg->create_blocks(func.basic_blocks.size());
Expand Down Expand Up @@ -1716,25 +1715,16 @@ std::shared_ptr<ControlFlowGraph> build_cfg(const LinkedObjectFile& file, int se

cfg->flag_early_exit(func.basic_blocks);

// if(func.guessed_name.to_string() == "(method 9 thread)")
// cfg->find_cond_w_else();

// if (func.guessed_name.to_string() != "looping-code") {
// return cfg;
// }

bool changed = true;
while (changed) {
changed = false;
// note - we should prioritize finding short-circuiting expressions.
// printf("%s\n", cfg->to_dot().c_str());
// printf("%s\n", cfg->to_form()->toStringPretty().c_str());

changed = changed | cfg->find_cond_w_else();
changed = changed | cfg->find_cond_n_else();
changed = changed || cfg->find_cond_w_else();
changed = changed || cfg->find_cond_n_else();
changed = changed || cfg->find_while_loop_top_level();
// //// printf("while loops? %d\n", changed);
//// changed = changed || cfg->find_if_else_top_level();
changed = changed || cfg->find_seq_top_level();
changed = changed || cfg->find_short_circuits();

Expand Down
45 changes: 42 additions & 3 deletions decompiler/Function/Function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#include "Function.h"
#include "decompiler/Disasm/InstructionMatching.h"
#include "decompiler/ObjectFile/LinkedObjectFile.h"
#include "decompiler/TypeSystem/TypeInfo.h"
#include "decompiler/util/DecompilerTypeSystem.h"

namespace {
std::vector<Register> gpr_backups = {make_gpr(Reg::GP), make_gpr(Reg::S5), make_gpr(Reg::S4),
Expand Down Expand Up @@ -418,7 +418,7 @@ void Function::check_epilogue(const LinkedObjectFile& file) {
*
* Updates the guessed_name of the function and updates type_info
*/
void Function::find_global_function_defs(LinkedObjectFile& file) {
void Function::find_global_function_defs(LinkedObjectFile& file, DecompilerTypeSystem& dts) {
int state = 0;
int label_id = -1;
Register reg;
Expand Down Expand Up @@ -457,7 +457,8 @@ void Function::find_global_function_defs(LinkedObjectFile& file) {
auto& func = file.get_function_at_label(label_id);
assert(func.guessed_name.empty());
func.guessed_name.set_as_global(name);
get_type_info().inform_symbol(name, TypeSpec("function"));
dts.add_symbol(name, "function");
;
// todo - inform function.
}

Expand Down Expand Up @@ -549,4 +550,42 @@ void Function::find_method_defs(LinkedObjectFile& file) {
}
}
}
}

void Function::add_basic_op(std::shared_ptr<IR> 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()) {
auto start_instr = basic_op_to_instruction.at(op->second);
return start_instr == idx;
}
return false;
}

IR* Function::get_basic_op_at_instr(int idx) {
return basic_ops.at(instruction_to_basic_op.at(idx)).get();
}

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;
}
14 changes: 13 additions & 1 deletion decompiler/Function/Function.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
#include "decompiler/Disasm/Instruction.h"
#include "BasicBlocks.h"
#include "CfgVtx.h"
#include "decompiler/IR/IR.h"

class DecompilerTypeSystem;

struct FunctionName {
enum class FunctionKind {
Expand Down Expand Up @@ -60,8 +63,14 @@ class Function {
public:
Function(int _start_word, int _end_word);
void analyze_prologue(const LinkedObjectFile& file);
void find_global_function_defs(LinkedObjectFile& file);
void find_global_function_defs(LinkedObjectFile& file, DecompilerTypeSystem& dts);
void find_method_defs(LinkedObjectFile& file);
void add_basic_op(std::shared_ptr<IR> op, int start_instr, int end_instr);
bool has_basic_ops() { return !basic_ops.empty(); }
bool instr_starts_basic_op(int idx);
IR* get_basic_op_at_instr(int idx);
int get_basic_op_count();
int get_failed_basic_op_count();

int segment = -1;
int start_word = -1;
Expand Down Expand Up @@ -115,6 +124,9 @@ class Function {

private:
void check_epilogue(const LinkedObjectFile& file);
std::vector<std::shared_ptr<IR>> basic_ops;
std::unordered_map<int, int> instruction_to_basic_op;
std::unordered_map<int, int> basic_op_to_instruction;
};

#endif // NEXT_FUNCTION_H
Loading

0 comments on commit 376c273

Please sign in to comment.