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  }