A32/IR: Add SetVector and GetVector

This commit is contained in:
MerryMage 2020-05-28 20:39:19 +01:00
parent e85a08ec34
commit 07108246cf
9 changed files with 141 additions and 27 deletions

View file

@ -51,6 +51,10 @@ static Xbyak::Address MJitStateExtReg(A32::ExtReg reg) {
const size_t index = static_cast<size_t>(reg) - static_cast<size_t>(A32::ExtReg::D0);
return qword[r15 + offsetof(A32JitState, ExtReg) + sizeof(u64) * index];
}
if (A32::IsQuadExtReg(reg)) {
const size_t index = static_cast<size_t>(reg) - static_cast<size_t>(A32::ExtReg::Q0);
return xword[r15 + offsetof(A32JitState, ExtReg) + 2 * sizeof(u64) * index];
}
ASSERT_FALSE("Should never happen.");
}
@ -339,6 +343,19 @@ void A32EmitX64::EmitA32GetExtendedRegister64(A32EmitContext& ctx, IR::Inst* ins
ctx.reg_alloc.DefineValue(inst, result);
}
void A32EmitX64::EmitA32GetVector(A32EmitContext& ctx, IR::Inst* inst) {
const A32::ExtReg reg = inst->GetArg(0).GetA32ExtRegRef();
ASSERT(A32::IsDoubleExtReg(reg) || A32::IsQuadExtReg(reg));
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
if (A32::IsDoubleExtReg(reg)) {
code.movsd(result, MJitStateExtReg(reg));
} else {
code.movaps(result, MJitStateExtReg(reg));
}
ctx.reg_alloc.DefineValue(inst, result);
}
void A32EmitX64::EmitA32SetRegister(A32EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
const A32::Reg reg = inst->GetArg(0).GetA32RegRef();
@ -382,6 +399,19 @@ void A32EmitX64::EmitA32SetExtendedRegister64(A32EmitContext& ctx, IR::Inst* ins
}
}
void A32EmitX64::EmitA32SetVector(A32EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
const A32::ExtReg reg = inst->GetArg(0).GetA32ExtRegRef();
ASSERT(A32::IsDoubleExtReg(reg) || A32::IsQuadExtReg(reg));
const Xbyak::Xmm to_store = ctx.reg_alloc.UseXmm(args[1]);
if (A32::IsDoubleExtReg(reg)) {
code.movsd(MJitStateExtReg(reg), to_store);
} else {
code.movaps(MJitStateExtReg(reg), to_store);
}
}
static u32 GetCpsrImpl(A32JitState* jit_state) {
return jit_state->Cpsr();
}

View file

