[Decompiler] Clean Up (#271)

* clean up

* fix up until generic ops

* finish kernel

* documentation

* types

* add missing file
This commit is contained in:
water111 2021-02-18 11:35:45 -05:00 committed by GitHub
parent 1b5b9a2469
commit db48d94270
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 1230 additions and 784 deletions

View file

@ -232,6 +232,11 @@ class SimpleExpression {
goos::Object to_form(const std::vector<DecompilerLabel>& labels, const Env& env) const;
bool operator==(const SimpleExpression& other) const;
bool is_identity() const { return m_kind == Kind::IDENTITY; }
bool is_var() const { return is_identity() && get_arg(0).is_var(); }
const Variable& var() const {
assert(is_var());
return get_arg(0).var();
}
void get_regs(std::vector<Register>* out) const;
TP_Type get_type(const TypeState& input, const Env& env, const DecompilerTypeSystem& dts) const;
TP_Type get_type_int2(const TypeState& input,

View file

@ -106,10 +106,8 @@ FormElement* SetVarConditionOp::get_as_form(FormPool& pool, const Env& env) cons
FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const {
if (env.has_type_analysis()) {
if (m_addr.is_identity() && m_addr.get_arg(0).is_sym_val()) {
auto val = pool.alloc_single_element_form<SimpleExpressionElement>(nullptr, m_value.as_expr(),
m_my_idx);
auto src = pool.alloc_single_element_form<SimpleExpressionElement>(nullptr, m_addr, m_my_idx);
return pool.alloc_element<SetFormFormElement>(src, val);
return pool.alloc_element<StoreInSymbolElement>(m_addr.get_arg(0).get_str(),
m_value.as_expr(), m_my_idx);
}
IR2_RegOffset ro;
@ -120,22 +118,9 @@ FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const {
(input_type.typespec() == TypeSpec("object") ||
input_type.typespec() == TypeSpec("pair"))) {
if (ro.offset == 2) {
auto base = pool.alloc_single_element_form<SimpleExpressionElement>(
nullptr, SimpleAtom::make_var(ro.var).as_expr(), m_my_idx);
auto val = pool.alloc_single_element_form<SimpleExpressionElement>(
nullptr, m_value.as_expr(), m_my_idx);
auto addr = pool.alloc_single_element_form<GenericElement>(
nullptr, GenericOperator::make_fixed(FixedOperatorKind::CDR), base);
auto fr = pool.alloc_element<SetFormFormElement>(addr, val);
return fr;
return pool.alloc_element<StoreInPairElement>(false, ro.var, m_value.as_expr(), m_my_idx);
} else if (ro.offset == -2) {
auto base = pool.alloc_single_element_form<SimpleExpressionElement>(
nullptr, SimpleAtom::make_var(ro.var).as_expr(), m_my_idx);
auto val = pool.alloc_single_element_form<SimpleExpressionElement>(
nullptr, m_value.as_expr(), m_my_idx);
auto addr = pool.alloc_single_element_form<GenericElement>(
nullptr, GenericOperator::make_fixed(FixedOperatorKind::CAR), base);
return pool.alloc_element<SetFormFormElement>(addr, val);
return pool.alloc_element<StoreInPairElement>(true, ro.var, m_value.as_expr(), m_my_idx);
}
}
@ -160,14 +145,14 @@ FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const {
// we pass along the register offset because code generation seems to be a bit
// different in different cases.
auto source = pool.alloc_single_element_form<ArrayFieldAccess>(
nullptr, ro.var, tokens, input_type.get_multiplier(), ro.offset);
auto source = pool.alloc_element<ArrayFieldAccess>(
ro.var, tokens, input_type.get_multiplier(), ro.offset);
auto val = pool.alloc_single_element_form<SimpleExpressionElement>(
nullptr, m_value.as_expr(), m_my_idx);
// auto val = pool.alloc_single_element_form<SimpleExpressionElement>(
// nullptr, m_value.as_expr(), m_my_idx);
assert(!rd.addr_of);
return pool.alloc_element<SetFormFormElement>(source, val);
return pool.alloc_element<StoreArrayAccess>(source, m_value.as_expr(), m_my_idx, ro.var);
}
}
@ -183,8 +168,6 @@ FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const {
auto rd = env.dts->ts.reverse_field_lookup(rd_in);
if (rd.success) {
auto val = pool.alloc_single_element_form<SimpleExpressionElement>(
nullptr, m_value.as_expr(), m_my_idx);
auto source = pool.alloc_single_element_form<SimpleExpressionElement>(
nullptr, SimpleAtom::make_var(ro.var).as_expr(), m_my_idx);
std::vector<DerefToken> tokens;
@ -192,13 +175,13 @@ FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const {
tokens.push_back(to_token(x));
}
assert(!rd.addr_of);
auto addr =
pool.alloc_single_element_form<DerefElement>(nullptr, source, rd.addr_of, tokens);
return pool.alloc_element<SetFormFormElement>(addr, val);
auto addr = pool.alloc_element<DerefElement>(source, rd.addr_of, tokens);
return pool.alloc_element<StorePlainDeref>(addr, m_value.as_expr(), m_my_idx, ro.var,
std::nullopt);
}
if (input_type.typespec() == TypeSpec("pointer") && ro.offset == 0) {
std::string cast_type;
if (input_type.typespec() == TypeSpec("pointer") && ro.offset == 0) {
switch (m_size) {
case 1:
cast_type = "int8";
@ -220,11 +203,10 @@ FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const {
nullptr, SimpleAtom::make_var(ro.var).as_expr(), m_my_idx);
auto cast_source = pool.alloc_single_element_form<CastElement>(
nullptr, TypeSpec("pointer", {TypeSpec(cast_type)}), source);
auto deref = pool.alloc_single_element_form<DerefElement>(nullptr, cast_source, false,
std::vector<DerefToken>());
auto val = pool.alloc_single_element_form<SimpleExpressionElement>(
nullptr, m_value.as_expr(), m_my_idx);
return pool.alloc_element<SetFormFormElement>(deref, val);
auto deref =
pool.alloc_element<DerefElement>(cast_source, false, std::vector<DerefToken>());
return pool.alloc_element<StorePlainDeref>(deref, m_value.as_expr(), m_my_idx, ro.var,
TypeSpec("pointer", {TypeSpec(cast_type)}));
}
}
}

View file

@ -319,6 +319,50 @@ bool SetVarElement::active() const {
}
}
StoreInSymbolElement::StoreInSymbolElement(std::string sym_name, SimpleExpression value, int my_idx)
: m_sym_name(std::move(sym_name)), m_value(std::move(value)), m_my_idx(my_idx) {}
goos::Object StoreInSymbolElement::to_form_internal(const Env& env) const {
return pretty_print::build_list("set!", m_sym_name, m_value.to_form(env.file->labels, env));
}
void StoreInSymbolElement::apply(const std::function<void(FormElement*)>& f) {
f(this);
}
void StoreInSymbolElement::apply_form(const std::function<void(Form*)>&) {}
void StoreInSymbolElement::collect_vars(VariableSet& vars) const {
m_value.collect_vars(vars);
}
void StoreInSymbolElement::get_modified_regs(RegSet&) const {}
StoreInPairElement::StoreInPairElement(bool is_car,
Variable pair,
SimpleExpression value,
int my_idx)
: m_is_car(is_car), m_pair(pair), m_value(value), m_my_idx(my_idx) {}
goos::Object StoreInPairElement::to_form_internal(const Env& env) const {
return pretty_print::build_list(
"set!", pretty_print::build_list(m_is_car ? "car" : "cdr", m_pair.to_form(env)),
m_value.to_form(env.file->labels, env));
}
void StoreInPairElement::apply(const std::function<void(FormElement*)>& f) {
f(this);
}
void StoreInPairElement::apply_form(const std::function<void(Form*)>&) {}
void StoreInPairElement::collect_vars(VariableSet& vars) const {
m_value.collect_vars(vars);
vars.insert(m_pair);
}
void StoreInPairElement::get_modified_regs(RegSet&) const {}
/////////////////////////////
// SetFormFormElement
/////////////////////////////
@ -335,6 +379,7 @@ goos::Object SetFormFormElement::to_form_internal(const Env& env) const {
}
void SetFormFormElement::apply(const std::function<void(FormElement*)>& f) {
f(this);
m_src->apply(f);
m_dst->apply(f);
}
@ -1598,4 +1643,69 @@ void ConstantTokenElement::apply_form(const std::function<void(Form*)>&) {}
void ConstantTokenElement::collect_vars(VariableSet&) const {}
void ConstantTokenElement::get_modified_regs(RegSet&) const {}
StorePlainDeref::StorePlainDeref(DerefElement* dst,
SimpleExpression expr,
int my_idx,
Variable base_var,
std::optional<TypeSpec> cast_type)
: m_dst(dst),
m_expr(std::move(expr)),
m_my_idx(my_idx),
m_base_var(std::move(base_var)),
m_cast_type(cast_type) {}
goos::Object StorePlainDeref::to_form_internal(const Env& env) const {
if (!m_cast_type.has_value()) {
return pretty_print::build_list("set!", m_dst->to_form(env),
m_expr.to_form(env.file->labels, env));
} else {
return pretty_print::build_list(
"set!", pretty_print::build_list("the-as", m_cast_type->print(), m_dst->to_form(env)),
m_expr.to_form(env.file->labels, env));
}
}
void StorePlainDeref::apply(const std::function<void(FormElement*)>& f) {
f(this);
m_dst->apply(f);
}
void StorePlainDeref::apply_form(const std::function<void(Form*)>&) {}
void StorePlainDeref::collect_vars(VariableSet& vars) const {
m_expr.collect_vars(vars);
m_dst->collect_vars(vars);
}
void StorePlainDeref::get_modified_regs(RegSet& regs) const {
m_dst->get_modified_regs(regs);
}
StoreArrayAccess::StoreArrayAccess(ArrayFieldAccess* dst,
SimpleExpression expr,
int my_idx,
Variable array_src)
: m_dst(dst), m_expr(expr), m_my_idx(my_idx), m_base_var(array_src) {}
goos::Object StoreArrayAccess::to_form_internal(const Env& env) const {
return pretty_print::build_list("set!", m_dst->to_form(env),
m_expr.to_form(env.file->labels, env));
}
void StoreArrayAccess::apply(const std::function<void(FormElement*)>& f) {
f(this);
m_dst->apply(f);
}
void StoreArrayAccess::apply_form(const std::function<void(Form*)>& f) {
m_dst->apply_form(f);
}
void StoreArrayAccess::collect_vars(VariableSet& vars) const {
m_expr.collect_vars(vars);
m_dst->collect_vars(vars);
}
void StoreArrayAccess::get_modified_regs(RegSet& regs) const {
m_dst->get_modified_regs(regs);
}
} // namespace decompiler

View file

@ -43,9 +43,16 @@ class FormElement {
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects);
bool is_popped() const { return m_popped; }
void mark_popped() {
assert(!m_popped);
m_popped = true;
}
protected:
friend class Form;
bool m_popped = false;
};
/*!
@ -61,8 +68,6 @@ class SimpleExpressionElement : public FormElement {
void apply_form(const std::function<void(Form*)>& f) override;
bool is_sequence_point() const override;
void collect_vars(VariableSet& vars) const override;
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
// void push_to_stack(const Env& env, FormStack& stack) override;
void update_from_stack(const Env& env,
FormPool& pool,
FormStack& stack,
@ -219,13 +224,11 @@ class SimpleAtomElement : public FormElement {
void collect_vars(VariableSet& vars) const override;
void get_modified_regs(RegSet& regs) const override;
const SimpleAtom& atom() const { return m_atom; }
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
void update_from_stack(const Env& env,
FormPool& pool,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) override;
// void push_to_stack(const Env& env, FormStack& stack) override;
private:
SimpleAtom m_atom;
@ -246,11 +249,6 @@ class SetVarElement : public FormElement {
bool is_sequence_point() const override;
void collect_vars(VariableSet& vars) const override;
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
void update_from_stack(const Env& env,
FormPool& pool,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) override;
void get_modified_regs(RegSet& regs) const override;
bool active() const override;
@ -276,6 +274,39 @@ class SetVarElement : public FormElement {
SetVarInfo m_var_info;
};
class StoreInSymbolElement : public FormElement {
public:
StoreInSymbolElement(std::string sym_name, SimpleExpression value, int my_idx);
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(VariableSet& vars) const override;
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
void get_modified_regs(RegSet& regs) const override;
private:
std::string m_sym_name;
SimpleExpression m_value;
int m_my_idx = -1;
};
class StoreInPairElement : public FormElement {
public:
StoreInPairElement(bool is_car, Variable pair, SimpleExpression value, int my_idx);
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(VariableSet& vars) const override;
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
void get_modified_regs(RegSet& regs) const override;
private:
bool m_is_car = false;
Variable m_pair;
SimpleExpression m_value;
int m_my_idx = -1;
};
/*!
* Like SetVar, but sets a form to another form.
* This is intended to be used with stores.
@ -298,6 +329,7 @@ class SetFormFormElement : public FormElement {
Form* dst() { return m_dst; }
private:
int m_real_push_count = 0;
Form* m_dst = nullptr;
Form* m_src = nullptr;
};
@ -341,7 +373,8 @@ class AsmOpElement : public FormElement {
/*!
* 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)). As a result, it implements both push
* and update.
*
* In the first case, it can be either a conditional move or actually branching. GOAL seems to use
* the branching when sometimes it could have used the conditional move, and for now, we don't
@ -892,10 +925,13 @@ class DerefElement : public FormElement {
bool allow_side_effects) override;
void get_modified_regs(RegSet& regs) const override;
void inline_nested();
bool is_addr_of() const { return m_is_addr_of; }
const Form* base() const { return m_base; }
Form* base() { return m_base; }
const std::vector<DerefToken>& tokens() const { return m_tokens; }
void set_base(Form* new_base) { m_base = new_base; }
private:
Form* m_base = nullptr;
@ -938,6 +974,12 @@ class ArrayFieldAccess : public FormElement {
bool allow_side_effects) override;
void get_modified_regs(RegSet& regs) const override;
void update_with_val(Form* new_val,
const Env& env,
FormPool& pool,
std::vector<FormElement*>* result,
bool allow_side_effects);
private:
Variable m_source;
std::vector<DerefToken> m_deref_tokens;
@ -1001,6 +1043,46 @@ class ConstantTokenElement : public FormElement {
std::string m_value;
};
class StorePlainDeref : public FormElement {
public:
StorePlainDeref(DerefElement* dst,
SimpleExpression expr,
int my_idx,
Variable base_var,
std::optional<TypeSpec> cast_type);
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(VariableSet& vars) const override;
void get_modified_regs(RegSet& regs) const override;
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
private:
DerefElement* m_dst = nullptr;
SimpleExpression m_expr;
int m_my_idx = -1;
Variable m_base_var;
std::optional<TypeSpec> m_cast_type;
};
class StoreArrayAccess : public FormElement {
public:
StoreArrayAccess(ArrayFieldAccess* dst, SimpleExpression expr, int my_idx, Variable array_src);
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(VariableSet& vars) const override;
void get_modified_regs(RegSet& regs) const override;
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
private:
ArrayFieldAccess* m_dst = nullptr;
SimpleExpression m_expr;
int m_my_idx = -1;
Variable m_base_var;
};
/*!
* A Form is a wrapper around one or more FormElements.
* This is done for two reasons:
@ -1073,6 +1155,14 @@ class Form {
bool has_side_effects();
void get_modified_regs(RegSet& regs) const;
bool is_popped() const { return m_elements.at(0)->is_popped(); }
void mark_popped() {
for (auto x : m_elements) {
x->mark_popped();
}
}
FormElement* parent_element = nullptr;
private:

View file

@ -233,10 +233,15 @@ void Form::update_children_from_stack(const Env& env,
for (size_t i = 0; i < m_elements.size(); i++) {
if (i == 0) {
// only bother doing the first one.
if (!m_elements[i]->is_popped()) {
m_elements[i]->update_from_stack(env, pool, stack, &new_elts, allow_side_effects);
} else {
new_elts.push_back(m_elements[i]);
}
} else {
new_elts.push_back(m_elements[i]);
}
}
for (auto& x : new_elts) {
@ -286,6 +291,7 @@ void LoadSourceElement::update_from_stack(const Env& env,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) {
mark_popped();
m_addr->update_children_from_stack(env, pool, stack, allow_side_effects);
result->push_back(this);
}
@ -356,6 +362,8 @@ void SimpleExpressionElement::update_from_stack_fpr_to_gpr(const Env& env,
// set ourself to identity.
m_expr = src.as_expr();
// then go again.
assert(m_popped);
m_popped = false;
update_from_stack(env, pool, stack, result, allow_side_effects);
} else {
throw std::runtime_error(
@ -756,6 +764,7 @@ void SimpleExpressionElement::update_from_stack(const Env& env,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) {
mark_popped();
switch (m_expr.kind()) {
case SimpleExpression::Kind::IDENTITY:
update_from_stack_identity(env, pool, stack, result, allow_side_effects);
@ -883,6 +892,7 @@ void SimpleExpressionElement::update_from_stack(const Env& env,
///////////////////
void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
mark_popped();
for (auto x : m_src->elts()) {
assert(x->parent_form == m_src);
}
@ -894,6 +904,7 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
}
m_src->update_children_from_stack(env, pool, stack, true);
for (auto x : m_src->elts()) {
assert(x->parent_form == m_src);
}
@ -926,23 +937,110 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
}
}
void SetVarElement::update_from_stack(const Env& env,
FormPool& pool,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) {
m_src->update_children_from_stack(env, pool, stack, allow_side_effects);
for (auto x : m_src->elts()) {
assert(x->parent_form == m_src);
}
result->push_back(this);
void SetFormFormElement::push_to_stack(const Env&, FormPool&, FormStack& stack) {
// todo - is the order here right?
assert(m_popped);
assert(m_real_push_count == 0);
m_real_push_count++;
stack.push_form_element(this, true);
}
void SetFormFormElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
// todo - is the order here right?
m_dst->update_children_from_stack(env, pool, stack, false);
m_src->update_children_from_stack(env, pool, stack, false);
stack.push_form_element(this, true);
void StoreInSymbolElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
auto sym = pool.alloc_single_element_form<ConstantTokenElement>(nullptr, m_sym_name);
auto val = pool.alloc_single_element_form<SimpleExpressionElement>(nullptr, m_value, m_my_idx);
val->update_children_from_stack(env, pool, stack, true);
auto elt = pool.alloc_element<SetFormFormElement>(sym, val);
elt->mark_popped();
stack.push_form_element(elt, true);
}
void StoreInPairElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
auto op = m_is_car ? FixedOperatorKind::CAR : FixedOperatorKind::CDR;
if (m_value.is_var()) {
auto vars = std::vector<Variable>({m_value.var(), m_pair});
auto popped = pop_to_forms(vars, env, pool, stack, true);
auto addr = pool.alloc_single_element_form<GenericElement>(
nullptr, GenericOperator::make_fixed(op), popped.at(1));
addr->mark_popped();
auto fr = pool.alloc_element<SetFormFormElement>(addr, popped.at(0));
fr->mark_popped();
stack.push_form_element(fr, true);
} else {
auto val = pool.alloc_single_element_form<SimpleExpressionElement>(nullptr, m_value, m_my_idx);
val->mark_popped();
auto addr = pool.alloc_single_element_form<GenericElement>(
nullptr, GenericOperator::make_fixed(op),
pop_to_forms({m_pair}, env, pool, stack, true).at(0));
addr->mark_popped();
auto fr = pool.alloc_element<SetFormFormElement>(addr, val);
fr->mark_popped();
stack.push_form_element(fr, true);
}
}
void StorePlainDeref::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
mark_popped();
if (m_expr.is_var()) {
auto vars = std::vector<Variable>({m_expr.var(), m_base_var});
auto popped = pop_to_forms(vars, env, pool, stack, true);
if (m_cast_type.has_value()) {
m_dst->set_base(
pool.alloc_single_element_form<CastElement>(nullptr, *m_cast_type, popped.at(1)));
} else {
m_dst->set_base(popped.at(1));
}
m_dst->mark_popped();
m_dst->inline_nested();
auto fr = pool.alloc_element<SetFormFormElement>(pool.alloc_single_form(nullptr, m_dst),
popped.at(0));
fr->mark_popped();
stack.push_form_element(fr, true);
} else {
auto vars = std::vector<Variable>({m_base_var});
auto popped = pop_to_forms(vars, env, pool, stack, true);
if (m_cast_type.has_value()) {
m_dst->set_base(
pool.alloc_single_element_form<CastElement>(nullptr, *m_cast_type, popped.at(1)));
} else {
m_dst->set_base(popped.at(0));
}
m_dst->mark_popped();
m_dst->inline_nested();
auto val = pool.alloc_single_element_form<SimpleExpressionElement>(nullptr, m_expr, m_my_idx);
val->mark_popped();
auto fr = pool.alloc_element<SetFormFormElement>(pool.alloc_single_form(nullptr, m_dst), val);
fr->mark_popped();
stack.push_form_element(fr, true);
}
}
void StoreArrayAccess::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
mark_popped();
Form* expr_form = nullptr;
Form* array_form = nullptr;
if (m_expr.is_var()) {
auto vars = std::vector<Variable>({m_expr.var(), m_base_var});
auto popped = pop_to_forms(vars, env, pool, stack, true);
m_dst->mark_popped();
expr_form = popped.at(0);
array_form = popped.at(1);
} else {
auto vars = std::vector<Variable>({m_base_var});
auto popped = pop_to_forms(vars, env, pool, stack, true);
m_dst->mark_popped();
expr_form = pool.alloc_single_element_form<SimpleExpressionElement>(nullptr, m_expr, m_my_idx);
array_form = popped.at(0);
}
std::vector<FormElement*> forms_out;
m_dst->update_with_val(array_form, env, pool, &forms_out, true);
auto form_out = pool.alloc_sequence_form(nullptr, forms_out);
auto fr = pool.alloc_element<SetFormFormElement>(form_out, expr_form);
fr->mark_popped();
stack.push_form_element(fr, true);
}
///////////////////
@ -954,6 +1052,7 @@ void AshElement::update_from_stack(const Env& env,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) {
mark_popped();
auto forms = pop_to_forms({value, shift_amount}, env, pool, stack, allow_side_effects, consumed);
auto new_form = pool.alloc_element<GenericElement>(
GenericOperator::make_fixed(FixedOperatorKind::ARITH_SHIFT), forms.at(0), forms.at(1));
@ -969,6 +1068,7 @@ void AbsElement::update_from_stack(const Env& env,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) {
mark_popped();
auto forms = pop_to_forms({source}, env, pool, stack, allow_side_effects, consumed);
auto new_form = pool.alloc_element<GenericElement>(
GenericOperator::make_fixed(FixedOperatorKind::ABS), forms.at(0));
@ -984,6 +1084,7 @@ void FunctionCallElement::update_from_stack(const Env& env,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) {
mark_popped();
std::vector<Form*> args;
auto nargs = m_op->arg_vars().size();
args.resize(nargs, nullptr);
@ -1272,17 +1373,12 @@ void DerefElement::update_from_stack(const Env& env,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) {
mark_popped();
// todo - update var tokens from stack?
m_base->update_children_from_stack(env, pool, stack, allow_side_effects);
// merge nested ->'s
auto as_deref = dynamic_cast<DerefElement*>(m_base->try_as_single_element());
if (as_deref) {
if (!m_is_addr_of && !as_deref->is_addr_of()) {
m_tokens.insert(m_tokens.begin(), as_deref->tokens().begin(), as_deref->tokens().end());
m_base = as_deref->m_base;
}
}
inline_nested();
if (m_tokens.size() >= 3) {
auto& method_name = m_tokens.at(m_tokens.size() - 1);
@ -1332,11 +1428,22 @@ void DerefElement::update_from_stack(const Env& env,
}
}
void DerefElement::inline_nested() {
auto as_deref = dynamic_cast<DerefElement*>(m_base->try_as_single_element());
if (as_deref) {
if (!m_is_addr_of && !as_deref->is_addr_of()) {
m_tokens.insert(m_tokens.begin(), as_deref->tokens().begin(), as_deref->tokens().end());
m_base = as_deref->m_base;
}
}
}
///////////////////
// UntilElement
///////////////////
void UntilElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
mark_popped();
for (auto form : {condition, body}) {
FormStack temp_stack(false);
for (auto& entry : form->elts()) {
@ -1353,6 +1460,7 @@ void UntilElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stac
}
void WhileElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
mark_popped();
bool first = true;
for (auto form : {body, condition}) {
FormStack temp_stack(first && stack.is_root());
@ -1373,12 +1481,25 @@ void WhileElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stac
// CondNoElseElement
///////////////////
void CondNoElseElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
mark_popped();
if (already_rewritten) {
stack.push_form_element(this, true);
return;
}
// the first condition is special
auto first_condition = entries.front().condition;
// lets evaluate in on the parent stack...
for (auto x : first_condition->elts()) {
x->push_to_stack(env, pool, stack);
}
for (auto& entry : entries) {
for (auto form : {entry.condition, entry.body}) {
if (form == first_condition) {
form->clear();
form->push_back(stack.pop_back(pool));
} else {
FormStack temp_stack(false);
for (auto& elt : form->elts()) {
elt->push_to_stack(env, pool, temp_stack);
@ -1397,16 +1518,6 @@ void CondNoElseElement::push_to_stack(const Env& env, FormPool& pool, FormStack&
}
}
}
// raise expression.
auto top_condition = entries.front().condition;
if (!top_condition->is_single_element()) {
auto real_condition = top_condition->back();
top_condition->pop_back();
for (auto x : top_condition->elts()) {
x->push_to_stack(env, pool, stack);
}
top_condition->elts() = {real_condition};
}
if (used_as_value) {
@ -1418,6 +1529,7 @@ void CondNoElseElement::push_to_stack(const Env& env, FormPool& pool, FormStack&
}
void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
mark_popped();
if (already_rewritten) {
stack.push_form_element(this, true);
return;
@ -1426,9 +1538,20 @@ void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStac
std::optional<Variable> last_var;
bool rewrite_as_set = true;
// the first condition is special
auto first_condition = entries.front().condition;
// lets evaluate in on the parent stack...
for (auto x : first_condition->elts()) {
x->push_to_stack(env, pool, stack);
}
// process conditions and bodies
for (auto& entry : entries) {
for (auto form : {entry.condition, entry.body}) {
if (form == first_condition) {
form->clear();
form->push_back(stack.pop_back(pool));
} else {
FormStack temp_stack(false);
for (auto& elt : form->elts()) {
elt->push_to_stack(env, pool, temp_stack);
@ -1443,6 +1566,7 @@ void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStac
}
}
}
}
// process else.
FormStack temp_stack(false);
@ -1500,17 +1624,6 @@ void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStac
rewrite_to_get_var(else_ir->elts(), pool, *last_var);
}
// raise expression.
auto top_condition = entries.front().condition;
if (!top_condition->is_single_element()) {
auto real_condition = top_condition->back();
top_condition->pop_back();
for (auto x : top_condition->elts()) {
x->push_to_stack(env, pool, stack);
}
top_condition->elts() = {real_condition};
}
if (rewrite_as_set) {
if (set_unused) {
stack.push_form_element(this, true);
@ -1528,6 +1641,7 @@ void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStac
///////////////////
void ShortCircuitElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
mark_popped();
if (!used_as_value.value_or(false)) {
throw std::runtime_error(
"ShortCircuitElement::push_to_stack not implemented for result not used case.");
@ -1538,8 +1652,20 @@ void ShortCircuitElement::push_to_stack(const Env& env, FormPool& pool, FormStac
stack.push_form_element(this, true);
return;
}
// the first condition is special
auto first_condition = entries.front().condition;
// lets evaluate in on the parent stack...
for (auto x : first_condition->elts()) {
x->push_to_stack(env, pool, stack);
}
for (int i = 0; i < int(entries.size()); i++) {
auto& entry = entries.at(i);
if (entry.condition == first_condition) {
entry.condition->clear();
entry.condition->push_back(stack.pop_back(pool));
} else {
FormStack temp_stack(false);
for (auto& elt : entry.condition->elts()) {
elt->push_to_stack(env, pool, temp_stack);
@ -1557,15 +1683,6 @@ void ShortCircuitElement::push_to_stack(const Env& env, FormPool& pool, FormStac
entry.condition->push_back(e);
}
}
auto top_condition = entries.front().condition;
if (!top_condition->is_single_element()) {
auto real_condition = top_condition->back();
top_condition->pop_back();
for (auto x : top_condition->elts()) {
x->push_to_stack(env, pool, stack);
}
top_condition->elts() = {real_condition};
}
assert(used_as_value.has_value());
@ -1579,6 +1696,7 @@ void ShortCircuitElement::update_from_stack(const Env& env,
FormStack& stack,
std::vector<FormElement*>* result,
bool) {
mark_popped();
(void)stack;
if (already_rewritten) {
result->push_back(this);
@ -1717,6 +1835,7 @@ FormElement* ConditionElement::make_generic(const Env&,
}
void ConditionElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
mark_popped();
std::vector<Form*> source_forms, popped_forms;
std::vector<TypeSpec> source_types;
std::vector<Variable> vars;
@ -1766,6 +1885,7 @@ void ConditionElement::update_from_stack(const Env& env,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) {
mark_popped();
std::vector<Form*> source_forms, popped_forms;
std::vector<TypeSpec> source_types;
std::vector<Variable> vars;
@ -1811,6 +1931,7 @@ void ConditionElement::update_from_stack(const Env& env,
}
void ReturnElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
mark_popped();
FormStack temp_stack(false);
for (auto& elt : return_code->elts()) {
elt->push_to_stack(env, pool, temp_stack);
@ -1827,6 +1948,7 @@ void ReturnElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
}
void AtomicOpElement::push_to_stack(const Env& env, FormPool&, FormStack& stack) {
mark_popped();
auto as_end = dynamic_cast<const FunctionEndOp*>(m_op);
if (as_end) {
// we don't want to push this to the stack (for now at least)
@ -1851,6 +1973,7 @@ void AtomicOpElement::push_to_stack(const Env& env, FormPool&, FormStack& stack)
}
void AsmOpElement::push_to_stack(const Env&, FormPool&, FormStack& stack) {
mark_popped();
stack.push_form_element(this, true);
}
@ -1859,11 +1982,11 @@ void GenericElement::update_from_stack(const Env& env,
FormStack& stack,
std::vector<FormElement*>* result,
bool) {
// TODO improve.
if (m_head.m_kind == GenericOperator::Kind::FUNCTION_EXPR) {
m_head.m_function->update_children_from_stack(env, pool, stack, false);
} else {
m_elts.back()->update_children_from_stack(env, pool, stack, false);
mark_popped();
if (m_elts.size() == 1) {
// a bit of a hack, but AtomicOpForm uses this for loading car/cdr
// this is safe to do.
m_elts.front()->update_children_from_stack(env, pool, stack, true);
}
result->push_back(this);
}
@ -1871,6 +1994,7 @@ void GenericElement::update_from_stack(const Env& env,
void GenericElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
(void)env;
(void)pool;
mark_popped();
stack.push_form_element(this, true);
}
@ -1883,6 +2007,7 @@ void DynamicMethodAccess::update_from_stack(const Env& env,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) {
mark_popped();
auto new_val = stack.pop_reg(m_source, {}, env, allow_side_effects);
auto reg0_matcher =
Matcher::match_or({Matcher::any_reg(0), Matcher::cast("uint", Matcher::any_reg(0))});
@ -1927,12 +2052,11 @@ bool is_power_of_two(int in, int* out) {
}
} // namespace
void ArrayFieldAccess::update_from_stack(const Env& env,
void ArrayFieldAccess::update_with_val(Form* new_val,
const Env& env,
FormPool& pool,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) {
auto new_val = stack.pop_reg(m_source, {}, env, allow_side_effects);
bool) {
int power_of_two = 0;
if (m_constant_offset == 0) {
@ -2077,6 +2201,16 @@ void ArrayFieldAccess::update_from_stack(const Env& env,
}
}
void ArrayFieldAccess::update_from_stack(const Env& env,
FormPool& pool,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) {
mark_popped();
auto new_val = stack.pop_reg(m_source, {}, env, allow_side_effects);
update_with_val(new_val, env, pool, result, allow_side_effects);
}
////////////////////////
// CastElement
////////////////////////
@ -2086,6 +2220,7 @@ void CastElement::update_from_stack(const Env& env,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) {
mark_popped();
m_source->update_children_from_stack(env, pool, stack, allow_side_effects);
result->push_back(this);
}
@ -2099,6 +2234,7 @@ void TypeOfElement::update_from_stack(const Env& env,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) {
mark_popped();
value->update_children_from_stack(env, pool, stack, allow_side_effects);
result->push_back(this);
}
@ -2108,6 +2244,7 @@ void TypeOfElement::update_from_stack(const Env& env,
////////////////////////
void EmptyElement::push_to_stack(const Env&, FormPool&, FormStack& stack) {
mark_popped();
stack.push_form_element(this, true);
}
@ -2121,6 +2258,7 @@ bool is_symbol_true(const Form* form) {
}
void ConditionalMoveFalseElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
mark_popped();
// pop the value and the original
auto popped = pop_to_forms({old_value, source}, env, pool, stack, true);
if (!is_symbol_true(popped.at(0))) {
@ -2136,27 +2274,21 @@ void ConditionalMoveFalseElement::push_to_stack(const Env& env, FormPool& pool,
true);
}
void SimpleAtomElement::push_to_stack(const Env&, FormPool&, FormStack& stack) {
stack.push_form_element(this, true);
}
void SimpleAtomElement::update_from_stack(const Env&,
FormPool&,
FormStack&,
std::vector<FormElement*>* result,
bool) {
mark_popped();
result->push_back(this);
}
void SimpleExpressionElement::push_to_stack(const Env&, FormPool&, FormStack& stack) {
stack.push_form_element(this, true);
}
void StringConstantElement::update_from_stack(const Env&,
FormPool&,
FormStack&,
std::vector<FormElement*>* result,
bool) {
mark_popped();
result->push_back(this);
}
@ -2165,6 +2297,7 @@ void GetMethodElement::update_from_stack(const Env&,
FormStack&,
std::vector<FormElement*>* result,
bool) {
mark_popped();
result->push_back(this);
}
@ -2173,6 +2306,7 @@ void CondNoElseElement::update_from_stack(const Env&,
FormStack&,
std::vector<FormElement*>* result,
bool) {
mark_popped();
result->push_back(this);
}
@ -2181,6 +2315,7 @@ void ConstantTokenElement::update_from_stack(const Env&,
FormStack&,
std::vector<FormElement*>* result,
bool) {
mark_popped();
result->push_back(this);
}

View file

@ -191,6 +191,21 @@ Form* FormStack::unsafe_peek(Register reg, const Env& env) {
return nullptr;
}
FormElement* FormStack::pop_back(FormPool& pool) {
auto& back = m_stack.back();
assert(back.active);
back.active = false;
if (back.elt) {
return back.elt;
} else {
assert(back.destination.has_value());
auto elt = pool.alloc_element<SetVarElement>(*back.destination, back.source,
back.sequence_point, back.set_info);
back.source->parent_element = elt;
return elt;
}
}
std::vector<FormElement*> FormStack::rewrite(FormPool& pool) {
std::vector<FormElement*> result;

View file

@ -36,6 +36,7 @@ class FormStack {
const Env& env,
bool allow_side_effects,
int begin_idx = -1);
FormElement* pop_back(FormPool& pool);
Form* unsafe_peek(Register reg, const Env& env);
bool is_single_expression();
std::vector<FormElement*> rewrite(FormPool& pool);

View file

@ -502,13 +502,13 @@
(define-extern search-process-tree (function process-tree (function process-tree object) process))
(define-extern execute-process-tree (function process-tree (function object object) kernel-context object))
(define-extern previous-brother (function process-tree process-tree))
(define-extern previous-brother (function process-tree object))
(define-extern change-parent (function process-tree process-tree process-tree))
(define-extern change-brother (function process-tree process-tree process-tree))
(define-extern change-brother (function process-tree process-tree object))
(define-extern change-to-last-brother (function process-tree process-tree))
(define-extern *active-pool* process-tree)
(define-extern kernel-dispatcher (function (function object)))
(define-extern kernel-dispatcher (function object))
(define-extern inspect-process-tree (function process-tree int int symbol process-tree))
(define-extern throw-dispatch (function catch-frame object none))
@ -11014,53 +11014,54 @@
:flag-assert #x900000028
)
; ;; progress-h
; (deftype progress (process)
; ((~Tcurrent-debug-string int32 :offset-assert 112)
; (~Tcurrent-debug-language int32 :offset-assert 116)
; (~Tcurrent-debug-group int32 :offset-assert 120)
; (~Tin-out-position int32 :offset-assert 124)
; (~Tdisplay-state uint64 :offset-assert 128)
; (~Tnext-display-state uint64 :offset-assert 136)
; (~Toption-index int32 :offset-assert 144)
; (~Tselected-option basic :offset-assert 148)
; (~Tcompletion-percentage float :offset-assert 152)
; (~Tready-to-run basic :offset-assert 156)
; (~Tdisplay-level-index int32 :offset-assert 160)
; (~Tnext-level-index int32 :offset-assert 164)
; (~Ttask-index int32 :offset-assert 168)
; (~Tin-transition basic :offset-assert 172)
; (~Tlast-in-transition basic :offset-assert 176)
; (~Tforce-transition basic :offset-assert 180)
; (~Tstat-transition basic :offset-assert 184)
; (~Tlevel-transition int32 :offset-assert 188)
; (~Tlanguage-selection uint64 :offset-assert 192)
; (~Tlanguage-direction basic :offset-assert 200)
; (~Tlanguage-transition basic :offset-assert 204)
; (~Tlanguage-x-offset int32 :offset-assert 208)
; (~Tsides-x-scale float :offset-assert 212)
; (~Tsides-y-scale float :offset-assert 216)
; (~Tleft-x-offset int32 :offset-assert 220)
; (~Tright-x-offset int32 :offset-assert 224)
; (~Tbutton-scale float :offset-assert 228)
; (~Tslot-scale float :offset-assert 232)
; (~Tleft-side-x-scale float :offset-assert 236)
; (~Tleft-side-y-scale float :offset-assert 240)
; (~Tright-side-x-scale float :offset-assert 244)
; (~Tright-side-y-scale float :offset-assert 248)
; (~Tsmall-orb-y-offset int32 :offset-assert 252)
; (~Tbig-orb-y-offset int32 :offset-assert 256)
; (~Ttransition-offset int32 :offset-assert 260)
; (~Ttransition-offset-invert int32 :offset-assert 264)
; (~Ttransition-percentage float :offset-assert 268)
; (~Ttransition-percentage-invert float :offset-assert 272)
; (~Ttransition-speed float :offset-assert 276)
; (~Ttotal-nb-of-power-cells int32 :offset-assert 280)
; (~Ttotal-nb-of-orbs int32 :offset-assert 284)
; (~Ttotal-nb-of-buzzers int32 :offset-assert 288)
; (~Tcard-info mc-slot-info :offset-assert 292)
; (~Tlast-option-index-change uint64 :offset-assert 296)
; (~Tvideo-mode-timeout uint64 :offset-assert 304)
;; progress-h
(deftype progress (process)
((~Tcurrent-debug-string int32 :offset-assert 112)
(~Tcurrent-debug-language int32 :offset-assert 116)
(~Tcurrent-debug-group int32 :offset-assert 120)
(~Tin-out-position int32 :offset-assert 124)
(~Tdisplay-state uint64 :offset-assert 128)
(~Tnext-display-state uint64 :offset-assert 136)
(~Toption-index int32 :offset-assert 144)
(~Tselected-option basic :offset-assert 148)
(~Tcompletion-percentage float :offset-assert 152)
(~Tready-to-run basic :offset-assert 156)
(~Tdisplay-level-index int32 :offset-assert 160)
(~Tnext-level-index int32 :offset-assert 164)
(~Ttask-index int32 :offset-assert 168)
(~Tin-transition basic :offset-assert 172)
(~Tlast-in-transition basic :offset-assert 176)
(~Tforce-transition basic :offset-assert 180)
(~Tstat-transition basic :offset-assert 184)
(~Tlevel-transition int32 :offset-assert 188)
(~Tlanguage-selection uint64 :offset-assert 192)
(~Tlanguage-direction basic :offset-assert 200)
(~Tlanguage-transition basic :offset-assert 204)
(~Tlanguage-x-offset int32 :offset-assert 208)
(~Tsides-x-scale float :offset-assert 212)
(~Tsides-y-scale float :offset-assert 216)
(~Tleft-x-offset int32 :offset-assert 220)
(~Tright-x-offset int32 :offset-assert 224)
(~Tbutton-scale float :offset-assert 228)
(~Tslot-scale float :offset-assert 232)
(~Tleft-side-x-scale float :offset-assert 236)
(~Tleft-side-y-scale float :offset-assert 240)
(~Tright-side-x-scale float :offset-assert 244)
(~Tright-side-y-scale float :offset-assert 248)
(~Tsmall-orb-y-offset int32 :offset-assert 252)
(~Tbig-orb-y-offset int32 :offset-assert 256)
(~Ttransition-offset int32 :offset-assert 260)
(~Ttransition-offset-invert int32 :offset-assert 264)
(~Ttransition-percentage float :offset-assert 268)
(~Ttransition-percentage-invert float :offset-assert 272)
(~Ttransition-speed float :offset-assert 276)
(~Ttotal-nb-of-power-cells int32 :offset-assert 280)
(~Ttotal-nb-of-orbs int32 :offset-assert 284)
(~Ttotal-nb-of-buzzers int32 :offset-assert 288)
(~Tcard-info mc-slot-info :offset-assert 292)
(~Tlast-option-index-change uint64 :offset-assert 296)
(~Tvideo-mode-timeout uint64 :offset-assert 304)
(pad uint8 :offset 731)
; (~Tdisplay-state-stack UNKNOWN 5 :offset-assert 312)
; (~Toption-index-stack UNKNOWN 5 :offset-assert 352)
; (~Tdisplay-state-pos int32 :offset-assert 372)
@ -11070,64 +11071,59 @@
; (~Tnb-of-particles int32 :offset-assert 408)
; (~Tparticles UNKNOWN 40 :offset-assert 412)
; (~Tparticle-state UNKNOWN 40 :offset-assert 572)
; )
; :method-count-assert 59
; :size-assert #x2dc
; :flag-assert #x3b027002dc
; ;; inherited inspect of process
; (:methods
; (dummy-9 () none 9)
; (dummy-10 () none 10)
; (dummy-11 () none 11)
; (dummy-12 () none 12)
; (dummy-13 () none 13)
; (dummy-14 () none 14)
; (dummy-15 () none 15)
; (dummy-16 () none 16)
; (dummy-17 () none 17)
; (dummy-18 () none 18)
; (dummy-19 () none 19)
; (dummy-20 () none 20)
; (dummy-21 () none 21)
; (dummy-22 () none 22)
; (dummy-23 () none 23)
; (dummy-24 () none 24)
; (dummy-25 () none 25)
; (dummy-26 () none 26)
; (dummy-27 () none 27)
; (dummy-28 () none 28)
; (dummy-29 () none 29)
; (dummy-30 () none 30)
; (dummy-31 () none 31)
; (dummy-32 () none 32)
; (dummy-33 () none 33)
; (dummy-34 () none 34)
; (dummy-35 () none 35)
; (dummy-36 () none 36)
; (dummy-37 () none 37)
; (dummy-38 () none 38)
; (dummy-39 () none 39)
; (dummy-40 () none 40)
; (dummy-41 () none 41)
; (dummy-42 () none 42)
; (dummy-43 () none 43)
; (dummy-44 () none 44)
; (dummy-45 () none 45)
; (dummy-46 () none 46)
; (dummy-47 () none 47)
; (dummy-48 () none 48)
; (dummy-49 () none 49)
; (dummy-50 () none 50)
; (dummy-51 () none 51)
; (dummy-52 () none 52)
; (dummy-53 () none 53)
; (dummy-54 () none 54)
; (dummy-55 () none 55)
; (dummy-56 () none 56)
; (dummy-57 () none 57)
; (dummy-58 () none 58)
; )
; )
)
:method-count-assert 59
:size-assert #x2dc
:flag-assert #x3b000002dc
;; inherited inspect of process
(:methods
(dummy-14 () none 14)
(dummy-15 () none 15)
(dummy-16 () none 16)
(dummy-17 () none 17)
(dummy-18 () none 18)
(dummy-19 () none 19)
(dummy-20 () none 20)
(dummy-21 () none 21)
(dummy-22 () none 22)
(dummy-23 () none 23)
(dummy-24 () none 24)
(dummy-25 () none 25)
(dummy-26 () none 26)
(dummy-27 () none 27)
(dummy-28 () none 28)
(dummy-29 () none 29)
(dummy-30 () none 30)
(dummy-31 () none 31)
(dummy-32 () none 32)
(dummy-33 () none 33)
(dummy-34 () none 34)
(dummy-35 () none 35)
(dummy-36 () none 36)
(dummy-37 () none 37)
(dummy-38 () none 38)
(dummy-39 () none 39)
(dummy-40 () none 40)
(dummy-41 () none 41)
(dummy-42 () none 42)
(dummy-43 () none 43)
(dummy-44 () none 44)
(dummy-45 () none 45)
(dummy-46 () none 46)
(dummy-47 () none 47)
(dummy-48 () none 48)
(dummy-49 () none 49)
(dummy-50 () none 50)
(dummy-51 () none 51)
(dummy-52 () none 52)
(dummy-53 () none 53)
(dummy-54 () none 54)
(dummy-55 () none 55)
(dummy-56 () none 56)
(dummy-57 () none 57)
(dummy-58 () none 58)
)
)
;; rpc-h
(deftype rpc-buffer (basic)
@ -33078,7 +33074,7 @@
;;(define-extern *hud-parts* object) ;; unknown type
(define-extern game-option type)
;;(define-extern progress object) ;; unknown type
;;(define-extern *progress-process* object) ;; unknown type
(define-extern *progress-process* process) ;; unknown type
;;(define-extern count-info object) ;; unknown type
(define-extern task-info-data type)
(define-extern game-count-info type)
@ -35375,13 +35371,13 @@
(define-extern main-cheats function)
;;(define-extern *progress-cheat* object) ;; unknown type
(define-extern display-loop function)
(define-extern letterbox function)
(define-extern letterbox (function none))
;;(define-extern *cheat-temp* object) ;; unknown type
;;(define-extern *master-exit* object) ;; unknown type
;;(define-extern *last-master-mode* object) ;; unknown type
(define-extern off function)
;;(define-extern *screen-filter* object) ;; unknown type
(define-extern set-letterbox-frames function)
(define-extern set-letterbox-frames (function int none))
(define-extern entity-by-type function)
;;(define-extern scf-get-timeout object) ;; unknown type
(define-extern pause-allowed? function)
@ -35767,7 +35763,7 @@
;;(define-extern iron object) ;; unknown type
;;(define-extern wood object) ;; unknown type
;;(define-extern crate-type object) ;; unknown type
;;(define-extern hud-arriving object) ;; unknown type
(define-extern hud-arriving state) ;; unknown type
;;(define-extern hud-leaving object) ;; unknown type
;;(define-extern hud-hidden object) ;; unknown type
;;(define-extern hud-in object) ;; unknown type

View file

@ -340,6 +340,11 @@
"(method 0 state)":{
"args":["allocation", "type-to-make", "name", "code", "trans", "enter", "exit", "event"],
"vars":{"v0-0":"obj"}
},
"previous-brother":{
"args":["proc"],
"vars":{"v1-0":"parent", "v1-2":"child"}
}

View file

@ -14,7 +14,9 @@
- The types `cpu-thread` and `catch-frame` have a slightly different layout in OpenGOAL to back up x86-64 registers
## `gkernel`:
- In progress
- Many changes for x86-64/OpenGOAL
- A few bugs in the game related to `process-tree` vs `(pointer process-tree)`.
- `change-brother` is totally wrong, unused, and left out.
## `pskernel`: **Done**
- Unimplemented in OpenGOAL. Seems to be debugging hooks into the PS2's kernel. Error strings indicate that there should have been a second related file included that actually contained the debugging handlers, but this file is not present.

24
doc/emacs_config.el Normal file
View file

@ -0,0 +1,24 @@
;; make gc files use lisp-mode
(add-to-list 'auto-mode-alist '("\\.gc\\'" . lisp-mode))
;; run setup-goal when we enter lisp mode
(add-hook 'lisp-mode-hook 'setup-goal)
(defun setup-goal ()
;; if we are in a gc file, change indent settings for GOAL
(when (and (stringp buffer-file-name)
(string-match "\\.gc\\'" buffer-file-name))
(put 'with-pp 'common-lisp-indent-function 0)
(put 'while 'common-lisp-indent-function 1)
(put 'rlet 'common-lisp-indent-function 1)
(put 'until 'common-lisp-indent-function 1)
(put 'countdown 'common-lisp-indent-function 1)
(put 'defun-debug 'common-lisp-indent-function 2)
(put 'defenum 'common-lisp-indent-function 2)
;; indent for common lisp, this makes if's look nicer
(custom-set-variables '(lisp-indent-function 'common-lisp-indent-function))
(autoload 'common-lisp-indent-function "cl-indent" "Common Lisp indent.")
;; use spaces, not tabs
(setq-default indent-tabs-mode nil)
)
)

View file

@ -113,21 +113,21 @@
;; Thread and CPU Thread
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; A GOAL thread represents the execution of code in a process.
; Each process has a "main thread", which is suspended and resumed.
; A process may also execute various temporary threads which always run until completion.
; A "temporary thread" cannot suspend and resume, but a "main thread" can.
; The currently executing thread of a process is the "top-thread".
;; A GOAL thread represents the execution of code in a process.
;; Each process has a "main thread", which is suspended and resumed.
;; A process may also execute various temporary threads which always run until completion.
;; A "temporary thread" cannot suspend and resume, but a "main thread" can.
;; The currently executing thread of a process is the "top-thread".
; Threads that suspend do so by saving their saved registers and their stack.
; All threads run on a single large stack and have small "backup" stacks that are much smaller than the main stack.
; as a result, suspending can fail if you are using more stack than the size of your backup stack.
; This "backup stack" can be different sizes for different threads and makes the thread type dynamic.
; The main thread is stored on the process heap, as they need the same lifetime as the process.
; The temporary threads are stored on the stack. There can be only one temporary thread at a time.
;; Threads that suspend do so by saving their saved registers and their stack.
;; All threads run on a single large stack and have small "backup" stacks that are much smaller than the main stack.
;; as a result, suspending can fail if you are using more stack than the size of your backup stack.
;; This "backup stack" can be different sizes for different threads and makes the thread type dynamic.
;; The main thread is stored on the process heap, as they need the same lifetime as the process.
;; The temporary threads are stored on the stack. There can be only one temporary thread at a time.
; All threads are actually cpu-threads. It's not clear why there are two separate types.
; Perhaps the thread was the public interface and cpu-thread is internal to the kernel?
;; All threads are actually cpu-threads. It's not clear why there are two separate types.
;; Perhaps the thread was the public interface and cpu-thread is internal to the kernel?
(defmethod delete thread ((obj thread))
"Clean up a temporary thread after it is done being used.
@ -1515,7 +1515,6 @@
(defun kill-by-type (type (pool process-tree))
"Call deactivate on all processes with the given type"
(break) ; this is sketchy.
(set! *global-search-name* (the basic type))
(let ((proc (the process-tree #f)))
(while (set! proc (search-process-tree pool (lambda ((var process))
@ -1537,7 +1536,6 @@
(defun kill-not-type (type (pool process-tree))
"Call deactivate on all prcesses that don't match the given type"
(break) ;; this function is weird.
(set! *global-search-name* (the basic type))
(let ((proc (the process-tree #f)))
(while (set! proc (search-process-tree pool (lambda ((var process))
@ -1693,8 +1691,7 @@
((-> obj trans-hook)
;; we have a trans hook defined. let's create a thread and run it. we can reuse the stack of the main-thread
;; it is safe to do this because the main-thread is currently suspended or hasn't run yet.
;; hack process -> global new todo
(let ((trans (new 'global 'cpu-thread obj 'trans PROCESS_STACK_SAVE_SIZE (-> obj main-thread stack-top))))
(let ((trans (new 'process 'cpu-thread obj 'trans PROCESS_STACK_SAVE_SIZE (-> obj main-thread stack-top))))
;; call the function in the thread.
(reset-and-call trans (-> obj trans-hook))
;; remove the cpu-thread
@ -1729,8 +1726,7 @@
;; POST CODE
(cond
((-> obj post-hook)
;; hack process -> global new todo
(let ((post (new 'global 'cpu-thread obj 'post PROCESS_STACK_SAVE_SIZE *kernel-dram-stack*)))
(let ((post (new 'process 'cpu-thread obj 'post PROCESS_STACK_SAVE_SIZE *kernel-dram-stack*)))
(reset-and-call post (-> obj post-hook))
(delete post)
(when (eq? (-> obj status) 'dead)
@ -1755,9 +1751,6 @@
)
*kernel-context*
)
;; todo, remove this and replace it with the rest of the kernel dispatcher.
(set! *listener-function* (the (function object) #f))
)
(define-extern inspect-process-tree (function process-tree int int symbol process-tree))
@ -1806,7 +1799,7 @@
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Stack Frame Stuff (TODO)
;; Stack Frame Stuff
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; The GOAL kernel supports dynamic throw and catch.
@ -2038,7 +2031,29 @@
;; Tree Stuff
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; todo previous-brother
(defun previous-brother ((proc process-tree))
"Get the process p where (-> p brother) is proc. Unused"
(local-vars (parent (pointer process-tree))
(child (pointer process-tree))
)
;; look up the tree to find our parent
(set! parent (-> proc parent))
(the-as process-tree
(when parent
;; make sure we aren't the only child.
(set! child (-> parent 0 child))
(if (= child proc) (return '#f))
;; iterate, until we find the one.
(while child
(if (= (-> child 0 brother) proc) (return child))
(set! child (-> child 0 brother))
)
;; nope, didn't find it. bad tree.
'#f
)
)
)
(defun change-parent ((obj process-tree) (new-parent process-tree))
"Make obj a child of new-parent"
@ -2071,8 +2086,112 @@
)
)
;; todo change-brother
;; todo change-to-last-brother
(defun change-brother ((arg0 process-tree) (arg1 process-tree))
"Unused, and wrong.
It seems like this was written when processes store process-trees, not (pointer process-tree)."
(local-vars
(v1-4 (pointer process-tree))
(a1-1 symbol)
(a2-1 (pointer process-tree))
(a3-1 (pointer process-tree))
(t0-0 (pointer process-tree))
(t1-0 (pointer process-tree))
(t1-3 (pointer process-tree))
(t1-4 (pointer process-tree))
(t1-7 (pointer process-tree))
(t1-8 (pointer process-tree))
(t1-12 (pointer process-tree))
(t1-13 (pointer process-tree))
(t1-17 (pointer process-tree))
)
(when (and arg0 (!= (-> arg0 brother) arg1) (!= arg0 arg1))
(set! a2-1 (-> arg0 parent))
(when a2-1
(set! t0-0 (-> a2-1 0 child))
(set! a3-1 '#f)
(set! v1-4 '#f)
(set! t1-0 t0-0)
(when (= (if t1-0 (-> t1-0 0 self)) arg0)
(set! a3-1 a2-1)
(set! t1-3 a3-1)
)
(set! t1-4 t0-0)
(when (= (if t1-4 (-> t1-4 0 self)) arg1)
(set! v1-4 a2-1)
(set! t1-7 v1-4)
)
(while (and (-> t0-0 0 brother) (or (not a3-1) (not v1-4)))
(set! t1-8 t0-0)
(when (= (-> (if t1-8 (-> t1-8 0 self)) brother) arg1)
(set! v1-4 t0-0)
(set! t1-12 v1-4)
)
(set! t1-13 t0-0)
(when (= (-> (if t1-13 (-> t1-13 0 self)) brother) arg0)
(set! a3-1 t0-0)
(set! t1-17 a3-1)
)
(set! t0-0 (-> t0-0 0 brother))
)
(if (or (not a3-1) (not v1-4))
(return 0)
(if (= a3-1 a2-1)
(set! (-> a3-1 4) (the process-tree (-> arg0 brother))) ;; wrong
(set! (-> a3-1 3) (the process-tree (-> arg0 brother))) ;; wrong
)
)
(cond
((= v1-4 a2-1)
(set! (-> arg0 brother) (the (pointer process-tree) (-> v1-4 4))) ;; wrong
(set! (-> v1-4 4) (the process-tree (-> arg0 ppointer))) ;; wrong
)
(else
(set! (-> arg0 brother) (the (pointer process-tree) (-> v1-4 3)))
(set! (-> v1-4 3) (the process-tree (-> arg0 ppointer)))
)
)
)
)
(the-as process-tree arg0)
)
(defun change-to-last-brother ((arg0 process-tree))
(local-vars
(v1-4 (pointer process-tree))
(v1-8 symbol)
(a1-0 (pointer process-tree))
(a1-5 symbol)
(a1-9 symbol)
)
(when (and (-> arg0 brother) (-> arg0 parent))
(set! a1-0 (-> arg0 parent))
(set! v1-4 (-> a1-0 0 child))
(cond
((= (-> v1-4 0) arg0)
(set! (-> a1-0 0 child) (-> arg0 brother)))
(else
(while (!= (-> v1-4 0 brother 0) arg0)
(nop!)
(nop!)
(nop!)
(nop!)
(set! v1-4 (-> v1-4 0 brother))
)
(set! (-> v1-4 0 brother) (-> arg0 brother))
)
)
(while (-> v1-4 0 brother)
(nop!)
(nop!)
(nop!)
(nop!)
(set! v1-4 (-> v1-4 0 brother))
)
(set! (-> v1-4 0 brother) (-> arg0 ppointer))
(set! (-> arg0 brother) '#f)
)
arg0
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -2106,8 +2225,7 @@
(set! (-> obj connection-list next1) #f)
(set! (-> obj connection-list prev1) #f)
;; todo global -> process
(let ((thread (new 'global 'cpu-thread obj 'code PROCESS_STACK_SAVE_SIZE stack-top)))
(let ((thread (new 'process 'cpu-thread obj 'code PROCESS_STACK_SAVE_SIZE stack-top)))
(set! (-> obj main-thread) thread)
)
@ -2244,12 +2362,10 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmethod deactivate process-tree ((obj process-tree))
;; todo
(format 0 "CALL TO DEACTIVATE~%")
(none)
)
;; todo defstate
;; The defstate macro isn't defined yet, so we do it manually.
(define dead-state
(new 'static 'state
:name #f
@ -2264,8 +2380,10 @@
(set! (-> dead-state code) nothing)
;; hack
;; this is not yet defined.
(define-extern entity-deactivate-handler (function process object none))
(define entity-deactivate-handler (the (function process object none) nothing))
(define-extern process-disconnect (function object none))
(defmethod deactivate process ((obj process))
@ -2372,8 +2490,7 @@
(let ((obj (define *listener-process* (new 'global 'process 'listener 2048))))
(set! (-> obj status) 'ready)
(set! (-> obj pid) 1)
;; allocation symbol is actually process, but it's ignored so this is ok for now.
(set! (-> obj main-thread) (new 'global 'cpu-thread obj 'main 256 *kernel-dram-stack*))
(set! (-> obj main-thread) (new 'process 'cpu-thread obj 'main 256 *kernel-dram-stack*))
)
;; these are unknown
@ -2418,26 +2535,3 @@
(change-parent (define *default-pool* (new 'global 'process-tree 'default-pool)) *active-pool*)
(set! (-> *default-pool* mask) (process-mask pause menu progress process-tree))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Temp Hacks
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; (defun kernel-dispatcher ()
; "Kernel Dispatcher Function. This gets called from the main loop in kboot.cpp's KernelCheckAndDispatch"
; ;; check if we have a new listener function to run
; (when *listener-function*
; ;; we do! enable method-set for debug purposes
; (+! *enable-method-set* 1)
; ;; execute and print result
; (let ((result (*listener-function*)))
; (format #t "~D~%" result)
; )
; (+! *enable-method-set* -1)
; ;; clear the pending function.
; (set! *listener-function* (the (function object) #f))
; )
; )

View file

@ -876,7 +876,7 @@ Val* Compiler::compile_new(const goos::Object& form, const goos::Object& _rest,
auto type = pair_car(*rest);
rest = &pair_cdr(*rest);
if (allocation == "global" || allocation == "debug") {
if (allocation == "global" || allocation == "debug" || allocation == "process") {
// allocate on a named heap
return compile_heap_new(form, allocation, type, rest, env);
} else if (allocation == "static") {

View file

@ -640,10 +640,8 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
" )\n"
" )\n"
" (else\n"
// todo - why doesn't this merge?
" (set! v1-40 (or (= v1-1 (quote uint128)) (= v1-1 (quote int128))))\n"
" (cond\n"
" (v1-40\n"
" ((or (= v1-1 (quote uint128)) (= v1-1 (quote int128)))\n"
" (set! s5-8 0)\n"
" (while\n"
" (< s5-8 (-> arg0 length))\n"
@ -1309,9 +1307,8 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
" )\n"
" )\n"
" (else\n"
" (set! v1-40 (or (= v1-1 (quote int128)) (= v1-1 (quote uint128))))\n"
" (cond\n"
" (v1-40\n"
" ((or (= v1-1 (quote int128)) (= v1-1 (quote uint128)))\n"
" (set! s5-8 0)\n"
" (while\n"
" (< s5-8 (-> arg0 length))\n"
@ -2092,16 +2089,11 @@ TEST_F(FormRegressionTest, ExprValid) {
" (quote #f)\n"
" )\n"
" (else\n"
// todo - why isn't this compacted?
" (set!\n"
" v1-33\n"
" (and\n"
" (!= arg1 type)\n"
" (not (valid? (rtype-of arg0) type (quote #f) (quote #t) 0))\n"
" )\n"
" )\n"
" (cond\n"
" (v1-33\n"
" ((and\t\n"
" (!= arg1 type)\t\n"
" (not (valid? (rtype-of arg0) type (quote #f) (quote #t) 0))\t\n"
" )\n"
" (if\n"
" arg2\n"
" (format\n"
@ -2483,7 +2475,6 @@ TEST_F(FormRegressionTest, ExprStringToInt) {
" (a0-5 symbol)\n"
" (a1-8 (pointer uint8))\n"
" (a1-14 uint)\n"
" (a1-16 symbol)\n"
" (a1-20 uint)\n"
" (a1-23 uint)\n"
" (a1-33 symbol)\n"
@ -2529,15 +2520,11 @@ TEST_F(FormRegressionTest, ExprStringToInt) {
" (set! a1-14 v0-0)\n"
" )\n"
" (else\n"
" (set!\n"
" a1-16\n"
" (and\n"
" (>= (-> a0-3 0) (the-as uint 97))\n"
" (>= (the-as uint 102) (-> a0-3 0))\n"
" )\n"
" )\n"
" (cond\n"
" (a1-16\n"
" ((and\t\n"
" (>= (-> a0-3 0) (the-as uint 97))\t\n"
" (>= (the-as uint 102) (-> a0-3 0))\t\n"
" )\n"
" (set! v0-0 (+ (+ (-> a0-3 0) -87) (the-as uint (shl v0-0 4))))\n"
" (set! a1-20 v0-0)\n"
" )\n"

View file

@ -534,8 +534,7 @@ TEST_F(FormRegressionTest, RemoveMethod3ProcessTree) {
" (set! a0-5 (quote #t))\n"
" (set! a1-4 \"~Tbrother: ~A~%\")\n"
" (set! v1-2 (-> arg0 brother))\n"
" (set! a2-4 (if v1-2 (-> v1-2 0 self)))\n"
" (t9-4 a0-5 a1-4 a2-4)\n"
" (t9-4 a0-5 a1-4 (if v1-2 (-> v1-2 0 self)))\n"
" (set! t9-5 format)\n"
" (set! a0-6 (quote #t))\n"
" (set! a1-5 \"~Tchild: ~A~%\")\n"
@ -2533,7 +2532,8 @@ TEST_F(FormRegressionTest, ExprMethod16DeadPoolHeap) {
std::string expected =
"(begin\n"
" (set! s4-0 (memory-free arg0))\n"
" (set! f0-2 (/ (the float s4-0) (the float (memory-total arg0))))\n"
" (set! v1-2 (memory-total arg0))\n"
" (set! f0-2 (/ (the float s4-0) (the float v1-2)))"
" (cond\n"
" ((< f0-2 (l.f L346))\n"
" (set! arg1 1000)\n"