2021-01-22 20:50:37 -05:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <optional>
|
|
|
|
#include "decompiler/Disasm/Register.h"
|
|
|
|
#include "decompiler/IR2/AtomicOp.h"
|
|
|
|
|
|
|
|
namespace decompiler {
|
|
|
|
class Form;
|
|
|
|
/*!
|
|
|
|
* A FormStack is used to track partial expressions when rebuilding the tree structure of
|
|
|
|
* GOAL code. Linear sequences of operations are added onto the expression stack.
|
|
|
|
*/
|
|
|
|
class FormStack {
|
|
|
|
public:
|
2021-02-14 18:50:45 -05:00
|
|
|
explicit FormStack(bool is_root_stack) : m_is_root_stack(is_root_stack) {}
|
2021-02-28 12:38:29 -05:00
|
|
|
void push_value_to_reg(RegisterAccess var,
|
2021-02-09 20:59:14 -05:00
|
|
|
Form* value,
|
|
|
|
bool sequence_point,
|
2021-03-13 16:10:39 -05:00
|
|
|
TypeSpec type,
|
2021-02-11 16:13:03 -05:00
|
|
|
const SetVarInfo& info = {});
|
2021-02-28 12:38:29 -05:00
|
|
|
void push_non_seq_reg_to_reg(const RegisterAccess& dst,
|
|
|
|
const RegisterAccess& src,
|
2021-02-09 20:59:14 -05:00
|
|
|
Form* src_as_form,
|
2021-03-13 16:10:39 -05:00
|
|
|
TypeSpec type,
|
2021-02-11 16:13:03 -05:00
|
|
|
const SetVarInfo& info = {});
|
2021-02-28 12:38:29 -05:00
|
|
|
void push_value_to_reg_dead(RegisterAccess var,
|
2021-02-15 11:36:59 -05:00
|
|
|
Form* value,
|
|
|
|
bool sequence_point,
|
2021-03-13 16:10:39 -05:00
|
|
|
TypeSpec type,
|
2021-02-15 11:36:59 -05:00
|
|
|
const SetVarInfo& info = {});
|
2021-03-13 16:10:39 -05:00
|
|
|
|
2021-01-22 20:50:37 -05:00
|
|
|
void push_form_element(FormElement* elt, bool sequence_point);
|
2021-02-28 12:38:29 -05:00
|
|
|
Form* pop_reg(const RegisterAccess& var,
|
2021-02-05 19:41:09 -05:00
|
|
|
const RegSet& barrier,
|
|
|
|
const Env& env,
|
2021-02-14 18:50:45 -05:00
|
|
|
bool allow_side_effects,
|
|
|
|
int begin_idx = -1);
|
|
|
|
Form* pop_reg(Register reg,
|
|
|
|
const RegSet& barrier,
|
|
|
|
const Env& env,
|
|
|
|
bool allow_side_effects,
|
2021-06-27 12:11:30 -04:00
|
|
|
int begin_idx = -1,
|
|
|
|
RegisterAccess* orig_out = nullptr,
|
|
|
|
bool* found_orig_out = nullptr);
|
2021-02-18 11:35:45 -05:00
|
|
|
FormElement* pop_back(FormPool& pool);
|
2021-01-22 20:50:37 -05:00
|
|
|
bool is_single_expression();
|
2021-05-30 19:57:11 -04:00
|
|
|
std::vector<FormElement*> rewrite(FormPool& pool, const Env& env) const;
|
2021-01-22 20:50:37 -05:00
|
|
|
std::string print(const Env& env);
|
2021-02-14 18:50:45 -05:00
|
|
|
bool is_root() const { return m_is_root_stack; }
|
2021-01-22 20:50:37 -05:00
|
|
|
|
|
|
|
struct StackEntry {
|
2021-02-28 12:38:29 -05:00
|
|
|
bool active = true; // should this appear in the output?
|
|
|
|
std::optional<RegisterAccess>
|
|
|
|
destination; // what register we are setting (or nullopt if no dest.)
|
|
|
|
std::optional<RegisterAccess> non_seq_source; // source variable, if we are setting var to var.
|
|
|
|
Form* source = nullptr; // the value we are setting the register to.
|
2021-01-22 20:50:37 -05:00
|
|
|
|
|
|
|
FormElement* elt = nullptr;
|
|
|
|
bool sequence_point = false;
|
2021-03-13 16:10:39 -05:00
|
|
|
// TP_Type type;
|
2021-02-24 19:08:55 -05:00
|
|
|
bool is_compactable = false;
|
2021-02-11 16:13:03 -05:00
|
|
|
|
|
|
|
SetVarInfo set_info;
|
2021-03-13 16:10:39 -05:00
|
|
|
TypeSpec set_type;
|
2021-02-11 16:13:03 -05:00
|
|
|
|
2021-01-22 20:50:37 -05:00
|
|
|
std::string print(const Env& env) const;
|
|
|
|
};
|
2021-06-26 18:30:35 -04:00
|
|
|
|
2021-06-26 22:52:52 -04:00
|
|
|
// requires consecutive active entries to succeed (can't skip over inactives).
|
|
|
|
// it's safe to use pop with the same size or smaller to remove the entries you expect.
|
2021-06-26 18:30:35 -04:00
|
|
|
std::optional<std::vector<StackEntry>> try_getting_active_stack_entries(
|
|
|
|
const std::vector<bool>& is_set) const {
|
|
|
|
if (is_set.size() > m_stack.size()) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<StackEntry> entries;
|
|
|
|
size_t offset = m_stack.size() - is_set.size();
|
|
|
|
for (size_t i = 0; i < is_set.size(); i++) {
|
|
|
|
auto& my_entry = m_stack.at(i + offset);
|
|
|
|
if (my_entry.active) {
|
|
|
|
if (is_set.at(i)) {
|
|
|
|
if (!my_entry.destination) {
|
|
|
|
return {};
|
|
|
|
}
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(my_entry.source && !my_entry.elt);
|
2021-06-26 18:30:35 -04:00
|
|
|
} else {
|
|
|
|
if (my_entry.destination) {
|
|
|
|
return {};
|
|
|
|
}
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(my_entry.elt && !my_entry.source);
|
2021-06-26 18:30:35 -04:00
|
|
|
}
|
|
|
|
entries.push_back(my_entry);
|
|
|
|
} else {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return entries;
|
|
|
|
}
|
|
|
|
|
|
|
|
void pop(int count) {
|
|
|
|
for (int i = 0; i < count; i++) {
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(!m_stack.empty());
|
2021-06-26 18:30:35 -04:00
|
|
|
m_stack.pop_back();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-26 22:52:52 -04:00
|
|
|
// get the back, skipping inactives
|
|
|
|
const StackEntry* active_back() const {
|
|
|
|
for (size_t i = m_stack.size(); i-- > 0;) {
|
|
|
|
auto& e = m_stack.at(i);
|
|
|
|
if (e.active) {
|
|
|
|
return &e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// pop the back, skipping inactives
|
|
|
|
void pop_active_back() {
|
|
|
|
for (size_t i = m_stack.size(); i-- > 0;) {
|
|
|
|
auto& e = m_stack.at(i);
|
|
|
|
if (e.active) {
|
|
|
|
m_stack.erase(m_stack.begin() + i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(false);
|
2021-06-26 22:52:52 -04:00
|
|
|
}
|
|
|
|
|
2021-08-22 20:12:47 -04:00
|
|
|
int size() const { return m_stack.size(); }
|
|
|
|
|
2021-06-26 18:30:35 -04:00
|
|
|
private:
|
2021-01-22 20:50:37 -05:00
|
|
|
std::vector<StackEntry> m_stack;
|
2021-02-14 18:50:45 -05:00
|
|
|
bool m_is_root_stack = false;
|
2021-01-22 20:50:37 -05:00
|
|
|
};
|
2021-02-14 18:50:45 -05:00
|
|
|
|
2021-06-26 16:31:38 -04:00
|
|
|
std::optional<RegisterAccess> rewrite_to_get_var(std::vector<FormElement*>& default_result,
|
|
|
|
FormPool& pool,
|
|
|
|
const RegisterAccess& var,
|
|
|
|
const Env& env);
|
2021-02-22 09:36:30 -05:00
|
|
|
std::vector<FormElement*> rewrite_to_get_var(FormStack& stack,
|
|
|
|
FormPool& pool,
|
2021-02-28 12:38:29 -05:00
|
|
|
const RegisterAccess& var,
|
2021-06-26 16:31:38 -04:00
|
|
|
const Env& env,
|
|
|
|
std::optional<RegisterAccess>* used_var = nullptr);
|
2021-01-22 20:50:37 -05:00
|
|
|
} // namespace decompiler
|