@ -37,13 +37,13 @@ struct A32JitState {
u32 Cpsr() const;
void SetCpsr(u32 cpsr);
alignas(u64) std::array<u32, 64> ExtReg{}; // Extension registers.
alignas(16) std::array<u32, 64> ExtReg{}; // Extension registers.
static constexpr size_t SpillCount = 64;
std::array<u64, SpillCount> Spill{}; // Spill.
alignas(16) std::array<std::array<u64, 2>, SpillCount> spill{}; // Spill.
static Xbyak::Address GetSpillLocationFromIndex(size_t i) {
using namespace Xbyak::util;
return qword[r15 + offsetof(A32JitState, Spill) + i * sizeof(u64)];
return xword[r15 + offsetof(A32JitState, spill) + i * sizeof(u64) * 2];
}
// For internal use (See: BlockOfCode::RunCode)

View file

@ -41,6 +41,11 @@ IR::U32U64 IREmitter::GetExtendedRegister(ExtReg reg) {
ASSERT_FALSE("Invalid reg.");
}
IR::U128 IREmitter::GetVector(ExtReg reg) {
ASSERT(A32::IsDoubleExtReg(reg) || A32::IsQuadExtReg(reg));
return Inst<IR::U128>(Opcode::A32GetVector, IR::Value(reg));
}
void IREmitter::SetRegister(const Reg reg, const IR::U32& value) {
ASSERT(reg != A32::Reg::PC);
Inst(Opcode::A32SetRegister, IR::Value(reg), value);
@ -56,6 +61,11 @@ void IREmitter::SetExtendedRegister(const ExtReg reg, const IR::U32U64& value) {
}
}
void IREmitter::SetVector(ExtReg reg, const IR::U128& value) {
ASSERT(A32::IsDoubleExtReg(reg) || A32::IsQuadExtReg(reg));
Inst(Opcode::A32SetVector, IR::Value(reg), value);
}
void IREmitter::ALUWritePC(const IR::U32& value) {
// This behaviour is ARM version-dependent.
// The below implementation is for ARMv6k

View file

@ -33,8 +33,10 @@ public:
IR::U32 GetRegister(Reg source_reg);
IR::U32U64 GetExtendedRegister(ExtReg source_reg);
IR::U128 GetVector(ExtReg source_reg);
void SetRegister(Reg dest_reg, const IR::U32& value);
void SetExtendedRegister(ExtReg dest_reg, const IR::U32U64& value);
void SetVector(ExtReg dest_reg, const IR::U128& value);
void ALUWritePC(const IR::U32& value);
void BranchWritePC(const IR::U32& value);

View file

@ -38,6 +38,9 @@ const char* ExtRegToString(ExtReg reg) {
"d9", "d10", "d11", "d12", "d13", "d14", "d15", "d16",
"d17", "d18", "d19", "d20", "d21", "d22", "d23", "d24",
"d25", "d26", "d27", "d28", "d29", "d30", "d31",
"q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8",
"q9", "q10", "q11", "q12", "q13", "q14", "q15", "q16",
};
return reg_strs.at(static_cast<size_t>(reg));
}

View file

@ -36,6 +36,8 @@ enum class ExtReg {
D8, D9, D10, D11, D12, D13, D14, D15,
D16, D17, D18, D19, D20, D21, D22, D23,
D24, D25, D26, D27, D28, D29, D30, D31,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7,
Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15,
};
using RegList = u16;
@ -73,6 +75,10 @@ constexpr bool IsDoubleExtReg(ExtReg reg) {
return reg >= ExtReg::D0 && reg <= ExtReg::D31;
}
constexpr bool IsQuadExtReg(ExtReg reg) {
return reg >= ExtReg::Q0 && reg <= ExtReg::Q15;
}
inline size_t RegNumber(Reg reg) {
ASSERT(reg != Reg::INVALID_REG);
return static_cast<size_t>(reg);
@ -87,6 +93,10 @@ inline size_t RegNumber(ExtReg reg) {
return static_cast<size_t>(reg) - static_cast<size_t>(ExtReg::D0);
}
if (IsQuadExtReg(reg)) {
return static_cast<size_t>(reg) - static_cast<size_t>(ExtReg::Q0);
}
ASSERT_FALSE("Invalid extended register");
}
@ -101,11 +111,16 @@ inline ExtReg operator+(ExtReg reg, size_t number) {
const auto new_reg = static_cast<ExtReg>(static_cast<size_t>(reg) + number);
ASSERT((IsSingleExtReg(reg) && IsSingleExtReg(new_reg)) ||
(IsDoubleExtReg(reg) && IsDoubleExtReg(new_reg)));
(IsDoubleExtReg(reg) && IsDoubleExtReg(new_reg)) ||
(IsQuadExtReg(reg) && IsQuadExtReg(new_reg)));
return new_reg;
}
inline ExtReg ToExtRegQ(size_t base, bool bit) {
return ExtReg::Q0 + ((base >> 1) + (bit ? 8 : 0));
}
inline ExtReg ToExtRegD(size_t base, bool bit) {
return ExtReg::D0 + (base + (bit ? 16 : 0));
}
@ -115,11 +130,11 @@ inline ExtReg ToExtRegS(size_t base, bool bit) {
}
inline ExtReg ToExtReg(bool sz, size_t base, bool bit) {
if (sz) {
return ToExtRegD(base, bit);
} else {
return ToExtRegS(base, bit);
}
return sz ? ToExtRegD(base, bit) : ToExtRegS(base, bit);
}
inline ExtReg ToVector(bool Q, size_t base, bool bit) {
return Q ? ToExtRegQ(base, bit) : ToExtRegD(base, bit);
}
} // namespace Dynarmic::A32

