[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; goos::Object to_form(const std::vector<DecompilerLabel>& labels, const Env& env) const;
bool operator==(const SimpleExpression& other) const; bool operator==(const SimpleExpression& other) const;
bool is_identity() const { return m_kind == Kind::IDENTITY; } 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; 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(const TypeState& input, const Env& env, const DecompilerTypeSystem& dts) const;
TP_Type get_type_int2(const TypeState& input, 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 { FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const {
if (env.has_type_analysis()) { if (env.has_type_analysis()) {
if (m_addr.is_identity() && m_addr.get_arg(0).is_sym_val()) { 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(), return pool.alloc_element<StoreInSymbolElement>(m_addr.get_arg(0).get_str(),
m_my_idx); 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);
} }
IR2_RegOffset ro; 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("object") ||
input_type.typespec() == TypeSpec("pair"))) { input_type.typespec() == TypeSpec("pair"))) {
if (ro.offset == 2) { if (ro.offset == 2) {
auto base = pool.alloc_single_element_form<SimpleExpressionElement>( return pool.alloc_element<StoreInPairElement>(false, ro.var, m_value.as_expr(), m_my_idx);
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;
} else if (ro.offset == -2) { } else if (ro.offset == -2) {
auto base = pool.alloc_single_element_form<SimpleExpressionElement>( return pool.alloc_element<StoreInPairElement>(true, ro.var, m_value.as_expr(), m_my_idx);
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);
} }
} }
@ -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 // we pass along the register offset because code generation seems to be a bit
// different in different cases. // different in different cases.
auto source = pool.alloc_single_element_form<ArrayFieldAccess>( auto source = pool.alloc_element<ArrayFieldAccess>(
nullptr, ro.var, tokens, input_type.get_multiplier(), ro.offset); ro.var, tokens, input_type.get_multiplier(), ro.offset);
auto val = pool.alloc_single_element_form<SimpleExpressionElement>( // auto val = pool.alloc_single_element_form<SimpleExpressionElement>(
nullptr, m_value.as_expr(), m_my_idx); // nullptr, m_value.as_expr(), m_my_idx);
assert(!rd.addr_of); 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); auto rd = env.dts->ts.reverse_field_lookup(rd_in);
if (rd.success) { 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>( auto source = pool.alloc_single_element_form<SimpleExpressionElement>(
nullptr, SimpleAtom::make_var(ro.var).as_expr(), m_my_idx); nullptr, SimpleAtom::make_var(ro.var).as_expr(), m_my_idx);
std::vector<DerefToken> tokens; 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)); tokens.push_back(to_token(x));
} }
assert(!rd.addr_of); assert(!rd.addr_of);
auto addr = auto addr = pool.alloc_element<DerefElement>(source, rd.addr_of, tokens);
pool.alloc_single_element_form<DerefElement>(nullptr, source, rd.addr_of, tokens); return pool.alloc_element<StorePlainDeref>(addr, m_value.as_expr(), m_my_idx, ro.var,
return pool.alloc_element<SetFormFormElement>(addr, val); std::nullopt);
} }
std::string cast_type;
if (input_type.typespec() == TypeSpec("pointer") && ro.offset == 0) { if (input_type.typespec() == TypeSpec("pointer") && ro.offset == 0) {
std::string cast_type;
switch (m_size) { switch (m_size) {
case 1: case 1:
cast_type = "int8"; 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); nullptr, SimpleAtom::make_var(ro.var).as_expr(), m_my_idx);
auto cast_source = pool.alloc_single_element_form<CastElement>( auto cast_source = pool.alloc_single_element_form<CastElement>(
nullptr, TypeSpec("pointer", {TypeSpec(cast_type)}), source); nullptr, TypeSpec("pointer", {TypeSpec(cast_type)}), source);
auto deref = pool.alloc_single_element_form<DerefElement>(nullptr, cast_source, false, auto deref =
std::vector<DerefToken>()); pool.alloc_element<DerefElement>(cast_source, false, std::vector<DerefToken>());
auto val = pool.alloc_single_element_form<SimpleExpressionElement>( return pool.alloc_element<StorePlainDeref>(deref, m_value.as_expr(), m_my_idx, ro.var,
nullptr, m_value.as_expr(), m_my_idx); TypeSpec("pointer", {TypeSpec(cast_type)}));
return pool.alloc_element<SetFormFormElement>(deref, val);
} }
} }
} }

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 // SetFormFormElement
///////////////////////////// /////////////////////////////
@ -335,6 +379,7 @@ goos::Object SetFormFormElement::to_form_internal(const Env& env) const {
} }
void SetFormFormElement::apply(const std::function<void(FormElement*)>& f) { void SetFormFormElement::apply(const std::function<void(FormElement*)>& f) {
f(this);
m_src->apply(f); m_src->apply(f);
m_dst->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::collect_vars(VariableSet&) const {}
void ConstantTokenElement::get_modified_regs(RegSet&) 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 } // namespace decompiler

View file

@ -43,9 +43,16 @@ class FormElement {
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result, std::vector<FormElement*>* result,
bool allow_side_effects); bool allow_side_effects);
bool is_popped() const { return m_popped; }
void mark_popped() {
assert(!m_popped);
m_popped = true;
}
protected: protected:
friend class Form; 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; void apply_form(const std::function<void(Form*)>& f) override;
bool is_sequence_point() const override; bool is_sequence_point() const override;
void collect_vars(VariableSet& vars) 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, void update_from_stack(const Env& env,
FormPool& pool, FormPool& pool,
FormStack& stack, FormStack& stack,
@ -219,13 +224,11 @@ class SimpleAtomElement : public FormElement {
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;
const SimpleAtom& atom() const { return m_atom; } 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, void update_from_stack(const Env& env,
FormPool& pool, FormPool& pool,
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result, std::vector<FormElement*>* result,
bool allow_side_effects) override; bool allow_side_effects) override;
// void push_to_stack(const Env& env, FormStack& stack) override;
private: private:
SimpleAtom m_atom; SimpleAtom m_atom;
@ -246,11 +249,6 @@ class SetVarElement : public FormElement {
bool is_sequence_point() const override; bool is_sequence_point() const override;
void collect_vars(VariableSet& vars) 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, 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; void get_modified_regs(RegSet& regs) const override;
bool active() const override; bool active() const override;
@ -276,6 +274,39 @@ class SetVarElement : public FormElement {
SetVarInfo m_var_info; 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. * Like SetVar, but sets a form to another form.
* This is intended to be used with stores. * This is intended to be used with stores.
@ -298,6 +329,7 @@ class SetFormFormElement : public FormElement {
Form* dst() { return m_dst; } Form* dst() { return m_dst; }
private: private:
int m_real_push_count = 0;
Form* m_dst = nullptr; Form* m_dst = nullptr;
Form* m_src = 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)) * 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 * 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 * 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; bool allow_side_effects) override;
void get_modified_regs(RegSet& regs) const override; void get_modified_regs(RegSet& regs) const override;
void inline_nested();
bool is_addr_of() const { return m_is_addr_of; } bool is_addr_of() const { return m_is_addr_of; }
const Form* base() const { return m_base; } const Form* base() const { return m_base; }
Form* base() { return m_base; } Form* base() { return m_base; }
const std::vector<DerefToken>& tokens() const { return m_tokens; } const std::vector<DerefToken>& tokens() const { return m_tokens; }
void set_base(Form* new_base) { m_base = new_base; }
private: private:
Form* m_base = nullptr; Form* m_base = nullptr;
@ -938,6 +974,12 @@ class ArrayFieldAccess : public FormElement {
bool allow_side_effects) override; bool allow_side_effects) override;
void get_modified_regs(RegSet& regs) const 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: private:
Variable m_source; Variable m_source;
std::vector<DerefToken> m_deref_tokens; std::vector<DerefToken> m_deref_tokens;
@ -1001,6 +1043,46 @@ class ConstantTokenElement : public FormElement {
std::string m_value; 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. * A Form is a wrapper around one or more FormElements.
* This is done for two reasons: * This is done for two reasons:
@ -1073,6 +1155,14 @@ class Form {
bool has_side_effects(); bool has_side_effects();
void get_modified_regs(RegSet& regs) const; 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; FormElement* parent_element = nullptr;
private: private:

View file

@ -233,7 +233,12 @@ void Form::update_children_from_stack(const Env& env,
for (size_t i = 0; i < m_elements.size(); i++) { for (size_t i = 0; i < m_elements.size(); i++) {
if (i == 0) { if (i == 0) {
// only bother doing the first one. // only bother doing the first one.
m_elements[i]->update_from_stack(env, pool, stack, &new_elts, allow_side_effects); 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 { } else {
new_elts.push_back(m_elements[i]); new_elts.push_back(m_elements[i]);
} }
@ -286,6 +291,7 @@ void LoadSourceElement::update_from_stack(const Env& env,
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result, std::vector<FormElement*>* result,
bool allow_side_effects) { bool allow_side_effects) {
mark_popped();
m_addr->update_children_from_stack(env, pool, stack, allow_side_effects); m_addr->update_children_from_stack(env, pool, stack, allow_side_effects);
result->push_back(this); result->push_back(this);
} }
@ -356,6 +362,8 @@ void SimpleExpressionElement::update_from_stack_fpr_to_gpr(const Env& env,
// set ourself to identity. // set ourself to identity.
m_expr = src.as_expr(); m_expr = src.as_expr();
// then go again. // then go again.
assert(m_popped);
m_popped = false;
update_from_stack(env, pool, stack, result, allow_side_effects); update_from_stack(env, pool, stack, result, allow_side_effects);
} else { } else {
throw std::runtime_error( throw std::runtime_error(
@ -756,6 +764,7 @@ void SimpleExpressionElement::update_from_stack(const Env& env,
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result, std::vector<FormElement*>* result,
bool allow_side_effects) { bool allow_side_effects) {
mark_popped();
switch (m_expr.kind()) { switch (m_expr.kind()) {
case SimpleExpression::Kind::IDENTITY: case SimpleExpression::Kind::IDENTITY:
update_from_stack_identity(env, pool, stack, result, allow_side_effects); 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) { void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
mark_popped();
for (auto x : m_src->elts()) { for (auto x : m_src->elts()) {
assert(x->parent_form == m_src); 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); m_src->update_children_from_stack(env, pool, stack, true);
for (auto x : m_src->elts()) { for (auto x : m_src->elts()) {
assert(x->parent_form == m_src); 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, void SetFormFormElement::push_to_stack(const Env&, FormPool&, FormStack& stack) {
FormPool& pool, // todo - is the order here right?
FormStack& stack, assert(m_popped);
std::vector<FormElement*>* result, assert(m_real_push_count == 0);
bool allow_side_effects) { m_real_push_count++;
m_src->update_children_from_stack(env, pool, stack, allow_side_effects); stack.push_form_element(this, true);
for (auto x : m_src->elts()) {
assert(x->parent_form == m_src);
}
result->push_back(this);
} }
void SetFormFormElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { void StoreInSymbolElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
// todo - is the order here right? auto sym = pool.alloc_single_element_form<ConstantTokenElement>(nullptr, m_sym_name);
m_dst->update_children_from_stack(env, pool, stack, false); auto val = pool.alloc_single_element_form<SimpleExpressionElement>(nullptr, m_value, m_my_idx);
m_src->update_children_from_stack(env, pool, stack, false); val->update_children_from_stack(env, pool, stack, true);
stack.push_form_element(this, 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, FormStack& stack,
std::vector<FormElement*>* result, std::vector<FormElement*>* result,
bool allow_side_effects) { bool allow_side_effects) {
mark_popped();
auto forms = pop_to_forms({value, shift_amount}, env, pool, stack, allow_side_effects, consumed); auto forms = pop_to_forms({value, shift_amount}, env, pool, stack, allow_side_effects, consumed);
auto new_form = pool.alloc_element<GenericElement>( auto new_form = pool.alloc_element<GenericElement>(
GenericOperator::make_fixed(FixedOperatorKind::ARITH_SHIFT), forms.at(0), forms.at(1)); 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, FormStack& stack,
std::vector<FormElement*>* result, std::vector<FormElement*>* result,
bool allow_side_effects) { bool allow_side_effects) {
mark_popped();
auto forms = pop_to_forms({source}, env, pool, stack, allow_side_effects, consumed); auto forms = pop_to_forms({source}, env, pool, stack, allow_side_effects, consumed);
auto new_form = pool.alloc_element<GenericElement>( auto new_form = pool.alloc_element<GenericElement>(
GenericOperator::make_fixed(FixedOperatorKind::ABS), forms.at(0)); GenericOperator::make_fixed(FixedOperatorKind::ABS), forms.at(0));
@ -984,6 +1084,7 @@ void FunctionCallElement::update_from_stack(const Env& env,
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result, std::vector<FormElement*>* result,
bool allow_side_effects) { bool allow_side_effects) {
mark_popped();
std::vector<Form*> args; std::vector<Form*> args;
auto nargs = m_op->arg_vars().size(); auto nargs = m_op->arg_vars().size();
args.resize(nargs, nullptr); args.resize(nargs, nullptr);
@ -1272,17 +1373,12 @@ void DerefElement::update_from_stack(const Env& env,
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result, std::vector<FormElement*>* result,
bool allow_side_effects) { bool allow_side_effects) {
mark_popped();
// todo - update var tokens from stack? // todo - update var tokens from stack?
m_base->update_children_from_stack(env, pool, stack, allow_side_effects); m_base->update_children_from_stack(env, pool, stack, allow_side_effects);
// merge nested ->'s // merge nested ->'s
auto as_deref = dynamic_cast<DerefElement*>(m_base->try_as_single_element()); inline_nested();
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;
}
}
if (m_tokens.size() >= 3) { if (m_tokens.size() >= 3) {
auto& method_name = m_tokens.at(m_tokens.size() - 1); 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 // UntilElement
/////////////////// ///////////////////
void UntilElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { void UntilElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
mark_popped();
for (auto form : {condition, body}) { for (auto form : {condition, body}) {
FormStack temp_stack(false); FormStack temp_stack(false);
for (auto& entry : form->elts()) { 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) { void WhileElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
mark_popped();
bool first = true; bool first = true;
for (auto form : {body, condition}) { for (auto form : {body, condition}) {
FormStack temp_stack(first && stack.is_root()); FormStack temp_stack(first && stack.is_root());
@ -1373,40 +1481,43 @@ void WhileElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stac
// CondNoElseElement // CondNoElseElement
/////////////////// ///////////////////
void CondNoElseElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { void CondNoElseElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
mark_popped();
if (already_rewritten) { if (already_rewritten) {
stack.push_form_element(this, true); stack.push_form_element(this, true);
return; return;
} }
for (auto& entry : entries) {
for (auto form : {entry.condition, entry.body}) {
FormStack temp_stack(false);
for (auto& elt : form->elts()) {
elt->push_to_stack(env, pool, temp_stack);
}
std::vector<FormElement*> new_entries; // the first condition is special
if (form == entry.body && used_as_value) { auto first_condition = entries.front().condition;
new_entries = rewrite_to_get_var(temp_stack, pool, final_destination); // lets evaluate in on the parent stack...
} else { for (auto x : first_condition->elts()) {
new_entries = temp_stack.rewrite(pool); x->push_to_stack(env, pool, stack);
}
form->clear();
for (auto e : new_entries) {
form->push_back(e);
}
}
} }
// raise expression. for (auto& entry : entries) {
auto top_condition = entries.front().condition; for (auto form : {entry.condition, entry.body}) {
if (!top_condition->is_single_element()) { if (form == first_condition) {
auto real_condition = top_condition->back(); form->clear();
top_condition->pop_back(); form->push_back(stack.pop_back(pool));
for (auto x : top_condition->elts()) { } else {
x->push_to_stack(env, pool, stack); FormStack temp_stack(false);
for (auto& elt : form->elts()) {
elt->push_to_stack(env, pool, temp_stack);
}
std::vector<FormElement*> new_entries;
if (form == entry.body && used_as_value) {
new_entries = rewrite_to_get_var(temp_stack, pool, final_destination);
} else {
new_entries = temp_stack.rewrite(pool);
}
form->clear();
for (auto e : new_entries) {
form->push_back(e);
}
}
} }
top_condition->elts() = {real_condition};
} }
if (used_as_value) { 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) { void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
mark_popped();
if (already_rewritten) { if (already_rewritten) {
stack.push_form_element(this, true); stack.push_form_element(this, true);
return; return;
@ -1426,20 +1538,32 @@ void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStac
std::optional<Variable> last_var; std::optional<Variable> last_var;
bool rewrite_as_set = true; 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 // process conditions and bodies
for (auto& entry : entries) { for (auto& entry : entries) {
for (auto form : {entry.condition, entry.body}) { for (auto form : {entry.condition, entry.body}) {
FormStack temp_stack(false); if (form == first_condition) {
for (auto& elt : form->elts()) { form->clear();
elt->push_to_stack(env, pool, temp_stack); 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);
}
std::vector<FormElement*> new_entries; std::vector<FormElement*> new_entries;
new_entries = temp_stack.rewrite(pool); new_entries = temp_stack.rewrite(pool);
form->clear(); form->clear();
for (auto e : new_entries) { for (auto e : new_entries) {
form->push_back(e); form->push_back(e);
}
} }
} }
} }
@ -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); 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 (rewrite_as_set) {
if (set_unused) { if (set_unused) {
stack.push_form_element(this, true); 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) { void ShortCircuitElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
mark_popped();
if (!used_as_value.value_or(false)) { if (!used_as_value.value_or(false)) {
throw std::runtime_error( throw std::runtime_error(
"ShortCircuitElement::push_to_stack not implemented for result not used case."); "ShortCircuitElement::push_to_stack not implemented for result not used case.");
@ -1538,34 +1652,37 @@ void ShortCircuitElement::push_to_stack(const Env& env, FormPool& pool, FormStac
stack.push_form_element(this, true); stack.push_form_element(this, true);
return; return;
} }
for (int i = 0; i < int(entries.size()); i++) {
auto& entry = entries.at(i);
FormStack temp_stack(false);
for (auto& elt : entry.condition->elts()) {
elt->push_to_stack(env, pool, temp_stack);
}
std::vector<FormElement*> new_entries; // the first condition is special
if (i == int(entries.size()) - 1) { auto first_condition = entries.front().condition;
new_entries = rewrite_to_get_var(temp_stack, pool, final_result); // lets evaluate in on the parent stack...
} else { for (auto x : first_condition->elts()) {
new_entries = temp_stack.rewrite(pool); x->push_to_stack(env, pool, stack);
}
entry.condition->clear();
for (auto e : new_entries) {
entry.condition->push_back(e);
}
} }
auto top_condition = entries.front().condition; for (int i = 0; i < int(entries.size()); i++) {
if (!top_condition->is_single_element()) { auto& entry = entries.at(i);
auto real_condition = top_condition->back(); if (entry.condition == first_condition) {
top_condition->pop_back(); entry.condition->clear();
for (auto x : top_condition->elts()) { entry.condition->push_back(stack.pop_back(pool));
x->push_to_stack(env, pool, stack); } else {
FormStack temp_stack(false);
for (auto& elt : entry.condition->elts()) {
elt->push_to_stack(env, pool, temp_stack);
}
std::vector<FormElement*> new_entries;
if (i == int(entries.size()) - 1) {
new_entries = rewrite_to_get_var(temp_stack, pool, final_result);
} else {
new_entries = temp_stack.rewrite(pool);
}
entry.condition->clear();
for (auto e : new_entries) {
entry.condition->push_back(e);
}
} }
top_condition->elts() = {real_condition};
} }
assert(used_as_value.has_value()); assert(used_as_value.has_value());
@ -1579,6 +1696,7 @@ void ShortCircuitElement::update_from_stack(const Env& env,
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result, std::vector<FormElement*>* result,
bool) { bool) {
mark_popped();
(void)stack; (void)stack;
if (already_rewritten) { if (already_rewritten) {
result->push_back(this); 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) { void ConditionElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
mark_popped();
std::vector<Form*> source_forms, popped_forms; std::vector<Form*> source_forms, popped_forms;
std::vector<TypeSpec> source_types; std::vector<TypeSpec> source_types;
std::vector<Variable> vars; std::vector<Variable> vars;
@ -1766,6 +1885,7 @@ void ConditionElement::update_from_stack(const Env& env,
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result, std::vector<FormElement*>* result,
bool allow_side_effects) { bool allow_side_effects) {
mark_popped();
std::vector<Form*> source_forms, popped_forms; std::vector<Form*> source_forms, popped_forms;
std::vector<TypeSpec> source_types; std::vector<TypeSpec> source_types;
std::vector<Variable> vars; 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) { void ReturnElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
mark_popped();
FormStack temp_stack(false); FormStack temp_stack(false);
for (auto& elt : return_code->elts()) { for (auto& elt : return_code->elts()) {
elt->push_to_stack(env, pool, temp_stack); 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) { void AtomicOpElement::push_to_stack(const Env& env, FormPool&, FormStack& stack) {
mark_popped();
auto as_end = dynamic_cast<const FunctionEndOp*>(m_op); auto as_end = dynamic_cast<const FunctionEndOp*>(m_op);
if (as_end) { if (as_end) {
// we don't want to push this to the stack (for now at least) // 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) { void AsmOpElement::push_to_stack(const Env&, FormPool&, FormStack& stack) {
mark_popped();
stack.push_form_element(this, true); stack.push_form_element(this, true);
} }
@ -1859,11 +1982,11 @@ void GenericElement::update_from_stack(const Env& env,
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result, std::vector<FormElement*>* result,
bool) { bool) {
// TODO improve. mark_popped();
if (m_head.m_kind == GenericOperator::Kind::FUNCTION_EXPR) { if (m_elts.size() == 1) {
m_head.m_function->update_children_from_stack(env, pool, stack, false); // a bit of a hack, but AtomicOpForm uses this for loading car/cdr
} else { // this is safe to do.
m_elts.back()->update_children_from_stack(env, pool, stack, false); m_elts.front()->update_children_from_stack(env, pool, stack, true);
} }
result->push_back(this); 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 GenericElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
(void)env; (void)env;
(void)pool; (void)pool;
mark_popped();
stack.push_form_element(this, true); stack.push_form_element(this, true);
} }
@ -1883,6 +2007,7 @@ void DynamicMethodAccess::update_from_stack(const Env& env,
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result, std::vector<FormElement*>* result,
bool allow_side_effects) { bool allow_side_effects) {
mark_popped();
auto new_val = stack.pop_reg(m_source, {}, env, allow_side_effects); auto new_val = stack.pop_reg(m_source, {}, env, allow_side_effects);
auto reg0_matcher = auto reg0_matcher =
Matcher::match_or({Matcher::any_reg(0), Matcher::cast("uint", Matcher::any_reg(0))}); 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 } // namespace
void ArrayFieldAccess::update_from_stack(const Env& env, void ArrayFieldAccess::update_with_val(Form* new_val,
FormPool& pool, const Env& env,
FormStack& stack, FormPool& pool,
std::vector<FormElement*>* result, std::vector<FormElement*>* result,
bool allow_side_effects) { bool) {
auto new_val = stack.pop_reg(m_source, {}, env, allow_side_effects);
int power_of_two = 0; int power_of_two = 0;
if (m_constant_offset == 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 // CastElement
//////////////////////// ////////////////////////
@ -2086,6 +2220,7 @@ void CastElement::update_from_stack(const Env& env,
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result, std::vector<FormElement*>* result,
bool allow_side_effects) { bool allow_side_effects) {
mark_popped();
m_source->update_children_from_stack(env, pool, stack, allow_side_effects); m_source->update_children_from_stack(env, pool, stack, allow_side_effects);
result->push_back(this); result->push_back(this);
} }
@ -2099,6 +2234,7 @@ void TypeOfElement::update_from_stack(const Env& env,
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result, std::vector<FormElement*>* result,
bool allow_side_effects) { bool allow_side_effects) {
mark_popped();
value->update_children_from_stack(env, pool, stack, allow_side_effects); value->update_children_from_stack(env, pool, stack, allow_side_effects);
result->push_back(this); 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) { void EmptyElement::push_to_stack(const Env&, FormPool&, FormStack& stack) {
mark_popped();
stack.push_form_element(this, true); 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) { void ConditionalMoveFalseElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
mark_popped();
// pop the value and the original // pop the value and the original
auto popped = pop_to_forms({old_value, source}, env, pool, stack, true); auto popped = pop_to_forms({old_value, source}, env, pool, stack, true);
if (!is_symbol_true(popped.at(0))) { if (!is_symbol_true(popped.at(0))) {
@ -2136,27 +2274,21 @@ void ConditionalMoveFalseElement::push_to_stack(const Env& env, FormPool& pool,
true); true);
} }
void SimpleAtomElement::push_to_stack(const Env&, FormPool&, FormStack& stack) {
stack.push_form_element(this, true);
}
void SimpleAtomElement::update_from_stack(const Env&, void SimpleAtomElement::update_from_stack(const Env&,
FormPool&, FormPool&,
FormStack&, FormStack&,
std::vector<FormElement*>* result, std::vector<FormElement*>* result,
bool) { bool) {
mark_popped();
result->push_back(this); 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&, void StringConstantElement::update_from_stack(const Env&,
FormPool&, FormPool&,
FormStack&, FormStack&,
std::vector<FormElement*>* result, std::vector<FormElement*>* result,
bool) { bool) {
mark_popped();
result->push_back(this); result->push_back(this);
} }
@ -2165,6 +2297,7 @@ void GetMethodElement::update_from_stack(const Env&,
FormStack&, FormStack&,
std::vector<FormElement*>* result, std::vector<FormElement*>* result,
bool) { bool) {
mark_popped();
result->push_back(this); result->push_back(this);
} }
@ -2173,6 +2306,7 @@ void CondNoElseElement::update_from_stack(const Env&,
FormStack&, FormStack&,
std::vector<FormElement*>* result, std::vector<FormElement*>* result,
bool) { bool) {
mark_popped();
result->push_back(this); result->push_back(this);
} }
@ -2181,6 +2315,7 @@ void ConstantTokenElement::update_from_stack(const Env&,
FormStack&, FormStack&,
std::vector<FormElement*>* result, std::vector<FormElement*>* result,
bool) { bool) {
mark_popped();
result->push_back(this); result->push_back(this);
} }

View file

@ -191,6 +191,21 @@ Form* FormStack::unsafe_peek(Register reg, const Env& env) {
return nullptr; 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*> FormStack::rewrite(FormPool& pool) {
std::vector<FormElement*> result; std::vector<FormElement*> result;

View file

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

View file

@ -340,6 +340,11 @@
"(method 0 state)":{ "(method 0 state)":{
"args":["allocation", "type-to-make", "name", "code", "trans", "enter", "exit", "event"], "args":["allocation", "type-to-make", "name", "code", "trans", "enter", "exit", "event"],
"vars":{"v0-0":"obj"} "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 - The types `cpu-thread` and `catch-frame` have a slightly different layout in OpenGOAL to back up x86-64 registers
## `gkernel`: ## `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** ## `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. - 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)
)
)

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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