mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 19:00:17 +02:00
4445 lines
213 KiB
C++
4445 lines
213 KiB
C++
// SPDX-License-Identifier: MIT
|
|
/* Load-store instruction emitters
|
|
*
|
|
* For GPR load-stores that take a `Size` argument as their first argument can be 32-bit or 64-bit.
|
|
* For GPR load-stores that don't take a `Size` argument, then their operating size is determined by the name of the instruction.
|
|
*
|
|
* For Vector load-stores, most take a `SubRegSize` to determine the size of the elements getting loaded or stored.
|
|
* Depending on the instruction it can be an single element or the full instruction, it depends on the instruction.
|
|
*
|
|
* There are some load-store helper functions which take a `ExtendedMemOperand` argument.
|
|
* This helper will select the viable load-store that can work with the provided encapsulated arguments.
|
|
*/
|
|
|
|
#pragma once
|
|
#ifndef INCLUDED_BY_EMITTER
|
|
#include <CodeEmitter/Emitter.h>
|
|
namespace ARMEmitter {
|
|
struct EmitterOps : Emitter {
|
|
#endif
|
|
|
|
public:
|
|
// Compare and swap pair
|
|
void casp(ARMEmitter::Size s, ARMEmitter::Register rs, ARMEmitter::Register rs2, ARMEmitter::Register rt, ARMEmitter::Register rt2,
|
|
ARMEmitter::Register rn) {
|
|
LOGMAN_THROW_A_FMT((rs.Idx() + 1) == rs2.Idx(), "These must be sequential");
|
|
LOGMAN_THROW_A_FMT((rt.Idx() + 1) == rt2.Idx(), "These must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1000'001 << 21;
|
|
AtomicOp(Op, s, 0, 0, rs, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void caspa(ARMEmitter::Size s, ARMEmitter::Register rs, ARMEmitter::Register rs2, ARMEmitter::Register rt, ARMEmitter::Register rt2,
|
|
ARMEmitter::Register rn) {
|
|
LOGMAN_THROW_A_FMT((rs.Idx() + 1) == rs2.Idx(), "These must be sequential");
|
|
LOGMAN_THROW_A_FMT((rt.Idx() + 1) == rt2.Idx(), "These must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1000'001 << 21;
|
|
AtomicOp(Op, s, 1, 0, rs, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void caspl(ARMEmitter::Size s, ARMEmitter::Register rs, ARMEmitter::Register rs2, ARMEmitter::Register rt, ARMEmitter::Register rt2,
|
|
ARMEmitter::Register rn) {
|
|
LOGMAN_THROW_A_FMT((rs.Idx() + 1) == rs2.Idx(), "These must be sequential");
|
|
LOGMAN_THROW_A_FMT((rt.Idx() + 1) == rt2.Idx(), "These must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1000'001 << 21;
|
|
AtomicOp(Op, s, 0, 1, rs, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void caspal(ARMEmitter::Size s, ARMEmitter::Register rs, ARMEmitter::Register rs2, ARMEmitter::Register rt, ARMEmitter::Register rt2,
|
|
ARMEmitter::Register rn) {
|
|
LOGMAN_THROW_A_FMT((rs.Idx() + 1) == rs2.Idx(), "These must be sequential");
|
|
LOGMAN_THROW_A_FMT((rt.Idx() + 1) == rt2.Idx(), "These must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1000'001 << 21;
|
|
AtomicOp(Op, s, 1, 1, rs, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
|
|
// Advanced SIMD load/store multiple structures
|
|
template<SubRegSize size, typename T>
|
|
void ld1(T rt, Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1100'000 << 21;
|
|
constexpr uint32_t Opcode = 0b0111 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, true>(Op, Opcode, rt, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void ld1(T rt, T rt2, Register rn) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1100'000 << 21;
|
|
constexpr uint32_t Opcode = 0b1010 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, true>(Op, Opcode, rt, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void ld1(T rt, T rt2, T rt3, Register rn) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1100'000 << 21;
|
|
constexpr uint32_t Opcode = 0b0110 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, true>(Op, Opcode, rt, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void ld1(T rt, T rt2, T rt3, T rt4, Register rn) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1100'000 << 21;
|
|
constexpr uint32_t Opcode = 0b0010 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, true>(Op, Opcode, rt, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void st1(T rt, Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1100'000 << 21;
|
|
constexpr uint32_t Opcode = 0b0111 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, false>(Op, Opcode, rt, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void st1(T rt, T rt2, Register rn) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1100'000 << 21;
|
|
constexpr uint32_t Opcode = 0b1010 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, false>(Op, Opcode, rt, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void st1(T rt, T rt2, T rt3, Register rn) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1100'000 << 21;
|
|
constexpr uint32_t Opcode = 0b0110 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, false>(Op, Opcode, rt, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void st1(T rt, T rt2, T rt3, T rt4, Register rn) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1100'000 << 21;
|
|
constexpr uint32_t Opcode = 0b0010 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, false>(Op, Opcode, rt, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void ld2(T rt, T rt2, Register rn) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1100'000 << 21;
|
|
constexpr uint32_t Opcode = 0b1000 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, true>(Op, Opcode, rt, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void st2(T rt, T rt2, Register rn) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1100'000 << 21;
|
|
constexpr uint32_t Opcode = 0b1000 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, false>(Op, Opcode, rt, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void ld3(T rt, T rt2, T rt3, Register rn) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1100'000 << 21;
|
|
constexpr uint32_t Opcode = 0b0100 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, true>(Op, Opcode, rt, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void st3(T rt, T rt2, T rt3, Register rn) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1100'000 << 21;
|
|
constexpr uint32_t Opcode = 0b0100 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, false>(Op, Opcode, rt, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void ld4(T rt, T rt2, T rt3, T rt4, Register rn) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1100'000 << 21;
|
|
constexpr uint32_t Opcode = 0b0000 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, true>(Op, Opcode, rt, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void st4(T rt, T rt2, T rt3, T rt4, Register rn) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1100'000 << 21;
|
|
constexpr uint32_t Opcode = 0b0000 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, false>(Op, Opcode, rt, rn, Reg::r0);
|
|
}
|
|
// Advanced SIMD load/store multiple structures (post-indexed)
|
|
static constexpr uint32_t ASIMDLoadstoreMultiplePost_Op = 0b0000'1100'100 << 21;
|
|
template<SubRegSize size, typename T>
|
|
void ld1(T rt, Register rn, Register rm) {
|
|
constexpr uint32_t Opcode = 0b0111 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, true>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, rm);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void ld1(T rt, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT((std::is_same_v<QRegister, T> && (PostOffset == 16)) || (std::is_same_v<DRegister, T> && (PostOffset == 8)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
|
|
constexpr uint32_t Opcode = 0b0111 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, true>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, Reg::r31);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void ld1(T rt, T rt2, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
constexpr uint32_t Opcode = 0b1010 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, true>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, rm);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void ld1(T rt, T rt2, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
LOGMAN_THROW_A_FMT((std::is_same_v<QRegister, T> && (PostOffset == 32)) || (std::is_same_v<DRegister, T> && (PostOffset == 16)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
|
|
constexpr uint32_t Opcode = 0b1010 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, true>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, Reg::r31);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void ld1(T rt, T rt2, T rt3, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
constexpr uint32_t Opcode = 0b0110 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, true>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, rm);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void ld1(T rt, T rt2, T rt3, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
LOGMAN_THROW_A_FMT((std::is_same_v<QRegister, T> && (PostOffset == 48)) || (std::is_same_v<DRegister, T> && (PostOffset == 24)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
|
|
constexpr uint32_t Opcode = 0b0110 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, true>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, Reg::r31);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void ld1(T rt, T rt2, T rt3, T rt4, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
constexpr uint32_t Opcode = 0b0010 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, true>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, rm);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void ld1(T rt, T rt2, T rt3, T rt4, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
LOGMAN_THROW_A_FMT((std::is_same_v<QRegister, T> && (PostOffset == 64)) || (std::is_same_v<DRegister, T> && (PostOffset == 32)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
|
|
constexpr uint32_t Opcode = 0b0010 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, true>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, Reg::r31);
|
|
}
|
|
|
|
template<SubRegSize size, typename T>
|
|
void st1(T rt, Register rn, Register rm) {
|
|
constexpr uint32_t Opcode = 0b0111 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, false>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, rm);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void st1(T rt, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT((std::is_same_v<QRegister, T> && (PostOffset == 16)) || (std::is_same_v<DRegister, T> && (PostOffset == 8)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
|
|
constexpr uint32_t Opcode = 0b0111 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, false>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, Reg::r31);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void st1(T rt, T rt2, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
constexpr uint32_t Opcode = 0b1010 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, false>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, rm);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void st1(T rt, T rt2, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
LOGMAN_THROW_A_FMT((std::is_same_v<QRegister, T> && (PostOffset == 32)) || (std::is_same_v<DRegister, T> && (PostOffset == 16)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
|
|
constexpr uint32_t Opcode = 0b1010 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, false>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, Reg::r31);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void st1(T rt, T rt2, T rt3, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
constexpr uint32_t Opcode = 0b0110 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, false>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, rm);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void st1(T rt, T rt2, T rt3, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
LOGMAN_THROW_A_FMT((std::is_same_v<QRegister, T> && (PostOffset == 48)) || (std::is_same_v<DRegister, T> && (PostOffset == 24)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
|
|
constexpr uint32_t Opcode = 0b0110 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, false>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, Reg::r31);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void st1(T rt, T rt2, T rt3, T rt4, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
constexpr uint32_t Opcode = 0b0010 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, false>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, rm);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void st1(T rt, T rt2, T rt3, T rt4, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
LOGMAN_THROW_A_FMT((std::is_same_v<QRegister, T> && (PostOffset == 64)) || (std::is_same_v<DRegister, T> && (PostOffset == 32)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
|
|
constexpr uint32_t Opcode = 0b0010 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, false>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, Reg::r31);
|
|
}
|
|
|
|
template<SubRegSize size, typename T>
|
|
void ld2(T rt, T rt2, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
constexpr uint32_t Opcode = 0b1000 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, true>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, rm);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void ld2(T rt, T rt2, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
LOGMAN_THROW_A_FMT((std::is_same_v<QRegister, T> && (PostOffset == 32)) || (std::is_same_v<DRegister, T> && (PostOffset == 16)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
|
|
constexpr uint32_t Opcode = 0b1000 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, true>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, Reg::r31);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void st2(T rt, T rt2, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
constexpr uint32_t Opcode = 0b1000 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, false>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, rm);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void st2(T rt, T rt2, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
LOGMAN_THROW_A_FMT((std::is_same_v<QRegister, T> && (PostOffset == 32)) || (std::is_same_v<DRegister, T> && (PostOffset == 16)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
|
|
constexpr uint32_t Opcode = 0b1000 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, false>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, Reg::r31);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void ld3(T rt, T rt2, T rt3, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
constexpr uint32_t Opcode = 0b0100 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, true>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, rm);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void ld3(T rt, T rt2, T rt3, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
LOGMAN_THROW_A_FMT((std::is_same_v<QRegister, T> && (PostOffset == 48)) || (std::is_same_v<DRegister, T> && (PostOffset == 24)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
|
|
constexpr uint32_t Opcode = 0b0100 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, true>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, Reg::r31);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void st3(T rt, T rt2, T rt3, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
constexpr uint32_t Opcode = 0b0100 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, false>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, rm);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void st3(T rt, T rt2, T rt3, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
LOGMAN_THROW_A_FMT((std::is_same_v<QRegister, T> && (PostOffset == 48)) || (std::is_same_v<DRegister, T> && (PostOffset == 24)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
|
|
constexpr uint32_t Opcode = 0b0100 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, false>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, Reg::r31);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void ld4(T rt, T rt2, T rt3, T rt4, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
constexpr uint32_t Opcode = 0b0000 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, true>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, rm);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void ld4(T rt, T rt2, T rt3, T rt4, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
LOGMAN_THROW_A_FMT((std::is_same_v<QRegister, T> && (PostOffset == 64)) || (std::is_same_v<DRegister, T> && (PostOffset == 32)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
|
|
constexpr uint32_t Opcode = 0b0000 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, true>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, Reg::r31);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void st4(T rt, T rt2, T rt3, T rt4, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
constexpr uint32_t Opcode = 0b0000 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, false>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, rm);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
void st4(T rt, T rt2, T rt3, T rt4, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
LOGMAN_THROW_A_FMT((std::is_same_v<QRegister, T> && (PostOffset == 64)) || (std::is_same_v<DRegister, T> && (PostOffset == 32)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
|
|
constexpr uint32_t Opcode = 0b0000 << 12;
|
|
ASIMDLoadStoreMultipleStructure<size, false>(ASIMDLoadstoreMultiplePost_Op, Opcode, rt, rn, Reg::r31);
|
|
}
|
|
|
|
// ASIMD loadstore single
|
|
template<SubRegSize size>
|
|
void st1(VRegister rt, uint32_t Index, Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1101'000 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, false, 1>(Op, Opcode, rt, Index, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size>
|
|
void st2(VRegister rt, VRegister rt2, uint32_t Index, Register rn) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1101'000 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, false, 2>(Op, Opcode, rt, Index, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size>
|
|
void st3(VRegister rt, VRegister rt2, VRegister rt3, uint32_t Index, Register rn) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1101'000 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, false, 3>(Op, Opcode, rt, Index, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size>
|
|
void st4(VRegister rt, VRegister rt2, VRegister rt3, VRegister rt4, uint32_t Index, Register rn) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1101'000 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, false, 4>(Op, Opcode, rt, Index, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size>
|
|
void ld1(VRegister rt, uint32_t Index, Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1101'000 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, true, 1>(Op, Opcode, rt, Index, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
requires (std::is_same_v<QRegister, T> || std::is_same_v<DRegister, T>)
|
|
void ld1r(T rt, Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1101'000 << 21;
|
|
constexpr uint32_t Opcode = 0b110;
|
|
ASIMDSTLD<size, true, 1>(Op, Opcode, rt, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size>
|
|
void ld2(VRegister rt, VRegister rt2, uint32_t Index, Register rn) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1101'000 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, true, 2>(Op, Opcode, rt, Index, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
requires (std::is_same_v<QRegister, T> || std::is_same_v<DRegister, T>)
|
|
void ld2r(T rt, T rt2, Register rn) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1101'000 << 21;
|
|
constexpr uint32_t Opcode = 0b110;
|
|
ASIMDSTLD<size, true, 2>(Op, Opcode, rt, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size>
|
|
void ld3(VRegister rt, VRegister rt2, VRegister rt3, uint32_t Index, Register rn) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1101'000 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, true, 3>(Op, Opcode, rt, Index, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
requires (std::is_same_v<QRegister, T> || std::is_same_v<DRegister, T>)
|
|
void ld3r(T rt, T rt2, T rt3, Register rn) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1101'000 << 21;
|
|
constexpr uint32_t Opcode = 0b110;
|
|
ASIMDSTLD<size, true, 3>(Op, Opcode, rt, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size>
|
|
void ld4(VRegister rt, VRegister rt2, VRegister rt3, VRegister rt4, uint32_t Index, Register rn) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1101'000 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, true, 4>(Op, Opcode, rt, Index, rn, Reg::r0);
|
|
}
|
|
template<SubRegSize size, typename T>
|
|
requires (std::is_same_v<QRegister, T> || std::is_same_v<DRegister, T>)
|
|
void ld4r(T rt, T rt2, T rt3, T rt4, Register rn) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1101'000 << 21;
|
|
constexpr uint32_t Opcode = 0b110;
|
|
ASIMDSTLD<size, true, 4>(Op, Opcode, rt, rn, Reg::r0);
|
|
}
|
|
|
|
// ASIMD loadstore single post-indexed
|
|
template<SubRegSize size>
|
|
void st1(VRegister rt, uint32_t Index, Register rn, Register rm) {
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, false, 1>(Op, Opcode, rt, Index, rn, rm);
|
|
}
|
|
template<SubRegSize size>
|
|
void st1(VRegister rt, uint32_t Index, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT((size == SubRegSize::i8Bit && (PostOffset == 1)) || (size == SubRegSize::i16Bit && (PostOffset == 2)) ||
|
|
(size == SubRegSize::i32Bit && (PostOffset == 4)) || (size == SubRegSize::i64Bit && (PostOffset == 8)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, false, 1>(Op, Opcode, rt, Index, rn, Reg::r31);
|
|
}
|
|
template<SubRegSize size>
|
|
void st2(VRegister rt, VRegister rt2, uint32_t Index, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, false, 2>(Op, Opcode, rt, Index, rn, rm);
|
|
}
|
|
template<SubRegSize size>
|
|
void st2(VRegister rt, uint32_t Index, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT((size == SubRegSize::i8Bit && (PostOffset == 2)) || (size == SubRegSize::i16Bit && (PostOffset == 4)) ||
|
|
(size == SubRegSize::i32Bit && (PostOffset == 8)) || (size == SubRegSize::i64Bit && (PostOffset == 16)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, false, 2>(Op, Opcode, rt, Index, rn, Reg::r31);
|
|
}
|
|
template<SubRegSize size>
|
|
void st3(VRegister rt, VRegister rt2, VRegister rt3, uint32_t Index, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, false, 3>(Op, Opcode, rt, Index, rn, rm);
|
|
}
|
|
template<SubRegSize size>
|
|
void st3(VRegister rt, uint32_t Index, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT((size == SubRegSize::i8Bit && (PostOffset == 3)) || (size == SubRegSize::i16Bit && (PostOffset == 6)) ||
|
|
(size == SubRegSize::i32Bit && (PostOffset == 8)) || (size == SubRegSize::i64Bit && (PostOffset == 24)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, false, 3>(Op, Opcode, rt, Index, rn, Reg::r31);
|
|
}
|
|
template<SubRegSize size>
|
|
void st4(VRegister rt, VRegister rt2, VRegister rt3, VRegister rt4, uint32_t Index, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, false, 4>(Op, Opcode, rt, Index, rn, rm);
|
|
}
|
|
template<SubRegSize size>
|
|
void st4(VRegister rt, uint32_t Index, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT((size == SubRegSize::i8Bit && (PostOffset == 4)) || (size == SubRegSize::i16Bit && (PostOffset == 8)) ||
|
|
(size == SubRegSize::i32Bit && (PostOffset == 16)) || (size == SubRegSize::i64Bit && (PostOffset == 32)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, false, 4>(Op, Opcode, rt, Index, rn, Reg::r31);
|
|
}
|
|
template<SubRegSize size>
|
|
void ld1(VRegister rt, uint32_t Index, Register rn, Register rm) {
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, true, 1>(Op, Opcode, rt, Index, rn, rm);
|
|
}
|
|
template<SubRegSize size>
|
|
void ld1(VRegister rt, uint32_t Index, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT((size == SubRegSize::i8Bit && (PostOffset == 1)) || (size == SubRegSize::i16Bit && (PostOffset == 2)) ||
|
|
(size == SubRegSize::i32Bit && (PostOffset == 4)) || (size == SubRegSize::i64Bit && (PostOffset == 8)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, true, 1>(Op, Opcode, rt, Index, rn, Reg::r31);
|
|
}
|
|
template<SubRegSize size>
|
|
void ld1r(VRegister rt, Register rn, Register rm) {
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode = 0b110;
|
|
ASIMDSTLD<size, true, 1>(Op, Opcode, rt, 0, rn, rm);
|
|
}
|
|
template<SubRegSize size>
|
|
void ld1r(VRegister rt, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT((size == SubRegSize::i8Bit && (PostOffset == 1)) || (size == SubRegSize::i16Bit && (PostOffset == 2)) ||
|
|
(size == SubRegSize::i32Bit && (PostOffset == 4)) || (size == SubRegSize::i64Bit && (PostOffset == 8)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode = 0b110;
|
|
ASIMDSTLD<size, true, 1>(Op, Opcode, rt, 0, rn, Reg::r31);
|
|
}
|
|
template<SubRegSize size>
|
|
void ld2(VRegister rt, VRegister rt2, uint32_t Index, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, true, 2>(Op, Opcode, rt, Index, rn, rm);
|
|
}
|
|
template<SubRegSize size>
|
|
void ld2(VRegister rt, uint32_t Index, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT((size == SubRegSize::i8Bit && (PostOffset == 2)) || (size == SubRegSize::i16Bit && (PostOffset == 4)) ||
|
|
(size == SubRegSize::i32Bit && (PostOffset == 8)) || (size == SubRegSize::i64Bit && (PostOffset == 16)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, true, 2>(Op, Opcode, rt, Index, rn, Reg::r31);
|
|
}
|
|
template<SubRegSize size>
|
|
void ld2r(VRegister rt, VRegister rt2, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode = 0b110;
|
|
ASIMDSTLD<size, true, 2>(Op, Opcode, rt, 0, rn, rm);
|
|
}
|
|
template<SubRegSize size>
|
|
void ld2r(VRegister rt, VRegister rt2, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
LOGMAN_THROW_A_FMT((size == SubRegSize::i8Bit && (PostOffset == 2)) || (size == SubRegSize::i16Bit && (PostOffset == 4)) ||
|
|
(size == SubRegSize::i32Bit && (PostOffset == 8)) || (size == SubRegSize::i64Bit && (PostOffset == 16)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode = 0b110;
|
|
ASIMDSTLD<size, true, 2>(Op, Opcode, rt, 0, rn, Reg::r31);
|
|
}
|
|
template<SubRegSize size>
|
|
void ld3(VRegister rt, VRegister rt2, VRegister rt3, uint32_t Index, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, true, 3>(Op, Opcode, rt, Index, rn, rm);
|
|
}
|
|
template<SubRegSize size>
|
|
void ld3(VRegister rt, uint32_t Index, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT((size == SubRegSize::i8Bit && (PostOffset == 3)) || (size == SubRegSize::i16Bit && (PostOffset == 6)) ||
|
|
(size == SubRegSize::i32Bit && (PostOffset == 12)) || (size == SubRegSize::i64Bit && (PostOffset == 16)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, true, 3>(Op, Opcode, rt, Index, rn, Reg::r31);
|
|
}
|
|
template<SubRegSize size>
|
|
void ld3r(VRegister rt, VRegister rt2, VRegister rt3, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode = 0b110;
|
|
ASIMDSTLD<size, true, 3>(Op, Opcode, rt, 0, rn, rm);
|
|
}
|
|
template<SubRegSize size>
|
|
void ld3r(VRegister rt, VRegister rt2, VRegister rt3, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
LOGMAN_THROW_A_FMT((size == SubRegSize::i8Bit && (PostOffset == 3)) || (size == SubRegSize::i16Bit && (PostOffset == 6)) ||
|
|
(size == SubRegSize::i32Bit && (PostOffset == 12)) || (size == SubRegSize::i64Bit && (PostOffset == 16)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode = 0b110;
|
|
ASIMDSTLD<size, true, 3>(Op, Opcode, rt, 0, rn, Reg::r31);
|
|
}
|
|
template<SubRegSize size>
|
|
void ld4(VRegister rt, VRegister rt2, VRegister rt3, VRegister rt4, uint32_t Index, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, true, 4>(Op, Opcode, rt, Index, rn, rm);
|
|
}
|
|
template<SubRegSize size>
|
|
void ld4(VRegister rt, uint32_t Index, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT((size == SubRegSize::i8Bit && (PostOffset == 4)) || (size == SubRegSize::i16Bit && (PostOffset == 8)) ||
|
|
(size == SubRegSize::i32Bit && (PostOffset == 16)) || (size == SubRegSize::i64Bit && (PostOffset == 32)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode =
|
|
size == SubRegSize::i8Bit ? 0b000 : // Scale = 0
|
|
size == SubRegSize::i16Bit ? 0b010 : // Scale = 1
|
|
size == SubRegSize::i32Bit ? 0b100 : // Scale = 2
|
|
size == SubRegSize::i64Bit ? 0b100 : // Scale = 2 (Uses size to determine difference between 32-bit).
|
|
0;
|
|
ASIMDSTLD<size, true, 4>(Op, Opcode, rt, Index, rn, Reg::r31);
|
|
}
|
|
template<SubRegSize size>
|
|
void ld4r(VRegister rt, VRegister rt2, VRegister rt3, VRegister rt4, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode = 0b110;
|
|
ASIMDSTLD<size, true, 4>(Op, Opcode, rt, 0, rn, rm);
|
|
}
|
|
template<SubRegSize size>
|
|
void ld4r(VRegister rt, VRegister rt2, VRegister rt3, VRegister rt4, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
LOGMAN_THROW_A_FMT((size == SubRegSize::i8Bit && (PostOffset == 4)) || (size == SubRegSize::i16Bit && (PostOffset == 8)) ||
|
|
(size == SubRegSize::i32Bit && (PostOffset == 16)) || (size == SubRegSize::i64Bit && (PostOffset == 32)),
|
|
"Post-index offset needs to match number of elements times their size");
|
|
constexpr uint32_t Op = 0b0000'1101'100 << 21;
|
|
constexpr uint32_t Opcode = 0b110;
|
|
ASIMDSTLD<size, true, 4>(Op, Opcode, rt, 0, rn, Reg::r31);
|
|
}
|
|
|
|
// Advanced SIMD load/store single structure (post-indexed)
|
|
template<typename T>
|
|
void st1(ARMEmitter::SubRegSize size, T rt, uint32_t Index, ARMEmitter::Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(size == SubRegSize::i8Bit || size == SubRegSize::i16Bit || size == SubRegSize::i32Bit || size == SubRegSize::i64Bit,
|
|
"Incorrect size");
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
uint32_t Q;
|
|
uint32_t R = 0;
|
|
uint32_t opcode;
|
|
uint32_t S;
|
|
uint32_t Size;
|
|
if (size == SubRegSize::i8Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 16, "Index too large");
|
|
Q = Index >> 3;
|
|
S = (Index >> 2) & 1;
|
|
opcode = 0b000;
|
|
Size = Index & 0b11;
|
|
} else if (size == SubRegSize::i16Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 8, "Index too large");
|
|
Q = Index >> 2;
|
|
S = (Index >> 1) & 1;
|
|
opcode = 0b010;
|
|
Size = (Index & 0b1) << 1;
|
|
} else if (size == SubRegSize::i32Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 4, "Index too large");
|
|
Q = Index >> 1;
|
|
S = Index & 1;
|
|
opcode = 0b100;
|
|
Size = 0b00;
|
|
} else if (size == SubRegSize::i64Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 2, "Index too large");
|
|
Q = Index;
|
|
S = 0;
|
|
opcode = 0b100;
|
|
Size = 0b01;
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unknown size");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
|
|
ASIMDLoadStoreSinglePost(Op, Q, 0, R, opcode, S, Size, ARMEmitter::Reg::r31, rn, rt.Q());
|
|
}
|
|
template<typename T>
|
|
void ld1(ARMEmitter::SubRegSize size, T rt, uint32_t Index, ARMEmitter::Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(size == SubRegSize::i8Bit || size == SubRegSize::i16Bit || size == SubRegSize::i32Bit || size == SubRegSize::i64Bit,
|
|
"Incorrect size");
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
uint32_t Q;
|
|
uint32_t R = 0;
|
|
uint32_t opcode;
|
|
uint32_t S;
|
|
uint32_t Size;
|
|
if (size == SubRegSize::i8Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 16, "Index too large");
|
|
Q = Index >> 3;
|
|
S = (Index >> 2) & 1;
|
|
opcode = 0b001;
|
|
Size = Index & 0b11;
|
|
} else if (size == SubRegSize::i16Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 8, "Index too large");
|
|
Q = Index >> 2;
|
|
S = (Index >> 1) & 1;
|
|
opcode = 0b011;
|
|
Size = (Index & 0b1) << 1;
|
|
} else if (size == SubRegSize::i32Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 4, "Index too large");
|
|
Q = Index >> 1;
|
|
S = Index & 1;
|
|
opcode = 0b100;
|
|
Size = 0b00;
|
|
} else if (size == SubRegSize::i64Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 2, "Index too large");
|
|
Q = Index;
|
|
S = 0;
|
|
opcode = 0b101;
|
|
Size = 0b01;
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unknown size");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
|
|
ASIMDLoadStoreSinglePost(Op, Q, 1, R, opcode, S, Size, ARMEmitter::Reg::r31, rn, rt.Q());
|
|
}
|
|
template<typename T>
|
|
void ld1r(ARMEmitter::SubRegSize size, T rt, ARMEmitter::Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(PostOffset == 1 || PostOffset == 2 || PostOffset == 4 || PostOffset == 8, "Index too large");
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
constexpr uint32_t Q = std::is_same_v<ARMEmitter::QRegister, T> ? 1 : 0;
|
|
uint32_t R = 0;
|
|
uint32_t opcode = 0b110;
|
|
uint32_t S = 0;
|
|
uint32_t Size = FEXCore::ToUnderlying(size);
|
|
ASIMDLoadStoreSinglePost<T>(Op, Q, 1, R, opcode, S, Size, ARMEmitter::Reg::r31, rn, rt);
|
|
}
|
|
|
|
template<typename T>
|
|
void ld2r(SubRegSize size, T rt, T rt2, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
LOGMAN_THROW_A_FMT(PostOffset == 2 || PostOffset == 4 || PostOffset == 8 || PostOffset == 16, "Index too large");
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
constexpr uint32_t Q = std::is_same_v<QRegister, T> ? 1 : 0;
|
|
uint32_t R = 1;
|
|
uint32_t opcode = 0b110;
|
|
uint32_t S = 0;
|
|
uint32_t Size = FEXCore::ToUnderlying(size);
|
|
ASIMDLoadStoreSinglePost<T>(Op, Q, 1, R, opcode, S, Size, Reg::r31, rn, rt);
|
|
}
|
|
|
|
template<typename T>
|
|
void ld3r(SubRegSize size, T rt, T rt2, T rt3, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
LOGMAN_THROW_A_FMT(PostOffset == 3 || PostOffset == 6 || PostOffset == 12 || PostOffset == 24, "Index too large");
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
constexpr uint32_t Q = std::is_same_v<QRegister, T> ? 1 : 0;
|
|
uint32_t R = 0;
|
|
uint32_t opcode = 0b111;
|
|
uint32_t S = 0;
|
|
uint32_t Size = FEXCore::ToUnderlying(size);
|
|
ASIMDLoadStoreSinglePost<T>(Op, Q, 1, R, opcode, S, Size, Reg::r31, rn, rt);
|
|
}
|
|
template<typename T>
|
|
void ld4r(SubRegSize size, T rt, T rt2, T rt3, T rt4, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
LOGMAN_THROW_A_FMT(PostOffset == 4 || PostOffset == 8 || PostOffset == 16 || PostOffset == 32, "Index too large");
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
constexpr uint32_t Q = std::is_same_v<QRegister, T> ? 1 : 0;
|
|
uint32_t R = 1;
|
|
uint32_t opcode = 0b111;
|
|
uint32_t S = 0;
|
|
uint32_t Size = FEXCore::ToUnderlying(size);
|
|
ASIMDLoadStoreSinglePost<T>(Op, Q, 1, R, opcode, S, Size, Reg::r31, rn, rt);
|
|
}
|
|
|
|
template<typename T>
|
|
void st2(SubRegSize size, T rt, T rt2, uint32_t Index, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(size == SubRegSize::i8Bit || size == SubRegSize::i16Bit || size == SubRegSize::i32Bit || size == SubRegSize::i64Bit,
|
|
"Incorrect size");
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
uint32_t Q;
|
|
uint32_t R = 1;
|
|
uint32_t opcode;
|
|
uint32_t S;
|
|
uint32_t Size;
|
|
if (size == SubRegSize::i8Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 16, "Index too large");
|
|
Q = Index >> 3;
|
|
S = (Index >> 2) & 1;
|
|
opcode = 0b000;
|
|
Size = Index & 0b11;
|
|
} else if (size == SubRegSize::i16Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 8, "Index too large");
|
|
Q = Index >> 2;
|
|
S = (Index >> 1) & 1;
|
|
opcode = 0b010;
|
|
Size = (Index & 0b1) << 1;
|
|
} else if (size == SubRegSize::i32Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 4, "Index too large");
|
|
Q = Index >> 1;
|
|
S = Index & 1;
|
|
opcode = 0b100;
|
|
Size = 0b00;
|
|
} else if (size == SubRegSize::i64Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 2, "Index too large");
|
|
Q = Index;
|
|
S = 0;
|
|
opcode = 0b100;
|
|
Size = 0b01;
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unknown size");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
|
|
ASIMDLoadStoreSinglePost(Op, Q, 0, R, opcode, S, Size, Reg::r31, rn, rt.Q());
|
|
}
|
|
template<typename T>
|
|
void ld2(SubRegSize size, T rt, T rt2, uint32_t Index, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(size == SubRegSize::i8Bit || size == SubRegSize::i16Bit || size == SubRegSize::i32Bit || size == SubRegSize::i64Bit,
|
|
"Incorrect size");
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
uint32_t Q;
|
|
uint32_t R = 1;
|
|
uint32_t opcode;
|
|
uint32_t S;
|
|
uint32_t Size;
|
|
if (size == SubRegSize::i8Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 16, "Index too large");
|
|
Q = Index >> 3;
|
|
S = (Index >> 2) & 1;
|
|
opcode = 0b000;
|
|
Size = Index & 0b11;
|
|
} else if (size == SubRegSize::i16Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 8, "Index too large");
|
|
Q = Index >> 2;
|
|
S = (Index >> 1) & 1;
|
|
opcode = 0b010;
|
|
Size = (Index & 0b1) << 1;
|
|
} else if (size == SubRegSize::i32Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 4, "Index too large");
|
|
Q = Index >> 1;
|
|
S = Index & 1;
|
|
opcode = 0b100;
|
|
Size = 0b00;
|
|
} else if (size == SubRegSize::i64Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 2, "Index too large");
|
|
Q = Index;
|
|
S = 0;
|
|
opcode = 0b100;
|
|
Size = 0b01;
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unknown size");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
|
|
ASIMDLoadStoreSinglePost(Op, Q, 1, R, opcode, S, Size, Reg::r31, rn, rt.Q());
|
|
}
|
|
template<typename T>
|
|
void st3(SubRegSize size, T rt, T rt2, T rt3, uint32_t Index, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(size == SubRegSize::i8Bit || size == SubRegSize::i16Bit || size == SubRegSize::i32Bit || size == SubRegSize::i64Bit,
|
|
"Incorrect size");
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
uint32_t Q;
|
|
uint32_t R = 0;
|
|
uint32_t opcode;
|
|
uint32_t S;
|
|
uint32_t Size;
|
|
if (size == SubRegSize::i8Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 16, "Index too large");
|
|
Q = Index >> 3;
|
|
S = (Index >> 2) & 1;
|
|
opcode = 0b001;
|
|
Size = Index & 0b11;
|
|
} else if (size == SubRegSize::i16Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 8, "Index too large");
|
|
Q = Index >> 2;
|
|
S = (Index >> 1) & 1;
|
|
opcode = 0b011;
|
|
Size = (Index & 0b1) << 1;
|
|
} else if (size == SubRegSize::i32Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 4, "Index too large");
|
|
Q = Index >> 1;
|
|
S = Index & 1;
|
|
opcode = 0b101;
|
|
Size = 0b00;
|
|
} else if (size == SubRegSize::i64Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 2, "Index too large");
|
|
Q = Index;
|
|
S = 0;
|
|
opcode = 0b101;
|
|
Size = 0b01;
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unknown size");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
|
|
ASIMDLoadStoreSinglePost(Op, Q, 0, R, opcode, S, Size, Reg::r31, rn, rt.Q());
|
|
}
|
|
template<typename T>
|
|
void ld3(SubRegSize size, T rt, T rt2, T rt3, uint32_t Index, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(size == SubRegSize::i8Bit || size == SubRegSize::i16Bit || size == SubRegSize::i32Bit || size == SubRegSize::i64Bit,
|
|
"Incorrect size");
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
uint32_t Q;
|
|
uint32_t R = 0;
|
|
uint32_t opcode;
|
|
uint32_t S;
|
|
uint32_t Size;
|
|
if (size == SubRegSize::i8Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 16, "Index too large");
|
|
Q = Index >> 3;
|
|
S = (Index >> 2) & 1;
|
|
opcode = 0b001;
|
|
Size = Index & 0b11;
|
|
} else if (size == SubRegSize::i16Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 8, "Index too large");
|
|
Q = Index >> 2;
|
|
S = (Index >> 1) & 1;
|
|
opcode = 0b011;
|
|
Size = (Index & 0b1) << 1;
|
|
} else if (size == SubRegSize::i32Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 4, "Index too large");
|
|
Q = Index >> 1;
|
|
S = Index & 1;
|
|
opcode = 0b101;
|
|
Size = 0b00;
|
|
} else if (size == SubRegSize::i64Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 2, "Index too large");
|
|
Q = Index;
|
|
S = 0;
|
|
opcode = 0b101;
|
|
Size = 0b01;
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unknown size");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
|
|
ASIMDLoadStoreSinglePost(Op, Q, 1, R, opcode, S, Size, Reg::r31, rn, rt.Q());
|
|
}
|
|
template<typename T>
|
|
void st4(SubRegSize size, T rt, T rt2, T rt3, T rt4, uint32_t Index, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(size == SubRegSize::i8Bit || size == SubRegSize::i16Bit || size == SubRegSize::i32Bit || size == SubRegSize::i64Bit,
|
|
"Incorrect size");
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
uint32_t Q;
|
|
uint32_t R = 1;
|
|
uint32_t opcode;
|
|
uint32_t S;
|
|
uint32_t Size;
|
|
if (size == SubRegSize::i8Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 16, "Index too large");
|
|
Q = Index >> 3;
|
|
S = (Index >> 2) & 1;
|
|
opcode = 0b001;
|
|
Size = Index & 0b11;
|
|
} else if (size == SubRegSize::i16Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 8, "Index too large");
|
|
Q = Index >> 2;
|
|
S = (Index >> 1) & 1;
|
|
opcode = 0b011;
|
|
Size = (Index & 0b1) << 1;
|
|
} else if (size == SubRegSize::i32Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 4, "Index too large");
|
|
Q = Index >> 1;
|
|
S = Index & 1;
|
|
opcode = 0b101;
|
|
Size = 0b00;
|
|
} else if (size == SubRegSize::i64Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 2, "Index too large");
|
|
Q = Index;
|
|
S = 0;
|
|
opcode = 0b101;
|
|
Size = 0b01;
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unknown size");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
|
|
ASIMDLoadStoreSinglePost(Op, Q, 0, R, opcode, S, Size, Reg::r31, rn, rt.Q());
|
|
}
|
|
template<typename T>
|
|
void ld4(SubRegSize size, T rt, T rt2, T rt3, T rt4, uint32_t Index, Register rn, uint32_t PostOffset) {
|
|
LOGMAN_THROW_A_FMT(size == SubRegSize::i8Bit || size == SubRegSize::i16Bit || size == SubRegSize::i32Bit || size == SubRegSize::i64Bit,
|
|
"Incorrect size");
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
uint32_t Q;
|
|
uint32_t R = 1;
|
|
uint32_t opcode;
|
|
uint32_t S;
|
|
uint32_t Size;
|
|
if (size == SubRegSize::i8Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 16, "Index too large");
|
|
Q = Index >> 3;
|
|
S = (Index >> 2) & 1;
|
|
opcode = 0b001;
|
|
Size = Index & 0b11;
|
|
} else if (size == SubRegSize::i16Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 8, "Index too large");
|
|
Q = Index >> 2;
|
|
S = (Index >> 1) & 1;
|
|
opcode = 0b011;
|
|
Size = (Index & 0b1) << 1;
|
|
} else if (size == SubRegSize::i32Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 4, "Index too large");
|
|
Q = Index >> 1;
|
|
S = Index & 1;
|
|
opcode = 0b101;
|
|
Size = 0b00;
|
|
} else if (size == SubRegSize::i64Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 2, "Index too large");
|
|
Q = Index;
|
|
S = 0;
|
|
opcode = 0b101;
|
|
Size = 0b01;
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unknown size");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
|
|
ASIMDLoadStoreSinglePost(Op, Q, 1, R, opcode, S, Size, Reg::r31, rn, rt.Q());
|
|
}
|
|
|
|
template<typename T>
|
|
void st1(ARMEmitter::SubRegSize size, T rt, uint32_t Index, ARMEmitter::Register rn, ARMEmitter::Register rm) {
|
|
LOGMAN_THROW_A_FMT(size == SubRegSize::i8Bit || size == SubRegSize::i16Bit || size == SubRegSize::i32Bit || size == SubRegSize::i64Bit,
|
|
"Incorrect size");
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
uint32_t Q;
|
|
uint32_t R = 0;
|
|
uint32_t opcode;
|
|
uint32_t S;
|
|
uint32_t Size;
|
|
if (size == SubRegSize::i8Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 16, "Index too large");
|
|
Q = Index >> 3;
|
|
S = (Index >> 2) & 1;
|
|
opcode = 0b000;
|
|
Size = Index & 0b11;
|
|
} else if (size == SubRegSize::i16Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 8, "Index too large");
|
|
Q = Index >> 2;
|
|
S = (Index >> 1) & 1;
|
|
opcode = 0b010;
|
|
Size = (Index & 0b1) << 1;
|
|
} else if (size == SubRegSize::i32Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 4, "Index too large");
|
|
Q = Index >> 1;
|
|
S = Index & 1;
|
|
opcode = 0b100;
|
|
Size = 0b00;
|
|
} else if (size == SubRegSize::i64Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 2, "Index too large");
|
|
Q = Index;
|
|
S = 0;
|
|
opcode = 0b100;
|
|
Size = 0b01;
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unknown size");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
|
|
ASIMDLoadStoreSinglePost(Op, Q, 0, R, opcode, S, Size, rm, rn, rt.Q());
|
|
}
|
|
template<typename T>
|
|
void ld1(ARMEmitter::SubRegSize size, T rt, uint32_t Index, ARMEmitter::Register rn, ARMEmitter::Register rm) {
|
|
LOGMAN_THROW_A_FMT(size == SubRegSize::i8Bit || size == SubRegSize::i16Bit || size == SubRegSize::i32Bit || size == SubRegSize::i64Bit,
|
|
"Incorrect size");
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
uint32_t Q;
|
|
uint32_t R = 0;
|
|
uint32_t opcode;
|
|
uint32_t S;
|
|
uint32_t Size;
|
|
if (size == SubRegSize::i8Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 16, "Index too large");
|
|
Q = Index >> 3;
|
|
S = (Index >> 2) & 1;
|
|
opcode = 0b001;
|
|
Size = Index & 0b11;
|
|
} else if (size == SubRegSize::i16Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 8, "Index too large");
|
|
Q = Index >> 2;
|
|
S = (Index >> 1) & 1;
|
|
opcode = 0b011;
|
|
Size = (Index & 0b1) << 1;
|
|
} else if (size == SubRegSize::i32Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 4, "Index too large");
|
|
Q = Index >> 1;
|
|
S = Index & 1;
|
|
opcode = 0b100;
|
|
Size = 0b00;
|
|
} else if (size == SubRegSize::i64Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 2, "Index too large");
|
|
Q = Index;
|
|
S = 0;
|
|
opcode = 0b101;
|
|
Size = 0b01;
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unknown size");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
|
|
ASIMDLoadStoreSinglePost(Op, Q, 1, R, opcode, S, Size, rm, rn, rt.Q());
|
|
}
|
|
template<typename T>
|
|
void ld1r(SubRegSize size, T rt, Register rn, Register rm) {
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
constexpr uint32_t Q = std::is_same_v<QRegister, T> ? 1 : 0;
|
|
uint32_t R = 0;
|
|
uint32_t opcode = 0b110;
|
|
uint32_t S = 0;
|
|
uint32_t Size = FEXCore::ToUnderlying(size);
|
|
ASIMDLoadStoreSinglePost<T>(Op, Q, 1, R, opcode, S, Size, rm, rn, rt);
|
|
}
|
|
|
|
template<typename T>
|
|
void ld2r(SubRegSize size, T rt, T rt2, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
constexpr uint32_t Q = std::is_same_v<QRegister, T> ? 1 : 0;
|
|
uint32_t R = 1;
|
|
uint32_t opcode = 0b110;
|
|
uint32_t S = 0;
|
|
uint32_t Size = FEXCore::ToUnderlying(size);
|
|
ASIMDLoadStoreSinglePost<T>(Op, Q, 1, R, opcode, S, Size, rm, rn, rt);
|
|
}
|
|
|
|
template<typename T>
|
|
void ld3r(SubRegSize size, T rt, T rt2, T rt3, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
constexpr uint32_t Q = std::is_same_v<QRegister, T> ? 1 : 0;
|
|
uint32_t R = 0;
|
|
uint32_t opcode = 0b111;
|
|
uint32_t S = 0;
|
|
uint32_t Size = FEXCore::ToUnderlying(size);
|
|
ASIMDLoadStoreSinglePost<T>(Op, Q, 1, R, opcode, S, Size, rm, rn, rt);
|
|
}
|
|
template<typename T>
|
|
void ld4r(SubRegSize size, T rt, T rt2, T rt3, T rt4, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
constexpr uint32_t Q = std::is_same_v<QRegister, T> ? 1 : 0;
|
|
uint32_t R = 1;
|
|
uint32_t opcode = 0b111;
|
|
uint32_t S = 0;
|
|
uint32_t Size = FEXCore::ToUnderlying(size);
|
|
ASIMDLoadStoreSinglePost<T>(Op, Q, 1, R, opcode, S, Size, rm, rn, rt);
|
|
}
|
|
|
|
template<typename T>
|
|
void st2(SubRegSize size, T rt, T rt2, uint32_t Index, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(size == SubRegSize::i8Bit || size == SubRegSize::i16Bit || size == SubRegSize::i32Bit || size == SubRegSize::i64Bit,
|
|
"Incorrect size");
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
uint32_t Q;
|
|
uint32_t R = 1;
|
|
uint32_t opcode;
|
|
uint32_t S;
|
|
uint32_t Size;
|
|
if (size == SubRegSize::i8Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 16, "Index too large");
|
|
Q = Index >> 3;
|
|
S = (Index >> 2) & 1;
|
|
opcode = 0b000;
|
|
Size = Index & 0b11;
|
|
} else if (size == SubRegSize::i16Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 8, "Index too large");
|
|
Q = Index >> 2;
|
|
S = (Index >> 1) & 1;
|
|
opcode = 0b010;
|
|
Size = (Index & 0b1) << 1;
|
|
} else if (size == SubRegSize::i32Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 4, "Index too large");
|
|
Q = Index >> 1;
|
|
S = Index & 1;
|
|
opcode = 0b100;
|
|
Size = 0b00;
|
|
} else if (size == SubRegSize::i64Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 2, "Index too large");
|
|
Q = Index;
|
|
S = 0;
|
|
opcode = 0b100;
|
|
Size = 0b01;
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unknown size");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
|
|
ASIMDLoadStoreSinglePost(Op, Q, 0, R, opcode, S, Size, rm, rn, rt.Q());
|
|
}
|
|
template<typename T>
|
|
void ld2(SubRegSize size, T rt, T rt2, uint32_t Index, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(size == SubRegSize::i8Bit || size == SubRegSize::i16Bit || size == SubRegSize::i32Bit || size == SubRegSize::i64Bit,
|
|
"Incorrect size");
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2), "rt and rt2 must be sequential");
|
|
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
uint32_t Q;
|
|
uint32_t R = 1;
|
|
uint32_t opcode;
|
|
uint32_t S;
|
|
uint32_t Size;
|
|
if (size == SubRegSize::i8Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 16, "Index too large");
|
|
Q = Index >> 3;
|
|
S = (Index >> 2) & 1;
|
|
opcode = 0b000;
|
|
Size = Index & 0b11;
|
|
} else if (size == SubRegSize::i16Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 8, "Index too large");
|
|
Q = Index >> 2;
|
|
S = (Index >> 1) & 1;
|
|
opcode = 0b010;
|
|
Size = (Index & 0b1) << 1;
|
|
} else if (size == SubRegSize::i32Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 4, "Index too large");
|
|
Q = Index >> 1;
|
|
S = Index & 1;
|
|
opcode = 0b100;
|
|
Size = 0b00;
|
|
} else if (size == SubRegSize::i64Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 2, "Index too large");
|
|
Q = Index;
|
|
S = 0;
|
|
opcode = 0b100;
|
|
Size = 0b01;
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unknown size");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
|
|
ASIMDLoadStoreSinglePost(Op, Q, 1, R, opcode, S, Size, rm, rn, rt.Q());
|
|
}
|
|
template<typename T>
|
|
void st3(SubRegSize size, T rt, T rt2, T rt3, uint32_t Index, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(size == SubRegSize::i8Bit || size == SubRegSize::i16Bit || size == SubRegSize::i32Bit || size == SubRegSize::i64Bit,
|
|
"Incorrect size");
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
uint32_t Q;
|
|
uint32_t R = 0;
|
|
uint32_t opcode;
|
|
uint32_t S;
|
|
uint32_t Size;
|
|
if (size == SubRegSize::i8Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 16, "Index too large");
|
|
Q = Index >> 3;
|
|
S = (Index >> 2) & 1;
|
|
opcode = 0b001;
|
|
Size = Index & 0b11;
|
|
} else if (size == SubRegSize::i16Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 8, "Index too large");
|
|
Q = Index >> 2;
|
|
S = (Index >> 1) & 1;
|
|
opcode = 0b011;
|
|
Size = (Index & 0b1) << 1;
|
|
} else if (size == SubRegSize::i32Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 4, "Index too large");
|
|
Q = Index >> 1;
|
|
S = Index & 1;
|
|
opcode = 0b101;
|
|
Size = 0b00;
|
|
} else if (size == SubRegSize::i64Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 2, "Index too large");
|
|
Q = Index;
|
|
S = 0;
|
|
opcode = 0b101;
|
|
Size = 0b01;
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unknown size");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
|
|
ASIMDLoadStoreSinglePost(Op, Q, 0, R, opcode, S, Size, rm, rn, rt.Q());
|
|
}
|
|
template<typename T>
|
|
void ld3(SubRegSize size, T rt, T rt2, T rt3, uint32_t Index, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(size == SubRegSize::i8Bit || size == SubRegSize::i16Bit || size == SubRegSize::i32Bit || size == SubRegSize::i64Bit,
|
|
"Incorrect size");
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3), "rt, rt2, and rt3 must be sequential");
|
|
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
uint32_t Q;
|
|
uint32_t R = 0;
|
|
uint32_t opcode;
|
|
uint32_t S;
|
|
uint32_t Size;
|
|
if (size == SubRegSize::i8Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 16, "Index too large");
|
|
Q = Index >> 3;
|
|
S = (Index >> 2) & 1;
|
|
opcode = 0b001;
|
|
Size = Index & 0b11;
|
|
} else if (size == SubRegSize::i16Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 8, "Index too large");
|
|
Q = Index >> 2;
|
|
S = (Index >> 1) & 1;
|
|
opcode = 0b011;
|
|
Size = (Index & 0b1) << 1;
|
|
} else if (size == SubRegSize::i32Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 4, "Index too large");
|
|
Q = Index >> 1;
|
|
S = Index & 1;
|
|
opcode = 0b101;
|
|
Size = 0b00;
|
|
} else if (size == SubRegSize::i64Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 2, "Index too large");
|
|
Q = Index;
|
|
S = 0;
|
|
opcode = 0b101;
|
|
Size = 0b01;
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unknown size");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
|
|
ASIMDLoadStoreSinglePost(Op, Q, 1, R, opcode, S, Size, rm, rn, rt.Q());
|
|
}
|
|
template<typename T>
|
|
void st4(SubRegSize size, T rt, T rt2, T rt3, T rt4, uint32_t Index, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(size == SubRegSize::i8Bit || size == SubRegSize::i16Bit || size == SubRegSize::i32Bit || size == SubRegSize::i64Bit,
|
|
"Incorrect size");
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
uint32_t Q;
|
|
uint32_t R = 1;
|
|
uint32_t opcode;
|
|
uint32_t S;
|
|
uint32_t Size;
|
|
if (size == SubRegSize::i8Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 16, "Index too large");
|
|
Q = Index >> 3;
|
|
S = (Index >> 2) & 1;
|
|
opcode = 0b001;
|
|
Size = Index & 0b11;
|
|
} else if (size == SubRegSize::i16Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 8, "Index too large");
|
|
Q = Index >> 2;
|
|
S = (Index >> 1) & 1;
|
|
opcode = 0b011;
|
|
Size = (Index & 0b1) << 1;
|
|
} else if (size == SubRegSize::i32Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 4, "Index too large");
|
|
Q = Index >> 1;
|
|
S = Index & 1;
|
|
opcode = 0b101;
|
|
Size = 0b00;
|
|
} else if (size == SubRegSize::i64Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 2, "Index too large");
|
|
Q = Index;
|
|
S = 0;
|
|
opcode = 0b101;
|
|
Size = 0b01;
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unknown size");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
|
|
ASIMDLoadStoreSinglePost(Op, Q, 0, R, opcode, S, Size, rm, rn, rt.Q());
|
|
}
|
|
template<typename T>
|
|
void ld4(SubRegSize size, T rt, T rt2, T rt3, T rt4, uint32_t Index, Register rn, Register rm) {
|
|
LOGMAN_THROW_A_FMT(size == SubRegSize::i8Bit || size == SubRegSize::i16Bit || size == SubRegSize::i32Bit || size == SubRegSize::i64Bit,
|
|
"Incorrect size");
|
|
LOGMAN_THROW_A_FMT(AreVectorsSequential(rt, rt2, rt3, rt4), "rt, rt2, rt3, and rt4 must be sequential");
|
|
|
|
constexpr uint32_t Op = 0b0000'1101'1 << 23;
|
|
uint32_t Q;
|
|
uint32_t R = 1;
|
|
uint32_t opcode;
|
|
uint32_t S;
|
|
uint32_t Size;
|
|
if (size == SubRegSize::i8Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 16, "Index too large");
|
|
Q = Index >> 3;
|
|
S = (Index >> 2) & 1;
|
|
opcode = 0b001;
|
|
Size = Index & 0b11;
|
|
} else if (size == SubRegSize::i16Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 8, "Index too large");
|
|
Q = Index >> 2;
|
|
S = (Index >> 1) & 1;
|
|
opcode = 0b011;
|
|
Size = (Index & 0b1) << 1;
|
|
} else if (size == SubRegSize::i32Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 4, "Index too large");
|
|
Q = Index >> 1;
|
|
S = Index & 1;
|
|
opcode = 0b101;
|
|
Size = 0b00;
|
|
} else if (size == SubRegSize::i64Bit) {
|
|
LOGMAN_THROW_A_FMT(Index < 2, "Index too large");
|
|
Q = Index;
|
|
S = 0;
|
|
opcode = 0b101;
|
|
Size = 0b01;
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unknown size");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
|
|
ASIMDLoadStoreSinglePost(Op, Q, 1, R, opcode, S, Size, rm, rn, rt.Q());
|
|
}
|
|
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void st1(T rt, uint32_t Index, ARMEmitter::Register rn, uint32_t PostOffset) {
|
|
st1(size, rt, Index, rn, PostOffset);
|
|
}
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void ld1(T rt, uint32_t Index, ARMEmitter::Register rn, uint32_t PostOffset) {
|
|
ld1(size, rt, Index, rn, PostOffset);
|
|
}
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void ld1r(T rt, ARMEmitter::Register rn, uint32_t PostOffset) {
|
|
ld1r(size, rt, rn, PostOffset);
|
|
}
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void ld2r(T rt, T rt2, ARMEmitter::Register rn, uint32_t PostOffset) {
|
|
ld2r(size, rt, rt2, rn, PostOffset);
|
|
}
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void ld3r(T rt, T rt2, T rt3, ARMEmitter::Register rn, uint32_t PostOffset) {
|
|
ld3r(size, rt, rt2, rt3, rn, PostOffset);
|
|
}
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void ld4r(T rt, T rt2, T rt3, T rt4, ARMEmitter::Register rn, uint32_t PostOffset) {
|
|
ld4r(size, rt, rt2, rt3, rt4, rn, PostOffset);
|
|
}
|
|
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void st2(T rt, T rt2, uint32_t Index, ARMEmitter::Register rn, uint32_t PostOffset) {
|
|
st2(size, rt, rt2, Index, rn, PostOffset);
|
|
}
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void ld2(T rt, T rt2, uint32_t Index, ARMEmitter::Register rn, uint32_t PostOffset) {
|
|
ld2(size, rt, rt2, Index, rn, PostOffset);
|
|
}
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void st3(T rt, T rt2, T rt3, uint32_t Index, ARMEmitter::Register rn, uint32_t PostOffset) {
|
|
st3(size, rt, rt2, rt3, Index, rn, PostOffset);
|
|
}
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void ld3(T rt, T rt2, T rt3, uint32_t Index, ARMEmitter::Register rn, uint32_t PostOffset) {
|
|
ld3(size, rt, rt2, rt3, Index, rn, PostOffset);
|
|
}
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void st4(T rt, T rt2, T rt3, T rt4, uint32_t Index, ARMEmitter::Register rn, uint32_t PostOffset) {
|
|
st4(size, rt, rt2, rt3, rt4, Index, rn, PostOffset);
|
|
}
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void ld4(T rt, T rt2, T rt3, T rt4, uint32_t Index, ARMEmitter::Register rn, uint32_t PostOffset) {
|
|
ld4(size, rt, rt2, rt3, rt4, Index, rn, PostOffset);
|
|
}
|
|
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void st1(T rt, uint32_t Index, ARMEmitter::Register rn, ARMEmitter::Register rm) {
|
|
st1(size, rt, Index, rn, rm);
|
|
}
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void ld1(T rt, uint32_t Index, ARMEmitter::Register rn, ARMEmitter::Register rm) {
|
|
ld1(size, rt, Index, rn, rm);
|
|
}
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void ld1r(T rt, ARMEmitter::Register rn, ARMEmitter::Register rm) {
|
|
ld1r(size, rt, rn, rm);
|
|
}
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void ld2r(T rt, T rt2, ARMEmitter::Register rn, ARMEmitter::Register rm) {
|
|
ld2r(size, rt, rt2, rn, rm);
|
|
}
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void ld3r(T rt, T rt2, T rt3, ARMEmitter::Register rn, ARMEmitter::Register rm) {
|
|
ld3r(size, rt, rt2, rt3, rn, rm);
|
|
}
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void ld4r(T rt, T rt2, T rt3, T rt4, ARMEmitter::Register rn, ARMEmitter::Register rm) {
|
|
ld4r(size, rt, rt2, rt3, rt4, rn, rm);
|
|
}
|
|
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void st2(T rt, T rt2, uint32_t Index, ARMEmitter::Register rn, ARMEmitter::Register rm) {
|
|
st2(size, rt, rt2, Index, rn, rm);
|
|
}
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void ld2(T rt, T rt2, uint32_t Index, ARMEmitter::Register rn, ARMEmitter::Register rm) {
|
|
ld2(size, rt, rt2, Index, rn, rm);
|
|
}
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void st3(T rt, T rt2, T rt3, uint32_t Index, ARMEmitter::Register rn, ARMEmitter::Register rm) {
|
|
st3(size, rt, rt2, rt3, Index, rn, rm);
|
|
}
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void ld3(T rt, T rt2, T rt3, uint32_t Index, ARMEmitter::Register rn, ARMEmitter::Register rm) {
|
|
ld3(size, rt, rt2, rt3, Index, rn, rm);
|
|
}
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void st4(T rt, T rt2, T rt3, T rt4, uint32_t Index, ARMEmitter::Register rn, ARMEmitter::Register rm) {
|
|
st4(size, rt, rt2, rt3, rt4, Index, rn, rm);
|
|
}
|
|
template<ARMEmitter::SubRegSize size, typename T>
|
|
void ld4(T rt, T rt2, T rt3, T rt4, uint32_t Index, ARMEmitter::Register rn, ARMEmitter::Register rm) {
|
|
ld4(size, rt, rt2, rt3, rt4, Index, rn, rm);
|
|
}
|
|
|
|
template<typename T>
|
|
void ASIMDLoadStoreSinglePost(uint32_t Op, uint32_t Q, uint32_t L, uint32_t R, uint32_t opcode, uint32_t S, uint32_t size,
|
|
ARMEmitter::Register rm, ARMEmitter::Register rn, T rt) {
|
|
LOGMAN_THROW_A_FMT(std::is_same_v<ARMEmitter::QRegister, T> || std::is_same_v<ARMEmitter::DRegister, T>, "Only supports 128-bit and "
|
|
"64-bit vector registers.");
|
|
uint32_t Instr = Op;
|
|
|
|
Instr |= Q << 30;
|
|
Instr |= L << 22;
|
|
Instr |= R << 21;
|
|
Instr |= Encode_rm(rm);
|
|
Instr |= opcode << 13;
|
|
Instr |= S << 12;
|
|
Instr |= size << 10;
|
|
Instr |= Encode_rn(rn);
|
|
Instr |= Encode_rt(rt);
|
|
dc32(Instr);
|
|
}
|
|
// Loadstore exclusive pair
|
|
void stxp(ARMEmitter::Size s, ARMEmitter::Register rs, ARMEmitter::Register rt, ARMEmitter::Register rt2, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b1000'1000'001 << 21;
|
|
AtomicOp(Op, s, 0, 0, rs, rt, rt2, rn);
|
|
}
|
|
void stlxp(ARMEmitter::Size s, ARMEmitter::Register rs, ARMEmitter::Register rt, ARMEmitter::Register rt2, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b1000'1000'001 << 21;
|
|
AtomicOp(Op, s, 0, 1, rs, rt, rt2, rn);
|
|
}
|
|
void ldxp(ARMEmitter::Size s, ARMEmitter::Register rt, ARMEmitter::Register rt2, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b1000'1000'001 << 21;
|
|
AtomicOp(Op, s, 1, 0, ARMEmitter::Reg::r31, rt, rt2, rn);
|
|
}
|
|
void ldaxp(ARMEmitter::Size s, ARMEmitter::Register rt, ARMEmitter::Register rt2, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b1000'1000'001 << 21;
|
|
AtomicOp(Op, s, 1, 1, ARMEmitter::Reg::r31, rt, rt2, rn);
|
|
}
|
|
// Loadstore exclusive register
|
|
void stxrb(ARMEmitter::Register rs, ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'000 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i8Bit, 0, 0, rs, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void stlxrb(ARMEmitter::Register rs, ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'000 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i8Bit, 0, 1, rs, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void ldxrb(ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'000 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i8Bit, 1, 0, ARMEmitter::Reg::r31, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void ldaxrb(ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'000 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i8Bit, 1, 1, ARMEmitter::Reg::r31, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void stxrh(ARMEmitter::Register rs, ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'000 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i16Bit, 0, 0, rs, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void stlxrh(ARMEmitter::Register rs, ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'000 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i16Bit, 0, 1, rs, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void ldxrh(ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'000 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i16Bit, 1, 0, ARMEmitter::Reg::r31, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void ldaxrh(ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'000 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i16Bit, 1, 1, ARMEmitter::Reg::r31, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void stxr(ARMEmitter::WRegister rs, ARMEmitter::WRegister rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'000 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i32Bit, 0, 0, rs, rt, ARMEmitter::WReg::w31, rn);
|
|
}
|
|
void stlxr(ARMEmitter::WRegister rs, ARMEmitter::WRegister rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'000 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i32Bit, 0, 1, rs, rt, ARMEmitter::WReg::w31, rn);
|
|
}
|
|
void ldxr(ARMEmitter::WRegister rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'000 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i32Bit, 1, 0, ARMEmitter::WReg::w31, rt, ARMEmitter::WReg::w31, rn);
|
|
}
|
|
void ldaxr(ARMEmitter::WRegister rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'000 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i32Bit, 1, 1, ARMEmitter::WReg::w31, rt, ARMEmitter::WReg::w31, rn);
|
|
}
|
|
void stxr(ARMEmitter::XRegister rs, ARMEmitter::XRegister rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'000 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i64Bit, 0, 0, rs, rt, ARMEmitter::XReg::x31, rn);
|
|
}
|
|
void stlxr(ARMEmitter::WRegister rs, ARMEmitter::XRegister rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'000 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i64Bit, 0, 1, rs.R(), rt.R(), ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void ldxr(ARMEmitter::XRegister rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'000 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i64Bit, 1, 0, ARMEmitter::XReg::x31, rt, ARMEmitter::XReg::x31, rn);
|
|
}
|
|
void ldaxr(ARMEmitter::XRegister rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'000 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i64Bit, 1, 1, ARMEmitter::XReg::x31, rt, ARMEmitter::XReg::x31, rn);
|
|
}
|
|
void stxr(ARMEmitter::SubRegSize size, ARMEmitter::Register rs, ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'000 << 21;
|
|
SubAtomicOp(Op, size, 0, 0, rs, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void stlxr(ARMEmitter::SubRegSize size, ARMEmitter::Register rs, ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'000 << 21;
|
|
SubAtomicOp(Op, size, 0, 1, rs, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void ldxr(ARMEmitter::SubRegSize size, ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'000 << 21;
|
|
SubAtomicOp(Op, size, 1, 0, ARMEmitter::Reg::r31, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void ldaxr(ARMEmitter::SubRegSize size, ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'000 << 21;
|
|
SubAtomicOp(Op, size, 1, 1, ARMEmitter::Reg::r31, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
|
|
// Load/store ordered
|
|
static constexpr uint32_t LoadStoreOrdered_Op = 0b0000'1000'100 << 21;
|
|
void stllrb(ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
SubAtomicOp(LoadStoreOrdered_Op, ARMEmitter::SubRegSize::i8Bit, 0, 0, ARMEmitter::Reg::r31, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void stlrb(ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
SubAtomicOp(LoadStoreOrdered_Op, ARMEmitter::SubRegSize::i8Bit, 0, 1, ARMEmitter::Reg::r31, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void ldlarb(ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
SubAtomicOp(LoadStoreOrdered_Op, ARMEmitter::SubRegSize::i8Bit, 1, 0, ARMEmitter::Reg::r31, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void ldarb(ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
SubAtomicOp(LoadStoreOrdered_Op, ARMEmitter::SubRegSize::i8Bit, 1, 1, ARMEmitter::Reg::r31, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void stllrh(ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
SubAtomicOp(LoadStoreOrdered_Op, ARMEmitter::SubRegSize::i16Bit, 0, 0, ARMEmitter::Reg::r31, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void stlrh(ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
SubAtomicOp(LoadStoreOrdered_Op, ARMEmitter::SubRegSize::i16Bit, 0, 1, ARMEmitter::Reg::r31, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void ldlarh(ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
SubAtomicOp(LoadStoreOrdered_Op, ARMEmitter::SubRegSize::i16Bit, 1, 0, ARMEmitter::Reg::r31, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void ldarh(ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
SubAtomicOp(LoadStoreOrdered_Op, ARMEmitter::SubRegSize::i16Bit, 1, 1, ARMEmitter::Reg::r31, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void stllr(ARMEmitter::WRegister rt, ARMEmitter::Register rn) {
|
|
SubAtomicOp(LoadStoreOrdered_Op, ARMEmitter::SubRegSize::i32Bit, 0, 0, ARMEmitter::WReg::w31, rt, ARMEmitter::WReg::w31, rn);
|
|
}
|
|
void stlr(ARMEmitter::WRegister rt, ARMEmitter::Register rn) {
|
|
SubAtomicOp(LoadStoreOrdered_Op, ARMEmitter::SubRegSize::i32Bit, 0, 1, ARMEmitter::WReg::w31, rt, ARMEmitter::WReg::w31, rn);
|
|
}
|
|
void ldlar(ARMEmitter::WRegister rt, ARMEmitter::Register rn) {
|
|
SubAtomicOp(LoadStoreOrdered_Op, ARMEmitter::SubRegSize::i32Bit, 1, 0, ARMEmitter::WReg::w31, rt, ARMEmitter::WReg::w31, rn);
|
|
}
|
|
void ldar(ARMEmitter::WRegister rt, ARMEmitter::Register rn) {
|
|
SubAtomicOp(LoadStoreOrdered_Op, ARMEmitter::SubRegSize::i32Bit, 1, 1, ARMEmitter::WReg::w31, rt, ARMEmitter::WReg::w31, rn);
|
|
}
|
|
void stllr(ARMEmitter::XRegister rt, ARMEmitter::Register rn) {
|
|
SubAtomicOp(LoadStoreOrdered_Op, ARMEmitter::SubRegSize::i64Bit, 0, 0, ARMEmitter::XReg::x31, rt, ARMEmitter::XReg::x31, rn);
|
|
}
|
|
void stlr(ARMEmitter::XRegister rt, ARMEmitter::Register rn) {
|
|
SubAtomicOp(LoadStoreOrdered_Op, ARMEmitter::SubRegSize::i64Bit, 0, 1, ARMEmitter::XReg::x31, rt, ARMEmitter::XReg::x31, rn);
|
|
}
|
|
void ldlar(ARMEmitter::XRegister rt, ARMEmitter::Register rn) {
|
|
SubAtomicOp(LoadStoreOrdered_Op, ARMEmitter::SubRegSize::i64Bit, 1, 0, ARMEmitter::XReg::x31, rt, ARMEmitter::XReg::x31, rn);
|
|
}
|
|
void ldar(ARMEmitter::XRegister rt, ARMEmitter::Register rn) {
|
|
SubAtomicOp(LoadStoreOrdered_Op, ARMEmitter::SubRegSize::i64Bit, 1, 1, ARMEmitter::XReg::x31, rt, ARMEmitter::XReg::x31, rn);
|
|
}
|
|
// Compare and swap
|
|
void casb(ARMEmitter::Register rs, ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'101 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i8Bit, 0, 0, rs, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void caslb(ARMEmitter::Register rs, ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'101 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i8Bit, 0, 1, rs, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void casab(ARMEmitter::Register rs, ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'101 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i8Bit, 1, 0, rs, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void casalb(ARMEmitter::Register rs, ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'101 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i8Bit, 1, 1, rs, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void cash(ARMEmitter::Register rs, ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'101 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i16Bit, 0, 0, rs, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void caslh(ARMEmitter::Register rs, ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'101 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i16Bit, 0, 1, rs, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void casah(ARMEmitter::Register rs, ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'101 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i16Bit, 1, 0, rs, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void casalh(ARMEmitter::Register rs, ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'101 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i16Bit, 1, 1, rs, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void cas(ARMEmitter::WRegister rs, ARMEmitter::WRegister rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'101 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i32Bit, 0, 0, rs.R(), rt.R(), ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void casl(ARMEmitter::WRegister rs, ARMEmitter::WRegister rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'101 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i32Bit, 0, 1, rs.R(), rt.R(), ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void casa(ARMEmitter::WRegister rs, ARMEmitter::WRegister rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'101 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i32Bit, 1, 0, rs.R(), rt.R(), ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void casal(ARMEmitter::WRegister rs, ARMEmitter::WRegister rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'101 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i32Bit, 1, 1, rs.R(), rt.R(), ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void cas(ARMEmitter::XRegister rs, ARMEmitter::XRegister rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'101 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i64Bit, 0, 0, rs.R(), rt.R(), ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void casl(ARMEmitter::XRegister rs, ARMEmitter::XRegister rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'101 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i64Bit, 0, 1, rs.R(), rt.R(), ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void casa(ARMEmitter::XRegister rs, ARMEmitter::XRegister rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'101 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i64Bit, 1, 0, rs.R(), rt.R(), ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void casal(ARMEmitter::XRegister rs, ARMEmitter::XRegister rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'101 << 21;
|
|
SubAtomicOp(Op, ARMEmitter::SubRegSize::i64Bit, 1, 1, rs.R(), rt.R(), ARMEmitter::Reg::r31, rn);
|
|
}
|
|
|
|
void cas(ARMEmitter::SubRegSize size, ARMEmitter::Register rs, ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'101 << 21;
|
|
SubAtomicOp(Op, size, 0, 0, rs, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void casl(ARMEmitter::SubRegSize size, ARMEmitter::Register rs, ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'101 << 21;
|
|
SubAtomicOp(Op, size, 0, 1, rs, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void casa(ARMEmitter::SubRegSize size, ARMEmitter::Register rs, ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'101 << 21;
|
|
SubAtomicOp(Op, size, 1, 0, rs, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
void casal(ARMEmitter::SubRegSize size, ARMEmitter::Register rs, ARMEmitter::Register rt, ARMEmitter::Register rn) {
|
|
constexpr uint32_t Op = 0b0000'1000'101 << 21;
|
|
SubAtomicOp(Op, size, 1, 1, rs, rt, ARMEmitter::Reg::r31, rn);
|
|
}
|
|
// LDAPR/STLR unscaled immediate
|
|
void stlurb(ARMEmitter::Register rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0001'1001'000 << 21;
|
|
SubAtomicImm(Op, ARMEmitter::SubRegSize::i8Bit, 0b00, rt, rn, static_cast<uint32_t>(Imm) & 0x1'FF);
|
|
}
|
|
void ldapurb(ARMEmitter::Register rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0001'1001'000 << 21;
|
|
SubAtomicImm(Op, ARMEmitter::SubRegSize::i8Bit, 0b01, rt, rn, static_cast<uint32_t>(Imm) & 0x1'FF);
|
|
}
|
|
void ldapursb(ARMEmitter::WRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0001'1001'000 << 21;
|
|
SubAtomicImm(Op, ARMEmitter::SubRegSize::i8Bit, 0b11, rt, rn, static_cast<uint32_t>(Imm) & 0x1'FF);
|
|
}
|
|
void ldapursb(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0001'1001'000 << 21;
|
|
SubAtomicImm(Op, ARMEmitter::SubRegSize::i8Bit, 0b10, rt, rn, static_cast<uint32_t>(Imm) & 0x1'FF);
|
|
}
|
|
void stlurh(ARMEmitter::Register rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0001'1001'000 << 21;
|
|
SubAtomicImm(Op, ARMEmitter::SubRegSize::i16Bit, 0b00, rt, rn, static_cast<uint32_t>(Imm) & 0x1'FF);
|
|
}
|
|
void ldapurh(ARMEmitter::Register rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0001'1001'000 << 21;
|
|
SubAtomicImm(Op, ARMEmitter::SubRegSize::i16Bit, 0b01, rt, rn, static_cast<uint32_t>(Imm) & 0x1'FF);
|
|
}
|
|
void ldapursh(ARMEmitter::WRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0001'1001'000 << 21;
|
|
SubAtomicImm(Op, ARMEmitter::SubRegSize::i16Bit, 0b11, rt, rn, static_cast<uint32_t>(Imm) & 0x1'FF);
|
|
}
|
|
void ldapursh(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0001'1001'000 << 21;
|
|
SubAtomicImm(Op, ARMEmitter::SubRegSize::i16Bit, 0b10, rt, rn, static_cast<uint32_t>(Imm) & 0x1'FF);
|
|
}
|
|
void stlur(ARMEmitter::WRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0001'1001'000 << 21;
|
|
SubAtomicImm(Op, ARMEmitter::SubRegSize::i32Bit, 0b00, rt, rn, static_cast<uint32_t>(Imm) & 0x1'FF);
|
|
}
|
|
void ldapur(ARMEmitter::WRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0001'1001'000 << 21;
|
|
SubAtomicImm(Op, ARMEmitter::SubRegSize::i32Bit, 0b01, rt, rn, static_cast<uint32_t>(Imm) & 0x1'FF);
|
|
}
|
|
void ldapursw(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0001'1001'000 << 21;
|
|
SubAtomicImm(Op, ARMEmitter::SubRegSize::i32Bit, 0b10, rt, rn, static_cast<uint32_t>(Imm) & 0x1'FF);
|
|
}
|
|
void stlur(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0001'1001'000 << 21;
|
|
SubAtomicImm(Op, ARMEmitter::SubRegSize::i64Bit, 0b00, rt, rn, static_cast<uint32_t>(Imm) & 0x1'FF);
|
|
}
|
|
void ldapur(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0001'1001'000 << 21;
|
|
SubAtomicImm(Op, ARMEmitter::SubRegSize::i64Bit, 0b01, rt, rn, static_cast<uint32_t>(Imm) & 0x1'FF);
|
|
}
|
|
// Load register literal
|
|
void ldr(ARMEmitter::WRegister rt, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -1048576 && Imm <= 1048575 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0001'1000 << 24;
|
|
LoadStoreLiteral(Op, rt, static_cast<uint32_t>(Imm >> 2) & 0x7'FFFF);
|
|
}
|
|
void ldr(ARMEmitter::SRegister rt, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -1048576 && Imm <= 1048575 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0001'1100 << 24;
|
|
LoadStoreLiteral(Op, rt, static_cast<uint32_t>(Imm >> 2) & 0x7'FFFF);
|
|
}
|
|
void ldr(ARMEmitter::XRegister rt, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -1048576 && Imm <= 1048575 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0101'1000 << 24;
|
|
LoadStoreLiteral(Op, rt, static_cast<uint32_t>(Imm >> 2) & 0x7'FFFF);
|
|
}
|
|
void ldr(ARMEmitter::DRegister rt, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -1048576 && Imm <= 1048575 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0101'1100 << 24;
|
|
LoadStoreLiteral(Op, rt, static_cast<uint32_t>(Imm >> 2) & 0x7'FFFF);
|
|
}
|
|
void ldrs(ARMEmitter::WRegister rt, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -1048576 && Imm <= 1048575 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b1001'1000 << 24;
|
|
LoadStoreLiteral(Op, rt, static_cast<uint32_t>(Imm >> 2) & 0x7'FFFF);
|
|
}
|
|
void ldr(ARMEmitter::QRegister rt, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -1048576 && Imm <= 1048575 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b1001'1100 << 24;
|
|
LoadStoreLiteral(Op, rt, static_cast<uint32_t>(Imm >> 2) & 0x7'FFFF);
|
|
}
|
|
void prfm(ARMEmitter::Prefetch prfop, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -1048576 && Imm <= 1048575 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b1101'1000 << 24;
|
|
LoadStoreLiteral(Op, prfop, static_cast<uint32_t>(Imm >> 2) & 0x7'FFFF);
|
|
}
|
|
void ldr(ARMEmitter::WRegister rt, const BackwardLabel* Label) {
|
|
int32_t Imm = static_cast<int32_t>(Label->Location - GetCursorAddress<uint8_t*>());
|
|
LOGMAN_THROW_A_FMT(Imm >= -1048576 && Imm <= 1048575 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0001'1000 << 24;
|
|
LoadStoreLiteral(Op, rt, static_cast<uint32_t>(Imm >> 2) & 0x7'FFFF);
|
|
}
|
|
void ldr(ARMEmitter::SRegister rt, const BackwardLabel* Label) {
|
|
int32_t Imm = static_cast<int32_t>(Label->Location - GetCursorAddress<uint8_t*>());
|
|
LOGMAN_THROW_A_FMT(Imm >= -1048576 && Imm <= 1048575 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0001'1100 << 24;
|
|
LoadStoreLiteral(Op, rt, static_cast<uint32_t>(Imm >> 2) & 0x7'FFFF);
|
|
}
|
|
void ldr(ARMEmitter::XRegister rt, const BackwardLabel* Label) {
|
|
int32_t Imm = static_cast<int32_t>(Label->Location - GetCursorAddress<uint8_t*>());
|
|
LOGMAN_THROW_A_FMT(Imm >= -1048576 && Imm <= 1048575 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0101'1000 << 24;
|
|
LoadStoreLiteral(Op, rt, static_cast<uint32_t>(Imm >> 2) & 0x7'FFFF);
|
|
}
|
|
void ldr(ARMEmitter::DRegister rt, const BackwardLabel* Label) {
|
|
int32_t Imm = static_cast<int32_t>(Label->Location - GetCursorAddress<uint8_t*>());
|
|
LOGMAN_THROW_A_FMT(Imm >= -1048576 && Imm <= 1048575 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0101'1100 << 24;
|
|
LoadStoreLiteral(Op, rt, static_cast<uint32_t>(Imm >> 2) & 0x7'FFFF);
|
|
}
|
|
void ldrsw(ARMEmitter::XRegister rt, const BackwardLabel* Label) {
|
|
int32_t Imm = static_cast<int32_t>(Label->Location - GetCursorAddress<uint8_t*>());
|
|
LOGMAN_THROW_A_FMT(Imm >= -1048576 && Imm <= 1048575 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b1001'1000 << 24;
|
|
LoadStoreLiteral(Op, rt, static_cast<uint32_t>(Imm >> 2) & 0x7'FFFF);
|
|
}
|
|
void ldr(ARMEmitter::QRegister rt, const BackwardLabel* Label) {
|
|
int32_t Imm = static_cast<int32_t>(Label->Location - GetCursorAddress<uint8_t*>());
|
|
LOGMAN_THROW_A_FMT(Imm >= -1048576 && Imm <= 1048575 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b1001'1100 << 24;
|
|
LoadStoreLiteral(Op, rt, static_cast<uint32_t>(Imm >> 2) & 0x7'FFFF);
|
|
}
|
|
void prfm(ARMEmitter::Prefetch prfop, const BackwardLabel* Label) {
|
|
int32_t Imm = static_cast<int32_t>(Label->Location - GetCursorAddress<uint8_t*>());
|
|
LOGMAN_THROW_A_FMT(Imm >= -1048576 && Imm <= 1048575 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b1101'1000 << 24;
|
|
LoadStoreLiteral(Op, prfop, static_cast<uint32_t>(Imm >> 2) & 0x7'FFFF);
|
|
}
|
|
|
|
template<typename LabelType>
|
|
requires (std::is_same_v<LabelType, ForwardLabel> || std::is_same_v<LabelType, SingleUseForwardLabel>)
|
|
void ldr(ARMEmitter::WRegister rt, LabelType* Label) {
|
|
AddLocationToLabel(
|
|
Label, SingleUseForwardLabel {.Location = GetCursorAddress<uint8_t*>(), .Type = SingleUseForwardLabel::InstType::RELATIVE_LOAD});
|
|
constexpr uint32_t Op = 0b0001'1000 << 24;
|
|
LoadStoreLiteral(Op, rt, 0);
|
|
}
|
|
|
|
template<typename LabelType>
|
|
requires (std::is_same_v<LabelType, ForwardLabel> || std::is_same_v<LabelType, SingleUseForwardLabel>)
|
|
void ldr(ARMEmitter::SRegister rt, LabelType* Label) {
|
|
AddLocationToLabel(
|
|
Label, SingleUseForwardLabel {.Location = GetCursorAddress<uint8_t*>(), .Type = SingleUseForwardLabel::InstType::RELATIVE_LOAD});
|
|
constexpr uint32_t Op = 0b0001'1100 << 24;
|
|
LoadStoreLiteral(Op, rt, 0);
|
|
}
|
|
|
|
template<typename LabelType>
|
|
requires (std::is_same_v<LabelType, ForwardLabel> || std::is_same_v<LabelType, SingleUseForwardLabel>)
|
|
void ldr(ARMEmitter::XRegister rt, LabelType* Label) {
|
|
AddLocationToLabel(
|
|
Label, SingleUseForwardLabel {.Location = GetCursorAddress<uint8_t*>(), .Type = SingleUseForwardLabel::InstType::RELATIVE_LOAD});
|
|
constexpr uint32_t Op = 0b0101'1000 << 24;
|
|
LoadStoreLiteral(Op, rt, 0);
|
|
}
|
|
|
|
template<typename LabelType>
|
|
requires (std::is_same_v<LabelType, ForwardLabel> || std::is_same_v<LabelType, SingleUseForwardLabel>)
|
|
void ldr(ARMEmitter::DRegister rt, LabelType* Label) {
|
|
AddLocationToLabel(
|
|
Label, SingleUseForwardLabel {.Location = GetCursorAddress<uint8_t*>(), .Type = SingleUseForwardLabel::InstType::RELATIVE_LOAD});
|
|
constexpr uint32_t Op = 0b0101'1100 << 24;
|
|
LoadStoreLiteral(Op, rt, 0);
|
|
}
|
|
|
|
template<typename LabelType>
|
|
requires (std::is_same_v<LabelType, ForwardLabel> || std::is_same_v<LabelType, SingleUseForwardLabel>)
|
|
void ldrsw(ARMEmitter::XRegister rt, LabelType* Label) {
|
|
AddLocationToLabel(
|
|
Label, SingleUseForwardLabel {.Location = GetCursorAddress<uint8_t*>(), .Type = SingleUseForwardLabel::InstType::RELATIVE_LOAD});
|
|
constexpr uint32_t Op = 0b1001'1000 << 24;
|
|
LoadStoreLiteral(Op, rt, 0);
|
|
}
|
|
|
|
template<typename LabelType>
|
|
requires (std::is_same_v<LabelType, ForwardLabel> || std::is_same_v<LabelType, SingleUseForwardLabel>)
|
|
void ldr(ARMEmitter::QRegister rt, LabelType* Label) {
|
|
AddLocationToLabel(
|
|
Label, SingleUseForwardLabel {.Location = GetCursorAddress<uint8_t*>(), .Type = SingleUseForwardLabel::InstType::RELATIVE_LOAD});
|
|
constexpr uint32_t Op = 0b1001'1100 << 24;
|
|
LoadStoreLiteral(Op, rt, 0);
|
|
}
|
|
|
|
template<typename LabelType>
|
|
requires (std::is_same_v<LabelType, ForwardLabel> || std::is_same_v<LabelType, SingleUseForwardLabel>)
|
|
void prfm(ARMEmitter::Prefetch prfop, LabelType* Label) {
|
|
AddLocationToLabel(
|
|
Label, SingleUseForwardLabel {.Location = GetCursorAddress<uint8_t*>(), .Type = SingleUseForwardLabel::InstType::RELATIVE_LOAD});
|
|
constexpr uint32_t Op = 0b1101'1000 << 24;
|
|
LoadStoreLiteral(Op, prfop, 0);
|
|
}
|
|
|
|
void ldr(ARMEmitter::WRegister rt, BiDirectionalLabel* Label) {
|
|
if (Label->Backward.Location) {
|
|
ldr(rt, &Label->Backward);
|
|
} else {
|
|
ldr(rt, &Label->Forward);
|
|
}
|
|
}
|
|
void ldr(ARMEmitter::SRegister rt, BiDirectionalLabel* Label) {
|
|
if (Label->Backward.Location) {
|
|
ldr(rt, &Label->Backward);
|
|
} else {
|
|
ldr(rt, &Label->Forward);
|
|
}
|
|
}
|
|
void ldr(ARMEmitter::XRegister rt, BiDirectionalLabel* Label) {
|
|
if (Label->Backward.Location) {
|
|
ldr(rt, &Label->Backward);
|
|
} else {
|
|
ldr(rt, &Label->Forward);
|
|
}
|
|
}
|
|
void ldr(ARMEmitter::DRegister rt, BiDirectionalLabel* Label) {
|
|
if (Label->Backward.Location) {
|
|
ldr(rt, &Label->Backward);
|
|
} else {
|
|
ldr(rt, &Label->Forward);
|
|
}
|
|
}
|
|
void ldrs(ARMEmitter::WRegister rt, BiDirectionalLabel* Label) {
|
|
if (Label->Backward.Location) {
|
|
ldr(rt, &Label->Backward);
|
|
} else {
|
|
ldr(rt, &Label->Forward);
|
|
}
|
|
}
|
|
void ldr(ARMEmitter::QRegister rt, BiDirectionalLabel* Label) {
|
|
if (Label->Backward.Location) {
|
|
ldr(rt, &Label->Backward);
|
|
} else {
|
|
ldr(rt, &Label->Forward);
|
|
}
|
|
}
|
|
void prfm(ARMEmitter::Prefetch prfop, BiDirectionalLabel* Label) {
|
|
if (Label->Backward.Location) {
|
|
prfm(prfop, &Label->Backward);
|
|
} else {
|
|
prfm(prfop, &Label->Forward);
|
|
}
|
|
}
|
|
|
|
// Memory copy/set
|
|
// TODO
|
|
// Loadstore no-allocate pair
|
|
void stnp(ARMEmitter::WRegister rt, ARMEmitter::WRegister rt2, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 252 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0010'1000'00 << 22;
|
|
LoadStoreNoAllocate(Op, rt, rt2, rn, static_cast<uint32_t>(Imm >> 2) & 0b111'1111);
|
|
}
|
|
void ldnp(ARMEmitter::WRegister rt, ARMEmitter::WRegister rt2, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 252 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0010'1000'01 << 22;
|
|
LoadStoreNoAllocate(Op, rt, rt2, rn, static_cast<uint32_t>(Imm >> 2) & 0b111'1111);
|
|
}
|
|
void stnp(ARMEmitter::SRegister rt, ARMEmitter::SRegister rt2, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 252 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0010'1100'00 << 22;
|
|
LoadStoreNoAllocate(Op, rt, rt2, rn, static_cast<uint32_t>(Imm >> 2) & 0b111'1111);
|
|
}
|
|
void ldnp(ARMEmitter::SRegister rt, ARMEmitter::SRegister rt2, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 252 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0010'1100'01 << 22;
|
|
LoadStoreNoAllocate(Op, rt, rt2, rn, static_cast<uint32_t>(Imm >> 2) & 0b111'1111);
|
|
}
|
|
void stnp(ARMEmitter::XRegister rt, ARMEmitter::XRegister rt2, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -512 && Imm <= 504 && ((Imm & 0b111) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b1010'1000'00 << 22;
|
|
LoadStoreNoAllocate(Op, rt, rt2, rn, static_cast<uint32_t>(Imm >> 3) & 0b111'1111);
|
|
}
|
|
void ldnp(ARMEmitter::XRegister rt, ARMEmitter::XRegister rt2, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -512 && Imm <= 504 && ((Imm & 0b111) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b1010'1000'01 << 22;
|
|
LoadStoreNoAllocate(Op, rt, rt2, rn, static_cast<uint32_t>(Imm >> 3) & 0b111'1111);
|
|
}
|
|
void stnp(ARMEmitter::DRegister rt, ARMEmitter::DRegister rt2, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -512 && Imm <= 504 && ((Imm & 0b111) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0110'1100'00 << 22;
|
|
LoadStoreNoAllocate(Op, rt, rt2, rn, static_cast<uint32_t>(Imm >> 3) & 0b111'1111);
|
|
}
|
|
void ldnp(ARMEmitter::DRegister rt, ARMEmitter::DRegister rt2, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -512 && Imm <= 504 && ((Imm & 0b111) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b0110'1100'01 << 22;
|
|
LoadStoreNoAllocate(Op, rt, rt2, rn, static_cast<uint32_t>(Imm >> 3) & 0b111'1111);
|
|
}
|
|
void stnp(ARMEmitter::QRegister rt, ARMEmitter::QRegister rt2, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -1024 && Imm <= 1008 && ((Imm & 0b1111) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b1010'1100'00 << 22;
|
|
LoadStoreNoAllocate(Op, rt, rt2, rn, static_cast<uint32_t>(Imm >> 4) & 0b111'1111);
|
|
}
|
|
void ldnp(ARMEmitter::QRegister rt, ARMEmitter::QRegister rt2, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -1024 && Imm <= 1008 && ((Imm & 0b1111) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = 0b1010'1100'01 << 22;
|
|
LoadStoreNoAllocate(Op, rt, rt2, rn, static_cast<uint32_t>(Imm >> 4) & 0b111'1111);
|
|
}
|
|
// Loadstore register pair post-indexed
|
|
// Loadstore register pair offset
|
|
// Loadstore register pair pre-indexed
|
|
template<IndexType Index>
|
|
void stp(ARMEmitter::WRegister rt, ARMEmitter::WRegister rt2, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 252 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = (0b0010'1000'00 << 22) | (Index == IndexType::POST ? (0b01 << 23) :
|
|
Index == IndexType::PRE ? (0b11 << 23) :
|
|
Index == IndexType::OFFSET ? (0b10 << 23) :
|
|
-1);
|
|
|
|
LoadStorePair(Op, rt, rt2, rn, (Imm >> 2) & 0b111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void ldp(ARMEmitter::WRegister rt, ARMEmitter::WRegister rt2, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 252 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = (0b0010'1000'01 << 22) | (Index == IndexType::POST ? (0b01 << 23) :
|
|
Index == IndexType::PRE ? (0b11 << 23) :
|
|
Index == IndexType::OFFSET ? (0b10 << 23) :
|
|
-1);
|
|
|
|
LoadStorePair(Op, rt, rt2, rn, (Imm >> 2) & 0b111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void ldpsw(ARMEmitter::XRegister rt, ARMEmitter::XRegister rt2, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 252 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = (0b0110'1000'01 << 22) | (Index == IndexType::POST ? (0b01 << 23) :
|
|
Index == IndexType::PRE ? (0b11 << 23) :
|
|
Index == IndexType::OFFSET ? (0b10 << 23) :
|
|
-1);
|
|
LoadStorePair(Op, rt, rt2, rn, (Imm >> 2) & 0b111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void stp(ARMEmitter::XRegister rt, ARMEmitter::XRegister rt2, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -512 && Imm <= 504 && ((Imm & 0b111) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = (0b1010'1000'00 << 22) | (Index == IndexType::POST ? (0b01 << 23) :
|
|
Index == IndexType::PRE ? (0b11 << 23) :
|
|
Index == IndexType::OFFSET ? (0b10 << 23) :
|
|
-1);
|
|
|
|
LoadStorePair(Op, rt, rt2, rn, (Imm >> 3) & 0b111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void ldp(ARMEmitter::XRegister rt, ARMEmitter::XRegister rt2, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -512 && Imm <= 504 && ((Imm & 0b111) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = (0b1010'1000'01 << 22) | (Index == IndexType::POST ? (0b01 << 23) :
|
|
Index == IndexType::PRE ? (0b11 << 23) :
|
|
Index == IndexType::OFFSET ? (0b10 << 23) :
|
|
-1);
|
|
|
|
LoadStorePair(Op, rt, rt2, rn, (Imm >> 3) & 0b111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void stp(ARMEmitter::SRegister rt, ARMEmitter::SRegister rt2, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stp_w<Index>(rt.V(), rt2.V(), rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
void ldp(ARMEmitter::SRegister rt, ARMEmitter::SRegister rt2, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldp_w<Index>(rt.V(), rt2.V(), rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
void stp(ARMEmitter::DRegister rt, ARMEmitter::DRegister rt2, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stp_x<Index>(rt.V(), rt2.V(), rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
void ldp(ARMEmitter::DRegister rt, ARMEmitter::DRegister rt2, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldp_x<Index>(rt.V(), rt2.V(), rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
void stp(ARMEmitter::QRegister rt, ARMEmitter::QRegister rt2, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stp_q<Index>(rt.V(), rt2.V(), rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
void ldp(ARMEmitter::QRegister rt, ARMEmitter::QRegister rt2, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldp_q<Index>(rt.V(), rt2.V(), rn, Imm);
|
|
}
|
|
|
|
// Loadstore register unscaled immediate
|
|
void sturb(ARMEmitter::Register rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stXrb<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
void ldurb(ARMEmitter::Register rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrb<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
void sturb(ARMEmitter::VRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stXrb<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
void ldurb(ARMEmitter::VRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrb<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
void ldursb(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrsb<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
void ldursb(ARMEmitter::WRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrsb<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
void sturh(ARMEmitter::Register rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stXrh<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
void ldurh(ARMEmitter::Register rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrh<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
void sturh(ARMEmitter::VRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stXrh<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
void ldurh(ARMEmitter::VRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrh<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
void ldursh(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrsh<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
void ldursh(ARMEmitter::WRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrsh<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
void stur(ARMEmitter::WRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stXr<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
void ldur(ARMEmitter::WRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXr<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
void stur(ARMEmitter::SRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stXr<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
void ldur(ARMEmitter::SRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXr<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
void ldursw(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrsw<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
void stur(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stXr<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
void ldur(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXr<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
void stur(ARMEmitter::DRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stXr<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
void ldur(ARMEmitter::DRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXr<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
void stur(ARMEmitter::QRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stXr<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
void ldur(ARMEmitter::QRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXr<IndexType::OFFSET>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
void prfum(ARMEmitter::Prefetch prfop, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
static_assert(Index == IndexType::OFFSET, "Doesn't support another index type");
|
|
|
|
constexpr uint32_t Op = 0b1111'1000'10 << 22;
|
|
constexpr uint32_t o2 = 0b00;
|
|
|
|
LoadStoreImm(Op, o2, prfop, rn, Imm);
|
|
}
|
|
|
|
// Loadstore register immediate post-indexed
|
|
// Loadstore register immediate pre-indexed
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void strb(ARMEmitter::Register rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stXrb<Index>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void ldrb(ARMEmitter::Register rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrb<Index>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void strb(ARMEmitter::VRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stXrb<Index>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void ldrb(ARMEmitter::VRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrb<Index>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void ldrsb(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrsb<Index>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void ldrsb(ARMEmitter::WRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrsb<Index>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void strh(ARMEmitter::Register rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stXrh<Index>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void ldrh(ARMEmitter::Register rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrh<Index>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void strh(ARMEmitter::VRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stXrh<Index>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void ldrh(ARMEmitter::VRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrh<Index>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void ldrsh(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrsh<Index>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void ldrsh(ARMEmitter::WRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrsh<Index>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void str(ARMEmitter::WRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stXr<Index>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void ldr(ARMEmitter::WRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXr<Index>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void str(ARMEmitter::SRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stXr<Index>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void ldr(ARMEmitter::SRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXr<Index>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void ldrsw(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrsw<Index>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void str(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stXr<Index>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void ldr(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXr<Index>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void str(ARMEmitter::DRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stXr<Index>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void ldr(ARMEmitter::DRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXr<Index>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void str(ARMEmitter::QRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stXr<Index>(rt, rn, Imm);
|
|
}
|
|
template<IndexType Index>
|
|
requires (Index == IndexType::POST || Index == IndexType::PRE)
|
|
void ldr(ARMEmitter::QRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXr<Index>(rt, rn, Imm);
|
|
}
|
|
|
|
// Loadstore register unprivileged
|
|
void sttrb(ARMEmitter::Register rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stXrb<IndexType::UNPRIVILEGED>(rt, rn, Imm);
|
|
}
|
|
void ldtrb(ARMEmitter::Register rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrb<IndexType::UNPRIVILEGED>(rt, rn, Imm);
|
|
}
|
|
void ldtrsb(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrsb<IndexType::UNPRIVILEGED>(rt, rn, Imm);
|
|
}
|
|
void ldtrsb(ARMEmitter::WRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrsb<IndexType::UNPRIVILEGED>(rt, rn, Imm);
|
|
}
|
|
void sttrh(ARMEmitter::Register rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stXrh<IndexType::UNPRIVILEGED>(rt, rn, Imm);
|
|
}
|
|
void ldtrh(ARMEmitter::Register rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrh<IndexType::UNPRIVILEGED>(rt, rn, Imm);
|
|
}
|
|
void ldtrsh(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrsh<IndexType::UNPRIVILEGED>(rt, rn, Imm);
|
|
}
|
|
void ldtrsh(ARMEmitter::WRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrsh<IndexType::UNPRIVILEGED>(rt, rn, Imm);
|
|
}
|
|
void sttr(ARMEmitter::WRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stXr<IndexType::UNPRIVILEGED>(rt, rn, Imm);
|
|
}
|
|
void ldtr(ARMEmitter::WRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXr<IndexType::UNPRIVILEGED>(rt, rn, Imm);
|
|
}
|
|
void ldtrsw(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXrsw<IndexType::UNPRIVILEGED>(rt, rn, Imm);
|
|
}
|
|
void sttr(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
stXr<IndexType::UNPRIVILEGED>(rt, rn, Imm);
|
|
}
|
|
void ldtr(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm = 0) {
|
|
ldXr<IndexType::UNPRIVILEGED>(rt, rn, Imm);
|
|
}
|
|
// Atomic memory operations
|
|
void stadd(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 0, 0, 0b000, rs, Reg::zr, rn);
|
|
}
|
|
void staddl(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 1, 0, 0b000, rs, Reg::zr, rn);
|
|
}
|
|
void stadda(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 0, 0, 0b000, rs, Reg::zr, rn);
|
|
}
|
|
void staddal(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 1, 0, 0b000, rs, Reg::zr, rn);
|
|
}
|
|
void stclr(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 0, 0, 0b001, rs, Reg::zr, rn);
|
|
}
|
|
void stclrl(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 1, 0, 0b001, rs, Reg::zr, rn);
|
|
}
|
|
void stclra(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 0, 0, 0b001, rs, Reg::zr, rn);
|
|
}
|
|
void stclral(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 1, 0, 0b001, rs, Reg::zr, rn);
|
|
}
|
|
void stset(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 0, 0, 0b011, rs, Reg::zr, rn);
|
|
}
|
|
void stsetl(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 1, 0, 0b011, rs, Reg::zr, rn);
|
|
}
|
|
void stseta(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 0, 0, 0b011, rs, Reg::zr, rn);
|
|
}
|
|
void stsetal(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 1, 0, 0b011, rs, Reg::zr, rn);
|
|
}
|
|
void steor(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 0, 0, 0b010, rs, Reg::zr, rn);
|
|
}
|
|
void steorl(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 1, 0, 0b010, rs, Reg::zr, rn);
|
|
}
|
|
void steora(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 0, 0, 0b010, rs, Reg::zr, rn);
|
|
}
|
|
void steoral(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 1, 0, 0b010, rs, Reg::zr, rn);
|
|
}
|
|
void stsmax(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 0, 0, 0b100, rs, Reg::zr, rn);
|
|
}
|
|
void stsmaxl(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 1, 0, 0b100, rs, Reg::zr, rn);
|
|
}
|
|
void stsmaxa(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 0, 0, 0b100, rs, Reg::zr, rn);
|
|
}
|
|
void stsmaxal(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 1, 0, 0b100, rs, Reg::zr, rn);
|
|
}
|
|
void stsmin(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 0, 0, 0b101, rs, Reg::zr, rn);
|
|
}
|
|
void stsminl(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 1, 0, 0b101, rs, Reg::zr, rn);
|
|
}
|
|
void stsmina(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 0, 0, 0b101, rs, Reg::zr, rn);
|
|
}
|
|
void stsminal(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 1, 0, 0b101, rs, Reg::zr, rn);
|
|
}
|
|
void stumax(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 0, 0, 0b110, rs, Reg::zr, rn);
|
|
}
|
|
void stumaxl(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 1, 0, 0b110, rs, Reg::zr, rn);
|
|
}
|
|
void stumaxa(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 0, 0, 0b110, rs, Reg::zr, rn);
|
|
}
|
|
void stumaxal(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 1, 0, 0b110, rs, Reg::zr, rn);
|
|
}
|
|
void stumin(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 0, 0, 0b111, rs, Reg::zr, rn);
|
|
}
|
|
void stuminl(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 1, 0, 0b111, rs, Reg::zr, rn);
|
|
}
|
|
void stumina(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 0, 0, 0b111, rs, Reg::zr, rn);
|
|
}
|
|
void stuminal(SubRegSize size, Register rs, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 1, 0, 0b111, rs, Reg::zr, rn);
|
|
}
|
|
void ldswp(SubRegSize size, Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 0, 1, 0b000, rs, rt, rn);
|
|
}
|
|
void ldswpl(SubRegSize size, Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 1, 1, 0b000, rs, rt, rn);
|
|
}
|
|
void ldswpa(SubRegSize size, Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 0, 1, 0b000, rs, rt, rn);
|
|
}
|
|
void ldswpal(SubRegSize size, Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 1, 1, 0b000, rs, rt, rn);
|
|
}
|
|
|
|
void ldadd(SubRegSize size, Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 0, 0, 0b000, rs, rt, rn);
|
|
}
|
|
void ldadda(SubRegSize size, Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 0, 0, 0b000, rs, rt, rn);
|
|
}
|
|
void ldaddl(SubRegSize size, Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 1, 0, 0b000, rs, rt, rn);
|
|
}
|
|
void ldaddal(SubRegSize size, Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 1, 0, 0b000, rs, rt, rn);
|
|
}
|
|
void ldclr(SubRegSize size, Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 0, 0, 0b001, rs, rt, rn);
|
|
}
|
|
void ldclra(SubRegSize size, Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 0, 0, 0b001, rs, rt, rn);
|
|
}
|
|
void ldclrl(SubRegSize size, Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 1, 0, 0b001, rs, rt, rn);
|
|
}
|
|
void ldclral(SubRegSize size, Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 1, 0, 0b001, rs, rt, rn);
|
|
}
|
|
|
|
void ldset(SubRegSize size, Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 0, 0, 0b011, rs, rt, rn);
|
|
}
|
|
void ldseta(SubRegSize size, Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 0, 0, 0b011, rs, rt, rn);
|
|
}
|
|
void ldsetl(SubRegSize size, Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 1, 0, 0b011, rs, rt, rn);
|
|
}
|
|
void ldsetal(SubRegSize size, Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 1, 0, 0b011, rs, rt, rn);
|
|
}
|
|
void ldeor(SubRegSize size, Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 0, 0, 0b010, rs, rt, rn);
|
|
}
|
|
void ldeora(SubRegSize size, Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 0, 0, 0b010, rs, rt, rn);
|
|
}
|
|
void ldeorl(SubRegSize size, Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(size, 0, 1, 0, 0b010, rs, rt, rn);
|
|
}
|
|
void ldeoral(SubRegSize size, Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(size, 1, 1, 0, 0b010, rs, rt, rn);
|
|
}
|
|
|
|
|
|
// 8-bit
|
|
void ldaddb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 0, 0, 0, 0b000, rs, rt, rn);
|
|
}
|
|
void ldclrb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 0, 0, 0, 0b001, rs, rt, rn);
|
|
}
|
|
void ldeorb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 0, 0, 0, 0b010, rs, rt, rn);
|
|
}
|
|
void ldsetb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 0, 0, 0, 0b011, rs, rt, rn);
|
|
}
|
|
void ldsmaxb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 0, 0, 0, 0b100, rs, rt, rn);
|
|
}
|
|
void ldsminb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 0, 0, 0, 0b101, rs, rt, rn);
|
|
}
|
|
void ldumaxb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 0, 0, 0, 0b110, rs, rt, rn);
|
|
}
|
|
void lduminb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 0, 0, 0, 0b111, rs, rt, rn);
|
|
}
|
|
void ldswpb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 0, 0, 1, 0b000, rs, rt, rn);
|
|
}
|
|
void ldaddlb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 0, 1, 0, 0b000, rs, rt, rn);
|
|
}
|
|
void ldclrlb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 0, 1, 0, 0b001, rs, rt, rn);
|
|
}
|
|
void ldeorlb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 0, 1, 0, 0b010, rs, rt, rn);
|
|
}
|
|
void ldsetlb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 0, 1, 0, 0b011, rs, rt, rn);
|
|
}
|
|
void ldsmaxlb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 0, 1, 0, 0b100, rs, rt, rn);
|
|
}
|
|
void ldsminlb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 0, 1, 0, 0b101, rs, rt, rn);
|
|
}
|
|
void ldumaxlb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 0, 1, 0, 0b110, rs, rt, rn);
|
|
}
|
|
void lduminlb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 0, 1, 0, 0b111, rs, rt, rn);
|
|
}
|
|
void ldswplb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 0, 1, 1, 0b000, rs, rt, rn);
|
|
}
|
|
void ldaddab(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 1, 0, 0, 0b000, rs, rt, rn);
|
|
}
|
|
void ldclrab(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 1, 0, 0, 0b001, rs, rt, rn);
|
|
}
|
|
void ldeorab(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 1, 0, 0, 0b010, rs, rt, rn);
|
|
}
|
|
void ldsetab(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 1, 0, 0, 0b011, rs, rt, rn);
|
|
}
|
|
void ldsmaxab(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 1, 0, 0, 0b100, rs, rt, rn);
|
|
}
|
|
void ldsminab(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 1, 0, 0, 0b101, rs, rt, rn);
|
|
}
|
|
void ldumaxab(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 1, 0, 0, 0b110, rs, rt, rn);
|
|
}
|
|
void lduminab(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 1, 0, 0, 0b111, rs, rt, rn);
|
|
}
|
|
void ldswpab(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 1, 0, 1, 0b000, rs, rt, rn);
|
|
}
|
|
void ldaddalb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 1, 1, 0, 0b000, rs, rt, rn);
|
|
}
|
|
void ldclralb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 1, 1, 0, 0b001, rs, rt, rn);
|
|
}
|
|
void ldeoralb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 1, 1, 0, 0b010, rs, rt, rn);
|
|
}
|
|
void ldsetalb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 1, 1, 0, 0b011, rs, rt, rn);
|
|
}
|
|
void ldsmaxalb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 1, 1, 0, 0b100, rs, rt, rn);
|
|
}
|
|
void ldsminalb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 1, 1, 0, 0b101, rs, rt, rn);
|
|
}
|
|
void ldumaxalb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 1, 1, 0, 0b110, rs, rt, rn);
|
|
}
|
|
void lduminalb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 1, 1, 0, 0b111, rs, rt, rn);
|
|
}
|
|
void ldswpalb(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 1, 1, 1, 0b000, rs, rt, rn);
|
|
}
|
|
// 16-bit
|
|
void ldaddh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 0, 0, 0, 0b000, rs, rt, rn);
|
|
}
|
|
void ldclrh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 0, 0, 0, 0b001, rs, rt, rn);
|
|
}
|
|
void ldeorh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 0, 0, 0, 0b010, rs, rt, rn);
|
|
}
|
|
void ldseth(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 0, 0, 0, 0b011, rs, rt, rn);
|
|
}
|
|
void ldsmaxh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 0, 0, 0, 0b100, rs, rt, rn);
|
|
}
|
|
void ldsminh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 0, 0, 0, 0b101, rs, rt, rn);
|
|
}
|
|
void ldumaxh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 0, 0, 0, 0b110, rs, rt, rn);
|
|
}
|
|
void lduminh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 0, 0, 0, 0b111, rs, rt, rn);
|
|
}
|
|
void ldswph(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 0, 0, 1, 0b000, rs, rt, rn);
|
|
}
|
|
void ldaddlh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 0, 1, 0, 0b000, rs, rt, rn);
|
|
}
|
|
void ldclrlh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 0, 1, 0, 0b001, rs, rt, rn);
|
|
}
|
|
void ldeorlh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 0, 1, 0, 0b010, rs, rt, rn);
|
|
}
|
|
void ldsetlh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 0, 1, 0, 0b011, rs, rt, rn);
|
|
}
|
|
void ldsmaxlh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 0, 1, 0, 0b100, rs, rt, rn);
|
|
}
|
|
void ldsminlh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 0, 1, 0, 0b101, rs, rt, rn);
|
|
}
|
|
void ldumaxlh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 0, 1, 0, 0b110, rs, rt, rn);
|
|
}
|
|
void lduminlh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 0, 1, 0, 0b111, rs, rt, rn);
|
|
}
|
|
void ldswplh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 0, 1, 1, 0b000, rs, rt, rn);
|
|
}
|
|
void ldaddah(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 1, 0, 0, 0b000, rs, rt, rn);
|
|
}
|
|
void ldclrah(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 1, 0, 0, 0b001, rs, rt, rn);
|
|
}
|
|
void ldeorah(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 1, 0, 0, 0b010, rs, rt, rn);
|
|
}
|
|
void ldsetah(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 1, 0, 0, 0b011, rs, rt, rn);
|
|
}
|
|
void ldsmaxah(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 1, 0, 0, 0b100, rs, rt, rn);
|
|
}
|
|
void ldsminah(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 1, 0, 0, 0b101, rs, rt, rn);
|
|
}
|
|
void ldumaxah(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 1, 0, 0, 0b110, rs, rt, rn);
|
|
}
|
|
void lduminah(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 1, 0, 0, 0b111, rs, rt, rn);
|
|
}
|
|
void ldswpah(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 1, 0, 1, 0b000, rs, rt, rn);
|
|
}
|
|
void ldaddalh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 1, 1, 0, 0b000, rs, rt, rn);
|
|
}
|
|
void ldclralh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 1, 1, 0, 0b001, rs, rt, rn);
|
|
}
|
|
void ldeoralh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 1, 1, 0, 0b010, rs, rt, rn);
|
|
}
|
|
void ldsetalh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 1, 1, 0, 0b011, rs, rt, rn);
|
|
}
|
|
void ldsmaxalh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 1, 1, 0, 0b100, rs, rt, rn);
|
|
}
|
|
void ldsminalh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 1, 1, 0, 0b101, rs, rt, rn);
|
|
}
|
|
void ldumaxalh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 1, 1, 0, 0b110, rs, rt, rn);
|
|
}
|
|
void lduminalh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 1, 1, 0, 0b111, rs, rt, rn);
|
|
}
|
|
void ldswpalh(Register rs, Register rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 1, 1, 1, 0b000, rs, rt, rn);
|
|
}
|
|
// 32-bit
|
|
void ldadd(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 0, 0, 0, 0b000, rs, rt, rn);
|
|
}
|
|
void ldclr(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 0, 0, 0, 0b001, rs, rt, rn);
|
|
}
|
|
void ldeor(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 0, 0, 0, 0b010, rs, rt, rn);
|
|
}
|
|
void ldset(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 0, 0, 0, 0b011, rs, rt, rn);
|
|
}
|
|
void ldsmax(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 0, 0, 0, 0b100, rs, rt, rn);
|
|
}
|
|
void ldsmin(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 0, 0, 0, 0b101, rs, rt, rn);
|
|
}
|
|
void ldumax(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 0, 0, 0, 0b110, rs, rt, rn);
|
|
}
|
|
void ldumin(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 0, 0, 0, 0b111, rs, rt, rn);
|
|
}
|
|
void ldswp(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 0, 0, 1, 0b000, rs, rt, rn);
|
|
}
|
|
void ldaddl(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 0, 1, 0, 0b000, rs, rt, rn);
|
|
}
|
|
void ldclrl(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 0, 1, 0, 0b001, rs, rt, rn);
|
|
}
|
|
void ldeorl(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 0, 1, 0, 0b010, rs, rt, rn);
|
|
}
|
|
void ldsetl(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 0, 1, 0, 0b011, rs, rt, rn);
|
|
}
|
|
void ldsmaxl(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 0, 1, 0, 0b100, rs, rt, rn);
|
|
}
|
|
void ldsminl(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 0, 1, 0, 0b101, rs, rt, rn);
|
|
}
|
|
void ldumaxl(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 0, 1, 0, 0b110, rs, rt, rn);
|
|
}
|
|
void lduminl(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 0, 1, 0, 0b111, rs, rt, rn);
|
|
}
|
|
void ldswpl(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 0, 1, 1, 0b000, rs, rt, rn);
|
|
}
|
|
void ldadda(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 1, 0, 0, 0b000, rs, rt, rn);
|
|
}
|
|
void ldclra(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 1, 0, 0, 0b001, rs, rt, rn);
|
|
}
|
|
void ldeora(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 1, 0, 0, 0b010, rs, rt, rn);
|
|
}
|
|
void ldseta(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 1, 0, 0, 0b011, rs, rt, rn);
|
|
}
|
|
void ldsmaxa(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 1, 0, 0, 0b100, rs, rt, rn);
|
|
}
|
|
void ldsmina(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 1, 0, 0, 0b101, rs, rt, rn);
|
|
}
|
|
void ldumaxa(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 1, 0, 0, 0b110, rs, rt, rn);
|
|
}
|
|
void ldumina(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 1, 0, 0, 0b111, rs, rt, rn);
|
|
}
|
|
void ldswpa(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 1, 0, 1, 0b000, rs, rt, rn);
|
|
}
|
|
void ldaddal(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 1, 1, 0, 0b000, rs, rt, rn);
|
|
}
|
|
void ldclral(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 1, 1, 0, 0b001, rs, rt, rn);
|
|
}
|
|
void ldeoral(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 1, 1, 0, 0b010, rs, rt, rn);
|
|
}
|
|
void ldsetal(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 1, 1, 0, 0b011, rs, rt, rn);
|
|
}
|
|
void ldsmaxal(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 1, 1, 0, 0b100, rs, rt, rn);
|
|
}
|
|
void ldsminal(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 1, 1, 0, 0b101, rs, rt, rn);
|
|
}
|
|
void ldumaxal(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 1, 1, 0, 0b110, rs, rt, rn);
|
|
}
|
|
void lduminal(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 1, 1, 0, 0b111, rs, rt, rn);
|
|
}
|
|
void ldswpal(WRegister rs, WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 1, 1, 1, 0b000, rs, rt, rn);
|
|
}
|
|
// 64-bit
|
|
void ldadd(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 0, 0, 0, 0b000, rs, rt, rn);
|
|
}
|
|
void ldclr(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 0, 0, 0, 0b001, rs, rt, rn);
|
|
}
|
|
void ldeor(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 0, 0, 0, 0b010, rs, rt, rn);
|
|
}
|
|
void ldset(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 0, 0, 0, 0b011, rs, rt, rn);
|
|
}
|
|
void ldsmax(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 0, 0, 0, 0b100, rs, rt, rn);
|
|
}
|
|
void ldsmin(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 0, 0, 0, 0b101, rs, rt, rn);
|
|
}
|
|
void ldumax(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 0, 0, 0, 0b110, rs, rt, rn);
|
|
}
|
|
void ldumin(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 0, 0, 0, 0b111, rs, rt, rn);
|
|
}
|
|
void ldswp(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 0, 0, 1, 0b000, rs, rt, rn);
|
|
}
|
|
void ldaddl(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 0, 1, 0, 0b000, rs, rt, rn);
|
|
}
|
|
void ldclrl(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 0, 1, 0, 0b001, rs, rt, rn);
|
|
}
|
|
void ldeorl(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 0, 1, 0, 0b010, rs, rt, rn);
|
|
}
|
|
void ldsetl(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 0, 1, 0, 0b011, rs, rt, rn);
|
|
}
|
|
void ldsmaxl(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 0, 1, 0, 0b100, rs, rt, rn);
|
|
}
|
|
void ldsminl(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 0, 1, 0, 0b101, rs, rt, rn);
|
|
}
|
|
void ldumaxl(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 0, 1, 0, 0b110, rs, rt, rn);
|
|
}
|
|
void lduminl(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 0, 1, 0, 0b111, rs, rt, rn);
|
|
}
|
|
void ldswpl(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 0, 1, 1, 0b000, rs, rt, rn);
|
|
}
|
|
void ldadda(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 1, 0, 0, 0b000, rs, rt, rn);
|
|
}
|
|
void ldclra(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 1, 0, 0, 0b001, rs, rt, rn);
|
|
}
|
|
void ldeora(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 1, 0, 0, 0b010, rs, rt, rn);
|
|
}
|
|
void ldseta(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 1, 0, 0, 0b011, rs, rt, rn);
|
|
}
|
|
void ldsmaxa(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 1, 0, 0, 0b100, rs, rt, rn);
|
|
}
|
|
void ldsmina(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 1, 0, 0, 0b101, rs, rt, rn);
|
|
}
|
|
void ldumaxa(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 1, 0, 0, 0b110, rs, rt, rn);
|
|
}
|
|
void ldumina(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 1, 0, 0, 0b111, rs, rt, rn);
|
|
}
|
|
void ldswpa(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 1, 0, 1, 0b000, rs, rt, rn);
|
|
}
|
|
void ldaddal(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 1, 1, 0, 0b000, rs, rt, rn);
|
|
}
|
|
void ldclral(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 1, 1, 0, 0b001, rs, rt, rn);
|
|
}
|
|
void ldeoral(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 1, 1, 0, 0b010, rs, rt, rn);
|
|
}
|
|
void ldsetal(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 1, 1, 0, 0b011, rs, rt, rn);
|
|
}
|
|
void ldsmaxal(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 1, 1, 0, 0b100, rs, rt, rn);
|
|
}
|
|
void ldsminal(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 1, 1, 0, 0b101, rs, rt, rn);
|
|
}
|
|
void ldumaxal(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 1, 1, 0, 0b110, rs, rt, rn);
|
|
}
|
|
void lduminal(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 1, 1, 0, 0b111, rs, rt, rn);
|
|
}
|
|
void ldswpal(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 1, 1, 1, 0b000, rs, rt, rn);
|
|
}
|
|
void ldaprb(WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i8Bit, 1, 0, 1, 0b100, WReg::w31, rt, rn);
|
|
}
|
|
void ldaprh(WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i16Bit, 1, 0, 1, 0b100, WReg::w31, rt, rn);
|
|
}
|
|
void ldapr(WRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i32Bit, 1, 0, 1, 0b100, WReg::w31, rt, rn);
|
|
}
|
|
void ldapr(XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 1, 0, 1, 0b100, XReg::x31, rt, rn);
|
|
}
|
|
void st64bv0(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 0, 0, 1, 0b010, rs, rt, rn);
|
|
}
|
|
void st64bv(XRegister rs, XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 0, 0, 1, 0b011, rs, rt, rn);
|
|
}
|
|
void st64b(XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 0, 0, 1, 0b001, XReg::x31, rt, rn);
|
|
}
|
|
void ld64b(XRegister rt, Register rn) {
|
|
LoadStoreAtomicLSE(SubRegSize::i64Bit, 0, 0, 1, 0b101, XReg::x31, rt, rn);
|
|
}
|
|
|
|
// Loadstore register-register offset
|
|
void strb(ARMEmitter::Register rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option, bool Shift = false) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
constexpr uint32_t Op = 0b0011'1000'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b00, rt, rn, rm, Option, Shift ? 1 : 0);
|
|
}
|
|
void ldrb(ARMEmitter::Register rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option, bool Shift = false) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
constexpr uint32_t Op = 0b0011'1000'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b01, rt, rn, rm, Option, Shift ? 1 : 0);
|
|
}
|
|
void ldrsb(ARMEmitter::XRegister rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option, bool Shift = false) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
constexpr uint32_t Op = 0b0011'1000'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b10, rt, rn, rm, Option, Shift ? 1 : 0);
|
|
}
|
|
void ldrsb(ARMEmitter::WRegister rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option, bool Shift = false) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
constexpr uint32_t Op = 0b0011'1000'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b11, rt, rn, rm, Option, Shift ? 1 : 0);
|
|
}
|
|
void strh(ARMEmitter::Register rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option, uint32_t Shift) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
LOGMAN_THROW_A_FMT(Shift == 0 || Shift == 1, "Unsupported shift amount");
|
|
constexpr uint32_t Op = 0b0111'1000'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b00, rt, rn, rm, Option, Shift ? 1 : 0);
|
|
}
|
|
void ldrh(ARMEmitter::Register rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option, uint32_t Shift) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
LOGMAN_THROW_A_FMT(Shift == 0 || Shift == 1, "Unsupported shift amount");
|
|
constexpr uint32_t Op = 0b0111'1000'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b01, rt, rn, rm, Option, Shift ? 1 : 0);
|
|
}
|
|
void ldrsh(ARMEmitter::XRegister rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option, uint32_t Shift) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
LOGMAN_THROW_A_FMT(Shift == 0 || Shift == 1, "Unsupported shift amount");
|
|
constexpr uint32_t Op = 0b0111'1000'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b10, rt, rn, rm, Option, Shift ? 1 : 0);
|
|
}
|
|
void ldrsh(ARMEmitter::WRegister rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option, uint32_t Shift) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
LOGMAN_THROW_A_FMT(Shift == 0 || Shift == 1, "Unsupported shift amount");
|
|
constexpr uint32_t Op = 0b0111'1000'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b11, rt, rn, rm, Option, Shift ? 1 : 0);
|
|
}
|
|
void str(ARMEmitter::WRegister rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option, uint32_t Shift) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
LOGMAN_THROW_A_FMT(Shift == 0 || Shift == 2, "Unsupported shift amount");
|
|
constexpr uint32_t Op = 0b1011'1000'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b00, rt, rn, rm, Option, Shift ? 1 : 0);
|
|
}
|
|
void ldr(ARMEmitter::WRegister rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option, uint32_t Shift) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
LOGMAN_THROW_A_FMT(Shift == 0 || Shift == 2, "Unsupported shift amount: {}", Shift);
|
|
constexpr uint32_t Op = 0b1011'1000'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b01, rt, rn, rm, Option, Shift ? 1 : 0);
|
|
}
|
|
void ldrsw(ARMEmitter::XRegister rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option, uint32_t Shift) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
LOGMAN_THROW_A_FMT(Shift == 0 || Shift == 2, "Unsupported shift amount");
|
|
constexpr uint32_t Op = 0b1011'1000'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b10, rt, rn, rm, Option, Shift ? 1 : 0);
|
|
}
|
|
void str(ARMEmitter::XRegister rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option, uint32_t Shift) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
LOGMAN_THROW_A_FMT(Shift == 0 || Shift == 3, "Unsupported shift amount");
|
|
constexpr uint32_t Op = 0b1111'1000'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b00, rt, rn, rm, Option, Shift ? 1 : 0);
|
|
}
|
|
void ldr(ARMEmitter::XRegister rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option, uint32_t Shift) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
LOGMAN_THROW_A_FMT(Shift == 0 || Shift == 3, "Unsupported shift amount");
|
|
constexpr uint32_t Op = 0b1111'1000'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b01, rt, rn, rm, Option, Shift ? 1 : 0);
|
|
}
|
|
void prfm(ARMEmitter::Prefetch prfop, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option, uint32_t Shift) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
LOGMAN_THROW_A_FMT(Shift == 0 || Shift == 3, "Unsupported shift amount");
|
|
constexpr uint32_t Op = 0b1111'1000'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b10, prfop, rn, rm, Option, Shift ? 1 : 0);
|
|
}
|
|
void strb(ARMEmitter::VRegister rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
constexpr uint32_t Op = 0b0011'1100'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b00, rt, rn, rm, Option, 0);
|
|
}
|
|
void ldrb(ARMEmitter::VRegister rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
constexpr uint32_t Op = 0b0011'1100'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b01, rt, rn, rm, Option, 0);
|
|
}
|
|
void strh(ARMEmitter::VRegister rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option, uint32_t Shift) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
LOGMAN_THROW_A_FMT(Shift == 0 || Shift == 1, "Unsupported shift amount");
|
|
constexpr uint32_t Op = 0b0111'1100'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b00, rt, rn, rm, Option, Shift ? 1 : 0);
|
|
}
|
|
void ldrh(ARMEmitter::VRegister rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option, uint32_t Shift) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
LOGMAN_THROW_A_FMT(Shift == 0 || Shift == 1, "Unsupported shift amount");
|
|
constexpr uint32_t Op = 0b0111'1100'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b01, rt, rn, rm, Option, Shift ? 1 : 0);
|
|
}
|
|
void str(ARMEmitter::SRegister rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option, uint32_t Shift) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
LOGMAN_THROW_A_FMT(Shift == 0 || Shift == 2, "Unsupported shift amount");
|
|
constexpr uint32_t Op = 0b1011'1100'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b00, rt, rn, rm, Option, Shift ? 1 : 0);
|
|
}
|
|
void ldr(ARMEmitter::SRegister rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option, uint32_t Shift) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
LOGMAN_THROW_A_FMT(Shift == 0 || Shift == 2, "Unsupported shift amount");
|
|
constexpr uint32_t Op = 0b1011'1100'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b01, rt, rn, rm, Option, Shift ? 1 : 0);
|
|
}
|
|
void str(ARMEmitter::DRegister rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option, uint32_t Shift) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
LOGMAN_THROW_A_FMT(Shift == 0 || Shift == 3, "Unsupported shift amount");
|
|
constexpr uint32_t Op = 0b1111'1100'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b00, rt, rn, rm, Option, Shift ? 1 : 0);
|
|
}
|
|
void ldr(ARMEmitter::DRegister rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option, uint32_t Shift) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
LOGMAN_THROW_A_FMT(Shift == 0 || Shift == 3, "Unsupported shift amount");
|
|
constexpr uint32_t Op = 0b1111'1100'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b01, rt, rn, rm, Option, Shift ? 1 : 0);
|
|
}
|
|
void str(ARMEmitter::QRegister rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option, uint32_t Shift) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
LOGMAN_THROW_A_FMT(Shift == 0 || Shift == 4, "Unsupported shift amount");
|
|
constexpr uint32_t Op = 0b0011'1100'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b10, rt, rn, rm, Option, Shift ? 1 : 0);
|
|
}
|
|
void ldr(ARMEmitter::QRegister rt, ARMEmitter::Register rn, ARMEmitter::Register rm, ARMEmitter::ExtendedType Option, uint32_t Shift) {
|
|
LOGMAN_THROW_A_FMT((FEXCore::ToUnderlying(Option) & 0b010) == 0b010, "Unsupported Extendtype");
|
|
LOGMAN_THROW_A_FMT(Shift == 0 || Shift == 4, "Unsupported shift amount");
|
|
constexpr uint32_t Op = 0b0011'1100'001 << 21 | (0b10 << 10);
|
|
LoadStoreRegisterOffset(Op, 0b11, rt, rn, rm, Option, Shift ? 1 : 0);
|
|
}
|
|
|
|
void strb(ARMEmitter::Register rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
strb(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option, MemSrc.MetaType.ExtendedType.Shift);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
strb(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if (MemSrc.MetaType.ImmType.Imm < 0) {
|
|
sturb(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
strb(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
strb<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
strb<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
void ldrb(ARMEmitter::Register rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
ldrb(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option, MemSrc.MetaType.ExtendedType.Shift);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
ldrb(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if (MemSrc.MetaType.ImmType.Imm < 0) {
|
|
ldurb(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
ldrb(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
ldrb<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
ldrb<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
void ldrsb(ARMEmitter::XRegister rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
ldrsb(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option, MemSrc.MetaType.ExtendedType.Shift);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
ldrsb(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if (MemSrc.MetaType.ImmType.Imm < 0) {
|
|
ldursb(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
ldrsb(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
ldrsb<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
ldrsb<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
void ldrsb(ARMEmitter::WRegister rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
ldrsb(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option, MemSrc.MetaType.ExtendedType.Shift);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
ldrsb(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if (MemSrc.MetaType.ImmType.Imm < 0) {
|
|
ldursb(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
ldrsb(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
ldrsb<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
ldrsb<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
void strh(ARMEmitter::Register rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
strh(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option, MemSrc.MetaType.ExtendedType.Shift);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
strh(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if ((MemSrc.MetaType.ImmType.Imm & 0b1) || MemSrc.MetaType.ImmType.Imm < 0) {
|
|
sturh(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
strh(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
strh<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
strh<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
void ldrh(ARMEmitter::Register rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
ldrh(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option, MemSrc.MetaType.ExtendedType.Shift);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
ldrh(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if ((MemSrc.MetaType.ImmType.Imm & 0b1) || MemSrc.MetaType.ImmType.Imm < 0) {
|
|
ldurh(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
ldrh(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
ldrh<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
ldrh<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
void ldrsh(ARMEmitter::XRegister rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
ldrsh(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option, MemSrc.MetaType.ExtendedType.Shift);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
ldrsh(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if ((MemSrc.MetaType.ImmType.Imm & 0b1) || MemSrc.MetaType.ImmType.Imm < 0) {
|
|
ldursh(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
ldrsh(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
ldrsh<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
ldrsh<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
void ldrsh(ARMEmitter::WRegister rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
ldrsh(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option, MemSrc.MetaType.ExtendedType.Shift);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
ldrsh(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if ((MemSrc.MetaType.ImmType.Imm & 0b1) || MemSrc.MetaType.ImmType.Imm < 0) {
|
|
ldursh(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
ldrsh(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
ldrsh<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
ldrsh<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
void str(ARMEmitter::WRegister rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
str(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option, MemSrc.MetaType.ExtendedType.Shift);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
str(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if ((MemSrc.MetaType.ImmType.Imm & 0b11) || MemSrc.MetaType.ImmType.Imm < 0) {
|
|
stur(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
str(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
str<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
str<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
void ldr(ARMEmitter::WRegister rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
ldr(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option, MemSrc.MetaType.ExtendedType.Shift);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
ldr(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if ((MemSrc.MetaType.ImmType.Imm & 0b11) || MemSrc.MetaType.ImmType.Imm < 0) {
|
|
ldur(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
ldr(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
ldr<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
ldr<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
void ldrsw(ARMEmitter::XRegister rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
ldrsw(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option, MemSrc.MetaType.ExtendedType.Shift);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
ldrsw(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if ((MemSrc.MetaType.ImmType.Imm & 0b11) || MemSrc.MetaType.ImmType.Imm < 0) {
|
|
ldursw(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
ldrsw(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
ldrsw<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
ldrsw<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
void str(ARMEmitter::XRegister rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
str(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option, MemSrc.MetaType.ExtendedType.Shift);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
str(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if ((MemSrc.MetaType.ImmType.Imm & 0b111) || MemSrc.MetaType.ImmType.Imm < 0) {
|
|
stur(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
str(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
str<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
str<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
void ldr(ARMEmitter::XRegister rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
ldr(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option, MemSrc.MetaType.ExtendedType.Shift);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
ldr(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if ((MemSrc.MetaType.ImmType.Imm & 0b111) || MemSrc.MetaType.ImmType.Imm < 0) {
|
|
ldur(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
ldr(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
ldr<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
ldr<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
void prfm(ARMEmitter::Prefetch prfop, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
prfm(prfop, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option, MemSrc.MetaType.ExtendedType.Shift);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
prfm(prfop, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if ((MemSrc.MetaType.ImmType.Imm & 0b111) || MemSrc.MetaType.ImmType.Imm < 0) {
|
|
prfum<IndexType::OFFSET>(prfop, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
prfm(prfop, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
|
|
void strb(ARMEmitter::VRegister rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
LOGMAN_THROW_A_FMT(MemSrc.MetaType.ExtendedType.Shift == false, "Can't shift byte");
|
|
strb(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
strb(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if (MemSrc.MetaType.ImmType.Imm < 0) {
|
|
sturb(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
strb(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
strb<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
strb<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
void ldrb(ARMEmitter::VRegister rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
LOGMAN_THROW_A_FMT(MemSrc.MetaType.ExtendedType.Shift == false, "Can't shift byte");
|
|
ldrb(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
ldrb(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if (MemSrc.MetaType.ImmType.Imm < 0) {
|
|
ldurb(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
ldrb(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
ldrb<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
ldrb<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
void strh(ARMEmitter::VRegister rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
strh(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option, MemSrc.MetaType.ExtendedType.Shift);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
strh(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if ((MemSrc.MetaType.ImmType.Imm & 0b1) || MemSrc.MetaType.ImmType.Imm < 0) {
|
|
sturh(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
strh(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
strh<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
strh<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
void ldrh(ARMEmitter::VRegister rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
ldrh(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option, MemSrc.MetaType.ExtendedType.Shift);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
ldrh(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if ((MemSrc.MetaType.ImmType.Imm & 0b1) || MemSrc.MetaType.ImmType.Imm < 0) {
|
|
ldurh(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
ldrh(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
ldrh<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
ldrh<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
void str(ARMEmitter::SRegister rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
str(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option, MemSrc.MetaType.ExtendedType.Shift);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
str(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if ((MemSrc.MetaType.ImmType.Imm & 0b11) || MemSrc.MetaType.ImmType.Imm < 0) {
|
|
stur(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
str(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
str<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
str<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
void ldr(ARMEmitter::SRegister rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
ldr(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option, MemSrc.MetaType.ExtendedType.Shift);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
ldr(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if ((MemSrc.MetaType.ImmType.Imm & 0b11) || MemSrc.MetaType.ImmType.Imm < 0) {
|
|
ldur(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
ldr(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
ldr<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
ldr<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
void str(ARMEmitter::DRegister rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
str(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option, MemSrc.MetaType.ExtendedType.Shift);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
str(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if ((MemSrc.MetaType.ImmType.Imm & 0b111) || MemSrc.MetaType.ImmType.Imm < 0) {
|
|
stur(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
str(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
str<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
str<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
void ldr(ARMEmitter::DRegister rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
ldr(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option, MemSrc.MetaType.ExtendedType.Shift);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
ldr(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if ((MemSrc.MetaType.ImmType.Imm & 0b111) || MemSrc.MetaType.ImmType.Imm < 0) {
|
|
ldur(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
ldr(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
ldr<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
ldr<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
void str(ARMEmitter::QRegister rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
str(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option, MemSrc.MetaType.ExtendedType.Shift);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
str(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if ((MemSrc.MetaType.ImmType.Imm & 0b1111) || MemSrc.MetaType.ImmType.Imm < 0) {
|
|
stur(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
str(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
str<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
str<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
void ldr(ARMEmitter::QRegister rt, ARMEmitter::ExtendedMemOperand MemSrc) {
|
|
if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED &&
|
|
MemSrc.MetaType.ExtendedType.rm.Idx() != ARMEmitter::Reg::r31.Idx()) {
|
|
ldr(rt, MemSrc.rn, MemSrc.MetaType.ExtendedType.rm, MemSrc.MetaType.ExtendedType.Option, MemSrc.MetaType.ExtendedType.Shift);
|
|
} else if (MemSrc.MetaType.Header.MemType == ARMEmitter::ExtendedMemOperand::Type::TYPE_EXTENDED) {
|
|
ldr(rt, MemSrc.rn);
|
|
} else {
|
|
if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::OFFSET) {
|
|
if ((MemSrc.MetaType.ImmType.Imm & 0b1111) || MemSrc.MetaType.ImmType.Imm < 0) {
|
|
ldur(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
ldr(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
}
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::POST) {
|
|
ldr<ARMEmitter::IndexType::POST>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else if (MemSrc.MetaType.ImmType.Index == ARMEmitter::IndexType::PRE) {
|
|
ldr<ARMEmitter::IndexType::PRE>(rt, MemSrc.rn, MemSrc.MetaType.ImmType.Imm);
|
|
} else {
|
|
LOGMAN_MSG_A_FMT("Unexpected loadstore index type");
|
|
FEX_UNREACHABLE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Loadstore PAC
|
|
// TODO
|
|
|
|
// Loadstore unsigned immediate
|
|
// Maximum values of unsigned immediate offsets for particular data sizes.
|
|
static constexpr uint32_t LSByteMaxUnsignedOffset = 4095;
|
|
static constexpr uint32_t LSHalfMaxUnsignedOffset = 8190;
|
|
static constexpr uint32_t LSWordMaxUnsignedOffset = 16380;
|
|
static constexpr uint32_t LSDWordMaxUnsignedOffset = 32760;
|
|
static constexpr uint32_t LSQWordMaxUnsignedOffset = 65520;
|
|
|
|
void strb(Register rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b00, 0, 0b00, rt, rn, Imm);
|
|
}
|
|
void ldrb(Register rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b00, 0, 0b01, rt, rn, Imm);
|
|
}
|
|
void ldrsb(XRegister rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b00, 0, 0b10, rt, rn, Imm);
|
|
}
|
|
void ldrsb(WRegister rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b00, 0, 0b11, rt, rn, Imm);
|
|
}
|
|
void strb(VRegister rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b00, 1, 0b00, rt, rn, Imm);
|
|
}
|
|
void ldrb(VRegister rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b00, 1, 0b01, rt, rn, Imm);
|
|
}
|
|
void strh(Register rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b01, 0, 0b00, rt, rn, Imm);
|
|
}
|
|
void ldrh(Register rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b01, 0, 0b01, rt, rn, Imm);
|
|
}
|
|
void ldrsh(XRegister rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b01, 0, 0b10, rt, rn, Imm);
|
|
}
|
|
void ldrsh(WRegister rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b01, 0, 0b11, rt, rn, Imm);
|
|
}
|
|
void strh(VRegister rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b01, 1, 0b00, rt, rn, Imm);
|
|
}
|
|
void ldrh(VRegister rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b01, 1, 0b01, rt, rn, Imm);
|
|
}
|
|
void str(WRegister rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b10, 0, 0b00, rt, rn, Imm);
|
|
}
|
|
void ldr(WRegister rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b10, 0, 0b01, rt, rn, Imm);
|
|
}
|
|
void ldrsw(XRegister rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b10, 0, 0b10, rt, rn, Imm);
|
|
}
|
|
void str(SRegister rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b10, 1, 0b00, rt, rn, Imm);
|
|
}
|
|
void ldr(SRegister rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b10, 1, 0b01, rt, rn, Imm);
|
|
}
|
|
void str(XRegister rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b11, 0, 0b00, rt, rn, Imm);
|
|
}
|
|
void ldr(XRegister rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b11, 0, 0b01, rt, rn, Imm);
|
|
}
|
|
|
|
void ldr(SubRegSize size, Register rt, Register rn, uint32_t Imm = 0) {
|
|
LOGMAN_THROW_A_FMT(size != SubRegSize::i128Bit, "Can't use 128-bit size");
|
|
LoadStoreUnsigned(FEXCore::ToUnderlying(size), 0, 0b01, rt, rn, Imm);
|
|
}
|
|
void str(SubRegSize size, Register rt, Register rn, uint32_t Imm = 0) {
|
|
LOGMAN_THROW_A_FMT(size != SubRegSize::i128Bit, "Can't use 128-bit size");
|
|
LoadStoreUnsigned(FEXCore::ToUnderlying(size), 0, 0b00, rt, rn, Imm);
|
|
}
|
|
|
|
void prfm(Prefetch prfop, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b11, 0, 0b10, prfop, rn, Imm);
|
|
}
|
|
void str(DRegister rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b11, 1, 0b00, rt, rn, Imm);
|
|
}
|
|
void ldr(DRegister rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b11, 1, 0b01, rt, rn, Imm);
|
|
}
|
|
void str(QRegister rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b00, 1, 0b10, rt, rn, Imm);
|
|
}
|
|
void ldr(QRegister rt, Register rn, uint32_t Imm = 0) {
|
|
LoadStoreUnsigned(0b00, 1, 0b11, rt, rn, Imm);
|
|
}
|
|
|
|
private:
|
|
void AtomicOp(uint32_t Op, ARMEmitter::Size s, uint32_t L, uint32_t o0, ARMEmitter::Register rs, ARMEmitter::Register rt,
|
|
ARMEmitter::Register rt2, ARMEmitter::Register rn) {
|
|
const uint32_t sz = s == ARMEmitter::Size::i64Bit ? (1U << 30) : 0;
|
|
uint32_t Instr = Op;
|
|
|
|
Instr |= sz;
|
|
Instr |= L << 22;
|
|
Instr |= Encode_rs(rs);
|
|
Instr |= o0 << 15;
|
|
Instr |= Encode_rt2(rt2);
|
|
Instr |= Encode_rn(rn);
|
|
Instr |= Encode_rt(rt);
|
|
|
|
dc32(Instr);
|
|
}
|
|
|
|
template<typename T>
|
|
void SubAtomicOp(uint32_t Op, ARMEmitter::SubRegSize s, uint32_t L, uint32_t o0, T rs, T rt, T rt2, ARMEmitter::Register rn) {
|
|
const uint32_t sz = FEXCore::ToUnderlying(s) << 30;
|
|
uint32_t Instr = Op;
|
|
|
|
Instr |= sz;
|
|
Instr |= L << 22;
|
|
Instr |= Encode_rs(rs);
|
|
Instr |= o0 << 15;
|
|
Instr |= Encode_rt2(rt2);
|
|
Instr |= Encode_rn(rn);
|
|
Instr |= Encode_rt(rt);
|
|
|
|
dc32(Instr);
|
|
}
|
|
|
|
template<typename T>
|
|
void SubAtomicImm(uint32_t Op, ARMEmitter::SubRegSize s, uint32_t opc, T rt, ARMEmitter::Register rn, uint32_t Imm) {
|
|
const uint32_t sz = FEXCore::ToUnderlying(s) << 30;
|
|
uint32_t Instr = Op;
|
|
|
|
Instr |= sz;
|
|
Instr |= opc << 22;
|
|
Instr |= Imm << 12;
|
|
Instr |= Encode_rn(rn);
|
|
Instr |= Encode_rt(rt);
|
|
|
|
dc32(Instr);
|
|
}
|
|
// Load register literal
|
|
template<typename T>
|
|
void LoadStoreLiteral(uint32_t Op, T rt, uint32_t Imm) {
|
|
uint32_t Instr = Op;
|
|
|
|
Instr |= Imm << 5;
|
|
Instr |= Encode_rt(rt);
|
|
dc32(Instr);
|
|
}
|
|
|
|
// Loadstore no-allocate pair
|
|
template<typename T>
|
|
void LoadStoreNoAllocate(uint32_t Op, T rt, T rt2, ARMEmitter::Register rn, uint32_t Imm) {
|
|
uint32_t Instr = Op;
|
|
|
|
Instr |= Imm << 15;
|
|
Instr |= Encode_rt2(rt2);
|
|
Instr |= Encode_rn(rn);
|
|
Instr |= Encode_rt(rt);
|
|
dc32(Instr);
|
|
}
|
|
// Loadstore register pair post-indexed
|
|
template<typename T>
|
|
void LoadStorePair(uint32_t Op, T rt, T rt2, ARMEmitter::Register rn, uint32_t Imm) {
|
|
uint32_t Instr = Op;
|
|
Instr |= Imm << 15;
|
|
Instr |= Encode_rt2(rt2);
|
|
Instr |= Encode_rn(rn);
|
|
Instr |= Encode_rt(rt);
|
|
dc32(Instr);
|
|
}
|
|
|
|
// Loadstore register unscaled immediate
|
|
// Loadstore register immediate post-indexed
|
|
// Loadstore register unprivileged
|
|
// Loadstore register immediate pre-indexed
|
|
template<typename T>
|
|
void LoadStoreImm(uint32_t Op, uint32_t o2, T rt, ARMEmitter::Register rn, uint32_t Imm) {
|
|
uint32_t Instr = Op;
|
|
|
|
Instr |= Imm << 12;
|
|
Instr |= o2 << 10;
|
|
Instr |= Encode_rn(rn);
|
|
Instr |= Encode_rt(rt);
|
|
dc32(Instr);
|
|
}
|
|
|
|
// Atomic memory operations
|
|
void LoadStoreAtomicLSE(SubRegSize s, uint32_t A, uint32_t R, uint32_t o3, uint32_t opc, Register rs, Register rt, Register rn) {
|
|
uint32_t Instr = 0b0011'1000'0010'0000'0000'0000'0000'0000;
|
|
Instr |= FEXCore::ToUnderlying(s) << 30;
|
|
Instr |= A << 23;
|
|
Instr |= R << 22;
|
|
Instr |= Encode_rs(rs);
|
|
Instr |= o3 << 15;
|
|
Instr |= opc << 12;
|
|
Instr |= Encode_rn(rn);
|
|
Instr |= Encode_rt(rt);
|
|
dc32(Instr);
|
|
}
|
|
|
|
// Loadstore register-register offset
|
|
template<typename T>
|
|
void LoadStoreRegisterOffset(uint32_t Op, uint32_t opc, T rt, ARMEmitter::Register rn, ARMEmitter::Register rm,
|
|
ARMEmitter::ExtendedType Option, uint32_t Shift) {
|
|
uint32_t Instr = Op;
|
|
|
|
Instr |= opc << 22;
|
|
Instr |= Encode_rt(rt);
|
|
Instr |= FEXCore::ToUnderlying(Option) << 13;
|
|
Instr |= Shift << 12;
|
|
Instr |= Encode_rn(rn);
|
|
Instr |= Encode_rm(rm);
|
|
dc32(Instr);
|
|
}
|
|
|
|
// Loadstore unsigned immediate
|
|
template<typename T>
|
|
void LoadStoreUnsigned(uint32_t size, uint32_t V, uint32_t opc, T rt, Register rn, uint32_t Imm) {
|
|
uint32_t SizeShift = size;
|
|
if constexpr (std::is_same_v<T, QRegister>) {
|
|
// 128-bit variant is specified via size=0b00, V=1, opc=0b1x
|
|
// so we need to special case this one based on whether or not
|
|
// rt indicates a 128-bit vector. Nice thing is this can be
|
|
// checked at compile-time.
|
|
SizeShift = 4;
|
|
}
|
|
|
|
[[maybe_unused]] const uint32_t MaxImm = LSByteMaxUnsignedOffset << SizeShift;
|
|
[[maybe_unused]] const uint32_t ElementSize = 1U << SizeShift;
|
|
|
|
LOGMAN_THROW_A_FMT(Imm <= MaxImm, "{}: Offset not valid: Imm: 0x{:x} Max: 0x{:x}", __func__, Imm, MaxImm);
|
|
LOGMAN_THROW_A_FMT((Imm % ElementSize) == 0, "{}: Offset must be a multiple of {}. Offset: 0x{:x}", __func__, ElementSize, Imm);
|
|
|
|
const uint32_t ShiftedImm = Imm >> SizeShift;
|
|
|
|
uint32_t Instr = 0b0011'1001'0000'0000'0000'0000'0000'0000;
|
|
Instr |= size << 30;
|
|
Instr |= V << 26;
|
|
Instr |= opc << 22;
|
|
Instr |= ShiftedImm << 10;
|
|
Instr |= Encode_rn(rn);
|
|
Instr |= Encode_rt(rt);
|
|
dc32(Instr);
|
|
}
|
|
|
|
template<IndexType Index>
|
|
void ldp_w(ARMEmitter::VRegister rt, ARMEmitter::VRegister rt2, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 252 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = (0b0010'1100'01 << 22) | (Index == IndexType::POST ? (0b01 << 23) :
|
|
Index == IndexType::PRE ? (0b11 << 23) :
|
|
Index == IndexType::OFFSET ? (0b10 << 23) :
|
|
-1);
|
|
|
|
LoadStorePair(Op, rt, rt2, rn, (Imm >> 2) & 0b111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void ldp_x(ARMEmitter::VRegister rt, ARMEmitter::VRegister rt2, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -512 && Imm <= 504 && ((Imm & 0b111) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = (0b0110'1100'01 << 22) | (Index == IndexType::POST ? (0b01 << 23) :
|
|
Index == IndexType::PRE ? (0b11 << 23) :
|
|
Index == IndexType::OFFSET ? (0b10 << 23) :
|
|
-1);
|
|
|
|
LoadStorePair(Op, rt, rt2, rn, (Imm >> 3) & 0b111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void stp_w(ARMEmitter::VRegister rt, ARMEmitter::VRegister rt2, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 252 && ((Imm & 0b11) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = (0b0010'1100'00 << 22) | (Index == IndexType::POST ? (0b01 << 23) :
|
|
Index == IndexType::PRE ? (0b11 << 23) :
|
|
Index == IndexType::OFFSET ? (0b10 << 23) :
|
|
-1);
|
|
|
|
LoadStorePair(Op, rt, rt2, rn, (Imm >> 2) & 0b111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void stp_x(ARMEmitter::VRegister rt, ARMEmitter::VRegister rt2, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -512 && Imm <= 504 && ((Imm & 0b111) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = (0b0110'1100'00 << 22) | (Index == IndexType::POST ? (0b01 << 23) :
|
|
Index == IndexType::PRE ? (0b11 << 23) :
|
|
Index == IndexType::OFFSET ? (0b10 << 23) :
|
|
-1);
|
|
|
|
LoadStorePair(Op, rt, rt2, rn, (Imm >> 3) & 0b111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void ldp_q(ARMEmitter::VRegister rt, ARMEmitter::VRegister rt2, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -1024 && Imm <= 1008 && ((Imm & 0b1111) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = (0b1010'1100'01 << 22) | (Index == IndexType::POST ? (0b01 << 23) :
|
|
Index == IndexType::PRE ? (0b11 << 23) :
|
|
Index == IndexType::OFFSET ? (0b10 << 23) :
|
|
-1);
|
|
|
|
LoadStorePair(Op, rt, rt2, rn, (Imm >> 4) & 0b111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void stp_q(ARMEmitter::VRegister rt, ARMEmitter::VRegister rt2, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -1024 && Imm <= 1008 && ((Imm & 0b1111) == 0), "Unscaled offset too large");
|
|
constexpr uint32_t Op = (0b1010'1100'00 << 22) | (Index == IndexType::POST ? (0b01 << 23) :
|
|
Index == IndexType::PRE ? (0b11 << 23) :
|
|
Index == IndexType::OFFSET ? (0b10 << 23) :
|
|
-1);
|
|
|
|
LoadStorePair(Op, rt, rt2, rn, (Imm >> 4) & 0b111'1111);
|
|
}
|
|
|
|
template<IndexType Index>
|
|
void stXrb(ARMEmitter::Register rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b0011'1000'00 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void ldXrb(ARMEmitter::Register rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b0011'1000'01 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void stXrb(ARMEmitter::VRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b0011'1100'00 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void ldXrb(ARMEmitter::VRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b0011'1100'01 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void ldXrsb(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b0011'1000'10 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void ldXrsb(ARMEmitter::WRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b0011'1000'11 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void stXrh(ARMEmitter::Register rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b0111'1000'00 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void ldXrh(ARMEmitter::Register rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b0111'1000'01 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void stXrh(ARMEmitter::VRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b0111'1100'00 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void ldXrh(ARMEmitter::VRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b0111'1100'01 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void ldXrsh(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b0111'1000'10 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void ldXrsh(ARMEmitter::WRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b0111'1000'11 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void stXr(ARMEmitter::WRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b1011'1000'00 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void ldXr(ARMEmitter::WRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b1011'1000'01 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void stXr(ARMEmitter::SRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b1011'1100'00 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void ldXr(ARMEmitter::SRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b1011'1100'01 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void ldXrsw(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b1011'1000'10 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void stXr(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b1111'1000'00 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void ldXr(ARMEmitter::XRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b1111'1000'01 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void stXr(ARMEmitter::DRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b1111'1100'00 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void ldXr(ARMEmitter::DRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b1111'1100'01 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void stXr(ARMEmitter::QRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b0011'1100'10 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
template<IndexType Index>
|
|
void ldXr(ARMEmitter::QRegister rt, ARMEmitter::Register rn, int32_t Imm) {
|
|
LOGMAN_THROW_A_FMT(Imm >= -256 && Imm <= 255, "Unscaled offset too large");
|
|
|
|
constexpr uint32_t Op = 0b0011'1100'11 << 22;
|
|
constexpr uint32_t o2 = Index == IndexType::POST ? 0b01 :
|
|
Index == IndexType::PRE ? 0b11 :
|
|
Index == IndexType::OFFSET ? 0b00 :
|
|
Index == IndexType::UNPRIVILEGED ? 0b10 :
|
|
-1;
|
|
|
|
LoadStoreImm(Op, o2, rt, rn, Imm & 0b1'1111'1111);
|
|
}
|
|
|
|
#ifndef INCLUDED_BY_EMITTER
|
|
}; // struct LoadstoreEmitterOps
|
|
} // namespace ARMEmitter
|
|
#endif
|