mirror of
https://github.com/open-goal/jak-project
synced 2026-08-16 21:28:00 -04:00
[decompiler] Several small fixes (#775)
* fix assorted bugs * stricter return types * only look for functions in code files
This commit is contained in:
@@ -1121,6 +1121,21 @@ void StoreOp::collect_vars(RegAccessSet& vars) const {
|
||||
// LoadVarOp
|
||||
/////////////////////////////
|
||||
|
||||
std::string load_kind_to_string(LoadVarOp::Kind kind) {
|
||||
switch (kind) {
|
||||
case LoadVarOp::Kind::FLOAT:
|
||||
return "float";
|
||||
case LoadVarOp::Kind::VECTOR_FLOAT:
|
||||
return "vector-float";
|
||||
case LoadVarOp::Kind::SIGNED:
|
||||
return "signed";
|
||||
case LoadVarOp::Kind::UNSIGNED:
|
||||
return "unsigned";
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
LoadVarOp::LoadVarOp(Kind kind, int size, RegisterAccess dst, SimpleExpression src, int my_idx)
|
||||
: AtomicOp(my_idx), m_kind(kind), m_size(size), m_dst(dst), m_src(std::move(src)) {}
|
||||
|
||||
|
||||
@@ -467,7 +467,7 @@ class StoreOp : public AtomicOp {
|
||||
*/
|
||||
class LoadVarOp : public AtomicOp {
|
||||
public:
|
||||
enum class Kind { UNSIGNED, SIGNED, FLOAT, VECTOR_FLOAT };
|
||||
enum class Kind { UNSIGNED, SIGNED, FLOAT, VECTOR_FLOAT, INVALID };
|
||||
LoadVarOp(Kind kind, int size, RegisterAccess dst, SimpleExpression src, int my_idx);
|
||||
goos::Object to_form(const std::vector<DecompilerLabel>& labels, const Env& env) const override;
|
||||
bool operator==(const AtomicOp& other) const override;
|
||||
@@ -490,6 +490,13 @@ class LoadVarOp : public AtomicOp {
|
||||
std::optional<TypeSpec> m_type;
|
||||
};
|
||||
|
||||
std::string load_kind_to_string(LoadVarOp::Kind kind);
|
||||
FormElement* make_label_load(int label_idx,
|
||||
const Env& env,
|
||||
FormPool& pool,
|
||||
int load_size,
|
||||
LoadVarOp::Kind load_kind);
|
||||
|
||||
/*!
|
||||
* This represents one of the possible instructions that can go in a branch delay slot.
|
||||
* These will be "absorbed" into higher level structures, but for the purpose of printing AtomicOps,
|
||||
|
||||
@@ -476,6 +476,82 @@ FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const {
|
||||
return pool.alloc_element<StoreElement>(this);
|
||||
}
|
||||
|
||||
FormElement* make_label_load(int label_idx,
|
||||
const Env& env,
|
||||
FormPool& pool,
|
||||
int load_size,
|
||||
LoadVarOp::Kind load_kind) {
|
||||
auto label = env.file->labels.at(label_idx);
|
||||
auto label_name = label.name;
|
||||
auto hint = env.label_types().find(label_name);
|
||||
if (hint != env.label_types().end()) {
|
||||
if (hint->second.is_const) {
|
||||
if ((load_kind == LoadVarOp::Kind::FLOAT || load_kind == LoadVarOp::Kind::SIGNED) &&
|
||||
load_size == 4 && hint->second.type_name == "float") {
|
||||
assert((label.offset % 4) == 0);
|
||||
auto word = env.file->words_by_seg.at(label.target_segment).at(label.offset / 4);
|
||||
assert(word.kind == LinkedWord::PLAIN_DATA);
|
||||
float value;
|
||||
memcpy(&value, &word.data, 4);
|
||||
return pool.alloc_element<ConstantFloatElement>(value);
|
||||
} else if (hint->second.type_name == "uint64" && load_kind != LoadVarOp::Kind::FLOAT &&
|
||||
load_size == 8) {
|
||||
assert((label.offset % 8) == 0);
|
||||
auto word0 = env.file->words_by_seg.at(label.target_segment).at(label.offset / 4);
|
||||
auto word1 = env.file->words_by_seg.at(label.target_segment).at(1 + (label.offset / 4));
|
||||
assert(word0.kind == LinkedWord::PLAIN_DATA);
|
||||
assert(word1.kind == LinkedWord::PLAIN_DATA);
|
||||
u64 value;
|
||||
memcpy(&value, &word0.data, 4);
|
||||
memcpy(((u8*)&value) + 4, &word1.data, 4);
|
||||
return pool.alloc_element<CastElement>(TypeSpec("uint"),
|
||||
pool.alloc_single_element_form<SimpleAtomElement>(
|
||||
nullptr, SimpleAtom::make_int_constant(value)));
|
||||
}
|
||||
|
||||
// is it a constant bitfield?
|
||||
auto& ts = env.dts->ts;
|
||||
auto as_bitfield = dynamic_cast<BitFieldType*>(ts.lookup_type(hint->second.type_name));
|
||||
if (as_bitfield && load_kind != LoadVarOp::Kind::FLOAT && load_size == 8) {
|
||||
// get the data
|
||||
assert((label.offset % 8) == 0);
|
||||
auto word0 = env.file->words_by_seg.at(label.target_segment).at(label.offset / 4);
|
||||
auto word1 = env.file->words_by_seg.at(label.target_segment).at(1 + (label.offset / 4));
|
||||
assert(word0.kind == LinkedWord::PLAIN_DATA);
|
||||
assert(word1.kind == LinkedWord::PLAIN_DATA);
|
||||
u64 value;
|
||||
memcpy(&value, &word0.data, 4);
|
||||
memcpy(((u8*)&value) + 4, &word1.data, 4);
|
||||
// for some reason, GOAL would use a 64-bit constant for all bitfields, even if they are
|
||||
// smaller. We should check that the higher bits are all zero.
|
||||
int bits = as_bitfield->get_size_in_memory() * 8;
|
||||
assert(bits <= 64);
|
||||
if (bits < 64) {
|
||||
assert((value >> bits) == 0);
|
||||
// technically ub if bits == 64.
|
||||
}
|
||||
TypeSpec typespec(hint->second.type_name);
|
||||
auto defs = decompile_bitfield_from_int(typespec, ts, value);
|
||||
return pool.alloc_element<BitfieldStaticDefElement>(typespec, defs, pool);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (load_kind == LoadVarOp::Kind::FLOAT && load_size == 4) {
|
||||
assert((label.offset % 4) == 0);
|
||||
const auto& words = env.file->words_by_seg.at(label.target_segment);
|
||||
if ((int)words.size() > label.offset / 4) {
|
||||
auto word = words.at(label.offset / 4);
|
||||
assert(word.kind == LinkedWord::PLAIN_DATA);
|
||||
float value;
|
||||
memcpy(&value, &word.data, 4);
|
||||
return pool.alloc_element<ConstantFloatElement>(value);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Form* LoadVarOp::get_load_src(FormPool& pool, const Env& env) const {
|
||||
if (env.has_type_analysis()) {
|
||||
IR2_RegOffset ro;
|
||||
@@ -584,6 +660,12 @@ Form* LoadVarOp::get_load_src(FormPool& pool, const Env& env) const {
|
||||
return pool.alloc_single_element_form<DerefElement>(nullptr, source, rd.addr_of, tokens);
|
||||
}
|
||||
|
||||
if (ro.offset == 0 && input_type.kind == TP_Type::Kind::LABEL_ADDR) {
|
||||
// we no longer resolve label stuff here because sometimes we need expressions for this
|
||||
return pool.alloc_single_element_form<LabelDerefElement>(nullptr, input_type.label_id(),
|
||||
m_size, m_kind, ro.var);
|
||||
}
|
||||
|
||||
if (ro.offset == 0 && (input_type.typespec() == TypeSpec("pointer") ||
|
||||
input_type.kind == TP_Type::Kind::OBJECT_PLUS_PRODUCT_WITH_CONSTANT)) {
|
||||
std::string cast_type;
|
||||
@@ -623,74 +705,9 @@ Form* LoadVarOp::get_load_src(FormPool& pool, const Env& env) const {
|
||||
}
|
||||
|
||||
if (m_src.is_identity() && m_src.get_arg(0).is_label()) {
|
||||
// try to see if we're loading a constant
|
||||
auto label = env.file->labels.at(m_src.get_arg(0).label());
|
||||
auto label_name = label.name;
|
||||
auto hint = env.label_types().find(label_name);
|
||||
if (hint != env.label_types().end()) {
|
||||
if (hint->second.is_const) {
|
||||
if ((m_kind == Kind::FLOAT || m_kind == Kind::SIGNED) && m_size == 4 &&
|
||||
hint->second.type_name == "float") {
|
||||
assert((label.offset % 4) == 0);
|
||||
auto word = env.file->words_by_seg.at(label.target_segment).at(label.offset / 4);
|
||||
assert(word.kind == LinkedWord::PLAIN_DATA);
|
||||
float value;
|
||||
memcpy(&value, &word.data, 4);
|
||||
return pool.alloc_single_element_form<ConstantFloatElement>(nullptr, value);
|
||||
} else if (hint->second.type_name == "uint64" && m_kind != Kind::FLOAT && m_size == 8) {
|
||||
assert((label.offset % 8) == 0);
|
||||
auto word0 = env.file->words_by_seg.at(label.target_segment).at(label.offset / 4);
|
||||
auto word1 = env.file->words_by_seg.at(label.target_segment).at(1 + (label.offset / 4));
|
||||
assert(word0.kind == LinkedWord::PLAIN_DATA);
|
||||
assert(word1.kind == LinkedWord::PLAIN_DATA);
|
||||
u64 value;
|
||||
memcpy(&value, &word0.data, 4);
|
||||
memcpy(((u8*)&value) + 4, &word1.data, 4);
|
||||
return pool.alloc_single_element_form<CastElement>(
|
||||
nullptr, TypeSpec("uint"),
|
||||
pool.alloc_single_element_form<SimpleAtomElement>(
|
||||
nullptr, SimpleAtom::make_int_constant(value)));
|
||||
}
|
||||
|
||||
// is it a constant bitfield?
|
||||
auto& ts = env.dts->ts;
|
||||
auto as_bitfield = dynamic_cast<BitFieldType*>(ts.lookup_type(hint->second.type_name));
|
||||
if (as_bitfield && m_kind != Kind::FLOAT && m_size == 8) {
|
||||
// get the data
|
||||
assert((label.offset % 8) == 0);
|
||||
auto word0 = env.file->words_by_seg.at(label.target_segment).at(label.offset / 4);
|
||||
auto word1 = env.file->words_by_seg.at(label.target_segment).at(1 + (label.offset / 4));
|
||||
assert(word0.kind == LinkedWord::PLAIN_DATA);
|
||||
assert(word1.kind == LinkedWord::PLAIN_DATA);
|
||||
u64 value;
|
||||
memcpy(&value, &word0.data, 4);
|
||||
memcpy(((u8*)&value) + 4, &word1.data, 4);
|
||||
// for some reason, GOAL would use a 64-bit constant for all bitfields, even if they are
|
||||
// smaller. We should check that the higher bits are all zero.
|
||||
int bits = as_bitfield->get_size_in_memory() * 8;
|
||||
assert(bits <= 64);
|
||||
if (bits < 64) {
|
||||
assert((value >> bits) == 0);
|
||||
// technically ub if bits == 64.
|
||||
}
|
||||
TypeSpec typespec(hint->second.type_name);
|
||||
auto defs = decompile_bitfield_from_int(typespec, ts, value);
|
||||
return pool.alloc_single_element_form<BitfieldStaticDefElement>(nullptr, typespec, defs,
|
||||
pool);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_kind == Kind::FLOAT && m_size == 4) {
|
||||
assert((label.offset % 4) == 0);
|
||||
const auto& words = env.file->words_by_seg.at(label.target_segment);
|
||||
if ((int)words.size() > label.offset / 4) {
|
||||
auto word = words.at(label.offset / 4);
|
||||
assert(word.kind == LinkedWord::PLAIN_DATA);
|
||||
float value;
|
||||
memcpy(&value, &word.data, 4);
|
||||
return pool.alloc_single_element_form<ConstantFloatElement>(nullptr, value);
|
||||
}
|
||||
auto label_load_element = make_label_load(m_src.get_arg(0).label(), env, pool, m_size, m_kind);
|
||||
if (label_load_element) {
|
||||
return pool.alloc_single_form(nullptr, label_load_element);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ TP_Type SimpleAtom::get_type(const TypeState& input,
|
||||
}
|
||||
// todo: should we take out this warning?
|
||||
lg::warn("IR_StaticAddress does not know the type of {}", label.name);
|
||||
return TP_Type::make_label_addr();
|
||||
return TP_Type::make_label_addr(m_int);
|
||||
}
|
||||
case Kind::INVALID:
|
||||
default:
|
||||
|
||||
@@ -2776,6 +2776,32 @@ void LabelElement::apply_form(const std::function<void(Form*)>&) {}
|
||||
void LabelElement::collect_vars(RegAccessSet&, bool) const {}
|
||||
void LabelElement::get_modified_regs(RegSet&) const {}
|
||||
|
||||
////////////////////////////////
|
||||
// LabelDerefElement
|
||||
///////////////////////////////
|
||||
|
||||
LabelDerefElement::LabelDerefElement(int lid,
|
||||
int size,
|
||||
LoadVarOp::Kind load_kind,
|
||||
RegisterAccess var)
|
||||
: m_lid(lid), m_size(size), m_load_kind(load_kind), m_var(var) {}
|
||||
|
||||
goos::Object LabelDerefElement::to_form_internal(const Env& env) const {
|
||||
return pretty_print::build_list(fmt::format("label-deref {} :label {} :size {} :kind {}",
|
||||
m_var.to_string(env), env.file->labels.at(m_lid).name,
|
||||
m_size, load_kind_to_string(m_load_kind)));
|
||||
}
|
||||
|
||||
void LabelDerefElement::apply(const std::function<void(FormElement*)>& f) {
|
||||
f(this);
|
||||
}
|
||||
|
||||
void LabelDerefElement::apply_form(const std::function<void(Form*)>&) {}
|
||||
void LabelDerefElement::collect_vars(RegAccessSet& regs, bool) const {
|
||||
regs.insert(m_var);
|
||||
}
|
||||
void LabelDerefElement::get_modified_regs(RegSet&) const {}
|
||||
|
||||
////////////////////////////////
|
||||
// GetSymbolStringPointer
|
||||
//////////////////////////////
|
||||
|
||||
@@ -632,6 +632,7 @@ class ReturnElement : public FormElement {
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
std::optional<TypeSpec> return_type;
|
||||
};
|
||||
|
||||
/*!
|
||||
@@ -1549,6 +1550,27 @@ class LabelElement : public FormElement {
|
||||
int m_lid = -1;
|
||||
};
|
||||
|
||||
class LabelDerefElement : public FormElement {
|
||||
public:
|
||||
LabelDerefElement(int lid, int size, LoadVarOp::Kind load_kind, RegisterAccess var);
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects) override;
|
||||
|
||||
private:
|
||||
int m_lid = -1;
|
||||
int m_size = -1;
|
||||
LoadVarOp::Kind m_load_kind = LoadVarOp::Kind::INVALID;
|
||||
RegisterAccess m_var;
|
||||
};
|
||||
|
||||
class GetSymbolStringPointer : public FormElement {
|
||||
public:
|
||||
GetSymbolStringPointer(Form* src);
|
||||
|
||||
@@ -3549,6 +3549,24 @@ FormElement* ConditionElement::make_zero_check_generic(const Env& env,
|
||||
return pool.alloc_element<GenericElement>(GenericOperator::make_compare(m_kind), source_forms);
|
||||
}
|
||||
|
||||
FormElement* try_make_nonzero_logtest(Form* in, FormPool& pool) {
|
||||
/*
|
||||
(defmacro logtest? (a b)
|
||||
"does a have any of the bits in b?"
|
||||
`(nonzero? (logand ,a ,b))
|
||||
)
|
||||
*/
|
||||
auto logand_matcher = Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::LOGAND),
|
||||
{Matcher::any(0), Matcher::any(1)});
|
||||
auto mr_logand = match(logand_matcher, in);
|
||||
if (mr_logand.matched) {
|
||||
return pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_fixed(FixedOperatorKind::LOGTEST), mr_logand.maps.forms.at(0),
|
||||
mr_logand.maps.forms.at(1));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FormElement* ConditionElement::make_nonzero_check_generic(const Env& env,
|
||||
FormPool& pool,
|
||||
const std::vector<Form*>& source_forms,
|
||||
@@ -3578,19 +3596,9 @@ FormElement* ConditionElement::make_nonzero_check_generic(const Env& env,
|
||||
std::vector<Form*>{mr.maps.forms.at(0), value_form});
|
||||
}
|
||||
|
||||
/*
|
||||
(defmacro logtest? (a b)
|
||||
"does a have any of the bits in b?"
|
||||
`(nonzero? (logand ,a ,b))
|
||||
)
|
||||
*/
|
||||
auto logand_matcher = Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::LOGAND),
|
||||
{Matcher::any(0), Matcher::any(1)});
|
||||
auto mr_logand = match(logand_matcher, source_forms.at(0));
|
||||
if (mr_logand.matched) {
|
||||
return pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_fixed(FixedOperatorKind::LOGTEST), mr_logand.maps.forms.at(0),
|
||||
mr_logand.maps.forms.at(1));
|
||||
auto as_logand = try_make_nonzero_logtest(source_forms.at(0), pool);
|
||||
if (as_logand) {
|
||||
return as_logand;
|
||||
}
|
||||
|
||||
return pool.alloc_element<GenericElement>(GenericOperator::make_compare(m_kind), source_forms);
|
||||
@@ -3967,7 +3975,8 @@ 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))) {
|
||||
return_type = env.get_variable_type(*var, false);
|
||||
if (func_type != return_type) {
|
||||
auto as_cast = return_code->try_as_element<CastElement>();
|
||||
if (as_cast) {
|
||||
return_code->clear();
|
||||
@@ -4643,13 +4652,25 @@ void ConditionalMoveFalseElement::push_to_stack(const Env& env, FormPool& pool,
|
||||
stack.push_form_element(this, true);
|
||||
return;
|
||||
}
|
||||
stack.push_value_to_reg(dest,
|
||||
pool.alloc_single_element_form<GenericElement>(
|
||||
nullptr,
|
||||
GenericOperator::make_compare(on_zero ? IR2_Condition::Kind::NONZERO
|
||||
: IR2_Condition::Kind::ZERO),
|
||||
std::vector<Form*>{popped.at(1)}),
|
||||
true, TypeSpec("symbol"));
|
||||
|
||||
Form* val = nullptr;
|
||||
|
||||
if (!val && on_zero) {
|
||||
auto as_logtest = try_make_nonzero_logtest(popped.at(1), pool);
|
||||
if (as_logtest) {
|
||||
val = pool.alloc_single_form(nullptr, as_logtest);
|
||||
}
|
||||
}
|
||||
|
||||
if (!val) {
|
||||
val = pool.alloc_single_element_form<GenericElement>(
|
||||
nullptr,
|
||||
GenericOperator::make_compare(on_zero ? IR2_Condition::Kind::NONZERO
|
||||
: IR2_Condition::Kind::ZERO),
|
||||
std::vector<Form*>{popped.at(1)});
|
||||
}
|
||||
|
||||
stack.push_value_to_reg(dest, val, true, TypeSpec("symbol"));
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
@@ -4951,6 +4972,32 @@ void DefstateElement::update_from_stack(const Env&,
|
||||
result->push_back(this);
|
||||
}
|
||||
|
||||
void LabelDerefElement::update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects) {
|
||||
mark_popped();
|
||||
auto label_var = pop_to_forms({m_var}, env, pool, stack, allow_side_effects).at(0);
|
||||
auto atom = form_as_atom(label_var);
|
||||
if (!atom || !atom->is_label()) {
|
||||
throw std::runtime_error(fmt::format("LabelDerefElement didn't get a label, got {} instead",
|
||||
label_var->to_string(env)));
|
||||
}
|
||||
|
||||
if (atom->label() != m_lid) {
|
||||
throw std::runtime_error(
|
||||
fmt::format("Label ID error in LabelDerefElement: {} vs {}", atom->label(), m_lid));
|
||||
}
|
||||
|
||||
auto as_label = make_label_load(m_lid, env, pool, m_size, m_load_kind);
|
||||
if (!as_label) {
|
||||
throw std::runtime_error(
|
||||
fmt::format("Unable to figure out label load for {}\n", env.file->labels.at(m_lid).name));
|
||||
}
|
||||
result->push_back(as_label);
|
||||
}
|
||||
|
||||
void LabelElement::push_to_stack(const Env&, FormPool&, FormStack& stack) {
|
||||
mark_popped();
|
||||
stack.push_form_element(this, true);
|
||||
|
||||
@@ -158,9 +158,11 @@ class ObjectFileDB {
|
||||
void for_each_function_in_seg(int seg, Func f) {
|
||||
for_each_obj([&](ObjectFileData& data) {
|
||||
int fn = 0;
|
||||
for (size_t j = data.linked_data.functions_by_seg.at(seg).size(); j-- > 0;) {
|
||||
f(data.linked_data.functions_by_seg.at(seg).at(j), data);
|
||||
fn++;
|
||||
if (data.linked_data.segments == 3) {
|
||||
for (size_t j = data.linked_data.functions_by_seg.at(seg).size(); j-- > 0;) {
|
||||
f(data.linked_data.functions_by_seg.at(seg).at(j), data);
|
||||
fn++;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -84,8 +84,31 @@ bool convert_to_expressions(
|
||||
}
|
||||
}
|
||||
|
||||
bool needs_cast = false;
|
||||
if (!dts.ts.tc(f.type.last_arg(), return_type)) {
|
||||
// we need to cast the final value.
|
||||
needs_cast = true;
|
||||
|
||||
} else {
|
||||
bool found_early_return = false;
|
||||
for (auto e : new_entries) {
|
||||
e->apply([&](FormElement* elt) {
|
||||
auto as_ret = dynamic_cast<ReturnElement*>(elt);
|
||||
if (as_ret) {
|
||||
found_early_return = true;
|
||||
}
|
||||
});
|
||||
if (found_early_return) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_early_return && f.type.last_arg() != return_type) {
|
||||
needs_cast = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (needs_cast) {
|
||||
auto to_cast = new_entries.back();
|
||||
auto as_cast = dynamic_cast<CastElement*>(to_cast);
|
||||
if (as_cast) {
|
||||
|
||||
@@ -640,7 +640,6 @@
|
||||
:bitfield #t
|
||||
:type uint32
|
||||
(display-marks 0)
|
||||
(bit0 0) ;; TODO - nav-enemy::45
|
||||
(bit1 1)
|
||||
(bit2 2)
|
||||
(bit3 3) ;; TODO - nav-enemy::45
|
||||
@@ -14752,7 +14751,7 @@
|
||||
(define-extern show-iop-info (function dma-buffer int))
|
||||
(define-extern show-iop-memory (function dma-buffer int))
|
||||
(define-extern make-sqrt-table (function int))
|
||||
(define-extern flava-lookup (function symbol int integer))
|
||||
(define-extern flava-lookup (function symbol int int))
|
||||
|
||||
;; - Symbols
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ std::string TP_Type::print() const {
|
||||
case Kind::PCPYUD_BITFIELD_AND:
|
||||
return fmt::format("<pcpyud-and {}>", m_ts.print());
|
||||
case Kind::LABEL_ADDR:
|
||||
return "<label-addr>";
|
||||
return fmt::format("<label-{}>", m_int);
|
||||
case Kind::ENTER_STATE_FUNCTION:
|
||||
return "<enter-state-func>";
|
||||
case Kind::INVALID:
|
||||
|
||||
@@ -262,9 +262,10 @@ class TP_Type {
|
||||
return result;
|
||||
}
|
||||
|
||||
static TP_Type make_label_addr() {
|
||||
static TP_Type make_label_addr(int label_id) {
|
||||
TP_Type result;
|
||||
result.kind = Kind::LABEL_ADDR;
|
||||
result.m_int = label_id;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -342,6 +343,11 @@ class TP_Type {
|
||||
return m_flipped_order;
|
||||
}
|
||||
|
||||
int label_id() const {
|
||||
assert(kind == Kind::LABEL_ADDR);
|
||||
return m_int;
|
||||
}
|
||||
|
||||
private:
|
||||
TypeSpec m_ts;
|
||||
TypeSpec m_method_from_type;
|
||||
|
||||
@@ -1255,11 +1255,22 @@ std::vector<std::string> decompile_bitfield_enum_from_int(const TypeSpec& type,
|
||||
return type_info->entries().at(a) < type_info->entries().at(b);
|
||||
});
|
||||
|
||||
for (auto& field_name : bit_sorted_names) {
|
||||
u64 mask = ((u64)1) << type_info->entries().at(field_name);
|
||||
for (auto& kv : type_info->entries()) {
|
||||
u64 mask = ((u64)1) << kv.second;
|
||||
if (value & mask) {
|
||||
reconstructed |= mask;
|
||||
result.push_back(field_name);
|
||||
result.push_back(kv.first);
|
||||
}
|
||||
}
|
||||
|
||||
int bit_count = 0;
|
||||
{
|
||||
u64 x = value;
|
||||
while (x) {
|
||||
if (x & 1) {
|
||||
bit_count++;
|
||||
}
|
||||
x >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1270,10 +1281,18 @@ std::vector<std::string> decompile_bitfield_enum_from_int(const TypeSpec& type,
|
||||
type.print(), value, reconstructed));
|
||||
}
|
||||
|
||||
// unordered map will give us these fields in a weird order, let's order them explicitly.
|
||||
std::sort(result.begin(), result.end(), [&](const std::string& a, const std::string& b) {
|
||||
return type_info->entries().at(a) < type_info->entries().at(b);
|
||||
});
|
||||
if (bit_count == (int)result.size()) {
|
||||
// unordered map will give us these fields in a weird order, let's order them explicitly.
|
||||
// because we have exactly one name per bit, we can just order them in bit order.
|
||||
std::sort(result.begin(), result.end(), [&](const std::string& a, const std::string& b) {
|
||||
return type_info->entries().at(a) < type_info->entries().at(b);
|
||||
});
|
||||
} else {
|
||||
// we have multiple. Just sort alphabetically and complain.
|
||||
lg::warn("Enum type {} has multiple entries with the same value.", type_info->get_name());
|
||||
std::sort(result.begin(), result.end());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -561,7 +561,7 @@
|
||||
(when
|
||||
(and
|
||||
(< 8192.0 f28-1)
|
||||
(nonzero? (logand (-> *camera* master-options) 2))
|
||||
(logtest? (-> *camera* master-options) 2)
|
||||
)
|
||||
(vector-!
|
||||
(the-as vector (-> s1-0 vector))
|
||||
|
||||
@@ -141,5 +141,5 @@
|
||||
|
||||
;; definition for method 11 of type vol-control
|
||||
(defmethod TODO-RENAME-11 vol-control ((obj vol-control))
|
||||
(and *display-vol-marks* (nonzero? (logand (-> obj flags) 1)))
|
||||
(and *display-vol-marks* (logtest? (-> obj flags) 1))
|
||||
)
|
||||
|
||||
@@ -1004,9 +1004,7 @@
|
||||
(+ tex-dest-base-chunk (the-as uint upload-chunk-idx))
|
||||
)
|
||||
;; can we possibly use existing data in VRAM?
|
||||
(set! need-tex
|
||||
(nonzero? (logand needed-mask (ash 1 upload-chunk-idx)))
|
||||
)
|
||||
(set! need-tex (logtest? needed-mask (ash 1 upload-chunk-idx)))
|
||||
;; look for the start of a run of uploads.
|
||||
(if (zero? chunks-to-upload-count)
|
||||
(when (and (!= (-> pool ids current-dest-chunk) page-id) need-tex)
|
||||
@@ -1579,7 +1577,7 @@
|
||||
(dotimes (v1-0 32)
|
||||
(let ((a2-0 (-> obj common-page v1-0)))
|
||||
(when (and (nonzero? a2-0) ;; known common texture page
|
||||
(nonzero? (logand (-> obj common-page-mask) (ash 1 v1-0))) ;; in the mask.
|
||||
(and (nonzero? a2-0) (logtest? (-> obj common-page-mask) (ash 1 v1-0))) ;; in the mask.
|
||||
)
|
||||
;; upload it!
|
||||
(upload-vram-pages obj (-> obj segment-common) a2-0 -2 (bucket-id bucket-65))
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
)
|
||||
|
||||
(defmethod display-water-marks? water-control ((obj water-control))
|
||||
(and *display-water-marks* (nonzero? (logand (-> obj flags) 1)))
|
||||
(and *display-water-marks* (logtest? (-> obj flags) 1))
|
||||
)
|
||||
|
||||
(defmethod new water-control ((allocation symbol) (type-to-make type) (arg0 process) (arg1 int) (arg2 float) (arg3 float) (arg4 float))
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
(defmethod get-bit bit-array ((obj bit-array) (idx int))
|
||||
"Is the bit at idx set or not?"
|
||||
(let ((v1-2 (-> obj bytes (/ idx 8))))
|
||||
(nonzero? (logand v1-2 (ash 1 (logand idx 7))))
|
||||
(logtest? v1-2 (ash 1 (logand idx 7)))
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
:bitfield #t
|
||||
:type uint32
|
||||
(display-marks 0)
|
||||
(bit0 0) ;; TODO - nav-enemy::45
|
||||
(bit1 1)
|
||||
(bit2 2)
|
||||
(bit3 3) ;; TODO - nav-enemy::45
|
||||
@@ -402,7 +401,7 @@
|
||||
(defmethod should-display? nav-control ((obj nav-control))
|
||||
(and
|
||||
*display-nav-marks*
|
||||
(nonzero? (logand (-> obj flags) (nav-control-flags bit0 display-marks)))
|
||||
(logtest? (-> obj flags) (nav-control-flags display-marks))
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
(defmethod should-display? path-control ((obj path-control))
|
||||
"Should we display path marks?"
|
||||
(and *display-path-marks*
|
||||
(nonzero? (logand (-> obj flags) (path-control-flag display)))
|
||||
(logtest? (-> obj flags) (path-control-flag display))
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
((let ((a0-5 obj))
|
||||
(and
|
||||
*display-path-marks*
|
||||
(nonzero? (logand (-> a0-5 flags) (path-control-flag display)))
|
||||
(logtest? (-> a0-5 flags) (path-control-flag display))
|
||||
)
|
||||
)
|
||||
(dotimes (s5-1 (-> obj curve num-cverts))
|
||||
@@ -412,12 +412,12 @@
|
||||
((let ((a0-5 obj))
|
||||
(and
|
||||
*display-path-marks*
|
||||
(nonzero? (logand (-> a0-5 flags) (path-control-flag display)))
|
||||
(logtest? (-> a0-5 flags) (path-control-flag display))
|
||||
)
|
||||
)
|
||||
(if
|
||||
(and
|
||||
(nonzero? (logand (-> obj flags) (path-control-flag draw-line)))
|
||||
(logtest? (-> obj flags) (path-control-flag draw-line))
|
||||
(> (-> obj curve num-cverts) 0)
|
||||
)
|
||||
(add-debug-curve2
|
||||
|
||||
@@ -826,7 +826,7 @@
|
||||
|
||||
(dotimes (i (-> *flava-table* count))
|
||||
(if (= (-> *flava-table* row i music) music)
|
||||
(return (-> *flava-table* row i flava n))
|
||||
(return (the-as int (-> *flava-table* row i flava n)))
|
||||
)
|
||||
)
|
||||
0
|
||||
|
||||
@@ -107,50 +107,46 @@
|
||||
;; INFO: Return type mismatch int vs none.
|
||||
(defmethod TODO-RENAME-39 nav-enemy ((obj nav-enemy))
|
||||
(when
|
||||
(and
|
||||
(logtest? (-> obj nav-enemy-flags) 256)
|
||||
(or
|
||||
(not *target*)
|
||||
(and
|
||||
(zero? (logand (-> *target* state-flags) #x80f8))
|
||||
(>=
|
||||
(the-as int (- (-> *display* base-frame-counter) (-> obj touch-time)))
|
||||
15
|
||||
)
|
||||
(and
|
||||
(logtest? (-> obj nav-enemy-flags) 256)
|
||||
(or
|
||||
(not *target*)
|
||||
(and
|
||||
(zero? (logand (-> *target* state-flags) #x80f8))
|
||||
(>=
|
||||
(the-as int (- (-> *display* base-frame-counter) (-> obj touch-time)))
|
||||
15
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(dummy-54 (-> obj collide-info) 2 1)
|
||||
(set! (-> obj nav-enemy-flags) (logand -257 (-> obj nav-enemy-flags)))
|
||||
)
|
||||
(dummy-54 (-> obj collide-info) 2 1)
|
||||
(set! (-> obj nav-enemy-flags) (logand -257 (-> obj nav-enemy-flags)))
|
||||
)
|
||||
((method-of-object (-> obj draw shadow-ctrl) dummy-14))
|
||||
(when *target*
|
||||
(if *target*
|
||||
(look-at-enemy!
|
||||
(-> *target* neck)
|
||||
(the-as vector (-> obj collide-info root-prim prim-core))
|
||||
(if (logtest? (-> obj nav-enemy-flags) 4)
|
||||
'attacking
|
||||
)
|
||||
obj
|
||||
)
|
||||
(if *target*
|
||||
(look-at-enemy!
|
||||
(-> *target* neck)
|
||||
(the-as vector (-> obj collide-info root-prim prim-core))
|
||||
(if (logtest? (-> obj nav-enemy-flags) 4)
|
||||
'attacking
|
||||
)
|
||||
obj
|
||||
)
|
||||
)
|
||||
(if (and (nonzero? (-> obj neck)) (logtest? (-> obj nav-enemy-flags) #x4000))
|
||||
(set-target!
|
||||
(-> obj neck)
|
||||
(target-pos (-> obj nav-info player-look-at-joint))
|
||||
)
|
||||
)
|
||||
)
|
||||
(if
|
||||
(and
|
||||
(nonzero? (-> obj neck))
|
||||
(nonzero? (logand (-> obj nav-enemy-flags) #x4000))
|
||||
)
|
||||
(set-target!
|
||||
(-> obj neck)
|
||||
(target-pos (-> obj nav-info player-look-at-joint))
|
||||
)
|
||||
)
|
||||
)
|
||||
(when (-> obj nav-info debug-draw-neck)
|
||||
(if (nonzero? (-> obj neck))
|
||||
(joint-mod-debug-draw (-> obj neck))
|
||||
(if (nonzero? (-> obj neck))
|
||||
(joint-mod-debug-draw (-> obj neck))
|
||||
)
|
||||
)
|
||||
)
|
||||
(ja-post)
|
||||
0
|
||||
(none)
|
||||
@@ -3168,7 +3164,7 @@ nav-enemy-default-event-handler
|
||||
)
|
||||
(logior!
|
||||
(-> obj nav flags)
|
||||
(nav-control-flags bit0 display-marks bit3 bit5 bit6 bit7)
|
||||
(nav-control-flags display-marks bit3 bit5 bit6 bit7)
|
||||
)
|
||||
(set! (-> obj nav gap-event) 'jump)
|
||||
(dummy-26 (-> obj nav))
|
||||
|
||||
@@ -557,7 +557,7 @@
|
||||
(when
|
||||
(and
|
||||
(< 8192.0 f28-1)
|
||||
(nonzero? (logand (-> *camera* master-options) 2))
|
||||
(logtest? (-> *camera* master-options) 2)
|
||||
)
|
||||
(vector-!
|
||||
(the-as vector (-> s1-0 vector))
|
||||
|
||||
@@ -166,13 +166,13 @@
|
||||
(let ((v1-32 #f))
|
||||
(set! a0-16 #f)
|
||||
(when s4-0
|
||||
(set! v1-32 (nonzero? (logand (shl #x8000 16) (-> s4-0 flags))))
|
||||
(set! v1-32 (logtest? (shl #x8000 16) (-> s4-0 flags)))
|
||||
(if (< (-> s4-0 length) (-> s4-0 from-bsp current-leaf-idx))
|
||||
(set! v1-32 #f)
|
||||
)
|
||||
)
|
||||
(when s3-0
|
||||
(set! a0-16 (nonzero? (logand (shl #x8000 16) (-> s3-0 flags))))
|
||||
(set! a0-16 (logtest? (shl #x8000 16) (-> s3-0 flags)))
|
||||
(if (< (-> s3-0 length) (-> s3-0 from-bsp current-leaf-idx))
|
||||
(set! a0-16 #f)
|
||||
)
|
||||
|
||||
+1
-1
@@ -1686,7 +1686,7 @@
|
||||
(logtest? (-> *cpad-list* cpads 0 button0-abs 0) (pad-buttons right))
|
||||
(logtest? (-> *cpad-list* cpads 0 button0-abs 0) (pad-buttons left))
|
||||
(logtest? (-> *cpad-list* cpads 0 button0-abs 0) (pad-buttons down))
|
||||
(nonzero? (logand (-> *cpad-list* cpads 0 button0-abs 0) (pad-buttons up)))
|
||||
(logtest? (-> *cpad-list* cpads 0 button0-abs 0) (pad-buttons up))
|
||||
)
|
||||
(let ((v1-39 (cond
|
||||
((logtest?
|
||||
|
||||
@@ -46,19 +46,19 @@
|
||||
|
||||
;; definition for method 12 of type task-cstage
|
||||
(defmethod closed? task-cstage ((obj task-cstage))
|
||||
(nonzero? (logand (-> obj flags) (task-flags closed)))
|
||||
(logtest? (-> obj flags) (task-flags closed))
|
||||
)
|
||||
|
||||
;; definition for method 13 of type task-cstage
|
||||
(defmethod closed-by-default? task-cstage ((obj task-cstage))
|
||||
(nonzero? (logand (-> obj flags) (task-flags closed-by-default)))
|
||||
(logtest? (-> obj flags) (task-flags closed-by-default))
|
||||
)
|
||||
|
||||
;; definition for method 11 of type task-cstage
|
||||
(defmethod task-available? task-cstage ((obj task-cstage) (arg0 task-control))
|
||||
(let ((a0-1 obj))
|
||||
(cond
|
||||
((nonzero? (logand (-> a0-1 flags) (task-flags closed)))
|
||||
((logtest? (-> a0-1 flags) (task-flags closed))
|
||||
#f
|
||||
)
|
||||
((>=
|
||||
@@ -227,11 +227,9 @@
|
||||
(dotimes (s4-0 (-> obj stage length))
|
||||
(if (or (= arg0 'game) (let ((a0-4 (-> obj stage s4-0)))
|
||||
(not
|
||||
(nonzero?
|
||||
(logand
|
||||
(-> a0-4 flags)
|
||||
(task-flags closed-by-default)
|
||||
)
|
||||
(logtest?
|
||||
(-> a0-4 flags)
|
||||
(task-flags closed-by-default)
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -239,7 +237,7 @@
|
||||
(open-task! (-> obj stage s4-0))
|
||||
)
|
||||
(let ((a0-10 (-> obj stage s4-0)))
|
||||
(if (nonzero? (logand (-> a0-10 flags) (task-flags closed)))
|
||||
(if (logtest? (-> a0-10 flags) (task-flags closed))
|
||||
(close-task! (-> obj stage s4-0))
|
||||
)
|
||||
)
|
||||
@@ -263,7 +261,7 @@
|
||||
(= arg1 (-> obj stage v1-3 status))
|
||||
)
|
||||
(let ((a0-3 (-> obj stage v1-3)))
|
||||
(return (nonzero? (logand (-> a0-3 flags) (task-flags closed))))
|
||||
(return (logtest? (-> a0-3 flags) (task-flags closed)))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
+1
-1
@@ -173,5 +173,5 @@
|
||||
|
||||
;; definition for method 11 of type vol-control
|
||||
(defmethod TODO-RENAME-11 vol-control ((obj vol-control))
|
||||
(and *display-vol-marks* (nonzero? (logand (-> obj flags) 1)))
|
||||
(and *display-vol-marks* (logtest? (-> obj flags) 1))
|
||||
)
|
||||
|
||||
@@ -22,11 +22,9 @@
|
||||
(v1-4 (logand a0-4 3))
|
||||
(a0-6 (+ (* a3-0 4) a2-3))
|
||||
)
|
||||
(nonzero?
|
||||
(logand
|
||||
(-> *ocean-work* trans-camera-masks 0 mask (+ a1-2 (* a0-6 8)))
|
||||
(ash 1 v1-4)
|
||||
)
|
||||
(logtest?
|
||||
(-> *ocean-work* trans-camera-masks 0 mask (+ a1-2 (* a0-6 8)))
|
||||
(ash 1 v1-4)
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -62,7 +60,7 @@
|
||||
)
|
||||
)
|
||||
(if a0-11
|
||||
(nonzero? (logand (-> a0-11 1) (ash 1 v1-4)))
|
||||
(logtest? (-> a0-11 1) (ash 1 v1-4))
|
||||
#f
|
||||
)
|
||||
)
|
||||
|
||||
+2
-8
@@ -1213,10 +1213,7 @@
|
||||
)
|
||||
(dotimes (upload-chunk-idx chunk-count)
|
||||
(set! current-dest-chunk (+ tex-dest-base-chunk upload-chunk-idx))
|
||||
(set!
|
||||
need-tex
|
||||
(nonzero? (logand allow-cache-mask (ash 1 upload-chunk-idx)))
|
||||
)
|
||||
(set! need-tex (logtest? allow-cache-mask (ash 1 upload-chunk-idx)))
|
||||
(cond
|
||||
((zero? chunks-to-upload-count)
|
||||
(when (and (!= (-> pool ids current-dest-chunk) page-id) need-tex)
|
||||
@@ -1856,10 +1853,7 @@
|
||||
(dotimes (v1-0 32)
|
||||
(let ((a2-0 (-> obj common-page v1-0)))
|
||||
(when
|
||||
(and
|
||||
(nonzero? a2-0)
|
||||
(nonzero? (logand (-> obj common-page-mask) (ash 1 v1-0)))
|
||||
)
|
||||
(and (nonzero? a2-0) (logtest? (-> obj common-page-mask) (ash 1 v1-0)))
|
||||
(upload-vram-pages
|
||||
obj
|
||||
(-> obj segment-common)
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
|
||||
;; definition for method 14 of type water-control
|
||||
(defmethod display-water-marks? water-control ((obj water-control))
|
||||
(and *display-water-marks* (nonzero? (logand (-> obj flags) 1)))
|
||||
(and *display-water-marks* (logtest? (-> obj flags) 1))
|
||||
)
|
||||
|
||||
;; definition for method 0 of type water-control
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@
|
||||
;; definition for method 9 of type bit-array
|
||||
(defmethod get-bit bit-array ((obj bit-array) (arg0 int))
|
||||
(let ((v1-2 (-> obj bytes (/ arg0 8))))
|
||||
(nonzero? (logand v1-2 (ash 1 (logand arg0 7))))
|
||||
(logtest? v1-2 (ash 1 (logand arg0 7)))
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -591,7 +591,7 @@
|
||||
(defmethod should-display? nav-control ((obj nav-control))
|
||||
(and
|
||||
*display-nav-marks*
|
||||
(nonzero? (logand (-> obj flags) (nav-control-flags display-marks bit0)))
|
||||
(logtest? (-> obj flags) (nav-control-flags display-marks))
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -135,7 +135,7 @@
|
||||
(defmethod should-display? path-control ((obj path-control))
|
||||
(and
|
||||
*display-path-marks*
|
||||
(nonzero? (logand (-> obj flags) (path-control-flag display)))
|
||||
(logtest? (-> obj flags) (path-control-flag display))
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
+2
-2
@@ -34,7 +34,7 @@
|
||||
((let ((a0-5 obj))
|
||||
(and
|
||||
*display-path-marks*
|
||||
(nonzero? (logand (-> a0-5 flags) (path-control-flag display)))
|
||||
(logtest? (-> a0-5 flags) (path-control-flag display))
|
||||
)
|
||||
)
|
||||
(dotimes (s5-1 (-> obj curve num-cverts))
|
||||
@@ -404,7 +404,7 @@
|
||||
((let ((a0-5 obj))
|
||||
(and
|
||||
*display-path-marks*
|
||||
(nonzero? (logand (-> a0-5 flags) (path-control-flag display)))
|
||||
(logtest? (-> a0-5 flags) (path-control-flag display))
|
||||
)
|
||||
)
|
||||
(if
|
||||
|
||||
@@ -1135,7 +1135,6 @@
|
||||
(set! (-> *flava-table* count) 0)
|
||||
|
||||
;; definition for function flava-lookup
|
||||
;; INFO: Return type mismatch int vs integer.
|
||||
(defun flava-lookup ((arg0 symbol) (arg1 int))
|
||||
(dotimes (v1-0 (-> *flava-table* count))
|
||||
(if (= (-> *flava-table* row v1-0 music) arg0)
|
||||
|
||||
+2
-2
@@ -1508,11 +1508,11 @@
|
||||
(when parent
|
||||
(let ((child (-> parent 0 child)))
|
||||
(if (= child proc)
|
||||
(return (the-as (pointer process-tree) #f))
|
||||
(return (the-as object #f))
|
||||
)
|
||||
(while child
|
||||
(if (= (-> child 0 brother) proc)
|
||||
(return child)
|
||||
(return (the-as object child))
|
||||
)
|
||||
(set! child (-> child 0 brother))
|
||||
)
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@
|
||||
((and
|
||||
(-> obj draw shadow)
|
||||
(zero? (-> obj draw cur-lod))
|
||||
(nonzero? (logand (-> obj draw status) 8))
|
||||
(logtest? (-> obj draw status) 8)
|
||||
)
|
||||
(let ((v1-9 (-> obj draw shadow-ctrl)))
|
||||
(set! (-> v1-9 settings flags) (logand -33 (-> v1-9 settings flags)))
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@
|
||||
((and
|
||||
(-> obj draw shadow)
|
||||
(zero? (-> obj draw cur-lod))
|
||||
(nonzero? (logand (-> obj draw status) 8))
|
||||
(logtest? (-> obj draw status) 8)
|
||||
)
|
||||
(let ((v1-9 (-> obj draw shadow-ctrl)))
|
||||
(set! (-> v1-9 settings flags) (logand -33 (-> v1-9 settings flags)))
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@
|
||||
((and
|
||||
(-> obj draw shadow)
|
||||
(zero? (-> obj draw cur-lod))
|
||||
(nonzero? (logand (-> obj draw status) 8))
|
||||
(logtest? (-> obj draw status) 8)
|
||||
)
|
||||
(let ((v1-9 (-> obj draw shadow-ctrl)))
|
||||
(set! (-> v1-9 settings flags) (logand -33 (-> v1-9 settings flags)))
|
||||
|
||||
+19
-29
@@ -131,11 +131,7 @@
|
||||
obj
|
||||
)
|
||||
)
|
||||
(if
|
||||
(and
|
||||
(nonzero? (-> obj neck))
|
||||
(nonzero? (logand (-> obj nav-enemy-flags) #x4000))
|
||||
)
|
||||
(if (and (nonzero? (-> obj neck)) (logtest? (-> obj nav-enemy-flags) #x4000))
|
||||
(set-target!
|
||||
(-> obj neck)
|
||||
(target-pos (-> obj nav-info player-look-at-joint))
|
||||
@@ -259,10 +255,11 @@
|
||||
(set! (-> a1-1 mode) arg2)
|
||||
(set! (-> v1-0 param 1) (the-as uint a1-1))
|
||||
)
|
||||
(when (send-event-function arg0 v1-0)
|
||||
(dummy-54 (-> self collide-info) 2 0)
|
||||
(logior! (-> self nav-enemy-flags) 256)
|
||||
#t
|
||||
(the-as object (when (send-event-function arg0 v1-0)
|
||||
(dummy-54 (-> self collide-info) 2 0)
|
||||
(logior! (-> self nav-enemy-flags) 256)
|
||||
#t
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -456,7 +453,7 @@ nav-enemy-default-event-handler
|
||||
(if
|
||||
(or
|
||||
(logtest? (-> obj nav-enemy-flags) 128)
|
||||
(nonzero? (logand #x80000 (-> obj nav flags)))
|
||||
(logtest? #x80000 (-> obj nav flags))
|
||||
)
|
||||
(seek-to-point-toward-point!
|
||||
(-> obj collide-info)
|
||||
@@ -487,7 +484,7 @@ nav-enemy-default-event-handler
|
||||
8192.0
|
||||
#f
|
||||
(-> obj nav-info hover-if-no-ground)
|
||||
(nonzero? (logand (-> obj nav-enemy-flags) #x8000))
|
||||
(logtest? (-> obj nav-enemy-flags) #x8000)
|
||||
)
|
||||
(dummy-58 (-> obj collide-info) (-> obj collide-info transv))
|
||||
)
|
||||
@@ -600,7 +597,7 @@ nav-enemy-default-event-handler
|
||||
;; definition for function nav-enemy-face-player-post
|
||||
;; INFO: Return type mismatch int vs none.
|
||||
(defbehavior nav-enemy-face-player-post nav-enemy ()
|
||||
(if (and *target* (nonzero? (logand (-> self nav-enemy-flags) 16)))
|
||||
(if (and *target* (logtest? (-> self nav-enemy-flags) 16))
|
||||
(seek-to-point-toward-point!
|
||||
(-> self collide-info)
|
||||
(target-pos 0)
|
||||
@@ -660,10 +657,7 @@ nav-enemy-default-event-handler
|
||||
;; INFO: Return type mismatch int vs none.
|
||||
(defbehavior nav-enemy-neck-control-inactive nav-enemy ()
|
||||
(when
|
||||
(and
|
||||
(nonzero? (-> self neck))
|
||||
(nonzero? (logand (-> self nav-enemy-flags) #x4000))
|
||||
)
|
||||
(and (nonzero? (-> self neck)) (logtest? (-> self nav-enemy-flags) #x4000))
|
||||
(set! (-> self nav-enemy-flags) (logand -16385 (-> self nav-enemy-flags)))
|
||||
(shut-down! (-> self neck))
|
||||
)
|
||||
@@ -1087,7 +1081,7 @@ nav-enemy-default-event-handler
|
||||
(nonzero? (-> obj skel))
|
||||
(!= (-> obj skel root-channel 0) (-> obj skel channel))
|
||||
)
|
||||
(and (nonzero? (-> obj draw)) (nonzero? (logand (-> obj draw status) 16)))
|
||||
(and (nonzero? (-> obj draw)) (logtest? (-> obj draw status) 16))
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -1139,7 +1133,7 @@ nav-enemy-default-event-handler
|
||||
(the-as int (-> self state-timeout))
|
||||
)
|
||||
(nonzero? (-> self draw))
|
||||
(nonzero? (logand (-> self draw status) 8))
|
||||
(logtest? (-> self draw status) 8)
|
||||
)
|
||||
(go-virtual nav-enemy-patrol)
|
||||
)
|
||||
@@ -1227,11 +1221,7 @@ nav-enemy-default-event-handler
|
||||
)
|
||||
(the-as int (-> self state-timeout))
|
||||
)
|
||||
(if
|
||||
(and
|
||||
(nonzero? (-> self draw))
|
||||
(nonzero? (logand (-> self draw status) 8))
|
||||
)
|
||||
(if (and (nonzero? (-> self draw)) (logtest? (-> self draw status) 8))
|
||||
(set! (-> self free-time) (-> *display* base-frame-counter))
|
||||
)
|
||||
(if
|
||||
@@ -1903,7 +1893,7 @@ nav-enemy-default-event-handler
|
||||
(if
|
||||
(or
|
||||
(not (TODO-RENAME-46 self (-> self nav-info stop-chase-distance)))
|
||||
(nonzero? (logand (-> self nav-enemy-flags) 8192))
|
||||
(logtest? (-> self nav-enemy-flags) 8192)
|
||||
)
|
||||
(go-virtual nav-enemy-stop-chase)
|
||||
)
|
||||
@@ -2198,7 +2188,7 @@ nav-enemy-default-event-handler
|
||||
)
|
||||
)
|
||||
)
|
||||
(nonzero? (logand #x20000 (-> self nav flags)))
|
||||
(logtest? #x20000 (-> self nav flags))
|
||||
)
|
||||
(go-virtual nav-enemy-give-up)
|
||||
)
|
||||
@@ -2529,7 +2519,7 @@ nav-enemy-default-event-handler
|
||||
(logior! (-> self nav-enemy-flags) 1024)
|
||||
)
|
||||
)
|
||||
(when (and arg1 (nonzero? (logand (-> self nav-enemy-flags) 1024)))
|
||||
(when (and arg1 (logtest? (-> self nav-enemy-flags) 1024))
|
||||
(set! (-> self nav-enemy-flags) (logand -513 (-> self nav-enemy-flags)))
|
||||
(set! f30-0 2048.0)
|
||||
)
|
||||
@@ -2850,7 +2840,7 @@ nav-enemy-default-event-handler
|
||||
(if
|
||||
(or
|
||||
(logtest? (-> self nav-enemy-flags) 128)
|
||||
(nonzero? (logand #x80000 (-> self nav flags)))
|
||||
(logtest? #x80000 (-> self nav flags))
|
||||
)
|
||||
(seek-to-point-toward-point!
|
||||
(-> self collide-info)
|
||||
@@ -2915,7 +2905,7 @@ nav-enemy-default-event-handler
|
||||
)
|
||||
150
|
||||
)
|
||||
(nonzero? (logand #x80000 (-> self nav flags)))
|
||||
(logtest? #x80000 (-> self nav flags))
|
||||
)
|
||||
(go-virtual nav-enemy-chase)
|
||||
)
|
||||
@@ -3164,7 +3154,7 @@ nav-enemy-default-event-handler
|
||||
)
|
||||
(logior!
|
||||
(-> obj nav flags)
|
||||
(nav-control-flags display-marks bit0 bit3 bit5 bit6 bit7)
|
||||
(nav-control-flags display-marks bit3 bit5 bit6 bit7)
|
||||
)
|
||||
(set! (-> obj nav gap-event) 'jump)
|
||||
(dummy-26 (-> obj nav))
|
||||
|
||||
+18
-15
@@ -1786,21 +1786,24 @@
|
||||
:virtual #t
|
||||
:event
|
||||
(behavior ((arg0 process) (arg1 int) (arg2 symbol) (arg3 event-message-block))
|
||||
(case arg2
|
||||
(('move-to)
|
||||
(set!
|
||||
(-> self root trans quad)
|
||||
(-> (the-as vector (-> arg3 param 0)) quad)
|
||||
)
|
||||
(set! (-> self water-height) (-> self root trans y))
|
||||
(if (nonzero? (-> self sound))
|
||||
(update-trans! (-> self sound) (-> self root trans))
|
||||
)
|
||||
(let ((v0-0 (logclear (-> self mask) (process-mask sleep-code))))
|
||||
(set! (-> self mask) v0-0)
|
||||
v0-0
|
||||
)
|
||||
)
|
||||
(let ((v1-0 arg2))
|
||||
(the-as object (when (= v1-0 'move-to)
|
||||
(set!
|
||||
(-> self root trans quad)
|
||||
(-> (the-as vector (-> arg3 param 0)) quad)
|
||||
)
|
||||
(set! (-> self water-height) (-> self root trans y))
|
||||
(if (nonzero? (-> self sound))
|
||||
(update-trans! (-> self sound) (-> self root trans))
|
||||
)
|
||||
(let
|
||||
((v0-0 (logclear (-> self mask) (process-mask sleep-code)))
|
||||
)
|
||||
(set! (-> self mask) v0-0)
|
||||
v0-0
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
:trans
|
||||
|
||||
@@ -129,59 +129,60 @@
|
||||
(defstate teetertotter-launch (teetertotter)
|
||||
:event
|
||||
(behavior ((arg0 process) (arg1 int) (arg2 symbol) (arg3 event-message-block))
|
||||
(when (= arg2 'touch)
|
||||
(when
|
||||
(and
|
||||
((method-of-type touching-shapes-entry prims-touching?)
|
||||
(the-as touching-shapes-entry (-> arg3 param 0))
|
||||
(the-as collide-shape-moving (-> self root))
|
||||
(the-as uint 1)
|
||||
)
|
||||
(-> self rock-is-dangerous)
|
||||
)
|
||||
(let ((a1-2 (new 'stack-no-clear 'event-message-block)))
|
||||
(set! (-> a1-2 from) self)
|
||||
(set! (-> a1-2 num-params) 2)
|
||||
(set! (-> a1-2 message) 'attack)
|
||||
(set! (-> a1-2 param 0) (-> arg3 param 0))
|
||||
(let ((a0-2 (new 'static 'attack-info :mask #x20)))
|
||||
(set! (-> a0-2 mode) 'deadly)
|
||||
(set! (-> a1-2 param 1) (the-as uint a0-2))
|
||||
)
|
||||
(send-event-function arg0 a1-2)
|
||||
)
|
||||
)
|
||||
(when
|
||||
(and
|
||||
((method-of-type touching-shapes-entry prims-touching?)
|
||||
(the-as touching-shapes-entry (-> arg3 param 0))
|
||||
(the-as collide-shape-moving (-> self root))
|
||||
(the-as uint 2)
|
||||
)
|
||||
(target-on-end-of-teetertotter? self)
|
||||
(not (-> self launched-player))
|
||||
(-> self in-launch-window)
|
||||
)
|
||||
(let ((a1-4 (new 'stack-no-clear 'event-message-block)))
|
||||
(set! (-> a1-4 from) self)
|
||||
(set! (-> a1-4 num-params) 2)
|
||||
(set! (-> a1-4 message) 'shove)
|
||||
(set! (-> a1-4 param 0) (the-as uint #f))
|
||||
(let ((v1-16 (new 'static 'attack-info :mask #xcc0)))
|
||||
(set! (-> v1-16 shove-back) 0.0)
|
||||
(set! (-> v1-16 shove-up) 53248.0)
|
||||
(set! (-> v1-16 angle) 'jump)
|
||||
(set! (-> v1-16 control) 1.0)
|
||||
(set! (-> a1-4 param 1) (the-as uint v1-16))
|
||||
)
|
||||
(when (send-event-function arg0 a1-4)
|
||||
(let ((v0-0 #t))
|
||||
(set! (-> self launched-player) v0-0)
|
||||
v0-0
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(the-as object (when (= arg2 'touch)
|
||||
(when
|
||||
(and
|
||||
((method-of-type touching-shapes-entry prims-touching?)
|
||||
(the-as touching-shapes-entry (-> arg3 param 0))
|
||||
(the-as collide-shape-moving (-> self root))
|
||||
(the-as uint 1)
|
||||
)
|
||||
(-> self rock-is-dangerous)
|
||||
)
|
||||
(let ((a1-2 (new 'stack-no-clear 'event-message-block)))
|
||||
(set! (-> a1-2 from) self)
|
||||
(set! (-> a1-2 num-params) 2)
|
||||
(set! (-> a1-2 message) 'attack)
|
||||
(set! (-> a1-2 param 0) (-> arg3 param 0))
|
||||
(let ((a0-2 (new 'static 'attack-info :mask #x20)))
|
||||
(set! (-> a0-2 mode) 'deadly)
|
||||
(set! (-> a1-2 param 1) (the-as uint a0-2))
|
||||
)
|
||||
(send-event-function arg0 a1-2)
|
||||
)
|
||||
)
|
||||
(when
|
||||
(and
|
||||
((method-of-type touching-shapes-entry prims-touching?)
|
||||
(the-as touching-shapes-entry (-> arg3 param 0))
|
||||
(the-as collide-shape-moving (-> self root))
|
||||
(the-as uint 2)
|
||||
)
|
||||
(target-on-end-of-teetertotter? self)
|
||||
(not (-> self launched-player))
|
||||
(-> self in-launch-window)
|
||||
)
|
||||
(let ((a1-4 (new 'stack-no-clear 'event-message-block)))
|
||||
(set! (-> a1-4 from) self)
|
||||
(set! (-> a1-4 num-params) 2)
|
||||
(set! (-> a1-4 message) 'shove)
|
||||
(set! (-> a1-4 param 0) (the-as uint #f))
|
||||
(let ((v1-16 (new 'static 'attack-info :mask #xcc0)))
|
||||
(set! (-> v1-16 shove-back) 0.0)
|
||||
(set! (-> v1-16 shove-up) 53248.0)
|
||||
(set! (-> v1-16 angle) 'jump)
|
||||
(set! (-> v1-16 control) 1.0)
|
||||
(set! (-> a1-4 param 1) (the-as uint v1-16))
|
||||
)
|
||||
(when (send-event-function arg0 a1-4)
|
||||
(let ((v0-0 #t))
|
||||
(set! (-> self launched-player) v0-0)
|
||||
v0-0
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
:code
|
||||
|
||||
@@ -283,9 +283,7 @@
|
||||
(if
|
||||
(and
|
||||
(-> obj entity)
|
||||
(nonzero?
|
||||
(logand (-> obj entity extra perm status) (entity-perm-status complete))
|
||||
)
|
||||
(logtest? (-> obj entity extra perm status) (entity-perm-status complete))
|
||||
)
|
||||
(go silostep-rise #t)
|
||||
(go silostep-idle)
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
((and
|
||||
(-> obj draw shadow)
|
||||
(zero? (-> obj draw cur-lod))
|
||||
(nonzero? (logand (-> obj draw status) 8))
|
||||
(logtest? (-> obj draw status) 8)
|
||||
)
|
||||
(let ((v1-9 (-> obj draw shadow-ctrl)))
|
||||
(set! (-> v1-9 settings flags) (logand -33 (-> v1-9 settings flags)))
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
((and
|
||||
(-> obj draw shadow)
|
||||
(zero? (-> obj draw cur-lod))
|
||||
(nonzero? (logand (-> obj draw status) 8))
|
||||
(logtest? (-> obj draw status) 8)
|
||||
)
|
||||
(let ((v1-9 (-> obj draw shadow-ctrl)))
|
||||
(set! (-> v1-9 settings flags) (logand -33 (-> v1-9 settings flags)))
|
||||
|
||||
@@ -2564,7 +2564,7 @@ TEST_F(FormRegressionTest, MoveFalse) {
|
||||
" daddiu sp, sp, 16\n";
|
||||
std::string type = "(function int symbol)";
|
||||
|
||||
std::string expected = "(nonzero? (logand (+ arg0 12) 1))";
|
||||
std::string expected = "(logtest? (+ arg0 12) 1)";
|
||||
test_with_expr(func, type, expected, false, "", {{"L17", "A ~A"}});
|
||||
}
|
||||
|
||||
@@ -2934,7 +2934,7 @@ TEST_F(FormRegressionTest, AshPropagation2) {
|
||||
std::string type = "(function bit-array int symbol)";
|
||||
std::string expected =
|
||||
"(let ((v1-2 (-> arg0 bytes (/ arg1 8))))\n"
|
||||
" (nonzero? (logand v1-2 (ash 1 (logand arg1 7))))\n"
|
||||
" (logtest? v1-2 (ash 1 (logand arg1 7)))\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected);
|
||||
}
|
||||
@@ -160,6 +160,6 @@ TEST_F(FormRegressionTest, WeirdShortCircuit2) {
|
||||
" jr ra\n"
|
||||
" daddu sp, sp, r0";
|
||||
std::string type = "(function actor-link-info object)";
|
||||
std::string expected = "(and (-> arg0 prev) (-> arg0 prev extra process))";
|
||||
std::string expected = "(the-as object (and (-> arg0 prev) (-> arg0 prev extra process)))";
|
||||
test_with_stack_structures(func, type, expected, "[[16, \"event-message-block\"]]");
|
||||
}
|
||||
Reference in New Issue
Block a user