mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 11:26:18 -04:00
started sc recognize, but ash min and max should be recognized first
This commit is contained in:
parent
5bcd10b5b0
commit
e195e2b299
|
@ -130,6 +130,29 @@ void clean_up_cond_with_else(std::shared_ptr<IR>* ir, LinkedObjectFile& file) {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* before we do this we'll have to to recognize ash...
|
||||
|
||||
bool try_clean_up_sc_as_and(const std::shared_ptr<IR_ShortCircuit>& ir) {
|
||||
for(size_t i = 0; i < ir->entries.size(); i++) {
|
||||
auto& e = ir->entries.at(i);
|
||||
if (i < ir->entries.size() - 1) {
|
||||
// check we load the delay slot with false
|
||||
auto branch = get_condition_branch(&e.condition);
|
||||
assert(branch.first);
|
||||
}
|
||||
}
|
||||
// ir->kind = IR_ShortCircuit::AND;
|
||||
// return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void clean_up_sc(std::shared_ptr<IR_ShortCircuit> ir) {
|
||||
assert(ir->entries.size() > 1);
|
||||
//try_clean_up_sc_as_and(ir);
|
||||
}
|
||||
*/
|
||||
|
||||
/*!
|
||||
* A GOAL comparison which produces a boolean is recognized as a cond-no-else by the CFG analysis.
|
||||
* But it should not be decompiled as a branching statement.
|
||||
|
@ -153,7 +176,11 @@ void convert_cond_no_else_to_compare(std::shared_ptr<IR>* ir) {
|
|||
// as far as I can tell this is totally valid but just happens to not appear?
|
||||
// if this case is ever hit in the future it's fine and we just need to implement this.
|
||||
// but leaving empty for now so there's fewer things to test.
|
||||
assert(false);
|
||||
// assert(false);
|
||||
|
||||
auto replacement = std::make_shared<IR_Set>(
|
||||
IR_Set::REG_64, dst, std::make_shared<IR_Compare>(condition.first->condition));
|
||||
*ir = replacement;
|
||||
} else {
|
||||
auto condition_as_seq = dynamic_cast<IR_Begin*>(cne->entries.front().condition.get());
|
||||
assert(condition_as_seq);
|
||||
|
@ -354,6 +381,43 @@ std::shared_ptr<IR> try_sc_as_type_of(Function& f, LinkedObjectFile& file, Short
|
|||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<IR> merge_cond_else_with_sc_cond(CondWithElse* cwe,
|
||||
const std::shared_ptr<IR>& else_ir,
|
||||
Function& f,
|
||||
LinkedObjectFile& file) {
|
||||
auto as_seq = dynamic_cast<IR_Begin*>(else_ir.get());
|
||||
if (!as_seq || as_seq->forms.size() != 2) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto first = dynamic_cast<IR_ShortCircuit*>(as_seq->forms.at(0).get());
|
||||
auto second = dynamic_cast<IR_Cond*>(as_seq->forms.at(1).get());
|
||||
if (!first || !second) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<IR_Cond::Entry> entries;
|
||||
for (auto& x : cwe->entries) {
|
||||
IR_Cond::Entry e;
|
||||
e.condition = cfg_to_ir(f, file, x.condition);
|
||||
e.body = cfg_to_ir(f, file, x.body);
|
||||
entries.push_back(std::move(e));
|
||||
}
|
||||
|
||||
auto first_condition = std::make_shared<IR_Begin>();
|
||||
first_condition->forms.push_back(as_seq->forms.at(0));
|
||||
first_condition->forms.push_back(second->entries.front().condition);
|
||||
|
||||
second->entries.front().condition = first_condition;
|
||||
|
||||
for (auto& x : second->entries) {
|
||||
entries.push_back(x);
|
||||
}
|
||||
std::shared_ptr<IR> result = std::make_shared<IR_Cond>(entries);
|
||||
clean_up_cond_no_else(&result, file);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Main CFG vertex to IR conversion. Will pull basic IR ops from the provided function as needed.
|
||||
*/
|
||||
|
@ -400,6 +464,10 @@ std::shared_ptr<IR> cfg_to_ir(Function& f, LinkedObjectFile& file, CfgVtx* vtx)
|
|||
// I don't know if this is sufficient to catch all cases. it may even recognize the wrong
|
||||
// thing in some cases... maybe we should check the delay slot instead?
|
||||
auto else_ir = cfg_to_ir(f, file, cvtx->else_vtx);
|
||||
auto fancy_compact_result = merge_cond_else_with_sc_cond(cvtx, else_ir, f, file);
|
||||
if (fancy_compact_result) {
|
||||
return fancy_compact_result;
|
||||
}
|
||||
|
||||
if (dynamic_cast<IR_Cond*>(else_ir.get())) {
|
||||
auto extra_cond = dynamic_cast<IR_Cond*>(else_ir.get());
|
||||
|
@ -430,10 +498,21 @@ std::shared_ptr<IR> cfg_to_ir(Function& f, LinkedObjectFile& file, CfgVtx* vtx)
|
|||
}
|
||||
} else if (dynamic_cast<ShortCircuit*>(vtx)) {
|
||||
auto* svtx = dynamic_cast<ShortCircuit*>(vtx);
|
||||
// try as a type of expression first
|
||||
auto as_type_of = try_sc_as_type_of(f, file, svtx);
|
||||
if (as_type_of) {
|
||||
return as_type_of;
|
||||
}
|
||||
// now try as a normal and/or
|
||||
std::vector<IR_ShortCircuit::Entry> entries;
|
||||
for (auto& x : svtx->entries) {
|
||||
IR_ShortCircuit::Entry e;
|
||||
e.condition = cfg_to_ir(f, file, x);
|
||||
entries.push_back(e);
|
||||
}
|
||||
auto result = std::make_shared<IR_ShortCircuit>(entries);
|
||||
clean_up_sc(result);
|
||||
return result;
|
||||
} else if (dynamic_cast<CondNoElse*>(vtx)) {
|
||||
auto* cvtx = dynamic_cast<CondNoElse*>(vtx);
|
||||
std::vector<IR_Cond::Entry> entries;
|
||||
|
|
|
@ -646,13 +646,32 @@ void IR_Cond::get_children(std::vector<std::shared_ptr<IR>>* output) const {
|
|||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Form> IR_PartialNot::to_form(const LinkedObjectFile& file) const {
|
||||
return buildList("INCOMPLETE-NOT", dst->to_form(file), src->to_form(file));
|
||||
std::shared_ptr<Form> IR_ShortCircuit::to_form(const LinkedObjectFile& file) const {
|
||||
std::vector<std::shared_ptr<Form>> forms;
|
||||
switch (kind) {
|
||||
case UNKNOWN:
|
||||
forms.push_back(toForm("unknown-sc"));
|
||||
break;
|
||||
case AND:
|
||||
forms.push_back(toForm("and"));
|
||||
break;
|
||||
case OR:
|
||||
forms.push_back(toForm("or"));
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
for (auto& x : entries) {
|
||||
forms.push_back(x.condition->to_form(file));
|
||||
}
|
||||
return buildList(forms);
|
||||
}
|
||||
|
||||
void IR_PartialNot::get_children(std::vector<std::shared_ptr<IR>>* output) const {
|
||||
// probably we could get away with not returning anything here because these should
|
||||
// always be registers?
|
||||
output->push_back(dst);
|
||||
output->push_back(src);
|
||||
}
|
||||
void IR_ShortCircuit::get_children(std::vector<std::shared_ptr<IR>>* output) const {
|
||||
for (auto& x : entries) {
|
||||
output->push_back(x.condition);
|
||||
if (x.output) {
|
||||
output->push_back(x.output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -306,7 +306,7 @@ class IR_Cond : public IR {
|
|||
bool cleaned = false;
|
||||
};
|
||||
std::vector<Entry> entries;
|
||||
IR_Cond(std::vector<Entry> _entries) : entries(std::move(_entries)) {}
|
||||
explicit IR_Cond(std::vector<Entry> _entries) : entries(std::move(_entries)) {}
|
||||
std::shared_ptr<Form> to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* output) const override;
|
||||
};
|
||||
|
@ -321,11 +321,18 @@ class IR_GetRuntimeType : public IR {
|
|||
void get_children(std::vector<std::shared_ptr<IR>>* output) const override;
|
||||
};
|
||||
|
||||
class IR_PartialNot : public IR {
|
||||
class IR_ShortCircuit : public IR {
|
||||
public:
|
||||
std::shared_ptr<IR> dst, src;
|
||||
IR_PartialNot(std::shared_ptr<IR> _dst, std::shared_ptr<IR> _src)
|
||||
: dst(std::move(_dst)), src(std::move(_src)) {}
|
||||
struct Entry {
|
||||
std::shared_ptr<IR> condition = nullptr;
|
||||
std::shared_ptr<IR> output = nullptr; // where the delay slot writes to.
|
||||
bool cleaned = false;
|
||||
};
|
||||
|
||||
enum Kind { UNKNOWN, AND, OR } kind = UNKNOWN;
|
||||
|
||||
std::vector<Entry> entries;
|
||||
explicit IR_ShortCircuit(std::vector<Entry> _entries) : entries(std::move(_entries)) {}
|
||||
std::shared_ptr<Form> to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* output) const override;
|
||||
};
|
||||
|
|
|
@ -606,7 +606,7 @@ void ObjectFileDB::analyze_functions() {
|
|||
timer.start();
|
||||
int total_basic_blocks = 0;
|
||||
for_each_function([&](Function& func, int segment_id, ObjectFileData& data) {
|
||||
printf("in %s\n", func.guessed_name.to_string().c_str());
|
||||
// printf("in %s\n", func.guessed_name.to_string().c_str());
|
||||
auto blocks = find_blocks_in_function(data.linked_data, segment_id, func);
|
||||
total_basic_blocks += blocks.size();
|
||||
func.basic_blocks = blocks;
|
||||
|
|
|
@ -42,9 +42,12 @@
|
|||
// this one fails due to false compaction where an else case has only a not expression in it.
|
||||
"master-is-hopeful-better?",
|
||||
|
||||
// temp remove me
|
||||
"target-falling-anim-trans",
|
||||
|
||||
// real asm
|
||||
"cspace<-parented-transformq-joint!", "blerc-a-fragment", "render-boundary-tri", "render-boundary-quad",
|
||||
"(method 19 collide-shape-prim-sphere)",
|
||||
"(method 19 collide-shape-prim-sphere)","vector-segment-distance-point!", "exp",
|
||||
|
||||
"(method 11 cpu-thread)", "atan0", "sincos!", "sincos-rad!", "disasm-dma-list", "vblank-handler", "vif1-handler",
|
||||
"vif1-handler-debug", "entity-actor-count", "decompress-frame-data-pair-to-accumulator",
|
||||
|
@ -52,7 +55,8 @@
|
|||
"generic-copy-vtx-dclr-dtex", "generic-no-light-dproc-only", "generic-no-light-proc", "mercneric-bittable-asm",
|
||||
"generic-tie-decompress", "matrix-axis-sin-cos!", "matrix-axis-sin-cos-vu!", "generic-prepare-dma-single",
|
||||
"(method 13 collide-shape-prim-sphere)", "(method 14 collide-shape-prim-sphere)", "(method 12 collide-shape-prim-sphere)",
|
||||
"adgif-shader<-texture-with-update!", "generic-interp-dproc",
|
||||
"adgif-shader<-texture-with-update!", "generic-interp-dproc", "sprite-draw-distorters", "draw-bones", "(method 9 collide-mesh-cache)",
|
||||
"(method 18 collide-shape-prim-sphere)",
|
||||
|
||||
"collide-do-primitives", "draw-bones-check-longest-edge-asm",
|
||||
"sp-launch-particles-var", "(method 15 collide-shape-prim-mesh)", "(method 15 collide-shape-prim-sphere)",
|
||||
|
|
Loading…
Reference in a new issue