IR work
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
#include <common.hpp>
|
#include <common.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <IR/Opcode.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
struct Entry {
|
struct Entry {
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <log.hpp>
|
#include <log.hpp>
|
||||||
|
#include <IR/Value.hpp>
|
||||||
|
#include <IR/Register.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
enum class IROpcodeClass {
|
enum class IROpcodeClass {
|
||||||
Normal, Special, Regimm, COP0, COP1
|
StorePC, Add, Special, Regimm, COP0, COP1
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IROpcode {
|
struct IROpcode {
|
||||||
@@ -13,6 +15,7 @@ struct IROpcode {
|
|||||||
virtual auto Writes(IRVariable const& var) -> bool = 0;
|
virtual auto Writes(IRVariable const& var) -> bool = 0;
|
||||||
virtual void Repoint(IRVariable const& var_old, IRVariable const& var_new) = 0;
|
virtual void Repoint(IRVariable const& var_old, IRVariable const& var_new) = 0;
|
||||||
virtual void PropagateConstant(IRVariable const& var, IRConstant const& constant) {}
|
virtual void PropagateConstant(IRVariable const& var, IRConstant const& constant) {}
|
||||||
|
virtual auto ToString() -> std::string = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<IROpcodeClass _class>
|
template<IROpcodeClass _class>
|
||||||
@@ -20,13 +23,59 @@ struct IROpcodeBase : IROpcode {
|
|||||||
auto GetClass() const -> IROpcodeClass override { return _class; }
|
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 {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Writes(IRVariable const& var) -> bool override {
|
auto Writes(IRVariable const& var) -> bool override {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Repoint(
|
void Repoint(
|
||||||
@@ -36,7 +85,20 @@ struct IRNoOp final : IROpcodeBase<IROpcodeClass::NOP> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto ToString() -> std::string override {
|
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 {
|
namespace n64 {
|
||||||
enum IRPrimitive {
|
enum IRPrimitive {
|
||||||
Uint32, Sint32, Uint64, Sint32, Uint128, Sint128
|
Uint32, Sint32, Uint64, Sint64
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IRVariable {
|
struct IRVariable {
|
||||||
IRVariable(IRPrimitive type, const u32 id, char const* const label) : type(type), id(id), label(label) {}
|
IRVariable(IRPrimitive type, const u32 id, char const* const label) : type(type), id(id), label(label), assigned(false) {}
|
||||||
private:
|
|
||||||
IRPrimitive type;
|
IRPrimitive type;
|
||||||
const u32 id;
|
u32 id;
|
||||||
char const* const label;
|
char const* label;
|
||||||
|
bool assigned;
|
||||||
|
|
||||||
|
bool HasValue() const { return assigned; }
|
||||||
|
bool IsNull() const { return !assigned; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IRConstant {
|
struct IRConstant {
|
||||||
IRConstant() {}
|
IRConstant() {}
|
||||||
IRConstant(IRPrimitive type, u128 value) : type(type), value(value) {}
|
IRConstant(IRPrimitive type, u64 value) : type(type), value(value) {}
|
||||||
|
|
||||||
|
u64 value = 0;
|
||||||
private:
|
private:
|
||||||
IRPrimitive type = Uint128;
|
IRPrimitive type = Uint64;
|
||||||
u128 value = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IRAnyRef {
|
struct IRAnyRef {
|
||||||
@@ -95,4 +99,47 @@ struct IRVarRef {
|
|||||||
private:
|
private:
|
||||||
IRVariable const* p_var;
|
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