View file

@ -198,6 +198,7 @@ bool Inst::ReadsFromCoreRegister() const {
case Opcode::A32GetRegister:
case Opcode::A32GetExtendedRegister32:
case Opcode::A32GetExtendedRegister64:
case Opcode::A32GetVector:
case Opcode::A64GetW:
case Opcode::A64GetX:
case Opcode::A64GetS:
@ -216,6 +217,7 @@ bool Inst::WritesToCoreRegister() const {
case Opcode::A32SetRegister:
case Opcode::A32SetExtendedRegister32:
case Opcode::A32SetExtendedRegister64:
case Opcode::A32SetVector:
case Opcode::A32BXWritePC:
case Opcode::A64SetW:
case Opcode::A64SetX:

View file

@ -9,9 +9,11 @@ A32OPC(SetCheckBit, Void, U1
A32OPC(GetRegister, U32, A32Reg )
A32OPC(GetExtendedRegister32, U32, A32ExtReg )
A32OPC(GetExtendedRegister64, U64, A32ExtReg )
A32OPC(GetVector, U128, A32ExtReg )
A32OPC(SetRegister, Void, A32Reg, U32 )
A32OPC(SetExtendedRegister32, Void, A32ExtReg, U32 )
A32OPC(SetExtendedRegister64, Void, A32ExtReg, U64 )
A32OPC(SetVector, Void, A32ExtReg, U128 )
A32OPC(GetCpsr, U32, )
A32OPC(SetCpsr, Void, U32 )
A32OPC(SetCpsrNZCV, Void, U32 )

View file

@ -23,8 +23,10 @@ void A32GetSetElimination(IR::Block& block) {
Iterator last_set_instruction;
};
std::array<RegisterInfo, 15> reg_info;
std::array<RegisterInfo, 32> ext_reg_singles_info;
std::array<RegisterInfo, 64> ext_reg_singles_info;
std::array<RegisterInfo, 32> ext_reg_doubles_info;
std::array<RegisterInfo, 32> ext_reg_vector_double_info;
std::array<RegisterInfo, 16> ext_reg_vector_quad_info;
struct CpsrInfo {
RegisterInfo n;
RegisterInfo z;
@ -75,10 +77,9 @@ void A32GetSetElimination(IR::Block& block) {
const size_t reg_index = A32::RegNumber(reg);
do_set(ext_reg_singles_info[reg_index], inst->GetArg(1), inst);
const size_t doubles_reg_index = reg_index / 2;
if (doubles_reg_index < ext_reg_doubles_info.size()) {
ext_reg_doubles_info[doubles_reg_index] = {};
}
ext_reg_doubles_info[reg_index / 2] = {};
ext_reg_vector_double_info[reg_index / 2] = {};
ext_reg_vector_quad_info[reg_index / 4] = {};
break;
}
case IR::Opcode::A32GetExtendedRegister32: {
@ -86,10 +87,9 @@ void A32GetSetElimination(IR::Block& block) {
const size_t reg_index = A32::RegNumber(reg);
do_get(ext_reg_singles_info[reg_index], inst);
const size_t doubles_reg_index = reg_index / 2;
if (doubles_reg_index < ext_reg_doubles_info.size()) {
ext_reg_doubles_info[doubles_reg_index] = {};
}
ext_reg_doubles_info[reg_index / 2] = {};
ext_reg_vector_double_info[reg_index / 2] = {};
ext_reg_vector_quad_info[reg_index / 4] = {};
break;
}
case IR::Opcode::A32SetExtendedRegister64: {
@ -97,11 +97,10 @@ void A32GetSetElimination(IR::Block& block) {
const size_t reg_index = A32::RegNumber(reg);
do_set(ext_reg_doubles_info[reg_index], inst->GetArg(1), inst);
const size_t singles_reg_index = reg_index * 2;
if (singles_reg_index < ext_reg_singles_info.size()) {
ext_reg_singles_info[singles_reg_index] = {};
ext_reg_singles_info[singles_reg_index+1] = {};
}
ext_reg_singles_info[reg_index * 2 + 0] = {};
ext_reg_singles_info[reg_index * 2 + 1] = {};
ext_reg_vector_double_info[reg_index] = {};
ext_reg_vector_quad_info[reg_index / 2] = {};
break;
}
case IR::Opcode::A32GetExtendedRegister64: {
@ -109,10 +108,61 @@ void A32GetSetElimination(IR::Block& block) {
const size_t reg_index = A32::RegNumber(reg);
do_get(ext_reg_doubles_info[reg_index], inst);
const size_t singles_reg_index = reg_index * 2;
if (singles_reg_index < ext_reg_singles_info.size()) {
ext_reg_singles_info[singles_reg_index] = {};
ext_reg_singles_info[singles_reg_index+1] = {};
ext_reg_singles_info[reg_index * 2 + 0] = {};
ext_reg_singles_info[reg_index * 2 + 1] = {};
ext_reg_vector_double_info[reg_index] = {};
ext_reg_vector_quad_info[reg_index / 2] = {};
break;
}
case IR::Opcode::A32SetVector: {
const A32::ExtReg reg = inst->GetArg(0).GetA32ExtRegRef();
const size_t reg_index = A32::RegNumber(reg);
if (A32::IsDoubleExtReg(reg)) {
do_set(ext_reg_vector_double_info[reg_index], inst->GetArg(1), inst);
ext_reg_singles_info[reg_index * 2 + 0] = {};
ext_reg_singles_info[reg_index * 2 + 1] = {};
ext_reg_doubles_info[reg_index] = {};
ext_reg_vector_quad_info[reg_index / 2] = {};
} else {
DEBUG_ASSERT(A32::IsQuadExtReg(reg));
do_set(ext_reg_vector_quad_info[reg_index], inst->GetArg(1), inst);
ext_reg_singles_info[reg_index * 4 + 0] = {};
ext_reg_singles_info[reg_index * 4 + 1] = {};
ext_reg_singles_info[reg_index * 4 + 2] = {};
ext_reg_singles_info[reg_index * 4 + 3] = {};
ext_reg_doubles_info[reg_index * 2 + 0] = {};
ext_reg_doubles_info[reg_index * 2 + 1] = {};
ext_reg_vector_double_info[reg_index * 2 + 0] = {};
ext_reg_vector_double_info[reg_index * 2 + 1] = {};
}
break;
}
case IR::Opcode::A32GetVector: {
const A32::ExtReg reg = inst->GetArg(0).GetA32ExtRegRef();
const size_t reg_index = A32::RegNumber(reg);
if (A32::IsDoubleExtReg(reg)) {
do_get(ext_reg_vector_double_info[reg_index], inst);
ext_reg_singles_info[reg_index * 2 + 0] = {};
ext_reg_singles_info[reg_index * 2 + 1] = {};
ext_reg_doubles_info[reg_index] = {};
ext_reg_vector_quad_info[reg_index / 2] = {};
} else {
DEBUG_ASSERT(A32::IsQuadExtReg(reg));
do_get(ext_reg_vector_quad_info[reg_index], inst);
ext_reg_singles_info[reg_index * 4 + 0] = {};
ext_reg_singles_info[reg_index * 4 + 1] = {};
ext_reg_singles_info[reg_index * 4 + 2] = {};
ext_reg_singles_info[reg_index * 4 + 3] = {};
ext_reg_doubles_info[reg_index * 2 + 0] = {};
ext_reg_doubles_info[reg_index * 2 + 1] = {};
ext_reg_vector_double_info[reg_index * 2 + 0] = {};
ext_reg_vector_double_info[reg_index * 2 + 1] = {};
}
break;
}