/src/php-src/ext/standard/crc32.c
Line | Count | Source |
1 | | /* |
2 | | +----------------------------------------------------------------------+ |
3 | | | Copyright (c) The PHP Group | |
4 | | +----------------------------------------------------------------------+ |
5 | | | This source file is subject to version 3.01 of the PHP license, | |
6 | | | that is bundled with this package in the file LICENSE, and is | |
7 | | | available through the world-wide-web at the following url: | |
8 | | | http://www.php.net/license/3_01.txt | |
9 | | | If you did not receive a copy of the PHP license and are unable to | |
10 | | | obtain it through the world-wide-web, please send a note to | |
11 | | | license@php.net so we can mail you a copy immediately. | |
12 | | +----------------------------------------------------------------------+ |
13 | | | Author: Rasmus Lerdorf <rasmus@php.net> | |
14 | | +----------------------------------------------------------------------+ |
15 | | */ |
16 | | |
17 | | #include "php.h" |
18 | | #include "basic_functions.h" |
19 | | #include "crc32.h" |
20 | | |
21 | | #if HAVE_AARCH64_CRC32 |
22 | | # include <arm_acle.h> |
23 | | # if defined(__linux__) |
24 | | # include <sys/auxv.h> |
25 | | # include <asm/hwcap.h> |
26 | | # endif |
27 | | |
28 | | static inline int has_crc32_insn() { |
29 | | /* Only go through the runtime detection once. */ |
30 | | static int res = -1; |
31 | | if (res != -1) |
32 | | return res; |
33 | | # if defined(HWCAP_CRC32) |
34 | | res = getauxval(AT_HWCAP) & HWCAP_CRC32; |
35 | | return res; |
36 | | # elif defined(HWCAP2_CRC32) |
37 | | res = getauxval(AT_HWCAP2) & HWCAP2_CRC32; |
38 | | return res; |
39 | | # else |
40 | | res = 0; |
41 | | return res; |
42 | | # endif |
43 | | } |
44 | | |
45 | | # pragma GCC push_options |
46 | | # pragma GCC target ("+nothing+crc") |
47 | | static uint32_t crc32_aarch64(uint32_t crc, char *p, size_t nr) { |
48 | | while (nr >= sizeof(uint64_t)) { |
49 | | crc = __crc32d(crc, *(uint64_t *)p); |
50 | | p += sizeof(uint64_t); |
51 | | nr -= sizeof(uint64_t); |
52 | | } |
53 | | if (nr >= sizeof(int32_t)) { |
54 | | crc = __crc32w(crc, *(uint32_t *)p); |
55 | | p += sizeof(uint32_t); |
56 | | nr -= sizeof(uint32_t); |
57 | | } |
58 | | if (nr >= sizeof(int16_t)) { |
59 | | crc = __crc32h(crc, *(uint16_t *)p); |
60 | | p += sizeof(uint16_t); |
61 | | nr -= sizeof(uint16_t); |
62 | | } |
63 | | if (nr) { |
64 | | crc = __crc32b(crc, *p); |
65 | | } |
66 | | return crc; |
67 | | } |
68 | | # pragma GCC pop_options |
69 | | #endif |
70 | | |
71 | | /* {{{ Calculate the crc32 polynomial of a string */ |
72 | | PHP_FUNCTION(crc32) |
73 | 484 | { |
74 | 484 | char *p; |
75 | 484 | size_t nr; |
76 | 484 | uint32_t crcinit = 0; |
77 | 484 | register uint32_t crc; |
78 | | |
79 | 1.45k | ZEND_PARSE_PARAMETERS_START(1, 1) |
80 | 484 | Z_PARAM_STRING(p, nr) |
81 | 484 | ZEND_PARSE_PARAMETERS_END(); |
82 | | |
83 | 484 | crc = crcinit^0xFFFFFFFF; |
84 | | |
85 | | #if HAVE_AARCH64_CRC32 |
86 | | if (has_crc32_insn()) { |
87 | | crc = crc32_aarch64(crc, p, nr); |
88 | | RETURN_LONG(crc^0xFFFFFFFF); |
89 | | } |
90 | | #endif |
91 | | |
92 | 6.65k | for (; nr--; ++p) { |
93 | 6.17k | crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32tab[(crc ^ (*p)) & 0xFF ]; |
94 | 6.17k | } |
95 | 484 | RETURN_LONG(crc^0xFFFFFFFF); |
96 | 484 | } |
97 | | /* }}} */ |