This commit is contained in:
water
2021-06-22 19:05:11 -04:00
parent b9f91e04af
commit 9fb15899bb
4 changed files with 88 additions and 2 deletions
+20
View File
@@ -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;
+2
View File
@@ -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")));
+58 -1
View File
@@ -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
+8 -1
View File
@@ -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; }