jak-project/decompiler/analysis/inline_asm_rewrite.cpp
Tyler Wilding 60db0e5ef9
deps: update fmt to latest version (#3403)
This updates `fmt` to the latest version and moves to just being a copy
of their repo to make updating easier (no editing their cmake / figuring
out which files to minimally include).

The motivation for this is now that we switched to C++ 20, there were a
ton of deprecated function usages that is going away in future compiler
versions. This gets rid of all those warnings.
2024-03-05 22:11:52 -05:00

100 lines
3.6 KiB
C++

#include "inline_asm_rewrite.h"
#include "common/goos/PrettyPrinter.h"
#include "common/log/log.h"
#include "decompiler/Function/Function.h"
#include "decompiler/IR2/Form.h"
#include "decompiler/IR2/FormStack.h"
#include "decompiler/IR2/OpenGoalMapping.h"
#include "decompiler/ObjectFile/LinkedObjectFile.h"
#include "decompiler/analysis/reg_usage.h"
#include "decompiler/util/DecompilerTypeSystem.h"
namespace decompiler {
bool rewrite_inline_asm_instructions(Form* top_level_form,
FormPool& pool,
Function& f,
const DecompilerTypeSystem&) {
ASSERT(top_level_form);
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) {
auto as_load_store = dynamic_cast<VectorFloatLoadStoreElement*>(entry);
if (as_load_store) {
as_load_store->collect_vf_regs(vf_regs);
}
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);*/
f.warnings.error("Unsupported inline assembly instruction kind - [{}]",
asmOp.m_instr.to_string(f.ir2.env.file->labels));
new_entries.push_back(entry);
continue;
} else if (asmOp.skip) {
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());*/
f.warnings.error("Inline assembly instruction marked with TODO - [{}]",
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);
}
ASSERT(!new_entries.empty());
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) {
std::string warning =
fmt::format("ASM instruction re-writing failed in {}: {}", f.name(), e.what());
lg::warn("{}", warning);
f.warnings.error(";; {}", warning);
return false;
}
return true;
}
} // namespace decompiler