jak-project/goalc/emitter/Register.h

165 lines
3.8 KiB
C
Raw Normal View History

#pragma once
2020-08-28 20:16:30 -04:00
/*!
* @file Register.h
* Representation of an x86-64 Register.
*/
#ifndef JAK_REGISTER_H
#define JAK_REGISTER_H
#include <cassert>
#include <array>
#include <vector>
2020-09-04 23:24:16 -04:00
#include <string>
2020-08-28 20:16:30 -04:00
#include "common/common_types.h"
namespace emitter {
enum class RegKind : u8 { GPR, XMM, INVALID };
std::string to_string(RegKind kind);
2020-08-28 20:16:30 -04:00
// registers by name
enum X86_REG : s8 {
2020-08-28 20:16:30 -04:00
RAX, // return, temp
2020-09-02 17:51:42 -04:00
RCX, // arg 3, temp
RDX, // arg 2, temp
RBX, // saved
2020-08-28 20:16:30 -04:00
2020-09-02 17:51:42 -04:00
RSP, // stack pointer (special)
RBP, // saved
RSI, // arg 1, temp
RDI, // arg 0, temp
2020-08-28 20:16:30 -04:00
2020-09-02 17:51:42 -04:00
R8, // arg 4, temp
R9, // arg 5, temp
2020-08-28 20:16:30 -04:00
R10, // arg 6, saved (arg in GOAL only)
R11, // arg 7, saved (arg in GOAL only)
2020-09-02 17:51:42 -04:00
R12, // saved
R13, // pp (special!)
R14, // st (special!)
R15, // offset (special!)
2020-08-28 20:16:30 -04:00
XMM0,
XMM1,
XMM2,
XMM3,
XMM4,
XMM5,
XMM6,
XMM7,
XMM8,
XMM9,
XMM10,
XMM11,
XMM12,
XMM13,
XMM14,
XMM15,
2020-08-28 20:16:30 -04:00
};
class Register {
public:
Register() = default;
// intentionally not explicit so we can use X86_REGs in place of Registers
Register(int id) : m_id(id) {}
2020-08-29 19:13:29 -04:00
bool is_xmm() const { return m_id >= XMM0 && m_id <= XMM15; }
2020-08-28 20:16:30 -04:00
2020-08-29 19:13:29 -04:00
bool is_gpr() const { return m_id >= RAX && m_id <= R15; }
2020-08-28 20:16:30 -04:00
2020-08-29 19:13:29 -04:00
int hw_id() const {
2020-08-28 20:16:30 -04:00
if (is_xmm()) {
return m_id - XMM0;
} else if (is_gpr()) {
return m_id - RAX;
} else {
assert(false);
}
return 0xff;
}
2020-08-29 22:41:46 -04:00
int id() const { return m_id; }
2020-08-29 19:13:29 -04:00
2020-08-28 20:16:30 -04:00
struct hash {
auto operator()(const Register& x) const { return std::hash<u8>()(x.m_id); }
};
2020-08-29 19:13:29 -04:00
bool operator==(const Register& x) const { return m_id == x.m_id; }
2020-08-28 20:16:30 -04:00
2020-08-29 19:13:29 -04:00
bool operator!=(const Register& x) const { return m_id != x.m_id; }
2020-08-28 20:16:30 -04:00
std::string print() const;
2020-08-28 20:16:30 -04:00
private:
s8 m_id = -1;
2020-08-28 20:16:30 -04:00
};
2020-08-29 19:13:29 -04:00
class RegisterInfo {
public:
static constexpr int N_ARGS = 8;
static constexpr int N_REGS = 32;
static constexpr int N_SAVED_GPRS = 5;
static constexpr int N_SAVED_XMMS = 8;
static constexpr int N_TEMP_GPRS = 5;
static constexpr int N_TEMP_XMMS = 8;
2020-08-29 19:13:29 -04:00
static_assert(N_REGS - 1 == XMM15, "bad register count");
2020-08-28 20:16:30 -04:00
2020-08-29 19:13:29 -04:00
static RegisterInfo make_register_info();
2020-08-28 20:16:30 -04:00
struct Info {
2020-08-29 19:13:29 -04:00
int argument_id = -1; // -1 if not argument
bool saved = false; // does the callee save it?
bool special = false; // is it a special GOAL register?
2020-08-28 20:16:30 -04:00
std::string name;
bool temp() const { return !saved && !special; }
2020-08-28 20:16:30 -04:00
};
2020-08-29 22:41:46 -04:00
const Info& get_info(Register r) const { return m_info.at(r.id()); }
2020-08-29 19:13:29 -04:00
2020-08-29 22:41:46 -04:00
Register get_arg_reg(int id) const { return m_arg_regs.at(id); }
2020-08-29 19:13:29 -04:00
2020-08-29 22:41:46 -04:00
Register get_saved_gpr(int id) const { return m_saved_gprs.at(id); }
2020-08-28 20:16:30 -04:00
2020-08-29 22:41:46 -04:00
Register get_saved_xmm(int id) const { return m_saved_xmms.at(id); }
2020-08-28 20:16:30 -04:00
2020-08-29 22:41:46 -04:00
Register get_process_reg() const { return R13; }
2020-08-28 20:16:30 -04:00
2020-08-29 22:41:46 -04:00
Register get_st_reg() const { return R14; }
2020-08-28 20:16:30 -04:00
2020-08-29 22:41:46 -04:00
Register get_offset_reg() const { return R15; }
2020-08-29 19:13:29 -04:00
2020-08-29 22:41:46 -04:00
Register get_ret_reg() const { return RAX; }
2020-08-29 19:13:29 -04:00
const std::vector<Register>& get_gpr_alloc_order() { return m_gpr_alloc_order; }
const std::vector<Register>& get_xmm_alloc_order() { return m_xmm_alloc_order; }
const std::vector<Register>& get_gpr_spill_alloc_order() { return m_gpr_spill_temp_alloc_order; }
const std::vector<Register>& get_xmm_spill_alloc_order() { return m_xmm_spill_temp_alloc_order; }
const std::array<Register, N_SAVED_XMMS + N_SAVED_GPRS>& get_all_saved() { return m_saved_all; }
2020-08-29 19:13:29 -04:00
private:
RegisterInfo() = default;
std::array<Info, N_REGS> m_info;
std::array<Register, N_ARGS> m_arg_regs;
std::array<Register, N_SAVED_GPRS> m_saved_gprs;
std::array<Register, N_SAVED_XMMS> m_saved_xmms;
std::array<Register, N_SAVED_XMMS + N_SAVED_GPRS> m_saved_all;
std::vector<Register> m_gpr_alloc_order;
std::vector<Register> m_xmm_alloc_order;
std::vector<Register> m_gpr_spill_temp_alloc_order;
std::vector<Register> m_xmm_spill_temp_alloc_order;
2020-08-29 19:13:29 -04:00
};
2020-08-28 20:16:30 -04:00
extern RegisterInfo gRegInfo;
2020-08-28 20:16:30 -04:00
} // namespace emitter
#endif // JAK_REGISTER_H