[decompiler] Jak 2 modifications, new all-types code (#1553)

* temp

* look at old game types

* clean up
This commit is contained in:
water111
2022-06-25 21:26:15 -04:00
committed by GitHub
parent c9de15ba64
commit 91fa0122d8
40 changed files with 1762 additions and 586 deletions
+40
View File
@@ -1842,4 +1842,44 @@ RegisterAccess StackSpillLoadOp::get_set_destination() const {
throw std::runtime_error("StackSpillLoadOp cannot be treated as a set! operation");
}
bool is_op_2(AtomicOp* op,
MatchParam<SimpleExpression::Kind> kind,
MatchParam<Register> dst,
MatchParam<Register> src0,
Register* dst_out,
Register* src0_out) {
// should be a set reg to int math 2 ir
auto set = dynamic_cast<SetVarOp*>(op);
if (!set) {
return false;
}
// destination should be a register
auto dest = set->dst();
if (dst != dest.reg()) {
return false;
}
auto math = set->src();
if (kind != math.kind()) {
return false;
}
auto arg = math.get_arg(0);
if (!arg.is_var() || src0 != arg.var().reg()) {
return false;
}
// it's a match!
if (dst_out) {
*dst_out = dest.reg();
}
if (src0_out) {
*src0_out = arg.var().reg();
}
return true;
}
} // namespace decompiler
+8
View File
@@ -12,6 +12,7 @@
#include "decompiler/Disasm/Instruction.h"
#include "decompiler/Disasm/Register.h"
#include "decompiler/IR2/IR2_common.h"
#include "decompiler/util/MatchParam.h"
namespace decompiler {
class FormElement;
@@ -807,4 +808,11 @@ class StackSpillLoadOp : public AtomicOp {
};
bool get_as_reg_offset(const SimpleExpression& expr, IR2_RegOffset* out);
bool is_op_2(AtomicOp* op,
MatchParam<SimpleExpression::Kind> kind,
MatchParam<Register> dst,
MatchParam<Register> src0,
Register* dst_out = nullptr,
Register* src0_out = nullptr);
} // namespace decompiler
+8
View File
@@ -188,6 +188,11 @@ TP_Type SimpleExpression::get_type(const TypeState& input,
// GOAL is smart enough to use binary 0b0 as floating point 0.
return TP_Type::make_from_ts("float");
}
// new for jak 2:
if (env.version == GameVersion::Jak2 && in_type.is_integer_constant() &&
in_type.get_integer_constant() <= UINT32_MAX) {
return TP_Type::make_from_ts("float");
}
return in_type;
}
case Kind::FPR_TO_GPR:
@@ -398,6 +403,9 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input,
}
if (m_kind == Kind::RIGHT_SHIFT_ARITH) {
if (env.version == GameVersion::Jak2 && arg0_type.typespec().base_type() == "float") {
return TP_Type::make_from_ts(TypeSpec("float"));
}
return TP_Type::make_from_ts(TypeSpec("int"));
}
} break;
+1
View File
@@ -58,6 +58,7 @@ struct FunctionVariableDefinitions {
*/
class Env {
public:
GameVersion version = GameVersion::Jak1;
bool types_succeeded = false;
bool has_local_vars() const { return m_has_local_vars; }
bool has_type_analysis() const { return m_has_types; }
+1
View File
@@ -801,6 +801,7 @@ class UntilElement : public FormElement {
bool allow_in_if() const override { return false; }
Form* condition = nullptr;
Form* body = nullptr;
std::optional<RegisterAccess> false_destination; // used in jak 2, sometimes.
};
/*!
+38 -4
View File
@@ -708,10 +708,28 @@ void SimpleExpressionElement::update_from_stack_gpr_to_fpr(const Env& env,
result->push_back(x);
}
} else {
// converting something else to an FPR, put an expression around it.
result->push_back(pool.alloc_element<GenericElement>(
GenericOperator::make_fixed(FixedOperatorKind::GPR_TO_FPR),
pool.alloc_sequence_form(nullptr, src_fes)));
if (env.version != GameVersion::Jak1) {
auto frm = pool.alloc_sequence_form(nullptr, src_fes);
if (src_fes.size() == 1) {
auto int_constant = get_goal_integer_constant(frm, env);
if (int_constant && (*int_constant <= UINT32_MAX)) {
float flt;
memcpy(&flt, &int_constant.value(), sizeof(float));
result->push_back(pool.alloc_element<ConstantFloatElement>(flt));
return;
}
}
// converting something else to an FPR, put an expression around it.
result->push_back(pool.alloc_element<GenericElement>(
GenericOperator::make_fixed(FixedOperatorKind::GPR_TO_FPR), frm));
} else {
result->push_back(pool.alloc_element<GenericElement>(
GenericOperator::make_fixed(FixedOperatorKind::GPR_TO_FPR),
pool.alloc_sequence_form(nullptr, src_fes)));
}
}
}
@@ -3538,6 +3556,22 @@ void UntilElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stac
}
stack.push_form_element(this, true);
if (false_destination) {
env.func->warnings.general_warning("new jak 2 until loop case, check carefully");
stack.push_value_to_reg(*false_destination,
pool.form<SimpleAtomElement>(SimpleAtom::make_sym_val("#f")), true,
TypeSpec("symbol"));
RegAccessSet accessed_regs;
body->collect_vars(accessed_regs, true);
condition->collect_vars(accessed_regs, true);
auto check_name = env.get_variable_name(*false_destination);
for (auto& reg : accessed_regs) {
if (env.get_variable_name(reg) == check_name) {
ASSERT_MSG(false, fmt::format("Jak 2 loop uses delay slot variable improperly: {} {}\n",
env.func->name(), check_name));
}
}
}
}
void WhileElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {