mirror of
https://github.com/open-goal/jak-project.git
synced 2024-11-23 14:20:07 +00:00
[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:
parent
65206823ef
commit
ddffda1e8c
@ -70,7 +70,7 @@ bool create_dir_if_needed(const std::string& path) {
|
||||
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");
|
||||
if (!fp) {
|
||||
throw std::runtime_error("couldn't open file " + name);
|
||||
|
@ -12,7 +12,7 @@ namespace file_util {
|
||||
std::string get_project_path();
|
||||
std::string get_file_path(const std::vector<std::string>& input);
|
||||
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_text_file(const std::string& file_name, const std::string& text);
|
||||
std::vector<uint8_t> read_binary_file(const std::string& filename);
|
||||
|
@ -13,7 +13,7 @@
|
||||
namespace versions {
|
||||
// language version (OpenGOAL)
|
||||
constexpr s32 GOAL_VERSION_MAJOR = 0;
|
||||
constexpr s32 GOAL_VERSION_MINOR = 5;
|
||||
constexpr s32 GOAL_VERSION_MINOR = 6;
|
||||
|
||||
// these versions are from the game
|
||||
constexpr u32 ART_FILE_VERSION = 6;
|
||||
|
@ -355,10 +355,13 @@ class IR2_Condition {
|
||||
const SimpleAtom& src(int i) const { return m_src[i]; }
|
||||
ConditionElement* get_as_form(FormPool& pool, const Env& env, int my_idx) const;
|
||||
void collect_vars(VariableSet& vars) const;
|
||||
void make_flipped() { m_flipped_eval = true; }
|
||||
bool flipped() const { return m_flipped_eval; }
|
||||
|
||||
private:
|
||||
Kind m_kind = Kind::INVALID;
|
||||
SimpleAtom m_src[2];
|
||||
bool m_flipped_eval = false;
|
||||
};
|
||||
|
||||
std::string get_condition_kind_name(IR2_Condition::Kind kind);
|
||||
|
@ -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++) {
|
||||
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 {
|
||||
@ -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 {
|
||||
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;
|
||||
if (get_as_reg_offset(m_addr, &ro)) {
|
||||
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);
|
||||
|
||||
auto load = pool.alloc_single_element_form<ArrayFieldAccess>(nullptr, ro.var, tokens,
|
||||
input_type.get_multiplier());
|
||||
// we pass along the register offset because code generation seems to be a bit
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
@ -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()));
|
||||
}
|
||||
|
||||
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;
|
||||
for (auto& entry : entries) {
|
||||
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;
|
||||
for (auto& x : vars) {
|
||||
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;
|
||||
}
|
||||
count++;
|
||||
|
@ -356,8 +356,9 @@ void AtomicOpElement::get_modified_regs(RegSet& regs) const {
|
||||
ConditionElement::ConditionElement(IR2_Condition::Kind kind,
|
||||
std::optional<SimpleAtom> src0,
|
||||
std::optional<SimpleAtom> src1,
|
||||
RegSet consumed)
|
||||
: m_kind(kind), m_consumed(std::move(consumed)) {
|
||||
RegSet consumed,
|
||||
bool flipped)
|
||||
: m_kind(kind), m_consumed(std::move(consumed)), m_flipped(flipped) {
|
||||
m_src[0] = src0;
|
||||
m_src[1] = src1;
|
||||
}
|
||||
@ -768,7 +769,7 @@ goos::Object CondNoElseElement::to_form(const Env& env) const {
|
||||
for (auto& e : entries) {
|
||||
std::vector<goos::Object> entry;
|
||||
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));
|
||||
}
|
||||
return pretty_print::build_list(list);
|
||||
@ -1067,10 +1068,12 @@ std::string fixed_operator_to_string(FixedOperatorKind kind) {
|
||||
return "lognor";
|
||||
case FixedOperatorKind::LOGNOT:
|
||||
return "lognot";
|
||||
case FixedOperatorKind::SLL:
|
||||
return "sll";
|
||||
case FixedOperatorKind::SRL:
|
||||
return "srl";
|
||||
case FixedOperatorKind::SHL:
|
||||
return "shl";
|
||||
case FixedOperatorKind::SHR:
|
||||
return "shr";
|
||||
case FixedOperatorKind::SAR:
|
||||
return "sar";
|
||||
case FixedOperatorKind::CAR:
|
||||
return "car";
|
||||
case FixedOperatorKind::CDR:
|
||||
@ -1079,6 +1082,21 @@ std::string fixed_operator_to_string(FixedOperatorKind kind) {
|
||||
return "new";
|
||||
case FixedOperatorKind::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:
|
||||
assert(false);
|
||||
}
|
||||
@ -1323,8 +1341,12 @@ void DynamicMethodAccess::get_modified_regs(RegSet&) const {}
|
||||
/////////////////////////////
|
||||
ArrayFieldAccess::ArrayFieldAccess(Variable source,
|
||||
const std::vector<DerefToken>& deref_tokens,
|
||||
int expected_stride)
|
||||
: m_source(source), m_deref_tokens(deref_tokens), m_expected_stride(expected_stride) {}
|
||||
int 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 {
|
||||
std::vector<goos::Object> elts;
|
||||
|
@ -30,13 +30,15 @@ class FormElement {
|
||||
virtual void collect_vars(VariableSet& vars) const = 0;
|
||||
virtual void get_modified_regs(RegSet& regs) const = 0;
|
||||
std::string to_string(const Env& env) const;
|
||||
bool has_side_effects();
|
||||
|
||||
// push the result of this operation to the operation stack
|
||||
virtual void push_to_stack(const Env& env, FormPool& pool, FormStack& stack);
|
||||
virtual void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result);
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects);
|
||||
|
||||
protected:
|
||||
friend class Form;
|
||||
@ -59,53 +61,62 @@ class SimpleExpressionElement : public FormElement {
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
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 update_from_stack_identity(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result);
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects);
|
||||
void update_from_stack_gpr_to_fpr(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result);
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects);
|
||||
void update_from_stack_fpr_to_gpr(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result);
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects);
|
||||
void update_from_stack_div_s(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result);
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects);
|
||||
void update_from_stack_add_i(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result);
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects);
|
||||
void update_from_stack_mult_si(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result);
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects);
|
||||
void update_from_stack_lognot(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result);
|
||||
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects);
|
||||
void update_from_stack_force_si_2(const Env& env,
|
||||
FixedOperatorKind kind,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result);
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects);
|
||||
void update_from_stack_force_ui_2(const Env& env,
|
||||
FixedOperatorKind kind,
|
||||
FormPool& pool,
|
||||
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,
|
||||
FixedOperatorKind kind,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result);
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects);
|
||||
|
||||
const SimpleExpression& expr() const { return m_expr; }
|
||||
|
||||
@ -151,7 +162,8 @@ class LoadSourceElement : public FormElement {
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result) override;
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects) override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
|
||||
private:
|
||||
@ -194,7 +206,8 @@ class SetVarElement : public FormElement {
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result) override;
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects) override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
|
||||
const Variable& dst() const { return m_dst; }
|
||||
@ -259,7 +272,8 @@ class ConditionElement : public FormElement {
|
||||
ConditionElement(IR2_Condition::Kind kind,
|
||||
std::optional<SimpleAtom> src0,
|
||||
std::optional<SimpleAtom> src1,
|
||||
RegSet consumed);
|
||||
RegSet consumed,
|
||||
bool flipped);
|
||||
goos::Object to_form(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;
|
||||
@ -269,15 +283,22 @@ class ConditionElement : public FormElement {
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
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 invert();
|
||||
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:
|
||||
IR2_Condition::Kind m_kind;
|
||||
std::optional<SimpleAtom> m_src[2];
|
||||
RegSet m_consumed;
|
||||
bool m_flipped;
|
||||
};
|
||||
|
||||
/*!
|
||||
@ -293,7 +314,8 @@ class FunctionCallElement : public FormElement {
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
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 get_modified_regs(RegSet& regs) const override;
|
||||
|
||||
@ -395,6 +417,7 @@ class CondWithElseElement : public FormElement {
|
||||
};
|
||||
std::vector<Entry> entries;
|
||||
Form* else_ir = nullptr;
|
||||
bool already_rewritten = false;
|
||||
CondWithElseElement(std::vector<Entry> _entries, Form* _else_ir)
|
||||
: entries(std::move(_entries)), else_ir(_else_ir) {}
|
||||
goos::Object to_form(const Env& env) const override;
|
||||
@ -481,6 +504,7 @@ class ShortCircuitElement : public FormElement {
|
||||
Variable final_result;
|
||||
std::vector<Entry> entries;
|
||||
std::optional<bool> used_as_value = std::nullopt;
|
||||
bool already_rewritten = false;
|
||||
|
||||
explicit ShortCircuitElement(std::vector<Entry> _entries) : entries(std::move(_entries)) {}
|
||||
goos::Object to_form(const Env& env) const override;
|
||||
@ -491,7 +515,8 @@ class ShortCircuitElement : public FormElement {
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result) override;
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects) override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
};
|
||||
|
||||
@ -511,6 +536,7 @@ class CondNoElseElement : public FormElement {
|
||||
};
|
||||
Variable final_destination;
|
||||
bool used_as_value = false;
|
||||
bool already_rewritten = false;
|
||||
std::vector<Entry> entries;
|
||||
explicit CondNoElseElement(std::vector<Entry> _entries) : entries(std::move(_entries)) {}
|
||||
goos::Object to_form(const Env& env) const override;
|
||||
@ -534,7 +560,8 @@ class AbsElement : public FormElement {
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result) override;
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects) override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
Variable source;
|
||||
RegSet consumed;
|
||||
@ -563,7 +590,8 @@ class AshElement : public FormElement {
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result) override;
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects) override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
};
|
||||
|
||||
@ -584,7 +612,8 @@ class TypeOfElement : public FormElement {
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
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,
|
||||
FormPool& pool,
|
||||
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 push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
|
||||
const GenericOperator& op() const { return m_head; }
|
||||
@ -704,7 +734,8 @@ class CastElement : public FormElement {
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result) override;
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects) override;
|
||||
const TypeSpec& type() const { return m_type; }
|
||||
const Form* source() const { return m_source; }
|
||||
Form* source() { return m_source; }
|
||||
@ -756,7 +787,8 @@ class DerefElement : public FormElement {
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result) override;
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects) override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
|
||||
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,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result) override;
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects) override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
|
||||
private:
|
||||
@ -791,7 +824,8 @@ class ArrayFieldAccess : public FormElement {
|
||||
public:
|
||||
ArrayFieldAccess(Variable source,
|
||||
const std::vector<DerefToken>& deref_tokens,
|
||||
int expected_stride);
|
||||
int expected_stride,
|
||||
int constant_offset);
|
||||
goos::Object to_form(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
@ -799,13 +833,15 @@ class ArrayFieldAccess : public FormElement {
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result) override;
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects) override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
|
||||
private:
|
||||
Variable m_source;
|
||||
std::vector<DerefToken> m_deref_tokens;
|
||||
int m_expected_stride = -1;
|
||||
int m_constant_offset = -1;
|
||||
};
|
||||
|
||||
class GetMethodElement : public FormElement {
|
||||
@ -888,7 +924,11 @@ class Form {
|
||||
void apply_form(const std::function<void(Form*)>& f);
|
||||
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;
|
||||
|
||||
FormElement* parent_element = nullptr;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -26,6 +26,7 @@ std::string FormStack::print(const Env& env) {
|
||||
}
|
||||
|
||||
void FormStack::push_value_to_reg(Variable var, Form* value, bool sequence_point) {
|
||||
assert(value);
|
||||
StackEntry entry;
|
||||
entry.active = true; // by default, we should display everything!
|
||||
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,
|
||||
const Variable& src,
|
||||
Form* src_as_form) {
|
||||
assert(src_as_form);
|
||||
StackEntry entry;
|
||||
entry.active = true;
|
||||
entry.sequence_point = false;
|
||||
@ -64,8 +66,11 @@ void FormStack::push_form_element(FormElement* elt, bool sequence_point) {
|
||||
m_stack.push_back(entry);
|
||||
}
|
||||
|
||||
Form* FormStack::pop_reg(const Variable& var, const RegSet& barrier, const Env& env) {
|
||||
return pop_reg(var.reg(), barrier, env);
|
||||
Form* FormStack::pop_reg(const Variable& var,
|
||||
const RegSet& barrier,
|
||||
const Env& env,
|
||||
bool allow_side_effects) {
|
||||
return pop_reg(var.reg(), barrier, env, allow_side_effects);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -77,22 +82,30 @@ bool nonempty_intersection(const RegSet& a, const RegSet& b) {
|
||||
}
|
||||
} // 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.
|
||||
RegSet modified;
|
||||
for (size_t i = m_stack.size(); i-- > 0;) {
|
||||
auto& entry = m_stack.at(i);
|
||||
if (entry.active) {
|
||||
if (entry.destination->reg() == reg) {
|
||||
if (entry.destination.has_value() && entry.destination->reg() == reg) {
|
||||
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)) {
|
||||
// violating the barrier registers.
|
||||
return nullptr;
|
||||
}
|
||||
entry.active = false;
|
||||
assert(entry.source);
|
||||
if (entry.non_seq_source.has_value()) {
|
||||
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) {
|
||||
return result;
|
||||
}
|
||||
@ -108,9 +121,17 @@ Form* FormStack::pop_reg(Register reg, const RegSet& barrier, const Env& env) {
|
||||
if (entry.source) {
|
||||
assert(!entry.elt);
|
||||
entry.source->get_modified_regs(modified);
|
||||
if (!allow_side_effects) {
|
||||
// shouldn't allow skipping past a set! (may be too conservative?)
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
assert(entry.elt);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,11 @@ class FormStack {
|
||||
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_form_element(FormElement* elt, bool sequence_point);
|
||||
Form* pop_reg(const Variable& var, const RegSet& barrier, const Env& env);
|
||||
Form* pop_reg(Register reg, const RegSet& barrier, const Env& env);
|
||||
Form* pop_reg(const Variable& var,
|
||||
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();
|
||||
std::vector<FormElement*> rewrite(FormPool& pool);
|
||||
std::vector<FormElement*> rewrite_to_get_var(FormPool& pool, const Variable& var, const Env& env);
|
||||
|
@ -105,12 +105,20 @@ enum class FixedOperatorKind {
|
||||
LOGXOR,
|
||||
LOGNOR,
|
||||
LOGNOT,
|
||||
SLL,
|
||||
SRL,
|
||||
SHL,
|
||||
SHR,
|
||||
SAR,
|
||||
CAR,
|
||||
CDR,
|
||||
NEW,
|
||||
OBJECT_NEW,
|
||||
TYPE_NEW,
|
||||
LT,
|
||||
GT,
|
||||
LEQ,
|
||||
GEQ,
|
||||
EQ,
|
||||
NEQ,
|
||||
INVALID
|
||||
};
|
||||
|
||||
|
@ -779,6 +779,7 @@ std::unique_ptr<AtomicOp> convert_bne_2(const Instruction& i0,
|
||||
} else {
|
||||
condition = IR2_Condition(IR2_Condition::Kind::NOT_EQUAL, make_src_atom(s0, idx),
|
||||
make_src_atom(s1, idx));
|
||||
condition.make_flipped();
|
||||
}
|
||||
return make_branch(condition, i1, likely, dest, idx);
|
||||
}
|
||||
@ -809,6 +810,7 @@ std::unique_ptr<AtomicOp> convert_beq_2(const Instruction& i0,
|
||||
} else {
|
||||
condition =
|
||||
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);
|
||||
}
|
||||
|
@ -1065,7 +1065,7 @@ Form* cfg_to_ir(FormPool& pool, const Function& f, const CfgVtx* vtx) {
|
||||
} else if (dynamic_cast<const InfiniteLoopBlock*>(vtx)) {
|
||||
auto wvtx = dynamic_cast<const InfiniteLoopBlock*>(vtx);
|
||||
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,
|
||||
cfg_to_ir(pool, f, wvtx->block));
|
||||
clean_up_infinite_while_loop(pool,
|
||||
|
@ -436,6 +436,23 @@ void SSA::remap() {
|
||||
}
|
||||
};
|
||||
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) {
|
||||
assert(block.phis.empty());
|
||||
for (auto& instr : block.ins) {
|
||||
|
@ -112,4 +112,7 @@
|
||||
- Fixed bug where `(-> obj type)` caused a compiler error when `obj` had compile time type of `array` (the fancy boxed array)
|
||||
- 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...)`
|
||||
- `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.
|
||||
|
@ -47,7 +47,7 @@
|
||||
|
||||
(defun log2 ((x int))
|
||||
"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))
|
||||
@ -139,7 +139,7 @@
|
||||
(set! (-> *random-generator* seed) #x666EDD1E)
|
||||
|
||||
(defmacro sext32-64 (x)
|
||||
`(sarv (shlv ,x 32) 32)
|
||||
`(sar (shl ,x 32) 32)
|
||||
)
|
||||
|
||||
(defun rand-uint31-gen ((gen random-generator))
|
||||
@ -152,17 +152,17 @@
|
||||
;; mult3 v0, v1, a1
|
||||
(prod (imul64 16807 sd))
|
||||
;; mfhi v1
|
||||
(hi (shrv prod 32)) ;; sign extend this?
|
||||
(lo (sarv (shlv prod 32) 32))
|
||||
(hi (shr prod 32)) ;; sign extend this?
|
||||
(lo (sar (shl prod 32) 32))
|
||||
;; daddu v1, v1, v1
|
||||
(v1 (+ hi hi))
|
||||
;; srl a1, v0, 31
|
||||
(a1 (logand #xffffffff (shrv lo 31)))
|
||||
(a1 (logand #xffffffff (shr lo 31)))
|
||||
;; or v1, v1, a1
|
||||
;; daddu v0, v0 v1
|
||||
(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)
|
||||
result
|
||||
)
|
||||
|
@ -71,8 +71,8 @@
|
||||
;; these correspond to x86-64 variable shift instructions.
|
||||
;; the exact behavior of GOAL shifts (signed/unsigned) are unknown so for now shifts must
|
||||
;; be manually specified.
|
||||
(shlv value shift-amount)
|
||||
(sarv value (- shift-amount))
|
||||
(shl value shift-amount)
|
||||
(sar value (- shift-amount))
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -390,9 +390,6 @@ class Compiler {
|
||||
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_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_sar(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
Val* compile_shr(const goos::Object& form, const goos::Object& rest, Env* env);
|
||||
|
@ -148,9 +148,6 @@ static const std::unordered_map<
|
||||
{"*", &Compiler::compile_mul},
|
||||
{"imul64", &Compiler::compile_imul64},
|
||||
{"/", &Compiler::compile_div},
|
||||
{"shlv", &Compiler::compile_shlv},
|
||||
{"shrv", &Compiler::compile_shrv},
|
||||
{"sarv", &Compiler::compile_sarv},
|
||||
{"shl", &Compiler::compile_shl},
|
||||
{"shr", &Compiler::compile_shr},
|
||||
{"sar", &Compiler::compile_sar},
|
||||
|
@ -396,30 +396,6 @@ Val* Compiler::compile_div(const goos::Object& form, const goos::Object& rest, E
|
||||
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,
|
||||
const RegVal* in,
|
||||
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) {
|
||||
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 sa = args.unnamed.at(1).as_int();
|
||||
if (sa < 0 || sa > 64) {
|
||||
throw_compiler_error(form, "Cannot shift by more than 64, or by a negative amount.");
|
||||
int64_t constant_sa = -1;
|
||||
if (try_getting_constant_integer(args.unnamed.at(1), &constant_sa, env)) {
|
||||
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) {
|
||||
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 sa = args.unnamed.at(1).as_int();
|
||||
if (sa < 0 || sa > 64) {
|
||||
throw_compiler_error(form, "Cannot shift by more than 64, or by a negative amount");
|
||||
int64_t constant_sa = -1;
|
||||
if (try_getting_constant_integer(args.unnamed.at(1), &constant_sa, env)) {
|
||||
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) {
|
||||
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 sa = args.unnamed.at(1).as_int();
|
||||
if (sa < 0 || sa > 64) {
|
||||
throw_compiler_error(form, "Cannot shift by more than 64, or by a negative amount");
|
||||
int64_t constant_sa = -1;
|
||||
if (try_getting_constant_integer(args.unnamed.at(1), &constant_sa, env)) {
|
||||
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,
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "decompiler/analysis/reg_usage.h"
|
||||
#include "decompiler/analysis/cfg_builder.h"
|
||||
#include "decompiler/analysis/expression_build.h"
|
||||
#include "decompiler/analysis/final_output.h"
|
||||
#include "common/goos/PrettyPrinter.h"
|
||||
#include "decompiler/IR2/Form.h"
|
||||
#include "third-party/json.hpp"
|
||||
@ -180,6 +181,30 @@ void FormRegressionTest::test(const std::string& code,
|
||||
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(
|
||||
const std::string& in) {
|
||||
std::unordered_map<int, std::vector<decompiler::TypeHint>> out;
|
||||
|
@ -66,5 +66,13 @@ class FormRegressionTest : public ::testing::Test {
|
||||
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);
|
||||
};
|
@ -422,7 +422,7 @@ TEST_F(FormRegressionTest, ExprSizeOfType) {
|
||||
" daddiu sp, sp, 16";
|
||||
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, "");
|
||||
}
|
||||
|
||||
@ -469,6 +469,52 @@ TEST_F(FormRegressionTest, ExprBasicTypeP) {
|
||||
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) {
|
||||
std::string func =
|
||||
" sll r0, r0, 0\n"
|
||||
@ -616,7 +662,7 @@ TEST_F(FormRegressionTest, ExprRef) {
|
||||
"(begin\n"
|
||||
" (set! v1-0 0)\n"
|
||||
" (while\n"
|
||||
" (<.si v1-0 a1-0)\n"
|
||||
" (< v1-0 a1-0)\n"
|
||||
" (nop!)\n"
|
||||
" (nop!)\n"
|
||||
" (set! a0-0 (cdr a0-0))\n"
|
||||
@ -684,7 +730,7 @@ TEST_F(FormRegressionTest, ExprPairMethod4) {
|
||||
" (set! v0-0 1)\n"
|
||||
" (while\n"
|
||||
" (and (!= v1-1 '()) "
|
||||
" (<0.si (sll (the-as uint v1-1) 62))\n"
|
||||
" (< (shl (the-as int v1-1) 62) 0)\n"
|
||||
" )\n"
|
||||
" (set! v0-0 (+ v0-0 1))\n"
|
||||
" (set! v1-1 (cdr v1-1))\n"
|
||||
@ -1548,13 +1594,13 @@ TEST_F(FormRegressionTest, ExprSort) {
|
||||
" (set! s3-0 gp-0)\n"
|
||||
" (while\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"
|
||||
" (set! s2-0 (car s3-0))\n"
|
||||
" (set! s1-0 (car (cdr s3-0)))\n"
|
||||
" (set! v1-1 (s5-0 s2-0 s1-0))\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! (car s3-0) s1-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! v1-0 0)\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! a0-0 (+ a0-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! v1-0 0)\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! a0-0 (+ a0-0 (the-as uint 4)))\n"
|
||||
" (nop!)\n"
|
||||
@ -1940,7 +1986,7 @@ TEST_F(FormRegressionTest, ExprMemOr) {
|
||||
" (set! v0-0 a0-0)\n"
|
||||
" (set! v1-0 0)\n"
|
||||
" (while\n"
|
||||
" (<.si v1-0 a2-0)\n"
|
||||
" (< v1-0 a2-0)\n"
|
||||
" (set!\n"
|
||||
" (-> (the-as (pointer int8) a0-0))\n"
|
||||
" (logior\n"
|
||||
@ -2166,17 +2212,138 @@ TEST_F(FormRegressionTest, ExprPrintTreeBitmask) {
|
||||
" (set! s5-0 a1-0)\n"
|
||||
" (set! s4-0 0)\n"
|
||||
" (while\n"
|
||||
" (<.si s4-0 s5-0)\n"
|
||||
" (< s4-0 s5-0)\n"
|
||||
" (if\n"
|
||||
" (zero? (logand gp-0 1))\n"
|
||||
" (format (quote #t) L323)\n"
|
||||
" (format (quote #t) L322)\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"
|
||||
" )\n"
|
||||
" (set! v1-3 (quote #f))\n"
|
||||
" (quote #f)\n"
|
||||
" )";
|
||||
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\"]]]"));
|
||||
}
|
@ -547,7 +547,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
|
||||
" ((= v1-1 (quote int32))\n"
|
||||
" (set! s5-0 0)\n"
|
||||
" (while\n"
|
||||
" (<.si s5-0 (-> gp-0 length))\n"
|
||||
" (< s5-0 (-> gp-0 length))\n"
|
||||
" (format\n"
|
||||
" (quote #t)\n"
|
||||
" (if (zero? s5-0) L341 L340)\n"
|
||||
@ -561,7 +561,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
|
||||
" ((= v1-1 (quote uint32))\n"
|
||||
" (set! s5-1 0)\n"
|
||||
" (while\n"
|
||||
" (<.si s5-1 (-> gp-0 length))\n"
|
||||
" (< s5-1 (-> gp-0 length))\n"
|
||||
" (format\n"
|
||||
" (quote #t)\n"
|
||||
" (if (zero? s5-1) L341 L340)\n"
|
||||
@ -575,7 +575,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
|
||||
" ((= v1-1 (quote int64))\n"
|
||||
" (set! s5-2 0)\n"
|
||||
" (while\n"
|
||||
" (<.si s5-2 (-> gp-0 length))\n"
|
||||
" (< s5-2 (-> gp-0 length))\n"
|
||||
" (format\n"
|
||||
" (quote #t)\n"
|
||||
" (if (zero? s5-2) L341 L340)\n"
|
||||
@ -589,7 +589,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
|
||||
" ((= v1-1 (quote uint64))\n"
|
||||
" (set! s5-3 0)\n"
|
||||
" (while\n"
|
||||
" (<.si s5-3 (-> gp-0 length))\n"
|
||||
" (< s5-3 (-> gp-0 length))\n"
|
||||
" (format\n"
|
||||
" (quote #t)\n"
|
||||
" (if (zero? s5-3) L339 L338)\n"
|
||||
@ -603,7 +603,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
|
||||
" ((= v1-1 (quote int8))\n"
|
||||
" (set! s5-4 0)\n"
|
||||
" (while\n"
|
||||
" (<.si s5-4 (-> gp-0 length))\n"
|
||||
" (< s5-4 (-> gp-0 length))\n"
|
||||
" (format\n"
|
||||
" (quote #t)\n"
|
||||
" (if (zero? s5-4) L341 L340)\n"
|
||||
@ -617,7 +617,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
|
||||
" ((= v1-1 (quote uint8))\n"
|
||||
" (set! s5-5 0)\n"
|
||||
" (while\n"
|
||||
" (<.si s5-5 (-> gp-0 length))\n"
|
||||
" (< s5-5 (-> gp-0 length))\n"
|
||||
" (format\n"
|
||||
" (quote #t)\n"
|
||||
" (if (zero? s5-5) L341 L340)\n"
|
||||
@ -631,7 +631,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
|
||||
" ((= v1-1 (quote int16))\n"
|
||||
" (set! s5-6 0)\n"
|
||||
" (while\n"
|
||||
" (<.si s5-6 (-> gp-0 length))\n"
|
||||
" (< s5-6 (-> gp-0 length))\n"
|
||||
" (format\n"
|
||||
" (quote #t)\n"
|
||||
" (if (zero? s5-6) L341 L340)\n"
|
||||
@ -645,7 +645,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
|
||||
" ((= v1-1 (quote uint16))\n"
|
||||
" (set! s5-7 0)\n"
|
||||
" (while\n"
|
||||
" (<.si s5-7 (-> gp-0 length))\n"
|
||||
" (< s5-7 (-> gp-0 length))\n"
|
||||
" (format\n"
|
||||
" (quote #t)\n"
|
||||
" (if (zero? s5-7) L341 L340)\n"
|
||||
@ -662,14 +662,14 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
|
||||
" (v1-40\n"
|
||||
" (set! s5-8 0)\n"
|
||||
" (while\n"
|
||||
" (<.si s5-8 (-> gp-0 length))\n"
|
||||
" (< s5-8 (-> gp-0 length))\n"
|
||||
" (set! t9-10 format)\n"
|
||||
" (set! a0-21 (quote #t))\n"
|
||||
" (set! a1-11 (if (zero? s5-8) L339 L338))\n"
|
||||
" (set!\n"
|
||||
" v1-42\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"
|
||||
" )\n"
|
||||
" )\n"
|
||||
@ -683,7 +683,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
|
||||
" (else\n"
|
||||
" (set! s5-9 0)\n"
|
||||
" (while\n"
|
||||
" (<.si s5-9 (-> gp-0 length))\n"
|
||||
" (< s5-9 (-> gp-0 length))\n"
|
||||
" (format\n"
|
||||
" (quote #t)\n"
|
||||
" (if (zero? s5-9) L341 L340)\n"
|
||||
@ -704,7 +704,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) {
|
||||
" ((= (-> gp-0 content-type) float)\n"
|
||||
" (set! s5-10 0)\n"
|
||||
" (while\n"
|
||||
" (<.si s5-10 (-> gp-0 length))\n"
|
||||
" (< s5-10 (-> gp-0 length))\n"
|
||||
" (if\n"
|
||||
" (zero? 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"
|
||||
" (set! s5-11 0)\n"
|
||||
" (while\n"
|
||||
" (<.si s5-11 (-> gp-0 length))\n"
|
||||
" (< s5-11 (-> gp-0 length))\n"
|
||||
" (if\n"
|
||||
" (zero? 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"
|
||||
" (set! s5-0 0)\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"
|
||||
" (set! s5-0 (+ s5-0 1))\n"
|
||||
" )\n"
|
||||
@ -1241,7 +1241,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
|
||||
" ((= v1-1 (quote uint32))\n"
|
||||
" (set! s5-1 0)\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"
|
||||
" (set! s5-1 (+ s5-1 1))\n"
|
||||
" )\n"
|
||||
@ -1251,7 +1251,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
|
||||
" ((= v1-1 (quote int64))\n"
|
||||
" (set! s5-2 0)\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"
|
||||
" (set! s5-2 (+ s5-2 1))\n"
|
||||
" )\n"
|
||||
@ -1261,7 +1261,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
|
||||
" ((= v1-1 (quote uint64))\n"
|
||||
" (set! s5-3 0)\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"
|
||||
" (set! s5-3 (+ s5-3 1))\n"
|
||||
" )\n"
|
||||
@ -1271,7 +1271,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
|
||||
" ((= v1-1 (quote int8))\n"
|
||||
" (set! s5-4 0)\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"
|
||||
" (set! s5-4 (+ s5-4 1))\n"
|
||||
" )\n"
|
||||
@ -1281,7 +1281,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
|
||||
" ((= v1-1 (quote uint8))\n"
|
||||
" (set! s5-5 0)\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"
|
||||
" (set! s5-5 (+ s5-5 1))\n"
|
||||
" )\n"
|
||||
@ -1291,7 +1291,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
|
||||
" ((= v1-1 (quote int16))\n"
|
||||
" (set! s5-6 0)\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"
|
||||
" (set! s5-6 (+ s5-6 1))\n"
|
||||
" )\n"
|
||||
@ -1301,7 +1301,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
|
||||
" ((= v1-1 (quote uint16))\n"
|
||||
" (set! s5-7 0)\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"
|
||||
" (set! s5-7 (+ s5-7 1))\n"
|
||||
" )\n"
|
||||
@ -1314,7 +1314,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
|
||||
" (v1-40\n"
|
||||
" (set! s5-8 0)\n"
|
||||
" (while\n"
|
||||
" (<.si s5-8 (-> gp-0 length))\n"
|
||||
" (< s5-8 (-> gp-0 length))\n"
|
||||
" (set! t9-14 format)\n"
|
||||
" (set! a0-25 (quote #t))\n"
|
||||
" (set! a1-15 L327)\n"
|
||||
@ -1322,7 +1322,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
|
||||
" (set!\n"
|
||||
" v1-42\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"
|
||||
" )\n"
|
||||
" )\n"
|
||||
@ -1336,7 +1336,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
|
||||
" (else\n"
|
||||
" (set! s5-9 0)\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"
|
||||
" (set! s5-9 (+ s5-9 1))\n"
|
||||
" )\n"
|
||||
@ -1353,7 +1353,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
|
||||
" ((= (-> gp-0 content-type) float)\n"
|
||||
" (set! s5-10 0)\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"
|
||||
" (set! s5-10 (+ s5-10 1))\n"
|
||||
" )\n"
|
||||
@ -1363,7 +1363,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) {
|
||||
" (else\n"
|
||||
" (set! s5-11 0)\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"
|
||||
" (set! s5-11 (+ s5-11 1))\n"
|
||||
" )\n"
|
||||
@ -1932,13 +1932,16 @@ TEST_F(FormRegressionTest, ExprValid) {
|
||||
" (set! s3-0 a1-0)\n"
|
||||
" (set! s4-0 a2-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"
|
||||
" (cond\n"
|
||||
" ((not s3-0)\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"
|
||||
" (quote #f)\n"
|
||||
" )\n"
|
||||
@ -1946,18 +1949,22 @@ TEST_F(FormRegressionTest, ExprValid) {
|
||||
" (else (quote #t))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" ((and a3-2 (not gp-0)) (quote #t))\n"
|
||||
" ((and a3-0 (not gp-0)) (quote #t))\n"
|
||||
" (else\n"
|
||||
" (cond\n"
|
||||
" ((= s3-0 structure)\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"
|
||||
" (quote #f)\n"
|
||||
" )\n"
|
||||
" ((or\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"
|
||||
" (if s4-0 (set! v1-13 (format s5-0 L318 gp-0 s4-0 s3-0)))\n"
|
||||
" (quote #f)\n"
|
||||
@ -1967,7 +1974,7 @@ TEST_F(FormRegressionTest, ExprValid) {
|
||||
" )\n"
|
||||
" ((= s3-0 pair)\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"
|
||||
" (quote #f)\n"
|
||||
" )\n"
|
||||
@ -1980,14 +1987,14 @@ TEST_F(FormRegressionTest, ExprValid) {
|
||||
" )\n"
|
||||
" ((= s3-0 binteger)\n"
|
||||
" (cond\n"
|
||||
" ((zero? (logand gp-0 7)) (quote #t))\n"
|
||||
" ((zero? (logand (the-as int gp-0) 7)) (quote #t))\n"
|
||||
" (else\n"
|
||||
" (if s4-0 (set! v1-20 (format s5-0 L319 gp-0 s4-0 s3-0)))\n"
|
||||
" (quote #f)\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"
|
||||
" (quote #f)\n"
|
||||
" )\n"
|
||||
@ -2020,14 +2027,18 @@ TEST_F(FormRegressionTest, ExprValid) {
|
||||
" (set! v1-43 32768)\n"
|
||||
" (.daddu v1-44 v1-43 s7-0)\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"
|
||||
" (quote #f)\n"
|
||||
" )\n"
|
||||
" (else (quote #t))\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"
|
||||
" (quote #f)\n"
|
||||
" )\n"
|
||||
|
@ -1,8 +1,8 @@
|
||||
(defun ash ((value integer) (shift-amount integer))
|
||||
(declare (inline))
|
||||
(if (> shift-amount 0)
|
||||
(shlv value shift-amount)
|
||||
(sarv value (- shift-amount))
|
||||
(shl value shift-amount)
|
||||
(sar value (- shift-amount))
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -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
|
@ -543,7 +543,7 @@ TEST_P(VectorFloatParameterizedTestFixtureWithRunner, VF_ABS_DEST) {
|
||||
testCase.operation = [](float x, float y) {
|
||||
// Avoid compiler warnings for unused variable, making a varient that accepts a lambda with only
|
||||
// 1 float is just unnecessary complexity
|
||||
y = 0;
|
||||
(void)y;
|
||||
return fabs(x);
|
||||
};
|
||||
|
||||
|
@ -28,7 +28,7 @@ int main(int argc, char** argv) {
|
||||
// write files:
|
||||
for (auto& entry : dgo.entries()) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user