Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[decompiler] Use meters, degrees, and seconds #689

Merged
merged 2 commits into from
Jul 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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