1
0
mirror of https://git.tukaani.org/xz.git synced 2026-10-31 03:14:56 +00:00

liblzma: ARM64 & LoongArch: Avoid aligned_readXXle on unaligned pointers

While most ARM64 and LoongArch processors support unaligned access,
the code wouldn't have worked on strict-align processors.

Use byte-by-byte method if the input buffer is at most 7 bytes. This
way the code works on strict-align processors too. It might not be
the very best method for tiny buffers, but it shouldn't matter in
practice (the simple implementation for big buffers isn't amazing
either because it cannot execute more than one CRC32 instruction
at a time on superscalar processors).

Reported-by: Guanni Qu
Fixes: 0ed893668554 ("liblzma: ARM64 CRC32: Align the buffer faster")
Fixes: 7baf6835cfbf ("liblzma: Speed up CRC32 calculation on 64-bit LoongArch")
This commit is contained in:
Lasse Collin 2026-05-19 17:36:15 +03:00
parent c2fe308792
commit 81faa2e653
No known key found for this signature in database
GPG Key ID: 38EE757D69184620
2 changed files with 39 additions and 29 deletions

View File

@ -50,9 +50,15 @@ crc32_arch_optimized(const uint8_t *buf, size_t size, uint32_t crc)
{
crc = ~crc;
if (size >= 8) {
// Align the input buffer because this was shown to be
// significantly faster than unaligned accesses.
if (size < 8) {
while (size > 0) {
crc = __crc32b(crc, *buf++);
--size;
}
} else {
// We have at least 8 bytes of input. Align the input buffer.
// Aligned is faster than unaligned access and works also on
// strict-align targets.
const size_t align = (0 - (uintptr_t)buf) & 7;
if (align & 1)
@ -79,23 +85,21 @@ crc32_arch_optimized(const uint8_t *buf, size_t size, uint32_t crc)
buf < limit; buf += 8)
crc = __crc32d(crc, aligned_read64le(buf));
size &= 7;
}
// Process the remaining 0-7 bytes.
if (size & 4) {
crc = __crc32w(crc, aligned_read32le(buf));
buf += 4;
}
// Process the remaining bytes that are not 8 byte aligned.
if (size & 4) {
crc = __crc32w(crc, aligned_read32le(buf));
buf += 4;
}
if (size & 2) {
crc = __crc32h(crc, aligned_read16le(buf));
buf += 2;
}
if (size & 2) {
crc = __crc32h(crc, aligned_read16le(buf));
buf += 2;
if (size & 1)
crc = __crc32b(crc, *buf);
}
if (size & 1)
crc = __crc32b(crc, *buf);
return ~crc;
}

View File

@ -21,7 +21,13 @@ crc32_arch_optimized(const uint8_t *buf, size_t size, uint32_t crc_unsigned)
{
int32_t crc = (int32_t)~crc_unsigned;
if (size >= 8) {
if (size < 8) {
while (size > 0) {
crc = __crc_w_b_w((int8_t)*buf++, crc);
--size;
}
} else {
// We have at least 8 bytes of input. Align the input buffer.
const size_t align = (0 - (uintptr_t)buf) & 7;
if (align & 1)
@ -39,26 +45,26 @@ crc32_arch_optimized(const uint8_t *buf, size_t size, uint32_t crc_unsigned)
size -= align;
// Process 8 bytes at a time.
for (const uint8_t *limit = buf + (size & ~(size_t)7);
buf < limit; buf += 8)
crc = __crc_w_d_w((int64_t)aligned_read64le(buf), crc);
size &= 7;
}
// Process the remaining 0-7 bytes.
if (size & 4) {
crc = __crc_w_w_w((int32_t)aligned_read32le(buf), crc);
buf += 4;
}
if (size & 4) {
crc = __crc_w_w_w((int32_t)aligned_read32le(buf), crc);
buf += 4;
}
if (size & 2) {
crc = __crc_w_h_w((int16_t)aligned_read16le(buf), crc);
buf += 2;
}
if (size & 2) {
crc = __crc_w_h_w((int16_t)aligned_read16le(buf), crc);
buf += 2;
if (size & 1)
crc = __crc_w_b_w((int8_t)*buf, crc);
}
if (size & 1)
crc = __crc_w_b_w((int8_t)*buf, crc);
return (uint32_t)~crc;
}