Skip to content

Commit

Permalink
[decompiler] Use meters, degrees, and seconds (#689)
Browse files Browse the repository at this point in the history
* use meters degrees and seconds

* update changelog
  • Loading branch information
water111 authored Jul 11, 2021
1 parent d508c40 commit 0a9cc68
Show file tree
Hide file tree
Showing 55 changed files with 939 additions and 742 deletions.
8 changes: 4 additions & 4 deletions common/goal_constants.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
#pragma once

#ifndef JAK_GOAL_CONSTANTS_H
#define JAK_GOAL_CONSTANTS_H

#include "common_types.h"

constexpr s32 BINTEGER_OFFSET = 0;
Expand Down Expand Up @@ -36,4 +33,7 @@ constexpr u64 EE_MAIN_MEM_MAP = 0x2123000000; // intentionally > 32-bit to
// so this should be used only for debugging.
constexpr bool EE_MEM_LOW_MAP = false;

#endif // JAK_GOAL_CONSTANTS_H
constexpr double METER_LENGTH = 4096.0;
constexpr double DEGREES_PER_ROT = 65536.0;
constexpr double DEGREES_LENGTH = DEGREES_PER_ROT / 360.0;
constexpr u64 TICKS_PER_SECOND = 300.0;
24 changes: 23 additions & 1 deletion common/type_system/TypeSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,13 @@ void TypeSystem::add_builtin_types() {
add_builtin_value_type("uinteger", "uint64", 8);
add_builtin_value_type("uinteger", "uint128", 16, false, false, RegClass::INT_128);

// add special units types.
add_builtin_value_type("float", "meters", 4, false, false, RegClass::FLOAT)
->set_runtime_type("float");
add_builtin_value_type("float", "degrees", 4, false, false, RegClass::FLOAT)
->set_runtime_type("float");
add_builtin_value_type("uint64", "seconds", 8, false, false)->set_runtime_type("uint64");

auto int_type = add_builtin_value_type("integer", "int", 8, false, true);
int_type->disallow_in_runtime();
auto uint_type = add_builtin_value_type("uinteger", "uint", 8, false, false);
Expand Down Expand Up @@ -1352,8 +1359,23 @@ bool TypeSystem::typecheck_and_throw(const TypeSpec& expected,
/*!
* Is actual of type expected? For base types.
*/
bool TypeSystem::typecheck_base_types(const std::string& expected,
bool TypeSystem::typecheck_base_types(const std::string& input_expected,
const std::string& actual) const {
std::string expected = input_expected;

// the unit types aren't picky.
if (expected == "meters") {
expected = "float";
}

if (expected == "seconds") {
expected = "uint";
}

if (expected == "degrees") {
expected = "float";
}

// just to make sure it exists.
lookup_type_allow_partial_def(expected);

Expand Down
2 changes: 1 addition & 1 deletion decompiler/IR2/AtomicOpTypeAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,7 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input,
if (m_kind == Kind::ADD && tc(dts, TypeSpec("structure"), arg0_type) &&
arg1_type.is_integer_constant()) {
auto type_info = dts.ts.lookup_type(arg0_type.typespec());
if (type_info->get_size_in_memory() == arg1_type.get_integer_constant()) {
if ((u64)type_info->get_size_in_memory() == arg1_type.get_integer_constant()) {
return TP_Type::make_from_ts(arg0_type.typespec());
}
}
Expand Down
7 changes: 6 additions & 1 deletion decompiler/IR2/Form.h
Original file line number Diff line number Diff line change
Expand Up @@ -1274,6 +1274,7 @@ class ConstantFloatElement : public FormElement {
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) override;
float value() const { return m_value; }

private:
float m_value;
Expand Down Expand Up @@ -1770,5 +1771,9 @@ GenericElement* alloc_generic_token_op(const std::string& name,
const std::vector<Form*>& args,
FormPool& pool);
Form* alloc_var_form(const RegisterAccess& var, FormPool& pool);
Form* try_cast_simplify(Form* in, const TypeSpec& new_type, FormPool& pool, const Env& env);
Form* try_cast_simplify(Form* in,
const TypeSpec& new_type,
FormPool& pool,
const Env& env,
bool tc_pass = false);
} // namespace decompiler
78 changes: 67 additions & 11 deletions decompiler/IR2/FormExpressionAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,59 @@ Form* strip_pcypld_64(Form* in) {
return in;
}
}

std::optional<float> get_goal_float_constant(Form* in) {
auto as_fc = in->try_as_element<ConstantFloatElement>();
if (as_fc) {
return as_fc->value();
}
return {};
}
} // namespace

Form* try_cast_simplify(Form* in, const TypeSpec& new_type, FormPool& pool, const Env& env) {
Form* try_cast_simplify(Form* in,
const TypeSpec& new_type,
FormPool& pool,
const Env& env,
bool tc_pass) {
auto in_as_cast = dynamic_cast<CastElement*>(in->try_as_single_element());
if (in_as_cast && in_as_cast->type() == new_type) {
return in; // no need to cast again, it already has it!
}

if (new_type == TypeSpec("meters")) {
auto fc = get_goal_float_constant(in);

if (fc) {
double div = (double)*fc / METER_LENGTH; // GOOS will use doubles here
if (div * METER_LENGTH == *fc) {
return pool.alloc_single_element_form<GenericElement>(
nullptr,
GenericOperator::make_function(
pool.alloc_single_element_form<ConstantTokenElement>(nullptr, "meters")),
pool.alloc_single_element_form<ConstantFloatElement>(nullptr, div));
} else {
lg::error("Floating point value {} could not be converted to meters.", *fc);
}
}
}

if (new_type == TypeSpec("degrees")) {
auto fc = get_goal_float_constant(in);
if (fc) {
double div = (double)*fc / DEGREES_LENGTH; // GOOS will use doubles here
if (div * DEGREES_LENGTH == *fc) {
return pool.alloc_single_element_form<GenericElement>(
nullptr,
GenericOperator::make_function(
pool.alloc_single_element_form<ConstantTokenElement>(nullptr, "degrees")),
pool.alloc_single_element_form<ConstantFloatElement>(nullptr, div));
} else {
lg::error("Floating point value {} could not be converted to degrees.", *fc);
}
}
}

auto type_info = env.dts->ts.lookup_type(new_type);
auto bitfield_info = dynamic_cast<BitFieldType*>(type_info);
if (bitfield_info) {
Expand All @@ -91,7 +136,11 @@ Form* try_cast_simplify(Form* in, const TypeSpec& new_type, FormPool& pool, cons
}
}

return nullptr;
if (tc_pass) {
return in;
} else {
return nullptr;
}
}

bool Form::has_side_effects() {
Expand Down Expand Up @@ -285,8 +334,12 @@ void pop_helper(const std::vector<RegisterAccess>& vars,
/*!
* This should be used to generate all casts.
*/
Form* cast_form(Form* in, const TypeSpec& new_type, FormPool& pool, const Env& env) {
auto result = try_cast_simplify(in, new_type, pool, env);
Form* cast_form(Form* in,
const TypeSpec& new_type,
FormPool& pool,
const Env& env,
bool tc_pass = false) {
auto result = try_cast_simplify(in, new_type, pool, env, tc_pass);
if (result) {
return result;
}
Expand Down Expand Up @@ -340,15 +393,12 @@ std::vector<Form*> pop_to_forms(const std::vector<RegisterAccess>& vars,
return forms;
}

// TODO - if we start using child classes of float/int/uint for things like degrees/meters
// we may need to adjust these.

/*!
* type == float (exactly)?
*/
bool is_float_type(const Env& env, int my_idx, RegisterAccess var) {
auto type = env.get_types_before_op(my_idx).get(var.reg()).typespec();
return type == TypeSpec("float");
return env.dts->ts.tc(TypeSpec("float"), type);
}

/*!
Expand Down Expand Up @@ -436,6 +486,10 @@ Form* make_cast_if_needed(Form* in,
if (in_type == out_type) {
return in;
}

if (out_type == TypeSpec("float") && env.dts->ts.tc(TypeSpec("float"), in_type)) {
return in;
}
return cast_form(in, out_type, pool, env);
}

Expand Down Expand Up @@ -548,7 +602,8 @@ void SimpleExpressionElement::update_from_stack_fpr_to_gpr(const Env& env,
bool allow_side_effects) {
auto src = m_expr.get_arg(0);
auto src_type = env.get_types_before_op(m_my_idx).get(src.var().reg());
if (src_type.typespec() == TypeSpec("float") || src_type.typespec() == TypeSpec("int")) {
if (env.dts->ts.tc(TypeSpec("float"), src_type.typespec()) ||
src_type.typespec() == TypeSpec("int")) {
// set ourself to identity.
m_expr = src.as_expr();
// then go again.
Expand Down Expand Up @@ -2229,8 +2284,9 @@ void FunctionCallElement::update_from_stack(const Env& env,
}

auto desired_arg_type = function_type.get_arg(arg_id);
if (!env.dts->ts.tc(desired_arg_type, actual_arg_type)) {
arg_forms.push_back(cast_form(val, desired_arg_type, pool, env));
if (env.dts->should_attempt_cast_simplify(desired_arg_type, actual_arg_type)) {
arg_forms.push_back(cast_form(val, desired_arg_type, pool, env,
env.dts->ts.tc(desired_arg_type, actual_arg_type)));
} else {
arg_forms.push_back(val);
}
Expand Down
Loading

0 comments on commit 0a9cc68

Please sign in to comment.