diff --git a/libc/src/string/memory_utils/elements_aarch64.h b/libc/src/string/memory_utils/elements_aarch64.h index 394951bae3aa..0529df70b87a 100644 --- a/libc/src/string/memory_utils/elements_aarch64.h +++ b/libc/src/string/memory_utils/elements_aarch64.h @@ -52,8 +52,9 @@ using _4 = __llvm_libc::scalar::_4; using _32 = Chained<_16, _16>; using _64 = Chained<_32, _32>; -struct ZVA { +struct Zva64 { static constexpr size_t SIZE = 64; + static void splat_set(char *dst, const unsigned char) { #if __SIZEOF_POINTER__ == 4 asm("dc zva, %w[dst]" : : [dst] "r"(dst) : "memory"); @@ -63,13 +64,14 @@ struct ZVA { } }; -inline static bool AArch64ZVA(char *dst, size_t count) { +inline static bool hasZva() { uint64_t zva_val; asm("mrs %[zva_val], dczid_el0" : [zva_val] "=r"(zva_val)); - if ((zva_val & 31) != 4) - return false; - splat_set::Then>>(dst, 0, count); - return true; + // DC ZVA is permitted if DZP, bit [4] is zero. + // BS, bits [3:0] is log2 of the block size in words. + // So the next line checks whether the instruction is permitted and block size + // is 16 words (i.e. 64 bytes). + return (zva_val & 0b11111) == 0b00100; } } // namespace aarch64_memset diff --git a/libc/src/string/memory_utils/memset_implementations.h b/libc/src/string/memory_utils/memset_implementations.h index 3fffc03e6439..4d893f44e245 100644 --- a/libc/src/string/memory_utils/memset_implementations.h +++ b/libc/src/string/memory_utils/memset_implementations.h @@ -92,7 +92,7 @@ inline static void inline_memset(char *dst, unsigned char value, size_t count) { return splat_set>(dst, value, count); if (count <= 32) return splat_set>(dst, value, count); - if (count <= 96) { + if (count <= (32 + 64)) { splat_set<_32>(dst, value); if (count <= 64) return splat_set>(dst, value, count); @@ -100,7 +100,9 @@ inline static void inline_memset(char *dst, unsigned char value, size_t count) { splat_set>(dst, value, count); return; } - if (count < 448 || value != 0 || !AArch64ZVA(dst, count)) + if (count >= 448 && value == 0 && hasZva()) + return splat_set::Then>>(dst, 0, count); + else return splat_set::Then>>(dst, value, count); #else /////////////////////////////////////////////////////////////////////////////