/* This file is part of the dynarmic project. * Copyright (c) 2016 MerryMage * This software may be used and distributed according to the terms of the GNU * General Public License version 2 or any later version. */ #pragma once #include #include #include #include #include "backend_x64/block_of_code.h" #include "backend_x64/hostloc.h" #include "backend_x64/oparg.h" #include "common/common_types.h" #include "frontend/ir/microinstruction.h" #include "frontend/ir/value.h" namespace Dynarmic { namespace BackendX64 { struct HostLocInfo { public: bool IsIdle() const { return !is_being_used; } bool IsLocked() const { return is_being_used; } bool IsEmpty() const { return !is_being_used && !def && values.empty(); } bool IsScratch() const { return is_being_used && !def && values.empty(); } bool IsUse() const { return is_being_used && !def && !values.empty(); } bool IsDef() const { return is_being_used && def && values.empty(); } bool IsUseDef() const { return is_being_used && def && !values.empty(); } bool ContainsValue(const IR::Inst* inst) const { return std::find(values.begin(), values.end(), inst) != values.end(); } void Lock() { is_being_used = true; } void AddValue(IR::Inst* inst) { values.push_back(inst); } void Def(IR::Inst* inst) { ASSERT(!def); def = inst; } void EndOfAllocScope() { const auto to_erase = std::remove_if(values.begin(), values.end(), [](const auto& inst){ return !inst->HasUses(); }); values.erase(to_erase, values.end()); if (def) { ASSERT(values.empty()); AddValue(def); def = nullptr; } is_being_used = false; } private: std::vector values; // early value IR::Inst* def = nullptr; // late value bool is_being_used = false; }; class RegAlloc final { public: explicit RegAlloc(BlockOfCode* code) : code(code) {} /// Late-def Xbyak::Reg64 DefGpr(IR::Inst* def_inst, HostLocList desired_locations = any_gpr) { return HostLocToReg64(DefHostLocReg(def_inst, desired_locations)); } Xbyak::Xmm DefXmm(IR::Inst* def_inst, HostLocList desired_locations = any_xmm) { return HostLocToXmm(DefHostLocReg(def_inst, desired_locations)); } void RegisterAddDef(IR::Inst* def_inst, const IR::Value& use_inst); /// Early-use, Late-def Xbyak::Reg64 UseDefGpr(IR::Value use_value, IR::Inst* def_inst, HostLocList desired_locations = any_gpr) { return HostLocToReg64(UseDefHostLocReg(use_value, def_inst, desired_locations)); } Xbyak::Xmm UseDefXmm(IR::Value use_value, IR::Inst* def_inst, HostLocList desired_locations = any_xmm) { return HostLocToXmm(UseDefHostLocReg(use_value, def_inst, desired_locations)); } std::tuple UseDefOpArgGpr(IR::Value use_value, IR::Inst* def_inst, HostLocList desired_locations = any_gpr) { OpArg op; HostLoc host_loc; std::tie(op, host_loc) = UseDefOpArgHostLocReg(use_value, def_inst, desired_locations); return std::make_tuple(op, HostLocToReg64(host_loc)); } std::tuple UseDefOpArgXmm(IR::Value use_value, IR::Inst* def_inst, HostLocList desired_locations = any_xmm) { OpArg op; HostLoc host_loc; std::tie(op, host_loc) = UseDefOpArgHostLocReg(use_value, def_inst, desired_locations); return std::make_tuple(op, HostLocToXmm(host_loc)); } /// Early-use Xbyak::Reg64 UseGpr(IR::Value use_value, HostLocList desired_locations = any_gpr) { return HostLocToReg64(UseHostLocReg(use_value, desired_locations)); } Xbyak::Xmm UseXmm(IR::Value use_value, HostLocList desired_locations = any_xmm) { return HostLocToXmm(UseHostLocReg(use_value, desired_locations)); } OpArg UseOpArg(IR::Value use_value, HostLocList desired_locations); /// Early-use, Destroyed Xbyak::Reg64 UseScratchGpr(IR::Value use_value, HostLocList desired_locations = any_gpr) { return HostLocToReg64(UseScratchHostLocReg(use_value, desired_locations)); } Xbyak::Xmm UseScratchXmm(IR::Value use_value, HostLocList desired_locations = any_xmm) { return HostLocToXmm(UseScratchHostLocReg(use_value, desired_locations)); } /// Early-def, Late-use, single-use Xbyak::Reg64 ScratchGpr(HostLocList desired_locations = any_gpr) { return HostLocToReg64(ScratchHostLocReg(desired_locations)); } Xbyak::Xmm ScratchXmm(HostLocList desired_locations = any_xmm) { return HostLocToXmm(ScratchHostLocReg(desired_locations)); } /// Late-def for result register, Early-use for all arguments, Each value is placed into registers according to host ABI. void HostCall(IR::Inst* result_def = nullptr, IR::Value arg0_use = {}, IR::Value arg1_use = {}, IR::Value arg2_use = {}, IR::Value arg3_use = {}); // TODO: Values in host flags void EndOfAllocScope(); void AssertNoMoreUses(); void Reset(); private: HostLoc SelectARegister(HostLocList desired_locations) const; boost::optional ValueLocation(const IR::Inst* value) const; bool IsRegisterOccupied(HostLoc loc) const; bool IsRegisterAllocated(HostLoc loc) const; bool IsLastUse(const IR::Inst* inst) const; HostLoc DefHostLocReg(IR::Inst* def_inst, HostLocList desired_locations); HostLoc UseDefHostLocReg(IR::Value use_value, IR::Inst* def_inst, HostLocList desired_locations); HostLoc UseDefHostLocReg(IR::Inst* use_inst, IR::Inst* def_inst, HostLocList desired_locations); std::tuple UseDefOpArgHostLocReg(IR::Value use_value, IR::Inst* def_inst, HostLocList desired_locations); HostLoc UseHostLocReg(IR::Value use_value, HostLocList desired_locations); HostLoc UseHostLocReg(IR::Inst* use_inst, HostLocList desired_locations); std::tuple UseHostLoc(IR::Inst* use_inst, HostLocList desired_locations); HostLoc UseScratchHostLocReg(IR::Value use_value, HostLocList desired_locations); HostLoc UseScratchHostLocReg(IR::Inst* use_inst, HostLocList desired_locations); HostLoc ScratchHostLocReg(HostLocList desired_locations); void EmitMove(HostLoc to, HostLoc from); void EmitExchange(HostLoc a, HostLoc b); HostLoc LoadImmediateIntoHostLocReg(IR::Value imm, HostLoc reg); void SpillRegister(HostLoc loc); HostLoc FindFreeSpill() const; BlockOfCode* code = nullptr; std::array hostloc_info; HostLocInfo& LocInfo(HostLoc loc) { DEBUG_ASSERT(loc != HostLoc::RSP && loc != HostLoc::R15); return hostloc_info[static_cast(loc)]; } const HostLocInfo& LocInfo(HostLoc loc) const { DEBUG_ASSERT(loc != HostLoc::RSP && loc != HostLoc::R15); return hostloc_info[static_cast(loc)]; } }; } // namespace BackendX64 } // namespace Dynarmic