IR work
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
#include <common.hpp>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <IR/Opcode.hpp>
|
||||
|
||||
namespace n64 {
|
||||
struct Entry {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#pragma once
|
||||
#include <log.hpp>
|
||||
#include <IR/Value.hpp>
|
||||
#include <IR/Register.hpp>
|
||||
|
||||
namespace n64 {
|
||||
enum class IROpcodeClass {
|
||||
Normal, Special, Regimm, COP0, COP1
|
||||
StorePC, Add, Special, Regimm, COP0, COP1
|
||||
};
|
||||
|
||||
struct IROpcode {
|
||||
@@ -13,6 +15,7 @@ struct IROpcode {
|
||||
virtual auto Writes(IRVariable const& var) -> bool = 0;
|
||||
virtual void Repoint(IRVariable const& var_old, IRVariable const& var_new) = 0;
|
||||
virtual void PropagateConstant(IRVariable const& var, IRConstant const& constant) {}
|
||||
virtual auto ToString() -> std::string = 0;
|
||||
};
|
||||
|
||||
template<IROpcodeClass _class>
|
||||
@@ -20,13 +23,59 @@ struct IROpcodeBase : IROpcode {
|
||||
auto GetClass() const -> IROpcodeClass override { return _class; }
|
||||
};
|
||||
|
||||
struct IRNoOp final : IROpcodeBase<IROpcodeClass::NOP> {
|
||||
template<IROpcodeClass _class>
|
||||
struct IRBinaryOpBase : IROpcodeBase<_class> {
|
||||
IRBinaryOpBase(IRVariable const& result, IRVariable lhs, IRAnyRef rhs)
|
||||
: result(const_cast<IRVariable &>(result)), lhs(lhs), rhs(rhs) {}
|
||||
|
||||
IRVariable& result;
|
||||
IRVarRef lhs;
|
||||
IRAnyRef rhs;
|
||||
|
||||
auto Reads(IRVariable const& var) -> bool override {
|
||||
return &lhs.Get() == &var ||
|
||||
(rhs.IsVariable() && (&rhs.GetVar() == &var));
|
||||
}
|
||||
|
||||
auto Writes(IRVariable const& var) -> bool override {
|
||||
return result.HasValue() && (&result == &var);
|
||||
}
|
||||
|
||||
void Repoint(
|
||||
IRVariable const& var_old,
|
||||
IRVariable const& var_new
|
||||
) override {
|
||||
// TODO: make this reusable?
|
||||
if (result.HasValue() && (&result == &var_old)) {
|
||||
result = var_new;
|
||||
}
|
||||
|
||||
lhs.Repoint(var_old, var_new);
|
||||
rhs.Repoint(var_old, var_new);
|
||||
}
|
||||
|
||||
void PropagateConstant(
|
||||
IRVariable const& var,
|
||||
IRConstant const& constant
|
||||
) override {
|
||||
rhs.PropagateConstant(var, constant);
|
||||
}
|
||||
};
|
||||
|
||||
struct IRStorePC final : IROpcodeBase<IROpcodeClass::StorePC> {
|
||||
IRStorePC(IRAnyRef val) : val(val) {}
|
||||
|
||||
IRAnyRef val;
|
||||
|
||||
auto Reads(IRVariable const& var) -> bool override {
|
||||
if(val.IsVariable()) {
|
||||
return &var == &val.GetVar();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto Writes(IRVariable const& var) -> bool override {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Repoint(
|
||||
@@ -36,7 +85,20 @@ struct IRNoOp final : IROpcodeBase<IROpcodeClass::NOP> {
|
||||
}
|
||||
|
||||
auto ToString() -> std::string override {
|
||||
return "nop";
|
||||
return fmt::format("str_pc {}", std::to_string(val));
|
||||
}
|
||||
};
|
||||
|
||||
struct IRAdd final : IRBinaryOpBase<IROpcodeClass::Add> {
|
||||
using IRBinaryOpBase::IRBinaryOpBase;
|
||||
|
||||
auto ToString() -> std::string override {
|
||||
return fmt::format(
|
||||
"add {}, {}, {}",
|
||||
std::to_string(result),
|
||||
std::to_string(lhs),
|
||||
std::to_string(rhs)
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -3,23 +3,27 @@
|
||||
|
||||
namespace n64 {
|
||||
enum IRPrimitive {
|
||||
Uint32, Sint32, Uint64, Sint32, Uint128, Sint128
|
||||
Uint32, Sint32, Uint64, Sint64
|
||||
};
|
||||
|
||||
struct IRVariable {
|
||||
IRVariable(IRPrimitive type, const u32 id, char const* const label) : type(type), id(id), label(label) {}
|
||||
private:
|
||||
IRVariable(IRPrimitive type, const u32 id, char const* const label) : type(type), id(id), label(label), assigned(false) {}
|
||||
IRPrimitive type;
|
||||
const u32 id;
|
||||
char const* const label;
|
||||
u32 id;
|
||||
char const* label;
|
||||
bool assigned;
|
||||
|
||||
bool HasValue() const { return assigned; }
|
||||
bool IsNull() const { return !assigned; }
|
||||
};
|
||||
|
||||
struct IRConstant {
|
||||
IRConstant() {}
|
||||
IRConstant(IRPrimitive type, u128 value) : type(type), value(value) {}
|
||||
IRConstant(IRPrimitive type, u64 value) : type(type), value(value) {}
|
||||
|
||||
u64 value = 0;
|
||||
private:
|
||||
IRPrimitive type = Uint128;
|
||||
u128 value = 0;
|
||||
IRPrimitive type = Uint64;
|
||||
};
|
||||
|
||||
struct IRAnyRef {
|
||||
@@ -96,3 +100,46 @@ private:
|
||||
IRVariable const* p_var;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
namespace std {
|
||||
inline auto to_string(n64::IRPrimitive data_type) -> std::string {
|
||||
switch (data_type) {
|
||||
case n64::IRPrimitive::Uint32:
|
||||
return "u32";
|
||||
case n64::IRPrimitive::Sint32:
|
||||
return "s32";
|
||||
case n64::IRPrimitive::Uint64:
|
||||
return "u64";
|
||||
case n64::IRPrimitive::Sint64:
|
||||
return "s64";
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
||||
inline auto to_string(n64::IRVariable const &variable) -> std::string {
|
||||
if (variable.label) {
|
||||
return fmt::format("var{}_{}", variable.id, variable.label);
|
||||
}
|
||||
return fmt::format("var{}", variable.id);
|
||||
}
|
||||
|
||||
inline auto to_string(n64::IRConstant const &constant) -> std::string {
|
||||
return fmt::format("0x{:0X}", constant.value);
|
||||
}
|
||||
|
||||
inline auto to_string(n64::IRAnyRef const &value) -> std::string {
|
||||
if (value.IsNull()) {
|
||||
return "(null)";
|
||||
}
|
||||
if (value.IsConstant()) {
|
||||
return std::to_string(value.GetConst());
|
||||
}
|
||||
return std::to_string(value.GetVar());
|
||||
}
|
||||
|
||||
inline auto to_string(n64::IRVarRef const &variable) -> std::string {
|
||||
return std::to_string(variable.Get());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user