[gcommon decomp] compiler and decompiler fixes (#239)

* wip

* decompile file-io

* a

* fix
This commit is contained in:
water111 2021-02-07 18:21:00 -05:00 committed by GitHub
parent f8b63a3f92
commit e01e065170
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 925 additions and 164 deletions

View file

@ -13,12 +13,18 @@ bool debug_reverse_lookup = false;
/*! /*!
* Is the actual dereference compatible with the expected? * Is the actual dereference compatible with the expected?
*/ */
bool deref_matches(const DerefInfo& expected, const DerefKind& actual, bool is_integer) { bool deref_matches(const DerefInfo& expected,
const DerefKind& actual,
bool is_integer,
bool is_basic) {
assert(expected.mem_deref); assert(expected.mem_deref);
assert(expected.can_deref); assert(expected.can_deref);
if (actual.is_store || actual.size >= 8 || !is_integer) { if (actual.is_store || actual.size >= 8 || !is_integer) {
// don't check sign extension // don't check sign extension
return expected.load_size == actual.size; return expected.load_size == actual.size;
} else if (is_basic) {
// this is kinda weird, but it seems like GOAL uses lw and lwu for loading basics.
return expected.load_size == actual.size;
} else { } else {
return expected.load_size == actual.size && expected.sign_extend == actual.sign_extend; return expected.load_size == actual.size && expected.sign_extend == actual.sign_extend;
} }
@ -105,6 +111,7 @@ bool TypeSystem::try_reverse_lookup_pointer(const FieldReverseLookupInput& input
auto di = get_deref_info(input.base_type); auto di = get_deref_info(input.base_type);
bool is_integer = bool is_integer =
typecheck(TypeSpec("integer"), input.base_type.get_single_arg(), "", false, false); typecheck(TypeSpec("integer"), input.base_type.get_single_arg(), "", false, false);
bool is_basic = typecheck(TypeSpec("basic"), input.base_type.get_single_arg(), "", false, false);
assert(di.mem_deref); // it's accessing a pointer. assert(di.mem_deref); // it's accessing a pointer.
auto elt_type = di.result_type; auto elt_type = di.result_type;
if (input.stride) { if (input.stride) {
@ -123,7 +130,7 @@ bool TypeSystem::try_reverse_lookup_pointer(const FieldReverseLookupInput& input
token.kind = FieldReverseLookupOutput::Token::Kind::VAR_IDX; token.kind = FieldReverseLookupOutput::Token::Kind::VAR_IDX;
path->push_back(token); path->push_back(token);
if (input.deref.has_value()) { if (input.deref.has_value()) {
if (deref_matches(di, input.deref.value(), is_integer)) { if (deref_matches(di, input.deref.value(), is_integer, is_basic)) {
// access element of array // access element of array
*addr_of = false; *addr_of = false;
*result_type = elt_type; *result_type = elt_type;
@ -151,7 +158,7 @@ bool TypeSystem::try_reverse_lookup_pointer(const FieldReverseLookupInput& input
token.kind = FieldReverseLookupOutput::Token::Kind::CONSTANT_IDX; token.kind = FieldReverseLookupOutput::Token::Kind::CONSTANT_IDX;
token.idx = elt_idx; token.idx = elt_idx;
if (input.deref.has_value()) { if (input.deref.has_value()) {
if (!deref_matches(di, input.deref.value(), is_integer)) { if (!deref_matches(di, input.deref.value(), is_integer, is_basic)) {
// this isn't the right type of dereference // this isn't the right type of dereference
return false; return false;
} }
@ -200,6 +207,7 @@ bool TypeSystem::try_reverse_lookup_array(const FieldReverseLookupInput& input,
auto di = get_deref_info(array_data_type); auto di = get_deref_info(array_data_type);
bool is_integer = bool is_integer =
typecheck(TypeSpec("integer"), input.base_type.get_single_arg(), "", false, false); typecheck(TypeSpec("integer"), input.base_type.get_single_arg(), "", false, false);
bool is_basic = typecheck(TypeSpec("basic"), input.base_type.get_single_arg(), "", false, false);
assert(di.mem_deref); // it's accessing a pointer. assert(di.mem_deref); // it's accessing a pointer.
auto elt_type = di.result_type; auto elt_type = di.result_type;
if (input.stride) { if (input.stride) {
@ -218,7 +226,7 @@ bool TypeSystem::try_reverse_lookup_array(const FieldReverseLookupInput& input,
token.kind = FieldReverseLookupOutput::Token::Kind::VAR_IDX; token.kind = FieldReverseLookupOutput::Token::Kind::VAR_IDX;
path->push_back(token); path->push_back(token);
if (input.deref.has_value()) { if (input.deref.has_value()) {
if (deref_matches(di, input.deref.value(), is_integer)) { if (deref_matches(di, input.deref.value(), is_integer, is_basic)) {
// access element of array // access element of array
*addr_of = false; *addr_of = false;
*result_type = elt_type; *result_type = elt_type;
@ -248,7 +256,7 @@ bool TypeSystem::try_reverse_lookup_array(const FieldReverseLookupInput& input,
// always put array index, even if it's zero. // always put array index, even if it's zero.
path->push_back(token); path->push_back(token);
if (input.deref.has_value()) { if (input.deref.has_value()) {
if (!deref_matches(di, input.deref.value(), is_integer)) { if (!deref_matches(di, input.deref.value(), is_integer, is_basic)) {
// this isn't the right type of dereference // this isn't the right type of dereference
return false; return false;
} }
@ -391,7 +399,8 @@ bool TypeSystem::try_reverse_lookup_other(const FieldReverseLookupInput& input,
TypeSpec loc_type = make_pointer_typespec(field_deref.type); TypeSpec loc_type = make_pointer_typespec(field_deref.type);
auto di = get_deref_info(loc_type); auto di = get_deref_info(loc_type);
bool is_integer = typecheck(TypeSpec("integer"), field_deref.type, "", false, false); bool is_integer = typecheck(TypeSpec("integer"), field_deref.type, "", false, false);
if (!deref_matches(di, input.deref.value(), is_integer)) { bool is_basic = typecheck(TypeSpec("basic"), field_deref.type, "", false, false);
if (!deref_matches(di, input.deref.value(), is_integer, is_basic)) {
continue; // try another field! continue; // try another field!
} }
// it's a match, just access the field like normal! // it's a match, just access the field like normal!

View file

@ -820,7 +820,13 @@ void TypeSystem::add_builtin_types() {
add_field_to_type(connectable_type, "prev1", make_typespec("connectable")); add_field_to_type(connectable_type, "prev1", make_typespec("connectable"));
// todo // todo
(void)file_stream_type; builtin_structure_inherit(file_stream_type);
add_field_to_type(file_stream_type, "flags", make_typespec("uint32"));
add_field_to_type(file_stream_type, "mode", make_typespec("basic"));
add_field_to_type(file_stream_type, "name", make_typespec("string"));
add_field_to_type(file_stream_type, "file", make_typespec("uint32"));
add_method(file_stream_type, "new",
make_function_typespec({"symbol", "type", "string", "basic"}, "_type_"));
} }
/*! /*!

View file

@ -291,6 +291,7 @@ class AsmOp : public AtomicOp {
const Env& env, const Env& env,
DecompilerTypeSystem& dts) override; DecompilerTypeSystem& dts) override;
void collect_vars(VariableSet& vars) const override; void collect_vars(VariableSet& vars) const override;
const Instruction& instruction() const { return m_instr; }
private: private:
Instruction m_instr; Instruction m_instr;

View file

@ -79,7 +79,7 @@ FormElement* SetVarOp::get_as_form(FormPool& pool, const Env& env) const {
} }
FormElement* AsmOp::get_as_form(FormPool& pool, const Env&) const { FormElement* AsmOp::get_as_form(FormPool& pool, const Env&) const {
return pool.alloc_element<AtomicOpElement>(this); return pool.alloc_element<AsmOpElement>(this);
} }
FormElement* SetVarConditionOp::get_as_form(FormPool& pool, const Env& env) const { FormElement* SetVarConditionOp::get_as_form(FormPool& pool, const Env& env) const {

View file

@ -112,7 +112,9 @@ TP_Type SimpleAtom::get_type(const TypeState& input,
} else if ((label.offset & 7) == PAIR_OFFSET) { } else if ((label.offset & 7) == PAIR_OFFSET) {
return TP_Type::make_from_ts(TypeSpec("pair")); return TP_Type::make_from_ts(TypeSpec("pair"));
} }
throw std::runtime_error("IR_StaticAddress couldn't figure out the type: " + label.name); // throw std::runtime_error("IR_StaticAddress couldn't figure out the type: " + label.name);
lg::error("IR_StaticAddress doesn't know the type of {}", label.name);
return TP_Type::make_from_ts("object");
} }
case Kind::INVALID: case Kind::INVALID:
default: default:
@ -136,6 +138,12 @@ TP_Type SimpleExpression::get_type(const TypeState& input,
} }
case Kind::FPR_TO_GPR: case Kind::FPR_TO_GPR:
case Kind::DIV_S: case Kind::DIV_S:
case Kind::SUB_S:
case Kind::MUL_S:
case Kind::ADD_S:
case Kind::SQRT_S:
case Kind::ABS_S:
case Kind::NEG_S:
return TP_Type::make_from_ts("float"); return TP_Type::make_from_ts("float");
case Kind::ADD: case Kind::ADD:
case Kind::SUB: case Kind::SUB:

View file

@ -349,6 +349,36 @@ void AtomicOpElement::get_modified_regs(RegSet& regs) const {
} }
} }
/////////////////////////////
// AsmOpElement
/////////////////////////////
AsmOpElement::AsmOpElement(const AsmOp* op) : m_op(op) {}
goos::Object AsmOpElement::to_form(const Env& env) const {
return m_op->to_form(env.file->labels, env);
}
void AsmOpElement::apply(const std::function<void(FormElement*)>& f) {
f(this);
}
void AsmOpElement::apply_form(const std::function<void(Form*)>&) {}
void AsmOpElement::collect_vars(VariableSet& vars) const {
m_op->collect_vars(vars);
}
void AsmOpElement::get_modified_regs(RegSet& regs) const {
for (auto r : m_op->write_regs()) {
regs.insert(r);
}
for (auto r : m_op->clobber_regs()) {
regs.insert(r);
}
}
///////////////////////////// /////////////////////////////
// ConditionElement // ConditionElement
///////////////////////////// /////////////////////////////
@ -474,29 +504,38 @@ goos::Object ReturnElement::to_form(const Env& env) const {
std::vector<goos::Object> forms; std::vector<goos::Object> forms;
forms.push_back(pretty_print::to_symbol("return")); forms.push_back(pretty_print::to_symbol("return"));
forms.push_back(return_code->to_form(env)); forms.push_back(return_code->to_form(env));
forms.push_back(dead_code->to_form(env)); if (dead_code) {
forms.push_back(dead_code->to_form(env));
}
return pretty_print::build_list(forms); return pretty_print::build_list(forms);
} }
void ReturnElement::apply(const std::function<void(FormElement*)>& f) { void ReturnElement::apply(const std::function<void(FormElement*)>& f) {
f(this); f(this);
return_code->apply(f); return_code->apply(f);
dead_code->apply(f); if (dead_code) {
dead_code->apply(f);
}
} }
void ReturnElement::apply_form(const std::function<void(Form*)>& f) { void ReturnElement::apply_form(const std::function<void(Form*)>& f) {
return_code->apply_form(f); return_code->apply_form(f);
dead_code->apply_form(f); if (dead_code) {
dead_code->apply_form(f);
}
} }
void ReturnElement::collect_vars(VariableSet& vars) const { void ReturnElement::collect_vars(VariableSet& vars) const {
return_code->collect_vars(vars); return_code->collect_vars(vars);
dead_code->collect_vars(vars); if (dead_code) {
dead_code->collect_vars(vars);
}
} }
void ReturnElement::get_modified_regs(RegSet& regs) const { void ReturnElement::get_modified_regs(RegSet& regs) const {
for (auto x : {return_code, dead_code}) { return_code->get_modified_regs(regs);
x->get_modified_regs(regs); if (dead_code) {
dead_code->get_modified_regs(regs);
} }
} }
@ -874,7 +913,7 @@ TypeOfElement::TypeOfElement(Form* _value, std::optional<Variable> _clobber)
} }
goos::Object TypeOfElement::to_form(const Env& env) const { goos::Object TypeOfElement::to_form(const Env& env) const {
return pretty_print::build_list("type-of", value->to_form(env)); return pretty_print::build_list("rtype-of", value->to_form(env));
} }
void TypeOfElement::apply(const std::function<void(FormElement*)>& f) { void TypeOfElement::apply(const std::function<void(FormElement*)>& f) {
@ -1048,6 +1087,8 @@ std::string fixed_operator_to_string(FixedOperatorKind kind) {
return "-"; return "-";
case FixedOperatorKind::MULTIPLICATION: case FixedOperatorKind::MULTIPLICATION:
return "*"; return "*";
case FixedOperatorKind::SQRT:
return "sqrt";
case FixedOperatorKind::ARITH_SHIFT: case FixedOperatorKind::ARITH_SHIFT:
return "ash"; return "ash";
case FixedOperatorKind::MOD: case FixedOperatorKind::MOD:

View file

@ -84,6 +84,18 @@ class SimpleExpressionElement : public FormElement {
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result, std::vector<FormElement*>* result,
bool allow_side_effects); bool allow_side_effects);
void update_from_stack_float_2(const Env& env,
FixedOperatorKind kind,
FormPool& pool,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects);
void update_from_stack_float_1(const Env& env,
FixedOperatorKind kind,
FormPool& pool,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects);
void update_from_stack_add_i(const Env& env, void update_from_stack_add_i(const Env& env,
FormPool& pool, FormPool& pool,
FormStack& stack, FormStack& stack,
@ -259,6 +271,24 @@ class AtomicOpElement : public FormElement {
const AtomicOp* m_op; const AtomicOp* m_op;
}; };
/*!
* A wrapper around a single AsmOp
*/
class AsmOpElement : public FormElement {
public:
explicit AsmOpElement(const AsmOp* op);
goos::Object to_form(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(VariableSet& vars) const override;
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
void get_modified_regs(RegSet& regs) const override;
const AsmOp* op() const { return m_op; }
private:
const AsmOp* m_op;
};
/*! /*!
* A "condition" like (< a b). This can be used as a boolean value directly: (set! a (< b c)) * A "condition" like (< a b). This can be used as a boolean value directly: (set! a (< b c))
* or it can be used as a branch condition: (if (< a b)). * or it can be used as a branch condition: (if (< a b)).
@ -344,6 +374,8 @@ class BranchElement : public FormElement {
/*! /*!
* Represents a (return-from #f x) form, which immediately returns from the function. * Represents a (return-from #f x) form, which immediately returns from the function.
* This always has some "dead code" after it that can't be reached, which is the "dead_code". * This always has some "dead code" after it that can't be reached, which is the "dead_code".
* We store the dead code because it may contain an unreachable jump to the next place that can
* be stripped away in later analysis passes. Or they may have written code after the return.
*/ */
class ReturnElement : public FormElement { class ReturnElement : public FormElement {
public: public:
@ -444,6 +476,7 @@ class EmptyElement : public FormElement {
void apply_form(const std::function<void(Form*)>& f) override; void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override; void collect_vars(VariableSet& vars) const override;
void get_modified_regs(RegSet& regs) const override; void get_modified_regs(RegSet& regs) const override;
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
}; };
/*! /*!
@ -646,6 +679,7 @@ class ConditionalMoveFalseElement : public FormElement {
void apply_form(const std::function<void(Form*)>& f) override; void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(VariableSet& vars) const override; void collect_vars(VariableSet& vars) const override;
void get_modified_regs(RegSet& regs) const override; void get_modified_regs(RegSet& regs) const override;
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
}; };
std::string fixed_operator_to_string(FixedOperatorKind kind); std::string fixed_operator_to_string(FixedOperatorKind kind);

View file

@ -2,6 +2,7 @@
#include "FormStack.h" #include "FormStack.h"
#include "GenericElementMatcher.h" #include "GenericElementMatcher.h"
#include "common/goos/PrettyPrinter.h" #include "common/goos/PrettyPrinter.h"
#include "decompiler/util/DecompilerTypeSystem.h"
/* /*
* TODO * TODO
@ -335,6 +336,42 @@ void SimpleExpressionElement::update_from_stack_div_s(const Env& env,
} }
} }
void SimpleExpressionElement::update_from_stack_float_2(const Env& env,
FixedOperatorKind kind,
FormPool& pool,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) {
if (is_float_type(env, m_my_idx, m_expr.get_arg(0).var()) &&
is_float_type(env, m_my_idx, m_expr.get_arg(1).var())) {
// todo - check the order here
auto args = pop_to_forms({m_expr.get_arg(0).var(), m_expr.get_arg(1).var()}, env, pool, stack,
allow_side_effects);
auto new_form = pool.alloc_element<GenericElement>(GenericOperator::make_fixed(kind),
args.at(0), args.at(1));
result->push_back(new_form);
} else {
throw std::runtime_error(fmt::format("Floating point math attempted on invalid types."));
}
}
void SimpleExpressionElement::update_from_stack_float_1(const Env& env,
FixedOperatorKind kind,
FormPool& pool,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) {
if (is_float_type(env, m_my_idx, m_expr.get_arg(0).var())) {
auto args = pop_to_forms({m_expr.get_arg(0).var()}, env, pool, stack, allow_side_effects);
auto new_form =
pool.alloc_element<GenericElement>(GenericOperator::make_fixed(kind), args.at(0));
result->push_back(new_form);
} else {
throw std::runtime_error(fmt::format("Floating point division attempted on invalid types."));
}
}
void SimpleExpressionElement::update_from_stack_add_i(const Env& env, void SimpleExpressionElement::update_from_stack_add_i(const Env& env,
FormPool& pool, FormPool& pool,
FormStack& stack, FormStack& stack,
@ -546,6 +583,30 @@ void SimpleExpressionElement::update_from_stack(const Env& env,
case SimpleExpression::Kind::DIV_S: case SimpleExpression::Kind::DIV_S:
update_from_stack_div_s(env, pool, stack, result, allow_side_effects); update_from_stack_div_s(env, pool, stack, result, allow_side_effects);
break; break;
case SimpleExpression::Kind::SUB_S:
update_from_stack_float_2(env, FixedOperatorKind::SUBTRACTION, pool, stack, result,
allow_side_effects);
break;
case SimpleExpression::Kind::MUL_S:
update_from_stack_float_2(env, FixedOperatorKind::MULTIPLICATION, pool, stack, result,
allow_side_effects);
break;
case SimpleExpression::Kind::ADD_S:
update_from_stack_float_2(env, FixedOperatorKind::ADDITION, pool, stack, result,
allow_side_effects);
break;
case SimpleExpression::Kind::SQRT_S:
update_from_stack_float_1(env, FixedOperatorKind::SQRT, pool, stack, result,
allow_side_effects);
break;
case SimpleExpression::Kind::ABS_S:
update_from_stack_float_1(env, FixedOperatorKind::ABS, pool, stack, result,
allow_side_effects);
break;
case SimpleExpression::Kind::NEG_S:
update_from_stack_float_1(env, FixedOperatorKind::SUBTRACTION, pool, stack, result,
allow_side_effects);
break;
case SimpleExpression::Kind::ADD: case SimpleExpression::Kind::ADD:
update_from_stack_add_i(env, pool, stack, result, allow_side_effects); update_from_stack_add_i(env, pool, stack, result, allow_side_effects);
break; break;
@ -702,7 +763,29 @@ void FunctionCallElement::update_from_stack(const Env& env,
} }
auto unstacked = pop_to_forms(all_pop_vars, env, pool, stack, allow_side_effects); auto unstacked = pop_to_forms(all_pop_vars, env, pool, stack, allow_side_effects);
std::vector<Form*> arg_forms; std::vector<Form*> arg_forms;
arg_forms.insert(arg_forms.begin(), unstacked.begin() + 1, unstacked.end()); TypeSpec function_type;
if (env.has_type_analysis()) {
function_type =
env.get_types_before_op(all_pop_vars.at(0).idx()).get(all_pop_vars.at(0).reg()).typespec();
}
for (size_t arg_id = 0; arg_id < nargs; arg_id++) {
auto val = unstacked.at(arg_id + 1); // first is the function itself.
auto& var = all_pop_vars.at(arg_id + 1);
if (env.has_type_analysis() && function_type.arg_count() == nargs + 1) {
auto actual_arg_type = env.get_types_before_op(var.idx()).get(var.reg()).typespec();
auto desired_arg_type = function_type.get_arg(arg_id);
if (!env.dts->ts.typecheck(desired_arg_type, actual_arg_type, "", false, false)) {
arg_forms.push_back(
pool.alloc_single_element_form<CastElement>(nullptr, desired_arg_type, val));
} else {
arg_forms.push_back(val);
}
} else {
arg_forms.push_back(val);
}
}
auto new_form = pool.alloc_element<GenericElement>( auto new_form = pool.alloc_element<GenericElement>(
GenericOperator::make_function(unstacked.at(0)), arg_forms); GenericOperator::make_function(unstacked.at(0)), arg_forms);
@ -1161,6 +1244,36 @@ FormElement* ConditionElement::make_generic(const Env&,
casted); casted);
} }
case IR2_Condition::Kind::FLOAT_NOT_EQUAL: {
auto casted = make_cast(source_forms, types, TypeSpec("float"), pool);
return pool.alloc_element<GenericElement>(GenericOperator::make_fixed(FixedOperatorKind::NEQ),
casted);
}
case IR2_Condition::Kind::FLOAT_EQUAL: {
auto casted = make_cast(source_forms, types, TypeSpec("float"), pool);
return pool.alloc_element<GenericElement>(GenericOperator::make_fixed(FixedOperatorKind::EQ),
casted);
}
case IR2_Condition::Kind::FLOAT_LEQ: {
auto casted = make_cast(source_forms, types, TypeSpec("float"), pool);
return pool.alloc_element<GenericElement>(GenericOperator::make_fixed(FixedOperatorKind::LEQ),
casted);
}
case IR2_Condition::Kind::FLOAT_LESS_THAN: {
auto casted = make_cast(source_forms, types, TypeSpec("float"), pool);
return pool.alloc_element<GenericElement>(GenericOperator::make_fixed(FixedOperatorKind::LT),
casted);
}
case IR2_Condition::Kind::FLOAT_GEQ: {
auto casted = make_cast(source_forms, types, TypeSpec("float"), pool);
return pool.alloc_element<GenericElement>(GenericOperator::make_fixed(FixedOperatorKind::GEQ),
casted);
}
default: default:
throw std::runtime_error("ConditionElement::make_generic NYI for kind " + throw std::runtime_error("ConditionElement::make_generic NYI for kind " +
get_condition_kind_name(m_kind)); get_condition_kind_name(m_kind));
@ -1254,6 +1367,10 @@ void AtomicOpElement::push_to_stack(const Env& env, FormPool&, FormStack& stack)
throw std::runtime_error("Can't push atomic op to stack: " + m_op->to_string(env)); throw std::runtime_error("Can't push atomic op to stack: " + m_op->to_string(env));
} }
void AsmOpElement::push_to_stack(const Env&, FormPool&, FormStack& stack) {
stack.push_form_element(this, true);
}
void GenericElement::update_from_stack(const Env& env, void GenericElement::update_from_stack(const Env& env,
FormPool& pool, FormPool& pool,
FormStack& stack, FormStack& stack,
@ -1305,7 +1422,7 @@ void DynamicMethodAccess::update_from_stack(const Env& env,
auto deref = pool.alloc_element<DerefElement>( auto deref = pool.alloc_element<DerefElement>(
var_to_form(base.value(), pool), false, var_to_form(base.value(), pool), false,
std::vector<DerefToken>{DerefToken::make_field_name("methods"), std::vector<DerefToken>{DerefToken::make_field_name("method-table"),
DerefToken::make_int_expr(var_to_form(idx.value(), pool))}); DerefToken::make_int_expr(var_to_form(idx.value(), pool))});
result->push_back(deref); result->push_back(deref);
} }
@ -1450,4 +1567,16 @@ void TypeOfElement::update_from_stack(const Env& env,
result->push_back(this); result->push_back(this);
} }
////////////////////////
// EmptyElement
////////////////////////
void EmptyElement::push_to_stack(const Env&, FormPool&, FormStack& stack) {
stack.push_form_element(this, true);
}
void ConditionalMoveFalseElement::push_to_stack(const Env&, FormPool&, FormStack& stack) {
stack.push_form_element(this, true);
}
} // namespace decompiler } // namespace decompiler

View file

@ -95,6 +95,7 @@ enum class FixedOperatorKind {
ADDITION, ADDITION,
SUBTRACTION, SUBTRACTION,
MULTIPLICATION, MULTIPLICATION,
SQRT,
ARITH_SHIFT, ARITH_SHIFT,
MOD, MOD,
ABS, ABS,
@ -125,9 +126,15 @@ enum class FixedOperatorKind {
struct VariableNames { struct VariableNames {
struct VarInfo { struct VarInfo {
VarInfo() = default; VarInfo() = default;
std::string name() const { return fmt::format("{}-{}", reg_id.reg.to_charp(), reg_id.id); } std::string name() const {
if (!override_name.empty()) {
return override_name;
}
return fmt::format("{}-{}", reg_id.reg.to_charp(), reg_id.id);
}
TP_Type type; TP_Type type;
RegId reg_id; RegId reg_id;
std::string override_name;
bool initialized = false; bool initialized = false;
}; };

View file

@ -150,6 +150,30 @@ void clean_up_return(FormPool& pool, ReturnElement* ir) {
} }
} }
void clean_up_return_final(const Function& f, ReturnElement* ir) {
SetVarElement* dead = dynamic_cast<SetVarElement*>(ir->dead_code->try_as_single_element());
if (!dead) {
dead = dynamic_cast<SetVarElement*>(ir->dead_code->elts().front());
for (int i = 1; i < ir->dead_code->size(); i++) {
if (!dynamic_cast<EmptyElement*>(ir->dead_code->at(i))) {
dead = nullptr;
break;
}
}
}
if (!dead) {
lg::error("failed to recognize dead code after return, got {}",
ir->dead_code->to_string(f.ir2.env));
}
assert(dead);
auto src = dynamic_cast<SimpleExpressionElement*>(dead->src()->try_as_single_element());
assert(src);
assert(src->expr().is_identity() && src->expr().get_arg(0).is_int() &&
src->expr().get_arg(0).get_int() == 0);
ir->dead_code = nullptr;
}
/*! /*!
* Remove the branch in a break (really return-from nonfunction scope) * Remove the branch in a break (really return-from nonfunction scope)
*/ */
@ -1355,8 +1379,22 @@ Form* cfg_to_ir(FormPool& pool, Function& f, const CfgVtx* vtx) {
return result; return result;
} else if (dynamic_cast<const GotoEnd*>(vtx)) { } else if (dynamic_cast<const GotoEnd*>(vtx)) {
auto* cvtx = dynamic_cast<const GotoEnd*>(vtx); auto* cvtx = dynamic_cast<const GotoEnd*>(vtx);
// dead code should always be (set! var 0)
auto dead_code = cfg_to_ir(pool, f, cvtx->unreachable_block);
// auto dead = dynamic_cast<SetVarElement*>(dead_code->try_as_single_element());
// if (!dead) {
// lg::error("failed to recognize dead code after return, got {}",
// dead_code->to_string(f.ir2.env));
// }
// assert(dead);
// auto src = dynamic_cast<SimpleExpressionElement*>(dead->src()->try_as_single_element());
// assert(src);
// assert(src->expr().is_identity() && src->expr().get_arg(0).is_int() &&
// src->expr().get_arg(0).get_int() == 0);
auto result = pool.alloc_single_element_form<ReturnElement>( auto result = pool.alloc_single_element_form<ReturnElement>(
nullptr, cfg_to_ir(pool, f, cvtx->body), cfg_to_ir(pool, f, cvtx->unreachable_block)); nullptr, cfg_to_ir(pool, f, cvtx->body), dead_code);
clean_up_return(pool, dynamic_cast<ReturnElement*>(result->try_as_single_element())); clean_up_return(pool, dynamic_cast<ReturnElement*>(result->try_as_single_element()));
return result; return result;
} else if (dynamic_cast<const Break*>(vtx)) { } else if (dynamic_cast<const Break*>(vtx)) {
@ -1433,6 +1471,11 @@ void build_initial_forms(Function& function) {
if (as_cne) { if (as_cne) {
clean_up_cond_no_else_final(function, as_cne); clean_up_cond_no_else_final(function, as_cne);
} }
auto as_return = dynamic_cast<ReturnElement*>(form);
if (as_return) {
clean_up_return_final(function, as_return);
}
}); });
function.ir2.top_form = result; function.ir2.top_form = result;

View file

@ -8,7 +8,7 @@
namespace decompiler { namespace decompiler {
// TODO - remove all these and put them in the analysis methods instead. // TODO - remove all these and put them in the analysis methods instead.
void clean_up_ifs(Form* top_level_form) { void clean_up_ifs(Form* top_level_form, const Env&) {
bool changed = true; bool changed = true;
while (changed) { while (changed) {
changed = false; changed = false;
@ -30,6 +30,9 @@ void clean_up_ifs(Form* top_level_form) {
assert(me != parent_vector.end()); assert(me != parent_vector.end());
// now insert the fake condition // now insert the fake condition
for (auto& x : top_condition->elts()) {
x->parent_form = elt->parent_form;
}
parent_vector.insert(me, top_condition->elts().begin(), top_condition->elts().end()); parent_vector.insert(me, top_condition->elts().begin(), top_condition->elts().end());
top_condition->elts() = {real_condition}; top_condition->elts() = {real_condition};
changed = true; changed = true;
@ -54,6 +57,9 @@ void clean_up_ifs(Form* top_level_form) {
assert(me != parent_vector.end()); assert(me != parent_vector.end());
// now insert the fake condition // now insert the fake condition
for (auto& x : top_condition->elts()) {
x->parent_form = elt->parent_form;
}
parent_vector.insert(me, top_condition->elts().begin(), top_condition->elts().end()); parent_vector.insert(me, top_condition->elts().begin(), top_condition->elts().end());
top_condition->elts() = {real_condition}; top_condition->elts() = {real_condition};
changed = true; changed = true;
@ -81,6 +87,9 @@ void clean_up_ifs(Form* top_level_form) {
assert(me != parent_vector.end()); assert(me != parent_vector.end());
// now insert the fake condition // now insert the fake condition
for (auto& x : top_condition->elts()) {
x->parent_form = elt->parent_form;
}
parent_vector.insert(me, top_condition->elts().begin(), top_condition->elts().end()); parent_vector.insert(me, top_condition->elts().begin(), top_condition->elts().end());
top_condition->elts() = {real_condition}; top_condition->elts() = {real_condition};
changed = true; changed = true;
@ -153,7 +162,7 @@ bool convert_to_expressions(Form* top_level_form,
// fmt::print("Before clean:\n{}\n", // fmt::print("Before clean:\n{}\n",
// pretty_print::to_string(top_level_form->to_form(f.ir2.env))); // pretty_print::to_string(top_level_form->to_form(f.ir2.env)));
// fix up stuff // fix up stuff
clean_up_ifs(top_level_form); clean_up_ifs(top_level_form, f.ir2.env);
} catch (std::exception& e) { } catch (std::exception& e) {
std::string warning = fmt::format("Expression building failed: {}", e.what()); std::string warning = fmt::format("Expression building failed: {}", e.what());

View file

@ -56,6 +56,10 @@
(define-extern *enable-method-set* int) (define-extern *enable-method-set* int)
(define-extern install-debug-handler (function int object symbol)) (define-extern install-debug-handler (function int object symbol))
(define-extern file-stream-open (function file-stream basic basic file-stream))
(define-extern file-stream-length (function file-stream int))
(define-extern file-stream-read (function file-stream pointer int int))
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; GCOMMON ;;;;;;;;;;;;;;;;;;; ;;;; GCOMMON ;;;;;;;;;;;;;;;;;;;
@ -740,6 +744,7 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
(deftype bit-array (basic) (deftype bit-array (basic)
((length int32 :offset-assert 4) ((length int32 :offset-assert 4)
(allocated-length int32 :offset-assert 8) (allocated-length int32 :offset-assert 8)
@ -914,7 +919,8 @@
) )
(deftype vector (structure) (deftype vector (structure)
((data float 4 :offset-assert 0) (
(data float 4 :offset-assert 0)
(x float :offset 0) (x float :offset 0)
(y float :offset 4) (y float :offset 4)
(z float :offset 8) (z float :offset 8)
@ -1793,6 +1799,7 @@
; ;; likely a bitfield type ; ;; likely a bitfield type
; ) ; )
; ;; dma-h ; ;; dma-h
(deftype dma-bucket (structure) (deftype dma-bucket (structure)
((tag uint64 :offset-assert 0) ((tag uint64 :offset-assert 0)
@ -2219,24 +2226,109 @@
(define-extern *display* display) (define-extern *display* display)
;;;;;;;;;;;;;;; ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
;; file-io ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;; ;;;; VECTOR ;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
;; todo (define-extern sin (function float float))
; (deftype file-stream (basic) (define-extern cos (function float float))
; ((flags uint32 :offset-assert 4) (define-extern atan (function float float float))
; (mode basic :offset-assert 8)
; (name basic :offset-assert 12) (define-extern vector-cross! (function vector vector vector vector))
; (file uint32 :offset-assert 16) (define-extern vector+float! (function vector vector float vector))
; ) (define-extern vector*! (function vector vector vector vector))
; :method-count-assert 9 (define-extern vector+*! (function vector vector vector float vector))
; :size-assert #x14 (define-extern vector-*! (function vector vector vector float vector))
; :flag-assert #x900000014 (define-extern vector/! (function vector vector vector vector))
; ) (define-extern vector-float*! (function vector vector float vector))
(define-extern vector-average! (function vector vector vector vector))
(define-extern vector+float*! (function vector vector vector float vector))
(define-extern vector--float*! (function vector vector vector float vector))
(define-extern vector-float/! (function vector vector float vector))
(define-extern vector-negate! (function vector vector vector))
(define-extern vector-negate-in-place! (function vector vector))
(define-extern vector= (function vector vector symbol))
(define-extern vector-delta (function vector vector float))
(define-extern vector-seek! (function vector vector float vector))
(define-extern vector-seek-2d-xz-smooth! (function vector vector float float vector))
(define-extern vector-seek-2d-yz-smooth! (function vector vector float float vector))
(define-extern vector-seek-3d-smooth! (function vector vector float float vector))
(define-extern seek-with-smooth (function float float float float float float))
(define-extern vector-identity! (function vector vector))
(define-extern vector-seconds (function vector vector vector))
(define-extern vector-seconds! (function vector vector))
(define-extern vector-v! (function vector vector))
(define-extern vector-v+! (function vector vector vector vector))
(define-extern vector-v*float+! (function vector vector vector float vector))
(define-extern vector-v++! (function vector vector vector))
(define-extern vector-v*float! (function vector float float vector))
(define-extern vector-v*float++! (function vector vector float vector))
(define-extern vector-to-ups! (function vector vector vector))
(define-extern vector-from-ups! (function vector vector vector))
(define-extern vector-length (function vector float))
(define-extern vector-length-squared (function vector float))
(define-extern vector-xz-length-squared (function vector float))
(define-extern vector-xz-length (function vector float))
(define-extern vector-vector-distance (function vector vector float))
(define-extern vector-vector-distance-squared (function vector vector float))
(define-extern vector-vector-xz-distance (function vector vector float))
(define-extern vector-vector-xz-distance-squared (function vector vector float))
(define-extern vector-normalize! (function vector vector vector))
(define-extern vector-normalize-ret-len! (function vector float float))
(define-extern vector-normalize-copy! (function vector vector float vector))
(define-extern vector-xz-normalize! (function vector float vector))
(define-extern vector-length-max! (function vector float vector))
(define-extern vector-xz-length-max! (function vector float vector))
(define-extern vector-rotate-around-y! (function vector vector float vector))
(define-extern rotate-y<-vector+vector (function vector vector float))
(define-extern vector-cvt.w.s! (function vector vector vector))
(define-extern vector-cvt.s.w! (function vector vector vector))
(define-extern rot-zxy-from-vector! (function vector vector vector))
(define-extern rot-zyx-from-vector! (function vector vector vector))
(define-extern vector-lerp! (function vector vector vector))
(define-extern vector-lerp-clamp! (function vector vector float float vector))
(define-extern vector4-lerp! (function vector vector vector))
(define-extern vector4-lerp-clamp! (function vector vector float float vector))
(define-extern vector-degi (function vector vector vector))
(define-extern vector-degf (function vector vector vector))
(define-extern vector-degmod (function vector vector vector))
(define-extern vector-deg-diff (function vector vector vector vector))
(define-extern vector-deg-lerp-clamp! function) ;; todo
(define-extern vector3s-copy! (function vector vector vector))
(define-extern vector3s+! (function vector vector vector vector))
(define-extern vector3s*float! (function vector vector float vector))
(define-extern vector3s-! (function vector vector vector vector))
(define-extern spheres-overlap? (function vector vector symbol))
(define-extern sphere<-vector! (function sphere vector sphere))
(define-extern sphere<-vector+r! (function sphere vector float sphere))
(define-extern rand-vu-sphere-point! function) ;; todo
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; FILE-IO ;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
(deftype file-stream (basic)
((flags uint32 :offset-assert 4)
(mode basic :offset-assert 8)
(name string :offset-assert 12)
(file uint32 :offset-assert 16)
)
(:methods
(new ((allocation symbol) (type-to-make type) (name string) (mode basic)) _type_)
)
:method-count-assert 9
:size-assert #x14
:flag-assert #x900000014
)
(define-extern file-stream-read-string (function file-stream string string))
(deftype file-info (basic) (deftype file-info (basic)
((file-type basic :offset-assert 4) ((file-type symbol :offset-assert 4)
(file-name basic :offset-assert 8) (file-name basic :offset-assert 8)
(major-version uint32 :offset-assert 12) (major-version uint32 :offset-assert 12)
(minor-version uint32 :offset-assert 16) (minor-version uint32 :offset-assert 16)
@ -2249,6 +2341,12 @@
:flag-assert #x900000020 :flag-assert #x900000020
) )
(define-extern *file-temp-string* string)
(define-extern make-file-name (function int string int string))
(define-extern make-vfile-name (function int string string))
(define-extern file-info-correct-version? (function file-info int int symbol))
;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;
;; loader-h ;; loader-h
;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;
@ -31396,14 +31494,11 @@
(define-extern matrix-translate! function) (define-extern matrix-translate! function)
(define-extern matrix-4x4-inverse! function) (define-extern matrix-4x4-inverse! function)
(define-extern matrix-! function) (define-extern matrix-! function)
(define-extern atan function)
(define-extern vector-sincos! function) (define-extern vector-sincos! function)
(define-extern cos function)
(define-extern sin function)
(define-extern trs-matrix-calc! function) (define-extern trs-matrix-calc! function)
(define-extern transform-matrix-parent-calc! function) (define-extern transform-matrix-parent-calc! function)
(define-extern transform-matrix-calc! function) (define-extern transform-matrix-calc! function)
(define-extern vector-identity! function)
(define-extern quaternion-zero! function) (define-extern quaternion-zero! function)
(define-extern quaternion-set! function) (define-extern quaternion-set! function)
(define-extern matrix->quaternion function) (define-extern matrix->quaternion function)
@ -31457,15 +31552,15 @@
(define-extern quaternion-i! function) (define-extern quaternion-i! function)
(define-extern sincos-rad! function) (define-extern sincos-rad! function)
(define-extern vector-sincos-rad! function) (define-extern vector-sincos-rad! function)
(define-extern vector-xz-normalize! function)
(define-extern atan-series-rad function) (define-extern atan-series-rad function)
(define-extern atan2-rad function) (define-extern atan2-rad function)
(define-extern quaternion-from-two-vectors-max-angle! function) (define-extern quaternion-from-two-vectors-max-angle! function)
(define-extern vector-length function)
(define-extern vector-rad<-vector-deg/2! function) (define-extern vector-rad<-vector-deg/2! function)
(define-extern vector-sin-rad! function) (define-extern vector-sin-rad! function)
(define-extern acos-rad function) (define-extern acos-rad function)
(define-extern vector-xz-length function)
(define-extern acos function) (define-extern acos function)
(define-extern quat->eul function) (define-extern quat->eul function)
(define-extern set-eul! function) (define-extern set-eul! function)
@ -31514,15 +31609,7 @@
(define-extern forward-down-nopitch->inv-matrix function) (define-extern forward-down-nopitch->inv-matrix function)
(define-extern vector-reflect-flat-above! function) (define-extern vector-reflect-flat-above! function)
(define-extern vector-circle-tangent-new function) (define-extern vector-circle-tangent-new function)
(define-extern vector-vector-distance-squared function)
(define-extern vector-cross! function)
(define-extern vector+float*! function)
(define-extern vector-normalize! function)
(define-extern vector-negate! function)
(define-extern vector-vector-distance function)
(define-extern vector-normalize-ret-len! function)
(define-extern vector-normalize-copy! function)
(define-extern vector-float*! function)
(define-extern coserp function) (define-extern coserp function)
(define-extern sinerp-clamp function) (define-extern sinerp-clamp function)
;;(define-extern exp-slead object) ;; unknown type ;;(define-extern exp-slead object) ;; unknown type
@ -31773,72 +31860,9 @@
;;(define-extern draw-env object) ;; unknown type ;;(define-extern draw-env object) ;; unknown type
;;(define-extern *pre-draw-hook* object) ;; unknown type ;;(define-extern *pre-draw-hook* object) ;; unknown type
(define-extern set-display function) (define-extern set-display function)
(define-extern vector4-lerp! function)
(define-extern rotate-y<-vector+vector function)
(define-extern rot-zxy-from-vector! function)
(define-extern vector3s-copy! function)
(define-extern vector-seek-2d-yz-smooth! function)
(define-extern vector-from-ups! function)
(define-extern vector-seek-2d-xz-smooth! function)
(define-extern vector/! function)
(define-extern rand-vu-sphere-point! function)
(define-extern vector-vector-xz-distance function)
(define-extern vector-v*float+! function)
(define-extern vector-length-max! function)
(define-extern vector*! function)
(define-extern vector+*! function)
(define-extern vector-deg-lerp-clamp! function)
(define-extern vector-negate-in-place! function)
(define-extern vector--float*! function)
(define-extern rot-zyx-from-vector! function)
(define-extern vector4-lerp-clamp! function)
(define-extern vector-seconds! function)
(define-extern vector-degmod function)
(define-extern vector-v*float++! function)
(define-extern vector-degi function)
(define-extern sphere<-vector+r! function)
(define-extern vector-xz-length-max! function)
(define-extern vector3s-! function)
(define-extern vector3s+! function)
(define-extern vector-average! function)
(define-extern vector-cvt.w.s! function)
(define-extern vector-v! function)
(define-extern vector-degf function)
(define-extern vector-vector-xz-distance-squared function)
(define-extern vector-xz-length-squared function)
(define-extern vector-lerp-clamp! function)
(define-extern vector-cvt.s.w! function)
(define-extern vector-to-ups! function)
(define-extern vector-seek! function)
(define-extern vector-seconds function)
(define-extern vector-deg-diff function)
(define-extern vector-delta function)
(define-extern vector+float! function)
(define-extern vector-v+! function)
(define-extern vector3s*float! function)
(define-extern spheres-overlap? function)
(define-extern vector-length-squared function)
(define-extern vector-lerp! function)
(define-extern vector-rotate-around-y! function)
(define-extern vector-*! function)
(define-extern seek-with-smooth function)
(define-extern vector-v*float! function)
(define-extern vector-v++! function)
(define-extern vector-seek-3d-smooth! function)
(define-extern sphere<-vector! function)
(define-extern vector-float/! function)
(define-extern vector= function)
;;(define-extern *display* object) ;; unknown type ;;(define-extern *display* object) ;; unknown type
(define-extern make-vfile-name function)
;;(define-extern file-stream object) ;; unknown type
(define-extern file-info type)
(define-extern make-file-name function)
(define-extern file-info-correct-version? function)
;;(define-extern *file-temp-string* object) ;; unknown type
(define-extern file-stream-read-string function)
;;(define-extern file-stream-length object) ;; unknown type
;;(define-extern file-stream-read object) ;; unknown type
;;(define-extern file-stream-open object) ;; unknown type
;;(define-extern load-dir object) ;; unknown type ;;(define-extern load-dir object) ;; unknown type
;;(define-extern external-art-buffer object) ;; unknown type ;;(define-extern external-art-buffer object) ;; unknown type
;;(define-extern load-dir-art-group object) ;; unknown type ;;(define-extern load-dir-art-group object) ;; unknown type
@ -32085,7 +32109,7 @@
;;(define-extern *display-strip-lines* object) ;; unknown type ;;(define-extern *display-strip-lines* object) ;; unknown type
;;(define-extern *display-process-anim* object) ;; unknown type ;;(define-extern *display-process-anim* object) ;; unknown type
;;(define-extern *display-actor-marks* object) ;; unknown type ;;(define-extern *display-actor-marks* object) ;; unknown type
(define-extern *menu-hook* function) (define-extern *menu-hook* (function none))
;;(define-extern *display-load-boundaries* object) ;; unknown type ;;(define-extern *display-load-boundaries* object) ;; unknown type
;;(define-extern *display-water-marks* object) ;; unknown type ;;(define-extern *display-water-marks* object) ;; unknown type
;;(define-extern *artist-flip-visible* object) ;; unknown type ;;(define-extern *artist-flip-visible* object) ;; unknown type

View file

@ -574,6 +574,13 @@ if `x` is a match, returns `x` from the function (not shown) immediately.
The `return-from` form is very rarely used to return from a block, but sometimes used to return from a function. The `return-from` form is very rarely used to return from a block, but sometimes used to return from a function.
## `return`
Exit a function early.
```lisp
(return value)
```
Has the same behavior as `(return-from #f value)`.
## `label` ## `label`
Create a named label for `goto` or `goto-when`. Create a named label for `goto` or `goto-when`.
```lisp ```lisp
@ -1290,7 +1297,16 @@ This code generation is identical to using a `(set! dst src)` form.
(.nop.vf) (.nop.vf)
``` ```
Inserts a `FNOP` assembly instruction, which is fundamentally the same as a `NOP`. Inserts a `FNOP` assembly instruction, which is fundamentally the same as a `NOP`. It is a 2-byte instruction.
## `.nop` or `(nop!)`
```lisp
(.nop)
;; or
(nop!)
```
Inserts a single-byte `nop`.
## `.lvf` ## `.lvf`
```lisp ```lisp

View file

@ -425,7 +425,8 @@ u64 kopen(u64 fs, u64 name, u64 mode) {
file_stream->flags = 0; file_stream->flags = 0;
printf("****** CALL TO kopen() ******\n"); printf("****** CALL TO kopen() ******\n");
char buffer[128]; char buffer[128];
sprintf(buffer, "host:%s", Ptr<String>(name)->data()); // sprintf(buffer, "host:%s", Ptr<String>(name)->data());
sprintf(buffer, "%s", Ptr<String>(name)->data());
if (!strcmp(info(Ptr<Symbol>(mode))->str->data(), "read")) { if (!strcmp(info(Ptr<Symbol>(mode))->str->data(), "read")) {
file_stream->file = sceOpen(buffer, SCE_RDONLY); file_stream->file = sceOpen(buffer, SCE_RDONLY);
} else { } else {

View file

@ -5,3 +5,133 @@
;; name in dgo: main-h ;; name in dgo: main-h
;; dgos: GAME, ENGINE ;; dgos: GAME, ENGINE
(define *stats-poly* '#f)
(define *stats-memory* '#f)
(define *stats-memory-short* '#f)
(define *stats-collide* '#f)
(define *stats-bsp* '#f)
(define *stats-buffer* '#f)
(define *stats-target* '#f)
(define *stats-dma-test* '#f)
(define *artist-all-visible* '#f)
(define *artist-flip-visible* '#f)
(define *artist-fix-visible* '#f)
(define *artist-fix-frustum* '#f)
(define *artist-error-spheres* '#f)
(define *artist-use-menu-subdiv* '#f)
(define *display-profile* '#t)
(define *display-sidekick-stats* '#f)
(define *display-quad-stats* '#f)
(define *display-tri-stats* '#f)
(define *display-perf-stats* '#f)
(define *display-ground-stats* '#f)
(define *display-collision-marks* '#f)
(define *display-collide-cache* '#f)
(define *display-render-collision* '#f)
(define *display-hipri-collision-marks* '#f)
(define *display-edge-collision-marks* '#f)
(define *display-geo-marks* '#f)
(define *display-target-marks* '#f)
(define *display-collide-history* 0)
(define *display-xyz-axes* '#f)
(define *display-cam-collide-history* '#f)
(define *record-cam-collide-history* '#f)
(define *display-cam-master-marks* '#f)
(define *display-cam-other* '#f)
(define *display-camera-marks* '#f)
(define *camera-no-mip-correction* '#f)
(define *display-cam-los-info* '#f)
(define *display-cam-los-debug* '#f)
(define *display-cam-los-marks* '#f)
(define *display-cam-coll-marks* '#f)
(define *display-camera-info* '#f)
(define *display-camera-old-stats* '#f)
(define *display-camera-last-attacker* '#f)
(define *display-file-info* '#f)
(define *display-actor-marks* '#f)
(define *display-ambient-hint-marks* '#f)
(define *display-ambient-sound-marks* '#f)
(define *display-ambient-poi-marks* '#f)
(define *display-ambient-light-marks* '#f)
(define *display-ambient-dark-marks* '#f)
(define *display-ambient-weather-off-marks* '#f)
(define *display-ambient-ocean-off-marks* '#f)
(define *display-ambient-ocean-near-off-marks* '#f)
(define *display-ambient-music-marks* '#f)
(define *display-sprite-info* '#f)
(define *display-entity-errors* '#t)
(define *display-lights* '#f)
(define *display-instance-info* '#f)
(define *display-deci-count* '#f)
(define *sync-dma* '#f)
(define *display-strip-lines* 0)
(define *display-nav-marks* '#f)
(define *display-path-marks* '#f)
(define *display-vol-marks* '#f)
(define *display-water-marks* '#f)
(define *display-actor-anim* '#f)
(define *display-process-anim* '#f)
(define *display-actor-vis* '#f)
(define *display-actor-graph* '#f)
(define *display-level-border* '#f)
(define *display-load-boundaries* '#f)
(define *display-memcard-info* '#f)
(define *display-split-boxes* '#f)
(define *display-split-box-info* '#f)
(define *display-texture-download* '#f)
(define *display-art-control* '#f)
(define *display-level-spheres* '#f)
(define *time-of-day-effects* '#t)
(define *time-of-day-fast* '#t)
(define *display-iop-info* '#f)
(define *ambient-sound-class* '#t)
(define *slow-frame-rate* '#f)
(define *weather-off* '#f)
(define *debug-pause* '#f)
(define *subdivide-draw-mode* 0)
(define *ocean-subdivide-draw-mode* 0)
;; this is a bit of a trick.
;; I believe *dproc* is the display process.
;; if it is already created and this file is reloaded, we don't want to write over it.
;; so we only set it to #f if we think it hasn't been set before.
(define-extern *dproc* process)
(when (or (not *dproc*)
(zero? *dproc*))
;; no dproc, safe to write over it.
(set! *dproc* #f)
)
(define *run* '#f)
(define *teleport* '#f)
(define *teleport-count* 0)
(define *draw-hook* nothing)
(define *debug-hook* nothing)
(define *menu-hook* nothing)
(define *progress-hook* nothing)
(define *dma-timeout-hook* nothing)
(deftype frame-stats (structure)
((field-time uint64 2 :offset-assert 0)
(field int32 :offset-assert 16)
)
:method-count-assert 9
:size-assert #x14
:flag-assert #x900000014
)
(define *frame-stats* (new 'static 'frame-stats))
(deftype screen-filter (basic)
((draw? basic :offset-assert 4)
(color uint32 :offset-assert 8)
)
:method-count-assert 10
:size-assert #xc
:flag-assert #xa0000000c
(:methods
(dummy-9 () none 9)
)
)

View file

@ -5,3 +5,186 @@
;; name in dgo: file-io ;; name in dgo: file-io
;; dgos: GAME, ENGINE ;; dgos: GAME, ENGINE
;; represents a file that can be read/written, similar to FILE* in C.
;; NOTE: this is a special type in three ways:
;; 1). It is used in the C runtime. This must be kept in sync with kmachine.h's FileStream
;; 2). This type is built-in to the compiler (see TypeSystem.cpp, add_builtin_types)
;; It must be kept up to date with that definition as well.
;; 3). The C runtime constructs this type before anything is loaded. The sizes
;; must be kept up to date there as well.
(deftype file-stream (basic)
((flags uint32 :offset-assert 4)
(mode basic :offset-assert 8)
(name string :offset-assert 12)
(file uint32 :offset-assert 16)
)
(:methods
(new ((allocation symbol) (type-to-make type) (name string) (mode basic)) _type_)
)
:method-count-assert 9
:size-assert #x14
:flag-assert #x900000014
)
(defmethod new file-stream ((allocation symbol) (type-to-make type) (name string) (mode basic))
"Allocate a file-stream and open it."
(let ((stream (object-new)))
(file-stream-open stream name mode)
stream
)
)
;; we already have a length method for a file-stream defined in C.
;; just store that in the method table.
(set! (-> file-stream method-table 4) file-stream-length)
(defun file-stream-read-string ((stream file-stream) (str string))
"Fill a string with data from a file stream.
Note: this function does not work."
;; makes the length of the string 0.
(clear str)
;; so this will read nothing.
(file-stream-read stream (-> str data) (length str))
str
)
;; A common file header found in GOAL files.
(deftype file-info (basic)
((file-type symbol :offset-assert 4)
(file-name basic :offset-assert 8)
(major-version uint32 :offset-assert 12)
(minor-version uint32 :offset-assert 16)
(maya-file-name basic :offset-assert 20)
(tool-debug basic :offset-assert 24)
(mdb-file-name basic :offset-assert 28)
)
:method-count-assert 9
:size-assert #x20
:flag-assert #x900000020
)
(defmethod print file-info ((obj file-info))
"Print information about a file"
(format #t "#<~A ~A :version ~D.~D @ #x~X>"
(-> obj type) (-> obj file-name) (-> obj major-version) (-> obj minor-version) obj)
obj
)
;; allocate a temporary string
(define *file-temp-string* (new 'global 'string 128 (the string #f)))
(defun make-file-name ((kind int) (name string) (art-group-version int))
"Make a file name. Similar to MakeFileName in C.
Note: file type enum is different between C and GOAL.
File versions should match those in versions.h.
Uses a single *file-temp-string* buffer, shared with make-vfile-name."
(clear *file-temp-string*)
(cond
((= kind 3)
(format *file-temp-string* "texture-page~D/dir-tpages" 7))
((= kind 2)
(format *file-temp-string* "texture-page~D/tpage-~S" 7 name))
((zero? kind)
(format *file-temp-string* "level~D/~S-bt" 30 name))
((= kind 5)
(format *file-temp-string* "res~D/~S-tx" 1 name))
((= kind 4)
(format *file-temp-string* "level~D/~S-vs" 30 name))
((= kind 6)
(format *file-temp-string* "~S.VIS" name))
((= kind 1)
(format *file-temp-string* "art-group~D/~S-ag"
(if (> art-group-version 0) art-group-version 6)
name
)
)
)
*file-temp-string*
)
(defun make-vfile-name ((a0-0 int) (a1-0 string))
"Make another type of file name."
(local-vars
(s5-0 int)
(gp-0 string)
)
(set! s5-0 a0-0)
(set! gp-0 a1-0)
(clear *file-temp-string*)
(cond
((zero? s5-0) (format *file-temp-string* "$LEVEL/~S" gp-0))
((= s5-0 1) (format *file-temp-string* "$ART_GROUP/~S" gp-0))
)
*file-temp-string*
)
(defun file-info-correct-version? ((info file-info) (kind int) (version int))
"Check if the file info is valid. If you call this with version = 0,
it will pick the right version for the kind automatically."
(local-vars
(v1-0 int)
(v1-1 int)
(expected-kind string)
(expected-version int)
)
;; figure out the expected major version
(set! expected-version
(cond
((zero? version) ;; version not specified.
(set! v1-0 kind)
(cond
((or (zero? (+ v1-0 -2)) (zero? (+ v1-0 -3))) 7) ;; textures.
((zero? v1-0) 30) ;; level
((= v1-0 1) 6) ;; art-group
)
)
(else version) ;; version was specified
)
)
;; figure out the expected kind
(set! expected-kind
(begin
(set! v1-1 kind)
(cond ((= v1-1 2) "texture-page")
((zero? v1-1) "bsp-header")
((= v1-1 1) "art-group"))
)
)
;; check:
(cond
;; first, check the name is right:
;; not clear why we dereference the symbol like this.
((not (name= (the-as basic (-> info file-type value)) expected-kind))
(format 0 "ERROR: file ~A is of type ~S but needs to be ~S.~%"
(-> info file-name) (-> info file-type) expected-kind)
;; FAIL
'#f
)
;; check versions (only major)
((!= expected-version (-> info major-version))
(format
0
"ERROR: file ~A is version ~D.~D, but needs to be ~D.x~%"
(-> info file-name)
(-> info major-version)
(-> info minor-version)
expected-version
)
'#f
)
;; both tests pass!
(else '#t)
)
)

View file

@ -302,7 +302,9 @@
) )
) )
;; TODO - these work but aren't very efficient. (defmacro return (val)
`(return-from #f ,val)
)
;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;

View file

@ -126,10 +126,11 @@
;; install-handler ;; install-handler
;; install-debug-handler ;; install-debug-handler
;; file-stream-open ;; file-stream-open
(define-extern file-stream-open (function file-stream basic basic file-stream))
;; file-stream-close ;; file-stream-close
;; file-stream-length (define-extern file-stream-length (function file-stream int))
;; file-stream-seek ;; file-stream-seek
;; file-stream-read (define-extern file-stream-read (function file-stream pointer int int))
;; file-stream-write ;; file-stream-write
;; scf-get-language ;; scf-get-language
;; scf-get-time ;; scf-get-time

View file

@ -389,9 +389,67 @@
) )
) )
;; todo (defun nassoc ((a0-0 string) (a1-0 object))
;; nassoc (local-vars
;; nassce (v0-2 object)
(v1-1 object)
(v1-3 symbol)
(a1-1 object)
(s5-0 string)
(gp-0 object)
)
(begin
(set! s5-0 a0-0)
(set! gp-0 a1-0)
(while
(not
(or
(= gp-0 '())
(begin
(set! a1-1 (car (car gp-0)))
(if (pair? a1-1) (nmember s5-0 a1-1) (name= (the basic a1-1) s5-0))
)
)
)
(set! gp-0 (cdr gp-0))
)
(set! v1-3 '#f)
(if (!= gp-0 '()) (car gp-0))
)
)
(defun nassoce ((a0-0 string) (a1-0 object))
(local-vars
(v0-2 object)
(v1-1 object)
(v1-4 symbol)
(s4-0 object)
(s5-0 string)
(gp-0 object)
)
(begin
(set! s5-0 a0-0)
(set! gp-0 a1-0)
(while
(not
(or
(= gp-0 '())
(begin
(set! s4-0 (car (car gp-0)))
(if
(pair? s4-0)
(nmember s5-0 s4-0)
(or (name= (the basic s4-0) s5-0) (= s4-0 'else))
)
)
)
)
(set! gp-0 (cdr gp-0))
)
(set! v1-4 '#f)
(if (!= gp-0 '()) (car gp-0))
)
)
(defun append! ((front object) (back object)) (defun append! ((front object) (back object))
"Append back to front." "Append back to front."
@ -605,7 +663,7 @@
dst dst
) )
(defun mem-set32! ((dst pointer) (value int) (n int)) (defun mem-set32! ((dst pointer) (n int) (value int))
"Memset a 32-bit value n times. Total memory filled is 4 * n bytes." "Memset a 32-bit value n times. Total memory filled is 4 * n bytes."
(let ((p (the pointer dst)) (let ((p (the pointer dst))
(i 0)) (i 0))

View file

@ -85,7 +85,11 @@
;; cat-string<-string_to_charp ;; cat-string<-string_to_charp
;; append-character-to-string ;; append-character-to-string
;; charp-basename ;; charp-basename
;; clear
(defun clear ((a0-0 string))
(set! (-> a0-0 data 0) 0) a0-0
)
;; string<? ;; string<?
;; string>? ;; string>?
;; string<=? ;; string<=?

View file

@ -338,6 +338,7 @@ class Compiler {
Val* compile_return_from(const goos::Object& form, const goos::Object& rest, Env* env); Val* compile_return_from(const goos::Object& form, const goos::Object& rest, Env* env);
Val* compile_label(const goos::Object& form, const goos::Object& rest, Env* env); Val* compile_label(const goos::Object& form, const goos::Object& rest, Env* env);
Val* compile_goto(const goos::Object& form, const goos::Object& rest, Env* env); Val* compile_goto(const goos::Object& form, const goos::Object& rest, Env* env);
Val* compile_nop(const goos::Object& form, const goos::Object& rest, Env* env);
// CompilerControl // CompilerControl
Val* compile_seval(const goos::Object& form, const goos::Object& rest, Env* env); Val* compile_seval(const goos::Object& form, const goos::Object& rest, Env* env);

View file

@ -1023,6 +1023,26 @@ void IR_GetStackAddr::do_codegen(emitter::ObjectGenerator* gen,
} }
} }
///////////////////////
// Nop
///////////////////////
IR_Nop::IR_Nop() {}
std::string IR_Nop::print() {
return fmt::format("nop");
}
RegAllocInstr IR_Nop::to_rai() {
return {};
}
void IR_Nop::do_codegen(emitter::ObjectGenerator* gen,
const AllocationResult&,
emitter::IR_Record irec) {
gen->add_instr(IGen::nop(), irec);
}
/////////////////////// ///////////////////////
// Asm // Asm
/////////////////////// ///////////////////////

View file

@ -340,6 +340,16 @@ class IR_GetStackAddr : public IR {
int m_slot = -1; int m_slot = -1;
}; };
class IR_Nop : public IR {
public:
IR_Nop();
std::string print() override;
RegAllocInstr to_rai() override;
void do_codegen(emitter::ObjectGenerator* gen,
const AllocationResult& allocs,
emitter::IR_Record irec) override;
};
class IR_Asm : public IR { class IR_Asm : public IR {
public: public:
explicit IR_Asm(bool use_coloring); explicit IR_Asm(bool use_coloring);

View file

@ -26,6 +26,7 @@ static const std::unordered_map<
// INLINE ASM - VECTOR FLOAT OPERATIONS // INLINE ASM - VECTOR FLOAT OPERATIONS
{".nop.vf", &Compiler::compile_asm_nop_vf}, {".nop.vf", &Compiler::compile_asm_nop_vf},
{".nop", &Compiler::compile_nop},
{".lvf", &Compiler::compile_asm_lvf}, {".lvf", &Compiler::compile_asm_lvf},
{".svf", &Compiler::compile_asm_svf}, {".svf", &Compiler::compile_asm_svf},
{".xor.vf", &Compiler::compile_asm_xor_vf}, {".xor.vf", &Compiler::compile_asm_xor_vf},
@ -70,6 +71,7 @@ static const std::unordered_map<
{"return-from", &Compiler::compile_return_from}, {"return-from", &Compiler::compile_return_from},
{"label", &Compiler::compile_label}, {"label", &Compiler::compile_label},
{"goto", &Compiler::compile_goto}, {"goto", &Compiler::compile_goto},
{"nop!", &Compiler::compile_nop},
// COMPILER CONTROL // COMPILER CONTROL
{"gs", &Compiler::compile_gs}, {"gs", &Compiler::compile_gs},

View file

@ -185,4 +185,11 @@ Val* Compiler::compile_goto(const goos::Object& form, const goos::Object& rest,
get_parent_env_of_type<FunctionEnv>(env)->unresolved_gotos.push_back({ir_goto.get(), label_name}); get_parent_env_of_type<FunctionEnv>(env)->unresolved_gotos.push_back({ir_goto.get(), label_name});
env->emit(std::move(ir_goto)); env->emit(std::move(ir_goto));
return get_none(); return get_none();
}
Val* Compiler::compile_nop(const goos::Object& form, const goos::Object& rest, Env* env) {
auto args = get_va(form, rest);
va_check(form, args, {}, {});
env->emit_ir<IR_Nop>();
return get_none();
} }

View file

@ -2009,6 +2009,12 @@ class IGen {
return instr; return instr;
} }
static Instruction nop() {
// NOP
Instruction instr(0x90);
return instr;
}
static Instruction nop_vf() { static Instruction nop_vf() {
// FNOP // FNOP
Instruction instr(0xd9); Instruction instr(0xd9);

View file

@ -234,7 +234,7 @@ TEST_F(FormRegressionTest, WhileLoop) {
" (begin (set! v1-0 (-> v1-0 parent)) (= v1-0 a0-1))\n" " (begin (set! v1-0 (-> v1-0 parent)) (= v1-0 a0-1))\n"
" (if\n" " (if\n"
" (= v1-0 a1-0)\n" " (= v1-0 a1-0)\n"
" (return (begin (set! v1-1 '#t) (set! v0-0 v1-1)) (set! v1-0 0))\n" " (return (begin (set! v1-1 '#t) (set! v0-0 v1-1)))\n"
" )\n" " )\n"
" )\n" " )\n"
" (set! v0-0 '#f)\n" " (set! v0-0 '#f)\n"
@ -300,7 +300,7 @@ TEST_F(FormRegressionTest, Or) {
" )\n" " )\n"
" (if\n" " (if\n"
" (= a0-0 a1-0)\n" " (= a0-0 a1-0)\n"
" (return (begin (set! v1-1 '#t) (set! v0-0 v1-1)) (set! v1-0 0))\n" " (return (begin (set! v1-1 '#t) (set! v0-0 v1-1)))\n"
" )\n" " )\n"
" )\n" " )\n"
" (set! v0-0 '#f)\n" " (set! v0-0 '#f)\n"
@ -365,9 +365,9 @@ TEST_F(FormRegressionTest, DynamicMethodAccess) {
" (if\n" " (if\n"
" (begin\n" " (begin\n"
" (if\n" " (if\n"
" (begin (set! a2-0 object) (= a0-0 a2-0))\n" // if we reached the top " (begin (set! a2-0 object) (= a0-0 a2-0))\n" // if we reached the top
" (return (begin (set! v1-3 nothing) (set! v0-0 v1-3)) (set! v1-2 0))\n" // return " (return (begin (set! v1-3 nothing) (set! v0-0 v1-3)))\n" // return
// nothing. // nothing.
" )\n" " )\n"
" (set! a0-0 (-> a0-0 parent))\n" // get next parent type " (set! a0-0 (-> a0-0 parent))\n" // get next parent type
" (set! a2-2 (sll a1-0 2))\n" // fancy access " (set! a2-2 (sll a1-0 2))\n" // fancy access
@ -376,9 +376,9 @@ TEST_F(FormRegressionTest, DynamicMethodAccess) {
// condition) // condition)
" (zero? v0-0)\n" // is it defined? " (zero? v0-0)\n" // is it defined?
" )\n" " )\n"
" (return (begin (set! v1-4 nothing) (set! v0-0 v1-4)) (set! v1-2 0))\n" // also " (return (begin (set! v1-4 nothing) (set! v0-0 v1-4)))\n" // also
// return // return
// nothing. // nothing.
" )\n" " )\n"
" )\n" " )\n"
" (set! v1-5 '#f)\n" " (set! v1-5 '#f)\n"
@ -887,7 +887,7 @@ TEST_F(FormRegressionTest, TypeOf) {
std::string type = "(function object object)"; std::string type = "(function object object)";
std::string expected = std::string expected =
"(begin\n" "(begin\n"
" (set! v1-1 (type-of a0-0))\n" " (set! v1-1 (rtype-of a0-0))\n"
" (set! t9-0 (-> v1-1 methods-by-name print))\n" // print method. " (set! t9-0 (-> v1-1 methods-by-name print))\n" // print method.
" (set! v0-0 (call! a0-0))\n" " (set! v0-0 (call! a0-0))\n"
" (ret-value v0-0)\n" " (ret-value v0-0)\n"

View file

@ -461,7 +461,7 @@ TEST_F(FormRegressionTest, ExprBasicTypeP) {
// don't plan on supporting this. // don't plan on supporting this.
" (if\n" " (if\n"
" (= v1-0 a1-0)\n" " (= v1-0 a1-0)\n"
" (return '#t (set! v1-0 0))\n" " (return '#t)\n"
" )\n" " )\n"
" )\n" " )\n"
" '#f\n" " '#f\n"
@ -507,7 +507,7 @@ TEST_F(FormRegressionTest, FinalBasicTypeP) {
" (set! a0-1 object)\n" " (set! a0-1 object)\n"
" (until\n" " (until\n"
" (begin (set! v1-0 (-> v1-0 parent)) (= v1-0 a0-1))\n" " (begin (set! v1-0 (-> v1-0 parent)) (= v1-0 a0-1))\n"
" (if (= v1-0 a1-0) (return (quote #t) (set! v1-0 0)))\n" " (if (= v1-0 a1-0) (return (quote #t)))\n"
" )\n" " )\n"
" (quote #f)\n" " (quote #f)\n"
" )\n" " )\n"
@ -562,7 +562,7 @@ TEST_F(FormRegressionTest, ExprTypeTypep) {
" (set! a0-0 (-> a0-0 parent))\n" " (set! a0-0 (-> a0-0 parent))\n"
" (or (= a0-0 v1-0) (zero? a0-0))\n" " (or (= a0-0 v1-0) (zero? a0-0))\n"
" )\n" " )\n"
" (if (= a0-0 a1-0) (return '#t (set! v1-0 0)))\n" " (if (= a0-0 a1-0) (return '#t))\n"
" )\n" " )\n"
" '#f\n" " '#f\n"
" )"; " )";
@ -618,13 +618,13 @@ TEST_F(FormRegressionTest, ExprFindParentMethod) {
std::string expected = std::string expected =
"(begin\n" "(begin\n"
" (set! v1-2 (-> a0-0 methods a1-0))\n" " (set! v1-2 (-> a0-0 method-table a1-0))\n"
" (until\n" " (until\n"
" (!= v0-0 v1-2)\n" " (!= v0-0 v1-2)\n"
" (if (= a0-0 object) (return nothing (set! v1-2 0)))\n" " (if (= a0-0 object) (return nothing))\n"
" (set! a0-0 (-> a0-0 parent))\n" " (set! a0-0 (-> a0-0 parent))\n"
" (set! v0-0 (-> a0-0 methods a1-0))\n" " (set! v0-0 (-> a0-0 method-table a1-0))\n"
" (if (zero? v0-0) (return nothing (set! v1-2 0)))\n" " (if (zero? v0-0) (return nothing))\n"
" )\n" " )\n"
" (set! v1-5 '#f)\n" " (set! v1-5 '#f)\n"
" v0-0\n" " v0-0\n"
@ -902,7 +902,7 @@ TEST_F(FormRegressionTest, ExprNmember) {
" (set! s5-0 a0-0)\n" " (set! s5-0 a0-0)\n"
" (set! gp-0 a1-0)\n" " (set! gp-0 a1-0)\n"
" (while\n" " (while\n"
" (not (or (= gp-0 '()) (name= (car gp-0) s5-0)))\n" " (not (or (= gp-0 '()) (name= (the-as basic (car gp-0)) s5-0)))\n"
" (set! gp-0 (cdr gp-0))\n" " (set! gp-0 (cdr gp-0))\n"
" )\n" " )\n"
" (set! v1-2 '#f)\n" " (set! v1-2 '#f)\n"
@ -1110,7 +1110,11 @@ TEST_F(FormRegressionTest, ExprNassoc) {
" (= gp-0 (quote ()))\n" " (= gp-0 (quote ()))\n"
" (begin\n" " (begin\n"
" (set! a1-1 (car (car gp-0)))\n" " (set! a1-1 (car (car gp-0)))\n"
" (if (pair? a1-1) (nmember s5-0 a1-1) (name= a1-1 s5-0))\n" " (if "
" (pair? a1-1)\n"
" (nmember (the-as basic s5-0) a1-1)\n"
" (name= (the-as basic a1-1) (the-as basic s5-0))"
" )\n"
" )\n" " )\n"
" )\n" " )\n"
" )\n" " )\n"
@ -1213,8 +1217,11 @@ TEST_F(FormRegressionTest, ExprNassoce) {
" (set! s4-0 (car (car gp-0)))\n" " (set! s4-0 (car (car gp-0)))\n"
" (if\n" " (if\n"
" (pair? s4-0)\n" " (pair? s4-0)\n"
" (nmember s5-0 s4-0)\n" " (nmember (the-as basic s5-0) s4-0)\n"
" (or (name= s4-0 s5-0) (= s4-0 (quote else)))\n" " (or\n"
" (name= (the-as basic s4-0) (the-as basic s5-0))\n"
" (= s4-0 (quote else))\n"
" )\n"
" )\n" " )\n"
" )\n" " )\n"
" )\n" " )\n"
@ -2063,7 +2070,7 @@ TEST_F(FormRegressionTest, ExprPrint) {
" daddiu sp, sp, 16"; " daddiu sp, sp, 16";
std::string type = "(function object object)"; std::string type = "(function object object)";
std::string expected = "((method-of-type (type-of a0-0) print) a0-0)"; std::string expected = "((method-of-type (rtype-of a0-0) print) a0-0)";
test_with_expr(func, type, expected); test_with_expr(func, type, expected);
} }
@ -2112,7 +2119,7 @@ TEST_F(FormRegressionTest, ExprPrintl) {
"(begin\n" "(begin\n"
" (set! gp-0 a0-0)\n" " (set! gp-0 a0-0)\n"
" (set! a0-1 gp-0)\n" " (set! a0-1 gp-0)\n"
" (set! v1-2 ((method-of-type (type-of a0-1) print) a0-1))\n" " (set! v1-2 ((method-of-type (rtype-of a0-1) print) a0-1))\n"
" (format (quote #t) L324)\n" " (format (quote #t) L324)\n"
" gp-0\n" " gp-0\n"
" )"; " )";
@ -2143,7 +2150,7 @@ TEST_F(FormRegressionTest, ExprInspect) {
" daddiu sp, sp, 16"; " daddiu sp, sp, 16";
std::string type = "(function object object)"; std::string type = "(function object object)";
std::string expected = "((method-of-type (type-of a0-0) inspect) a0-0)"; std::string expected = "((method-of-type (rtype-of a0-0) inspect) a0-0)";
test_with_expr(func, type, expected); test_with_expr(func, type, expected);
} }
@ -2334,13 +2341,13 @@ TEST_F(FormRegressionTest, ExprPrintName) {
"(cond\n" "(cond\n"
" ((= a0-0 a1-0) (quote #t))\n" " ((= a0-0 a1-0) (quote #t))\n"
" ((and (= (-> a0-0 type) string) (= (-> a1-0 type) string))\n" " ((and (= (-> a0-0 type) string) (= (-> a1-0 type) string))\n"
" (string= a0-0 a1-0)\n" " (string= (the-as string a0-0) (the-as string a1-0))\n"
" )\n" " )\n"
" ((and (= (-> a0-0 type) string) (= (-> a1-0 type) symbol))\n" " ((and (= (-> a0-0 type) string) (= (-> a1-0 type) symbol))\n"
" (string= a0-0 (-> (+ 65336 (the-as int a1-0)) 0))\n" " (string= (the-as string a0-0) (-> (+ 65336 (the-as int a1-0)) 0))\n"
" )\n" " )\n"
" ((and (= (-> a1-0 type) string) (= (-> a0-0 type) symbol))\n" " ((and (= (-> a1-0 type) string) (= (-> a0-0 type) symbol))\n"
" (string= a1-0 (-> (+ 65336 (the-as int a0-0)) 0))\n" " (string= (the-as string a1-0) (-> (+ 65336 (the-as int a0-0)) 0))\n"
" )\n" " )\n"
" )"; " )";
test_with_expr(func, type, expected, false, "", {}, test_with_expr(func, type, expected, false, "", {},

View file

@ -2002,8 +2002,8 @@ TEST_F(FormRegressionTest, ExprValid) {
" (if s4-0 (set! v1-24 (format s5-0 L318 gp-0 s4-0 s3-0)))\n" " (if s4-0 (set! v1-24 (format s5-0 L318 gp-0 s4-0 s3-0)))\n"
" (quote #f)\n" " (quote #f)\n"
" )\n" " )\n"
" ((and (= s3-0 type) (!= (type-of gp-0) type))\n" " ((and (= s3-0 type) (!= (rtype-of gp-0) type))\n"
" (if s4-0 (set! v1-31 (format s5-0 L317 gp-0 s4-0 s3-0 (type-of gp-0))))\n" " (if s4-0 (set! v1-31 (format s5-0 L317 gp-0 s4-0 s3-0 (rtype-of gp-0))))\n"
" (quote #f)\n" " (quote #f)\n"
" )\n" " )\n"
" (else\n" " (else\n"
@ -2011,16 +2011,16 @@ TEST_F(FormRegressionTest, ExprValid) {
" v1-33\n" " v1-33\n"
" (and\n" " (and\n"
" (!= s3-0 type)\n" " (!= s3-0 type)\n"
" (not (valid? (type-of gp-0) type (quote #f) (quote #t) 0))\n" " (not (valid? (rtype-of gp-0) type (quote #f) (quote #t) 0))\n"
" )\n" " )\n"
" )\n" " )\n"
" (cond\n" " (cond\n"
" (v1-33\n" " (v1-33\n"
" (if s4-0 (set! v1-37 (format s5-0 L317 gp-0 s4-0 s3-0 (type-of gp-0))))\n" " (if s4-0 (set! v1-37 (format s5-0 L317 gp-0 s4-0 s3-0 (rtype-of gp-0))))\n"
" (quote #f)\n" " (quote #f)\n"
" )\n" " )\n"
" ((not (type-type? (type-of gp-0) s3-0))\n" " ((not (type-type? (rtype-of gp-0) s3-0))\n"
" (if s4-0 (set! v1-41 (format s5-0 L316 gp-0 s4-0 s3-0 (type-of gp-0))))\n" " (if s4-0 (set! v1-41 (format s5-0 L316 gp-0 s4-0 s3-0 (rtype-of gp-0))))\n"
" (quote #f)\n" " (quote #f)\n"
" )\n" " )\n"
" ((= s3-0 symbol)\n" " ((= s3-0 symbol)\n"

View file

@ -3,9 +3,9 @@
(let* ((base-addr #x6000000) (let* ((base-addr #x6000000)
(word-cnt 23) (word-cnt 23)
(base (the (pointer int32) base-addr)) (base (the (pointer int32) base-addr))
(foo (mem-set32! base #x0 (+ 1 word-cnt))) (foo (mem-set32! base (+ 1 word-cnt) #x0))
(last-byte (the (pointer uint8) (+ base-addr 3 (* 4 (- word-cnt 1))))) (last-byte (the (pointer uint8) (+ base-addr 3 (* 4 (- word-cnt 1)))))
(dst (mem-set32! base #x0badbeef word-cnt)) (dst (mem-set32! base word-cnt #x0badbeef))
) )
(if (!= dst base) (if (!= dst base)

View file

@ -8,6 +8,8 @@
(set! (-> b x) 2.) (set! (-> b x) 2.)
(set! (-> b y) 3.) (set! (-> b y) 3.)
(set! (-> b z) 4.) (set! (-> b z) 4.)
(.nop)
(nop!)
(expect-true (= 20.0 (vector-dot-vu a b))) (expect-true (= 20.0 (vector-dot-vu a b)))
) )