mirror of
https://github.com/open-goal/jak-project
synced 2026-08-20 22:35:07 -04:00
wip
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include "common/util/assert.h"
|
||||
|
||||
@@ -46,9 +48,11 @@ class CopyOnWrite {
|
||||
* Construct a new object.
|
||||
*/
|
||||
template <typename... Args>
|
||||
explicit CopyOnWrite(Args&&... args) {
|
||||
static CopyOnWrite<T> make_cow(Args&&... args) {
|
||||
CopyOnWrite<T> result;
|
||||
auto obj = new ObjectAndCount(std::forward<Args>(args)...);
|
||||
acquire_object(obj);
|
||||
result.acquire_object(obj);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -112,3 +116,8 @@ class CopyOnWrite {
|
||||
|
||||
ObjectAndCount* m_data = nullptr;
|
||||
};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
CopyOnWrite<T> make_cow(Args&&... args) {
|
||||
return CopyOnWrite<T>::make_cow(std::forward<Args>(args)...);
|
||||
}
|
||||
@@ -189,16 +189,17 @@ namespace {
|
||||
* Create a register type state with no parent and the given typespec.
|
||||
*/
|
||||
RegState make_typespec_parent_regstate(const TypeSpec& typespec) {
|
||||
RegState result = make_cow
|
||||
return make_cow<RegisterTypeState>(TP_Type::make_from_ts(typespec));
|
||||
}
|
||||
|
||||
/*!
|
||||
* Create an instruction type state for the first instruction of a function.
|
||||
*/
|
||||
InstrTypeState construct_initial_typestate(const TypeSpec& function_type,
|
||||
const TypeSpec& behavior_type,
|
||||
const Env& env,
|
||||
const RegState& uninitialized) {
|
||||
// start with everything unintialized
|
||||
// start with everything uninitialized
|
||||
InstrTypeState result(uninitialized);
|
||||
assert(function_type.base_type() == "function");
|
||||
assert(function_type.arg_count() >= 1); // must know the function type.
|
||||
@@ -207,9 +208,20 @@ InstrTypeState construct_initial_typestate(const TypeSpec& function_type,
|
||||
for (int i = 0; i < int(function_type.arg_count()) - 1; i++) {
|
||||
auto reg_id = Register::get_arg_reg(i);
|
||||
const auto& reg_type = function_type.get_arg(i);
|
||||
result.get(Register(Reg::GPR, reg_id)) = TP_Type::make_from_ts(reg_type);
|
||||
result.get(reg_id) = make_cow<RegisterTypeState>(TP_Type::make_from_ts(reg_type));
|
||||
}
|
||||
|
||||
if (behavior_type != TypeSpec("none")) {
|
||||
result.get(Register(Reg::GPR, Reg::S6)) =
|
||||
make_cow<RegisterTypeState>(TP_Type::make_from_ts(behavior_type));
|
||||
}
|
||||
|
||||
// set stack slots as uninitialized too.
|
||||
for (auto slot_info : env.stack_spills().map()) {
|
||||
result.add_stack_slot(slot_info.first, uninitialized);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -15,16 +15,14 @@ struct PossibleType;
|
||||
|
||||
struct DerefHint {
|
||||
struct Token {
|
||||
enum class Kind {
|
||||
INTEGER, FIELD, VAR, INVALID
|
||||
} kind = Kind::INVALID;
|
||||
enum class Kind { INTEGER, FIELD, VAR, INVALID } kind = Kind::INVALID;
|
||||
int integer = 0;
|
||||
std::string name;
|
||||
bool matches(const FieldReverseLookupOutput::Token& other)const ;
|
||||
bool matches(const FieldReverseLookupOutput::Token& other) const;
|
||||
};
|
||||
std::vector<Token> tokens;
|
||||
|
||||
bool matches(const FieldReverseLookupOutput& value)const ;
|
||||
bool matches(const FieldReverseLookupOutput& value) const;
|
||||
};
|
||||
|
||||
/*!
|
||||
@@ -47,10 +45,12 @@ struct PossibleType {
|
||||
TP_Type type; // the actual type.
|
||||
std::optional<FieldReverseLookupOutput> deref_path; // the field accessed to get here
|
||||
double deref_score = 0.;
|
||||
TypeDecisionParent parent; // the decision we made to allow this.
|
||||
TypeDecisionParent parent; // the decision we made to allow this.
|
||||
void eliminate() { m_valid_cache = false; }
|
||||
bool is_valid() const; // true, unless we were eliminated.
|
||||
|
||||
PossibleType(const TP_Type& tp_type) : type(tp_type) {}
|
||||
|
||||
private:
|
||||
mutable bool m_valid_cache = true;
|
||||
};
|
||||
@@ -59,8 +59,12 @@ struct PossibleType {
|
||||
* The set of all possible types in a register.
|
||||
*/
|
||||
struct RegisterTypeState {
|
||||
std::optional<TypeSpec> override_type; // this is just for printing errors.
|
||||
std::optional<int> single_type_cache;
|
||||
std::vector<PossibleType> possible_types;
|
||||
|
||||
RegisterTypeState() = delete;
|
||||
RegisterTypeState(const PossibleType& single_type) : possible_types({single_type}) {}
|
||||
void reduce_to_single_type(DecompWarnings* warnings, int op_idx, const DerefHint* hint);
|
||||
const PossibleType& get_single_type_decision() const;
|
||||
const TP_Type& get_single_tp_type() const;
|
||||
@@ -83,7 +87,30 @@ class InstrTypeState {
|
||||
return m_regs[reg.reg_id()];
|
||||
}
|
||||
|
||||
CopyOnWrite<RegisterTypeState>& get_stack_slot(int offset) {
|
||||
for (auto& slot : m_stack_slots) {
|
||||
if (slot.first == offset) {
|
||||
return slot.second;
|
||||
}
|
||||
}
|
||||
assert(false);
|
||||
}
|
||||
|
||||
const RegisterTypeState& get_stack_slot_const(int offset) const {
|
||||
for (auto& slot : m_stack_slots) {
|
||||
if (slot.first == offset) {
|
||||
return *slot.second;
|
||||
}
|
||||
}
|
||||
assert(false);
|
||||
}
|
||||
|
||||
void add_stack_slot(int offset, const CopyOnWrite<RegisterTypeState>& value) {
|
||||
m_stack_slots.emplace_back(offset, value);
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<CopyOnWrite<RegisterTypeState>, Reg::MAX_VAR_REG_ID> m_regs;
|
||||
std::vector<std::pair<int, CopyOnWrite<RegisterTypeState>>> m_stack_slots;
|
||||
};
|
||||
} // namespace decompiler
|
||||
@@ -144,7 +144,7 @@ TEST(CommonUtil, PowerOfTwo) {
|
||||
}
|
||||
|
||||
TEST(CommonUtil, CopyOnWrite) {
|
||||
CopyOnWrite<int> x(2);
|
||||
CopyOnWrite<int> x = make_cow<int>(2);
|
||||
|
||||
EXPECT_EQ(*x, 2);
|
||||
*x.mut() = 3;
|
||||
|
||||
Reference in New Issue
Block a user