diff options
author | Sebastian Pop <spop@amazon.com> | 2019-05-01 16:05:11 +0000 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2019-07-11 10:29:45 +0200 |
commit | 2a535a9707c89502df8bc0bd785f2e9192929422 (patch) | |
tree | d90b25d5feecb62b2fe8e4a59618357b7427068c /ext/standard/crc32.c | |
parent | ba8c4894d8b1316e986c01789b3dd0c25108c689 (diff) | |
download | php-git-2a535a9707c89502df8bc0bd785f2e9192929422.tar.gz |
[AArch64] Use crc32 instructions when available
The time goes from 0.838s down to 0.029s (a 28x speedup) on a Graviton A1
instance and the following benchmark:
function simple_crc32() {
$a = "foo";
for ($i = 0; $i < 10000; $i++) {
crc32($a);
$a .= "o".$i;
}
}
Diffstat (limited to 'ext/standard/crc32.c')
-rw-r--r-- | ext/standard/crc32.c | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/ext/standard/crc32.c b/ext/standard/crc32.c index fb6e85ab07..904ea25ff7 100644 --- a/ext/standard/crc32.c +++ b/ext/standard/crc32.c @@ -20,6 +20,32 @@ #include "basic_functions.h" #include "crc32.h" +#if defined(__aarch64__) +# pragma GCC target ("+nothing+crc") +# include <arm_acle.h> +# if defined(__linux__) +# include <sys/auxv.h> +# include <asm/hwcap.h> +# endif + +static inline int has_crc32_insn() { + /* Only go through the runtime detection once. */ + static int res = -1; + if (res != -1) + return res; +# if defined(HWCAP_CRC32) + res = getauxval(AT_HWCAP) & HWCAP_CRC32; + return res; +# elif defined(HWCAP2_CRC32) + res = getauxval(AT_HWCAP2) & HWCAP2_CRC32; + return res; +# else + res = 0; + return res; +# endif +} +#endif + /* {{{ proto string crc32(string str) Calculate the crc32 polynomial of a string */ PHP_NAMED_FUNCTION(php_if_crc32) @@ -35,6 +61,30 @@ PHP_NAMED_FUNCTION(php_if_crc32) crc = crcinit^0xFFFFFFFF; +#if defined(__aarch64__) + if (has_crc32_insn()) { + while(nr >= sizeof(uint64_t)) { + crc = __crc32d(crc, *(uint64_t *)p); + p += sizeof(uint64_t); + nr -= sizeof(uint64_t); + } + if (nr >= sizeof(int32_t)) { + crc = __crc32w(crc, *(uint32_t *)p); + p += sizeof(uint32_t); + nr -= sizeof(uint32_t); + } + if (nr >= sizeof(int16_t)) { + crc = __crc32h(crc, *(uint16_t *)p); + p += sizeof(uint16_t); + nr -= sizeof(uint16_t); + } + if (nr) { + crc = __crc32b(crc, *p); + p += sizeof(uint8_t); + nr -= sizeof(uint8_t); + } + } +#endif for (; nr--; ++p) { crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32tab[(crc ^ (*p)) & 0xFF ]; } |