github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/src/hash/crc32/crc32_amd64.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // AMD64-specific hardware-assisted CRC32 algorithms. See crc32.go for a 6 // description of the interface that each architecture-specific file 7 // implements. 8 9 package crc32 10 11 import "unsafe" 12 13 // This file contains the code to call the SSE 4.2 version of the Castagnoli 14 // and IEEE CRC. 15 16 // haveSSE41/haveSSE42/haveCLMUL are defined in crc_amd64.s and use 17 // CPUID to test for SSE 4.1, 4.2 and CLMUL support. 18 func haveSSE41() bool 19 func haveSSE42() bool 20 func haveCLMUL() bool 21 22 // castagnoliSSE42 is defined in crc32_amd64.s and uses the SSE4.2 CRC32 23 // instruction. 24 //go:noescape 25 func castagnoliSSE42(crc uint32, p []byte) uint32 26 27 // castagnoliSSE42Triple is defined in crc32_amd64.s and uses the SSE4.2 CRC32 28 // instruction. 29 //go:noescape 30 func castagnoliSSE42Triple( 31 crcA, crcB, crcC uint32, 32 a, b, c []byte, 33 rounds uint32, 34 ) (retA uint32, retB uint32, retC uint32) 35 36 // ieeeCLMUL is defined in crc_amd64.s and uses the PCLMULQDQ 37 // instruction as well as SSE 4.1. 38 //go:noescape 39 func ieeeCLMUL(crc uint32, p []byte) uint32 40 41 var sse42 = haveSSE42() 42 var useFastIEEE = haveCLMUL() && haveSSE41() 43 44 const castagnoliK1 = 168 45 const castagnoliK2 = 1344 46 47 type sse42Table [4]Table 48 49 var castagnoliSSE42TableK1 *sse42Table 50 var castagnoliSSE42TableK2 *sse42Table 51 52 func archAvailableCastagnoli() bool { 53 return sse42 54 } 55 56 func archInitCastagnoli() { 57 if !sse42 { 58 panic("arch-specific Castagnoli not available") 59 } 60 castagnoliSSE42TableK1 = new(sse42Table) 61 castagnoliSSE42TableK2 = new(sse42Table) 62 // See description in updateCastagnoli. 63 // t[0][i] = CRC(i000, O) 64 // t[1][i] = CRC(0i00, O) 65 // t[2][i] = CRC(00i0, O) 66 // t[3][i] = CRC(000i, O) 67 // where O is a sequence of K zeros. 68 var tmp [castagnoliK2]byte 69 for b := 0; b < 4; b++ { 70 for i := 0; i < 256; i++ { 71 val := uint32(i) << uint32(b*8) 72 castagnoliSSE42TableK1[b][i] = castagnoliSSE42(val, tmp[:castagnoliK1]) 73 castagnoliSSE42TableK2[b][i] = castagnoliSSE42(val, tmp[:]) 74 } 75 } 76 } 77 78 // castagnoliShift computes the CRC32-C of K1 or K2 zeroes (depending on the 79 // table given) with the given initial crc value. This corresponds to 80 // CRC(crc, O) in the description in updateCastagnoli. 81 func castagnoliShift(table *sse42Table, crc uint32) uint32 { 82 return table[3][crc>>24] ^ 83 table[2][(crc>>16)&0xFF] ^ 84 table[1][(crc>>8)&0xFF] ^ 85 table[0][crc&0xFF] 86 } 87 88 func archUpdateCastagnoli(crc uint32, p []byte) uint32 { 89 if !sse42 { 90 panic("not available") 91 } 92 93 // This method is inspired from the algorithm in Intel's white paper: 94 // "Fast CRC Computation for iSCSI Polynomial Using CRC32 Instruction" 95 // The same strategy of splitting the buffer in three is used but the 96 // combining calculation is different; the complete derivation is explained 97 // below. 98 // 99 // -- The basic idea -- 100 // 101 // The CRC32 instruction (available in SSE4.2) can process 8 bytes at a 102 // time. In recent Intel architectures the instruction takes 3 cycles; 103 // however the processor can pipeline up to three instructions if they 104 // don't depend on each other. 105 // 106 // Roughly this means that we can process three buffers in about the same 107 // time we can process one buffer. 108 // 109 // The idea is then to split the buffer in three, CRC the three pieces 110 // separately and then combine the results. 111 // 112 // Combining the results requires precomputed tables, so we must choose a 113 // fixed buffer length to optimize. The longer the length, the faster; but 114 // only buffers longer than this length will use the optimization. We choose 115 // two cutoffs and compute tables for both: 116 // - one around 512: 168*3=504 117 // - one around 4KB: 1344*3=4032 118 // 119 // -- The nitty gritty -- 120 // 121 // Let CRC(I, X) be the non-inverted CRC32-C of the sequence X (with 122 // initial non-inverted CRC I). This function has the following properties: 123 // (a) CRC(I, AB) = CRC(CRC(I, A), B) 124 // (b) CRC(I, A xor B) = CRC(I, A) xor CRC(0, B) 125 // 126 // Say we want to compute CRC(I, ABC) where A, B, C are three sequences of 127 // K bytes each, where K is a fixed constant. Let O be the sequence of K zero 128 // bytes. 129 // 130 // CRC(I, ABC) = CRC(I, ABO xor C) 131 // = CRC(I, ABO) xor CRC(0, C) 132 // = CRC(CRC(I, AB), O) xor CRC(0, C) 133 // = CRC(CRC(I, AO xor B), O) xor CRC(0, C) 134 // = CRC(CRC(I, AO) xor CRC(0, B), O) xor CRC(0, C) 135 // = CRC(CRC(CRC(I, A), O) xor CRC(0, B), O) xor CRC(0, C) 136 // 137 // The castagnoliSSE42Triple function can compute CRC(I, A), CRC(0, B), 138 // and CRC(0, C) efficiently. We just need to find a way to quickly compute 139 // CRC(uvwx, O) given a 4-byte initial value uvwx. We can precompute these 140 // values; since we can't have a 32-bit table, we break it up into four 141 // 8-bit tables: 142 // 143 // CRC(uvwx, O) = CRC(u000, O) xor 144 // CRC(0v00, O) xor 145 // CRC(00w0, O) xor 146 // CRC(000x, O) 147 // 148 // We can compute tables corresponding to the four terms for all 8-bit 149 // values. 150 151 crc = ^crc 152 153 // If a buffer is long enough to use the optimization, process the first few 154 // bytes to align the buffer to an 8 byte boundary (if necessary). 155 if len(p) >= castagnoliK1*3 { 156 delta := int(uintptr(unsafe.Pointer(&p[0])) & 7) 157 if delta != 0 { 158 delta = 8 - delta 159 crc = castagnoliSSE42(crc, p[:delta]) 160 p = p[delta:] 161 } 162 } 163 164 // Process 3*K2 at a time. 165 for len(p) >= castagnoliK2*3 { 166 // Compute CRC(I, A), CRC(0, B), and CRC(0, C). 167 crcA, crcB, crcC := castagnoliSSE42Triple( 168 crc, 0, 0, 169 p, p[castagnoliK2:], p[castagnoliK2*2:], 170 castagnoliK2/24) 171 172 // CRC(I, AB) = CRC(CRC(I, A), O) xor CRC(0, B) 173 crcAB := castagnoliShift(castagnoliSSE42TableK2, crcA) ^ crcB 174 // CRC(I, ABC) = CRC(CRC(I, AB), O) xor CRC(0, C) 175 crc = castagnoliShift(castagnoliSSE42TableK2, crcAB) ^ crcC 176 p = p[castagnoliK2*3:] 177 } 178 179 // Process 3*K1 at a time. 180 for len(p) >= castagnoliK1*3 { 181 // Compute CRC(I, A), CRC(0, B), and CRC(0, C). 182 crcA, crcB, crcC := castagnoliSSE42Triple( 183 crc, 0, 0, 184 p, p[castagnoliK1:], p[castagnoliK1*2:], 185 castagnoliK1/24) 186 187 // CRC(I, AB) = CRC(CRC(I, A), O) xor CRC(0, B) 188 crcAB := castagnoliShift(castagnoliSSE42TableK1, crcA) ^ crcB 189 // CRC(I, ABC) = CRC(CRC(I, AB), O) xor CRC(0, C) 190 crc = castagnoliShift(castagnoliSSE42TableK1, crcAB) ^ crcC 191 p = p[castagnoliK1*3:] 192 } 193 194 // Use the simple implementation for what's left. 195 crc = castagnoliSSE42(crc, p) 196 return ^crc 197 } 198 199 func archAvailableIEEE() bool { 200 return useFastIEEE 201 } 202 203 var archIeeeTable8 *slicing8Table 204 205 func archInitIEEE() { 206 if !useFastIEEE { 207 panic("not available") 208 } 209 // We still use slicing-by-8 for small buffers. 210 archIeeeTable8 = slicingMakeTable(IEEE) 211 } 212 213 func archUpdateIEEE(crc uint32, p []byte) uint32 { 214 if !useFastIEEE { 215 panic("not available") 216 } 217 218 if len(p) >= 64 { 219 left := len(p) & 15 220 do := len(p) - left 221 crc = ^ieeeCLMUL(^crc, p[:do]) 222 p = p[do:] 223 } 224 if len(p) == 0 { 225 return crc 226 } 227 return slicingUpdate(crc, archIeeeTable8, p) 228 }