This commit is contained in:
water
2021-06-21 21:12:02 -04:00
parent 2a62e28e46
commit 9c07c64c9a
7 changed files with 871 additions and 713 deletions
+10
View File
@@ -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)
+16
View File
@@ -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
+49 -27
View File
@@ -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
+2 -2
View File
@@ -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;
+6 -2
View File
@@ -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));