mirror of
https://github.com/open-goal/jak-project
synced 2026-08-03 00:47:12 -04:00
[decompiler] Jak 2 modifications, new all-types code (#1553)
* temp * look at old game types * clean up
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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.
|
||||
};
|
||||
|
||||
/*!
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user