]> granicus.if.org Git - php/commitdiff
[AArch64] Use crc32 instructions when available
authorSebastian Pop <spop@amazon.com>
Wed, 1 May 2019 16:05:11 +0000 (16:05 +0000)
committerNikita Popov <nikita.ppv@gmail.com>
Thu, 11 Jul 2019 08:29:45 +0000 (10:29 +0200)
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;
  }
}

ext/standard/crc32.c

index fb6e85ab071be9444ddd5ea1be171e93c8fe52f6..904ea25ff79487e2f73ea9a9e5d1d016076eaff2 100644 (file)
 #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 ];
        }