2021-03-06 10:46:26 -05:00
|
|
|
#include "inline_asm_rewrite.h"
|
2021-09-11 20:52:35 -04:00
|
|
|
#include "common/goos/PrettyPrinter.h"
|
2021-03-06 10:46:26 -05:00
|
|
|
#include "decompiler/Function/Function.h"
|
|
|
|
#include "decompiler/IR2/Form.h"
|
|
|
|
#include "decompiler/IR2/FormStack.h"
|
|
|
|
#include "decompiler/IR2/OpenGoalMapping.h"
|
2021-03-28 20:26:30 -04:00
|
|
|
#include "decompiler/ObjectFile/LinkedObjectFile.h"
|
2021-09-11 20:52:35 -04:00
|
|
|
#include "decompiler/analysis/reg_usage.h"
|
|
|
|
#include "decompiler/util/DecompilerTypeSystem.h"
|
2021-03-06 10:46:26 -05:00
|
|
|
|
|
|
|
namespace decompiler {
|
|
|
|
|
|
|
|
bool rewrite_inline_asm_instructions(Form* top_level_form,
|
|
|
|
FormPool& pool,
|
|
|
|
Function& f,
|
2021-03-06 20:16:48 -05:00
|
|
|
const DecompilerTypeSystem&) {
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(top_level_form);
|
2021-03-06 10:46:26 -05:00
|
|
|
|
|
|
|
try {
|
|
|
|
RegSet vf_regs;
|
|
|
|
// Iterate through all TLFs
|
|
|
|
top_level_form->apply_form([&](Form* form) {
|
|
|
|
std::vector<FormElement*> new_entries;
|
|
|
|
for (auto& entry : form->elts()) {
|
|
|
|
// All vector instructions are inline assembly, so we only care to re-write assembly
|
|
|
|
// operations
|
|
|
|
AsmOpElement* elem = dynamic_cast<AsmOpElement*>(entry);
|
|
|
|
if (!elem) {
|
2021-03-27 15:18:59 -04:00
|
|
|
auto as_load_store = dynamic_cast<VectorFloatLoadStoreElement*>(entry);
|
|
|
|
if (as_load_store) {
|
|
|
|
as_load_store->collect_vf_regs(vf_regs);
|
|
|
|
}
|
2021-03-06 10:46:26 -05:00
|
|
|
new_entries.push_back(entry);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We then convert the normal AsmOpElement to a more tailor-made FormElement that has
|
|
|
|
// OpenGOAL considerations Not _all_ assembly instructors are vector
|
|
|
|
OpenGOALAsm asmOp = OpenGOALAsm(elem->op()->instruction());
|
|
|
|
if (!asmOp.valid) {
|
|
|
|
// If its an invalid or unsupported exception, skip it
|
|
|
|
/*lg::warn("[ASM Re-Write] - Unsupported inline assembly instruction kind - [{}]",
|
|
|
|
asmOp.instr.kind);*/
|
2021-03-06 20:16:48 -05:00
|
|
|
f.warnings.general_warning("Unsupported inline assembly instruction kind - [{}]",
|
2022-01-18 01:14:47 -05:00
|
|
|
asmOp.m_instr.to_string(f.ir2.env.file->labels));
|
2021-03-06 10:46:26 -05:00
|
|
|
new_entries.push_back(entry);
|
|
|
|
continue;
|
|
|
|
} else if (asmOp.todo) {
|
|
|
|
// If its an invalid or unsupported exception, skip it
|
|
|
|
/*lg::warn("[ASM Re-Write] - Inline assembly instruction marked with TODO - [{}]",
|
|
|
|
asmOp.full_function_name());*/
|
2021-03-06 20:16:48 -05:00
|
|
|
f.warnings.general_warning("Inline assembly instruction marked with TODO - [{}]",
|
2021-03-06 10:46:26 -05:00
|
|
|
asmOp.full_function_name());
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we've made it this far, it's an AsmOperation that is also a supported vector
|
|
|
|
// instruction by OpenGOAL All we have to do is convert it to the correct `FormElement` that
|
|
|
|
// will write the form so it works for OpenGOAL
|
|
|
|
|
|
|
|
OpenGoalAsmOpElement* newElem = pool.alloc_element<OpenGoalAsmOpElement>(elem->op());
|
|
|
|
newElem->collect_vf_regs(vf_regs);
|
|
|
|
|
|
|
|
new_entries.push_back(newElem);
|
|
|
|
}
|
|
|
|
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(!new_entries.empty());
|
2021-03-06 10:46:26 -05:00
|
|
|
form->clear();
|
|
|
|
for (auto x : new_entries) {
|
|
|
|
form->push_back(x);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// If we have to wrap the entire function in an 'rlet'
|
|
|
|
if (!vf_regs.empty()) {
|
|
|
|
Form* body = pool.alloc_empty_form();
|
|
|
|
for (auto& entry : top_level_form->elts()) {
|
|
|
|
body->push_back(entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
RLetElement* rlet = pool.alloc_element<RLetElement>(body, vf_regs);
|
|
|
|
top_level_form->clear();
|
|
|
|
top_level_form->push_back(rlet);
|
|
|
|
}
|
|
|
|
} catch (std::exception& e) {
|
2021-09-11 20:52:35 -04:00
|
|
|
std::string warning =
|
|
|
|
fmt::format("ASM instruction re-writing failed in {}: {}", f.name(), e.what());
|
2021-03-06 10:46:26 -05:00
|
|
|
lg::warn(warning);
|
|
|
|
f.warnings.general_warning(";; {}", warning);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} // namespace decompiler
|