citra-emu
/
citra-canary
Archived
1
0
Fork 0

common/aarch64: Push/Pop pairs of registers at a time (#7129)

This commit is contained in:
Wunk 2023-11-08 15:39:11 -08:00 committed by GitHub
parent 7930e1ea86
commit ee372572a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 72 additions and 26 deletions

View File

@ -89,22 +89,45 @@ inline void ABI_PushRegisters(oaknut::CodeGenerator& code, std::bitset<64> regs,
code.SUB(SP, SP, frame_info.subtraction); code.SUB(SP, SP, frame_info.subtraction);
} }
// TODO(wunk): Push pairs of registers at a time with STP {
std::size_t offset = 0; const std::bitset<64> gprs_mask = (regs & ABI_ALL_GPRS);
for (std::size_t i = 0; i < 32; ++i) { std::vector<XReg> gprs;
if (regs[i] && ABI_ALL_GPRS[i]) { gprs.reserve(32);
const XReg reg = IndexToXReg(i); for (u8 i = 0; i < 32; ++i) {
code.STR(reg, SP, offset); if (gprs_mask.test(i)) {
offset += 8; gprs.emplace_back(IndexToXReg(i));
}
}
if (!gprs.empty()) {
for (size_t i = 0; i < gprs.size() - 1; i += 2) {
code.STP(gprs[i], gprs[i + 1], SP, i * sizeof(u64));
}
if (gprs.size() % 2 == 1) {
const size_t i = gprs.size() - 1;
code.STR(gprs[i], SP, i * sizeof(u64));
}
} }
} }
offset = 0; {
for (std::size_t i = 32; i < 64; ++i) { const std::bitset<64> fprs_mask = (regs & ABI_ALL_FPRS);
if (regs[i] && ABI_ALL_FPRS[i]) { std::vector<QReg> fprs;
const VReg reg = IndexToVReg(i); fprs.reserve(32);
code.STR(reg.toQ(), SP, u16(frame_info.fprs_offset + offset)); for (u8 i = 32; i < 64; ++i) {
offset += 16; if (fprs_mask.test(i)) {
fprs.emplace_back(IndexToVReg(i).toQ());
}
}
if (!fprs.empty()) {
for (size_t i = 0; i < fprs.size() - 1; i += 2) {
code.STP(fprs[i], fprs[i + 1], SP, frame_info.fprs_offset + i * (sizeof(u64) * 2));
}
if (fprs.size() % 2 == 1) {
const size_t i = fprs.size() - 1;
code.STR(fprs[i], SP, frame_info.fprs_offset + i * (sizeof(u64) * 2));
}
} }
} }
@ -125,22 +148,45 @@ inline void ABI_PopRegisters(oaknut::CodeGenerator& code, std::bitset<64> regs,
code.ADD(SP, SP, frame_size); code.ADD(SP, SP, frame_size);
} }
// TODO(wunk): Pop pairs of registers at a time with LDP {
std::size_t offset = 0; const std::bitset<64> gprs_mask = (regs & ABI_ALL_GPRS);
for (std::size_t i = 0; i < 32; ++i) { std::vector<XReg> gprs;
if (regs[i] && ABI_ALL_GPRS[i]) { gprs.reserve(32);
const XReg reg = IndexToXReg(i); for (u8 i = 0; i < 32; ++i) {
code.LDR(reg, SP, offset); if (gprs_mask.test(i)) {
offset += 8; gprs.emplace_back(IndexToXReg(i));
}
}
if (!gprs.empty()) {
for (size_t i = 0; i < gprs.size() - 1; i += 2) {
code.LDP(gprs[i], gprs[i + 1], SP, i * sizeof(u64));
}
if (gprs.size() % 2 == 1) {
const size_t i = gprs.size() - 1;
code.LDR(gprs[i], SP, i * sizeof(u64));
}
} }
} }
offset = 0; {
for (std::size_t i = 32; i < 64; ++i) { const std::bitset<64> fprs_mask = (regs & ABI_ALL_FPRS);
if (regs[i] && ABI_ALL_FPRS[i]) { std::vector<QReg> fprs;
const VReg reg = IndexToVReg(i); fprs.reserve(32);
code.LDR(reg.toQ(), SP, frame_info.fprs_offset + offset); for (u8 i = 32; i < 64; ++i) {
offset += 16; if (fprs_mask.test(i)) {
fprs.emplace_back(IndexToVReg(i).toQ());
}
}
if (!fprs.empty()) {
for (size_t i = 0; i < fprs.size() - 1; i += 2) {
code.LDP(fprs[i], fprs[i + 1], SP, frame_info.fprs_offset + i * (sizeof(u64) * 2));
}
if (fprs.size() % 2 == 1) {
const size_t i = fprs.size() - 1;
code.LDR(fprs[i], SP, frame_info.fprs_offset + i * (sizeof(u64) * 2));
}
} }
} }