[Decompilation] Fixes to compiler/decompiler for gcommon (#227)

* fix shift naming issue

* fix bad argument variable names

* fix missing variable issue

* small missing things

* wip

* cleanup

* wip

* fix conditions

* small bug fix in rewriter

* fix incredibly stupid printing bug
This commit is contained in:
water111 2021-02-05 19:41:09 -05:00 committed by GitHub
parent 65206823ef
commit ddffda1e8c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 1000 additions and 379 deletions

View file

@ -70,7 +70,7 @@ bool create_dir_if_needed(const std::string& path) {
return false; return false;
} }
void write_binary_file(const std::string& name, void* data, size_t size) { void write_binary_file(const std::string& name, const void* data, size_t size) {
FILE* fp = fopen(name.c_str(), "wb"); FILE* fp = fopen(name.c_str(), "wb");
if (!fp) { if (!fp) {
throw std::runtime_error("couldn't open file " + name); throw std::runtime_error("couldn't open file " + name);

View file

@ -12,7 +12,7 @@ namespace file_util {
std::string get_project_path(); std::string get_project_path();
std::string get_file_path(const std::vector<std::string>& input); std::string get_file_path(const std::vector<std::string>& input);
bool create_dir_if_needed(const std::string& path); bool create_dir_if_needed(const std::string& path);
void write_binary_file(const std::string& name, void* data, size_t size); void write_binary_file(const std::string& name, const void* data, size_t size);
void write_rgba_png(const std::string& name, void* data, int w, int h); void write_rgba_png(const std::string& name, void* data, int w, int h);
void write_text_file(const std::string& file_name, const std::string& text); void write_text_file(const std::string& file_name, const std::string& text);
std::vector<uint8_t> read_binary_file(const std::string& filename); std::vector<uint8_t> read_binary_file(const std::string& filename);

View file

@ -13,7 +13,7 @@
namespace versions { namespace versions {
// language version (OpenGOAL) // language version (OpenGOAL)
constexpr s32 GOAL_VERSION_MAJOR = 0; constexpr s32 GOAL_VERSION_MAJOR = 0;
constexpr s32 GOAL_VERSION_MINOR = 5; constexpr s32 GOAL_VERSION_MINOR = 6;
// these versions are from the game // these versions are from the game
constexpr u32 ART_FILE_VERSION = 6; constexpr u32 ART_FILE_VERSION = 6;

View file

@ -355,10 +355,13 @@ class IR2_Condition {
const SimpleAtom& src(int i) const { return m_src[i]; } const SimpleAtom& src(int i) const { return m_src[i]; }
ConditionElement* get_as_form(FormPool& pool, const Env& env, int my_idx) const; ConditionElement* get_as_form(FormPool& pool, const Env& env, int my_idx) const;
void collect_vars(VariableSet& vars) const; void collect_vars(VariableSet& vars) const;
void make_flipped() { m_flipped_eval = true; }
bool flipped() const { return m_flipped_eval; }
private: private:
Kind m_kind = Kind::INVALID; Kind m_kind = Kind::INVALID;
SimpleAtom m_src[2]; SimpleAtom m_src[2];
bool m_flipped_eval = false;
}; };
std::string get_condition_kind_name(IR2_Condition::Kind kind); std::string get_condition_kind_name(IR2_Condition::Kind kind);

View file

@ -45,7 +45,7 @@ ConditionElement* IR2_Condition::get_as_form(FormPool& pool, const Env& env, int
for (int i = 0; i < get_condition_num_args(m_kind); i++) { for (int i = 0; i < get_condition_num_args(m_kind); i++) {
vars[i] = m_src[i]; vars[i] = m_src[i];
} }
return pool.alloc_element<ConditionElement>(m_kind, vars[0], vars[1], consumed); return pool.alloc_element<ConditionElement>(m_kind, vars[0], vars[1], consumed, m_flipped_eval);
} }
FormElement* SetVarOp::get_as_form(FormPool& pool, const Env& env) const { FormElement* SetVarOp::get_as_form(FormPool& pool, const Env& env) const {
@ -90,6 +90,13 @@ 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()) {
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);
}
IR2_RegOffset ro; IR2_RegOffset ro;
if (get_as_reg_offset(m_addr, &ro)) { if (get_as_reg_offset(m_addr, &ro)) {
auto& input_type = env.get_types_before_op(m_my_idx).get(ro.reg); auto& input_type = env.get_types_before_op(m_my_idx).get(ro.reg);
@ -238,8 +245,10 @@ FormElement* LoadVarOp::get_as_form(FormPool& pool, const Env& env) const {
} }
assert(rd.tokens.back().kind == FieldReverseLookupOutput::Token::Kind::VAR_IDX); assert(rd.tokens.back().kind == FieldReverseLookupOutput::Token::Kind::VAR_IDX);
auto load = pool.alloc_single_element_form<ArrayFieldAccess>(nullptr, ro.var, tokens, // we pass along the register offset because code generation seems to be a bit
input_type.get_multiplier()); // different in different cases.
auto load = pool.alloc_single_element_form<ArrayFieldAccess>(
nullptr, ro.var, tokens, input_type.get_multiplier(), ro.offset);
return pool.alloc_element<SetVarElement>(m_dst, load, true); return pool.alloc_element<SetVarElement>(m_dst, load, true);
} }
} }

View file

@ -57,67 +57,6 @@ std::string Env::print_local_var_types(const Form* top_level_form) const {
entries.push_back(fmt::format("{}: {}", x.name(), x.type.typespec().print())); entries.push_back(fmt::format("{}: {}", x.name(), x.type.typespec().print()));
} }
if (top_level_form) {
VariableSet var_set;
top_level_form->collect_vars(var_set);
// we want to sort them for easier reading:
std::vector<std::pair<RegId, Variable>> vars;
for (auto& x : var_set) {
vars.push_back(std::make_pair(get_ssa_var(x), x));
}
std::sort(vars.begin(), vars.end(),
[](const std::pair<RegId, Variable>& a, const std::pair<RegId, Variable>& b) {
return a.first < b.first;
});
RegId* prev = nullptr;
for (auto& x : vars) {
// sorted by ssa var and there are likely duplicates of Variables and SSA vars, only print
// unique ssa variables.
if (prev && x.first == *prev) {
continue;
}
prev = &x.first;
auto& map = x.second.mode() == VariableMode::WRITE ? m_var_names.write_vars.at(x.second.reg())
: m_var_names.read_vars.at(x.second.reg());
auto& info = map.at(x.first.id);
if (info.initialized) {
entries.push_back(fmt::format("{}: {}", info.name(), info.type.typespec().print()));
} else {
assert(false);
}
}
} else {
std::unordered_map<Register, std::unordered_set<int>, Register::hash> printed;
for (auto& reg_info : m_var_names.read_vars) {
auto& reg_printed = printed[reg_info.first];
for (int var_id = 0; var_id < int(reg_info.second.size()); var_id++) {
auto& info = reg_info.second.at(var_id);
if (info.initialized) {
reg_printed.insert(var_id);
entries.push_back(fmt::format("{}: {}", info.name(), info.type.typespec().print()));
}
}
}
for (auto& reg_info : m_var_names.write_vars) {
auto& reg_printed = printed[reg_info.first];
for (int var_id = 0; var_id < int(reg_info.second.size()); var_id++) {
auto& info = reg_info.second.at(var_id);
if (info.initialized) {
if (reg_printed.find(var_id) == reg_printed.end()) {
entries.push_back(fmt::format("{}: {}", info.name(), info.type.typespec().print()));
}
}
}
}
}
int max_len = 0; int max_len = 0;
for (auto& entry : entries) { for (auto& entry : entries) {
if (int(entry.length()) > max_len) { if (int(entry.length()) > max_len) {
@ -228,7 +167,7 @@ goos::Object Env::local_var_type_list(const Form* top_level_form,
int count = 0; int count = 0;
for (auto& x : vars) { for (auto& x : vars) {
if (x.reg_id.reg.get_kind() == Reg::GPR && x.reg_id.reg.get_gpr() < Reg::A0 + nargs_to_ignore && if (x.reg_id.reg.get_kind() == Reg::GPR && x.reg_id.reg.get_gpr() < Reg::A0 + nargs_to_ignore &&
x.reg_id.reg.get_gpr() >= Reg::A0) { x.reg_id.reg.get_gpr() >= Reg::A0 && x.reg_id.id == 0) {
continue; continue;
} }
count++; count++;

View file

@ -356,8 +356,9 @@ void AtomicOpElement::get_modified_regs(RegSet& regs) const {
ConditionElement::ConditionElement(IR2_Condition::Kind kind, ConditionElement::ConditionElement(IR2_Condition::Kind kind,
std::optional<SimpleAtom> src0, std::optional<SimpleAtom> src0,
std::optional<SimpleAtom> src1, std::optional<SimpleAtom> src1,
RegSet consumed) RegSet consumed,
: m_kind(kind), m_consumed(std::move(consumed)) { bool flipped)
: m_kind(kind), m_consumed(std::move(consumed)), m_flipped(flipped) {
m_src[0] = src0; m_src[0] = src0;
m_src[1] = src1; m_src[1] = src1;
} }
@ -768,7 +769,7 @@ goos::Object CondNoElseElement::to_form(const Env& env) const {
for (auto& e : entries) { for (auto& e : entries) {
std::vector<goos::Object> entry; std::vector<goos::Object> entry;
entry.push_back(e.condition->to_form_as_condition(env)); entry.push_back(e.condition->to_form_as_condition(env));
entries.front().body->inline_forms(list, env); e.body->inline_forms(entry, env);
list.push_back(pretty_print::build_list(entry)); list.push_back(pretty_print::build_list(entry));
} }
return pretty_print::build_list(list); return pretty_print::build_list(list);
@ -1067,10 +1068,12 @@ std::string fixed_operator_to_string(FixedOperatorKind kind) {
return "lognor"; return "lognor";
case FixedOperatorKind::LOGNOT: case FixedOperatorKind::LOGNOT:
return "lognot"; return "lognot";
case FixedOperatorKind::SLL: case FixedOperatorKind::SHL:
return "sll"; return "shl";
case FixedOperatorKind::SRL: case FixedOperatorKind::SHR:
return "srl"; return "shr";
case FixedOperatorKind::SAR:
return "sar";
case FixedOperatorKind::CAR: case FixedOperatorKind::CAR:
return "car"; return "car";
case FixedOperatorKind::CDR: case FixedOperatorKind::CDR:
@ -1079,6 +1082,21 @@ std::string fixed_operator_to_string(FixedOperatorKind kind) {
return "new"; return "new";
case FixedOperatorKind::OBJECT_NEW: case FixedOperatorKind::OBJECT_NEW:
return "object-new"; return "object-new";
case FixedOperatorKind::TYPE_NEW:
return "type-new";
case FixedOperatorKind::LT:
return "<";
case FixedOperatorKind::GT:
return ">";
case FixedOperatorKind::LEQ:
return "<=";
case FixedOperatorKind::GEQ:
return ">=";
case FixedOperatorKind::EQ:
return "=";
case FixedOperatorKind::NEQ:
return "!=";
default: default:
assert(false); assert(false);
} }
@ -1323,8 +1341,12 @@ void DynamicMethodAccess::get_modified_regs(RegSet&) const {}
///////////////////////////// /////////////////////////////
ArrayFieldAccess::ArrayFieldAccess(Variable source, ArrayFieldAccess::ArrayFieldAccess(Variable source,
const std::vector<DerefToken>& deref_tokens, const std::vector<DerefToken>& deref_tokens,
int expected_stride) int expected_stride,
: m_source(source), m_deref_tokens(deref_tokens), m_expected_stride(expected_stride) {} int constant_offset)
: m_source(source),
m_deref_tokens(deref_tokens),
m_expected_stride(expected_stride),
m_constant_offset(constant_offset) {}
goos::Object ArrayFieldAccess::to_form(const Env& env) const { goos::Object ArrayFieldAccess::to_form(const Env& env) const {
std::vector<goos::Object> elts; std::vector<goos::Object> elts;

View file

@ -30,13 +30,15 @@ class FormElement {
virtual void collect_vars(VariableSet& vars) const = 0; virtual void collect_vars(VariableSet& vars) const = 0;
virtual void get_modified_regs(RegSet& regs) const = 0; virtual void get_modified_regs(RegSet& regs) const = 0;
std::string to_string(const Env& env) const; std::string to_string(const Env& env) const;
bool has_side_effects();
// push the result of this operation to the operation stack // push the result of this operation to the operation stack
virtual void push_to_stack(const Env& env, FormPool& pool, FormStack& stack); virtual void push_to_stack(const Env& env, FormPool& pool, FormStack& stack);
virtual void update_from_stack(const Env& env, virtual 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);
protected: protected:
friend class Form; friend class Form;
@ -59,53 +61,62 @@ class SimpleExpressionElement : public FormElement {
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) override; 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;
void update_from_stack_identity(const Env& env, void update_from_stack_identity(const Env& env,
FormPool& pool, FormPool& pool,
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result); std::vector<FormElement*>* result,
bool allow_side_effects);
void update_from_stack_gpr_to_fpr(const Env& env, void update_from_stack_gpr_to_fpr(const Env& env,
FormPool& pool, FormPool& pool,
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result); std::vector<FormElement*>* result,
bool allow_side_effects);
void update_from_stack_fpr_to_gpr(const Env& env, void update_from_stack_fpr_to_gpr(const Env& env,
FormPool& pool, FormPool& pool,
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result); std::vector<FormElement*>* result,
bool allow_side_effects);
void update_from_stack_div_s(const Env& env, void update_from_stack_div_s(const Env& env,
FormPool& pool, FormPool& pool,
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result); std::vector<FormElement*>* result,
bool allow_side_effects);
void update_from_stack_add_i(const Env& env, void update_from_stack_add_i(const Env& env,
FormPool& pool, FormPool& pool,
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result); std::vector<FormElement*>* result,
bool allow_side_effects);
void update_from_stack_mult_si(const Env& env, void update_from_stack_mult_si(const Env& env,
FormPool& pool, FormPool& pool,
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result); std::vector<FormElement*>* result,
bool allow_side_effects);
void update_from_stack_lognot(const Env& env, void update_from_stack_lognot(const Env& env,
FormPool& pool, FormPool& pool,
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result); std::vector<FormElement*>* result,
bool allow_side_effects);
void update_from_stack_force_si_2(const Env& env, void update_from_stack_force_si_2(const Env& env,
FixedOperatorKind kind, FixedOperatorKind kind,
FormPool& pool, FormPool& pool,
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result); std::vector<FormElement*>* result,
bool allow_side_effects);
void update_from_stack_force_ui_2(const Env& env, void update_from_stack_force_ui_2(const Env& env,
FixedOperatorKind kind, FixedOperatorKind kind,
FormPool& pool, FormPool& pool,
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result); std::vector<FormElement*>* result,
bool allow_side_effects);
void update_from_stack_copy_first_int_2(const Env& env, void update_from_stack_copy_first_int_2(const Env& env,
FixedOperatorKind kind, FixedOperatorKind kind,
FormPool& pool, FormPool& pool,
FormStack& stack, FormStack& stack,
std::vector<FormElement*>* result); std::vector<FormElement*>* result,
bool allow_side_effects);
const SimpleExpression& expr() const { return m_expr; } const SimpleExpression& expr() const { return m_expr; }
@ -151,7 +162,8 @@ class LoadSourceElement : public FormElement {
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) override; 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;
private: private:
@ -194,7 +206,8 @@ class SetVarElement : public FormElement {
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) override; 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;
const Variable& dst() const { return m_dst; } const Variable& dst() const { return m_dst; }
@ -259,7 +272,8 @@ class ConditionElement : public FormElement {
ConditionElement(IR2_Condition::Kind kind, ConditionElement(IR2_Condition::Kind kind,
std::optional<SimpleAtom> src0, std::optional<SimpleAtom> src0,
std::optional<SimpleAtom> src1, std::optional<SimpleAtom> src1,
RegSet consumed); RegSet consumed,
bool flipped);
goos::Object to_form(const Env& env) const override; goos::Object to_form(const Env& env) const override;
goos::Object to_form_as_condition(const Env& env) const override; goos::Object to_form_as_condition(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override; void apply(const std::function<void(FormElement*)>& f) override;
@ -269,15 +283,22 @@ class ConditionElement : public FormElement {
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) override; 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;
void invert(); void invert();
const RegSet& consume() const { return m_consumed; } const RegSet& consume() const { return m_consumed; }
FormElement* make_generic(const Env& env,
FormPool& pool,
const std::vector<Form*>& source_forms,
const std::vector<TypeSpec>& types);
private: private:
IR2_Condition::Kind m_kind; IR2_Condition::Kind m_kind;
std::optional<SimpleAtom> m_src[2]; std::optional<SimpleAtom> m_src[2];
RegSet m_consumed; RegSet m_consumed;
bool m_flipped;
}; };
/*! /*!
@ -293,7 +314,8 @@ class FunctionCallElement : public FormElement {
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) override; std::vector<FormElement*>* result,
bool allow_side_effects) 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 get_modified_regs(RegSet& regs) const override; void get_modified_regs(RegSet& regs) const override;
@ -395,6 +417,7 @@ class CondWithElseElement : public FormElement {
}; };
std::vector<Entry> entries; std::vector<Entry> entries;
Form* else_ir = nullptr; Form* else_ir = nullptr;
bool already_rewritten = false;
CondWithElseElement(std::vector<Entry> _entries, Form* _else_ir) CondWithElseElement(std::vector<Entry> _entries, Form* _else_ir)
: entries(std::move(_entries)), else_ir(_else_ir) {} : entries(std::move(_entries)), else_ir(_else_ir) {}
goos::Object to_form(const Env& env) const override; goos::Object to_form(const Env& env) const override;
@ -481,6 +504,7 @@ class ShortCircuitElement : public FormElement {
Variable final_result; Variable final_result;
std::vector<Entry> entries; std::vector<Entry> entries;
std::optional<bool> used_as_value = std::nullopt; std::optional<bool> used_as_value = std::nullopt;
bool already_rewritten = false;
explicit ShortCircuitElement(std::vector<Entry> _entries) : entries(std::move(_entries)) {} explicit ShortCircuitElement(std::vector<Entry> _entries) : entries(std::move(_entries)) {}
goos::Object to_form(const Env& env) const override; goos::Object to_form(const Env& env) const override;
@ -491,7 +515,8 @@ class ShortCircuitElement : public FormElement {
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) override; 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;
}; };
@ -511,6 +536,7 @@ class CondNoElseElement : public FormElement {
}; };
Variable final_destination; Variable final_destination;
bool used_as_value = false; bool used_as_value = false;
bool already_rewritten = false;
std::vector<Entry> entries; std::vector<Entry> entries;
explicit CondNoElseElement(std::vector<Entry> _entries) : entries(std::move(_entries)) {} explicit CondNoElseElement(std::vector<Entry> _entries) : entries(std::move(_entries)) {}
goos::Object to_form(const Env& env) const override; goos::Object to_form(const Env& env) const override;
@ -534,7 +560,8 @@ class AbsElement : public FormElement {
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) override; 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;
Variable source; Variable source;
RegSet consumed; RegSet consumed;
@ -563,7 +590,8 @@ class AshElement : public FormElement {
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) override; 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;
}; };
@ -584,7 +612,8 @@ class TypeOfElement : public FormElement {
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) override; std::vector<FormElement*>* result,
bool allow_side_effects) override;
}; };
/*! /*!
@ -681,7 +710,8 @@ class GenericElement : public FormElement {
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) override; 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;
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override; void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
const GenericOperator& op() const { return m_head; } const GenericOperator& op() const { return m_head; }
@ -704,7 +734,8 @@ class CastElement : public FormElement {
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) override; std::vector<FormElement*>* result,
bool allow_side_effects) override;
const TypeSpec& type() const { return m_type; } const TypeSpec& type() const { return m_type; }
const Form* source() const { return m_source; } const Form* source() const { return m_source; }
Form* source() { return m_source; } Form* source() { return m_source; }
@ -756,7 +787,8 @@ class DerefElement : public FormElement {
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) override; 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 is_addr_of() const { return m_is_addr_of; } bool is_addr_of() const { return m_is_addr_of; }
@ -780,7 +812,8 @@ class DynamicMethodAccess : public FormElement {
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) override; 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;
private: private:
@ -791,7 +824,8 @@ class ArrayFieldAccess : public FormElement {
public: public:
ArrayFieldAccess(Variable source, ArrayFieldAccess(Variable source,
const std::vector<DerefToken>& deref_tokens, const std::vector<DerefToken>& deref_tokens,
int expected_stride); int expected_stride,
int constant_offset);
goos::Object to_form(const Env& env) const override; goos::Object to_form(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override; void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override; void apply_form(const std::function<void(Form*)>& f) override;
@ -799,13 +833,15 @@ class ArrayFieldAccess : public FormElement {
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) override; 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;
private: private:
Variable m_source; Variable m_source;
std::vector<DerefToken> m_deref_tokens; std::vector<DerefToken> m_deref_tokens;
int m_expected_stride = -1; int m_expected_stride = -1;
int m_constant_offset = -1;
}; };
class GetMethodElement : public FormElement { class GetMethodElement : public FormElement {
@ -888,7 +924,11 @@ class Form {
void apply_form(const std::function<void(Form*)>& f); void apply_form(const std::function<void(Form*)>& f);
void collect_vars(VariableSet& vars) const; void collect_vars(VariableSet& vars) const;
void update_children_from_stack(const Env& env, FormPool& pool, FormStack& stack); void update_children_from_stack(const Env& env,
FormPool& pool,
FormStack& stack,
bool allow_side_effects);
bool has_side_effects();
void get_modified_regs(RegSet& regs) const; void get_modified_regs(RegSet& regs) const;
FormElement* parent_element = nullptr; FormElement* parent_element = nullptr;

File diff suppressed because it is too large Load diff

View file

@ -26,6 +26,7 @@ std::string FormStack::print(const Env& env) {
} }
void FormStack::push_value_to_reg(Variable var, Form* value, bool sequence_point) { void FormStack::push_value_to_reg(Variable var, Form* value, bool sequence_point) {
assert(value);
StackEntry entry; StackEntry entry;
entry.active = true; // by default, we should display everything! entry.active = true; // by default, we should display everything!
entry.sequence_point = sequence_point; entry.sequence_point = sequence_point;
@ -37,6 +38,7 @@ void FormStack::push_value_to_reg(Variable var, Form* value, bool sequence_point
void FormStack::push_non_seq_reg_to_reg(const Variable& dst, void FormStack::push_non_seq_reg_to_reg(const Variable& dst,
const Variable& src, const Variable& src,
Form* src_as_form) { Form* src_as_form) {
assert(src_as_form);
StackEntry entry; StackEntry entry;
entry.active = true; entry.active = true;
entry.sequence_point = false; entry.sequence_point = false;
@ -64,8 +66,11 @@ void FormStack::push_form_element(FormElement* elt, bool sequence_point) {
m_stack.push_back(entry); m_stack.push_back(entry);
} }
Form* FormStack::pop_reg(const Variable& var, const RegSet& barrier, const Env& env) { Form* FormStack::pop_reg(const Variable& var,
return pop_reg(var.reg(), barrier, env); const RegSet& barrier,
const Env& env,
bool allow_side_effects) {
return pop_reg(var.reg(), barrier, env, allow_side_effects);
} }
namespace { namespace {
@ -77,22 +82,30 @@ bool nonempty_intersection(const RegSet& a, const RegSet& b) {
} }
} // namespace } // namespace
Form* FormStack::pop_reg(Register reg, const RegSet& barrier, const Env& env) { Form* FormStack::pop_reg(Register reg,
const RegSet& barrier,
const Env& env,
bool allow_side_effects) {
(void)env; // keep this for easy debugging. (void)env; // keep this for easy debugging.
RegSet modified; RegSet modified;
for (size_t i = m_stack.size(); i-- > 0;) { for (size_t i = m_stack.size(); i-- > 0;) {
auto& entry = m_stack.at(i); auto& entry = m_stack.at(i);
if (entry.active) { if (entry.active) {
if (entry.destination->reg() == reg) { if (entry.destination.has_value() && entry.destination->reg() == reg) {
entry.source->get_modified_regs(modified); entry.source->get_modified_regs(modified);
if (!allow_side_effects && entry.source->has_side_effects()) {
// the source of the set! has a side effect and that's not allowed, so abort.
return nullptr;
}
if (nonempty_intersection(modified, barrier)) { if (nonempty_intersection(modified, barrier)) {
// violating the barrier registers.
return nullptr; return nullptr;
} }
entry.active = false; entry.active = false;
assert(entry.source); assert(entry.source);
if (entry.non_seq_source.has_value()) { if (entry.non_seq_source.has_value()) {
assert(entry.sequence_point == false); assert(entry.sequence_point == false);
auto result = pop_reg(entry.non_seq_source->reg(), barrier, env); auto result = pop_reg(entry.non_seq_source->reg(), barrier, env, allow_side_effects);
if (result) { if (result) {
return result; return result;
} }
@ -108,9 +121,17 @@ Form* FormStack::pop_reg(Register reg, const RegSet& barrier, const Env& env) {
if (entry.source) { if (entry.source) {
assert(!entry.elt); assert(!entry.elt);
entry.source->get_modified_regs(modified); entry.source->get_modified_regs(modified);
if (!allow_side_effects) {
// shouldn't allow skipping past a set! (may be too conservative?)
return nullptr;
}
} else { } else {
assert(entry.elt); assert(entry.elt);
entry.elt->get_modified_regs(modified); entry.elt->get_modified_regs(modified);
if (!allow_side_effects && entry.elt->has_side_effects()) {
// shouldn't allow skipping past something with a set! (also may be too conservative?)
return nullptr;
}
} }
} }
} }

View file

@ -16,8 +16,11 @@ class FormStack {
void push_value_to_reg(Variable var, Form* value, bool sequence_point); void push_value_to_reg(Variable var, Form* value, bool sequence_point);
void push_non_seq_reg_to_reg(const Variable& dst, const Variable& src, Form* src_as_form); void push_non_seq_reg_to_reg(const Variable& dst, const Variable& src, Form* src_as_form);
void push_form_element(FormElement* elt, bool sequence_point); void push_form_element(FormElement* elt, bool sequence_point);
Form* pop_reg(const Variable& var, const RegSet& barrier, const Env& env); Form* pop_reg(const Variable& var,
Form* pop_reg(Register reg, const RegSet& barrier, const Env& env); const RegSet& barrier,
const Env& env,
bool allow_side_effects);
Form* pop_reg(Register reg, const RegSet& barrier, const Env& env, bool allow_side_effects);
bool is_single_expression(); bool is_single_expression();
std::vector<FormElement*> rewrite(FormPool& pool); std::vector<FormElement*> rewrite(FormPool& pool);
std::vector<FormElement*> rewrite_to_get_var(FormPool& pool, const Variable& var, const Env& env); std::vector<FormElement*> rewrite_to_get_var(FormPool& pool, const Variable& var, const Env& env);

View file

@ -105,12 +105,20 @@ enum class FixedOperatorKind {
LOGXOR, LOGXOR,
LOGNOR, LOGNOR,
LOGNOT, LOGNOT,
SLL, SHL,
SRL, SHR,
SAR,
CAR, CAR,
CDR, CDR,
NEW, NEW,
OBJECT_NEW, OBJECT_NEW,
TYPE_NEW,
LT,
GT,
LEQ,
GEQ,
EQ,
NEQ,
INVALID INVALID
}; };

View file

@ -779,6 +779,7 @@ std::unique_ptr<AtomicOp> convert_bne_2(const Instruction& i0,
} else { } else {
condition = IR2_Condition(IR2_Condition::Kind::NOT_EQUAL, make_src_atom(s0, idx), condition = IR2_Condition(IR2_Condition::Kind::NOT_EQUAL, make_src_atom(s0, idx),
make_src_atom(s1, idx)); make_src_atom(s1, idx));
condition.make_flipped();
} }
return make_branch(condition, i1, likely, dest, idx); return make_branch(condition, i1, likely, dest, idx);
} }
@ -809,6 +810,7 @@ std::unique_ptr<AtomicOp> convert_beq_2(const Instruction& i0,
} else { } else {
condition = condition =
IR2_Condition(IR2_Condition::Kind::EQUAL, make_src_atom(s0, idx), make_src_atom(s1, idx)); IR2_Condition(IR2_Condition::Kind::EQUAL, make_src_atom(s0, idx), make_src_atom(s1, idx));
condition.make_flipped();
} }
return make_branch(condition, i1, likely, dest, idx); return make_branch(condition, i1, likely, dest, idx);
} }

View file

@ -1065,7 +1065,7 @@ Form* cfg_to_ir(FormPool& pool, const Function& f, const CfgVtx* vtx) {
} else if (dynamic_cast<const InfiniteLoopBlock*>(vtx)) { } else if (dynamic_cast<const InfiniteLoopBlock*>(vtx)) {
auto wvtx = dynamic_cast<const InfiniteLoopBlock*>(vtx); auto wvtx = dynamic_cast<const InfiniteLoopBlock*>(vtx);
auto condition = pool.alloc_single_element_form<ConditionElement>( auto condition = pool.alloc_single_element_form<ConditionElement>(
nullptr, IR2_Condition::Kind::ALWAYS, std::nullopt, std::nullopt, RegSet()); nullptr, IR2_Condition::Kind::ALWAYS, std::nullopt, std::nullopt, RegSet(), false);
auto result = pool.alloc_single_element_form<WhileElement>(nullptr, condition, auto result = pool.alloc_single_element_form<WhileElement>(nullptr, condition,
cfg_to_ir(pool, f, wvtx->block)); cfg_to_ir(pool, f, wvtx->block));
clean_up_infinite_while_loop(pool, clean_up_infinite_while_loop(pool,

View file

@ -436,6 +436,23 @@ void SSA::remap() {
} }
}; };
std::unordered_map<Register, VarIdRecord, Register::hash> used_vars; std::unordered_map<Register, VarIdRecord, Register::hash> used_vars;
// we do this in two passes. the first pass collects only the B0 variables and adds those first,
// so these remain index 0 (expected by later decompiler passes)
for (auto& block : blocks) {
assert(block.phis.empty());
for (auto& instr : block.ins) {
if (instr.dst.has_value() && map.var_id(*instr.dst) == 0) {
used_vars[instr.dst->reg()].insert(map.var_id(*instr.dst));
}
for (auto& src : instr.src) {
if (map.var_id(src) == 0) {
used_vars[src.reg()].insert(map.var_id(src));
}
}
}
}
// and the second pass grabs all of them
for (auto& block : blocks) { for (auto& block : blocks) {
assert(block.phis.empty()); assert(block.phis.empty());
for (auto& instr : block.ins) { for (auto& instr : block.ins) {

View file

@ -113,3 +113,6 @@
- Fixed use-after-free if the top-level form fails to compile and you continue trying to compile stuff. - Fixed use-after-free if the top-level form fails to compile and you continue trying to compile stuff.
- `and` and `or` are more efficient and the type of the result is more specific: `LCA(symbol, cases...)` - `and` and `or` are more efficient and the type of the result is more specific: `LCA(symbol, cases...)`
- `print-type` now fully compiles the argument and returns the result instead of `none` - `print-type` now fully compiles the argument and returns the result instead of `none`
## V0.6
- There is no longer a separate compiler form for variable vs. constant shifts. Instead the compiler will pick the constant shift automatically when possible. The shifts are called `sar`, `shl` and `shr`, like the x86 instructions.

View file

@ -47,7 +47,7 @@
(defun log2 ((x int)) (defun log2 ((x int))
"Straight out of Bit Twiddling Hacks graphics.stanford.edu" "Straight out of Bit Twiddling Hacks graphics.stanford.edu"
(- (sarv (the-as integer (the float x)) 23) 127) (- (sar (the-as integer (the float x)) 23) 127)
) )
(defun seek ((x float) (target float) (diff float)) (defun seek ((x float) (target float) (diff float))
@ -139,7 +139,7 @@
(set! (-> *random-generator* seed) #x666EDD1E) (set! (-> *random-generator* seed) #x666EDD1E)
(defmacro sext32-64 (x) (defmacro sext32-64 (x)
`(sarv (shlv ,x 32) 32) `(sar (shl ,x 32) 32)
) )
(defun rand-uint31-gen ((gen random-generator)) (defun rand-uint31-gen ((gen random-generator))
@ -152,17 +152,17 @@
;; mult3 v0, v1, a1 ;; mult3 v0, v1, a1
(prod (imul64 16807 sd)) (prod (imul64 16807 sd))
;; mfhi v1 ;; mfhi v1
(hi (shrv prod 32)) ;; sign extend this? (hi (shr prod 32)) ;; sign extend this?
(lo (sarv (shlv prod 32) 32)) (lo (sar (shl prod 32) 32))
;; daddu v1, v1, v1 ;; daddu v1, v1, v1
(v1 (+ hi hi)) (v1 (+ hi hi))
;; srl a1, v0, 31 ;; srl a1, v0, 31
(a1 (logand #xffffffff (shrv lo 31))) (a1 (logand #xffffffff (shr lo 31)))
;; or v1, v1, a1 ;; or v1, v1, a1
;; daddu v0, v0 v1 ;; daddu v0, v0 v1
(result (+ lo (logior v1 a1))) (result (+ lo (logior v1 a1)))
) )
(set! result (shrv (logand #xffffffff (shlv result 1)) 1)) (set! result (shr (logand #xffffffff (shl result 1)) 1))
(set! (-> gen seed) result) (set! (-> gen seed) result)
result result
) )

View file

@ -71,8 +71,8 @@
;; these correspond to x86-64 variable shift instructions. ;; these correspond to x86-64 variable shift instructions.
;; the exact behavior of GOAL shifts (signed/unsigned) are unknown so for now shifts must ;; the exact behavior of GOAL shifts (signed/unsigned) are unknown so for now shifts must
;; be manually specified. ;; be manually specified.
(shlv value shift-amount) (shl value shift-amount)
(sarv value (- shift-amount)) (sar value (- shift-amount))
) )
) )

View file

@ -390,9 +390,6 @@ class Compiler {
Val* compile_mul(const goos::Object& form, const goos::Object& rest, Env* env); Val* compile_mul(const goos::Object& form, const goos::Object& rest, Env* env);
Val* compile_imul64(const goos::Object& form, const goos::Object& rest, Env* env); Val* compile_imul64(const goos::Object& form, const goos::Object& rest, Env* env);
Val* compile_div(const goos::Object& form, const goos::Object& rest, Env* env); Val* compile_div(const goos::Object& form, const goos::Object& rest, Env* env);
Val* compile_shlv(const goos::Object& form, const goos::Object& rest, Env* env);
Val* compile_sarv(const goos::Object& form, const goos::Object& rest, Env* env);
Val* compile_shrv(const goos::Object& form, const goos::Object& rest, Env* env);
Val* compile_shl(const goos::Object& form, const goos::Object& rest, Env* env); Val* compile_shl(const goos::Object& form, const goos::Object& rest, Env* env);
Val* compile_sar(const goos::Object& form, const goos::Object& rest, Env* env); Val* compile_sar(const goos::Object& form, const goos::Object& rest, Env* env);
Val* compile_shr(const goos::Object& form, const goos::Object& rest, Env* env); Val* compile_shr(const goos::Object& form, const goos::Object& rest, Env* env);

View file

@ -148,9 +148,6 @@ static const std::unordered_map<
{"*", &Compiler::compile_mul}, {"*", &Compiler::compile_mul},
{"imul64", &Compiler::compile_imul64}, {"imul64", &Compiler::compile_imul64},
{"/", &Compiler::compile_div}, {"/", &Compiler::compile_div},
{"shlv", &Compiler::compile_shlv},
{"shrv", &Compiler::compile_shrv},
{"sarv", &Compiler::compile_sarv},
{"shl", &Compiler::compile_shl}, {"shl", &Compiler::compile_shl},
{"shr", &Compiler::compile_shr}, {"shr", &Compiler::compile_shr},
{"sar", &Compiler::compile_sar}, {"sar", &Compiler::compile_sar},

View file

@ -396,30 +396,6 @@ Val* Compiler::compile_div(const goos::Object& form, const goos::Object& rest, E
return get_none(); return get_none();
} }
Val* Compiler::compile_shlv(const goos::Object& form, const goos::Object& rest, Env* env) {
auto args = get_va(form, rest);
va_check(form, args, {{}, {}}, {});
auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env);
auto second = compile_error_guard(args.unnamed.at(1), env)->to_gpr(env);
return compile_variable_shift(form, first, second, env, IntegerMathKind::SHLV_64);
}
Val* Compiler::compile_sarv(const goos::Object& form, const goos::Object& rest, Env* env) {
auto args = get_va(form, rest);
va_check(form, args, {{}, {}}, {});
auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env);
auto second = compile_error_guard(args.unnamed.at(1), env)->to_gpr(env);
return compile_variable_shift(form, first, second, env, IntegerMathKind::SARV_64);
}
Val* Compiler::compile_shrv(const goos::Object& form, const goos::Object& rest, Env* env) {
auto args = get_va(form, rest);
va_check(form, args, {{}, {}}, {});
auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env);
auto second = compile_error_guard(args.unnamed.at(1), env)->to_gpr(env);
return compile_variable_shift(form, first, second, env, IntegerMathKind::SHRV_64);
}
Val* Compiler::compile_variable_shift(const goos::Object& form, Val* Compiler::compile_variable_shift(const goos::Object& form,
const RegVal* in, const RegVal* in,
const RegVal* sa, const RegVal* sa,
@ -449,35 +425,50 @@ Val* Compiler::compile_variable_shift(const goos::Object& form,
Val* Compiler::compile_shl(const goos::Object& form, const goos::Object& rest, Env* env) { Val* Compiler::compile_shl(const goos::Object& form, const goos::Object& rest, Env* env) {
auto args = get_va(form, rest); auto args = get_va(form, rest);
va_check(form, args, {{}, {goos::ObjectType::INTEGER}}, {}); va_check(form, args, {{}, {}}, {});
auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env); auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env);
auto sa = args.unnamed.at(1).as_int(); int64_t constant_sa = -1;
if (sa < 0 || sa > 64) { if (try_getting_constant_integer(args.unnamed.at(1), &constant_sa, env)) {
throw_compiler_error(form, "Cannot shift by more than 64, or by a negative amount."); if (constant_sa < 0 || constant_sa > 64) {
throw_compiler_error(form, "Cannot shift by more than 64, or by a negative amount.");
}
return compile_fixed_shift(form, first, constant_sa, env, IntegerMathKind::SHL_64);
} else {
auto second = compile_error_guard(args.unnamed.at(1), env)->to_gpr(env);
return compile_variable_shift(form, first, second, env, IntegerMathKind::SHLV_64);
} }
return compile_fixed_shift(form, first, sa, env, IntegerMathKind::SHL_64);
} }
Val* Compiler::compile_shr(const goos::Object& form, const goos::Object& rest, Env* env) { Val* Compiler::compile_shr(const goos::Object& form, const goos::Object& rest, Env* env) {
auto args = get_va(form, rest); auto args = get_va(form, rest);
va_check(form, args, {{}, {goos::ObjectType::INTEGER}}, {}); va_check(form, args, {{}, {}}, {});
auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env); auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env);
auto sa = args.unnamed.at(1).as_int(); int64_t constant_sa = -1;
if (sa < 0 || sa > 64) { if (try_getting_constant_integer(args.unnamed.at(1), &constant_sa, env)) {
throw_compiler_error(form, "Cannot shift by more than 64, or by a negative amount"); if (constant_sa < 0 || constant_sa > 64) {
throw_compiler_error(form, "Cannot shift by more than 64, or by a negative amount.");
}
return compile_fixed_shift(form, first, constant_sa, env, IntegerMathKind::SHR_64);
} else {
auto second = compile_error_guard(args.unnamed.at(1), env)->to_gpr(env);
return compile_variable_shift(form, first, second, env, IntegerMathKind::SHRV_64);
} }
return compile_fixed_shift(form, first, sa, env, IntegerMathKind::SHR_64);
} }
Val* Compiler::compile_sar(const goos::Object& form, const goos::Object& rest, Env* env) { Val* Compiler::compile_sar(const goos::Object& form, const goos::Object& rest, Env* env) {
auto args = get_va(form, rest); auto args = get_va(form, rest);
va_check(form, args, {{}, {goos::ObjectType::INTEGER}}, {}); va_check(form, args, {{}, {}}, {});
auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env); auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env);
auto sa = args.unnamed.at(1).as_int(); int64_t constant_sa = -1;
if (sa < 0 || sa > 64) { if (try_getting_constant_integer(args.unnamed.at(1), &constant_sa, env)) {
throw_compiler_error(form, "Cannot shift by more than 64, or by a negative amount"); if (constant_sa < 0 || constant_sa > 64) {
throw_compiler_error(form, "Cannot shift by more than 64, or by a negative amount.");
}
return compile_fixed_shift(form, first, constant_sa, env, IntegerMathKind::SAR_64);
} else {
auto second = compile_error_guard(args.unnamed.at(1), env)->to_gpr(env);
return compile_variable_shift(form, first, second, env, IntegerMathKind::SARV_64);
} }
return compile_fixed_shift(form, first, sa, env, IntegerMathKind::SAR_64);
} }
Val* Compiler::compile_fixed_shift(const goos::Object& form, Val* Compiler::compile_fixed_shift(const goos::Object& form,

View file

@ -4,6 +4,7 @@
#include "decompiler/analysis/reg_usage.h" #include "decompiler/analysis/reg_usage.h"
#include "decompiler/analysis/cfg_builder.h" #include "decompiler/analysis/cfg_builder.h"
#include "decompiler/analysis/expression_build.h" #include "decompiler/analysis/expression_build.h"
#include "decompiler/analysis/final_output.h"
#include "common/goos/PrettyPrinter.h" #include "common/goos/PrettyPrinter.h"
#include "decompiler/IR2/Form.h" #include "decompiler/IR2/Form.h"
#include "third-party/json.hpp" #include "third-party/json.hpp"
@ -180,6 +181,30 @@ void FormRegressionTest::test(const std::string& code,
EXPECT_TRUE(expected_form == actual_form); EXPECT_TRUE(expected_form == actual_form);
} }
void FormRegressionTest::test_final_function(
const std::string& code,
const std::string& type,
const std::string& expected,
bool allow_pairs,
const std::vector<std::pair<std::string, std::string>>& strings,
const std::unordered_map<int, std::vector<decompiler::TypeHint>>& hints) {
auto ts = dts->parse_type_spec(type);
auto test = make_function(code, ts, true, allow_pairs, "", strings, hints);
ASSERT_TRUE(test);
auto expected_form =
pretty_print::get_pretty_printer_reader().read_from_string(expected, false).as_pair()->car;
ASSERT_TRUE(test->func.ir2.top_form);
auto final = final_defun_out(test->func, test->func.ir2.env, *dts);
auto actual_form =
pretty_print::get_pretty_printer_reader().read_from_string(final, false).as_pair()->car;
if (expected_form != actual_form) {
printf("Got:\n%s\n\nExpected\n%s\n", pretty_print::to_string(actual_form).c_str(),
pretty_print::to_string(expected_form).c_str());
}
EXPECT_TRUE(expected_form == actual_form);
}
std::unordered_map<int, std::vector<decompiler::TypeHint>> FormRegressionTest::parse_hint_json( std::unordered_map<int, std::vector<decompiler::TypeHint>> FormRegressionTest::parse_hint_json(
const std::string& in) { const std::string& in) {
std::unordered_map<int, std::vector<decompiler::TypeHint>> out; std::unordered_map<int, std::vector<decompiler::TypeHint>> out;

View file

@ -66,5 +66,13 @@ class FormRegressionTest : public ::testing::Test {
test(code, type, expected, true, allow_pairs, method_name, strings, hints); test(code, type, expected, true, allow_pairs, method_name, strings, hints);
} }
void test_final_function(
const std::string& code,
const std::string& type,
const std::string& expected,
bool allow_pairs = false,
const std::vector<std::pair<std::string, std::string>>& strings = {},
const std::unordered_map<int, std::vector<decompiler::TypeHint>>& hints = {});
std::unordered_map<int, std::vector<decompiler::TypeHint>> parse_hint_json(const std::string& in); std::unordered_map<int, std::vector<decompiler::TypeHint>> parse_hint_json(const std::string& in);
}; };

View file

@ -422,7 +422,7 @@ TEST_F(FormRegressionTest, ExprSizeOfType) {
" daddiu sp, sp, 16"; " daddiu sp, sp, 16";
std::string type = "(function type uint)"; std::string type = "(function type uint)";
std::string expected = "(logand (l.d L346) (+ (sll (-> a0-1 allocated-length) 2) 43))"; std::string expected = "(logand (l.d L346) (+ (shl (-> a0-0 allocated-length) 2) 43))";
test_with_expr(func, type, expected, false, ""); test_with_expr(func, type, expected, false, "");
} }
@ -469,6 +469,52 @@ TEST_F(FormRegressionTest, ExprBasicTypeP) {
test_with_expr(func, type, expected); test_with_expr(func, type, expected);
} }
TEST_F(FormRegressionTest, FinalBasicTypeP) {
std::string func =
" sll r0, r0, 0\n"
"L285:\n"
" lwu v1, -4(a0)\n"
" lw a0, object(s7)\n"
"L286:\n"
" bne v1, a1, L287\n"
" or a2, s7, r0\n"
" daddiu v1, s7, #t\n"
" or v0, v1, r0\n"
" beq r0, r0, L288\n"
" sll r0, r0, 0\n"
" or v1, r0, r0\n"
"L287:\n"
" lwu v1, 4(v1)\n"
" bne v1, a0, L286\n"
" sll r0, r0, 0\n"
" or v0, s7, r0\n"
"L288:\n"
" jr ra\n"
" daddu sp, sp, r0";
std::string type = "(function basic type symbol)";
std::string expected =
"(defun test-function ((a0-0 basic) (a1-0 type))\n"
" (local-vars\n"
" (v1-0 type)\n"
" (a0-1 type)\n"
" (a2-0 symbol)\n"
" )\n"
" (begin\n"
" (set! v1-0 (-> a0-0 type))\n"
" (set! a0-1 object)\n"
" (until\n"
" (begin (set! v1-0 (-> v1-0 parent)) (= v1-0 a0-1))\n"
" (if (= v1-0 a1-0) (return (quote #t) (set! v1-0 0)))\n"
" )\n"
" (quote #f)\n"
" )\n"
" )";
test_final_function(func, type, expected);
}
TEST_F(FormRegressionTest, ExprTypeTypep) { TEST_F(FormRegressionTest, ExprTypeTypep) {
std::string func = std::string func =
" sll r0, r0, 0\n" " sll r0, r0, 0\n"
@ -616,7 +662,7 @@ TEST_F(FormRegressionTest, ExprRef) {
"(begin\n" "(begin\n"
" (set! v1-0 0)\n" " (set! v1-0 0)\n"
" (while\n" " (while\n"
" (<.si v1-0 a1-0)\n" " (< v1-0 a1-0)\n"
" (nop!)\n" " (nop!)\n"
" (nop!)\n" " (nop!)\n"
" (set! a0-0 (cdr a0-0))\n" " (set! a0-0 (cdr a0-0))\n"
@ -684,7 +730,7 @@ TEST_F(FormRegressionTest, ExprPairMethod4) {
" (set! v0-0 1)\n" " (set! v0-0 1)\n"
" (while\n" " (while\n"
" (and (!= v1-1 '()) " " (and (!= v1-1 '()) "
" (<0.si (sll (the-as uint v1-1) 62))\n" " (< (shl (the-as int v1-1) 62) 0)\n"
" )\n" " )\n"
" (set! v0-0 (+ v0-0 1))\n" " (set! v0-0 (+ v0-0 1))\n"
" (set! v1-1 (cdr v1-1))\n" " (set! v1-1 (cdr v1-1))\n"
@ -1548,13 +1594,13 @@ TEST_F(FormRegressionTest, ExprSort) {
" (set! s3-0 gp-0)\n" " (set! s3-0 gp-0)\n"
" (while\n" " (while\n"
" (not\n" " (not\n"
" (or (= (cdr s3-0) (quote ())) (>=0.si (sll (the-as uint (cdr s3-0)) 62)))\n" " (or (= (cdr s3-0) (quote ())) (>= (shl (the-as int (cdr s3-0)) 62) 0))\n"
" )\n" " )\n"
" (set! s2-0 (car s3-0))\n" " (set! s2-0 (car s3-0))\n"
" (set! s1-0 (car (cdr s3-0)))\n" " (set! s1-0 (car (cdr s3-0)))\n"
" (set! v1-1 (s5-0 s2-0 s1-0))\n" " (set! v1-1 (s5-0 s2-0 s1-0))\n"
" (when\n" " (when\n"
" (and (or (not v1-1) (>0.si v1-1)) (!= v1-2 (quote #t)))\n" " (and (or (not v1-1) (> (the-as int v1-1) 0)) (!= v1-2 (quote #t)))\n"
" (set! s4-0 (+ s4-0 1))\n" " (set! s4-0 (+ s4-0 1))\n"
" (set! (car s3-0) s1-0)\n" " (set! (car s3-0) s1-0)\n"
" (set! (car (cdr s3-0)) s2-0)\n" " (set! (car (cdr s3-0)) s2-0)\n"
@ -1851,7 +1897,7 @@ TEST_F(FormRegressionTest, ExprMemCopy) {
" (set! v0-0 a0-0)\n" " (set! v0-0 a0-0)\n"
" (set! v1-0 0)\n" " (set! v1-0 0)\n"
" (while\n" " (while\n"
" (<.si v1-0 a2-0)\n" " (< v1-0 a2-0)\n"
" (set! (-> (the-as (pointer int8) a0-0)) (-> (the-as (pointer uint8) a1-0)))\n" " (set! (-> (the-as (pointer int8) a0-0)) (-> (the-as (pointer uint8) a1-0)))\n"
" (set! a0-0 (+ a0-0 (the-as uint 1)))\n" " (set! a0-0 (+ a0-0 (the-as uint 1)))\n"
" (set! a1-0 (+ a1-0 (the-as uint 1)))\n" " (set! a1-0 (+ a1-0 (the-as uint 1)))\n"
@ -1894,7 +1940,7 @@ TEST_F(FormRegressionTest, ExprMemSet32) {
" (set! v0-0 a0-0)\n" " (set! v0-0 a0-0)\n"
" (set! v1-0 0)\n" " (set! v1-0 0)\n"
" (while\n" " (while\n"
" (<.si v1-0 a1-0)\n" " (< v1-0 a1-0)\n"
" (set! (-> (the-as (pointer int32) a0-0)) a2-0)\n" " (set! (-> (the-as (pointer int32) a0-0)) a2-0)\n"
" (set! a0-0 (+ a0-0 (the-as uint 4)))\n" " (set! a0-0 (+ a0-0 (the-as uint 4)))\n"
" (nop!)\n" " (nop!)\n"
@ -1940,7 +1986,7 @@ TEST_F(FormRegressionTest, ExprMemOr) {
" (set! v0-0 a0-0)\n" " (set! v0-0 a0-0)\n"
" (set! v1-0 0)\n" " (set! v1-0 0)\n"
" (while\n" " (while\n"
" (<.si v1-0 a2-0)\n" " (< v1-0 a2-0)\n"
" (set!\n" " (set!\n"
" (-> (the-as (pointer int8) a0-0))\n" " (-> (the-as (pointer int8) a0-0))\n"
" (logior\n" " (logior\n"
@ -2166,13 +2212,13 @@ TEST_F(FormRegressionTest, ExprPrintTreeBitmask) {
" (set! s5-0 a1-0)\n" " (set! s5-0 a1-0)\n"
" (set! s4-0 0)\n" " (set! s4-0 0)\n"
" (while\n" " (while\n"
" (<.si s4-0 s5-0)\n" " (< s4-0 s5-0)\n"
" (if\n" " (if\n"
" (zero? (logand gp-0 1))\n" " (zero? (logand gp-0 1))\n"
" (format (quote #t) L323)\n" " (format (quote #t) L323)\n"
" (format (quote #t) L322)\n" " (format (quote #t) L322)\n"
" )\n" " )\n"
" (set! gp-0 (srl (the-as uint gp-0) 1))\n" " (set! gp-0 (shr (the-as uint gp-0) 1))\n"
" (set! s4-0 (+ s4-0 1))\n" " (set! s4-0 (+ s4-0 1))\n"
" )\n" " )\n"
" (set! v1-3 (quote #f))\n" " (set! v1-3 (quote #f))\n"
@ -2180,3 +2226,124 @@ TEST_F(FormRegressionTest, ExprPrintTreeBitmask) {
" )"; " )";
test_with_expr(func, type, expected, false, "", {{"L323", " "}, {"L322", "| "}}); test_with_expr(func, type, expected, false, "", {{"L323", " "}, {"L322", "| "}});
} }
TEST_F(FormRegressionTest, ExprPrintName) {
std::string func =
" sll r0, r0, 0\n"
"L136:\n"
" daddiu sp, sp, -16\n"
" sd ra, 0(sp)\n"
" bne a0, a1, L137\n"
" or v1, s7, r0\n"
" daddiu v0, s7, #t\n"
" beq r0, r0, L143\n"
" sll r0, r0, 0\n"
"L137:\n"
" lwu v1, -4(a0)\n"
" lw a2, string(s7)\n"
" dsubu v1, v1, a2\n"
" daddiu a2, s7, 8\n"
" movn a2, s7, v1\n"
" beql s7, a2, L138\n"
" or v1, a2, r0\n"
" lwu v1, -4(a1)\n"
" lw a2, string(s7)\n"
" dsubu a2, v1, a2\n"
" daddiu v1, s7, 8\n"
" movn v1, s7, a2\n"
"L138:\n"
" beq s7, v1, L139\n"
" or v1, s7, r0\n"
" lw t9, string=(s7)\n"
" jalr ra, t9\n"
" sll v0, ra, 0\n"
" beq r0, r0, L143\n"
" sll r0, r0, 0\n"
"L139:\n"
" lwu v1, -4(a0)\n"
" lw a2, string(s7)\n"
" dsubu v1, v1, a2\n"
" daddiu a2, s7, 8\n"
" movn a2, s7, v1\n"
" beql s7, a2, L140\n"
" or v1, a2, r0\n"
" lwu v1, -4(a1)\n"
" lw a2, symbol(s7)\n"
" dsubu a2, v1, a2\n"
" daddiu v1, s7, 8\n"
" movn v1, s7, a2\n"
"L140:\n"
" beq s7, v1, L141\n"
" or v1, s7, r0\n"
" lw t9, string=(s7)\n"
" ori v1, r0, 65336\n"
" daddu v1, v1, a1\n"
" lwu a1, 0(v1)\n"
" jalr ra, t9\n"
" sll v0, ra, 0\n"
"\n"
" beq r0, r0, L143\n"
" sll r0, r0, 0\n"
"L141:\n"
" lwu v1, -4(a1)\n"
" lw a2, string(s7)\n"
" dsubu v1, v1, a2\n"
" daddiu a2, s7, 8\n"
" movn a2, s7, v1\n"
" beql s7, a2, L142\n"
" or v1, a2, r0\n"
" lwu v1, -4(a0)\n"
" lw a2, symbol(s7)\n"
" dsubu a2, v1, a2\n"
" daddiu v1, s7, 8\n"
" movn v1, s7, a2\n"
"L142:\n"
" beq s7, v1, L143\n"
" or v0, s7, r0\n"
" lw t9, string=(s7)\n"
" or v1, a1, r0\n"
" ori a1, r0, 65336\n"
" daddu a0, a1, a0\n"
" lwu a1, 0(a0)\n"
" or a0, v1, r0\n"
" jalr ra, t9\n"
" sll v0, ra, 0\n"
"L143:\n"
" ld ra, 0(sp)\n"
" jr ra\n"
" daddiu sp, sp, 16";
std::string type = "(function basic basic symbol)";
std::string expected =
"(cond\n"
" ((= a0-0 a1-0) (quote #t))\n"
" ((and (= (-> a0-0 type) string) (= (-> a1-0 type) string))\n"
" (string= a0-0 a1-0)\n"
" )\n"
" ((and (= (-> a0-0 type) string) (= (-> a1-0 type) symbol))\n"
" (string= a0-0 (-> (+ 65336 (the-as int (the-as symbol a1-0))) 0))\n"
" )\n"
" ((and (= (-> a1-0 type) string) (= (-> a0-0 type) symbol))\n"
" (string= a1-0 (-> (+ 65336 (the-as int (the-as symbol a0-0))) 0))\n"
" )\n"
" )";
test_with_expr(func, type, expected, false, "", {},
parse_hint_json("[\t\t[24, [\"a1\", \"symbol\"]],\n"
"\t\t[39, [\"a0\", \"symbol\"]]]"));
}

View file

@ -547,7 +547,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
" ((= v1-1 (quote int32))\n" " ((= v1-1 (quote int32))\n"
" (set! s5-0 0)\n" " (set! s5-0 0)\n"
" (while\n" " (while\n"
" (<.si s5-0 (-> gp-0 length))\n" " (< s5-0 (-> gp-0 length))\n"
" (format\n" " (format\n"
" (quote #t)\n" " (quote #t)\n"
" (if (zero? s5-0) L341 L340)\n" " (if (zero? s5-0) L341 L340)\n"
@ -561,7 +561,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
" ((= v1-1 (quote uint32))\n" " ((= v1-1 (quote uint32))\n"
" (set! s5-1 0)\n" " (set! s5-1 0)\n"
" (while\n" " (while\n"
" (<.si s5-1 (-> gp-0 length))\n" " (< s5-1 (-> gp-0 length))\n"
" (format\n" " (format\n"
" (quote #t)\n" " (quote #t)\n"
" (if (zero? s5-1) L341 L340)\n" " (if (zero? s5-1) L341 L340)\n"
@ -575,7 +575,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
" ((= v1-1 (quote int64))\n" " ((= v1-1 (quote int64))\n"
" (set! s5-2 0)\n" " (set! s5-2 0)\n"
" (while\n" " (while\n"
" (<.si s5-2 (-> gp-0 length))\n" " (< s5-2 (-> gp-0 length))\n"
" (format\n" " (format\n"
" (quote #t)\n" " (quote #t)\n"
" (if (zero? s5-2) L341 L340)\n" " (if (zero? s5-2) L341 L340)\n"
@ -589,7 +589,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
" ((= v1-1 (quote uint64))\n" " ((= v1-1 (quote uint64))\n"
" (set! s5-3 0)\n" " (set! s5-3 0)\n"
" (while\n" " (while\n"
" (<.si s5-3 (-> gp-0 length))\n" " (< s5-3 (-> gp-0 length))\n"
" (format\n" " (format\n"
" (quote #t)\n" " (quote #t)\n"
" (if (zero? s5-3) L339 L338)\n" " (if (zero? s5-3) L339 L338)\n"
@ -603,7 +603,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
" ((= v1-1 (quote int8))\n" " ((= v1-1 (quote int8))\n"
" (set! s5-4 0)\n" " (set! s5-4 0)\n"
" (while\n" " (while\n"
" (<.si s5-4 (-> gp-0 length))\n" " (< s5-4 (-> gp-0 length))\n"
" (format\n" " (format\n"
" (quote #t)\n" " (quote #t)\n"
" (if (zero? s5-4) L341 L340)\n" " (if (zero? s5-4) L341 L340)\n"
@ -617,7 +617,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
" ((= v1-1 (quote uint8))\n" " ((= v1-1 (quote uint8))\n"
" (set! s5-5 0)\n" " (set! s5-5 0)\n"
" (while\n" " (while\n"
" (<.si s5-5 (-> gp-0 length))\n" " (< s5-5 (-> gp-0 length))\n"
" (format\n" " (format\n"
" (quote #t)\n" " (quote #t)\n"
" (if (zero? s5-5) L341 L340)\n" " (if (zero? s5-5) L341 L340)\n"
@ -631,7 +631,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
" ((= v1-1 (quote int16))\n" " ((= v1-1 (quote int16))\n"
" (set! s5-6 0)\n" " (set! s5-6 0)\n"
" (while\n" " (while\n"
" (<.si s5-6 (-> gp-0 length))\n" " (< s5-6 (-> gp-0 length))\n"
" (format\n" " (format\n"
" (quote #t)\n" " (quote #t)\n"
" (if (zero? s5-6) L341 L340)\n" " (if (zero? s5-6) L341 L340)\n"
@ -645,7 +645,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
" ((= v1-1 (quote uint16))\n" " ((= v1-1 (quote uint16))\n"
" (set! s5-7 0)\n" " (set! s5-7 0)\n"
" (while\n" " (while\n"
" (<.si s5-7 (-> gp-0 length))\n" " (< s5-7 (-> gp-0 length))\n"
" (format\n" " (format\n"
" (quote #t)\n" " (quote #t)\n"
" (if (zero? s5-7) L341 L340)\n" " (if (zero? s5-7) L341 L340)\n"
@ -662,14 +662,14 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
" (v1-40\n" " (v1-40\n"
" (set! s5-8 0)\n" " (set! s5-8 0)\n"
" (while\n" " (while\n"
" (<.si s5-8 (-> gp-0 length))\n" " (< s5-8 (-> gp-0 length))\n"
" (set! t9-10 format)\n" " (set! t9-10 format)\n"
" (set! a0-21 (quote #t))\n" " (set! a0-21 (quote #t))\n"
" (set! a1-11 (if (zero? s5-8) L339 L338))\n" " (set! a1-11 (if (zero? s5-8) L339 L338))\n"
" (set!\n" " (set!\n"
" v1-42\n" " v1-42\n"
" (+\n" " (+\n"
" (sll (the-as uint s5-8) 4)\n" " (shl s5-8 4)\n"
" (the-as int (the-as (array uint128) gp-0))\n" " (the-as int (the-as (array uint128) gp-0))\n"
" )\n" " )\n"
" )\n" " )\n"
@ -683,7 +683,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
" (else\n" " (else\n"
" (set! s5-9 0)\n" " (set! s5-9 0)\n"
" (while\n" " (while\n"
" (<.si s5-9 (-> gp-0 length))\n" " (< s5-9 (-> gp-0 length))\n"
" (format\n" " (format\n"
" (quote #t)\n" " (quote #t)\n"
" (if (zero? s5-9) L341 L340)\n" " (if (zero? s5-9) L341 L340)\n"
@ -704,7 +704,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
" ((= (-> gp-0 content-type) float)\n" " ((= (-> gp-0 content-type) float)\n"
" (set! s5-10 0)\n" " (set! s5-10 0)\n"
" (while\n" " (while\n"
" (<.si s5-10 (-> gp-0 length))\n" " (< s5-10 (-> gp-0 length))\n"
" (if\n" " (if\n"
" (zero? s5-10)\n" " (zero? s5-10)\n"
" (format (quote #t) L343 (-> (the-as (array float) gp-0) s5-10))\n" " (format (quote #t) L343 (-> (the-as (array float) gp-0) s5-10))\n"
@ -718,7 +718,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
" (else\n" " (else\n"
" (set! s5-11 0)\n" " (set! s5-11 0)\n"
" (while\n" " (while\n"
" (<.si s5-11 (-> gp-0 length))\n" " (< s5-11 (-> gp-0 length))\n"
" (if\n" " (if\n"
" (zero? s5-11)\n" " (zero? s5-11)\n"
" (format (quote #t) L336 (-> (the-as (array basic) gp-0) s5-11))\n" " (format (quote #t) L336 (-> (the-as (array basic) gp-0) s5-11))\n"
@ -1231,7 +1231,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
" ((= v1-1 (quote int32))\n" " ((= v1-1 (quote int32))\n"
" (set! s5-0 0)\n" " (set! s5-0 0)\n"
" (while\n" " (while\n"
" (<.si s5-0 (-> gp-0 length))\n" " (< s5-0 (-> gp-0 length))\n"
" (format (quote #t) L328 s5-0 (-> (the-as (array int32) gp-0) s5-0))\n" " (format (quote #t) L328 s5-0 (-> (the-as (array int32) gp-0) s5-0))\n"
" (set! s5-0 (+ s5-0 1))\n" " (set! s5-0 (+ s5-0 1))\n"
" )\n" " )\n"
@ -1241,7 +1241,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
" ((= v1-1 (quote uint32))\n" " ((= v1-1 (quote uint32))\n"
" (set! s5-1 0)\n" " (set! s5-1 0)\n"
" (while\n" " (while\n"
" (<.si s5-1 (-> gp-0 length))\n" " (< s5-1 (-> gp-0 length))\n"
" (format (quote #t) L328 s5-1 (-> (the-as (array uint32) gp-0) s5-1))\n" " (format (quote #t) L328 s5-1 (-> (the-as (array uint32) gp-0) s5-1))\n"
" (set! s5-1 (+ s5-1 1))\n" " (set! s5-1 (+ s5-1 1))\n"
" )\n" " )\n"
@ -1251,7 +1251,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
" ((= v1-1 (quote int64))\n" " ((= v1-1 (quote int64))\n"
" (set! s5-2 0)\n" " (set! s5-2 0)\n"
" (while\n" " (while\n"
" (<.si s5-2 (-> gp-0 length))\n" " (< s5-2 (-> gp-0 length))\n"
" (format (quote #t) L328 s5-2 (-> (the-as (array int64) gp-0) s5-2))\n" " (format (quote #t) L328 s5-2 (-> (the-as (array int64) gp-0) s5-2))\n"
" (set! s5-2 (+ s5-2 1))\n" " (set! s5-2 (+ s5-2 1))\n"
" )\n" " )\n"
@ -1261,7 +1261,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
" ((= v1-1 (quote uint64))\n" " ((= v1-1 (quote uint64))\n"
" (set! s5-3 0)\n" " (set! s5-3 0)\n"
" (while\n" " (while\n"
" (<.si s5-3 (-> gp-0 length))\n" " (< s5-3 (-> gp-0 length))\n"
" (format (quote #t) L327 s5-3 (-> (the-as (array uint64) gp-0) s5-3))\n" " (format (quote #t) L327 s5-3 (-> (the-as (array uint64) gp-0) s5-3))\n"
" (set! s5-3 (+ s5-3 1))\n" " (set! s5-3 (+ s5-3 1))\n"
" )\n" " )\n"
@ -1271,7 +1271,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
" ((= v1-1 (quote int8))\n" " ((= v1-1 (quote int8))\n"
" (set! s5-4 0)\n" " (set! s5-4 0)\n"
" (while\n" " (while\n"
" (<.si s5-4 (-> gp-0 length))\n" " (< s5-4 (-> gp-0 length))\n"
" (format (quote #t) L328 s5-4 (-> (the-as (array int8) gp-0) s5-4))\n" " (format (quote #t) L328 s5-4 (-> (the-as (array int8) gp-0) s5-4))\n"
" (set! s5-4 (+ s5-4 1))\n" " (set! s5-4 (+ s5-4 1))\n"
" )\n" " )\n"
@ -1281,7 +1281,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
" ((= v1-1 (quote uint8))\n" " ((= v1-1 (quote uint8))\n"
" (set! s5-5 0)\n" " (set! s5-5 0)\n"
" (while\n" " (while\n"
" (<.si s5-5 (-> gp-0 length))\n" " (< s5-5 (-> gp-0 length))\n"
" (format (quote #t) L328 s5-5 (-> (the-as (array int8) gp-0) s5-5))\n" " (format (quote #t) L328 s5-5 (-> (the-as (array int8) gp-0) s5-5))\n"
" (set! s5-5 (+ s5-5 1))\n" " (set! s5-5 (+ s5-5 1))\n"
" )\n" " )\n"
@ -1291,7 +1291,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
" ((= v1-1 (quote int16))\n" " ((= v1-1 (quote int16))\n"
" (set! s5-6 0)\n" " (set! s5-6 0)\n"
" (while\n" " (while\n"
" (<.si s5-6 (-> gp-0 length))\n" " (< s5-6 (-> gp-0 length))\n"
" (format (quote #t) L328 s5-6 (-> (the-as (array int16) gp-0) s5-6))\n" " (format (quote #t) L328 s5-6 (-> (the-as (array int16) gp-0) s5-6))\n"
" (set! s5-6 (+ s5-6 1))\n" " (set! s5-6 (+ s5-6 1))\n"
" )\n" " )\n"
@ -1301,7 +1301,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
" ((= v1-1 (quote uint16))\n" " ((= v1-1 (quote uint16))\n"
" (set! s5-7 0)\n" " (set! s5-7 0)\n"
" (while\n" " (while\n"
" (<.si s5-7 (-> gp-0 length))\n" " (< s5-7 (-> gp-0 length))\n"
" (format (quote #t) L328 s5-7 (-> (the-as (array uint16) gp-0) s5-7))\n" " (format (quote #t) L328 s5-7 (-> (the-as (array uint16) gp-0) s5-7))\n"
" (set! s5-7 (+ s5-7 1))\n" " (set! s5-7 (+ s5-7 1))\n"
" )\n" " )\n"
@ -1314,7 +1314,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
" (v1-40\n" " (v1-40\n"
" (set! s5-8 0)\n" " (set! s5-8 0)\n"
" (while\n" " (while\n"
" (<.si s5-8 (-> gp-0 length))\n" " (< s5-8 (-> gp-0 length))\n"
" (set! t9-14 format)\n" " (set! t9-14 format)\n"
" (set! a0-25 (quote #t))\n" " (set! a0-25 (quote #t))\n"
" (set! a1-15 L327)\n" " (set! a1-15 L327)\n"
@ -1322,7 +1322,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
" (set!\n" " (set!\n"
" v1-42\n" " v1-42\n"
" (+\n" " (+\n"
" (sll (the-as uint s5-8) 4)\n" " (shl s5-8 4)\n"
" (the-as int (the-as (array uint128) gp-0))\n" " (the-as int (the-as (array uint128) gp-0))\n"
" )\n" " )\n"
" )\n" " )\n"
@ -1336,7 +1336,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
" (else\n" " (else\n"
" (set! s5-9 0)\n" " (set! s5-9 0)\n"
" (while\n" " (while\n"
" (<.si s5-9 (-> gp-0 length))\n" " (< s5-9 (-> gp-0 length))\n"
" (format (quote #t) L328 s5-9 (-> gp-0 s5-9))\n" " (format (quote #t) L328 s5-9 (-> gp-0 s5-9))\n"
" (set! s5-9 (+ s5-9 1))\n" " (set! s5-9 (+ s5-9 1))\n"
" )\n" " )\n"
@ -1353,7 +1353,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
" ((= (-> gp-0 content-type) float)\n" " ((= (-> gp-0 content-type) float)\n"
" (set! s5-10 0)\n" " (set! s5-10 0)\n"
" (while\n" " (while\n"
" (<.si s5-10 (-> gp-0 length))\n" " (< s5-10 (-> gp-0 length))\n"
" (format (quote #t) L326 s5-10 (-> (the-as (array float) gp-0) s5-10))\n" " (format (quote #t) L326 s5-10 (-> (the-as (array float) gp-0) s5-10))\n"
" (set! s5-10 (+ s5-10 1))\n" " (set! s5-10 (+ s5-10 1))\n"
" )\n" " )\n"
@ -1363,7 +1363,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
" (else\n" " (else\n"
" (set! s5-11 0)\n" " (set! s5-11 0)\n"
" (while\n" " (while\n"
" (<.si s5-11 (-> gp-0 length))\n" " (< s5-11 (-> gp-0 length))\n"
" (format (quote #t) L325 s5-11 (-> (the-as (array basic) gp-0) s5-11))\n" " (format (quote #t) L325 s5-11 (-> (the-as (array basic) gp-0) s5-11))\n"
" (set! s5-11 (+ s5-11 1))\n" " (set! s5-11 (+ s5-11 1))\n"
" )\n" " )\n"
@ -1932,13 +1932,16 @@ TEST_F(FormRegressionTest, ExprValid) {
" (set! s3-0 a1-0)\n" " (set! s3-0 a1-0)\n"
" (set! s4-0 a2-0)\n" " (set! s4-0 a2-0)\n"
" (set! s5-0 t0-0)\n" " (set! s5-0 t0-0)\n"
" (and (>=.ui gp-0 __START-OF-TABLE__) (begin (<.ui gp-0 134217728) v1-1))\n" " (and\n"
" (>= (the-as uint gp-0) (the-as uint __START-OF-TABLE__))\n"
" (< (the-as uint gp-0) (the-as uint 134217728))\n"
" )\n"
" )\n" " )\n"
" )\n" " )\n"
" (cond\n" " (cond\n"
" ((not s3-0)\n" " ((not s3-0)\n"
" (cond\n" " (cond\n"
" ((nonzero? (logand gp-0 3))\n" " ((nonzero? (logand (the-as int gp-0) 3))\n"
" (if s4-0 (set! v1-4 (format s5-0 L321 gp-0 s4-0)))\n" " (if s4-0 (set! v1-4 (format s5-0 L321 gp-0 s4-0)))\n"
" (quote #f)\n" " (quote #f)\n"
" )\n" " )\n"
@ -1946,18 +1949,22 @@ TEST_F(FormRegressionTest, ExprValid) {
" (else (quote #t))\n" " (else (quote #t))\n"
" )\n" " )\n"
" )\n" " )\n"
" ((and a3-2 (not gp-0)) (quote #t))\n" " ((and a3-0 (not gp-0)) (quote #t))\n"
" (else\n" " (else\n"
" (cond\n" " (cond\n"
" ((= s3-0 structure)\n" " ((= s3-0 structure)\n"
" (cond\n" " (cond\n"
" ((nonzero? (logand gp-0 15))\n" " ((nonzero? (logand (the-as int gp-0) 15))\n"
" (if s4-0 (set! v1-8 (format s5-0 L319 gp-0 s4-0 s3-0)))\n" " (if s4-0 (set! v1-8 (format s5-0 L319 gp-0 s4-0 s3-0)))\n"
" (quote #f)\n" " (quote #f)\n"
" )\n" " )\n"
" ((or\n" " ((or\n"
" (not v1-1)\n" " (not v1-1)\n"
" (begin (set! v1-10 32768) (.daddu v1-11 v1-10 s7-0) (<.ui gp-0 v1-11))\n" " (begin\n"
" (set! v1-10 32768)\n"
" (.daddu v1-11 v1-10 s7-0)\n"
" (< (the-as uint gp-0) (the-as uint v1-11))\n"
" )\n"
" )\n" " )\n"
" (if s4-0 (set! v1-13 (format s5-0 L318 gp-0 s4-0 s3-0)))\n" " (if s4-0 (set! v1-13 (format s5-0 L318 gp-0 s4-0 s3-0)))\n"
" (quote #f)\n" " (quote #f)\n"
@ -1967,7 +1974,7 @@ TEST_F(FormRegressionTest, ExprValid) {
" )\n" " )\n"
" ((= s3-0 pair)\n" " ((= s3-0 pair)\n"
" (cond\n" " (cond\n"
" ((!= (logand gp-0 7) 2)\n" " ((!= (logand (the-as int gp-0) 7) 2)\n"
" (if s4-0 (set! v1-15 (format s5-0 L319 gp-0 s4-0 s3-0)))\n" " (if s4-0 (set! v1-15 (format s5-0 L319 gp-0 s4-0 s3-0)))\n"
" (quote #f)\n" " (quote #f)\n"
" )\n" " )\n"
@ -1980,14 +1987,14 @@ TEST_F(FormRegressionTest, ExprValid) {
" )\n" " )\n"
" ((= s3-0 binteger)\n" " ((= s3-0 binteger)\n"
" (cond\n" " (cond\n"
" ((zero? (logand gp-0 7)) (quote #t))\n" " ((zero? (logand (the-as int gp-0) 7)) (quote #t))\n"
" (else\n" " (else\n"
" (if s4-0 (set! v1-20 (format s5-0 L319 gp-0 s4-0 s3-0)))\n" " (if s4-0 (set! v1-20 (format s5-0 L319 gp-0 s4-0 s3-0)))\n"
" (quote #f)\n" " (quote #f)\n"
" )\n" " )\n"
" )\n" " )\n"
" )\n" " )\n"
" ((!= (logand gp-0 7) 4)\n" " ((!= (logand (the-as int gp-0) 7) 4)\n"
" (if s4-0 (set! v1-22 (format s5-0 L319 gp-0 s4-0 s3-0)))\n" " (if s4-0 (set! v1-22 (format s5-0 L319 gp-0 s4-0 s3-0)))\n"
" (quote #f)\n" " (quote #f)\n"
" )\n" " )\n"
@ -2020,14 +2027,18 @@ TEST_F(FormRegressionTest, ExprValid) {
" (set! v1-43 32768)\n" " (set! v1-43 32768)\n"
" (.daddu v1-44 v1-43 s7-0)\n" " (.daddu v1-44 v1-43 s7-0)\n"
" (cond\n" " (cond\n"
" ((>=.ui gp-0 v1-44)\n" " ((>= (the-as uint gp-0) (the-as uint v1-44))\n"
" (if s4-0 (set! v1-46 (format s5-0 L315 gp-0 s4-0 s3-0)))\n" " (if s4-0 (set! v1-46 (format s5-0 L315 gp-0 s4-0 s3-0)))\n"
" (quote #f)\n" " (quote #f)\n"
" )\n" " )\n"
" (else (quote #t))\n" " (else (quote #t))\n"
" )\n" " )\n"
" )\n" " )\n"
" ((begin (set! v1-47 32768) (.daddu v1-48 v1-47 s7-0) (<.ui gp-0 v1-48))\n" " ((begin\n"
" (set! v1-47 32768)\n"
" (.daddu v1-48 v1-47 s7-0)\n"
" (< (the-as uint gp-0) (the-as uint v1-48))\n"
" )\n"
" (if s4-0 (set! v1-50 (format s5-0 L314 gp-0 s4-0 s3-0)))\n" " (if s4-0 (set! v1-50 (format s5-0 L314 gp-0 s4-0 s3-0)))\n"
" (quote #f)\n" " (quote #f)\n"
" )\n" " )\n"

View file

@ -1,8 +1,8 @@
(defun ash ((value integer) (shift-amount integer)) (defun ash ((value integer) (shift-amount integer))
(declare (inline)) (declare (inline))
(if (> shift-amount 0) (if (> shift-amount 0)
(shlv value shift-amount) (shl value shift-amount)
(sarv value (- shift-amount)) (sar value (- shift-amount))
) )
) )

View file

@ -1,2 +1,7 @@
(+ (shlv 2 3) (shlv 1 0) (shlv 0 4) (shrv 2 3) (shrv 10 2) (shlv -2 1) (sarv -16 2))
(let ((one 1)
(two 2))
(+ (shl 2 3) (shl 1 0) (shl 0 4) (shr 2 3) (shr 10 two) (shl -2 one) (sar -16 two))
)
;; 16 1 0 0 2 -4 -4 ;; 16 1 0 0 2 -4 -4

View file

@ -543,7 +543,7 @@ TEST_P(VectorFloatParameterizedTestFixtureWithRunner, VF_ABS_DEST) {
testCase.operation = [](float x, float y) { testCase.operation = [](float x, float y) {
// Avoid compiler warnings for unused variable, making a varient that accepts a lambda with only // Avoid compiler warnings for unused variable, making a varient that accepts a lambda with only
// 1 float is just unnecessary complexity // 1 float is just unnecessary complexity
y = 0; (void)y;
return fabs(x); return fabs(x);
}; };

View file

@ -28,7 +28,7 @@ int main(int argc, char** argv) {
// write files: // write files:
for (auto& entry : dgo.entries()) { for (auto& entry : dgo.entries()) {
file_util::write_binary_file(file_util::combine_path(out_path, entry.unique_name), file_util::write_binary_file(file_util::combine_path(out_path, entry.unique_name),
(void*)entry.data.data(), entry.data.size()); (const void*)entry.data.data(), entry.data.size());
} }
} }