[a64] Optimize OPCODE_MEMSET with zva

* Add unit tests
* Use `dc zva` to zero out entire cache-lines worth of data, when possible
 * Special instruction that zaps an entire cache-line into being zero-values, typically 64-bytes at a time
* Statically read and initialize the `DCZID_EL0` register value since reading registers with `mrs` can be kinda slow and isn't worth doing redundantly at JIT-time when it never changes.
* Update store-instructions to use inline post-increments to avoid an additional `add` instruction and keep encoded instruction immediates small

Pretty much every arm processor has a cache line size of 64 bytes, so a typical `dcbz128` to clear 128-bytes of data now results in:
```
dc zva, x0
add x0, x0, 64
dc zva, x0
```
rather than a sequence of 8 `stp xzr, xzr, ...` instructions
This commit is contained in:
Wunkolo
2026-03-26 22:03:54 -07:00
committed by Heel
parent 1a53f261f7
commit 664b77f38e
3 changed files with 87 additions and 20 deletions

View File

@@ -241,6 +241,49 @@ TEST_CASE("STORE_F64_CONSTANT_BYTE_SWAP", "[instr]") {
});
}
// =============================================================================
// MEMSET — constant size
// =============================================================================
TEST_CASE("MEMSET_32_ZERO", "[instr]") {
TestFunction test([](HIRBuilder& b) {
auto addr = LoadGPR(b, 4);
b.Memset(addr, b.LoadZeroInt8(), b.LoadConstantInt64(32));
b.Return();
});
test.Run(
[&test](PPCContext* ctx) {
uint32_t addr = test.memory->SystemHeapAlloc(32, 32);
ctx->r[4] = addr;
},
[&test](PPCContext* ctx) {
auto* host =
test.memory->TranslateVirtual(static_cast<uint32_t>(ctx->r[4]));
const uint8_t result[32] = {};
REQUIRE(std::memcmp(result, host, 32) == 0);
test.memory->SystemHeapFree(static_cast<uint32_t>(ctx->r[4]));
});
}
TEST_CASE("MEMSET_128_ZERO", "[instr]") {
TestFunction test([](HIRBuilder& b) {
auto addr = LoadGPR(b, 4);
b.Memset(addr, b.LoadZeroInt8(), b.LoadConstantInt64(128));
b.Return();
});
test.Run(
[&test](PPCContext* ctx) {
uint32_t addr = test.memory->SystemHeapAlloc(128, 128);
ctx->r[4] = addr;
},
[&test](PPCContext* ctx) {
auto* host =
test.memory->TranslateVirtual(static_cast<uint32_t>(ctx->r[4]));
const uint8_t result[128] = {};
REQUIRE(std::memcmp(result, host, 128) == 0);
test.memory->SystemHeapFree(static_cast<uint32_t>(ctx->r[4]));
});
}
// =============================================================================
// LOAD_F32 / LOAD_F64 byte-swap (entirely unimplemented on x64)
// =============================================================================