mirror of
https://github.com/open-goal/jak-project
synced 2026-09-10 20:29:51 -04:00
wip
This commit is contained in:
@@ -175,6 +175,9 @@ class SimpleAtom {
|
||||
void get_regs(std::vector<Register>* out) const;
|
||||
SimpleExpression as_expr() const;
|
||||
TP_Type get_type(const TypeState& input, const Env& env, const DecompilerTypeSystem& dts) const;
|
||||
RegisterTypeState get_type(InstrTypeState& input,
|
||||
const Env& env,
|
||||
const DecompilerTypeSystem& dts) const;
|
||||
const std::string& get_str() const {
|
||||
assert(is_sym_ptr() || is_sym_val());
|
||||
return m_string;
|
||||
@@ -259,6 +262,10 @@ class SimpleExpression {
|
||||
}
|
||||
void get_regs(std::vector<Register>* out) const;
|
||||
TP_Type get_type(const TypeState& input, const Env& env, const DecompilerTypeSystem& dts) const;
|
||||
RegisterTypeState get_type(InstrTypeState& input,
|
||||
const Env& env,
|
||||
const DecompilerTypeSystem& dts) const;
|
||||
|
||||
TP_Type get_type_int2(const TypeState& input,
|
||||
const Env& env,
|
||||
const DecompilerTypeSystem& dts) const;
|
||||
@@ -298,10 +305,18 @@ class SetVarOp : public AtomicOp {
|
||||
const RegisterAccess& dst() const { return m_dst; }
|
||||
const SimpleExpression& src() const { return m_src; }
|
||||
|
||||
void multi_types_internal(InstrTypeState* output,
|
||||
InstrTypeState& input,
|
||||
const Env& env,
|
||||
DecompilerTypeSystem& dts) override;
|
||||
|
||||
private:
|
||||
RegisterAccess m_dst;
|
||||
SimpleExpression m_src;
|
||||
|
||||
// depending on if we use the new or old type pass.
|
||||
std::optional<TypeSpec> m_source_type;
|
||||
RegisterTypeState* m_source_type_new = nullptr;
|
||||
};
|
||||
|
||||
/*!
|
||||
@@ -725,6 +740,11 @@ class FunctionEndOp : public AtomicOp {
|
||||
return m_return_reg;
|
||||
}
|
||||
|
||||
void multi_types_internal(InstrTypeState* output,
|
||||
InstrTypeState& input,
|
||||
const Env& env,
|
||||
DecompilerTypeSystem& dts) override;
|
||||
|
||||
private:
|
||||
bool m_function_has_return_value = true;
|
||||
RegisterAccess m_return_reg;
|
||||
|
||||
@@ -65,6 +65,7 @@ FormElement* SetVarOp::get_as_form(FormPool& pool, const Env& env) const {
|
||||
}
|
||||
} else {
|
||||
// access a field
|
||||
// TODO: rework for new type pass.
|
||||
auto arg0_type = env.get_types_before_op(m_my_idx).get(m_src.get_arg(0).var().reg());
|
||||
if (arg0_type.kind == TP_Type::Kind::TYPESPEC) {
|
||||
FieldReverseLookupInput rd_in;
|
||||
@@ -93,6 +94,7 @@ FormElement* SetVarOp::get_as_form(FormPool& pool, const Env& env) const {
|
||||
|
||||
// create element
|
||||
auto source = pool.alloc_single_element_form<SimpleExpressionElement>(nullptr, m_src, m_my_idx);
|
||||
// TODO: rework m_source_type for new type pass.
|
||||
auto result = pool.alloc_element<SetVarElement>(m_dst, source, is_sequence_point(),
|
||||
m_source_type.value_or(TypeSpec("object")));
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* register, due to overlapping fields in types. When it encounters a function call, set, or
|
||||
* certain math operation, it will attempt to prune the decision tree to remove incompatible types.
|
||||
*
|
||||
* Compared to
|
||||
*
|
||||
* When there are multiple ways to get the same type, or the type is ambiguous, it will use the one
|
||||
* with the highest score.
|
||||
*
|
||||
@@ -614,7 +616,6 @@ std::vector<TypeState> convert_to_old_format(const std::vector<InstrTypeState>&
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool dbg_types = true;
|
||||
} // namespace
|
||||
|
||||
@@ -807,4 +808,60 @@ void AtomicOp::multi_types_internal(InstrTypeState*,
|
||||
fmt::format("multi_type_internal not yet implemented for {}", typeid(*this).name()));
|
||||
}
|
||||
|
||||
RegisterTypeState SimpleAtom::get_type(InstrTypeState& input,
|
||||
const Env& env,
|
||||
const DecompilerTypeSystem& dts) const {
|
||||
switch (m_kind) {
|
||||
case Kind::VARIABLE:
|
||||
// just get the type in the variable.
|
||||
return input.get_state(var().reg());
|
||||
default:
|
||||
throw std::runtime_error("Simple atom cannot get_type (multi types): " + to_string(env));
|
||||
}
|
||||
}
|
||||
|
||||
RegisterTypeState SimpleExpression::get_type(InstrTypeState& input,
|
||||
const Env& env,
|
||||
const DecompilerTypeSystem& dts) const {
|
||||
switch (m_kind) {
|
||||
case Kind::IDENTITY:
|
||||
// this expression is just an atom, so return the atom's type.
|
||||
return m_args[0].get_type(input, env, dts);
|
||||
default:
|
||||
throw std::runtime_error("Simple expression cannot get_type (multi types): " +
|
||||
to_string(env));
|
||||
}
|
||||
}
|
||||
|
||||
void SetVarOp::multi_types_internal(InstrTypeState* output,
|
||||
InstrTypeState& input,
|
||||
const Env& env,
|
||||
DecompilerTypeSystem& dts) {
|
||||
// we have special cases where we can infer something about the source type from the dest
|
||||
|
||||
// GOAL will use mfc, fX, r0 to set a float to 0.
|
||||
if (m_dst.reg().get_kind() == Reg::FPR && m_src.is_identity() && m_src.get_arg(0).is_int() &&
|
||||
m_src.get_arg(0).get_int() == 0) {
|
||||
output->assign(m_dst.reg(), RegisterTypeState("float"));
|
||||
} else {
|
||||
output->assign(m_dst.reg(), m_src.get_type(input, env, dts));
|
||||
}
|
||||
|
||||
// it's safe to do this, though a little confusing.
|
||||
// if this type is based on a cast, we can't have the possibility of referencing the temporary
|
||||
// cast. Instead we copy the cast (or the result of using the temporary cast) to the output.
|
||||
// If the next op casts this, it won't touch this because it will use its own temporary cast.
|
||||
|
||||
// In the final cast application, this is also okay because this node will be kept, but replaced
|
||||
// in the main graph. This will refer to the type without the cast, which is what we want.
|
||||
auto& out_node = output->get(m_dst.reg());
|
||||
assert(out_node.is_alloc_point() && !out_node.is_clobber() && !out_node.is_cast());
|
||||
m_source_type_new = &output->get_state(m_dst.reg());
|
||||
}
|
||||
|
||||
void FunctionEndOp::multi_types_internal(InstrTypeState*,
|
||||
InstrTypeState&,
|
||||
const Env&,
|
||||
DecompilerTypeSystem&) {}
|
||||
|
||||
} // namespace decompiler
|
||||
@@ -81,9 +81,15 @@ struct RegisterTypeState {
|
||||
bool is_temp_node = false;
|
||||
|
||||
RegisterTypeState() = default;
|
||||
RegisterTypeState(const PossibleType& single_type) : possible_types({single_type}) {
|
||||
explicit RegisterTypeState(const PossibleType& single_type) : possible_types({single_type}) {
|
||||
single_type_cache = 0;
|
||||
}
|
||||
explicit RegisterTypeState(const TP_Type& single_type)
|
||||
: RegisterTypeState(PossibleType(single_type)) {}
|
||||
explicit RegisterTypeState(const TypeSpec& type)
|
||||
: RegisterTypeState(TP_Type::make_from_ts(type)) {}
|
||||
explicit RegisterTypeState(const std::string& type)
|
||||
: RegisterTypeState(TP_Type::make_from_ts(type)) {}
|
||||
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;
|
||||
@@ -119,6 +125,7 @@ struct RegisterNode {
|
||||
}
|
||||
bool is_alloc_point() const { return m_flags & FLAG_ALLOC_POINT; }
|
||||
bool is_clobber() const { return m_flags & FLAG_CLOBBER; }
|
||||
bool is_cast() const { return m_flags & FLAG_CAST_TEMP; }
|
||||
s64 uid() const { return m_uid; }
|
||||
void set_uid(s64 val) { m_uid = val; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user