2016-07-01 14:01:06 +01:00
|
|
|
/* 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
|
|
|
|
|
2016-08-17 15:53:36 +01:00
|
|
|
#include <array>
|
2018-01-04 21:12:02 +00:00
|
|
|
#include <functional>
|
2018-01-27 02:35:42 +00:00
|
|
|
#include <utility>
|
2016-08-17 15:53:36 +01:00
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#include <boost/optional.hpp>
|
2016-08-24 20:07:08 +01:00
|
|
|
#include <xbyak.h>
|
2016-07-01 14:01:06 +01:00
|
|
|
|
2016-08-07 18:08:48 +01:00
|
|
|
#include "backend_x64/block_of_code.h"
|
2016-08-24 20:07:08 +01:00
|
|
|
#include "backend_x64/hostloc.h"
|
2017-02-21 23:38:36 +00:00
|
|
|
#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"
|
2016-08-17 15:53:36 +01:00
|
|
|
#include "frontend/ir/microinstruction.h"
|
|
|
|
#include "frontend/ir/value.h"
|
2016-07-01 14:01:06 +01:00
|
|
|
|
2018-01-26 13:51:48 +00:00
|
|
|
namespace Dynarmic::BackendX64 {
|
2016-07-01 14:01:06 +01:00
|
|
|
|
2017-02-24 21:09:12 +00:00
|
|
|
class RegAlloc;
|
|
|
|
|
2017-02-24 18:42:59 +00:00
|
|
|
struct HostLocInfo {
|
|
|
|
public:
|
2017-02-26 23:16:41 +00:00
|
|
|
bool IsLocked() const;
|
|
|
|
bool IsEmpty() const;
|
|
|
|
bool IsLastUse() const;
|
|
|
|
|
|
|
|
void ReadLock();
|
|
|
|
void WriteLock();
|
2017-11-27 19:38:22 +00:00
|
|
|
void AddArgReference();
|
2017-02-26 23:16:41 +00:00
|
|
|
void EndOfAllocScope();
|
2017-02-24 18:42:59 +00:00
|
|
|
|
2018-01-18 13:00:07 +00:00
|
|
|
bool ContainsValue(const IR::Inst* inst) const;
|
|
|
|
size_t GetMaxBitWidth() const;
|
|
|
|
|
|
|
|
void AddValue(IR::Inst* inst);
|
|
|
|
|
2017-02-24 18:42:59 +00:00
|
|
|
private:
|
2018-01-18 13:00:07 +00:00
|
|
|
// Current instruction state
|
2017-02-24 18:42:59 +00:00
|
|
|
bool is_being_used = false;
|
2017-02-24 20:19:50 +00:00
|
|
|
bool is_scratch = false;
|
2017-11-27 19:38:22 +00:00
|
|
|
|
2018-01-18 13:00:07 +00:00
|
|
|
// Block state
|
2017-11-27 19:38:22 +00:00
|
|
|
size_t current_references = 0;
|
|
|
|
size_t accumulated_uses = 0;
|
|
|
|
size_t total_uses = 0;
|
2018-01-18 13:00:07 +00:00
|
|
|
|
|
|
|
// Value state
|
|
|
|
std::vector<IR::Inst*> values;
|
|
|
|
size_t max_bit_width = 0;
|
2017-02-24 18:42:59 +00:00
|
|
|
};
|
|
|
|
|
2017-02-24 21:09:12 +00:00
|
|
|
struct Argument {
|
|
|
|
public:
|
2017-02-26 23:16:41 +00:00
|
|
|
IR::Type GetType() const;
|
|
|
|
bool IsImmediate() const;
|
2017-02-24 21:09:12 +00:00
|
|
|
|
2018-01-07 11:41:17 +00:00
|
|
|
bool FitsInImmediateU32() const;
|
2018-01-13 17:59:50 +00:00
|
|
|
bool FitsInImmediateS32() const;
|
2018-01-07 11:41:17 +00:00
|
|
|
|
2017-02-24 21:25:31 +00:00
|
|
|
bool GetImmediateU1() const;
|
2017-02-24 21:09:12 +00:00
|
|
|
u8 GetImmediateU8() const;
|
|
|
|
u16 GetImmediateU16() const;
|
|
|
|
u32 GetImmediateU32() const;
|
2018-01-13 17:59:50 +00:00
|
|
|
u64 GetImmediateS32() const;
|
2017-02-24 21:09:12 +00:00
|
|
|
u64 GetImmediateU64() const;
|
2018-01-18 11:36:48 +00:00
|
|
|
IR::Cond GetImmediateCond() const;
|
2017-02-24 21:09:12 +00:00
|
|
|
|
|
|
|
/// 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;
|
|
|
|
};
|
|
|
|
|
2016-07-01 14:01:06 +01:00
|
|
|
class RegAlloc final {
|
|
|
|
public:
|
2018-01-04 21:12:02 +00:00
|
|
|
explicit RegAlloc(BlockOfCode* code, size_t num_spills, std::function<Xbyak::Address(HostLoc)> spill_to_addr)
|
2018-01-27 02:35:42 +00:00
|
|
|
: hostloc_info(NonSpillHostLocCount + num_spills), code(code), spill_to_addr(std::move(spill_to_addr)) {}
|
2016-07-01 14:01:06 +01:00
|
|
|
|
2017-02-24 21:09:12 +00:00
|
|
|
std::array<Argument, 3> 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-24 21:09:12 +00:00
|
|
|
|
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-24 21:09:12 +00:00
|
|
|
|
2017-02-26 22:28:32 +00:00
|
|
|
void DefineValue(IR::Inst* inst, const Xbyak::Reg& reg);
|
|
|
|
void DefineValue(IR::Inst* inst, Argument& arg);
|
2017-02-24 21:09:12 +00:00
|
|
|
|
2017-02-26 22:28:32 +00:00
|
|
|
Xbyak::Reg64 ScratchGpr(HostLocList desired_locations = any_gpr);
|
|
|
|
Xbyak::Xmm ScratchXmm(HostLocList desired_locations = any_xmm);
|
2016-07-01 14:01:06 +01:00
|
|
|
|
2017-02-26 22:28:32 +00:00
|
|
|
void HostCall(IR::Inst* result_def = nullptr, boost::optional<Argument&> arg0 = {}, boost::optional<Argument&> arg1 = {}, boost::optional<Argument&> arg2 = {}, boost::optional<Argument&> arg3 = {});
|
2016-07-11 15:28:10 +01:00
|
|
|
|
2016-07-01 14:01:06 +01:00
|
|
|
// TODO: Values in host flags
|
|
|
|
|
|
|
|
void EndOfAllocScope();
|
|
|
|
|
2016-07-11 22:43:53 +01:00
|
|
|
void AssertNoMoreUses();
|
|
|
|
|
2016-07-01 14:01:06 +01:00
|
|
|
private:
|
2017-02-24 21:09:12 +00:00
|
|
|
friend struct Argument;
|
|
|
|
|
2016-08-02 13:46:12 +01:00
|
|
|
HostLoc SelectARegister(HostLocList desired_locations) const;
|
2016-08-19 03:13:38 +01:00
|
|
|
boost::optional<HostLoc> ValueLocation(const IR::Inst* value) const;
|
2016-08-05 14:10:39 +01:00
|
|
|
|
2017-02-26 22:28:32 +00:00
|
|
|
HostLoc UseImpl(IR::Value use_value, HostLocList desired_locations);
|
|
|
|
HostLoc UseScratchImpl(IR::Value use_value, HostLocList desired_locations);
|
|
|
|
HostLoc ScratchImpl(HostLocList desired_locations);
|
|
|
|
void DefineValueImpl(IR::Inst* def_inst, HostLoc host_loc);
|
|
|
|
void DefineValueImpl(IR::Inst* def_inst, const IR::Value& use_inst);
|
2017-02-24 19:08:58 +00:00
|
|
|
|
2017-02-26 22:28:32 +00:00
|
|
|
HostLoc LoadImmediate(IR::Value imm, HostLoc reg);
|
2017-02-24 19:42:36 +00:00
|
|
|
void Move(HostLoc to, HostLoc from);
|
2017-02-24 19:58:16 +00:00
|
|
|
void CopyToScratch(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 = nullptr;
|
|
|
|
std::function<Xbyak::Address(HostLoc)> spill_to_addr;
|
|
|
|
void EmitMove(HostLoc to, HostLoc from);
|
|
|
|
void EmitExchange(HostLoc a, HostLoc b);
|
2016-07-01 14:01:06 +01:00
|
|
|
};
|
|
|
|
|
2018-01-26 13:51:48 +00:00
|
|
|
} // namespace Dynarmic::BackendX64
|