diff --git a/src/backend_x64/reg_alloc.cpp b/src/backend_x64/reg_alloc.cpp index 6f9a1f6d..46e003d9 100644 --- a/src/backend_x64/reg_alloc.cpp +++ b/src/backend_x64/reg_alloc.cpp @@ -22,6 +22,8 @@ static u64 ImmediateToU64(const IR::Value& imm) { return u64(imm.GetU1()); case IR::Type::U8: return u64(imm.GetU8()); + case IR::Type::U16: + return u64(imm.GetU16()); case IR::Type::U32: return u64(imm.GetU32()); case IR::Type::U64: @@ -80,6 +82,49 @@ static void EmitExchange(BlockOfCode* code, HostLoc a, HostLoc b) { } } +u8 Argument::GetImmediateU8() const { + u64 imm = ImmediateToU64(value); + ASSERT(imm < 0x100); + return u8(imm); +} + +u16 Argument::GetImmediateU16() const { + u64 imm = ImmediateToU64(value); + ASSERT(imm < 0x10000); + return u16(imm); +} + +u32 Argument::GetImmediateU32() const { + u64 imm = ImmediateToU64(value); + ASSERT(imm < 0x100000000); + return u32(imm); +} + +u64 Argument::GetImmediateU64() const { + return ImmediateToU64(value); +} + +bool Argument::IsInGpr() const { + return HostLocIsGPR(*reg_alloc.ValueLocation(value.GetInst())); +} + +bool Argument::IsInXmm() const { + return HostLocIsXMM(*reg_alloc.ValueLocation(value.GetInst())); +} + +bool Argument::IsInMemory() const { + return HostLocIsSpill(*reg_alloc.ValueLocation(value.GetInst())); +} + +std::array RegAlloc::GetArgumentInfo(IR::Inst* inst) { + std::array ret = { Argument{*this}, Argument{*this}, Argument{*this}}; + for (size_t i = 0; i < inst->NumArgs(); i++) { + IR::Value arg = inst->GetArg(i); + ret[i].value = arg; + } + return ret; +} + void RegAlloc::RegisterAddDef(IR::Inst* def_inst, const IR::Value& use_inst) { DEBUG_ASSERT_MSG(!ValueLocation(def_inst), "def_inst has already been defined"); diff --git a/src/backend_x64/reg_alloc.h b/src/backend_x64/reg_alloc.h index 3bbc5a04..cbc3e56c 100644 --- a/src/backend_x64/reg_alloc.h +++ b/src/backend_x64/reg_alloc.h @@ -22,6 +22,8 @@ namespace Dynarmic { namespace BackendX64 { +class RegAlloc; + struct HostLocInfo { public: bool IsLocked() const { @@ -65,10 +67,88 @@ private: bool is_scratch = false; }; +struct Argument { +public: + IR::Type GetType() const { + return value.GetType(); + } + bool IsImmediate() const { + return value.IsImmediate(); + } + + u8 GetImmediateU8() const; + u16 GetImmediateU16() const; + u32 GetImmediateU32() const; + u64 GetImmediateU64() const; + + /// Is this value currently in a GPR? + bool IsInGpr() const; + /// Is this value currently in a XMM? + bool IsInXmm() const; + /// Is this value currently in memory? + bool IsInMemory() const; + +private: + friend class RegAlloc; + Argument(RegAlloc& reg_alloc) : reg_alloc(reg_alloc) {} + + bool allocated = false; + RegAlloc& reg_alloc; + IR::Value value; +}; + class RegAlloc final { public: explicit RegAlloc(BlockOfCode* code) : code(code) {} + std::array GetArgumentInfo(IR::Inst* inst); + + Xbyak::Reg64 UseGpr(Argument& arg) { + ASSERT(!arg.allocated); + arg.allocated = true; + return HostLocToReg64(UseHostLocReg(arg.value, any_gpr)); + } + Xbyak::Xmm UseXmm(Argument& arg) { + ASSERT(!arg.allocated); + arg.allocated = true; + return HostLocToXmm(UseHostLocReg(arg.value, any_xmm)); + } + void Use(Argument& arg, HostLoc host_loc) { + ASSERT(!arg.allocated); + arg.allocated = true; + UseHostLocReg(arg.value, {host_loc}); + } + + Xbyak::Reg64 UseScratchGpr(Argument& arg) { + ASSERT(!arg.allocated); + arg.allocated = true; + return HostLocToReg64(UseScratchHostLocReg(arg.value, any_gpr)); + } + Xbyak::Xmm UseScratchXmm(Argument& arg) { + ASSERT(!arg.allocated); + arg.allocated = true; + return HostLocToXmm(UseScratchHostLocReg(arg.value, any_xmm)); + } + void UseScratch(Argument& arg, HostLoc host_loc) { + ASSERT(!arg.allocated); + arg.allocated = true; + UseScratchHostLocReg(arg.value, {host_loc}); + } + + void DefineValue(IR::Inst* inst, const Xbyak::Reg64& reg) { + HostLoc hostloc = static_cast(reg.getIdx() + static_cast(HostLoc::RAX)); + DefineValue(inst, hostloc); + } + void DefineValue(IR::Inst* inst, const Xbyak::Xmm& reg) { + HostLoc hostloc = static_cast(reg.getIdx() + static_cast(HostLoc::XMM0)); + DefineValue(inst, hostloc); + } + void DefineValue(IR::Inst* inst, Argument& arg) { + ASSERT(!arg.allocated); + arg.allocated = true; + RegisterAddDef(inst, arg.value); + } + /// Late-def Xbyak::Reg64 DefGpr(IR::Inst* def_inst, HostLocList desired_locations = any_gpr) { HostLoc location = ScratchHostLocReg(desired_locations); @@ -139,6 +219,8 @@ public: void Reset(); private: + friend struct Argument; + HostLoc SelectARegister(HostLocList desired_locations) const; boost::optional ValueLocation(const IR::Inst* value) const;