mirror of
https://github.com/open-goal/jak-project
synced 2026-08-04 01:04:11 -04:00
add stack var support
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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 {}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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&,
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user