add stack var support

This commit is contained in:
water111
2026-04-13 15:26:20 -04:00
parent 5acb70ab4d
commit 06814108a4
8 changed files with 252 additions and 35 deletions
+5 -1
View File
@@ -843,9 +843,13 @@ FormElement* StackSpillLoadOp::get_as_form(FormPool& pool, const Env& env) const
if (kv != env.stack_slot_entries.end()) {
type = kv->second.typespec;
}
std::optional<TypeSpec> read_type;
if (env.has_type_analysis()) {
read_type = env.get_types_before_op(m_my_idx).get_slot(m_offset).typespec();
}
return pool.alloc_element<SetVarElement>(m_dst,
pool.alloc_single_element_form<StackSpillValueElement>(
nullptr, m_size, m_offset, m_is_signed),
nullptr, m_size, m_offset, m_is_signed, read_type),
true, type);
}
+75
View File
@@ -162,6 +162,10 @@ std::string Env::get_variable_name(const RegisterAccess& access) const {
}
std::string Env::get_variable_name_name_only(const RegisterAccess& access) const {
if (is_stack_slot_access(access)) {
return get_spill_slot_var_name(get_stack_slot_offset_from_access(access));
}
if (access.reg().get_kind() == Reg::FPR || access.reg().get_kind() == Reg::GPR) {
auto& var_info = m_var_names.lookup(access.reg(), access.idx(), access.mode());
return var_info.name();
@@ -172,6 +176,14 @@ std::string Env::get_variable_name_name_only(const RegisterAccess& access) const
}
VariableWithCast Env::get_variable_and_cast(const RegisterAccess& access) const {
if (is_stack_slot_access(access)) {
VariableWithCast result;
auto original_name = get_spill_slot_var_name(get_stack_slot_offset_from_access(access));
auto remapped = m_var_remap.find(original_name);
result.name = remapped != m_var_remap.end() ? remapped->second : original_name;
return result;
}
if (access.reg().get_kind() == Reg::FPR || access.reg().get_kind() == Reg::GPR) {
auto& var_info = m_var_names.lookup(access.reg(), access.idx(), access.mode());
// this is a bit of a confusing process. The first step is to grab the auto-generated name:
@@ -272,6 +284,10 @@ goos::Object Env::get_variable_name_with_cast(Register reg, int atomic_idx, Acce
}
std::optional<TypeSpec> Env::get_user_cast_for_access(const RegisterAccess& access) const {
if (is_stack_slot_access(access)) {
return {};
}
if (access.reg().get_kind() == Reg::FPR || access.reg().get_kind() == Reg::GPR) {
auto& var_info = m_var_names.lookup(access.reg(), access.idx(), access.mode());
std::string original_name = var_info.name();
@@ -310,6 +326,22 @@ std::optional<TypeSpec> Env::get_user_cast_for_access(const RegisterAccess& acce
* of the variable.
*/
TypeSpec Env::get_variable_type(const RegisterAccess& access, bool using_user_var_types) const {
if (is_stack_slot_access(access)) {
auto offset = get_stack_slot_offset_from_access(access);
auto it = stack_slot_entries.find(offset);
if (it != stack_slot_entries.end()) {
auto type_of_var = it->second.typespec;
if (using_user_var_types) {
auto retype_kv = m_var_retype.find(it->second.name());
if (retype_kv != m_var_retype.end()) {
type_of_var = retype_kv->second;
}
}
return type_of_var;
}
return TypeSpec("object");
}
if (access.reg().get_kind() == Reg::FPR || access.reg().get_kind() == Reg::GPR) {
auto& var_info = m_var_names.lookup(access.reg(), access.idx(), access.mode());
std::string original_name = var_info.name();
@@ -328,6 +360,37 @@ TypeSpec Env::get_variable_type(const RegisterAccess& access, bool using_user_va
}
}
TP_Type Env::get_variable_tp_type(const RegisterAccess& access, bool using_user_var_types) const {
if (is_stack_slot_access(access)) {
auto offset = get_stack_slot_offset_from_access(access);
auto it = stack_slot_entries.find(offset);
if (it != stack_slot_entries.end()) {
auto type_of_var = it->second.tp_type;
if (using_user_var_types) {
auto retype_kv = m_var_retype.find(it->second.name());
if (retype_kv != m_var_retype.end()) {
type_of_var = TP_Type::make_from_ts(retype_kv->second);
}
}
return type_of_var;
}
return TP_Type::make_from_ts(TypeSpec("object"));
}
if (access.reg().get_kind() == Reg::FPR || access.reg().get_kind() == Reg::GPR) {
auto& var_info = m_var_names.lookup(access.reg(), access.idx(), access.mode());
if (using_user_var_types) {
auto retype_kv = m_var_retype.find(var_info.name());
if (retype_kv != m_var_retype.end()) {
return TP_Type::make_from_ts(retype_kv->second);
}
}
return var_info.type;
}
throw std::runtime_error("TP types are not supported for this kind of register");
}
/*!
* Update the Env with the result of the type analysis pass.
*/
@@ -420,6 +483,9 @@ std::vector<VariableNames::VarInfo> Env::extract_visible_variables(
std::vector<std::pair<RegId, RegisterAccess>> vars;
for (auto& x : var_set) {
if (is_stack_slot_access(x)) {
continue;
}
if (x.reg().get_kind() == Reg::FPR || x.reg().get_kind() == Reg::GPR) {
vars.push_back(std::make_pair(get_program_var_id(x), x));
}
@@ -519,6 +585,9 @@ FunctionVariableDefinitions Env::local_var_type_list(const Form* top_level_form,
std::sort(spills.begin(), spills.end(),
[](const StackSpillEntry& a, const StackSpillEntry& b) { return a.offset < b.offset; });
for (auto& x : spills) {
if (m_vars_defined_in_let.find(x.name()) != m_vars_defined_in_let.end()) {
continue;
}
elts.push_back(pretty_print::build_list(x.name(), x.typespec.print()));
count++;
}
@@ -549,12 +618,18 @@ const UseDefInfo& Env::get_use_def_info(const RegisterAccess& ra) const {
}
void Env::disable_def(const RegisterAccess& access, DecompWarnings& warnings) {
if (is_stack_slot_access(access)) {
return;
}
if (has_local_vars()) {
m_var_names.disable_def(access, warnings);
}
}
void Env::disable_use(const RegisterAccess& access) {
if (is_stack_slot_access(access)) {
return;
}
if (has_local_vars()) {
m_var_names.disable_use(access);
}
+20
View File
@@ -44,6 +44,26 @@ struct StackSpillEntry {
}
};
inline bool is_stack_slot_access(const RegisterAccess& access) {
return access.reg() == Register(Reg::GPR, Reg::SP) && access.idx() < 0;
}
inline int get_stack_slot_offset_from_access(const RegisterAccess& access) {
ASSERT(is_stack_slot_access(access));
return -access.idx() - 1;
}
inline RegisterAccess make_stack_slot_access(int offset) {
return RegisterAccess(AccessMode::READ, Register(Reg::GPR, Reg::SP), -offset - 1, true);
}
inline bool same_expression_var(const RegisterAccess& a, const RegisterAccess& b) {
if (is_stack_slot_access(a) || is_stack_slot_access(b)) {
return a == b;
}
return a.reg() == b.reg();
}
struct FunctionVariableDefinitions {
std::optional<goos::Object> local_vars;
bool had_pp = false;
+18 -4
View File
@@ -7,6 +7,7 @@
#include "common/type_system/TypeSystem.h"
#include "common/util/print_float.h"
#include "decompiler/IR2/Env.h"
#include "decompiler/ObjectFile/LinkedObjectFile.h"
#include "decompiler/util/DecompilerTypeSystem.h"
#include "decompiler/util/data_decompile.h"
@@ -2801,11 +2802,22 @@ void StackSpillStoreElement::get_modified_regs(RegSet&) const {}
// StackSpillValueElement
////////////////////////////////
StackSpillValueElement::StackSpillValueElement(int size, int stack_offset, bool is_signed)
: m_size(size), m_stack_offset(stack_offset), m_is_signed(is_signed) {}
StackSpillValueElement::StackSpillValueElement(int size,
int stack_offset,
bool is_signed,
std::optional<TypeSpec> read_type)
: m_size(size),
m_stack_offset(stack_offset),
m_is_signed(is_signed),
m_read_type(std::move(read_type)) {}
goos::Object StackSpillValueElement::to_form_internal(const Env& env) const {
return pretty_print::to_symbol(env.get_spill_slot_var_name(m_stack_offset));
auto var = make_stack_slot_access(m_stack_offset);
auto base = pretty_print::to_symbol(env.get_spill_slot_var_name(m_stack_offset));
if (m_read_type && env.get_variable_type(var, true) != *m_read_type) {
return pretty_print::build_list("the-as", m_read_type->print(), base);
}
return base;
}
void StackSpillValueElement::apply(const std::function<void(FormElement*)>& f) {
@@ -2813,7 +2825,9 @@ void StackSpillValueElement::apply(const std::function<void(FormElement*)>& f) {
}
void StackSpillValueElement::apply_form(const std::function<void(Form*)>&) {}
void StackSpillValueElement::collect_vars(RegAccessSet&, bool) const {}
void StackSpillValueElement::collect_vars(RegAccessSet& vars, bool) const {
vars.insert(make_stack_slot_access(m_stack_offset));
}
void StackSpillValueElement::get_modified_regs(RegSet&) const {}
////////////////////////////////
+5 -1
View File
@@ -1564,7 +1564,10 @@ class StackSpillStoreElement : public FormElement {
// the value from a stack load.
class StackSpillValueElement : public FormElement {
public:
StackSpillValueElement(int size, int stack_offset, bool is_signed);
StackSpillValueElement(int size,
int stack_offset,
bool is_signed,
std::optional<TypeSpec> read_type = std::nullopt);
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
@@ -1580,6 +1583,7 @@ class StackSpillValueElement : public FormElement {
int m_size = -1;
int m_stack_offset = -1;
bool m_is_signed = false;
std::optional<TypeSpec> m_read_type;
};
class MethodOfTypeElement : public FormElement {
+103 -27
View File
@@ -12,6 +12,7 @@
#include "common/util/BitUtils.h"
#include "common/util/print_float.h"
#include "decompiler/IR2/Env.h"
#include "decompiler/IR2/ExpressionHelpers.h"
#include "decompiler/IR2/bitfields.h"
#include "decompiler/ObjectFile/LinkedObjectFile.h"
@@ -65,6 +66,27 @@
namespace decompiler {
namespace {
Form* cast_form(Form* in, const TypeSpec& new_type, FormPool& pool, const Env& env, bool tc_pass);
TypeSpec get_input_type_for_access(const Env& env, const RegisterAccess& access) {
if (is_stack_slot_access(access)) {
return env.get_variable_type(access, true);
}
return env.get_types_before_op(access.idx()).get(access.reg()).typespec();
}
Form* cast_stack_slot_var_if_needed(Form* in,
const TypeSpec& desired_type,
FormPool& pool,
const Env& env) {
auto atom = form_as_atom(in);
if (atom && atom->is_var() && is_stack_slot_access(atom->var()) &&
env.get_variable_type(atom->var(), true) != desired_type) {
return cast_form(in, desired_type, pool, env, false);
}
return in;
}
Form* strip_pcypld_64(Form* in) {
auto m = match(Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::PCPYLD),
{Matcher::integer(0), Matcher::any(0)}),
@@ -347,6 +369,9 @@ Form* repop_passthrough_arg(Form* in,
auto as_atom = form_as_atom(in);
if (as_atom && as_atom->is_var()) {
if (is_stack_slot_access(as_atom->var())) {
return in;
}
return stack.pop_reg(as_atom->var().reg(), {}, env, true, -1, orig_out, found_orig_out);
}
return in;
@@ -389,6 +414,9 @@ void pop_helper(const std::vector<RegisterAccess>& vars,
for (size_t var_idx = 0; var_idx < vars.size(); var_idx++) {
const auto& var = vars.at(var_idx);
if (is_stack_slot_access(var)) {
continue;
}
auto& ri = env.reg_use().op.at(var.idx());
RegSet consumes_to_use = consumes.value_or(ri.consumes);
if (consumes_to_use.find(var.reg()) != consumes_to_use.end()) {
@@ -555,6 +583,14 @@ std::vector<Form*> pop_to_forms(const std::vector<RegisterAccess>& vars,
for (size_t i = 0; i < vars.size(); i++) {
auto atom = form_as_atom(forms[i]);
bool is_var = atom && atom->is_var();
if (is_var && is_stack_slot_access(atom->var())) {
auto access_type = get_input_type_for_access(env, vars[i]);
if (env.get_variable_type(atom->var(), true) != access_type) {
forms[i] = cast_form(forms[i], access_type, pool, env);
atom = form_as_atom(forms[i]);
is_var = atom && atom->is_var();
}
}
auto cast = env.get_user_cast_for_access(vars[i]);
// only cast if we didn't get a var (compacting expressions).
// there is a separate system for casting variables that will do a better job.
@@ -1146,7 +1182,9 @@ void SimpleExpressionElement::update_from_stack_add_i(const Env& env,
}
}
ASSERT(used_index);
result->push_back(pool.alloc_element<DerefElement>(args.at(1), out.addr_of, tokens));
result->push_back(pool.alloc_element<DerefElement>(
cast_stack_slot_var_if_needed(args.at(1), arg1_type.typespec(), pool, env),
out.addr_of, tokens));
return;
} else {
throw std::runtime_error(
@@ -1186,7 +1224,9 @@ void SimpleExpressionElement::update_from_stack_add_i(const Env& env,
}
}
ASSERT(used_index);
result->push_back(pool.alloc_element<DerefElement>(args.at(1), out.addr_of, tokens));
result->push_back(pool.alloc_element<DerefElement>(
cast_stack_slot_var_if_needed(args.at(1), arg1_type.typespec(), pool, env),
out.addr_of, tokens));
return;
} else {
throw std::runtime_error(
@@ -1215,7 +1255,9 @@ void SimpleExpressionElement::update_from_stack_add_i(const Env& env,
}
}
ASSERT(used_index);
result->push_back(pool.alloc_element<DerefElement>(args.at(1), out.addr_of, tokens));
result->push_back(pool.alloc_element<DerefElement>(
cast_stack_slot_var_if_needed(args.at(1), arg1_type.typespec(), pool, env),
out.addr_of, tokens));
return;
} else {
throw std::runtime_error(
@@ -1267,7 +1309,9 @@ void SimpleExpressionElement::update_from_stack_add_i(const Env& env,
}
}
ASSERT(used_index);
result->push_back(pool.alloc_element<DerefElement>(args.at(0), rd_ok.addr_of, tokens));
result->push_back(pool.alloc_element<DerefElement>(
cast_stack_slot_var_if_needed(args.at(0), arg0_type.typespec(), pool, env),
rd_ok.addr_of, tokens));
return;
} else {
throw std::runtime_error(fmt::format(
@@ -1318,7 +1362,9 @@ void SimpleExpressionElement::update_from_stack_add_i(const Env& env,
}
}
ASSERT(used_index);
result->push_back(pool.alloc_element<DerefElement>(args.at(1), rd_ok.addr_of, tokens));
result->push_back(pool.alloc_element<DerefElement>(
cast_stack_slot_var_if_needed(args.at(1), arg1_type.typespec(), pool, env),
rd_ok.addr_of, tokens));
return;
} else {
// TODO - output error to IR
@@ -1341,7 +1387,9 @@ void SimpleExpressionElement::update_from_stack_add_i(const Env& env,
tokens.push_back(to_token(tok));
}
result->push_back(pool.alloc_element<DerefElement>(args.at(1), out.addr_of, tokens));
result->push_back(pool.alloc_element<DerefElement>(
cast_stack_slot_var_if_needed(args.at(1), arg1_type.typespec(), pool, env), out.addr_of,
tokens));
return;
}
}
@@ -2357,7 +2405,7 @@ void SimpleExpressionElement::update_from_stack_int_to_float(const Env& env,
// the gpr->fpr operation beacuse it doesn't matter.
auto fpr_convert_matcher =
Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::GPR_TO_FPR), {Matcher::any(0)});
auto type = env.get_types_before_op(var.idx()).get(var.reg()).typespec();
auto type = get_input_type_for_access(env, var);
// want to allow any child of integer so integer enums can also be converted to floats.
if (env.dts->ts.tc(TypeSpec("integer"), type) || type == TypeSpec("seconds")) {
auto mr = match(fpr_convert_matcher, arg);
@@ -2379,7 +2427,7 @@ void SimpleExpressionElement::update_from_stack_float_to_int(const Env& env,
bool allow_side_effects) {
auto var = m_expr.get_arg(0).var();
auto arg = pop_to_forms({var}, env, pool, stack, allow_side_effects).at(0);
auto type = env.get_types_before_op(var.idx()).get(var.reg()).typespec();
auto type = get_input_type_for_access(env, var);
auto fpr_convert_matcher =
Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::GPR_TO_FPR), {Matcher::any(0)});
auto mr = match(fpr_convert_matcher, arg);
@@ -2412,7 +2460,7 @@ void SimpleExpressionElement::update_from_stack_subu_l32_s7(const Env& env,
bool allow_side_effects) {
auto var = m_expr.get_arg(0).var();
auto arg = pop_to_forms({var}, env, pool, stack, allow_side_effects).at(0);
auto type = env.get_types_before_op(var.idx()).get(var.reg()).typespec();
auto type = get_input_type_for_access(env, var);
if (type != TypeSpec("handle")) {
env.func->warnings.warning(
".subu (32-bit) used on a {} at idx {}. This probably should be a handle.", type.print(),
@@ -2634,9 +2682,12 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
}
auto var = src_as_se->expr().get_arg(0).var();
auto& info = env.reg_use().op.at(var.idx());
if (var.reg() == Register(Reg::GPR, Reg::S6) ||
info.consumes.find(var.reg()) != info.consumes.end()) {
bool is_consumed_reg_move = false;
if (!is_stack_slot_access(var)) {
auto& info = env.reg_use().op.at(var.idx());
is_consumed_reg_move = info.consumes.find(var.reg()) != info.consumes.end();
}
if (var.reg() == Register(Reg::GPR, Reg::S6) || is_consumed_reg_move) {
stack.push_non_seq_reg_to_reg(m_dst, src_as_se->expr().get_arg(0).var(), m_src,
m_src_type, m_var_info);
return;
@@ -3495,8 +3546,14 @@ void FunctionCallElement::update_from_stack(const Env& env,
}
TypeSpec function_type;
auto& in_type_state = env.get_types_before_op(all_pop_vars.at(0).idx());
auto& tp_type = in_type_state.get(all_pop_vars.at(0).reg());
const TypeState* in_type_state = nullptr;
TP_Type tp_type;
if (!is_stack_slot_access(all_pop_vars.at(0))) {
in_type_state = &env.get_types_before_op(all_pop_vars.at(0).idx());
tp_type = in_type_state->get(all_pop_vars.at(0).reg());
} else {
tp_type = env.get_variable_tp_type(all_pop_vars.at(0), true);
}
if (env.has_type_analysis()) {
function_type = tp_type.typespec();
}
@@ -3504,7 +3561,8 @@ void FunctionCallElement::update_from_stack(const Env& env,
// if we're actually a go:
Form* go_next_state = nullptr;
if (tp_type.kind == TP_Type::Kind::ENTER_STATE_FUNCTION) {
auto& next_state_type = in_type_state.next_state_type;
ASSERT(in_type_state);
auto& next_state_type = in_type_state->next_state_type;
if (next_state_type.typespec().base_type() != "state") {
throw std::runtime_error("Bad state type in expressions (not state): " +
next_state_type.print());
@@ -3591,7 +3649,7 @@ void FunctionCallElement::update_from_stack(const Env& env,
auto val = unstacked.at(arg_id + 1); // first is the function itself.
auto& var = all_pop_vars.at(arg_id + 1);
if (has_good_types) {
auto actual_arg_type = env.get_types_before_op(var.idx()).get(var.reg()).typespec();
auto actual_arg_type = get_input_type_for_access(env, var);
if (arg_id == 0) {
first_arg_type = actual_arg_type;
@@ -3997,7 +4055,7 @@ void FunctionCallElement::update_from_stack(const Env& env,
ASSERT(new_args.size() >= 3);
for (size_t i = 0; i < 3; i++) {
auto& var = all_pop_vars.at(i + 1); // 0 is the function itself.
auto arg_type = env.get_types_before_op(var.idx()).get(var.reg()).typespec();
auto arg_type = get_input_type_for_access(env, var);
if (!env.dts->ts.tc(expected_arg_types.at(i), arg_type)) {
new_args.at(i) = pool.form<CastElement>(expected_arg_types.at(i), new_args.at(i));
}
@@ -5031,9 +5089,11 @@ void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStac
// determine if set destination is used
bool set_unused = false;
if (rewrite_as_set) {
auto& info = env.reg_use().op.at(last_var->idx());
if (info.written_and_unused.find(last_var->reg()) != info.written_and_unused.end()) {
set_unused = true;
if (!is_stack_slot_access(*last_var)) {
auto& info = env.reg_use().op.at(last_var->idx());
if (info.written_and_unused.find(last_var->reg()) != info.written_and_unused.end()) {
set_unused = true;
}
}
}
@@ -6019,7 +6079,7 @@ void ConditionElement::push_to_stack(const Env& env, FormPool& pool, FormStack&
if (m_src[i]->is_var()) {
auto& var = m_src[i]->var();
vars.push_back(var);
source_types.push_back(env.get_types_before_op(var.idx()).get(var.reg()).typespec());
source_types.push_back(get_input_type_for_access(env, var));
} else if (m_src[i]->is_int()) {
if (m_src[i]->get_int() == 0 && condition_uses_float(m_kind)) {
// if we're doing a floating point comparison, and one of our arguments is a constant
@@ -6072,7 +6132,7 @@ void ConditionElement::update_from_stack(const Env& env,
if (m_src[i]->is_var()) {
auto& var = m_src[i]->var();
vars.push_back(var);
source_types.push_back(env.get_types_before_op(var.idx()).get(var.reg()).typespec());
source_types.push_back(get_input_type_for_access(env, var));
} else if (m_src[i]->is_int()) {
if (m_src[i]->get_int() == 0 && condition_uses_float(m_kind)) {
// if we're doing a floating point comparison, and one of our arguments is a constant
@@ -6915,11 +6975,19 @@ void StackSpillStoreElement::push_to_stack(const Env& env, FormPool& pool, FormS
src = pool.form<SimpleAtomElement>(m_value);
}
auto dst = pool.form<ConstantTokenElement>(env.get_spill_slot_var_name(m_stack_offset));
if (m_cast_type) {
src = cast_form(src, *m_cast_type, pool, env);
}
stack.push_form_element(pool.alloc_element<SetFormFormElement>(dst, src), true);
TypeSpec stack_type("object");
auto it = env.stack_slot_entries.find(m_stack_offset);
if (it != env.stack_slot_entries.end()) {
stack_type = it->second.typespec;
} else if (m_cast_type) {
stack_type = *m_cast_type;
}
stack.push_value_to_reg(make_stack_slot_access(m_stack_offset), src, true, stack_type);
}
namespace {
@@ -7173,13 +7241,21 @@ void StackStructureDefElement::update_from_stack(const Env&,
result->push_back(this);
}
void StackSpillValueElement::update_from_stack(const Env&,
FormPool&,
void StackSpillValueElement::update_from_stack(const Env& env,
FormPool& pool,
FormStack&,
std::vector<FormElement*>* result,
bool) {
mark_popped();
result->push_back(this);
auto var = make_stack_slot_access(m_stack_offset);
Form* form =
pool.alloc_single_element_form<SimpleAtomElement>(nullptr, SimpleAtom::make_var(var));
if (m_read_type && env.get_variable_type(var, true) != *m_read_type) {
form = cast_form(form, *m_read_type, pool, env);
}
for (auto elt : form->elts()) {
result->push_back(elt);
}
}
void GetSymbolStringPointer::update_from_stack(const Env&,
+2 -2
View File
@@ -325,7 +325,7 @@ std::vector<FormElement*> FormStack::rewrite(FormPool& pool, const Env& env) con
while (keep_going && !result.empty()) {
keep_going = false;
auto last_op_as_set = dynamic_cast<SetVarElement*>(result.back());
if (last_op_as_set && last_op_as_set->dst().reg() == var_to_get.reg()) {
if (last_op_as_set && same_expression_var(last_op_as_set->dst(), var_to_get)) {
result.pop_back();
auto as_one = dynamic_cast<SimpleExpressionElement*>(
last_op_as_set->src()->try_as_single_element());
@@ -384,7 +384,7 @@ std::optional<RegisterAccess> rewrite_to_get_var(std::vector<FormElement*>& defa
while (keep_going && !default_result.empty()) {
keep_going = false;
auto last_op_as_set = dynamic_cast<SetVarElement*>(default_result.back());
if (last_op_as_set && last_op_as_set->dst().reg() == var_to_get.reg() &&
if (last_op_as_set && same_expression_var(last_op_as_set->dst(), var_to_get) &&
(first || last_op_as_set->info().is_compactable)) {
default_result.pop_back();
auto as_one =
+24
View File
@@ -45,6 +45,7 @@ If the previous let variables appear in the definition of new one, make the let
namespace {
FormElement* rewrite_let(LetElement* in, const Env& env, FormPool& pool, LetRewriteStats& stats);
bool let_uses_stack_slot_access(const LetElement* in);
std::vector<Form*> path_up_tree(Form* in, const Env&) {
std::vector<Form*> path;
@@ -2409,6 +2410,10 @@ FormElement* rewrite_set_font_single(LetElement* in,
FormElement* rewrite_let(LetElement* in, const Env& env, FormPool& pool, LetRewriteStats& stats) {
// ordered based on frequency. for best performance, you check the most likely rewrites first!
if (let_uses_stack_slot_access(in)) {
return nullptr;
}
auto as_unused = rewrite_empty_let(in, env, pool);
if (as_unused) {
stats.unused++;
@@ -3073,6 +3078,10 @@ FormElement* rewrite_multi_let(LetElement* in,
const Env& env,
FormPool& pool,
LetRewriteStats& stats) {
if (let_uses_stack_slot_access(in)) {
return in;
}
if (in->entries().size() >= 2) {
auto as_with_dma_buf_add_bucket = rewrite_with_dma_buf_add_bucket(in, env, pool);
if (as_with_dma_buf_add_bucket) {
@@ -3569,6 +3578,12 @@ FormElement* rewrite_let_sequence(const std::vector<LetElement*>& in,
const Env& env,
FormPool& pool,
LetRewriteStats& stats) {
for (const auto* let : in) {
if (let_uses_stack_slot_access(let)) {
return nullptr;
}
}
if (in.size() == 3) {
auto as_dma_buffer_add_gs_set = rewrite_dma_buffer_add_gs_set(in, env, pool);
if (as_dma_buffer_add_gs_set) {
@@ -3609,6 +3624,15 @@ Form* insert_cast_for_let(RegisterAccess dst,
return src;
}
bool let_uses_stack_slot_access(const LetElement* in) {
for (const auto& entry : in->entries()) {
if (is_stack_slot_access(entry.dest)) {
return true;
}
}
return false;
}
bool register_can_hold_var(const Register& reg) {
return reg.get_kind() == Reg::FPR || reg.get_kind() == Reg::GPR;
}