mirror of
https://github.com/open-goal/jak-project
synced 2026-08-03 17:02:47 -04:00
decompiler: detect and turn inverse mult to div
This commit is contained in:
+15
-1
@@ -57,6 +57,8 @@
|
||||
#include "common/util/Assert.h"
|
||||
#include "common/util/crc32.h"
|
||||
|
||||
#include "fmt/core.h"
|
||||
|
||||
namespace goos {
|
||||
|
||||
/*!
|
||||
@@ -234,10 +236,14 @@ class Object {
|
||||
|
||||
ObjectType type = ObjectType::INVALID;
|
||||
|
||||
private:
|
||||
bool disallow_hex_for_int = false;
|
||||
|
||||
public:
|
||||
std::string print() const {
|
||||
switch (type) {
|
||||
case ObjectType::INTEGER:
|
||||
return integer_obj.print();
|
||||
return disallow_hex_for_int ? fmt::format("{}", integer_obj.value) : integer_obj.print();
|
||||
case ObjectType::FLOAT:
|
||||
return float_obj.print();
|
||||
case ObjectType::CHAR:
|
||||
@@ -278,6 +284,14 @@ class Object {
|
||||
return o;
|
||||
}
|
||||
|
||||
static Object make_integer_no_hex(IntType value) {
|
||||
Object o;
|
||||
o.type = ObjectType::INTEGER;
|
||||
o.integer_obj.value = value;
|
||||
o.disallow_hex_for_int = true;
|
||||
return o;
|
||||
}
|
||||
|
||||
static Object make_float(FloatType value) {
|
||||
Object o;
|
||||
o.type = ObjectType::FLOAT;
|
||||
|
||||
@@ -149,6 +149,11 @@ SimpleAtom SimpleAtom::make_static_address(int static_label_id) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void SimpleAtom::mark_as_no_hex() {
|
||||
ASSERT(is_int() && !is_integer_promoted_to_float());
|
||||
m_no_display_int_as_hex = true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Mark this atom as a float. It will be printed as a float.
|
||||
* This can only be applied to an "integer" atom.
|
||||
@@ -194,6 +199,8 @@ goos::Object SimpleAtom::to_form(const std::vector<DecompilerLabel>& labels, con
|
||||
if (std::abs(m_int) > INT32_MAX) {
|
||||
u64 v = m_int;
|
||||
return pretty_print::to_symbol(fmt::format("#x{:x}", v));
|
||||
} else if (m_no_display_int_as_hex) {
|
||||
return goos::Object::make_integer_no_hex(m_int);
|
||||
} else {
|
||||
return goos::Object::make_integer(m_int);
|
||||
}
|
||||
|
||||
@@ -190,6 +190,7 @@ class SimpleAtom {
|
||||
ASSERT(is_sym_ptr() || is_sym_val() || is_sym_val_ptr());
|
||||
return m_string;
|
||||
}
|
||||
void mark_as_no_hex();
|
||||
void mark_as_float();
|
||||
bool is_integer_promoted_to_float() const;
|
||||
float get_integer_promoted_to_float() const;
|
||||
@@ -200,6 +201,7 @@ class SimpleAtom {
|
||||
s64 m_int = -1; // for integer constant and static address label id
|
||||
RegisterAccess m_variable;
|
||||
bool m_display_int_as_float = false;
|
||||
bool m_no_display_int_as_hex = false;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
||||
@@ -281,12 +281,19 @@ void LoadSourceElement::get_modified_regs(RegSet& regs) const {
|
||||
/////////////////////////////
|
||||
|
||||
SimpleAtomElement::SimpleAtomElement(const SimpleAtom& atom, bool omit_var_cast)
|
||||
: m_atom(atom), m_omit_var_cast(omit_var_cast) {
|
||||
: m_atom(atom), m_omit_var_cast(omit_var_cast), m_no_hex(false) {
|
||||
if (m_omit_var_cast) {
|
||||
ASSERT(atom.is_var());
|
||||
}
|
||||
}
|
||||
|
||||
SimpleAtomElement::SimpleAtomElement(int int_val, bool no_hex)
|
||||
: m_atom(SimpleAtom::make_int_constant(int_val)), m_omit_var_cast(false), m_no_hex(no_hex) {
|
||||
if (m_no_hex) {
|
||||
m_atom.mark_as_no_hex();
|
||||
}
|
||||
}
|
||||
|
||||
goos::Object SimpleAtomElement::to_form_internal(const Env& env) const {
|
||||
if (m_omit_var_cast) {
|
||||
return m_atom.var().to_form(env, RegisterAccess::Print::AS_VARIABLE_NO_CAST);
|
||||
|
||||
@@ -309,6 +309,7 @@ class LoadSourceElement : public FormElement {
|
||||
class SimpleAtomElement : public FormElement {
|
||||
public:
|
||||
explicit SimpleAtomElement(const SimpleAtom& var, bool omit_var_cast = false);
|
||||
SimpleAtomElement(int int_val, bool no_hex = false);
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
@@ -324,6 +325,7 @@ class SimpleAtomElement : public FormElement {
|
||||
private:
|
||||
SimpleAtom m_atom;
|
||||
bool m_omit_var_cast;
|
||||
bool m_no_hex;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
||||
@@ -965,7 +965,7 @@ FormElement* make_and_compact_math_op(Form* arg0,
|
||||
/*!
|
||||
* Update a two-argument form that uses two floats.
|
||||
* This is for operations like * and + that can be nested
|
||||
* (* (* a b)) -> (* a b c)
|
||||
* (* (* a b) c) -> (* a b c)
|
||||
* Note that we only apply this to the _first_ argument to keep the order of operations the same.
|
||||
*/
|
||||
void SimpleExpressionElement::update_from_stack_float_2_nestable(const Env& env,
|
||||
@@ -2603,6 +2603,9 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
|
||||
ASSERT(x->parent_form == m_src);
|
||||
}
|
||||
|
||||
if (auto test0 = m_src->to_string(env) == "(* 0.00024414062 (-> arg0 y))") {
|
||||
printf("");
|
||||
}
|
||||
if (m_src->is_single_element()) {
|
||||
auto src_as_se = dynamic_cast<SimpleExpressionElement*>(m_src->back());
|
||||
if (src_as_se) {
|
||||
@@ -2624,6 +2627,60 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// (* 0.125 b) -> (/ b 8)
|
||||
// adds explicit cast b to float if necessary
|
||||
auto src_as_ge = dynamic_cast<GenericElement*>(m_src->back());
|
||||
if (src_as_ge) {
|
||||
auto mr = match(Matcher::op_fixed(FixedOperatorKind::MULTIPLICATION,
|
||||
{Matcher::any_single(0), Matcher::any(1)}),
|
||||
m_src);
|
||||
if (mr.matched && std::abs(mr.maps.floats.at(0)) < 1 && mr.maps.floats.at(0) != 0) {
|
||||
float divisor_num = 1.0f / mr.maps.floats.at(0);
|
||||
int divisor_int = (int)divisor_num;
|
||||
// note: for some reason 0.016666668 shows up constantly where 1/60 should be. we won't
|
||||
// force it to 60, but we will transform it anyway
|
||||
if (divisor_int == divisor_num || mr.maps.floats.at(0) == 0.016666668f) {
|
||||
auto elt = mr.maps.forms.at(1)->try_as_single_element();
|
||||
auto b_as_simple = dynamic_cast<SimpleExpressionElement*>(elt);
|
||||
// WARNING : there is an assumption here that derefs DO NOT have implicit casts!
|
||||
auto b_as_deref = dynamic_cast<DerefElement*>(elt);
|
||||
if (b_as_deref ||
|
||||
(b_as_simple && b_as_simple->expr().kind() == SimpleExpression::Kind::IDENTITY)) {
|
||||
// TODO check if op is float, cast if so
|
||||
Form* divisor = nullptr;
|
||||
if (divisor_num == 4096.0f) {
|
||||
divisor = pool.form<ConstantTokenElement>("METER_LENGTH");
|
||||
} else if (divisor_num == (float)divisor_int && divisor_int % 2048 == 0) {
|
||||
divisor = pool.form<GenericElement>(
|
||||
GenericOperator::make_function(pool.form<ConstantTokenElement>("meters")),
|
||||
divisor_int % (int)METER_LENGTH
|
||||
? pool.form<ConstantFloatElement>(divisor_num / (float)METER_LENGTH)
|
||||
: pool.form<SimpleAtomElement>(divisor_int / 4096, true));
|
||||
} else if (divisor_num == divisor_int) {
|
||||
divisor = pool.form<SimpleAtomElement>(divisor_int, true);
|
||||
} else {
|
||||
// this shouldn't run because of the checks before.
|
||||
divisor = pool.form<ConstantFloatElement>(divisor_num);
|
||||
}
|
||||
if (divisor) {
|
||||
if (b_as_deref || (env.get_types_before_op(b_as_simple->expr().var().idx())
|
||||
.get(b_as_simple->expr().var().reg())
|
||||
.typespec() == TypeSpec("float"))) {
|
||||
*m_src->back_ref() = pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_fixed(FixedOperatorKind::DIVISION), mr.maps.forms.at(1),
|
||||
divisor);
|
||||
} else {
|
||||
*m_src->back_ref() = pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_fixed(FixedOperatorKind::DIVISION),
|
||||
pool.form<CastElement>(TypeSpec("float"), mr.maps.forms.at(1), true), divisor);
|
||||
}
|
||||
m_src->back()->parent_form = m_src;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stack.push_value_to_reg(m_dst, m_src, true, m_src_type, m_var_info);
|
||||
|
||||
@@ -127,6 +127,13 @@ Matcher Matcher::single(std::optional<float> value) {
|
||||
return m;
|
||||
}
|
||||
|
||||
Matcher Matcher::any_single(int match_id) {
|
||||
Matcher m;
|
||||
m.m_kind = Kind::ANY_FLOAT;
|
||||
m.m_float_out_id = match_id;
|
||||
return m;
|
||||
}
|
||||
|
||||
Matcher Matcher::any_quoted_symbol(int match_id) {
|
||||
Matcher m;
|
||||
m.m_kind = Kind::ANY_QUOTED_SYMBOL;
|
||||
@@ -477,6 +484,30 @@ bool Matcher::do_match(Form* input, MatchResult::Maps* maps_out, const Env* cons
|
||||
return false;
|
||||
} break;
|
||||
|
||||
case Kind::ANY_FLOAT: {
|
||||
auto as_const_float =
|
||||
dynamic_cast<ConstantFloatElement*>(input->try_as_single_active_element());
|
||||
if (as_const_float) {
|
||||
if (m_float_out_id != -1) {
|
||||
maps_out->floats[m_float_out_id] = as_const_float->value();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
auto as_expr = dynamic_cast<SimpleExpressionElement*>(input->try_as_single_active_element());
|
||||
if (as_expr && as_expr->expr().is_identity()) {
|
||||
const auto& atom = as_expr->expr().get_arg(0);
|
||||
if (atom.is_integer_promoted_to_float()) {
|
||||
if (m_float_out_id != -1) {
|
||||
maps_out->floats[m_float_out_id] = atom.get_integer_promoted_to_float();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} break;
|
||||
|
||||
case Kind::ANY_QUOTED_SYMBOL: {
|
||||
auto as_simple_atom = dynamic_cast<SimpleAtomElement*>(input->try_as_single_active_element());
|
||||
if (as_simple_atom) {
|
||||
|
||||
@@ -21,6 +21,7 @@ struct MatchResult {
|
||||
std::unordered_map<int, Form*> forms;
|
||||
std::unordered_map<int, s64> label;
|
||||
std::unordered_map<int, s64> ints;
|
||||
std::unordered_map<int, float> floats;
|
||||
} maps;
|
||||
|
||||
Form* int_or_form_to_form(FormPool& pool, int key_idx) {
|
||||
@@ -56,6 +57,7 @@ class Matcher {
|
||||
static Matcher integer(std::optional<int> value);
|
||||
static Matcher any_integer(int match_id = -1);
|
||||
static Matcher single(std::optional<float> value);
|
||||
static Matcher any_single(int match_id = -1);
|
||||
static Matcher any_reg_cast_to_int_or_uint(int match_id = -1);
|
||||
static Matcher any_quoted_symbol(int match_id = -1);
|
||||
static Matcher any_symbol(int match_id = -1);
|
||||
@@ -91,6 +93,7 @@ class Matcher {
|
||||
INT,
|
||||
ANY_INT,
|
||||
FLOAT,
|
||||
ANY_FLOAT,
|
||||
ANY_QUOTED_SYMBOL,
|
||||
ANY_SYMBOL,
|
||||
DEREF_OP,
|
||||
@@ -132,6 +135,7 @@ class Matcher {
|
||||
int m_form_match;
|
||||
int m_label_out_id;
|
||||
int m_int_out_id;
|
||||
int m_float_out_id;
|
||||
};
|
||||
std::optional<int> m_int_match;
|
||||
std::optional<float> m_float_match;
|
||||
|
||||
Reference in New Issue
Block a user