[Decomp] Math library: transform and quaternion (#344)

* decompile transform

* types for quaternion

* part of quaternion

* finish quaternion

* fix offline test reference

* wip fix to let issue

* fix
This commit is contained in:
water111
2021-04-02 11:35:14 -04:00
committed by GitHub
parent 7867de8fd7
commit 9969445cf7
44 changed files with 3485 additions and 459 deletions
+50 -3
View File
@@ -342,6 +342,12 @@ Form* make_cast(Form* in, const TypeSpec& in_type, const TypeSpec& out_type, For
if (in_type == out_type) {
return in;
}
auto in_as_cast = dynamic_cast<CastElement*>(in->try_as_single_element());
if (in_as_cast && in_as_cast->type() == out_type) {
return in;
}
return pool.alloc_single_element_form<CastElement>(nullptr, out_type, in);
}
@@ -378,7 +384,10 @@ void SimpleExpressionElement::update_from_stack_identity(const Env& env,
bool allow_side_effects) {
auto& arg = m_expr.get_arg(0);
if (arg.is_var()) {
pop_helper({arg.var()}, env, pool, stack, {result}, allow_side_effects);
auto forms = pop_to_forms({arg.var()}, env, pool, stack, allow_side_effects);
for (auto x : forms.at(0)->elts()) {
result->push_back(x);
}
} else if (arg.is_static_addr()) {
auto lab = env.file->labels.at(arg.label());
if (env.file->is_string(lab.target_segment, lab.offset)) {
@@ -422,7 +431,10 @@ void SimpleExpressionElement::update_from_stack_gpr_to_fpr(const Env& env,
auto src_type = env.get_types_before_op(src.var().idx()).get(src.var().reg());
std::vector<FormElement*> src_fes;
if (src.is_var()) {
pop_helper({src.var()}, env, pool, stack, {&src_fes}, allow_side_effects);
auto forms = pop_to_forms({src.var()}, env, pool, stack, allow_side_effects);
for (auto x : forms.at(0)->elts()) {
src_fes.push_back(x);
}
} else {
src_fes = {this};
}
@@ -966,6 +978,10 @@ void SimpleExpressionElement::update_from_stack(const Env& env,
update_from_stack_force_si_2(env, FixedOperatorKind::MOD, pool, stack, result,
allow_side_effects, false);
break;
case SimpleExpression::Kind::MOD_UNSIGNED:
update_from_stack_force_ui_2(env, FixedOperatorKind::MOD, pool, stack, result,
allow_side_effects);
break;
case SimpleExpression::Kind::MIN_SIGNED:
update_from_stack_force_si_2(env, FixedOperatorKind::MIN, pool, stack, result,
allow_side_effects, false);
@@ -1145,6 +1161,11 @@ void StoreInPairElement::push_to_stack(const Env& env, FormPool& pool, FormStack
namespace {
Form* make_optional_cast(const std::optional<TypeSpec>& cast_type, Form* in, FormPool& pool) {
if (cast_type) {
auto in_as_cast = dynamic_cast<CastElement*>(in->try_as_single_element());
if (in_as_cast && in_as_cast->type() == cast_type) {
return in;
}
return pool.alloc_single_element_form<CastElement>(nullptr, *cast_type, in);
} else {
return in;
@@ -1768,6 +1789,7 @@ void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStac
// check all to see if they write the value.
std::vector<SetVarElement*> dest_sets;
std::vector<TypeSpec> source_types; // only explicit accesses that aren't move-eliminated
for (auto form : write_output_forms) {
auto last_in_body = dynamic_cast<SetVarElement*>(form->elts().back());
if (last_in_body) {
@@ -1777,6 +1799,7 @@ void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStac
rewrite_as_set = false;
break;
}
source_types.push_back(last_in_body->src_type());
}
last_var = last_in_body->dst();
} // For now, I am fine with letting this fail. For example, if the set is eliminated by a
@@ -1822,7 +1845,31 @@ void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStac
if (set_unused) {
stack.push_form_element(this, true);
} else {
stack.push_value_to_reg(*last_var, pool.alloc_single_form(nullptr, this), true,
// We may need to insert a cast here.
// Note:
// I think this might skip a cast if you have something like
// (set! x (if y z (expr))) and z requires a cast, but the move from z to x is
// eliminated by GOAL's register allocator.
// fmt::print("checking:\n");
// for (auto& t : source_types) {
// fmt::print(" {}\n", t.print());
// }
auto expected_type = env.get_variable_type(*last_var, true);
// fmt::print("The expected type is {}\n", expected_type.print());
auto result_type =
source_types.empty() ? expected_type : env.dts->ts.lowest_common_ancestor(source_types);
// fmt::print("but we actually got {}\n", result_type.print());
Form* result_value = pool.alloc_single_form(nullptr, this);
if (!env.dts->ts.tc(expected_type, result_type)) {
result_value =
pool.alloc_single_element_form<CastElement>(nullptr, expected_type, result_value);
}
stack.push_value_to_reg(*last_var, result_value, true,
env.get_variable_type(*last_var, false));
}
} else {