get res decompiling (#705)

This commit is contained in:
water111 2021-07-17 13:41:05 -04:00 committed by GitHub
parent e7bc3eb3b0
commit 2754a8f2c4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 1832 additions and 119 deletions

View file

@ -187,13 +187,13 @@ TP_Type SimpleExpression::get_type(const TypeState& input,
case Kind::XOR: case Kind::XOR:
case Kind::LEFT_SHIFT: case Kind::LEFT_SHIFT:
case Kind::MUL_UNSIGNED: case Kind::MUL_UNSIGNED:
case Kind::PCPYLD:
return get_type_int2(input, env, dts); return get_type_int2(input, env, dts);
case Kind::NEG: case Kind::NEG:
case Kind::LOGNOT: case Kind::LOGNOT:
return get_type_int1(input, env, dts); return get_type_int1(input, env, dts);
case Kind::DIV_UNSIGNED: case Kind::DIV_UNSIGNED:
case Kind::MOD_UNSIGNED: case Kind::MOD_UNSIGNED:
case Kind::PCPYLD:
return TP_Type::make_from_ts("uint"); return TP_Type::make_from_ts("uint");
case Kind::VECTOR_PLUS: case Kind::VECTOR_PLUS:
case Kind::VECTOR_MINUS: case Kind::VECTOR_MINUS:
@ -427,6 +427,21 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input,
break; 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) { if (arg0_type.kind == TP_Type::Kind::INTEGER_CONSTANT_PLUS_VAR_MULT && m_kind == Kind::ADD) {
FieldReverseLookupInput rd_in; FieldReverseLookupInput rd_in;
rd_in.offset = arg0_type.get_add_int_constant(); rd_in.offset = arg0_type.get_add_int_constant();

View file

@ -82,6 +82,7 @@ class Env {
VariableWithCast get_variable_and_cast(const RegisterAccess& access) const; VariableWithCast get_variable_and_cast(const RegisterAccess& access) const;
std::optional<TypeSpec> get_user_cast_for_access(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; 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. * Get the types in registers _after_ the given operation has completed.

View file

@ -1904,10 +1904,11 @@ void GenericElement::get_modified_regs(RegSet& regs) const {
CastElement::CastElement(TypeSpec type, Form* source, bool numeric) CastElement::CastElement(TypeSpec type, Form* source, bool numeric)
: m_type(std::move(type)), m_source(source), m_numeric(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 { goos::Object CastElement::to_form_internal(const Env& env) const {
// assert(m_source->parent_element == this);
auto atom = form_as_atom(m_source); auto atom = form_as_atom(m_source);
if (atom && atom->is_var()) { if (atom && atom->is_var()) {
return pretty_print::build_list( 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) { void CastElement::apply(const std::function<void(FormElement*)>& f) {
// assert(m_source->parent_element == this);
f(this); f(this);
m_source->apply(f); m_source->apply(f);
} }
void CastElement::apply_form(const std::function<void(Form*)>& f) { void CastElement::apply_form(const std::function<void(Form*)>& f) {
// assert(m_source->parent_element == this);
m_source->apply_form(f); m_source->apply_form(f);
} }
void CastElement::collect_vars(RegAccessSet& vars, bool recursive) const { void CastElement::collect_vars(RegAccessSet& vars, bool recursive) const {
// assert(m_source->parent_element == this);
if (recursive) { if (recursive) {
m_source->collect_vars(vars, recursive); m_source->collect_vars(vars, recursive);
} }
} }
void CastElement::get_modified_regs(RegSet& regs) const { void CastElement::get_modified_regs(RegSet& regs) const {
assert(m_source->parent_element == this);
m_source->get_modified_regs(regs); m_source->get_modified_regs(regs);
} }

View file

@ -54,6 +54,10 @@ class FormElement {
bool allow_side_effects); bool allow_side_effects);
bool is_popped() const { return m_popped; } bool is_popped() const { return m_popped; }
FormElement() = default;
FormElement(const FormElement& other) = delete;
FormElement& operator=(const FormElement& other) = delete;
void mark_popped() { void mark_popped() {
assert(!m_popped); assert(!m_popped);
m_popped = true; m_popped = true;

View file

@ -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>( auto new_form = pool.alloc_element<GenericElement>(
GenericOperator::make_fixed(FixedOperatorKind::PCPYLD), args.at(0), args.at(1)); GenericOperator::make_fixed(FixedOperatorKind::PCPYLD), args.at(0), args.at(1));
result->push_back(new_form); result->push_back(new_form);
@ -1262,16 +1285,45 @@ void SimpleExpressionElement::update_from_stack_logor_or_logand(const Env& env,
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result, std::vector<FormElement*>* result,
bool allow_side_effects) { bool allow_side_effects) {
// grab the normal variable type
auto arg0_type = env.get_variable_type(m_expr.get_arg(0).var(), true); 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 type_info = env.dts->ts.lookup_type(arg0_type);
auto bitfield_info = dynamic_cast<BitFieldType*>(type_info); 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()) { if (bitfield_info && m_expr.get_arg(1).is_int()) {
// andi, ori with bitfield. // andi, ori with bitfield.
auto base = pop_to_forms({m_expr.get_arg(0).var()}, env, pool, stack, allow_side_effects).at(0); 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()); auto read_elt = dynamic_cast<BitfieldAccessElement*>(base->try_as_single_element());
if (!read_elt) { 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; 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; bool made_new_read_elt = false;
auto read_elt = dynamic_cast<BitfieldAccessElement*>(args.at(0)->try_as_single_element()); auto read_elt = dynamic_cast<BitfieldAccessElement*>(args.at(0)->try_as_single_element());
if (!read_elt) { 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; 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 stripped_arg1 = strip_int_or_uint_cast(args.at(1));
auto arg1_atom = form_as_atom(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_as_int = get_goal_integer_constant(stripped_arg1, env);
if (arg1_as_int) {
BitfieldManip::Kind manip_kind; BitfieldManip::Kind manip_kind;
if (kind == FixedOperatorKind::LOGAND) { if (kind == FixedOperatorKind::LOGAND) {
manip_kind = BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT; manip_kind = BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT;
@ -1328,10 +1386,14 @@ void SimpleExpressionElement::update_from_stack_logor_or_logand(const Env& env,
} else { } else {
assert(false); 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); 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); result->push_back(read_elt);
}
return; return;
} else if (!made_new_read_elt) { } else if (!made_new_read_elt) {
BitfieldManip::Kind manip_kind; BitfieldManip::Kind manip_kind;
@ -1847,6 +1909,13 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
return; 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. // 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. // it is the Stack's responsibility to untangle these later on.
if (m_src->is_single_element()) { 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 // we aren't a reg-reg move, so update our source
m_src->update_children_from_stack(env, pool, stack, true); 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()) { for (auto x : m_src->elts()) {
assert(x->parent_form == m_src); 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: // check for bitfield setting:
auto src_as_bf_set = dynamic_cast<ModifiedCopyBitfieldElement*>(m_src->try_as_single_element()); 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 dst_form = m_dst->to_form(env);
auto src_form = src_as_bf_set->base()->to_form(env); auto src_form = src_as_bf_set->base()->to_form(env);
if (dst_form == src_form) { if (dst_form == src_form) {
@ -1933,6 +2024,8 @@ void SetFormFormElement::push_to_stack(const Env& env, FormPool& pool, FormStack
m_dst = loc; m_dst = loc;
m_src = value; 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); stack.push_form_element(this, true);
@ -2314,15 +2407,20 @@ void FunctionCallElement::update_from_stack(const Env& env,
"type."); "type.");
} }
if (!env.dts->ts.should_use_virtual_methods(tp_type.method_from_type(), bool is_res_lump = tp_type.method_from_type().base_type() == "res-lump";
tp_type.method_id())) { 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( throw std::runtime_error(
fmt::format("Method call on {} id {} used a virtual call unexpectedly.", fmt::format("Method call on {} id {} used a virtual call unexpectedly.",
tp_type.method_from_type().print(), tp_type.method_id())); tp_type.method_from_type().print(), tp_type.method_id()));
} }
if (should_use_virtual) {
// fmt::print("STACK\n{}\n\n", stack.print(env)); // fmt::print("STACK\n{}\n\n", stack.print(env));
auto pop = auto pop = pop_to_forms({*arg0_mr.maps.regs.at(0)}, env, pool, stack, allow_side_effects,
pop_to_forms({*arg0_mr.maps.regs.at(0)}, env, pool, stack, allow_side_effects, {}, {2}) {}, {2})
.at(0); .at(0);
// fmt::print("GOT: {}\n", pop->to_string(env)); // fmt::print("GOT: {}\n", pop->to_string(env));
arg_forms.at(0) = pop; 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)), new_form = pool.alloc_element<GenericElement>(GenericOperator::make_function(unstacked.at(0)),
arg_forms); arg_forms);
@ -3525,9 +3624,11 @@ void ReturnElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
} }
std::vector<FormElement*> new_entries; 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()); assert(!new_entries.empty());
return_code->clear(); return_code->clear();
for (int i = 0; i < ((int)new_entries.size()) - 1; i++) { 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()); 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); stack.push_form_element(this, true);
} }

View file

@ -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, auto elt = pool.alloc_element<SetVarElement>(*e.destination, simplified_source,
e.sequence_point, type, e.set_info); e.sequence_point, type, e.set_info);
e.source->parent_element = elt;
auto final_elt = try_rewrites_in_place(elt, env, pool); auto final_elt = try_rewrites_in_place(elt, env, pool);
simplified_source->parent_element = final_elt;
result.push_back(final_elt); result.push_back(final_elt);
} else { } else {
result.push_back(e.elt); result.push_back(e.elt);
@ -411,7 +411,6 @@ std::optional<RegisterAccess> rewrite_to_get_var(std::vector<FormElement*>& defa
return {}; return {};
} else { } else {
for (auto x : result) { for (auto x : result) {
x->parent_form = nullptr;
default_result.push_back(x); default_result.push_back(x);
} }
return result_access; return result_access;

View file

@ -6,6 +6,7 @@
#include "common/util/BitUtils.h" #include "common/util/BitUtils.h"
#include "decompiler/util/DecompilerTypeSystem.h" #include "decompiler/util/DecompilerTypeSystem.h"
#include "decompiler/IR2/GenericElementMatcher.h" #include "decompiler/IR2/GenericElementMatcher.h"
#include "decompiler/Function/Function.h"
namespace decompiler { namespace decompiler {
@ -84,8 +85,12 @@ void BitfieldStaticDefElement::get_modified_regs(RegSet& regs) const {
ModifiedCopyBitfieldElement::ModifiedCopyBitfieldElement( ModifiedCopyBitfieldElement::ModifiedCopyBitfieldElement(
const TypeSpec& type, const TypeSpec& type,
Form* base, Form* base,
bool from_pcpyud,
const std::vector<BitFieldDef>& field_modifications) 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; m_base->parent_element = this;
for (auto& mod : m_field_modifications) { for (auto& mod : m_field_modifications) {
if (mod.value) { if (mod.value) {
@ -95,13 +100,23 @@ ModifiedCopyBitfieldElement::ModifiedCopyBitfieldElement(
} }
goos::Object ModifiedCopyBitfieldElement::to_form_internal(const Env& env) const { 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)); result.push_back(m_base->to_form(env));
for (auto& def : m_field_modifications) { for (auto& def : m_field_modifications) {
result.push_back(pretty_print::to_symbol(fmt::format(":{}", def.field_name))); result.push_back(pretty_print::to_symbol(fmt::format(":{}", def.field_name)));
result.push_back(def.value->to_form(env)); result.push_back(def.value->to_form(env));
} }
return pretty_print::build_list(result); return pretty_print::build_list(result);
}
} }
void ModifiedCopyBitfieldElement::apply(const std::function<void(FormElement*)>& f) { void ModifiedCopyBitfieldElement::apply(const std::function<void(FormElement*)>& f) {
@ -220,7 +235,8 @@ BitField find_field(const TypeSystem& ts,
namespace { namespace {
std::optional<BitField> find_field_from_mask(const TypeSystem& ts, std::optional<BitField> find_field_from_mask(const TypeSystem& ts,
const BitFieldType* type, const BitFieldType* type,
uint64_t mask) { uint64_t mask,
bool upper_64) {
// try to find a field that is masked by this: // try to find a field that is masked by this:
auto mask_range = get_bit_range(mask); auto mask_range = get_bit_range(mask);
if (!mask_range) { if (!mask_range) {
@ -228,6 +244,10 @@ std::optional<BitField> find_field_from_mask(const TypeSystem& ts,
return {}; 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(), {}); 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, std::optional<BitFieldDef> get_bitfield_initial_set(Form* form,
const BitFieldType* type, const BitFieldType* type,
const TypeSystem& ts) { const TypeSystem& ts,
int offset_in_bitfield) {
// (shr (shl arg1 59) 44) for example // (shr (shl arg1 59) 44) for example
{ {
auto matcher = Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::SHR), 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 right = mr.maps.ints.at(2);
int size = 64 - left; int size = 64 - left;
int offset = left - right; 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; BitFieldDef def;
def.value = value; def.value = value;
def.field_name = f.name(); def.field_name = f.name();
@ -278,7 +299,7 @@ std::optional<BitFieldDef> get_bitfield_initial_set(Form* form,
int right = *power_of_two; int right = *power_of_two;
int size = 64 - left; int size = 64 - left;
int offset = left - right; 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; BitFieldDef def;
def.value = value; def.value = value;
def.field_name = f.name(); def.field_name = f.name();
@ -298,7 +319,7 @@ std::optional<BitFieldDef> get_bitfield_initial_set(Form* form,
int right = 0; int right = 0;
int size = 64 - left; int size = 64 - left;
int offset = left - right; 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; BitFieldDef def;
def.value = value; def.value = value;
def.field_name = f.name(); 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); auto value = mr_sllv.maps.forms.at(0);
int size = 32; int size = 32;
int offset = 0; int offset = 0;
auto f = find_field(ts, type, offset, size, {}); auto f = find_field(ts, type, offset + offset_in_bitfield, size, {});
BitFieldDef def; BitFieldDef def;
def.value = value; def.value = value;
def.field_name = f.name(); 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 * Add a step to the bitfield access. If this completes the access, returns a form representing the
* access * access
@ -434,9 +468,7 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
if (m_steps.empty() && step.kind == BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT) { if (m_steps.empty() && step.kind == BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT) {
// and with mask // and with mask
if (m_got_pcpyud) { // no need to do anything with pcpyud here.
throw std::runtime_error("unknown pcpyud LOGAND_WITH_CONSTANT_INT sequence in bitfield");
}
m_steps.push_back(step); m_steps.push_back(step);
return nullptr; return nullptr;
} }
@ -449,7 +481,7 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
auto type = ts.lookup_type(m_type); auto type = ts.lookup_type(m_type);
auto as_bitfield = dynamic_cast<BitFieldType*>(type); auto as_bitfield = dynamic_cast<BitFieldType*>(type);
assert(as_bitfield); 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) { if (field) {
auto get_field = pool.alloc_element<DerefElement>(m_base, false, auto get_field = pool.alloc_element<DerefElement>(m_base, false,
DerefToken::make_field_name(field->name())); 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 && if (m_steps.size() == 1 && m_steps.at(0).kind == BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT &&
step.kind == BitfieldManip::Kind::LOGIOR_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. // this is setting a bitfield to a constant.
// first, let's check that the mask is used properly: // first, let's check that the mask is used properly:
u64 mask = m_steps.at(0).amount; 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); auto as_bitfield = dynamic_cast<BitFieldType*>(type);
assert(as_bitfield); assert(as_bitfield);
// use the mask to figure out the field. // 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); assert(field);
bool is_signed = bool is_signed =
ts.tc(TypeSpec("int"), field->type()) && !ts.tc(TypeSpec("uint"), field->type()); 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. // use the field to figure out what value is being set.
u64 set_value; u64 set_value;
if (is_signed) { 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 { } 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; BitFieldDef def;
def.field_name = field->name(); def.field_name = field->name();
def.value = pool.alloc_single_element_form<SimpleAtomElement>( def.value = pool.alloc_single_element_form<SimpleAtomElement>(
nullptr, SimpleAtom::make_int_constant(set_value)); 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}); std::vector<BitFieldDef>{def});
} }
if (m_steps.size() == 1 && m_steps.at(0).kind == BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT && if (m_steps.size() == 1 && m_steps.at(0).kind == BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT &&
step.kind == BitfieldManip::Kind::LOGIOR_WITH_FORM) { 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 // this is setting a bitfield to a variable
u64 mask = m_steps.at(0).amount; 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); auto as_bitfield = dynamic_cast<BitFieldType*>(type);
assert(as_bitfield); assert(as_bitfield);
// use the mask to figure out the field. // 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); 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) { if (!val) {
throw std::runtime_error( throw std::runtime_error(
@ -524,7 +550,7 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
throw std::runtime_error("Incompatible bitfield set"); 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}); std::vector<BitFieldDef>{*val});
} }
@ -532,7 +558,10 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
for (auto& old_step : m_steps) { for (auto& old_step : m_steps) {
lg::error(" {}", old_step.print()); 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"); 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; 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 {}; return {};
} }
@ -713,8 +758,9 @@ Form* cast_to_bitfield(const BitFieldType* type_info,
// now variables // now variables
for (auto& arg : args) { for (auto& arg : args) {
// it's a 64-bit constant so correct to set offset 0 here.
auto maybe_field = 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) { if (!maybe_field) {
// failed, just return cast. // failed, just return cast.
return pool.alloc_single_element_form<CastElement>(nullptr, typespec, in); return pool.alloc_single_element_form<CastElement>(nullptr, typespec, in);

View file

@ -101,6 +101,8 @@ class BitfieldAccessElement : public FormElement {
FormPool& pool, FormPool& pool,
const Env& env); const Env& env);
void push_pcpyud(const TypeSystem& ts, 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: private:
bool m_got_pcpyud = false; bool m_got_pcpyud = false;
@ -155,6 +157,7 @@ class ModifiedCopyBitfieldElement : public FormElement {
public: public:
ModifiedCopyBitfieldElement(const TypeSpec& type, ModifiedCopyBitfieldElement(const TypeSpec& type,
Form* base, Form* base,
bool from_pcpyud,
const std::vector<BitFieldDef>& field_modifications); const std::vector<BitFieldDef>& field_modifications);
goos::Object to_form_internal(const Env& env) const override; goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override; void apply(const std::function<void(FormElement*)>& f) override;
@ -164,11 +167,17 @@ class ModifiedCopyBitfieldElement : public FormElement {
Form* base() const { return m_base; } Form* base() const { return m_base; }
const std::vector<BitFieldDef> mods() const { return m_field_modifications; } 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: private:
TypeSpec m_type; TypeSpec m_type;
Form* m_base = nullptr; Form* m_base = nullptr;
std::vector<BitFieldDef> m_field_modifications; std::vector<BitFieldDef> m_field_modifications;
bool m_from_pcpyud = false;
}; };
Form* cast_to_bitfield(const BitFieldType* type_info, Form* cast_to_bitfield(const BitFieldType* type_info,

View file

@ -85,11 +85,16 @@ bool convert_to_expressions(
if (!dts.ts.tc(f.type.last_arg(), return_type)) { if (!dts.ts.tc(f.type.last_arg(), return_type)) {
// we need to cast the final value. // we need to cast the final value.
auto to_cast = new_entries.back(); 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(); new_entries.pop_back();
auto cast = pool.alloc_element<CastElement>(f.type.last_arg(), auto cast = pool.alloc_element<CastElement>(f.type.last_arg(),
pool.alloc_single_form(nullptr, to_cast)); pool.alloc_single_form(nullptr, to_cast));
new_entries.push_back(cast); new_entries.push_back(cast);
} }
}
} else { } else {
// or just get all the expressions // or just get all the expressions
new_entries = stack.rewrite(pool, f.ir2.env); new_entries = stack.rewrite(pool, f.ir2.env);

View file

@ -79,8 +79,8 @@ Form* lca_form(Form* a, Form* b, const Env& env) {
bi--; bi--;
} }
if (!result) { if (!result) {
auto* bad = b->parent_element; fmt::print("{} bad form is {}\n\n{}\n", env.func->guessed_name.to_string(), a->to_string(env),
fmt::print("bad form is {} {}\n", bad->to_string(env), (void*)bad); b->to_string(env));
} }
assert(result); assert(result);

View file

@ -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); merge_infos(program_write_vars, program_read_vars, dts);
// copy types from input argument coloring moves: // copy types from input argument coloring moves:

View file

@ -9325,10 +9325,10 @@
(get-property-value-float (_type_ symbol symbol float float (pointer res-tag) pointer) float :no-virtual 12) (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-index-data (_type_ int) pointer 13)
(get-tag-data (_type_ res-tag) pointer 14) (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) (sort! (_type_) _type_ 16)
(dummy-17 (_type_ res-tag pointer) res-lump 17) (add-data! (_type_ res-tag pointer) res-lump 17)
(dummy-18 (_type_ res-tag res-tag) res-lump 18) (add-32bit-data! (_type_ res-tag object) res-lump 18)
(lookup-tag-idx (_type_ symbol symbol float) res-tag-pair :no-virtual 19) (lookup-tag-idx (_type_ symbol symbol float) res-tag-pair :no-virtual 19)
(make-property-data (_type_ float res-tag-pair pointer) pointer 20) (make-property-data (_type_ float res-tag-pair pointer) pointer 20)
(get-curve-data! (_type_ curve symbol symbol float) symbol 21) (get-curve-data! (_type_ curve symbol symbol float) symbol 21)
@ -9346,9 +9346,6 @@
;; Containing DGOs - ['GAME', 'ENGINE'] ;; Containing DGOs - ['GAME', 'ENGINE']
;; Version - 3 ;; Version - 3
;; - Functions
(define-extern part-group-pointer? function)
;; - Symbols ;; - Symbols
@ -13254,6 +13251,8 @@
) )
(define-extern part-group-pointer? (function pointer symbol))
;; ---------------------- ;; ----------------------
;; File - sparticle-h ;; File - sparticle-h
;; Source Path - engine/sparticle/sparticle-h.gc ;; Source Path - engine/sparticle/sparticle-h.gc

View file

@ -453,7 +453,12 @@
"trajectory": [["L18", "uint64", true]], "trajectory": [["L18", "uint64", true]],
"res": [["L150", "uint64", true]], "res": [
["L150", "uint64", true],
["L152", "uint64", true],
["L151", "uint64", true],
["L153", "uint64", true]
],
"ripple": [ "ripple": [
["L73", "float", true], ["L73", "float", true],
@ -559,9 +564,7 @@
["L12", "uint64", true] ["L12", "uint64", true]
], ],
"shadow-cpu": [ "shadow-cpu": [["L122", "shadow-data", true]],
["L122", "shadow-data", true]
],
"entity-table": [["L8", "(array entity-info)", true]], "entity-table": [["L8", "(array entity-info)", true]],

View file

@ -414,9 +414,7 @@
[157, "a0", "(pointer process-drawable)"] [157, "a0", "(pointer process-drawable)"]
], ],
"load-game-text-info": [ "load-game-text-info": [[4, "v1", "game-text-info"]],
[4, "v1", "game-text-info"]
],
"texture-relocate": [ "texture-relocate": [
[[17, 21], "t4", "dma-packet"], [[17, 21], "t4", "dma-packet"],
@ -506,12 +504,29 @@
[22, "t1", "(pointer uint64)"], [22, "t1", "(pointer uint64)"],
[29, "t2", "(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)": [ "(method 21 res-lump)": [
["_stack_", 16, "res-tag"], ["_stack_", 16, "res-tag"],
["_stack_", 32, "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 // SHADOW-CPU-H
"(method 10 shadow-control)": [[1, "v1", "int"]], "(method 10 shadow-control)": [[1, "v1", "int"]],
@ -1172,5 +1187,7 @@
"blackout": [[[20, 24], "v1", "dma-packet"]], "blackout": [[[20, 24], "v1", "dma-packet"]],
"(method 10 external-art-control)": [[18, "v1", "pointer"]],
"placeholder-do-not-add-below": [] "placeholder-do-not-add-below": []
} }

View file

@ -1798,7 +1798,29 @@
}, },
"(method 15 res-lump)": { "(method 15 res-lump)": {
"vars": { "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"
} }
}, },

View file

@ -67,6 +67,8 @@ std::string TP_Type::print() const {
} }
case Kind::PCPYUD_BITFIELD: case Kind::PCPYUD_BITFIELD:
return fmt::format("<pcpyud {}>", m_ts.print()); return fmt::format("<pcpyud {}>", m_ts.print());
case Kind::PCPYUD_BITFIELD_AND:
return fmt::format("<pcpyud-and {}>", m_ts.print());
case Kind::LABEL_ADDR: case Kind::LABEL_ADDR:
return "<label-addr>"; return "<label-addr>";
case Kind::INVALID: 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; return m_int == other.m_int && m_ts == other.m_ts && m_pcpyud == other.m_pcpyud;
case Kind::PCPYUD_BITFIELD: case Kind::PCPYUD_BITFIELD:
return m_pcpyud == other.m_pcpyud && m_ts == other.m_ts; 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: case Kind::LABEL_ADDR:
return true; return true;
case Kind::INVALID: case Kind::INVALID:
@ -177,6 +181,8 @@ TypeSpec TP_Type::typespec() const {
return TypeSpec("int"); // ideally this is never used. return TypeSpec("int"); // ideally this is never used.
case Kind::PCPYUD_BITFIELD: case Kind::PCPYUD_BITFIELD:
return TypeSpec("int"); return TypeSpec("int");
case Kind::PCPYUD_BITFIELD_AND:
return TypeSpec("int");
case Kind::LABEL_ADDR: case Kind::LABEL_ADDR:
return TypeSpec("pointer"); // ? return TypeSpec("pointer"); // ?
case Kind::INVALID: case Kind::INVALID:

View file

@ -33,6 +33,7 @@ class TP_Type {
VIRTUAL_METHOD, VIRTUAL_METHOD,
NON_VIRTUAL_METHOD, NON_VIRTUAL_METHOD,
PCPYUD_BITFIELD, PCPYUD_BITFIELD,
PCPYUD_BITFIELD_AND,
LEFT_SHIFTED_BITFIELD, // (bitfield << some-constant) LEFT_SHIFTED_BITFIELD, // (bitfield << some-constant)
LABEL_ADDR, LABEL_ADDR,
INVALID INVALID
@ -62,6 +63,7 @@ class TP_Type {
case Kind::NON_VIRTUAL_METHOD: case Kind::NON_VIRTUAL_METHOD:
case Kind::LEFT_SHIFTED_BITFIELD: case Kind::LEFT_SHIFTED_BITFIELD:
case Kind::PCPYUD_BITFIELD: case Kind::PCPYUD_BITFIELD:
case Kind::PCPYUD_BITFIELD_AND:
case Kind::LABEL_ADDR: case Kind::LABEL_ADDR:
return false; return false;
case Kind::UNINITIALIZED: case Kind::UNINITIALIZED:
@ -244,6 +246,14 @@ class TP_Type {
return result; 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() { static TP_Type make_label_addr() {
TP_Type result; TP_Type result;
result.kind = Kind::LABEL_ADDR; result.kind = Kind::LABEL_ADDR;
@ -296,7 +306,8 @@ class TP_Type {
} }
const TypeSpec& get_bitfield_type() const { 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; return m_ts;
} }

View file

@ -47,10 +47,10 @@
(get-property-value-float (_type_ symbol symbol float float (pointer res-tag) pointer) float :no-virtual 12) (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-index-data (_type_ int) pointer 13)
(get-tag-data (_type_ res-tag) pointer 14) (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) (sort! (_type_) _type_ 16)
(dummy-17 (_type_ res-tag pointer) res-lump 17) (add-data! (_type_ res-tag pointer) res-lump 17)
(dummy-18 (_type_ res-tag res-tag) res-lump 18) (add-32bit-data! (_type_ res-tag object) res-lump 18)
(lookup-tag-idx (_type_ symbol symbol float) res-tag-pair :no-virtual 19) (lookup-tag-idx (_type_ symbol symbol float) res-tag-pair :no-virtual 19)
(make-property-data (_type_ float res-tag-pair pointer) pointer 20) (make-property-data (_type_ float res-tag-pair pointer) pointer 20)
(get-curve-data! (_type_ curve symbol symbol float) symbol 21) (get-curve-data! (_type_ curve symbol symbol float) symbol 21)

View file

@ -67,7 +67,7 @@ This is updated from the entity system used in Crash 2, which had most of these
(the int (the int
(if (res-ref? obj) (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)) (* (-> 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 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)) (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." "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 (define-extern part-group-pointer? (function pointer symbol))
;; method 17 res-lump (declare-type nav-mesh basic)
;; method 18 res-lump (declare-type collide-mesh basic)
;; mem-usage res-lump (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)) (define *res-static-buf* (malloc 'global 128))

View file

@ -81,3 +81,5 @@
:size-assert #x34 :size-assert #x34
:flag-assert #x900000034 :flag-assert #x900000034
) )
(define-extern part-group-pointer? (function pointer symbol))

View file

@ -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
)
)

View file

@ -190,3 +190,10 @@
`(* (/ 1.0 ,TICKS_PER_SECOND) ,vel) `(* (/ 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
)
)

View file

@ -36,10 +36,10 @@
(get-property-value-float (_type_ symbol symbol float float (pointer res-tag) pointer) float :no-virtual 12) (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-index-data (_type_ int) pointer 13)
(get-tag-data (_type_ res-tag) pointer 14) (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) (sort! (_type_) _type_ 16)
(dummy-17 (_type_ res-tag pointer) res-lump 17) (add-data! (_type_ res-tag pointer) res-lump 17)
(dummy-18 (_type_ res-tag res-tag) res-lump 18) (add-32bit-data! (_type_ res-tag object) res-lump 18)
(lookup-tag-idx (_type_ symbol symbol float) res-tag-pair :no-virtual 19) (lookup-tag-idx (_type_ symbol symbol float) res-tag-pair :no-virtual 19)
(make-property-data (_type_ float res-tag-pair pointer) pointer 20) (make-property-data (_type_ float res-tag-pair pointer) pointer 20)
(get-curve-data! (_type_ curve symbol symbol float) symbol 21) (get-curve-data! (_type_ curve symbol symbol float) symbol 21)
@ -47,6 +47,7 @@
) )
;; definition for method 3 of type res-lump ;; 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)) (defmethod inspect res-lump ((obj res-lump))
(format #t "[~8x] ~A~%" obj (-> obj type)) (format #t "[~8x] ~A~%" obj (-> obj type))
(format #t "~Tlength: ~D~%" (-> obj length)) (format #t "~Tlength: ~D~%" (-> obj length))

File diff suppressed because it is too large Load diff

View file

@ -726,12 +726,9 @@
;; INFO: Return type mismatch object vs function. ;; INFO: Return type mismatch object vs function.
(defun debug-menu-func-decode ((arg0 object)) (defun debug-menu-func-decode ((arg0 object))
(let ((v1-1 (rtype-of arg0))) (let ((v1-1 (rtype-of arg0)))
(the-as function (the-as symbol (cond (the-as function (cond
((or (= v1-1 symbol) (= v1-1 type)) ((or (= v1-1 symbol) (= v1-1 type))
(the-as (the-as symbol (-> (the-as symbol arg0) value))
symbol
(-> (the-as symbol arg0) value)
)
) )
((= v1-1 function) ((= v1-1 function)
(the-as symbol arg0) (the-as symbol arg0)
@ -743,7 +740,6 @@
) )
) )
) )
)
;; definition for function debug-menu-make-from-template ;; definition for function debug-menu-make-from-template
;; WARN: Stack slot load mismatch: defined as size 4, got size 16 ;; WARN: Stack slot load mismatch: defined as size 4, got size 16

View file

@ -5,7 +5,7 @@
;; INFO: Return type mismatch object vs cspace. ;; INFO: Return type mismatch object vs cspace.
(defun cspace-by-name-no-fail ((arg0 process-drawable) (arg1 string)) (defun cspace-by-name-no-fail ((arg0 process-drawable) (arg1 string))
(let ((result (cspace-by-name arg0 arg1))) (let ((result (cspace-by-name arg0 arg1)))
(the-as cspace (the-as cspace (cond (the-as cspace (cond
(result (result
(empty) (empty)
(the-as cspace result) (the-as cspace result)
@ -18,7 +18,6 @@
) )
) )
) )
)
;; definition for function cspace-index-by-name-no-fail ;; definition for function cspace-index-by-name-no-fail
(defun cspace-index-by-name-no-fail ((arg0 process-drawable) (arg1 string)) (defun cspace-index-by-name-no-fail ((arg0 process-drawable) (arg1 string))

View file

@ -166,7 +166,7 @@
(-> arg0 method-table 13) (-> arg0 method-table 13)
(the-as function (-> v1-1 a1-0)) (the-as function (-> v1-1 a1-0))
) )
(return (-> v1-1 a1-0)) (return (the-as entity-info (-> v1-1 a1-0)))
) )
) )
) )

View file

@ -5417,7 +5417,7 @@
(task-available? (-> gp-0 stage s5-0) gp-0) (task-available? (-> gp-0 stage s5-0) gp-0)
) )
(first-any gp-0 #t) (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)))
) )
) )
) )