dynarmic/src/backend/x64/reg_alloc.h

169 lines
4.7 KiB
C
Raw Normal View History

2016-07-01 14:01:06 +01:00
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
2020-04-23 15:25:11 +01:00
* SPDX-License-Identifier: 0BSD
2016-07-01 14:01:06 +01:00
*/
#pragma once
#include <array>
2018-01-04 21:12:02 +00:00
#include <functional>
#include <optional>
#include <utility>
#include <vector>
2016-08-24 20:07:08 +01:00
#include <xbyak.h>
2016-07-01 14:01:06 +01:00
#include "backend/x64/block_of_code.h"
#include "backend/x64/hostloc.h"
#include "backend/x64/oparg.h"
2016-07-01 14:01:06 +01:00
#include "common/common_types.h"
2018-01-18 11:36:48 +00:00
#include "frontend/ir/cond.h"
#include "frontend/ir/microinstruction.h"
#include "frontend/ir/value.h"
2016-07-01 14:01:06 +01:00
namespace Dynarmic::Backend::X64 {
2016-07-01 14:01:06 +01:00
class RegAlloc;
struct HostLocInfo {
public:
bool IsLocked() const;
bool IsEmpty() const;
bool IsLastUse() const;
void ReadLock();
void WriteLock();
void AddArgReference();
void ReleaseOne();
void ReleaseAll();
bool ContainsValue(const IR::Inst* inst) const;
size_t GetMaxBitWidth() const;
void AddValue(IR::Inst* inst);
private:
// Current instruction state
size_t is_being_used_count = 0;
bool is_scratch = false;
// Block state
size_t current_references = 0;
size_t accumulated_uses = 0;
size_t total_uses = 0;
// Value state
std::vector<IR::Inst*> values;
size_t max_bit_width = 0;
};
struct Argument {
public:
using copyable_reference = std::reference_wrapper<Argument>;
IR::Type GetType() const;
bool IsImmediate() const;
bool IsVoid() const;
2018-01-07 11:41:17 +00:00
bool FitsInImmediateU32() const;
bool FitsInImmediateS32() const;
2018-01-07 11:41:17 +00:00
bool GetImmediateU1() const;
u8 GetImmediateU8() const;
u16 GetImmediateU16() const;
u32 GetImmediateU32() const;
u64 GetImmediateS32() const;
u64 GetImmediateU64() const;
2018-01-18 11:36:48 +00:00
IR::Cond GetImmediateCond() 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;
explicit Argument(RegAlloc& reg_alloc) : reg_alloc(reg_alloc) {}
bool allocated = false;
RegAlloc& reg_alloc;
IR::Value value;
};
2016-07-01 14:01:06 +01:00
class RegAlloc final {
public:
using ArgumentInfo = std::array<Argument, IR::max_arg_count>;
explicit RegAlloc(BlockOfCode& code, size_t num_spills, std::function<Xbyak::Address(HostLoc)> spill_to_addr, std::vector<HostLoc> gpr_order, std::vector<HostLoc> xmm_order);
2016-07-01 14:01:06 +01:00
ArgumentInfo GetArgumentInfo(IR::Inst* inst);
2017-02-26 22:28:32 +00:00
Xbyak::Reg64 UseGpr(Argument& arg);
Xbyak::Xmm UseXmm(Argument& arg);
OpArg UseOpArg(Argument& arg);
void Use(Argument& arg, HostLoc host_loc);
2017-02-26 22:28:32 +00:00
Xbyak::Reg64 UseScratchGpr(Argument& arg);
Xbyak::Xmm UseScratchXmm(Argument& arg);
void UseScratch(Argument& arg, HostLoc host_loc);
2017-02-26 22:28:32 +00:00
void DefineValue(IR::Inst* inst, const Xbyak::Reg& reg);
void DefineValue(IR::Inst* inst, Argument& arg);
void Release(const Xbyak::Reg& reg);
Xbyak::Reg64 ScratchGpr();
Xbyak::Reg64 ScratchGpr(HostLoc desired_location);
Xbyak::Xmm ScratchXmm();
Xbyak::Xmm ScratchXmm(HostLoc desired_location);
2016-07-01 14:01:06 +01:00
void HostCall(IR::Inst* result_def = nullptr,
std::optional<Argument::copyable_reference> arg0 = {},
std::optional<Argument::copyable_reference> arg1 = {},
std::optional<Argument::copyable_reference> arg2 = {},
std::optional<Argument::copyable_reference> arg3 = {});
2016-07-01 14:01:06 +01:00
// TODO: Values in host flags
void EndOfAllocScope();
void AssertNoMoreUses();
2016-07-01 14:01:06 +01:00
private:
friend struct Argument;
std::vector<HostLoc> gpr_order;
std::vector<HostLoc> xmm_order;
HostLoc SelectARegister(const std::vector<HostLoc>& desired_locations) const;
std::optional<HostLoc> ValueLocation(const IR::Inst* value) const;
HostLoc UseImpl(IR::Value use_value, const std::vector<HostLoc>& desired_locations);
HostLoc UseScratchImpl(IR::Value use_value, const std::vector<HostLoc>& desired_locations);
HostLoc ScratchImpl(const std::vector<HostLoc>& desired_locations);
2017-02-26 22:28:32 +00:00
void DefineValueImpl(IR::Inst* def_inst, HostLoc host_loc);
void DefineValueImpl(IR::Inst* def_inst, const IR::Value& use_inst);
HostLoc LoadImmediate(IR::Value imm, HostLoc host_loc);
2017-02-24 19:42:36 +00:00
void Move(HostLoc to, HostLoc from);
void CopyToScratch(size_t bit_width, HostLoc to, HostLoc from);
2017-02-24 19:42:36 +00:00
void Exchange(HostLoc a, HostLoc b);
void MoveOutOfTheWay(HostLoc reg);
2016-07-01 14:01:06 +01:00
void SpillRegister(HostLoc loc);
HostLoc FindFreeSpill() const;
2018-01-04 21:12:02 +00:00
std::vector<HostLocInfo> hostloc_info;
2017-02-26 22:28:32 +00:00
HostLocInfo& LocInfo(HostLoc loc);
const HostLocInfo& LocInfo(HostLoc loc) const;
2018-01-04 21:12:02 +00:00
BlockOfCode& code;
2018-01-04 21:12:02 +00:00
std::function<Xbyak::Address(HostLoc)> spill_to_addr;
void EmitMove(size_t bit_width, HostLoc to, HostLoc from);
2018-01-04 21:12:02 +00:00
void EmitExchange(HostLoc a, HostLoc b);
2016-07-01 14:01:06 +01:00
};
} // namespace Dynarmic::Backend::X64