add cond with else

This commit is contained in:
water
2020-10-03 09:32:26 -04:00
parent 072283e442
commit 0094594f69
4 changed files with 115 additions and 16 deletions
+72 -15
View File
@@ -64,6 +64,58 @@ void insert_cfg_into_list(Function& f,
}
}
std::pair<IR_Branch*, std::vector<std::shared_ptr<IR>>*> get_condition_branch_as_vector(IR* in) {
auto as_seq = dynamic_cast<IR_Begin*>(in);
if (as_seq) {
auto irb = dynamic_cast<IR_Branch*>(as_seq->forms.back().get());
auto loc = &as_seq->forms;
assert(irb);
return std::make_pair(irb, loc);
}
return std::make_pair(nullptr, nullptr);
}
std::pair<IR_Branch*, std::shared_ptr<IR>*> get_condition_branch(std::shared_ptr<IR>* in) {
IR_Branch* condition_branch = dynamic_cast<IR_Branch*>(in->get());
std::shared_ptr<IR>* condition_branch_location = in;
if (!condition_branch) {
// not 100% sure this will always work
auto as_seq = dynamic_cast<IR_Begin*>(in->get());
if (as_seq) {
condition_branch = dynamic_cast<IR_Branch*>(as_seq->forms.back().get());
condition_branch_location = &as_seq->forms.back();
}
}
return std::make_pair(condition_branch, condition_branch_location);
}
void clean_up_cond_with_else(IR_CondWithElse* cwe, LinkedObjectFile& file) {
for (auto& e : cwe->entries) {
auto jump_to_next = get_condition_branch(&e.condition);
assert(jump_to_next.first);
assert(jump_to_next.first->branch_delay.kind == BranchDelay::NOP);
printf("got cond condition %s\n", jump_to_next.first->print(file).c_str());
auto replacement = std::make_shared<IR_Compare>(jump_to_next.first->condition);
*(jump_to_next.second) = replacement;
auto jump_to_end = get_condition_branch(&e.body);
assert(jump_to_end.first);
assert(jump_to_end.first->branch_delay.kind == BranchDelay::NOP);
assert(jump_to_end.first->condition.kind == Condition::ALWAYS);
auto as_end_of_sequence = get_condition_branch_as_vector(e.body.get());
if (as_end_of_sequence.first) {
assert(as_end_of_sequence.second->size() > 1);
as_end_of_sequence.second->pop_back();
} else {
// this means the case is empty, which is a little bit weird but does actually appear to
// happen in a few places. so we just replace the jump with a nop. In the future we could
// consider having a more explicit "this case is empty" operator so this doesn't get confused
// with an actual MIPS nop.
*(jump_to_end.second) = std::make_shared<IR_Nop>();
}
}
}
std::shared_ptr<IR> cfg_to_ir(Function& f, LinkedObjectFile& file, CfgVtx* vtx) {
if (dynamic_cast<BlockVtx*>(vtx)) {
auto* bv = dynamic_cast<BlockVtx*>(vtx);
@@ -97,6 +149,19 @@ std::shared_ptr<IR> cfg_to_ir(Function& f, LinkedObjectFile& file, CfgVtx* vtx)
auto result = std::make_shared<IR_WhileLoop>(cfg_to_ir(f, file, wvtx->condition),
cfg_to_ir(f, file, wvtx->body));
return result;
} else if (dynamic_cast<CondWithElse*>(vtx)) {
auto* cvtx = dynamic_cast<CondWithElse*>(vtx);
std::vector<IR_CondWithElse::Entry> entries;
for (auto& x : cvtx->entries) {
IR_CondWithElse::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 else_ir = cfg_to_ir(f, file, cvtx->else_vtx);
auto result = std::make_shared<IR_CondWithElse>(entries, else_ir);
clean_up_cond_with_else(result.get(), file);
return result;
}
else {
@@ -121,22 +186,14 @@ void clean_up_while_loops(IR_Begin* sequence, LinkedObjectFile& file) {
to_remove.push_back(i - 1);
// now we should try to find the condition branch:
IR_Branch* condition_branch = dynamic_cast<IR_Branch*>(form_as_while->condition.get());
std::shared_ptr<IR>* condition_branch_location = &form_as_while->condition;
if (!condition_branch) {
// not 100% sure this will always work
auto as_seq = dynamic_cast<IR_Begin*>(form_as_while->condition.get());
if (as_seq) {
condition_branch = dynamic_cast<IR_Branch*>(as_seq->forms.back().get());
condition_branch_location = &as_seq->forms.back();
}
}
assert(condition_branch);
assert(condition_branch->branch_delay.kind == BranchDelay::NOP);
printf("got while condition branch %s\n", condition_branch->print(file).c_str());
auto replacement = std::make_shared<IR_Compare>(condition_branch->condition);
*condition_branch_location = replacement;
auto condition_branch = get_condition_branch(&form_as_while->condition);
assert(condition_branch.first);
assert(condition_branch.first->branch_delay.kind == BranchDelay::NOP);
printf("got while condition branch %s\n", condition_branch.first->print(file).c_str());
auto replacement = std::make_shared<IR_Compare>(condition_branch.first->condition);
*(condition_branch.second) = replacement;
}
}
+26
View File
@@ -493,6 +493,7 @@ std::shared_ptr<Form> IR_Begin::to_form(const LinkedObjectFile& file) const {
return buildList(list);
}
void IR_Begin::get_children(std::vector<std::shared_ptr<IR>>* output) const {
for (auto& x : forms) {
output->push_back(x);
@@ -525,4 +526,29 @@ std::shared_ptr<Form> IR_WhileLoop::to_form(const LinkedObjectFile& file) const
void IR_WhileLoop::get_children(std::vector<std::shared_ptr<IR>>* output) const {
output->push_back(condition);
output->push_back(body);
}
std::shared_ptr<Form> IR_CondWithElse::to_form(const LinkedObjectFile& file) const {
// todo - special case to print as if with else
std::vector<std::shared_ptr<Form>> list;
list.push_back(toForm("cond"));
for(auto& e : entries) {
std::vector<std::shared_ptr<Form>> entry;
entry.push_back(e.condition->to_form(file));
print_inlining_begin(&entry, e.body.get(), file);
list.push_back(buildList(entry));
}
std::vector<std::shared_ptr<Form>> else_form;
else_form.push_back(toForm("else"));
print_inlining_begin(&else_form, else_ir.get(), file);
list.push_back(buildList(else_form));
return buildList(list);
}
void IR_CondWithElse::get_children(std::vector<std::shared_ptr<IR>>* output) const {
for(auto& e : entries) {
output->push_back(e.condition);
output->push_back(e.body);
}
output->push_back(else_ir);
}
+14
View File
@@ -279,4 +279,18 @@ class IR_WhileLoop : public IR {
std::shared_ptr<IR> condition, body;
};
class IR_CondWithElse : public IR {
public:
struct Entry {
std::shared_ptr<IR> condition = nullptr;
std::shared_ptr<IR> body = nullptr;
};
std::vector<Entry> entries;
std::shared_ptr<IR> else_ir;
IR_CondWithElse(std::vector<Entry> _entries, std::shared_ptr<IR> _else_ir)
: entries(std::move(_entries)), else_ir(std::move(_else_ir)) {}
std::shared_ptr<Form> to_form(const LinkedObjectFile& file) const override;
void get_children(std::vector<std::shared_ptr<IR>>* output) const override;
};
#endif // JAK_IR_H
@@ -40,7 +40,9 @@
"vif1-handler-debug", "entity-actor-count", "decompress-frame-data-pair-to-accumulator",
"decompress-frame-data-to-accumulator", "normalize-frame-quaternions", "clear-frame-accumulator",
"generic-copy-vtx-dclr-dtex", "generic-no-light-dproc-only", "generic-no-light-proc", "mercneric-bittable-asm",
"generic-tie-decompress",
"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!",
"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)",