[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;
}
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);

View file

@ -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);

View file

@ -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;

View file

@ -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);

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++) {
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);
}
}

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()));
}
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++;

View file

@ -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;

View file

@ -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

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) {
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;
}
}
}
}

View file

@ -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);

View file

@ -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
};

View file

@ -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);
}

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)) {
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,

View file

@ -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) {

View file

@ -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.

View file

@ -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
)

View file

@ -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))
)
)

View file

@ -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);

View file

@ -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},

View file

@ -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,

View file

@ -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;

View file

@ -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);
};

View file

@ -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\"]]]"));
}

View file

@ -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"

View file

@ -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))
)
)

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

View file

@ -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);
};

View file

@ -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());
}
}