/src/libtorrent/src/crc32c.cpp
Line | Count | Source |
1 | | /* |
2 | | |
3 | | Copyright (c) 2014-2020, Arvid Norberg |
4 | | Copyright (c) 2016, Alden Torres |
5 | | Copyright (c) 2018, Pavel Pimenov |
6 | | All rights reserved. |
7 | | |
8 | | Redistribution and use in source and binary forms, with or without |
9 | | modification, are permitted provided that the following conditions |
10 | | are met: |
11 | | |
12 | | * Redistributions of source code must retain the above copyright |
13 | | notice, this list of conditions and the following disclaimer. |
14 | | * Redistributions in binary form must reproduce the above copyright |
15 | | notice, this list of conditions and the following disclaimer in |
16 | | the documentation and/or other materials provided with the distribution. |
17 | | * Neither the name of the author nor the names of its |
18 | | contributors may be used to endorse or promote products derived |
19 | | from this software without specific prior written permission. |
20 | | |
21 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
22 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
23 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
24 | | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
25 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
26 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
27 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
28 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
29 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
30 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
31 | | POSSIBILITY OF SUCH DAMAGE. |
32 | | |
33 | | */ |
34 | | |
35 | | #include "libtorrent/config.hpp" |
36 | | #include "libtorrent/crc32c.hpp" |
37 | | #include "libtorrent/aux_/cpuid.hpp" |
38 | | #include "libtorrent/aux_/byteswap.hpp" |
39 | | #include "libtorrent/aux_/disable_warnings_push.hpp" |
40 | | |
41 | | #include <boost/crc.hpp> |
42 | | #if (defined _MSC_VER && _MSC_VER >= 1600 && (defined _M_IX86 || defined _M_X64)) |
43 | | #include <nmmintrin.h> |
44 | | #endif |
45 | | |
46 | | #include "libtorrent/aux_/disable_warnings_pop.hpp" |
47 | | |
48 | | #if TORRENT_HAS_ARM_CRC32 |
49 | | #include <arm_acle.h> |
50 | | #endif |
51 | | |
52 | | namespace libtorrent { |
53 | | |
54 | | std::uint32_t crc32c_32(std::uint32_t v) |
55 | 32 | { |
56 | 32 | #if TORRENT_HAS_SSE |
57 | 32 | if (aux::sse42_support) |
58 | 32 | { |
59 | 32 | std::uint32_t ret = 0xffffffff; |
60 | 32 | #ifdef __GNUC__ |
61 | | // we can't use these because then we'd have to tell |
62 | | // -msse4.2 to gcc on the command line |
63 | | // return __builtin_ia32_crc32si(ret, v) ^ 0xffffffff; |
64 | 32 | asm ("crc32l\t" "(%1), %0" |
65 | 32 | : "=r"(ret) |
66 | 32 | : "r"(&v), "0"(ret)); |
67 | 32 | return ret ^ 0xffffffff; |
68 | | #else |
69 | | return _mm_crc32_u32(ret, v) ^ 0xffffffff; |
70 | | #endif |
71 | 32 | } |
72 | 0 | #endif |
73 | | |
74 | | #if TORRENT_HAS_ARM_CRC32 |
75 | | if (aux::arm_crc32c_support) |
76 | | { |
77 | | std::uint32_t ret = 0xffffffff; |
78 | | return __crc32cw(ret, v) ^ 0xffffffff; |
79 | | } |
80 | | #endif |
81 | | |
82 | 0 | boost::crc_optimal<32, 0x1EDC6F41, 0xFFFFFFFF, 0xFFFFFFFF, true, true> crc; |
83 | 0 | crc.process_bytes(&v, 4); |
84 | 0 | return crc.checksum(); |
85 | 32 | } |
86 | | |
87 | | std::uint32_t crc32c(std::uint64_t const* buf, int num_words) |
88 | 0 | { |
89 | 0 | #if TORRENT_HAS_SSE |
90 | 0 | if (aux::sse42_support) |
91 | 0 | { |
92 | 0 | #if defined _M_AMD64 || defined __x86_64__ \ |
93 | 0 | || defined __x86_64 || defined _M_X64 || defined __amd64__ |
94 | 0 | std::uint64_t ret = 0xffffffff; |
95 | 0 | for (int i = 0; i < num_words; ++i) |
96 | 0 | { |
97 | 0 | #ifdef __GNUC__ |
98 | | // we can't use these because then we'd have to tell |
99 | | // -msse4.2 to gcc on the command line |
100 | | // ret = __builtin_ia32_crc32di(ret, buf[i]); |
101 | 0 | __asm__("crc32q\t" "(%1), %0" |
102 | 0 | : "=r"(ret) |
103 | 0 | : "r"(buf+i), "0"(ret)); |
104 | | #else |
105 | | ret = _mm_crc32_u64(ret, buf[i]); |
106 | | #endif |
107 | 0 | } |
108 | 0 | return std::uint32_t(ret) ^ 0xffffffff; |
109 | | #else |
110 | | std::uint32_t ret = 0xffffffff; |
111 | | std::uint32_t const* buf0 = reinterpret_cast<std::uint32_t const*>(buf); |
112 | | for (int i = 0; i < num_words; ++i) |
113 | | { |
114 | | #ifdef __GNUC__ |
115 | | // we can't use these because then we'd have to tell |
116 | | // -msse4.2 to gcc on the command line |
117 | | // ret = __builtin_ia32_crc32si(ret, buf0[i*2]); |
118 | | // ret = __builtin_ia32_crc32si(ret, buf0[i*2+1]); |
119 | | asm ("crc32l\t" "(%1), %0" |
120 | | : "=r"(ret) |
121 | | : "r"(buf0+i*2), "0"(ret)); |
122 | | asm ("crc32l\t" "(%1), %0" |
123 | | : "=r"(ret) |
124 | | : "r"(buf0+i*2+1), "0"(ret)); |
125 | | #else |
126 | | ret = _mm_crc32_u32(ret, buf0[i*2]); |
127 | | ret = _mm_crc32_u32(ret, buf0[i*2+1]); |
128 | | #endif |
129 | | } |
130 | | return ret ^ 0xffffffff; |
131 | | #endif // amd64 or x86 |
132 | 0 | } |
133 | 0 | #endif // x86 or amd64 and gcc or msvc |
134 | | |
135 | | #if TORRENT_HAS_ARM_CRC32 |
136 | | if (aux::arm_crc32c_support) |
137 | | { |
138 | | std::uint32_t ret = 0xffffffff; |
139 | | for (int i = 0; i < num_words; ++i) |
140 | | { |
141 | | ret = __crc32cd(ret, buf[i]); |
142 | | } |
143 | | return ret ^ 0xffffffff; |
144 | | } |
145 | | #endif |
146 | | |
147 | 0 | boost::crc_optimal<32, 0x1EDC6F41, 0xFFFFFFFF, 0xFFFFFFFF, true, true> crc; |
148 | 0 | crc.process_bytes(buf, std::size_t(num_words) * 8); |
149 | 0 | return crc.checksum(); |
150 | 0 | } |
151 | | } |