github.com/segmentio/parquet-go@v0.0.0-20230712180008-5d42db8f0d47/encoding/delta/binary_packed_amd64.go (about) 1 //go:build !purego 2 3 package delta 4 5 import ( 6 "github.com/segmentio/parquet-go/internal/unsafecast" 7 "golang.org/x/sys/cpu" 8 ) 9 10 func init() { 11 if cpu.X86.HasAVX2 { 12 encodeInt32 = encodeInt32AVX2 13 encodeInt64 = encodeInt64AVX2 14 } 15 } 16 17 //go:noescape 18 func blockDeltaInt32AVX2(block *[blockSize]int32, lastValue int32) int32 19 20 //go:noescape 21 func blockMinInt32AVX2(block *[blockSize]int32) int32 22 23 //go:noescape 24 func blockSubInt32AVX2(block *[blockSize]int32, value int32) 25 26 //go:noescape 27 func blockBitWidthsInt32AVX2(bitWidths *[numMiniBlocks]byte, block *[blockSize]int32) 28 29 //go:noescape 30 func encodeMiniBlockInt32Default(dst *byte, src *[miniBlockSize]int32, bitWidth uint) 31 32 //go:noescape 33 func encodeMiniBlockInt32x1bitAVX2(dst *byte, src *[miniBlockSize]int32) 34 35 //go:noescape 36 func encodeMiniBlockInt32x2bitsAVX2(dst *byte, src *[miniBlockSize]int32) 37 38 //go:noescape 39 func encodeMiniBlockInt32x3to16bitsAVX2(dst *byte, src *[miniBlockSize]int32, bitWidth uint) 40 41 //go:noescape 42 func encodeMiniBlockInt32x32bitsAVX2(dst *byte, src *[miniBlockSize]int32) 43 44 func encodeMiniBlockInt32(dst []byte, src *[miniBlockSize]int32, bitWidth uint) { 45 encodeMiniBlockInt32Default(&dst[0], src, bitWidth) 46 } 47 48 func encodeMiniBlockInt32AVX2(dst *byte, src *[miniBlockSize]int32, bitWidth uint) { 49 switch { 50 case bitWidth == 1: 51 encodeMiniBlockInt32x1bitAVX2(dst, src) 52 case bitWidth == 2: 53 encodeMiniBlockInt32x2bitsAVX2(dst, src) 54 case bitWidth == 32: 55 encodeMiniBlockInt32x32bitsAVX2(dst, src) 56 case bitWidth <= 16: 57 encodeMiniBlockInt32x3to16bitsAVX2(dst, src, bitWidth) 58 default: 59 encodeMiniBlockInt32Default(dst, src, bitWidth) 60 } 61 } 62 63 func encodeInt32AVX2(dst []byte, src []int32) []byte { 64 totalValues := len(src) 65 firstValue := int32(0) 66 if totalValues > 0 { 67 firstValue = src[0] 68 } 69 70 n := len(dst) 71 dst = resize(dst, n+maxHeaderLength32) 72 dst = dst[:n+encodeBinaryPackedHeader(dst[n:], blockSize, numMiniBlocks, totalValues, int64(firstValue))] 73 74 if totalValues < 2 { 75 return dst 76 } 77 78 lastValue := firstValue 79 for i := 1; i < len(src); i += blockSize { 80 block := [blockSize]int32{} 81 blockLength := copy(block[:], src[i:]) 82 83 lastValue = blockDeltaInt32AVX2(&block, lastValue) 84 minDelta := blockMinInt32AVX2(&block) 85 blockSubInt32AVX2(&block, minDelta) 86 blockClearInt32(&block, blockLength) 87 88 bitWidths := [numMiniBlocks]byte{} 89 blockBitWidthsInt32AVX2(&bitWidths, &block) 90 91 n := len(dst) 92 dst = resize(dst, n+maxMiniBlockLength32+16) 93 n += encodeBlockHeader(dst[n:], int64(minDelta), bitWidths) 94 95 for i, bitWidth := range bitWidths { 96 if bitWidth != 0 { 97 miniBlock := (*[miniBlockSize]int32)(block[i*miniBlockSize:]) 98 encodeMiniBlockInt32AVX2(&dst[n], miniBlock, uint(bitWidth)) 99 n += (miniBlockSize * int(bitWidth)) / 8 100 } 101 } 102 103 dst = dst[:n] 104 } 105 106 return dst 107 } 108 109 //go:noescape 110 func blockDeltaInt64AVX2(block *[blockSize]int64, lastValue int64) int64 111 112 //go:noescape 113 func blockMinInt64AVX2(block *[blockSize]int64) int64 114 115 //go:noescape 116 func blockSubInt64AVX2(block *[blockSize]int64, value int64) 117 118 //go:noescape 119 func blockBitWidthsInt64AVX2(bitWidths *[numMiniBlocks]byte, block *[blockSize]int64) 120 121 //go:noescape 122 func encodeMiniBlockInt64Default(dst *byte, src *[miniBlockSize]int64, bitWidth uint) 123 124 //go:noescape 125 func encodeMiniBlockInt64x1bitAVX2(dst *byte, src *[miniBlockSize]int64) 126 127 //go:noescape 128 func encodeMiniBlockInt64x2bitsAVX2(dst *byte, src *[miniBlockSize]int64) 129 130 //go:noescape 131 func encodeMiniBlockInt64x64bitsAVX2(dst *byte, src *[miniBlockSize]int64) 132 133 func encodeMiniBlockInt64(dst []byte, src *[miniBlockSize]int64, bitWidth uint) { 134 encodeMiniBlockInt64Default(&dst[0], src, bitWidth) 135 } 136 137 func encodeMiniBlockInt64AVX2(dst *byte, src *[miniBlockSize]int64, bitWidth uint) { 138 switch { 139 case bitWidth == 1: 140 encodeMiniBlockInt64x1bitAVX2(dst, src) 141 case bitWidth == 2: 142 encodeMiniBlockInt64x2bitsAVX2(dst, src) 143 case bitWidth == 64: 144 encodeMiniBlockInt64x64bitsAVX2(dst, src) 145 default: 146 encodeMiniBlockInt64Default(dst, src, bitWidth) 147 } 148 } 149 150 func encodeInt64AVX2(dst []byte, src []int64) []byte { 151 totalValues := len(src) 152 firstValue := int64(0) 153 if totalValues > 0 { 154 firstValue = src[0] 155 } 156 157 n := len(dst) 158 dst = resize(dst, n+maxHeaderLength64) 159 dst = dst[:n+encodeBinaryPackedHeader(dst[n:], blockSize, numMiniBlocks, totalValues, int64(firstValue))] 160 161 if totalValues < 2 { 162 return dst 163 } 164 165 lastValue := firstValue 166 for i := 1; i < len(src); i += blockSize { 167 block := [blockSize]int64{} 168 blockLength := copy(block[:], src[i:]) 169 170 lastValue = blockDeltaInt64AVX2(&block, lastValue) 171 minDelta := blockMinInt64AVX2(&block) 172 blockSubInt64AVX2(&block, minDelta) 173 blockClearInt64(&block, blockLength) 174 175 bitWidths := [numMiniBlocks]byte{} 176 blockBitWidthsInt64AVX2(&bitWidths, &block) 177 178 n := len(dst) 179 dst = resize(dst, n+maxMiniBlockLength64+16) 180 n += encodeBlockHeader(dst[n:], int64(minDelta), bitWidths) 181 182 for i, bitWidth := range bitWidths { 183 if bitWidth != 0 { 184 miniBlock := (*[miniBlockSize]int64)(block[i*miniBlockSize:]) 185 encodeMiniBlockInt64AVX2(&dst[n], miniBlock, uint(bitWidth)) 186 n += (miniBlockSize * int(bitWidth)) / 8 187 } 188 } 189 190 dst = dst[:n] 191 } 192 193 return dst 194 } 195 196 //go:noescape 197 func decodeBlockInt32Default(dst []int32, minDelta, lastValue int32) int32 198 199 //go:noescape 200 func decodeBlockInt32AVX2(dst []int32, minDelta, lastValue int32) int32 201 202 func decodeBlockInt32(dst []int32, minDelta, lastValue int32) int32 { 203 switch { 204 case cpu.X86.HasAVX2: 205 return decodeBlockInt32AVX2(dst, minDelta, lastValue) 206 default: 207 return decodeBlockInt32Default(dst, minDelta, lastValue) 208 } 209 } 210 211 //go:noescape 212 func decodeMiniBlockInt32Default(dst []int32, src []uint32, bitWidth uint) 213 214 //go:noescape 215 func decodeMiniBlockInt32x1to16bitsAVX2(dst []int32, src []uint32, bitWidth uint) 216 217 //go:noescape 218 func decodeMiniBlockInt32x17to26bitsAVX2(dst []int32, src []uint32, bitWidth uint) 219 220 //go:noescape 221 func decodeMiniBlockInt32x27to31bitsAVX2(dst []int32, src []uint32, bitWidth uint) 222 223 func decodeMiniBlockInt32(dst []int32, src []uint32, bitWidth uint) { 224 hasAVX2 := cpu.X86.HasAVX2 225 switch { 226 case hasAVX2 && bitWidth <= 16: 227 decodeMiniBlockInt32x1to16bitsAVX2(dst, src, bitWidth) 228 case hasAVX2 && bitWidth <= 26: 229 decodeMiniBlockInt32x17to26bitsAVX2(dst, src, bitWidth) 230 case hasAVX2 && bitWidth <= 31: 231 decodeMiniBlockInt32x27to31bitsAVX2(dst, src, bitWidth) 232 case bitWidth == 32: 233 copy(dst, unsafecast.Uint32ToInt32(src)) 234 default: 235 decodeMiniBlockInt32Default(dst, src, bitWidth) 236 } 237 } 238 239 //go:noescape 240 func decodeBlockInt64Default(dst []int64, minDelta, lastValue int64) int64 241 242 func decodeBlockInt64(dst []int64, minDelta, lastValue int64) int64 { 243 return decodeBlockInt64Default(dst, minDelta, lastValue) 244 } 245 246 //go:noescape 247 func decodeMiniBlockInt64Default(dst []int64, src []uint32, bitWidth uint) 248 249 func decodeMiniBlockInt64(dst []int64, src []uint32, bitWidth uint) { 250 switch { 251 case bitWidth == 64: 252 copy(dst, unsafecast.Uint32ToInt64(src)) 253 default: 254 decodeMiniBlockInt64Default(dst, src, bitWidth) 255 } 256 }