mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 11:26:18 -04:00
get res decompiling (#705)
This commit is contained in:
parent
e7bc3eb3b0
commit
2754a8f2c4
|
@ -187,13 +187,13 @@ TP_Type SimpleExpression::get_type(const TypeState& input,
|
|||
case Kind::XOR:
|
||||
case Kind::LEFT_SHIFT:
|
||||
case Kind::MUL_UNSIGNED:
|
||||
case Kind::PCPYLD:
|
||||
return get_type_int2(input, env, dts);
|
||||
case Kind::NEG:
|
||||
case Kind::LOGNOT:
|
||||
return get_type_int1(input, env, dts);
|
||||
case Kind::DIV_UNSIGNED:
|
||||
case Kind::MOD_UNSIGNED:
|
||||
case Kind::PCPYLD:
|
||||
return TP_Type::make_from_ts("uint");
|
||||
case Kind::VECTOR_PLUS:
|
||||
case Kind::VECTOR_MINUS:
|
||||
|
@ -427,6 +427,21 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input,
|
|||
break;
|
||||
}
|
||||
|
||||
if (arg0_type.kind == TP_Type::Kind::PCPYUD_BITFIELD &&
|
||||
(m_kind == Kind::AND || m_kind == Kind::OR)) {
|
||||
// anding a bitfield should return the bitfield type.
|
||||
return TP_Type::make_from_pcpyud_bitfield(arg0_type.get_bitfield_type());
|
||||
}
|
||||
|
||||
// this is right but breaks something else right now.
|
||||
if (m_kind == Kind::PCPYLD && arg0_type.kind == TP_Type::Kind::PCPYUD_BITFIELD) {
|
||||
return arg1_type;
|
||||
}
|
||||
|
||||
if (m_kind == Kind::PCPYLD) {
|
||||
return TP_Type::make_from_ts("uint");
|
||||
}
|
||||
|
||||
if (arg0_type.kind == TP_Type::Kind::INTEGER_CONSTANT_PLUS_VAR_MULT && m_kind == Kind::ADD) {
|
||||
FieldReverseLookupInput rd_in;
|
||||
rd_in.offset = arg0_type.get_add_int_constant();
|
||||
|
|
|
@ -82,6 +82,7 @@ class Env {
|
|||
VariableWithCast get_variable_and_cast(const RegisterAccess& access) const;
|
||||
std::optional<TypeSpec> get_user_cast_for_access(const RegisterAccess& access) const;
|
||||
TypeSpec get_variable_type(const RegisterAccess& access, bool using_user_var_types) const;
|
||||
TP_Type get_variable_tp_type(const RegisterAccess& access, bool using_user_var_types) const;
|
||||
|
||||
/*!
|
||||
* Get the types in registers _after_ the given operation has completed.
|
||||
|
|
|
@ -1904,10 +1904,11 @@ void GenericElement::get_modified_regs(RegSet& regs) const {
|
|||
|
||||
CastElement::CastElement(TypeSpec type, Form* source, bool numeric)
|
||||
: m_type(std::move(type)), m_source(source), m_numeric(numeric) {
|
||||
source->parent_element = this;
|
||||
m_source->parent_element = this;
|
||||
}
|
||||
|
||||
goos::Object CastElement::to_form_internal(const Env& env) const {
|
||||
// assert(m_source->parent_element == this);
|
||||
auto atom = form_as_atom(m_source);
|
||||
if (atom && atom->is_var()) {
|
||||
return pretty_print::build_list(
|
||||
|
@ -1919,21 +1920,25 @@ goos::Object CastElement::to_form_internal(const Env& env) const {
|
|||
}
|
||||
|
||||
void CastElement::apply(const std::function<void(FormElement*)>& f) {
|
||||
// assert(m_source->parent_element == this);
|
||||
f(this);
|
||||
m_source->apply(f);
|
||||
}
|
||||
|
||||
void CastElement::apply_form(const std::function<void(Form*)>& f) {
|
||||
// assert(m_source->parent_element == this);
|
||||
m_source->apply_form(f);
|
||||
}
|
||||
|
||||
void CastElement::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
// assert(m_source->parent_element == this);
|
||||
if (recursive) {
|
||||
m_source->collect_vars(vars, recursive);
|
||||
}
|
||||
}
|
||||
|
||||
void CastElement::get_modified_regs(RegSet& regs) const {
|
||||
assert(m_source->parent_element == this);
|
||||
m_source->get_modified_regs(regs);
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,10 @@ class FormElement {
|
|||
bool allow_side_effects);
|
||||
bool is_popped() const { return m_popped; }
|
||||
|
||||
FormElement() = default;
|
||||
FormElement(const FormElement& other) = delete;
|
||||
FormElement& operator=(const FormElement& other) = delete;
|
||||
|
||||
void mark_popped() {
|
||||
assert(!m_popped);
|
||||
m_popped = true;
|
||||
|
|
|
@ -1113,6 +1113,29 @@ void SimpleExpressionElement::update_from_stack_pcypld(const Env& env,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
pcpyud v1, s4, r0
|
||||
ld a0, L152(fp)
|
||||
and v1, v1, a0
|
||||
lui a0, 1
|
||||
dsll32 a0, a0, 0
|
||||
or v1, v1, a0
|
||||
pcpyld v1, v1, s4
|
||||
por s4, v1, r0
|
||||
*/
|
||||
|
||||
auto as_mod = args.at(0)->try_as_element<ModifiedCopyBitfieldElement>();
|
||||
if (as_mod && as_mod->from_pcpyud()) {
|
||||
auto base_form = as_mod->base()->to_form(env);
|
||||
auto a1_form = args.at(1)->to_form(env);
|
||||
if (base_form == a1_form) {
|
||||
as_mod->clear_pcpyud_flag();
|
||||
result->push_back(as_mod);
|
||||
return;
|
||||
} else {
|
||||
fmt::print("pcpyud rewrite form fail: {} {}\n", base_form.print(), a1_form.print());
|
||||
}
|
||||
}
|
||||
auto new_form = pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_fixed(FixedOperatorKind::PCPYLD), args.at(0), args.at(1));
|
||||
result->push_back(new_form);
|
||||
|
@ -1262,16 +1285,45 @@ void SimpleExpressionElement::update_from_stack_logor_or_logand(const Env& env,
|
|||
FormStack& stack,
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects) {
|
||||
// grab the normal variable type
|
||||
auto arg0_type = env.get_variable_type(m_expr.get_arg(0).var(), true);
|
||||
|
||||
// and try to get it as a bitfield
|
||||
auto type_info = env.dts->ts.lookup_type(arg0_type);
|
||||
auto bitfield_info = dynamic_cast<BitFieldType*>(type_info);
|
||||
bool had_pcpyud = false;
|
||||
TypeSpec bitfield_type = arg0_type;
|
||||
|
||||
if (!bitfield_info) {
|
||||
// the above won't work if we're already done a pcpyud to grab the upper 64 bits.
|
||||
// we need to grab the type in the register (a TP_type) and check
|
||||
const auto& arg0_reg_type =
|
||||
env.get_types_before_op(m_expr.get_arg(0).var().idx()).get(m_expr.get_arg(0).var().reg());
|
||||
if (arg0_reg_type.kind == TP_Type::Kind::PCPYUD_BITFIELD) {
|
||||
// yes!
|
||||
had_pcpyud = true;
|
||||
bitfield_info =
|
||||
dynamic_cast<BitFieldType*>(env.dts->ts.lookup_type(arg0_reg_type.get_bitfield_type()));
|
||||
assert(bitfield_info);
|
||||
} else if (arg0_reg_type.kind == TP_Type::Kind::PCPYUD_BITFIELD_AND) {
|
||||
// already have the pcpyud in the thing.
|
||||
bitfield_info =
|
||||
dynamic_cast<BitFieldType*>(env.dts->ts.lookup_type(arg0_reg_type.get_bitfield_type()));
|
||||
assert(bitfield_info);
|
||||
}
|
||||
}
|
||||
|
||||
if (bitfield_info && m_expr.get_arg(1).is_int()) {
|
||||
// andi, ori with bitfield.
|
||||
auto base = pop_to_forms({m_expr.get_arg(0).var()}, env, pool, stack, allow_side_effects).at(0);
|
||||
auto read_elt = dynamic_cast<BitfieldAccessElement*>(base->try_as_single_element());
|
||||
if (!read_elt) {
|
||||
read_elt = pool.alloc_element<BitfieldAccessElement>(base, arg0_type);
|
||||
read_elt = pool.alloc_element<BitfieldAccessElement>(base, bitfield_type);
|
||||
assert(!had_pcpyud);
|
||||
} else {
|
||||
if (had_pcpyud) {
|
||||
assert(read_elt->has_pcpyud());
|
||||
}
|
||||
}
|
||||
|
||||
BitfieldManip::Kind manip_kind;
|
||||
|
@ -1313,13 +1365,19 @@ void SimpleExpressionElement::update_from_stack_logor_or_logand(const Env& env,
|
|||
bool made_new_read_elt = false;
|
||||
auto read_elt = dynamic_cast<BitfieldAccessElement*>(args.at(0)->try_as_single_element());
|
||||
if (!read_elt) {
|
||||
read_elt = pool.alloc_element<BitfieldAccessElement>(args.at(0), arg0_type);
|
||||
read_elt = pool.alloc_element<BitfieldAccessElement>(args.at(0), bitfield_type);
|
||||
made_new_read_elt = true;
|
||||
assert(!had_pcpyud);
|
||||
} else {
|
||||
if (had_pcpyud) {
|
||||
assert(read_elt->has_pcpyud());
|
||||
}
|
||||
}
|
||||
|
||||
auto stripped_arg1 = strip_int_or_uint_cast(args.at(1));
|
||||
auto arg1_atom = form_as_atom(strip_int_or_uint_cast(args.at(1)));
|
||||
if (arg1_atom && arg1_atom->is_int()) {
|
||||
// auto arg1_atom = form_as_atom(strip_int_or_uint_cast(args.at(1)));
|
||||
auto arg1_as_int = get_goal_integer_constant(stripped_arg1, env);
|
||||
if (arg1_as_int) {
|
||||
BitfieldManip::Kind manip_kind;
|
||||
if (kind == FixedOperatorKind::LOGAND) {
|
||||
manip_kind = BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT;
|
||||
|
@ -1328,10 +1386,14 @@ void SimpleExpressionElement::update_from_stack_logor_or_logand(const Env& env,
|
|||
} else {
|
||||
assert(false);
|
||||
}
|
||||
BitfieldManip step(manip_kind, arg1_atom->get_int());
|
||||
BitfieldManip step(manip_kind, *arg1_as_int);
|
||||
auto other = read_elt->push_step(step, env.dts->ts, pool, env);
|
||||
assert(!other); // shouldn't be complete.
|
||||
// assert(!other); // shouldn't be complete.
|
||||
if (other) {
|
||||
result->push_back(other);
|
||||
} else {
|
||||
result->push_back(read_elt);
|
||||
}
|
||||
return;
|
||||
} else if (!made_new_read_elt) {
|
||||
BitfieldManip::Kind manip_kind;
|
||||
|
@ -1847,6 +1909,13 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
|
|||
return;
|
||||
}
|
||||
|
||||
// bool skip = false;
|
||||
// auto dst_type = env.get_variable_type(m_dst, false);
|
||||
// auto as_bitfield = dynamic_cast<BitFieldType*>(env.dts->ts.lookup_type(dst_type));
|
||||
// if (as_bitfield && as_bitfield->get_load_size() == 16) {
|
||||
// skip = true;
|
||||
// }
|
||||
|
||||
// if we are a reg-reg move that consumes the original, push it without popping from stack.
|
||||
// it is the Stack's responsibility to untangle these later on.
|
||||
if (m_src->is_single_element()) {
|
||||
|
@ -1874,6 +1943,28 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
|
|||
// we aren't a reg-reg move, so update our source
|
||||
m_src->update_children_from_stack(env, pool, stack, true);
|
||||
|
||||
/*
|
||||
auto src_as_bf_set = dynamic_cast<ModifiedCopyBitfieldElement*>(m_src->try_as_single_element());
|
||||
if (src_as_bf_set && !src_as_bf_set->from_pcpyud() && src_as_bf_set->mods().size() == 1) {
|
||||
auto dst_form = m_dst.to_form(env, RegisterAccess::Print::AS_VARIABLE_NO_CAST);
|
||||
auto src_form = src_as_bf_set->base()->to_form(env);
|
||||
if (dst_form == src_form) {
|
||||
// success!
|
||||
auto value = src_as_bf_set->mods().at(0).value;
|
||||
value->parent_element = this;
|
||||
|
||||
// make the (-> thing bitfield)
|
||||
auto field_token = DerefToken::make_field_name(src_as_bf_set->mods().at(0).field_name);
|
||||
auto dst_dform = pool.alloc_single_element_form<SimpleAtomElement>(nullptr,
|
||||
SimpleAtom::make_var(m_dst)); auto loc_elt = pool.alloc_element<DerefElement>(dst_dform, false,
|
||||
field_token); loc_elt->inline_nested(); auto loc = pool.alloc_single_form(nullptr, loc_elt); auto
|
||||
new_form_el = pool.alloc_element<SetFormFormElement>(loc, value);
|
||||
stack.push_form_element(new_form_el, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
for (auto x : m_src->elts()) {
|
||||
assert(x->parent_form == m_src);
|
||||
}
|
||||
|
@ -1915,7 +2006,7 @@ void SetFormFormElement::push_to_stack(const Env& env, FormPool& pool, FormStack
|
|||
|
||||
// check for bitfield setting:
|
||||
auto src_as_bf_set = dynamic_cast<ModifiedCopyBitfieldElement*>(m_src->try_as_single_element());
|
||||
if (src_as_bf_set && src_as_bf_set->mods().size() == 1) {
|
||||
if (src_as_bf_set && !src_as_bf_set->from_pcpyud() && src_as_bf_set->mods().size() == 1) {
|
||||
auto dst_form = m_dst->to_form(env);
|
||||
auto src_form = src_as_bf_set->base()->to_form(env);
|
||||
if (dst_form == src_form) {
|
||||
|
@ -1933,6 +2024,8 @@ void SetFormFormElement::push_to_stack(const Env& env, FormPool& pool, FormStack
|
|||
m_dst = loc;
|
||||
m_src = value;
|
||||
}
|
||||
} else if (src_as_bf_set) {
|
||||
fmt::print("invalid bf set: {}\n", src_as_bf_set->to_string(env));
|
||||
}
|
||||
|
||||
stack.push_form_element(this, true);
|
||||
|
@ -2314,15 +2407,20 @@ void FunctionCallElement::update_from_stack(const Env& env,
|
|||
"type.");
|
||||
}
|
||||
|
||||
if (!env.dts->ts.should_use_virtual_methods(tp_type.method_from_type(),
|
||||
tp_type.method_id())) {
|
||||
bool is_res_lump = tp_type.method_from_type().base_type() == "res-lump";
|
||||
bool should_use_virtual =
|
||||
env.dts->ts.should_use_virtual_methods(tp_type.method_from_type(), tp_type.method_id());
|
||||
|
||||
if (!should_use_virtual && !is_res_lump) {
|
||||
throw std::runtime_error(
|
||||
fmt::format("Method call on {} id {} used a virtual call unexpectedly.",
|
||||
tp_type.method_from_type().print(), tp_type.method_id()));
|
||||
}
|
||||
|
||||
if (should_use_virtual) {
|
||||
// fmt::print("STACK\n{}\n\n", stack.print(env));
|
||||
auto pop =
|
||||
pop_to_forms({*arg0_mr.maps.regs.at(0)}, env, pool, stack, allow_side_effects, {}, {2})
|
||||
auto pop = pop_to_forms({*arg0_mr.maps.regs.at(0)}, env, pool, stack, allow_side_effects,
|
||||
{}, {2})
|
||||
.at(0);
|
||||
// fmt::print("GOT: {}\n", pop->to_string(env));
|
||||
arg_forms.at(0) = pop;
|
||||
|
@ -2334,6 +2432,7 @@ void FunctionCallElement::update_from_stack(const Env& env,
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new_form = pool.alloc_element<GenericElement>(GenericOperator::make_function(unstacked.at(0)),
|
||||
arg_forms);
|
||||
|
@ -3525,9 +3624,11 @@ void ReturnElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
|
|||
}
|
||||
|
||||
std::vector<FormElement*> new_entries;
|
||||
new_entries = rewrite_to_get_var(temp_stack, pool, env.end_var(), env);
|
||||
std::optional<RegisterAccess> var;
|
||||
new_entries = rewrite_to_get_var(temp_stack, pool, env.end_var(), env, &var);
|
||||
|
||||
assert(!new_entries.empty());
|
||||
|
||||
return_code->clear();
|
||||
|
||||
for (int i = 0; i < ((int)new_entries.size()) - 1; i++) {
|
||||
|
@ -3535,6 +3636,20 @@ void ReturnElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
|
|||
}
|
||||
|
||||
return_code->push_back(new_entries.back());
|
||||
if (var) {
|
||||
const auto& func_type = env.func->type.last_arg();
|
||||
if (!env.dts->ts.tc(func_type, env.get_variable_type(*var, false))) {
|
||||
auto as_cast = return_code->try_as_element<CastElement>();
|
||||
if (as_cast) {
|
||||
return_code->clear();
|
||||
as_cast->set_type(func_type);
|
||||
return_code->push_back(as_cast);
|
||||
} else {
|
||||
return_code = cast_form(return_code, func_type, pool, env);
|
||||
return_code->parent_element = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
stack.push_form_element(this, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -349,9 +349,9 @@ std::vector<FormElement*> FormStack::rewrite(FormPool& pool, const Env& env) con
|
|||
|
||||
auto elt = pool.alloc_element<SetVarElement>(*e.destination, simplified_source,
|
||||
e.sequence_point, type, e.set_info);
|
||||
e.source->parent_element = elt;
|
||||
|
||||
auto final_elt = try_rewrites_in_place(elt, env, pool);
|
||||
simplified_source->parent_element = final_elt;
|
||||
result.push_back(final_elt);
|
||||
} else {
|
||||
result.push_back(e.elt);
|
||||
|
@ -411,7 +411,6 @@ std::optional<RegisterAccess> rewrite_to_get_var(std::vector<FormElement*>& defa
|
|||
return {};
|
||||
} else {
|
||||
for (auto x : result) {
|
||||
x->parent_form = nullptr;
|
||||
default_result.push_back(x);
|
||||
}
|
||||
return result_access;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "common/util/BitUtils.h"
|
||||
#include "decompiler/util/DecompilerTypeSystem.h"
|
||||
#include "decompiler/IR2/GenericElementMatcher.h"
|
||||
#include "decompiler/Function/Function.h"
|
||||
|
||||
namespace decompiler {
|
||||
|
||||
|
@ -84,8 +85,12 @@ void BitfieldStaticDefElement::get_modified_regs(RegSet& regs) const {
|
|||
ModifiedCopyBitfieldElement::ModifiedCopyBitfieldElement(
|
||||
const TypeSpec& type,
|
||||
Form* base,
|
||||
bool from_pcpyud,
|
||||
const std::vector<BitFieldDef>& field_modifications)
|
||||
: m_type(type), m_base(base), m_field_modifications(field_modifications) {
|
||||
: m_type(type),
|
||||
m_base(base),
|
||||
m_field_modifications(field_modifications),
|
||||
m_from_pcpyud(from_pcpyud) {
|
||||
m_base->parent_element = this;
|
||||
for (auto& mod : m_field_modifications) {
|
||||
if (mod.value) {
|
||||
|
@ -95,13 +100,23 @@ ModifiedCopyBitfieldElement::ModifiedCopyBitfieldElement(
|
|||
}
|
||||
|
||||
goos::Object ModifiedCopyBitfieldElement::to_form_internal(const Env& env) const {
|
||||
std::vector<goos::Object> result = {pretty_print::to_symbol("copy-and-set-bf")};
|
||||
if (m_field_modifications.size() == 1) {
|
||||
std::vector<goos::Object> result = {pretty_print::to_symbol("copy-and-set-field")};
|
||||
result.push_back(m_base->to_form(env));
|
||||
for (auto& def : m_field_modifications) {
|
||||
result.push_back(pretty_print::to_symbol(fmt::format("{}", def.field_name)));
|
||||
result.push_back(def.value->to_form(env));
|
||||
}
|
||||
return pretty_print::build_list(result);
|
||||
} else {
|
||||
std::vector<goos::Object> result = {pretty_print::to_symbol("copy-and-set-bf-multi")};
|
||||
result.push_back(m_base->to_form(env));
|
||||
for (auto& def : m_field_modifications) {
|
||||
result.push_back(pretty_print::to_symbol(fmt::format(":{}", def.field_name)));
|
||||
result.push_back(def.value->to_form(env));
|
||||
}
|
||||
return pretty_print::build_list(result);
|
||||
}
|
||||
}
|
||||
|
||||
void ModifiedCopyBitfieldElement::apply(const std::function<void(FormElement*)>& f) {
|
||||
|
@ -220,7 +235,8 @@ BitField find_field(const TypeSystem& ts,
|
|||
namespace {
|
||||
std::optional<BitField> find_field_from_mask(const TypeSystem& ts,
|
||||
const BitFieldType* type,
|
||||
uint64_t mask) {
|
||||
uint64_t mask,
|
||||
bool upper_64) {
|
||||
// try to find a field that is masked by this:
|
||||
auto mask_range = get_bit_range(mask);
|
||||
if (!mask_range) {
|
||||
|
@ -228,6 +244,10 @@ std::optional<BitField> find_field_from_mask(const TypeSystem& ts,
|
|||
return {};
|
||||
}
|
||||
|
||||
if (upper_64) {
|
||||
mask_range = Range<int>(mask_range->first() + 64, mask_range->last() + 64);
|
||||
}
|
||||
|
||||
return find_field(ts, type, mask_range->first(), mask_range->size(), {});
|
||||
}
|
||||
|
||||
|
@ -241,7 +261,8 @@ Form* strip_int_or_uint_cast(Form* in) {
|
|||
|
||||
std::optional<BitFieldDef> get_bitfield_initial_set(Form* form,
|
||||
const BitFieldType* type,
|
||||
const TypeSystem& ts) {
|
||||
const TypeSystem& ts,
|
||||
int offset_in_bitfield) {
|
||||
// (shr (shl arg1 59) 44) for example
|
||||
{
|
||||
auto matcher = Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::SHR),
|
||||
|
@ -255,7 +276,7 @@ std::optional<BitFieldDef> get_bitfield_initial_set(Form* form,
|
|||
int right = mr.maps.ints.at(2);
|
||||
int size = 64 - left;
|
||||
int offset = left - right;
|
||||
auto f = find_field(ts, type, offset, size, {});
|
||||
auto f = find_field(ts, type, offset + offset_in_bitfield, size, {});
|
||||
BitFieldDef def;
|
||||
def.value = value;
|
||||
def.field_name = f.name();
|
||||
|
@ -278,7 +299,7 @@ std::optional<BitFieldDef> get_bitfield_initial_set(Form* form,
|
|||
int right = *power_of_two;
|
||||
int size = 64 - left;
|
||||
int offset = left - right;
|
||||
auto f = find_field(ts, type, offset, size, {});
|
||||
auto f = find_field(ts, type, offset + offset_in_bitfield, size, {});
|
||||
BitFieldDef def;
|
||||
def.value = value;
|
||||
def.field_name = f.name();
|
||||
|
@ -298,7 +319,7 @@ std::optional<BitFieldDef> get_bitfield_initial_set(Form* form,
|
|||
int right = 0;
|
||||
int size = 64 - left;
|
||||
int offset = left - right;
|
||||
auto f = find_field(ts, type, offset, size, {});
|
||||
auto f = find_field(ts, type, offset + offset_in_bitfield, size, {});
|
||||
BitFieldDef def;
|
||||
def.value = value;
|
||||
def.field_name = f.name();
|
||||
|
@ -313,7 +334,7 @@ std::optional<BitFieldDef> get_bitfield_initial_set(Form* form,
|
|||
auto value = mr_sllv.maps.forms.at(0);
|
||||
int size = 32;
|
||||
int offset = 0;
|
||||
auto f = find_field(ts, type, offset, size, {});
|
||||
auto f = find_field(ts, type, offset + offset_in_bitfield, size, {});
|
||||
BitFieldDef def;
|
||||
def.value = value;
|
||||
def.field_name = f.name();
|
||||
|
@ -345,6 +366,19 @@ void BitfieldAccessElement::push_pcpyud(const TypeSystem& ts, FormPool& pool, co
|
|||
}
|
||||
}
|
||||
|
||||
std::string BitfieldAccessElement::debug_print(const Env& env) const {
|
||||
std::string result = "BitfieldAccessElement:";
|
||||
if (m_got_pcpyud) {
|
||||
result += "pcpyud";
|
||||
}
|
||||
result += '\n';
|
||||
result += fmt::format("base: {}\n", m_base->to_string(env));
|
||||
for (auto& step : m_steps) {
|
||||
result += fmt::format(" {}\n", step.print());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Add a step to the bitfield access. If this completes the access, returns a form representing the
|
||||
* access
|
||||
|
@ -434,9 +468,7 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
|||
|
||||
if (m_steps.empty() && step.kind == BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT) {
|
||||
// and with mask
|
||||
if (m_got_pcpyud) {
|
||||
throw std::runtime_error("unknown pcpyud LOGAND_WITH_CONSTANT_INT sequence in bitfield");
|
||||
}
|
||||
// no need to do anything with pcpyud here.
|
||||
m_steps.push_back(step);
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -449,7 +481,7 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
|||
auto type = ts.lookup_type(m_type);
|
||||
auto as_bitfield = dynamic_cast<BitFieldType*>(type);
|
||||
assert(as_bitfield);
|
||||
auto field = find_field_from_mask(ts, as_bitfield, m_steps.at(0).amount);
|
||||
auto field = find_field_from_mask(ts, as_bitfield, m_steps.at(0).amount, false); // todo PCPYUP
|
||||
if (field) {
|
||||
auto get_field = pool.alloc_element<DerefElement>(m_base, false,
|
||||
DerefToken::make_field_name(field->name()));
|
||||
|
@ -462,9 +494,6 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
|||
|
||||
if (m_steps.size() == 1 && m_steps.at(0).kind == BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT &&
|
||||
step.kind == BitfieldManip::Kind::LOGIOR_WITH_CONSTANT_INT) {
|
||||
if (m_got_pcpyud) {
|
||||
throw std::runtime_error("unknown pcpyud LOGIOR_WITH_CONSTANT_INT sequence in bitfield");
|
||||
}
|
||||
// this is setting a bitfield to a constant.
|
||||
// first, let's check that the mask is used properly:
|
||||
u64 mask = m_steps.at(0).amount;
|
||||
|
@ -477,7 +506,7 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
|||
auto as_bitfield = dynamic_cast<BitFieldType*>(type);
|
||||
assert(as_bitfield);
|
||||
// use the mask to figure out the field.
|
||||
auto field = find_field_from_mask(ts, as_bitfield, ~mask);
|
||||
auto field = find_field_from_mask(ts, as_bitfield, ~mask, m_got_pcpyud);
|
||||
assert(field);
|
||||
bool is_signed =
|
||||
ts.tc(TypeSpec("int"), field->type()) && !ts.tc(TypeSpec("uint"), field->type());
|
||||
|
@ -485,24 +514,21 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
|||
// use the field to figure out what value is being set.
|
||||
u64 set_value;
|
||||
if (is_signed) {
|
||||
set_value = extract_bitfield<s64>(value, field->offset(), field->size());
|
||||
set_value = extract_bitfield<s64>(value, field->offset() - pcpyud_offset, field->size());
|
||||
} else {
|
||||
set_value = extract_bitfield<u64>(value, field->offset(), field->size());
|
||||
set_value = extract_bitfield<u64>(value, field->offset() - pcpyud_offset, field->size());
|
||||
}
|
||||
|
||||
BitFieldDef def;
|
||||
def.field_name = field->name();
|
||||
def.value = pool.alloc_single_element_form<SimpleAtomElement>(
|
||||
nullptr, SimpleAtom::make_int_constant(set_value));
|
||||
return pool.alloc_element<ModifiedCopyBitfieldElement>(m_type, m_base,
|
||||
return pool.alloc_element<ModifiedCopyBitfieldElement>(m_type, m_base, m_got_pcpyud,
|
||||
std::vector<BitFieldDef>{def});
|
||||
}
|
||||
|
||||
if (m_steps.size() == 1 && m_steps.at(0).kind == BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT &&
|
||||
step.kind == BitfieldManip::Kind::LOGIOR_WITH_FORM) {
|
||||
if (m_got_pcpyud) {
|
||||
throw std::runtime_error("unknown pcpyud LOGIOR_WITH_FORM sequence in bitfield");
|
||||
}
|
||||
// this is setting a bitfield to a variable
|
||||
u64 mask = m_steps.at(0).amount;
|
||||
|
||||
|
@ -510,10 +536,10 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
|||
auto as_bitfield = dynamic_cast<BitFieldType*>(type);
|
||||
assert(as_bitfield);
|
||||
// use the mask to figure out the field.
|
||||
auto field = find_field_from_mask(ts, as_bitfield, ~mask);
|
||||
auto field = find_field_from_mask(ts, as_bitfield, ~mask, m_got_pcpyud);
|
||||
assert(field);
|
||||
|
||||
auto val = get_bitfield_initial_set(step.value, as_bitfield, ts);
|
||||
auto val = get_bitfield_initial_set(step.value, as_bitfield, ts, pcpyud_offset);
|
||||
|
||||
if (!val) {
|
||||
throw std::runtime_error(
|
||||
|
@ -524,7 +550,7 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
|||
throw std::runtime_error("Incompatible bitfield set");
|
||||
}
|
||||
|
||||
return pool.alloc_element<ModifiedCopyBitfieldElement>(m_type, m_base,
|
||||
return pool.alloc_element<ModifiedCopyBitfieldElement>(m_type, m_base, m_got_pcpyud,
|
||||
std::vector<BitFieldDef>{*val});
|
||||
}
|
||||
|
||||
|
@ -532,7 +558,10 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
|||
for (auto& old_step : m_steps) {
|
||||
lg::error(" {}", old_step.print());
|
||||
}
|
||||
lg::error("Current: {}\n", step.print());
|
||||
lg::error("Current: {}", step.print());
|
||||
if (m_got_pcpyud) {
|
||||
lg::error("Got pcpyud\n");
|
||||
}
|
||||
|
||||
throw std::runtime_error("Unknown state in BitfieldReadElement");
|
||||
}
|
||||
|
@ -595,6 +624,22 @@ std::optional<u64> get_goal_integer_constant(Form* in, const Env&) {
|
|||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// also (shl (shl <something> 16) 32)
|
||||
// why.
|
||||
matcher = Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::SHL),
|
||||
{Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::SHL),
|
||||
{Matcher::any(1), Matcher::integer(16)}),
|
||||
Matcher::integer(32)});
|
||||
mr = match(matcher, in);
|
||||
if (mr.matched) {
|
||||
auto arg_as_atom = form_as_atom(mr.maps.forms.at(1));
|
||||
if (arg_as_atom && arg_as_atom->is_int()) {
|
||||
u64 result = arg_as_atom->get_int();
|
||||
result <<= 48ull;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -713,8 +758,9 @@ Form* cast_to_bitfield(const BitFieldType* type_info,
|
|||
|
||||
// now variables
|
||||
for (auto& arg : args) {
|
||||
// it's a 64-bit constant so correct to set offset 0 here.
|
||||
auto maybe_field =
|
||||
get_bitfield_initial_set(strip_int_or_uint_cast(arg), type_info, env.dts->ts);
|
||||
get_bitfield_initial_set(strip_int_or_uint_cast(arg), type_info, env.dts->ts, 0);
|
||||
if (!maybe_field) {
|
||||
// failed, just return cast.
|
||||
return pool.alloc_single_element_form<CastElement>(nullptr, typespec, in);
|
||||
|
|
|
@ -101,6 +101,8 @@ class BitfieldAccessElement : public FormElement {
|
|||
FormPool& pool,
|
||||
const Env& env);
|
||||
void push_pcpyud(const TypeSystem& ts, FormPool& pool, const Env& env);
|
||||
std::string debug_print(const Env& env) const;
|
||||
bool has_pcpyud() const { return m_got_pcpyud; }
|
||||
|
||||
private:
|
||||
bool m_got_pcpyud = false;
|
||||
|
@ -155,6 +157,7 @@ class ModifiedCopyBitfieldElement : public FormElement {
|
|||
public:
|
||||
ModifiedCopyBitfieldElement(const TypeSpec& type,
|
||||
Form* base,
|
||||
bool from_pcpyud,
|
||||
const std::vector<BitFieldDef>& field_modifications);
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
|
@ -164,11 +167,17 @@ class ModifiedCopyBitfieldElement : public FormElement {
|
|||
|
||||
Form* base() const { return m_base; }
|
||||
const std::vector<BitFieldDef> mods() const { return m_field_modifications; }
|
||||
bool from_pcpyud() const { return m_from_pcpyud; }
|
||||
void clear_pcpyud_flag() {
|
||||
assert(m_from_pcpyud);
|
||||
m_from_pcpyud = false;
|
||||
}
|
||||
|
||||
private:
|
||||
TypeSpec m_type;
|
||||
Form* m_base = nullptr;
|
||||
std::vector<BitFieldDef> m_field_modifications;
|
||||
bool m_from_pcpyud = false;
|
||||
};
|
||||
|
||||
Form* cast_to_bitfield(const BitFieldType* type_info,
|
||||
|
|
|
@ -85,11 +85,16 @@ bool convert_to_expressions(
|
|||
if (!dts.ts.tc(f.type.last_arg(), return_type)) {
|
||||
// we need to cast the final value.
|
||||
auto to_cast = new_entries.back();
|
||||
auto as_cast = dynamic_cast<CastElement*>(to_cast);
|
||||
if (as_cast) {
|
||||
as_cast->set_type(f.type.last_arg());
|
||||
} else {
|
||||
new_entries.pop_back();
|
||||
auto cast = pool.alloc_element<CastElement>(f.type.last_arg(),
|
||||
pool.alloc_single_form(nullptr, to_cast));
|
||||
new_entries.push_back(cast);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// or just get all the expressions
|
||||
new_entries = stack.rewrite(pool, f.ir2.env);
|
||||
|
|
|
@ -79,8 +79,8 @@ Form* lca_form(Form* a, Form* b, const Env& env) {
|
|||
bi--;
|
||||
}
|
||||
if (!result) {
|
||||
auto* bad = b->parent_element;
|
||||
fmt::print("bad form is {} {}\n", bad->to_string(env), (void*)bad);
|
||||
fmt::print("{} bad form is {}\n\n{}\n", env.func->guessed_name.to_string(), a->to_string(env),
|
||||
b->to_string(env));
|
||||
}
|
||||
assert(result);
|
||||
|
||||
|
|
|
@ -730,6 +730,25 @@ void SSA::make_vars(const Function& function, const DecompilerTypeSystem& dts) {
|
|||
}
|
||||
}
|
||||
|
||||
// if (function.type.last_arg() != TypeSpec("none")) {
|
||||
// auto return_var = function.ir2.atomic_ops->end_op().return_var();
|
||||
// auto return_reg = return_var.reg();
|
||||
// const auto& last_block = blocks.at(blocks.size() - 1);
|
||||
// const auto& last_ins = last_block.ins.at(last_block.ins.size() - 1);
|
||||
// assert(last_ins.src.size() == 1);
|
||||
// auto return_idx = map.var_id(last_ins.src.at(0));
|
||||
//
|
||||
// if (!program_read_vars[return_reg].empty()) {
|
||||
// program_read_vars[return_reg].at(return_idx).type =
|
||||
// TP_Type::make_from_ts(function.type.last_arg());
|
||||
// }
|
||||
//
|
||||
// if (!program_write_vars[return_reg].empty()) {
|
||||
// program_write_vars[return_reg].at(return_idx).type =
|
||||
// TP_Type::make_from_ts(function.type.last_arg());
|
||||
// }
|
||||
// }
|
||||
|
||||
merge_infos(program_write_vars, program_read_vars, dts);
|
||||
|
||||
// copy types from input argument coloring moves:
|
||||
|
|
|
@ -9325,10 +9325,10 @@
|
|||
(get-property-value-float (_type_ symbol symbol float float (pointer res-tag) pointer) float :no-virtual 12)
|
||||
(get-tag-index-data (_type_ int) pointer 13)
|
||||
(get-tag-data (_type_ res-tag) pointer 14)
|
||||
(dummy-15 (_type_ res-tag) res-tag 15)
|
||||
(allocate-data-memory-for-tag! (_type_ res-tag) res-tag 15)
|
||||
(sort! (_type_) _type_ 16)
|
||||
(dummy-17 (_type_ res-tag pointer) res-lump 17)
|
||||
(dummy-18 (_type_ res-tag res-tag) res-lump 18)
|
||||
(add-data! (_type_ res-tag pointer) res-lump 17)
|
||||
(add-32bit-data! (_type_ res-tag object) res-lump 18)
|
||||
(lookup-tag-idx (_type_ symbol symbol float) res-tag-pair :no-virtual 19)
|
||||
(make-property-data (_type_ float res-tag-pair pointer) pointer 20)
|
||||
(get-curve-data! (_type_ curve symbol symbol float) symbol 21)
|
||||
|
@ -9346,9 +9346,6 @@
|
|||
;; Containing DGOs - ['GAME', 'ENGINE']
|
||||
;; Version - 3
|
||||
|
||||
;; - Functions
|
||||
|
||||
(define-extern part-group-pointer? function)
|
||||
|
||||
;; - Symbols
|
||||
|
||||
|
@ -13254,6 +13251,8 @@
|
|||
)
|
||||
|
||||
|
||||
(define-extern part-group-pointer? (function pointer symbol))
|
||||
|
||||
;; ----------------------
|
||||
;; File - sparticle-h
|
||||
;; Source Path - engine/sparticle/sparticle-h.gc
|
||||
|
|
|
@ -453,7 +453,12 @@
|
|||
|
||||
"trajectory": [["L18", "uint64", true]],
|
||||
|
||||
"res": [["L150", "uint64", true]],
|
||||
"res": [
|
||||
["L150", "uint64", true],
|
||||
["L152", "uint64", true],
|
||||
["L151", "uint64", true],
|
||||
["L153", "uint64", true]
|
||||
],
|
||||
|
||||
"ripple": [
|
||||
["L73", "float", true],
|
||||
|
@ -559,9 +564,7 @@
|
|||
["L12", "uint64", true]
|
||||
],
|
||||
|
||||
"shadow-cpu": [
|
||||
["L122", "shadow-data", true]
|
||||
],
|
||||
"shadow-cpu": [["L122", "shadow-data", true]],
|
||||
|
||||
"entity-table": [["L8", "(array entity-info)", true]],
|
||||
|
||||
|
|
|
@ -414,9 +414,7 @@
|
|||
[157, "a0", "(pointer process-drawable)"]
|
||||
],
|
||||
|
||||
"load-game-text-info": [
|
||||
[4, "v1", "game-text-info"]
|
||||
],
|
||||
"load-game-text-info": [[4, "v1", "game-text-info"]],
|
||||
|
||||
"texture-relocate": [
|
||||
[[17, 21], "t4", "dma-packet"],
|
||||
|
@ -506,12 +504,29 @@
|
|||
[22, "t1", "(pointer uint64)"],
|
||||
[29, "t2", "(pointer uint64)"]
|
||||
],
|
||||
"(method 18 res-lump)": [["_stack_", 16, "res-tag"]],
|
||||
"(method 18 res-lump)": [["_stack_", 16, "object"]],
|
||||
"(method 21 res-lump)": [
|
||||
["_stack_", 16, "res-tag"],
|
||||
["_stack_", 32, "res-tag"]
|
||||
],
|
||||
|
||||
"(method 15 res-lump)": [[132, "s5", "res-tag-pair"]],
|
||||
|
||||
"(method 17 res-lump)": [[22, "s4", "(pointer pointer)"]],
|
||||
|
||||
"(method 20 res-lump)": [[331, "a3", "(inline-array vector)"]],
|
||||
|
||||
"(method 8 res-lump)": [
|
||||
[215, "s0", "array"],
|
||||
[[0, 100], "s0", "basic"],
|
||||
[[102, 120], "s0", "basic"],
|
||||
[[147, 150], "s0", "collide-mesh"],
|
||||
[[157, 200], "s0", "(array object)"],
|
||||
//[[197, 199], "s0", "(array basic)"],
|
||||
//[[236, 240], "a0", "basic"]
|
||||
[235, "s0", "basic"]
|
||||
],
|
||||
|
||||
// SHADOW-CPU-H
|
||||
"(method 10 shadow-control)": [[1, "v1", "int"]],
|
||||
|
||||
|
@ -1172,5 +1187,7 @@
|
|||
|
||||
"blackout": [[[20, 24], "v1", "dma-packet"]],
|
||||
|
||||
"(method 10 external-art-control)": [[18, "v1", "pointer"]],
|
||||
|
||||
"placeholder-do-not-add-below": []
|
||||
}
|
||||
|
|
|
@ -1798,7 +1798,29 @@
|
|||
},
|
||||
"(method 15 res-lump)": {
|
||||
"vars": {
|
||||
"s5-0": ["tag-pair", "res-tag-pair"]
|
||||
"s5-0": ["tag-pair", "res-tag-pair"],
|
||||
"s2-0": "existing-tag",
|
||||
"s3-0": "data-size",
|
||||
"v1-25": "resource-mem"
|
||||
}
|
||||
},
|
||||
|
||||
"(method 17 res-lump)": {
|
||||
"vars": {
|
||||
"a0-2": "new-tag",
|
||||
"s4-0": "tag-mem"
|
||||
}
|
||||
},
|
||||
|
||||
"(method 8 res-lump)": {
|
||||
"args": ["obj", "block", "flags"],
|
||||
"vars": {
|
||||
"s3-0":"mem-use-id",
|
||||
"s2-0":"mem-use-name",
|
||||
"v1-22":"obj-size",
|
||||
"s1-0":"tag-idx",
|
||||
"s0-0":"tag-data"
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -67,6 +67,8 @@ std::string TP_Type::print() const {
|
|||
}
|
||||
case Kind::PCPYUD_BITFIELD:
|
||||
return fmt::format("<pcpyud {}>", m_ts.print());
|
||||
case Kind::PCPYUD_BITFIELD_AND:
|
||||
return fmt::format("<pcpyud-and {}>", m_ts.print());
|
||||
case Kind::LABEL_ADDR:
|
||||
return "<label-addr>";
|
||||
case Kind::INVALID:
|
||||
|
@ -119,6 +121,8 @@ bool TP_Type::operator==(const TP_Type& other) const {
|
|||
return m_int == other.m_int && m_ts == other.m_ts && m_pcpyud == other.m_pcpyud;
|
||||
case Kind::PCPYUD_BITFIELD:
|
||||
return m_pcpyud == other.m_pcpyud && m_ts == other.m_ts;
|
||||
case Kind::PCPYUD_BITFIELD_AND:
|
||||
return m_pcpyud == other.m_pcpyud && m_ts == other.m_ts;
|
||||
case Kind::LABEL_ADDR:
|
||||
return true;
|
||||
case Kind::INVALID:
|
||||
|
@ -177,6 +181,8 @@ TypeSpec TP_Type::typespec() const {
|
|||
return TypeSpec("int"); // ideally this is never used.
|
||||
case Kind::PCPYUD_BITFIELD:
|
||||
return TypeSpec("int");
|
||||
case Kind::PCPYUD_BITFIELD_AND:
|
||||
return TypeSpec("int");
|
||||
case Kind::LABEL_ADDR:
|
||||
return TypeSpec("pointer"); // ?
|
||||
case Kind::INVALID:
|
||||
|
|
|
@ -33,6 +33,7 @@ class TP_Type {
|
|||
VIRTUAL_METHOD,
|
||||
NON_VIRTUAL_METHOD,
|
||||
PCPYUD_BITFIELD,
|
||||
PCPYUD_BITFIELD_AND,
|
||||
LEFT_SHIFTED_BITFIELD, // (bitfield << some-constant)
|
||||
LABEL_ADDR,
|
||||
INVALID
|
||||
|
@ -62,6 +63,7 @@ class TP_Type {
|
|||
case Kind::NON_VIRTUAL_METHOD:
|
||||
case Kind::LEFT_SHIFTED_BITFIELD:
|
||||
case Kind::PCPYUD_BITFIELD:
|
||||
case Kind::PCPYUD_BITFIELD_AND:
|
||||
case Kind::LABEL_ADDR:
|
||||
return false;
|
||||
case Kind::UNINITIALIZED:
|
||||
|
@ -244,6 +246,14 @@ class TP_Type {
|
|||
return result;
|
||||
}
|
||||
|
||||
static TP_Type make_from_pcpyud_and_bitfield(const TypeSpec& ts) {
|
||||
TP_Type result;
|
||||
result.kind = Kind::PCPYUD_BITFIELD_AND;
|
||||
result.m_ts = ts;
|
||||
result.m_pcpyud = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
static TP_Type make_label_addr() {
|
||||
TP_Type result;
|
||||
result.kind = Kind::LABEL_ADDR;
|
||||
|
@ -296,7 +306,8 @@ class TP_Type {
|
|||
}
|
||||
|
||||
const TypeSpec& get_bitfield_type() const {
|
||||
assert(kind == Kind::LEFT_SHIFTED_BITFIELD || kind == Kind::PCPYUD_BITFIELD);
|
||||
assert(kind == Kind::LEFT_SHIFTED_BITFIELD || kind == Kind::PCPYUD_BITFIELD ||
|
||||
kind == Kind::PCPYUD_BITFIELD_AND);
|
||||
return m_ts;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,10 +47,10 @@
|
|||
(get-property-value-float (_type_ symbol symbol float float (pointer res-tag) pointer) float :no-virtual 12)
|
||||
(get-tag-index-data (_type_ int) pointer 13)
|
||||
(get-tag-data (_type_ res-tag) pointer 14)
|
||||
(dummy-15 (_type_ res-tag) res-tag 15)
|
||||
(allocate-data-memory-for-tag! (_type_ res-tag) res-tag 15)
|
||||
(sort! (_type_) _type_ 16)
|
||||
(dummy-17 (_type_ res-tag pointer) res-lump 17)
|
||||
(dummy-18 (_type_ res-tag res-tag) res-lump 18)
|
||||
(add-data! (_type_ res-tag pointer) res-lump 17)
|
||||
(add-32bit-data! (_type_ res-tag object) res-lump 18)
|
||||
(lookup-tag-idx (_type_ symbol symbol float) res-tag-pair :no-virtual 19)
|
||||
(make-property-data (_type_ float res-tag-pair pointer) pointer 20)
|
||||
(get-curve-data! (_type_ curve symbol symbol float) symbol 21)
|
||||
|
|
|
@ -67,7 +67,7 @@ This is updated from the entity system used in Crash 2, which had most of these
|
|||
(the int
|
||||
(if (res-ref? obj)
|
||||
|
||||
(* (-> obj elt-count) 4)
|
||||
(* (-> obj elt-count) 4) ;; elements are pointers/references to data.
|
||||
|
||||
(* (-> obj elt-count) (-> obj elt-type size))
|
||||
)
|
||||
|
@ -685,6 +685,148 @@ This is updated from the entity system used in Crash 2, which had most of these
|
|||
obj
|
||||
)
|
||||
|
||||
(defmethod allocate-data-memory-for-tag! res-lump ((obj res-lump) (arg0 res-tag))
|
||||
"Find space for the data described by arg0 in obj.
|
||||
Returns a tag with data-offset set correctly for this res-lump.
|
||||
If the lump already contains memory for the given tag, and it is big enough,
|
||||
it will be reused. Alignment will be at least 8 bytes.
|
||||
If the input tag has elt-count = 0, it will return a tag for elt-count = 1."
|
||||
(local-vars (resource-mem pointer))
|
||||
|
||||
;; first, look up the tag to see if it already exists in this res-lump
|
||||
(let ((tag-pair (lookup-tag-idx obj (-> arg0 name) 'exact (-> arg0 key-frame))))
|
||||
(let ((existing-tag (-> obj tag (-> tag-pair lo))))
|
||||
;; If our existing tag is valid, but our key-frame is NaN, then we forget about it.
|
||||
(if (and (>= (the-as int tag-pair) 0)
|
||||
(!= (-> arg0 key-frame) (-> arg0 key-frame)) ;; check for NaN
|
||||
)
|
||||
(set! tag-pair (new 'static 'res-tag-pair :lo #xffffffff :hi #xffffffff))
|
||||
)
|
||||
|
||||
;; modify the input to have at least one element
|
||||
(if (zero? (-> arg0 elt-count))
|
||||
(set! (-> arg0 elt-count) 1)
|
||||
)
|
||||
|
||||
;; next, we try to find some memory
|
||||
(let ((data-size (length arg0))) ;; size in bytes to store the data.
|
||||
(cond
|
||||
((and (>= (the-as int tag-pair) 0)
|
||||
(>= (the-as uint (length existing-tag)) (the-as uint data-size))
|
||||
)
|
||||
;; we have enough memory in the existing tag.
|
||||
;; so we can just reuse it.
|
||||
(set! resource-mem (&+ (-> obj data-base) (-> existing-tag data-offset)))
|
||||
|
||||
;; but we want at least 8 byte alignment. If this fails, allocate with 16-byte alignment from the top.
|
||||
(when (nonzero? (logand (the-as int resource-mem) 7))
|
||||
(set! resource-mem (logand -16 (&+ (-> obj data-top) 15)))
|
||||
(set! (-> obj data-top) (&+ resource-mem data-size))
|
||||
)
|
||||
)
|
||||
(else
|
||||
;; the existing tag wasn't there, or it wasn't big enough.
|
||||
;; just allocate new memory.
|
||||
(set! resource-mem (logand -16 (&+ (-> obj data-top) 15)))
|
||||
(set! (-> obj data-top) (&+ resource-mem data-size))
|
||||
)
|
||||
)
|
||||
|
||||
;; set our data offset.
|
||||
(set! (-> arg0 data-offset) (&- resource-mem (the-as uint (-> obj data-base))))
|
||||
|
||||
;; check for overflow of the data memory
|
||||
;; this will leave things in a bad state.
|
||||
(when (>= (the-as int (&+ resource-mem data-size))
|
||||
(the-as int (&+ (-> obj data-base) (-> obj data-size)))
|
||||
)
|
||||
(format 0 "ERROR: attempting to a new tag ~`res-tag`P data of #x~X bytes to ~A, but data memory is full.~%"
|
||||
arg0
|
||||
data-size
|
||||
obj
|
||||
)
|
||||
(return (the-as res-tag #f))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; next step is to add us to the list of tags.
|
||||
(cond
|
||||
((< (the-as int tag-pair) 0)
|
||||
;; we couldn't reuse an existing tag. Need to allocate another
|
||||
(cond
|
||||
((>= (-> obj length) (-> obj allocated-length))
|
||||
;; but there isn't room for another tag.
|
||||
(format 0 "ERROR: attempting to a new tag ~`res-tag`P to ~A, but tag memory is full.~%"
|
||||
arg0
|
||||
obj
|
||||
)
|
||||
(return (the-as res-tag #f))
|
||||
)
|
||||
(else
|
||||
;; allocate a new tag and sort, so the binary search works properly.
|
||||
(set! (-> obj tag (-> obj length)) arg0)
|
||||
(set! (-> obj length) (+ (-> obj length) 1))
|
||||
(sort! obj)
|
||||
)
|
||||
)
|
||||
)
|
||||
(else
|
||||
;; reuse the existing tag.
|
||||
(set! (-> obj tag (-> tag-pair lo)) arg0)
|
||||
)
|
||||
)
|
||||
)
|
||||
arg0
|
||||
)
|
||||
|
||||
(defmethod add-data! res-lump ((obj res-lump) (arg0 res-tag) (arg1 pointer))
|
||||
"Given a tag and a pointer to its data, copy it to this res-lump.
|
||||
This doesn't seem to do the right thing if the given tag is a non-inline tag
|
||||
with > 1 element."
|
||||
|
||||
;; get a tag for this lump with memory for the given tag.
|
||||
(let ((new-tag (allocate-data-memory-for-tag! obj arg0)))
|
||||
(when new-tag
|
||||
;; get pointer to new tag's memory
|
||||
(let* ((v1-2 obj)
|
||||
(a1-1 new-tag)
|
||||
(tag-mem (&+ (-> v1-2 data-base) (-> a1-1 data-offset)))
|
||||
)
|
||||
(cond
|
||||
((zero? (-> new-tag inlined?))
|
||||
;; this seems wrong, it should loop over the length maybe?
|
||||
(length new-tag) ;; unused?
|
||||
(set! (-> (the-as (pointer pointer) tag-mem)) arg1)
|
||||
)
|
||||
(else
|
||||
;; otherwise, copy the memory.
|
||||
(let ((a2-1 (length new-tag)))
|
||||
(mem-copy! tag-mem arg1 a2-1)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
obj
|
||||
)
|
||||
|
||||
(defmethod add-32bit-data! res-lump ((obj res-lump) (arg0 res-tag) (arg1 object))
|
||||
"Add a single 32-bit value using add-data."
|
||||
(set! (-> arg0 inlined?) 1)
|
||||
(add-data! obj arg0 (& arg1)) ;; note, only 32-bits are spilled to the stack here.
|
||||
#|
|
||||
(local-vars (sv-16 object))
|
||||
(set! sv-16 arg1)
|
||||
(let* ((v1-0 arg0)
|
||||
(a1-4 (copy-and-set-bf v1-0 :inlined? 1))
|
||||
)
|
||||
(add-data! obj a1-4 (& sv-16))
|
||||
)
|
||||
|#
|
||||
)
|
||||
|
||||
(defmethod get-curve-data! res-lump ((obj res-lump) (curve-target curve) (points-name symbol) (knots-name symbol) (time float))
|
||||
"Read curve data and write it to curve-target. Return #t if both control points and knots data was succesfully read, #f otherwise."
|
||||
|
||||
|
@ -720,10 +862,139 @@ This is updated from the entity system used in Crash 2, which had most of these
|
|||
)
|
||||
)
|
||||
|
||||
;; method 15 res-lump
|
||||
;; method 17 res-lump
|
||||
;; method 18 res-lump
|
||||
;; mem-usage res-lump
|
||||
(define-extern part-group-pointer? (function pointer symbol))
|
||||
(declare-type nav-mesh basic)
|
||||
(declare-type collide-mesh basic)
|
||||
(defmethod mem-usage res-lump ((obj res-lump) (block memory-usage-block) (flags int))
|
||||
"Get the memory usage of this lump and its data"
|
||||
(local-vars (sv-16 int))
|
||||
|
||||
;; get the name and ID
|
||||
(let ((mem-use-id (mem-usage-id res))
|
||||
(mem-use-name "res")
|
||||
)
|
||||
(cond
|
||||
((nonzero? (logand flags 256))
|
||||
(set! mem-use-id (mem-usage-id camera))
|
||||
(set! mem-use-name "camera")
|
||||
)
|
||||
((nonzero? (logand flags 64))
|
||||
(set! mem-use-id (mem-usage-id entity))
|
||||
(set! mem-use-name "entity")
|
||||
)
|
||||
((nonzero? (logand flags 128))
|
||||
(set! mem-use-id (mem-usage-id ambient))
|
||||
(set! mem-use-name "ambient")
|
||||
)
|
||||
((nonzero? (logand flags 512))
|
||||
(set! mem-use-id (mem-usage-id art-joint-geo))
|
||||
(set! mem-use-name "art-joint-geo")
|
||||
)
|
||||
)
|
||||
|
||||
;; set up the block
|
||||
(set! (-> block length) (max (-> block length) (+ mem-use-id 1)))
|
||||
(set! (-> block data mem-use-id name) mem-use-name)
|
||||
|
||||
;; the lump counts as 1 in the count field
|
||||
(set! (-> block data mem-use-id count) (+ (-> block data mem-use-id count) 1))
|
||||
|
||||
;; add the size of the lump itself.
|
||||
(let ((obj-size (asize-of obj)))
|
||||
(set! (-> block data mem-use-id used)
|
||||
(+ (-> block data mem-use-id used) obj-size)
|
||||
)
|
||||
(set! (-> block data mem-use-id total)
|
||||
(+ (-> block data mem-use-id total) (logand -16 (+ obj-size 15)))
|
||||
)
|
||||
)
|
||||
|
||||
;; add the tags
|
||||
(dotimes (tag-idx (-> obj length))
|
||||
(when (zero? (-> obj tag tag-idx inlined?))
|
||||
(let* ((a1-4 obj)
|
||||
(a0-15 tag-idx)
|
||||
(tag-data
|
||||
(the-as basic
|
||||
(-> (the-as (pointer uint32) (&+ (-> a1-4 data-base) (-> a1-4 tag a0-15 data-offset)))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
;; ref to non-inline data. Inline data would have been counted above.
|
||||
(when (not (part-group-pointer? (the-as pointer tag-data)))
|
||||
(case (-> (the-as basic tag-data) type)
|
||||
((symbol type)
|
||||
)
|
||||
((string)
|
||||
;; strings add like a normal object.
|
||||
;; this seems identical to the else case.
|
||||
(set! (-> block length) (max (-> block length) (+ mem-use-id 1)))
|
||||
(set! (-> block data mem-use-id name) mem-use-name)
|
||||
(set! (-> block data mem-use-id count)
|
||||
(+ (-> block data mem-use-id count) 1)
|
||||
)
|
||||
(let ((v1-47 (asize-of tag-data)))
|
||||
(set! (-> block data mem-use-id used)
|
||||
(+ (-> block data mem-use-id used) v1-47)
|
||||
)
|
||||
(set! (-> block data mem-use-id total)
|
||||
(+ (-> block data mem-use-id total) (logand -16 (+ v1-47 15)))
|
||||
)
|
||||
)
|
||||
)
|
||||
((nav-mesh collide-mesh)
|
||||
;; these have their own implementation.
|
||||
(mem-usage tag-data block flags)
|
||||
)
|
||||
((array)
|
||||
(set! (-> block length) (max (-> block length) (+ mem-use-id 1)))
|
||||
(set! (-> block data mem-use-id name) mem-use-name)
|
||||
(set! (-> block data mem-use-id count)
|
||||
(+ (-> block data mem-use-id count) 1)
|
||||
)
|
||||
(let ((v1-63 (asize-of (the-as (array object) tag-data))))
|
||||
(set! (-> block data mem-use-id used)
|
||||
(+ (-> block data mem-use-id used) v1-63)
|
||||
)
|
||||
(set! (-> block data mem-use-id total)
|
||||
(+ (-> block data mem-use-id total) (logand -16 (+ v1-63 15)))
|
||||
)
|
||||
)
|
||||
;; call mem usage on all of our children.
|
||||
(set! sv-16 0)
|
||||
(while (< sv-16 (-> (the-as array tag-data) length))
|
||||
(let ((a0-58 (-> (the-as (array object) tag-data) sv-16)))
|
||||
((method-of-type (rtype-of a0-58) mem-usage) a0-58 block flags)
|
||||
)
|
||||
(set! sv-16 (+ sv-16 1))
|
||||
)
|
||||
)
|
||||
(else
|
||||
;; unknown type.
|
||||
;; we assume its nothing fancy and use the asize of.
|
||||
(set! (-> block length) (max (-> block length) (+ mem-use-id 1)))
|
||||
(set! (-> block data mem-use-id name) mem-use-name)
|
||||
(set! (-> block data mem-use-id count)
|
||||
(+ (-> block data mem-use-id count) 1)
|
||||
)
|
||||
(let ((v1-88 (asize-of tag-data)))
|
||||
(set! (-> block data mem-use-id used)
|
||||
(+ (-> block data mem-use-id used) v1-88)
|
||||
)
|
||||
(set! (-> block data mem-use-id total)
|
||||
(+ (-> block data mem-use-id total) (logand -16 (+ v1-88 15)))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(the-as res-lump 0)
|
||||
)
|
||||
|
||||
|
||||
(define *res-static-buf* (malloc 'global 128))
|
||||
|
|
|
@ -81,3 +81,5 @@
|
|||
:size-assert #x34
|
||||
:flag-assert #x900000034
|
||||
)
|
||||
|
||||
(define-extern part-group-pointer? (function pointer symbol))
|
||||
|
|
|
@ -1388,3 +1388,13 @@
|
|||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; the decompiler may fail to recognize setting fields of a 128-bit bitfield
|
||||
;; and will rely on this macro:
|
||||
(defmacro copy-and-set-field (original field-name field-value)
|
||||
`(let ((temp-copy ,original))
|
||||
(set! (-> temp-copy ,field-name) ,field-value)
|
||||
temp-copy
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -190,3 +190,10 @@
|
|||
`(* (/ 1.0 ,TICKS_PER_SECOND) ,vel)
|
||||
)
|
||||
|
||||
(defmacro copy-and-set-field (original field-name field-value)
|
||||
`(let ((temp-copy ,original))
|
||||
(set! (-> temp-copy ,field-name) ,field-value)
|
||||
temp-copy
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -36,10 +36,10 @@
|
|||
(get-property-value-float (_type_ symbol symbol float float (pointer res-tag) pointer) float :no-virtual 12)
|
||||
(get-tag-index-data (_type_ int) pointer 13)
|
||||
(get-tag-data (_type_ res-tag) pointer 14)
|
||||
(dummy-15 (_type_ res-tag) res-tag 15)
|
||||
(allocate-data-memory-for-tag! (_type_ res-tag) res-tag 15)
|
||||
(sort! (_type_) _type_ 16)
|
||||
(dummy-17 (_type_ res-tag pointer) res-lump 17)
|
||||
(dummy-18 (_type_ res-tag res-tag) res-lump 18)
|
||||
(add-data! (_type_ res-tag pointer) res-lump 17)
|
||||
(add-32bit-data! (_type_ res-tag object) res-lump 18)
|
||||
(lookup-tag-idx (_type_ symbol symbol float) res-tag-pair :no-virtual 19)
|
||||
(make-property-data (_type_ float res-tag-pair pointer) pointer 20)
|
||||
(get-curve-data! (_type_ curve symbol symbol float) symbol 21)
|
||||
|
@ -47,6 +47,7 @@
|
|||
)
|
||||
|
||||
;; definition for method 3 of type res-lump
|
||||
;; INFO: this function exists in multiple non-identical object files
|
||||
(defmethod inspect res-lump ((obj res-lump))
|
||||
(format #t "[~8x] ~A~%" obj (-> obj type))
|
||||
(format #t "~Tlength: ~D~%" (-> obj length))
|
||||
|
|
1151
test/decompiler/reference/engine/data/res_REF.gc
Normal file
1151
test/decompiler/reference/engine/data/res_REF.gc
Normal file
File diff suppressed because it is too large
Load diff
|
@ -726,12 +726,9 @@
|
|||
;; INFO: Return type mismatch object vs function.
|
||||
(defun debug-menu-func-decode ((arg0 object))
|
||||
(let ((v1-1 (rtype-of arg0)))
|
||||
(the-as function (the-as symbol (cond
|
||||
(the-as function (cond
|
||||
((or (= v1-1 symbol) (= v1-1 type))
|
||||
(the-as
|
||||
symbol
|
||||
(-> (the-as symbol arg0) value)
|
||||
)
|
||||
(the-as symbol (-> (the-as symbol arg0) value))
|
||||
)
|
||||
((= v1-1 function)
|
||||
(the-as symbol arg0)
|
||||
|
@ -743,7 +740,6 @@
|
|||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for function debug-menu-make-from-template
|
||||
;; WARN: Stack slot load mismatch: defined as size 4, got size 16
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
;; INFO: Return type mismatch object vs cspace.
|
||||
(defun cspace-by-name-no-fail ((arg0 process-drawable) (arg1 string))
|
||||
(let ((result (cspace-by-name arg0 arg1)))
|
||||
(the-as cspace (the-as cspace (cond
|
||||
(the-as cspace (cond
|
||||
(result
|
||||
(empty)
|
||||
(the-as cspace result)
|
||||
|
@ -18,7 +18,6 @@
|
|||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for function cspace-index-by-name-no-fail
|
||||
(defun cspace-index-by-name-no-fail ((arg0 process-drawable) (arg1 string))
|
||||
|
|
|
@ -166,7 +166,7 @@
|
|||
(-> arg0 method-table 13)
|
||||
(the-as function (-> v1-1 a1-0))
|
||||
)
|
||||
(return (-> v1-1 a1-0))
|
||||
(return (the-as entity-info (-> v1-1 a1-0)))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -5417,7 +5417,7 @@
|
|||
(task-available? (-> gp-0 stage s5-0) gp-0)
|
||||
)
|
||||
(first-any gp-0 #t)
|
||||
(return (the-as int (-> gp-0 stage s5-0 status)))
|
||||
(return (the-as task-status (-> gp-0 stage s5-0 status)))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue