mirror of
https://github.com/open-goal/jak-project
synced 2026-09-12 12:55:22 -04:00
wip
This commit is contained in:
@@ -77,6 +77,11 @@ class AtomicOp {
|
||||
|
||||
TypeState propagate_types(const TypeState& input, const Env& env, DecompilerTypeSystem& dts);
|
||||
|
||||
void multi_types(InstrTypeState* output,
|
||||
InstrTypeState& input,
|
||||
const Env& env,
|
||||
DecompilerTypeSystem& dts);
|
||||
|
||||
int op_id() const { return m_my_idx; }
|
||||
const std::vector<Register>& read_regs() const { return m_read_regs; }
|
||||
const std::vector<Register>& write_regs() const { return m_write_regs; }
|
||||
@@ -97,6 +102,11 @@ class AtomicOp {
|
||||
virtual TypeState propagate_types_internal(const TypeState& input,
|
||||
const Env& env,
|
||||
DecompilerTypeSystem& dts) = 0;
|
||||
|
||||
virtual void multi_types_internal(InstrTypeState* output,
|
||||
InstrTypeState& input,
|
||||
const Env& env,
|
||||
DecompilerTypeSystem& dts);
|
||||
void clobber_temps();
|
||||
|
||||
// the register values that are read (at the start of this op)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "decompiler/IR2/IR2_common.h"
|
||||
#include "decompiler/analysis/reg_usage.h"
|
||||
#include "decompiler/config.h"
|
||||
#include "decompiler/IR2/MultiTypeAnalysis.h"
|
||||
|
||||
namespace decompiler {
|
||||
class LinkedObjectFile;
|
||||
@@ -208,6 +209,18 @@ class Env {
|
||||
// hacks:
|
||||
bool aggressively_reject_cond_to_value_rewrite = false;
|
||||
|
||||
void set_type_graph(std::shared_ptr<TypeAnalysisGraph> tg) {
|
||||
m_tg = std::move(tg);
|
||||
m_has_new_types = true;
|
||||
}
|
||||
|
||||
const TypeAnalysisGraph& type_graph() const {
|
||||
assert(m_has_new_types);
|
||||
return *m_tg;
|
||||
}
|
||||
|
||||
bool has_type_graph() const { return m_has_new_types; }
|
||||
|
||||
private:
|
||||
RegisterAccess m_end_var;
|
||||
|
||||
@@ -235,5 +248,8 @@ class Env {
|
||||
std::optional<TypeSpec> m_type_analysis_return_type;
|
||||
|
||||
StackSpillMap m_stack_spill_map;
|
||||
|
||||
bool m_has_new_types = false;
|
||||
std::shared_ptr<TypeAnalysisGraph> m_tg;
|
||||
};
|
||||
} // namespace decompiler
|
||||
@@ -2822,6 +2822,15 @@ FormElement* ConditionElement::make_generic(const Env& env,
|
||||
casted);
|
||||
}
|
||||
|
||||
case IR2_Condition::Kind::LESS_THAN_ZERO_UNSIGNED: {
|
||||
auto casted = make_casts_if_needed(source_forms, types, TypeSpec("uint"), pool, env);
|
||||
auto zero = pool.alloc_single_element_form<SimpleAtomElement>(
|
||||
nullptr, SimpleAtom::make_int_constant(0));
|
||||
casted.push_back(zero);
|
||||
return pool.alloc_element<GenericElement>(GenericOperator::make_fixed(FixedOperatorKind::LT),
|
||||
casted);
|
||||
}
|
||||
|
||||
case IR2_Condition::Kind::GREATER_THAN_ZERO_SIGNED: {
|
||||
auto casted = make_casts_if_needed(source_forms, types, TypeSpec("int"), pool, env);
|
||||
auto zero = pool.alloc_single_element_form<SimpleAtomElement>(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -32,6 +32,9 @@ struct DerefHint {
|
||||
struct TypeChoiceParent {
|
||||
RegisterTypeState* reg_type = nullptr;
|
||||
int idx_in_parent = -1;
|
||||
const PossibleType& get() const;
|
||||
PossibleType& get();
|
||||
void remove_ref();
|
||||
};
|
||||
|
||||
/*!
|
||||
@@ -41,9 +44,13 @@ struct TypeChoiceParent {
|
||||
*/
|
||||
struct PossibleType {
|
||||
TP_Type type; // the actual type.
|
||||
std::optional<FieldReverseLookupOutput>
|
||||
deref_path; // the field accessed to get here, assuming we did a deref.
|
||||
double score = 0.; // the sum of scores of all derefs to get here.
|
||||
|
||||
// the field accessed to get here, assuming we did a deref.
|
||||
std::optional<FieldReverseLookupOutput> deref_path;
|
||||
|
||||
// the sum of scores of all derefs to get here.
|
||||
// this can be used to compare us to others in the same RegisterTypeState.
|
||||
double score = 0.;
|
||||
|
||||
// if we are a child, 0.
|
||||
// otherwise, the number of children who have a reference to us.
|
||||
@@ -68,12 +75,15 @@ struct RegisterTypeState {
|
||||
std::optional<TypeSpec> override_type;
|
||||
|
||||
// if we're simplified to a single type, this will hold in the index in the possible types vector.
|
||||
|
||||
// the types we can be.
|
||||
std::vector<PossibleType> possible_types;
|
||||
|
||||
bool is_temp_node = false;
|
||||
|
||||
RegisterTypeState() = default;
|
||||
RegisterTypeState(const PossibleType& single_type) : possible_types({single_type}) {}
|
||||
RegisterTypeState(const PossibleType& single_type) : possible_types({single_type}) {
|
||||
single_type_cache = 0;
|
||||
}
|
||||
void reduce_to_single_best_type(DecompWarnings* warnings, int op_idx, const DerefHint* hint);
|
||||
bool is_single_type() const;
|
||||
const PossibleType& get_single_type_decision() const;
|
||||
@@ -90,36 +100,37 @@ struct RegisterTypeState {
|
||||
* During setup, this contains a alloc flag and a uid.
|
||||
* While it's running, it contains a pointer.
|
||||
*/
|
||||
/*
|
||||
struct RegisterNode {
|
||||
RegisterTypeState* ptr() { return (RegisterTypeState*)data; }
|
||||
bool alloc() { return data & 1; }
|
||||
u64 uid() { return data >> 32; }
|
||||
void set_alloc() { data |= 1; }
|
||||
void set_uid(u64 uid) { data |= (uid << 32); }
|
||||
|
||||
private:
|
||||
uintptr_t data = 0;
|
||||
static_assert(sizeof(uintptr_t) == 8);
|
||||
};
|
||||
*/
|
||||
|
||||
struct RegisterNode {
|
||||
RegisterTypeState* ptr() { return m_ptr; }
|
||||
void set_ptr(RegisterTypeState* ptr) { m_ptr = ptr; }
|
||||
const RegisterTypeState* ptr() const { return m_ptr; }
|
||||
void set_cast_temp_ptr(RegisterTypeState* ptr) {
|
||||
m_ptr = ptr;
|
||||
m_flags |= FLAG_CAST_TEMP;
|
||||
}
|
||||
bool alloc() const { return !!m_ptr; }
|
||||
void set_alloc(RegisterTypeState* state) {
|
||||
m_ptr = state;
|
||||
m_alloc_point = true;
|
||||
m_flags |= FLAG_ALLOC_POINT;
|
||||
}
|
||||
bool is_alloc_point() const { return m_alloc_point; }
|
||||
void set_clobber(RegisterTypeState* state) {
|
||||
m_ptr = state;
|
||||
m_flags |= FLAG_CLOBBER;
|
||||
}
|
||||
bool is_alloc_point() const { return m_flags & FLAG_ALLOC_POINT; }
|
||||
bool is_clobber() const { return m_flags & FLAG_CLOBBER; }
|
||||
s64 uid() const { return m_uid; }
|
||||
void set_uid(s64 val) { m_uid = val; }
|
||||
|
||||
private:
|
||||
RegisterTypeState* m_ptr = nullptr;
|
||||
s32 m_uid = 0;
|
||||
bool m_alloc_point = false;
|
||||
|
||||
u8 m_flags = 0;
|
||||
static constexpr u8 FLAG_ALLOC_POINT = 1;
|
||||
static constexpr u8 FLAG_CLOBBER = 2;
|
||||
static constexpr u8 FLAG_CAST_TEMP = 4;
|
||||
static constexpr u8 FLAG_CAST_FINAL = 8;
|
||||
};
|
||||
|
||||
class InstrTypeState {
|
||||
@@ -128,9 +139,11 @@ class InstrTypeState {
|
||||
int stack_slot_count() const { return m_stack_slots.size(); }
|
||||
std::array<RegisterNode, Reg::MAX_VAR_REG_ID>& regs() { return m_regs; }
|
||||
std::vector<std::pair<int, RegisterNode>>& slots() { return m_stack_slots; }
|
||||
const std::array<RegisterNode, Reg::MAX_VAR_REG_ID>& regs() const { return m_regs; }
|
||||
const std::vector<std::pair<int, RegisterNode>>& slots() const { return m_stack_slots; }
|
||||
|
||||
RegisterNode& get_slot(int offset) {
|
||||
for(auto& s : m_stack_slots) {
|
||||
for (auto& s : m_stack_slots) {
|
||||
if (s.first == offset) {
|
||||
return s.second;
|
||||
}
|
||||
@@ -143,6 +156,10 @@ class InstrTypeState {
|
||||
return m_regs[reg.reg_id()];
|
||||
}
|
||||
|
||||
RegisterTypeState& get_state(const Register& reg) { return *get(reg).ptr(); }
|
||||
RegisterTypeState& get_slot_state(int offset) { return *get_slot(offset).ptr(); }
|
||||
void assign(const Register& reg, const RegisterTypeState& value);
|
||||
|
||||
private:
|
||||
std::array<RegisterNode, Reg::MAX_VAR_REG_ID> m_regs;
|
||||
std::vector<std::pair<int, RegisterNode>> m_stack_slots;
|
||||
@@ -151,6 +168,7 @@ class InstrTypeState {
|
||||
struct TypeAnalysisGraph {
|
||||
std::vector<InstrTypeState> after_op_types;
|
||||
std::vector<InstrTypeState> block_start_types;
|
||||
std::vector<std::unique_ptr<RegisterTypeState>> final_cast_nodes;
|
||||
|
||||
BlockTopologicalSort topo_sort;
|
||||
|
||||
@@ -161,9 +179,13 @@ struct TypeAnalysisGraph {
|
||||
|
||||
class Function;
|
||||
class DecompilerTypeSystem;
|
||||
TypeAnalysisGraph make_analysis_graph(const TypeSpec& my_type,
|
||||
DecompilerTypeSystem& dts,
|
||||
Function& func,
|
||||
bool verbose);
|
||||
std::shared_ptr<TypeAnalysisGraph> allocate_analysis_graph(const TypeSpec& my_type,
|
||||
DecompilerTypeSystem& dts,
|
||||
Function& func,
|
||||
bool verbose);
|
||||
bool run_multi_type_analysis(const TypeSpec& my_type,
|
||||
DecompilerTypeSystem& dts,
|
||||
Function& func,
|
||||
TypeAnalysisGraph& graph);
|
||||
|
||||
} // namespace decompiler
|
||||
@@ -382,7 +382,7 @@ void ObjectFileDB::ir2_type_analysis_pass(const Config& config) {
|
||||
try_lookup(config.stack_structure_hints_by_function, func_name));
|
||||
|
||||
// experimental multi-type pass, for debugging.
|
||||
auto tg = make_analysis_graph(ts, dts, func, true);
|
||||
auto tg = allocate_analysis_graph(ts, dts, func, true);
|
||||
|
||||
if (run_type_analysis_ir2(ts, dts, func)) {
|
||||
successful_functions++;
|
||||
@@ -989,7 +989,7 @@ std::string ObjectFileDB::ir2_final_out(ObjectFileData& data,
|
||||
result += ";;-*-Lisp-*-\n";
|
||||
result += "(in-package goal)\n\n";
|
||||
assert(data.linked_data.functions_by_seg.at(TOP_LEVEL_SEGMENT).size() == 1);
|
||||
auto top_level = data.linked_data.functions_by_seg.at(TOP_LEVEL_SEGMENT).at(0);
|
||||
auto& top_level = data.linked_data.functions_by_seg.at(TOP_LEVEL_SEGMENT).at(0);
|
||||
result += write_from_top_level(top_level, dts, data.linked_data, skip_functions);
|
||||
result += "\n\n";
|
||||
return result;
|
||||
|
||||
@@ -185,8 +185,12 @@ std::unique_ptr<FormRegressionTest::TestData> FormRegressionTest::make_function(
|
||||
}
|
||||
|
||||
// analyze types
|
||||
EXPECT_TRUE(run_type_analysis_ir2(function_type, *dts, test->func));
|
||||
test->func.ir2.env.types_succeeded = true;
|
||||
// EXPECT_TRUE(run_type_analysis_ir2(function_type, *dts, test->func));
|
||||
auto tg = allocate_analysis_graph(function_type, *dts, test->func, true);
|
||||
bool ok = run_multi_type_analysis(function_type, *dts, test->func, *tg);
|
||||
EXPECT_TRUE(ok);
|
||||
test->func.ir2.env.set_type_graph(tg);
|
||||
test->func.ir2.env.types_succeeded = ok;
|
||||
|
||||
// analyze registers
|
||||
test->func.ir2.env.set_reg_use(analyze_ir2_register_usage(test->func));
|
||||
|
||||
Reference in New Issue
Block a user