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
|
|
|
|
|
|
|
|
#include <map>
|
|
|
|
|
|
|
|
#include "backend_x64/jitstate.h"
|
|
|
|
#include "common/common_types.h"
|
|
|
|
#include "common/x64/emitter.h"
|
2016-07-04 10:22:11 +01:00
|
|
|
#include "frontend/ir/ir.h"
|
2016-07-01 14:01:06 +01:00
|
|
|
|
|
|
|
namespace Dynarmic {
|
|
|
|
namespace BackendX64 {
|
|
|
|
|
|
|
|
enum class HostLoc {
|
2016-07-22 23:55:00 +01:00
|
|
|
// Ordering of the registers is intentional. See also: HostLocToX64.
|
|
|
|
RAX, RCX, RDX, RBX, RSP, RBP, RSI, RDI, R8, R9, R10, R11, R12, R13, R14,
|
2016-07-01 14:01:06 +01:00
|
|
|
CF, PF, AF, ZF, SF, OF,
|
|
|
|
FirstSpill,
|
|
|
|
};
|
|
|
|
|
2016-07-22 23:55:00 +01:00
|
|
|
constexpr size_t HostLocCount = static_cast<size_t>(HostLoc::FirstSpill) + SpillCount;
|
|
|
|
|
2016-07-01 14:01:06 +01:00
|
|
|
enum class HostLocState {
|
|
|
|
Idle, Def, Use, Scratch
|
|
|
|
};
|
|
|
|
|
|
|
|
inline bool HostLocIsRegister(HostLoc reg) {
|
|
|
|
return reg >= HostLoc::RAX && reg <= HostLoc::R14;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool HostLocIsFlag(HostLoc reg) {
|
|
|
|
return reg >= HostLoc::CF && reg <= HostLoc::OF;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline HostLoc HostLocSpill(size_t i) {
|
|
|
|
ASSERT_MSG(i < SpillCount, "Invalid spill");
|
|
|
|
return static_cast<HostLoc>(static_cast<int>(HostLoc::FirstSpill) + i);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool HostLocIsSpill(HostLoc reg) {
|
|
|
|
return reg >= HostLoc::FirstSpill && reg <= HostLocSpill(SpillCount - 1);
|
|
|
|
}
|
|
|
|
|
2016-07-12 13:25:33 +01:00
|
|
|
const std::initializer_list<HostLoc> hostloc_any_register = {
|
2016-07-01 14:01:06 +01:00
|
|
|
HostLoc::RAX,
|
|
|
|
HostLoc::RBX,
|
|
|
|
HostLoc::RCX,
|
|
|
|
HostLoc::RDX,
|
|
|
|
HostLoc::RSI,
|
|
|
|
HostLoc::RDI,
|
|
|
|
HostLoc::RBP,
|
|
|
|
HostLoc::RSP,
|
|
|
|
HostLoc::R8,
|
|
|
|
HostLoc::R9,
|
|
|
|
HostLoc::R10,
|
|
|
|
HostLoc::R11,
|
|
|
|
HostLoc::R12,
|
|
|
|
HostLoc::R13,
|
|
|
|
HostLoc::R14
|
|
|
|
};
|
|
|
|
|
|
|
|
class RegAlloc final {
|
|
|
|
public:
|
|
|
|
RegAlloc(Gen::XEmitter* code) : code(code) {}
|
|
|
|
|
|
|
|
/// Late-def
|
2016-07-22 23:55:00 +01:00
|
|
|
Gen::X64Reg DefRegister(IR::Inst* def_inst, std::initializer_list<HostLoc> desired_locations = hostloc_any_register);
|
2016-07-01 14:01:06 +01:00
|
|
|
/// Early-use, Late-def
|
2016-07-22 23:55:00 +01:00
|
|
|
Gen::X64Reg UseDefRegister(IR::Value use_value, IR::Inst* def_inst, std::initializer_list<HostLoc> desired_locations = hostloc_any_register);
|
|
|
|
Gen::X64Reg UseDefRegister(IR::Inst* use_inst, IR::Inst* def_inst, std::initializer_list<HostLoc> desired_locations = hostloc_any_register);
|
2016-07-01 14:01:06 +01:00
|
|
|
/// Early-use
|
2016-07-22 23:55:00 +01:00
|
|
|
Gen::X64Reg UseRegister(IR::Value use_value, std::initializer_list<HostLoc> desired_locations = hostloc_any_register);
|
|
|
|
Gen::X64Reg UseRegister(IR::Inst* use_inst, std::initializer_list<HostLoc> desired_locations = hostloc_any_register);
|
2016-07-18 15:11:16 +01:00
|
|
|
/// Early-use, Destroyed
|
2016-07-22 23:55:00 +01:00
|
|
|
Gen::X64Reg UseScratchRegister(IR::Value use_value, std::initializer_list<HostLoc> desired_locations = hostloc_any_register);
|
|
|
|
Gen::X64Reg UseScratchRegister(IR::Inst* use_inst, std::initializer_list<HostLoc> desired_locations = hostloc_any_register);
|
2016-07-01 14:01:06 +01:00
|
|
|
/// Early-def, Late-use, single-use
|
|
|
|
Gen::X64Reg ScratchRegister(std::initializer_list<HostLoc> desired_locations = hostloc_any_register);
|
2016-07-22 23:55:00 +01:00
|
|
|
Gen::X64Reg LoadImmediateIntoRegister(IR::Value imm, Gen::X64Reg reg);
|
2016-07-01 14:01:06 +01:00
|
|
|
|
2016-07-11 15:28:10 +01:00
|
|
|
/// Late-def for result register, Early-use for all arguments, Each value is placed into registers according to host ABI.
|
2016-07-22 23:55:00 +01:00
|
|
|
void HostCall(IR::Inst* result_def = nullptr, IR::Value arg0_use = {}, IR::Value arg1_use = {}, IR::Value arg2_use = {}, IR::Value arg3_use = {});
|
2016-07-11 15:28:10 +01:00
|
|
|
|
2016-07-01 14:01:06 +01:00
|
|
|
// TODO: Values in host flags
|
|
|
|
|
2016-07-22 23:55:00 +01:00
|
|
|
void DecrementRemainingUses(IR::Inst* value);
|
2016-07-11 22:43:53 +01:00
|
|
|
|
2016-07-01 14:01:06 +01:00
|
|
|
void EndOfAllocScope();
|
|
|
|
|
2016-07-11 22:43:53 +01:00
|
|
|
void AssertNoMoreUses();
|
|
|
|
|
2016-07-04 14:37:50 +01:00
|
|
|
void Reset();
|
|
|
|
|
2016-07-01 14:01:06 +01:00
|
|
|
private:
|
|
|
|
HostLoc SelectARegister(std::initializer_list<HostLoc> desired_locations) const;
|
2016-07-22 23:55:00 +01:00
|
|
|
std::vector<HostLoc> ValueLocations(IR::Inst* value) const;
|
2016-07-01 14:01:06 +01:00
|
|
|
bool IsRegisterOccupied(HostLoc loc) const;
|
|
|
|
bool IsRegisterAllocated(HostLoc loc) const;
|
|
|
|
|
|
|
|
void SpillRegister(HostLoc loc);
|
|
|
|
HostLoc FindFreeSpill() const;
|
|
|
|
|
|
|
|
Gen::XEmitter* code = nullptr;
|
|
|
|
|
2016-07-22 23:55:00 +01:00
|
|
|
using mapping_map_t = std::array<IR::Inst*, HostLocCount>;
|
|
|
|
mapping_map_t hostloc_to_inst;
|
|
|
|
std::array<HostLocState, HostLocCount> hostloc_state;
|
2016-07-01 14:01:06 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace BackendX64
|
|
|
|
} // namespace Dynarmic
|