diff --git a/src/backend/core/JIT/IR.hpp b/src/backend/core/JIT/IR.hpp index 62a9ea74..4cd60a82 100644 --- a/src/backend/core/JIT/IR.hpp +++ b/src/backend/core/JIT/IR.hpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace n64 { struct Entry { diff --git a/src/backend/core/JIT/IR/Opcode.hpp b/src/backend/core/JIT/IR/Opcode.hpp index 12ffd354..9bfc90bc 100644 --- a/src/backend/core/JIT/IR/Opcode.hpp +++ b/src/backend/core/JIT/IR/Opcode.hpp @@ -1,9 +1,11 @@ #pragma once #include +#include +#include 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 @@ -20,13 +23,59 @@ struct IROpcodeBase : IROpcode { auto GetClass() const -> IROpcodeClass override { return _class; } }; -struct IRNoOp final : IROpcodeBase { +template +struct IRBinaryOpBase : IROpcodeBase<_class> { + IRBinaryOpBase(IRVariable const& result, IRVariable lhs, IRAnyRef rhs) + : result(const_cast(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 { + 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 { } auto ToString() -> std::string override { - return "nop"; + return fmt::format("str_pc {}", std::to_string(val)); + } +}; + +struct IRAdd final : IRBinaryOpBase { + using IRBinaryOpBase::IRBinaryOpBase; + + auto ToString() -> std::string override { + return fmt::format( + "add {}, {}, {}", + std::to_string(result), + std::to_string(lhs), + std::to_string(rhs) + ); } }; } \ No newline at end of file diff --git a/src/backend/core/JIT/IR/Value.hpp b/src/backend/core/JIT/IR/Value.hpp index 94b853bd..a801fd7e 100644 --- a/src/backend/core/JIT/IR/Value.hpp +++ b/src/backend/core/JIT/IR/Value.hpp @@ -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 { @@ -95,4 +99,47 @@ struct IRVarRef { 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()); +} } \ No newline at end of file