summaryrefslogtreecommitdiff
path: root/ext/standard/crc32.c
diff options
context:
space:
mode:
authorSebastian Pop <spop@amazon.com>2019-05-01 16:05:11 +0000
committerNikita Popov <nikita.ppv@gmail.com>2019-07-11 10:29:45 +0200
commit2a535a9707c89502df8bc0bd785f2e9192929422 (patch)
treed90b25d5feecb62b2fe8e4a59618357b7427068c /ext/standard/crc32.c
parentba8c4894d8b1316e986c01789b3dd0c25108c689 (diff)
downloadphp-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.c50
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 ];
}