AArch64: Add Neon path for convertSequences_noRepcodes

Add a 4-way Neon implementation for the convertSequences_noRepcodes
function. Remove 'static' keywords from all of its implementations to
be able to add unit tests.

Relative performance to Clang-18 using: `./fullbench -b18 -l5 enwik5`

Neoverse-V2   before     after
Clang-18:    100.000%  311.703%
Clang-19:    100.191%  311.714%
Clang-20:    100.181%  311.723%
GCC-13:      107.520%  252.309%
GCC-14:      107.652%  253.158%
GCC-15:      107.674%  253.168%

Cortex-A720   before     after
Clang-18:    100.000%  204.512%
Clang-19:    102.825%  204.600%
Clang-20:    102.807%  204.558%
GCC-13:      110.668%  203.594%
GCC-14:      110.684%  203.978%
GCC-15:      102.864%  204.299%

Co-authored by, Thomas Daubney <Thomas.Daubney@arm.com>
This commit is contained in:
Arpad Panyik
2025-07-10 18:20:57 +00:00
parent 8e4400463a
commit 07cd78d366
2 changed files with 262 additions and 6 deletions
+126
View File
@@ -770,6 +770,130 @@ static void test_blockSplitter_incompressibleExpansionProtection(unsigned testNb
DISPLAYLEVEL(3, "OK \n");
}
size_t convertSequences_noRepcodes(SeqDef* dstSeqs, const ZSTD_Sequence* inSeqs,
size_t nbSequences);
static size_t convertSequences_noRepcodes_ref(
SeqDef* dstSeqs,
const ZSTD_Sequence* inSeqs,
size_t nbSequences)
{
size_t longLen = 0;
size_t n;
for (n=0; n<nbSequences; n++) {
dstSeqs[n].offBase = OFFSET_TO_OFFBASE(inSeqs[n].offset);
dstSeqs[n].litLength = (U16)inSeqs[n].litLength;
dstSeqs[n].mlBase = (U16)(inSeqs[n].matchLength - MINMATCH);
/* Check for long length > 65535. */
if (UNLIKELY(inSeqs[n].matchLength > 65535+MINMATCH)) {
assert(longLen == 0);
longLen = n + 1;
}
if (UNLIKELY(inSeqs[n].litLength > 65535)) {
assert(longLen == 0);
longLen = n + nbSequences + 1;
}
}
return longLen;
}
static unsigned test_convertSequences_noRepcodes(unsigned seed, unsigned testNb)
{
ZSTD_Sequence nsrc[12];
SeqDef ndst[12], rdst[12];
size_t ref, ret, i, j;
seed += 0xDEADBEEF;
for (i = 0; i < COUNTOF(nsrc); ++i) {
seed = 48271 * ((unsigned)i + seed);
nsrc[i].offset = (seed & 0xFFFF) | 1; /* Offset shall not be zero. */
seed = 48271 * ((unsigned)i + seed);
nsrc[i].litLength = seed & 0xFFFF;
seed = 48271 * ((unsigned)i + seed);
nsrc[i].matchLength = (seed & 0xFFFFFF) % (65536 + MINMATCH);
seed = 48271 * ((unsigned)i + seed);
nsrc[i].rep = seed & 0xFF;
}
/* For near overflow and proper negative value handling. */
nsrc[5].matchLength = 65535 + MINMATCH;
nsrc[6].litLength = 65535;
nsrc[6].matchLength = 0;
nsrc[7].litLength = 0;
nsrc[7].matchLength = MINMATCH;
for (i = 0; i <= COUNTOF(nsrc); ++i) {
DISPLAYLEVEL(3, "test%3u : convertSequences_noRepcodes with %u inputs : ",
testNb++, (unsigned)i);
memset(ndst, 0, sizeof(ndst));
memset(rdst, 0, sizeof(rdst));
ref = convertSequences_noRepcodes_ref(rdst, nsrc, i);
ret = convertSequences_noRepcodes(ndst, nsrc, i);
CHECK_EQ(ret, ref);
CHECK_EQ(memcmp(rdst, ndst, sizeof(ndst)), 0);
DISPLAYLEVEL(3, "OK \n");
}
nsrc[7].matchLength = 65536 + MINMATCH;
for (i = 8; i <= COUNTOF(nsrc); ++i) {
DISPLAYLEVEL(3, "test%3u : convertSequences_noRepcodes with %u inputs and "
"matchLength overflow : ",
testNb++, (unsigned)i);
memset(ndst, 0, sizeof(ndst));
memset(rdst, 0, sizeof(rdst));
ref = convertSequences_noRepcodes_ref(rdst, nsrc, i);
ret = convertSequences_noRepcodes(ndst, nsrc, i);
CHECK_EQ(ret, ref);
CHECK_EQ(memcmp(rdst, ndst, sizeof(ndst)), 0);
DISPLAYLEVEL(3, "OK \n");
assert(COUNTOF(nsrc) > 8);
for (j = 4; j < 8; ++j) {
DISPLAYLEVEL(3, "test%3u : convertSequences_noRepcodes with %u inputs and "
"matchLength overflow #%u : ",
testNb++, (unsigned)i, (unsigned)(i - j));
memset(ndst, 0, sizeof(ndst));
memset(rdst, 0, sizeof(rdst));
ref = convertSequences_noRepcodes_ref(rdst, nsrc + j, i - j);
ret = convertSequences_noRepcodes(ndst, nsrc + j, i - j);
CHECK_EQ(ret, ref);
CHECK_EQ(memcmp(rdst, ndst, sizeof(ndst)), 0);
DISPLAYLEVEL(3, "OK \n");
}
}
nsrc[7].matchLength = 1;
nsrc[7].litLength = 65536;
for (i = 8; i <= COUNTOF(nsrc); ++i) {
DISPLAYLEVEL(3, "test%3u : convertSequences_noRepcodes with %u inputs and "
"litLength overflow: ",
testNb++, (unsigned)i);
memset(ndst, 0, sizeof(ndst));
memset(rdst, 0, sizeof(rdst));
ref = convertSequences_noRepcodes_ref(rdst, nsrc, i);
ret = convertSequences_noRepcodes(ndst, nsrc, i);
CHECK_EQ(ret, ref);
CHECK_EQ(memcmp(rdst, ndst, sizeof(ndst)), 0);
DISPLAYLEVEL(3, "OK \n");
assert(COUNTOF(nsrc) > 8);
for (j = 4; j < 8; ++j) {
DISPLAYLEVEL(3, "test%3u : convertSequences_noRepcodes with %u inputs and "
"litLength overflow #%u: ",
testNb++, (unsigned)i, (unsigned)(i - j));
memset(ndst, 0, sizeof(ndst));
memset(rdst, 0, sizeof(rdst));
ref = convertSequences_noRepcodes_ref(rdst, nsrc + j, i - j);
ret = convertSequences_noRepcodes(ndst, nsrc + j, i - j);
CHECK_EQ(ret, ref);
CHECK_EQ(memcmp(rdst, ndst, sizeof(ndst)), 0);
DISPLAYLEVEL(3, "OK \n");
}
}
return testNb;
}
static unsigned test_get1BlockSummary(unsigned testNb)
{
static const ZSTD_Sequence nseqs[] = {
@@ -4085,6 +4209,8 @@ static int basicUnitTests(U32 const seed, double compressibility)
}
DISPLAYLEVEL(3, "OK \n");
testNb = test_convertSequences_noRepcodes(seed, testNb);
testNb = test_get1BlockSummary(testNb);
DISPLAYLEVEL(3, "test%3i : ZSTD_compressSequencesAndLiterals : ", testNb++);