github.com/segmentio/parquet-go@v0.0.0-20230712180008-5d42db8f0d47/bloom/xxhash/sum64uint_amd64.s (about)

     1  //go:build !purego
     2  
     3  #include "textflag.h"
     4  
     5  /*
     6  The algorithms in this file are assembly versions of the Go functions in the
     7  sum64uint_default.go file.
     8  
     9  The implementations are mostly direct translations of the Go code to assembly,
    10  leveraging SIMD instructions to process chunks of the input variables in
    11  parallel at each loop iteration. To maximize utilization of the CPU capacity,
    12  some of the functions unroll two steps of the vectorized loop per iteration,
    13  which yields further throughput because the CPU is able to process some of the
    14  instruction from the two steps in parallel due to having no data dependencies
    15  between the inputs and outputs.
    16  
    17  The use of AVX-512 yields a significant increase in throughput on all the
    18  algorithms, in most part thanks to the VPMULLQ instructions which compute
    19  8 x 64 bits multiplication. There were no equivalent instruction in AVX2, which
    20  required emulating vector multiplication with a combination of 32 bits multiply,
    21  additions, shifts, and masks: the amount of instructions and data dependencies
    22  resulted in the AVX2 code yielding equivalent performance characteristics for a
    23  much higher complexity.
    24  
    25  The benchmark results below showcase the improvements that the AVX-512 code
    26  yields on the XXH64 algorithms:
    27  
    28  name                   old speed      new speed       delta
    29  MultiSum64Uint8/4KB    4.97GB/s ± 0%  14.59GB/s ± 1%  +193.73%  (p=0.000 n=10+10)
    30  MultiSum64Uint16/4KB   3.55GB/s ± 0%   9.46GB/s ± 0%  +166.20%  (p=0.000 n=10+9)
    31  MultiSum64Uint32/4KB   4.48GB/s ± 0%  13.93GB/s ± 1%  +210.93%  (p=0.000 n=10+10)
    32  MultiSum64Uint64/4KB   3.57GB/s ± 0%  11.12GB/s ± 1%  +211.73%  (p=0.000 n=9+10)
    33  MultiSum64Uint128/4KB  2.54GB/s ± 0%   6.49GB/s ± 1%  +155.69%  (p=0.000 n=10+10)
    34  
    35  name                   old hash/s     new hash/s      delta
    36  MultiSum64Uint8/4KB        621M ± 0%      1823M ± 1%  +193.73%  (p=0.000 n=10+10)
    37  MultiSum64Uint16/4KB       444M ± 0%      1182M ± 0%  +166.20%  (p=0.000 n=10+9)
    38  MultiSum64Uint32/4KB       560M ± 0%      1742M ± 1%  +210.93%  (p=0.000 n=10+10)
    39  MultiSum64Uint64/4KB       446M ± 0%      1391M ± 1%  +211.73%  (p=0.000 n=9+10)
    40  MultiSum64Uint128/4KB      317M ± 0%       811M ± 1%  +155.69%  (p=0.000 n=10+10)
    41  
    42  The functions perform runtime detection of AVX-512 support by testing the value
    43  of the xxhash.hasAVX512 variable declared and initialized in sum64uint_amd64.go.
    44  Branch mispredictions on those tests are very unlikely since the value is never
    45  modified by the application. The cost of the comparisons are also amortized by
    46  the bulk APIs of the MultiSum64* functions (a single test is required per call).
    47  
    48  If a bug is suspected in the vectorized code, compiling the program or running
    49  the tests with -tags=purego can help verify whether the behavior changes when
    50  the program does not use the assembly versions.
    51  
    52  Maintenance of these functions can be complex; however, the XXH64 algorithm is
    53  unlikely to evolve, and the implementations unlikely to change. The tests in
    54  sum64uint_test.go compare the outputs of MultiSum64* functions with the
    55  reference xxhash.Sum64 function, future maintainers can rely on those tests
    56  passing as a guarantee that they have not introduced regressions.
    57  */
    58  
    59  #define PRIME1 0x9E3779B185EBCA87
    60  #define PRIME2 0xC2B2AE3D27D4EB4F
    61  #define PRIME3 0x165667B19E3779F9
    62  #define PRIME4 0x85EBCA77C2B2AE63
    63  #define PRIME5 0x27D4EB2F165667C5
    64  
    65  #define prime1 R12
    66  #define prime2 R13
    67  #define prime3 R14
    68  #define prime4 R15
    69  #define prime5 R15 // same as prime4 because they are not used together
    70  
    71  #define prime1ZMM Z12
    72  #define prime2ZMM Z13
    73  #define prime3ZMM Z14
    74  #define prime4ZMM Z15
    75  #define prime5ZMM Z15
    76  
    77  DATA prime1vec<>+0(SB)/8, $PRIME1
    78  DATA prime1vec<>+8(SB)/8, $PRIME1
    79  DATA prime1vec<>+16(SB)/8, $PRIME1
    80  DATA prime1vec<>+24(SB)/8, $PRIME1
    81  DATA prime1vec<>+32(SB)/8, $PRIME1
    82  DATA prime1vec<>+40(SB)/8, $PRIME1
    83  DATA prime1vec<>+48(SB)/8, $PRIME1
    84  DATA prime1vec<>+56(SB)/8, $PRIME1
    85  GLOBL prime1vec<>(SB), RODATA|NOPTR, $64
    86  
    87  DATA prime2vec<>+0(SB)/8, $PRIME2
    88  DATA prime2vec<>+8(SB)/8, $PRIME2
    89  DATA prime2vec<>+16(SB)/8, $PRIME2
    90  DATA prime2vec<>+24(SB)/8, $PRIME2
    91  DATA prime2vec<>+32(SB)/8, $PRIME2
    92  DATA prime2vec<>+40(SB)/8, $PRIME2
    93  DATA prime2vec<>+48(SB)/8, $PRIME2
    94  DATA prime2vec<>+56(SB)/8, $PRIME2
    95  GLOBL prime2vec<>(SB), RODATA|NOPTR, $64
    96  
    97  DATA prime3vec<>+0(SB)/8, $PRIME3
    98  DATA prime3vec<>+8(SB)/8, $PRIME3
    99  DATA prime3vec<>+16(SB)/8, $PRIME3
   100  DATA prime3vec<>+24(SB)/8, $PRIME3
   101  DATA prime3vec<>+32(SB)/8, $PRIME3
   102  DATA prime3vec<>+40(SB)/8, $PRIME3
   103  DATA prime3vec<>+48(SB)/8, $PRIME3
   104  DATA prime3vec<>+56(SB)/8, $PRIME3
   105  GLOBL prime3vec<>(SB), RODATA|NOPTR, $64
   106  
   107  DATA prime4vec<>+0(SB)/8, $PRIME4
   108  DATA prime4vec<>+8(SB)/8, $PRIME4
   109  DATA prime4vec<>+16(SB)/8, $PRIME4
   110  DATA prime4vec<>+24(SB)/8, $PRIME4
   111  DATA prime4vec<>+32(SB)/8, $PRIME4
   112  DATA prime4vec<>+40(SB)/8, $PRIME4
   113  DATA prime4vec<>+48(SB)/8, $PRIME4
   114  DATA prime4vec<>+56(SB)/8, $PRIME4
   115  GLOBL prime4vec<>(SB), RODATA|NOPTR, $64
   116  
   117  DATA prime5vec<>+0(SB)/8, $PRIME5
   118  DATA prime5vec<>+8(SB)/8, $PRIME5
   119  DATA prime5vec<>+16(SB)/8, $PRIME5
   120  DATA prime5vec<>+24(SB)/8, $PRIME5
   121  DATA prime5vec<>+32(SB)/8, $PRIME5
   122  DATA prime5vec<>+40(SB)/8, $PRIME5
   123  DATA prime5vec<>+48(SB)/8, $PRIME5
   124  DATA prime5vec<>+56(SB)/8, $PRIME5
   125  GLOBL prime5vec<>(SB), RODATA|NOPTR, $64
   126  
   127  DATA prime5vec1<>+0(SB)/8, $PRIME5+1
   128  DATA prime5vec1<>+8(SB)/8, $PRIME5+1
   129  DATA prime5vec1<>+16(SB)/8, $PRIME5+1
   130  DATA prime5vec1<>+24(SB)/8, $PRIME5+1
   131  DATA prime5vec1<>+32(SB)/8, $PRIME5+1
   132  DATA prime5vec1<>+40(SB)/8, $PRIME5+1
   133  DATA prime5vec1<>+48(SB)/8, $PRIME5+1
   134  DATA prime5vec1<>+56(SB)/8, $PRIME5+1
   135  GLOBL prime5vec1<>(SB), RODATA|NOPTR, $64
   136  
   137  DATA prime5vec2<>+0(SB)/8, $PRIME5+2
   138  DATA prime5vec2<>+8(SB)/8, $PRIME5+2
   139  DATA prime5vec2<>+16(SB)/8, $PRIME5+2
   140  DATA prime5vec2<>+24(SB)/8, $PRIME5+2
   141  DATA prime5vec2<>+32(SB)/8, $PRIME5+2
   142  DATA prime5vec2<>+40(SB)/8, $PRIME5+2
   143  DATA prime5vec2<>+48(SB)/8, $PRIME5+2
   144  DATA prime5vec2<>+56(SB)/8, $PRIME5+2
   145  GLOBL prime5vec2<>(SB), RODATA|NOPTR, $64
   146  
   147  DATA prime5vec4<>+0(SB)/8, $PRIME5+4
   148  DATA prime5vec4<>+8(SB)/8, $PRIME5+4
   149  DATA prime5vec4<>+16(SB)/8, $PRIME5+4
   150  DATA prime5vec4<>+24(SB)/8, $PRIME5+4
   151  DATA prime5vec4<>+32(SB)/8, $PRIME5+4
   152  DATA prime5vec4<>+40(SB)/8, $PRIME5+4
   153  DATA prime5vec4<>+48(SB)/8, $PRIME5+4
   154  DATA prime5vec4<>+56(SB)/8, $PRIME5+4
   155  GLOBL prime5vec4<>(SB), RODATA|NOPTR, $64
   156  
   157  DATA prime5vec8<>+0(SB)/8, $PRIME5+8
   158  DATA prime5vec8<>+8(SB)/8, $PRIME5+8
   159  DATA prime5vec8<>+16(SB)/8, $PRIME5+8
   160  DATA prime5vec8<>+24(SB)/8, $PRIME5+8
   161  DATA prime5vec8<>+32(SB)/8, $PRIME5+8
   162  DATA prime5vec8<>+40(SB)/8, $PRIME5+8
   163  DATA prime5vec8<>+48(SB)/8, $PRIME5+8
   164  DATA prime5vec8<>+56(SB)/8, $PRIME5+8
   165  GLOBL prime5vec8<>(SB), RODATA|NOPTR, $64
   166  
   167  DATA prime5vec16<>+0(SB)/8, $PRIME5+16
   168  DATA prime5vec16<>+8(SB)/8, $PRIME5+16
   169  DATA prime5vec16<>+16(SB)/8, $PRIME5+16
   170  DATA prime5vec16<>+24(SB)/8, $PRIME5+16
   171  DATA prime5vec16<>+32(SB)/8, $PRIME5+16
   172  DATA prime5vec16<>+40(SB)/8, $PRIME5+16
   173  DATA prime5vec16<>+48(SB)/8, $PRIME5+16
   174  DATA prime5vec16<>+56(SB)/8, $PRIME5+16
   175  GLOBL prime5vec16<>(SB), RODATA|NOPTR, $64
   176  
   177  DATA lowbytemask<>+0(SB)/8, $0xFF
   178  DATA lowbytemask<>+8(SB)/8, $0xFF
   179  DATA lowbytemask<>+16(SB)/8, $0xFF
   180  DATA lowbytemask<>+24(SB)/8, $0xFF
   181  DATA lowbytemask<>+32(SB)/8, $0xFF
   182  DATA lowbytemask<>+40(SB)/8, $0xFF
   183  DATA lowbytemask<>+48(SB)/8, $0xFF
   184  DATA lowbytemask<>+56(SB)/8, $0xFF
   185  GLOBL lowbytemask<>(SB), RODATA|NOPTR, $64
   186  
   187  DATA vpermi2qeven<>+0(SB)/8, $0
   188  DATA vpermi2qeven<>+8(SB)/8, $2
   189  DATA vpermi2qeven<>+16(SB)/8, $4
   190  DATA vpermi2qeven<>+24(SB)/8, $6
   191  DATA vpermi2qeven<>+32(SB)/8, $(1<<3)|0
   192  DATA vpermi2qeven<>+40(SB)/8, $(1<<3)|2
   193  DATA vpermi2qeven<>+48(SB)/8, $(1<<3)|4
   194  DATA vpermi2qeven<>+56(SB)/8, $(1<<3)|6
   195  GLOBL vpermi2qeven<>(SB), RODATA|NOPTR, $64
   196  
   197  DATA vpermi2qodd<>+0(SB)/8, $1
   198  DATA vpermi2qodd<>+8(SB)/8, $3
   199  DATA vpermi2qodd<>+16(SB)/8, $5
   200  DATA vpermi2qodd<>+24(SB)/8, $7
   201  DATA vpermi2qodd<>+32(SB)/8, $(1<<3)|1
   202  DATA vpermi2qodd<>+40(SB)/8, $(1<<3)|3
   203  DATA vpermi2qodd<>+48(SB)/8, $(1<<3)|5
   204  DATA vpermi2qodd<>+56(SB)/8, $(1<<3)|7
   205  GLOBL vpermi2qodd<>(SB), RODATA|NOPTR, $64
   206  
   207  #define round(input, acc) \
   208  	IMULQ prime2, input \
   209  	ADDQ  input, acc \
   210  	ROLQ  $31, acc \
   211  	IMULQ prime1, acc
   212  
   213  #define avalanche(tmp, acc) \
   214      MOVQ acc, tmp \
   215      SHRQ $33, tmp \
   216      XORQ tmp, acc \
   217      IMULQ prime2, acc \
   218      MOVQ acc, tmp \
   219      SHRQ $29, tmp \
   220      XORQ tmp, acc \
   221      IMULQ prime3, acc \
   222      MOVQ acc, tmp \
   223      SHRQ $32, tmp \
   224      XORQ tmp, acc
   225  
   226  #define round8x64(input, acc) \
   227      VPMULLQ prime2ZMM, input, input \
   228      VPADDQ input, acc, acc \
   229      VPROLQ $31, acc, acc \
   230      VPMULLQ prime1ZMM, acc, acc
   231  
   232  #define avalanche8x64(tmp, acc) \
   233      VPSRLQ $33, acc, tmp \
   234      VPXORQ tmp, acc, acc \
   235      VPMULLQ prime2ZMM, acc, acc \
   236      VPSRLQ $29, acc, tmp \
   237      VPXORQ tmp, acc, acc \
   238      VPMULLQ prime3ZMM, acc, acc \
   239      VPSRLQ $32, acc, tmp \
   240      VPXORQ tmp, acc, acc
   241  
   242  // func MultiSum64Uint8(h []uint64, v []uint8) int
   243  TEXT ·MultiSum64Uint8(SB), NOSPLIT, $0-54
   244      MOVQ $PRIME1, prime1
   245      MOVQ $PRIME2, prime2
   246      MOVQ $PRIME3, prime3
   247      MOVQ $PRIME5, prime5
   248  
   249      MOVQ h_base+0(FP), AX
   250      MOVQ h_len+8(FP), CX
   251      MOVQ v_base+24(FP), BX
   252      MOVQ v_len+32(FP), DX
   253  
   254      CMPQ CX, DX
   255      CMOVQGT DX, CX
   256      MOVQ CX, ret+48(FP)
   257  
   258      XORQ SI, SI
   259      CMPQ CX, $32
   260      JB loop
   261      CMPB ·hasAVX512(SB), $0
   262      JE loop
   263  
   264      MOVQ CX, DI
   265      SHRQ $5, DI
   266      SHLQ $5, DI
   267  
   268      VMOVDQU64 prime1vec<>(SB), prime1ZMM
   269      VMOVDQU64 prime2vec<>(SB), prime2ZMM
   270      VMOVDQU64 prime3vec<>(SB), prime3ZMM
   271      VMOVDQU64 prime5vec<>(SB), prime5ZMM
   272      VMOVDQU64 prime5vec1<>(SB), Z6
   273  loop32x64:
   274      VMOVDQA64 Z6, Z0
   275      VMOVDQA64 Z6, Z3
   276      VMOVDQA64 Z6, Z20
   277      VMOVDQA64 Z6, Z23
   278      VPMOVZXBQ (BX)(SI*1), Z1
   279      VPMOVZXBQ 8(BX)(SI*1), Z4
   280      VPMOVZXBQ 16(BX)(SI*1), Z21
   281      VPMOVZXBQ 24(BX)(SI*1), Z24
   282  
   283      VPMULLQ prime5ZMM, Z1, Z1
   284      VPMULLQ prime5ZMM, Z4, Z4
   285      VPMULLQ prime5ZMM, Z21, Z21
   286      VPMULLQ prime5ZMM, Z24, Z24
   287      VPXORQ Z1, Z0, Z0
   288      VPXORQ Z4, Z3, Z3
   289      VPXORQ Z21, Z20, Z20
   290      VPXORQ Z24, Z23, Z23
   291      VPROLQ $11, Z0, Z0
   292      VPROLQ $11, Z3, Z3
   293      VPROLQ $11, Z20, Z20
   294      VPROLQ $11, Z23, Z23
   295      VPMULLQ prime1ZMM, Z0, Z0
   296      VPMULLQ prime1ZMM, Z3, Z3
   297      VPMULLQ prime1ZMM, Z20, Z20
   298      VPMULLQ prime1ZMM, Z23, Z23
   299  
   300      avalanche8x64(Z1, Z0)
   301      avalanche8x64(Z4, Z3)
   302      avalanche8x64(Z21, Z20)
   303      avalanche8x64(Z24, Z23)
   304  
   305      VMOVDQU64 Z0, (AX)(SI*8)
   306      VMOVDQU64 Z3, 64(AX)(SI*8)
   307      VMOVDQU64 Z20, 128(AX)(SI*8)
   308      VMOVDQU64 Z23, 192(AX)(SI*8)
   309      ADDQ $32, SI
   310      CMPQ SI, DI
   311      JB loop32x64
   312      VZEROUPPER
   313  loop:
   314      CMPQ SI, CX
   315      JE done
   316      MOVQ $PRIME5+1, R8
   317      MOVBQZX (BX)(SI*1), R9
   318  
   319      IMULQ prime5, R9
   320      XORQ R9, R8
   321      ROLQ $11, R8
   322      IMULQ prime1, R8
   323      avalanche(R9, R8)
   324  
   325      MOVQ R8, (AX)(SI*8)
   326      INCQ SI
   327      JMP loop
   328  done:
   329      RET
   330  
   331  // func MultiSum64Uint16(h []uint64, v []uint16) int
   332  TEXT ·MultiSum64Uint16(SB), NOSPLIT, $0-54
   333      MOVQ $PRIME1, prime1
   334      MOVQ $PRIME2, prime2
   335      MOVQ $PRIME3, prime3
   336      MOVQ $PRIME5, prime5
   337  
   338      MOVQ h_base+0(FP), AX
   339      MOVQ h_len+8(FP), CX
   340      MOVQ v_base+24(FP), BX
   341      MOVQ v_len+32(FP), DX
   342  
   343      CMPQ CX, DX
   344      CMOVQGT DX, CX
   345      MOVQ CX, ret+48(FP)
   346  
   347      XORQ SI, SI
   348      CMPQ CX, $16
   349      JB loop
   350      CMPB ·hasAVX512(SB), $0
   351      JE loop
   352  
   353      MOVQ CX, DI
   354      SHRQ $4, DI
   355      SHLQ $4, DI
   356  
   357      VMOVDQU64 prime1vec<>(SB), prime1ZMM
   358      VMOVDQU64 prime2vec<>(SB), prime2ZMM
   359      VMOVDQU64 prime3vec<>(SB), prime3ZMM
   360      VMOVDQU64 prime5vec<>(SB), prime5ZMM
   361      VMOVDQU64 prime5vec2<>(SB), Z6
   362      VMOVDQU64 lowbytemask<>(SB), Z7
   363  loop16x64:
   364      VMOVDQA64 Z6, Z0
   365      VMOVDQA64 Z6, Z3
   366      VPMOVZXWQ (BX)(SI*2), Z1
   367      VPMOVZXWQ 16(BX)(SI*2), Z4
   368  
   369      VMOVDQA64 Z1, Z8
   370      VMOVDQA64 Z4, Z9
   371      VPSRLQ $8, Z8, Z8
   372      VPSRLQ $8, Z9, Z9
   373      VPANDQ Z7, Z1, Z1
   374      VPANDQ Z7, Z4, Z4
   375  
   376      VPMULLQ prime5ZMM, Z1, Z1
   377      VPMULLQ prime5ZMM, Z4, Z4
   378      VPXORQ Z1, Z0, Z0
   379      VPXORQ Z4, Z3, Z3
   380      VPROLQ $11, Z0, Z0
   381      VPROLQ $11, Z3, Z3
   382      VPMULLQ prime1ZMM, Z0, Z0
   383      VPMULLQ prime1ZMM, Z3, Z3
   384  
   385      VPMULLQ prime5ZMM, Z8, Z8
   386      VPMULLQ prime5ZMM, Z9, Z9
   387      VPXORQ Z8, Z0, Z0
   388      VPXORQ Z9, Z3, Z3
   389      VPROLQ $11, Z0, Z0
   390      VPROLQ $11, Z3, Z3
   391      VPMULLQ prime1ZMM, Z0, Z0
   392      VPMULLQ prime1ZMM, Z3, Z3
   393  
   394      avalanche8x64(Z1, Z0)
   395      avalanche8x64(Z4, Z3)
   396  
   397      VMOVDQU64 Z0, (AX)(SI*8)
   398      VMOVDQU64 Z3, 64(AX)(SI*8)
   399      ADDQ $16, SI
   400      CMPQ SI, DI
   401      JB loop16x64
   402      VZEROUPPER
   403  loop:
   404      CMPQ SI, CX
   405      JE done
   406      MOVQ $PRIME5+2, R8
   407      MOVWQZX (BX)(SI*2), R9
   408  
   409      MOVQ R9, R10
   410      SHRQ $8, R10
   411      ANDQ $0xFF, R9
   412  
   413      IMULQ prime5, R9
   414      XORQ R9, R8
   415      ROLQ $11, R8
   416      IMULQ prime1, R8
   417  
   418      IMULQ prime5, R10
   419      XORQ R10, R8
   420      ROLQ $11, R8
   421      IMULQ prime1, R8
   422  
   423      avalanche(R9, R8)
   424  
   425      MOVQ R8, (AX)(SI*8)
   426      INCQ SI
   427      JMP loop
   428  done:
   429      RET
   430  
   431  // func MultiSum64Uint32(h []uint64, v []uint32) int
   432  TEXT ·MultiSum64Uint32(SB), NOSPLIT, $0-54
   433      MOVQ $PRIME1, prime1
   434      MOVQ $PRIME2, prime2
   435      MOVQ $PRIME3, prime3
   436  
   437      MOVQ h_base+0(FP), AX
   438      MOVQ h_len+8(FP), CX
   439      MOVQ v_base+24(FP), BX
   440      MOVQ v_len+32(FP), DX
   441  
   442      CMPQ CX, DX
   443      CMOVQGT DX, CX
   444      MOVQ CX, ret+48(FP)
   445  
   446      XORQ SI, SI
   447      CMPQ CX, $32
   448      JB loop
   449      CMPB ·hasAVX512(SB), $0
   450      JE loop
   451  
   452      MOVQ CX, DI
   453      SHRQ $5, DI
   454      SHLQ $5, DI
   455  
   456      VMOVDQU64 prime1vec<>(SB), prime1ZMM
   457      VMOVDQU64 prime2vec<>(SB), prime2ZMM
   458      VMOVDQU64 prime3vec<>(SB), prime3ZMM
   459      VMOVDQU64 prime5vec4<>(SB), Z6
   460  loop32x64:
   461      VMOVDQA64 Z6, Z0
   462      VMOVDQA64 Z6, Z3
   463      VMOVDQA64 Z6, Z20
   464      VMOVDQA64 Z6, Z23
   465      VPMOVZXDQ (BX)(SI*4), Z1
   466      VPMOVZXDQ 32(BX)(SI*4), Z4
   467      VPMOVZXDQ 64(BX)(SI*4), Z21
   468      VPMOVZXDQ 96(BX)(SI*4), Z24
   469  
   470      VPMULLQ prime1ZMM, Z1, Z1
   471      VPMULLQ prime1ZMM, Z4, Z4
   472      VPMULLQ prime1ZMM, Z21, Z21
   473      VPMULLQ prime1ZMM, Z24, Z24
   474      VPXORQ Z1, Z0, Z0
   475      VPXORQ Z4, Z3, Z3
   476      VPXORQ Z21, Z20, Z20
   477      VPXORQ Z24, Z23, Z23
   478      VPROLQ $23, Z0, Z0
   479      VPROLQ $23, Z3, Z3
   480      VPROLQ $23, Z20, Z20
   481      VPROLQ $23, Z23, Z23
   482      VPMULLQ prime2ZMM, Z0, Z0
   483      VPMULLQ prime2ZMM, Z3, Z3
   484      VPMULLQ prime2ZMM, Z20, Z20
   485      VPMULLQ prime2ZMM, Z23, Z23
   486      VPADDQ prime3ZMM, Z0, Z0
   487      VPADDQ prime3ZMM, Z3, Z3
   488      VPADDQ prime3ZMM, Z20, Z20
   489      VPADDQ prime3ZMM, Z23, Z23
   490  
   491      avalanche8x64(Z1, Z0)
   492      avalanche8x64(Z4, Z3)
   493      avalanche8x64(Z21, Z20)
   494      avalanche8x64(Z24, Z23)
   495  
   496      VMOVDQU64 Z0, (AX)(SI*8)
   497      VMOVDQU64 Z3, 64(AX)(SI*8)
   498      VMOVDQU64 Z20, 128(AX)(SI*8)
   499      VMOVDQU64 Z23, 192(AX)(SI*8)
   500      ADDQ $32, SI
   501      CMPQ SI, DI
   502      JB loop32x64
   503      VZEROUPPER
   504  loop:
   505      CMPQ SI, CX
   506      JE done
   507      MOVQ $PRIME5+4, R8
   508      MOVLQZX (BX)(SI*4), R9
   509  
   510      IMULQ prime1, R9
   511      XORQ R9, R8
   512      ROLQ $23, R8
   513      IMULQ prime2, R8
   514      ADDQ prime3, R8
   515      avalanche(R9, R8)
   516  
   517      MOVQ R8, (AX)(SI*8)
   518      INCQ SI
   519      JMP loop
   520  done:
   521      RET
   522  
   523  // func MultiSum64Uint64(h []uint64, v []uint64) int
   524  TEXT ·MultiSum64Uint64(SB), NOSPLIT, $0-54
   525      MOVQ $PRIME1, prime1
   526      MOVQ $PRIME2, prime2
   527      MOVQ $PRIME3, prime3
   528      MOVQ $PRIME4, prime4
   529  
   530      MOVQ h_base+0(FP), AX
   531      MOVQ h_len+8(FP), CX
   532      MOVQ v_base+24(FP), BX
   533      MOVQ v_len+32(FP), DX
   534  
   535      CMPQ CX, DX
   536      CMOVQGT DX, CX
   537      MOVQ CX, ret+48(FP)
   538  
   539      XORQ SI, SI
   540      CMPQ CX, $32
   541      JB loop
   542      CMPB ·hasAVX512(SB), $0
   543      JE loop
   544  
   545      MOVQ CX, DI
   546      SHRQ $5, DI
   547      SHLQ $5, DI
   548  
   549      VMOVDQU64 prime1vec<>(SB), prime1ZMM
   550      VMOVDQU64 prime2vec<>(SB), prime2ZMM
   551      VMOVDQU64 prime3vec<>(SB), prime3ZMM
   552      VMOVDQU64 prime4vec<>(SB), prime4ZMM
   553      VMOVDQU64 prime5vec8<>(SB), Z6
   554  loop32x64:
   555      VMOVDQA64 Z6, Z0
   556      VMOVDQA64 Z6, Z3
   557      VMOVDQA64 Z6, Z20
   558      VMOVDQA64 Z6, Z23
   559      VMOVDQU64 (BX)(SI*8), Z1
   560      VMOVDQU64 64(BX)(SI*8), Z4
   561      VMOVDQU64 128(BX)(SI*8), Z21
   562      VMOVDQU64 192(BX)(SI*8), Z24
   563  
   564      VPXORQ Z2, Z2, Z2
   565      VPXORQ Z5, Z5, Z5
   566      VPXORQ Z22, Z22, Z22
   567      VPXORQ Z25, Z25, Z25
   568      round8x64(Z1, Z2)
   569      round8x64(Z4, Z5)
   570      round8x64(Z21, Z22)
   571      round8x64(Z24, Z25)
   572  
   573      VPXORQ Z2, Z0, Z0
   574      VPXORQ Z5, Z3, Z3
   575      VPXORQ Z22, Z20, Z20
   576      VPXORQ Z25, Z23, Z23
   577      VPROLQ $27, Z0, Z0
   578      VPROLQ $27, Z3, Z3
   579      VPROLQ $27, Z20, Z20
   580      VPROLQ $27, Z23, Z23
   581      VPMULLQ prime1ZMM, Z0, Z0
   582      VPMULLQ prime1ZMM, Z3, Z3
   583      VPMULLQ prime1ZMM, Z20, Z20
   584      VPMULLQ prime1ZMM, Z23, Z23
   585      VPADDQ prime4ZMM, Z0, Z0
   586      VPADDQ prime4ZMM, Z3, Z3
   587      VPADDQ prime4ZMM, Z20, Z20
   588      VPADDQ prime4ZMM, Z23, Z23
   589  
   590      avalanche8x64(Z1, Z0)
   591      avalanche8x64(Z4, Z3)
   592      avalanche8x64(Z21, Z20)
   593      avalanche8x64(Z24, Z23)
   594  
   595      VMOVDQU64 Z0, (AX)(SI*8)
   596      VMOVDQU64 Z3, 64(AX)(SI*8)
   597      VMOVDQU64 Z20, 128(AX)(SI*8)
   598      VMOVDQU64 Z23, 192(AX)(SI*8)
   599      ADDQ $32, SI
   600      CMPQ SI, DI
   601      JB loop32x64
   602      VZEROUPPER
   603  loop:
   604      CMPQ SI, CX
   605      JE done
   606      MOVQ $PRIME5+8, R8
   607      MOVQ (BX)(SI*8), R9
   608  
   609      XORQ R10, R10
   610      round(R9, R10)
   611      XORQ R10, R8
   612      ROLQ $27, R8
   613      IMULQ prime1, R8
   614      ADDQ prime4, R8
   615      avalanche(R9, R8)
   616  
   617      MOVQ R8, (AX)(SI*8)
   618      INCQ SI
   619      JMP loop
   620  done:
   621      RET
   622  
   623  // func MultiSum64Uint128(h []uint64, v [][16]byte) int
   624  TEXT ·MultiSum64Uint128(SB), NOSPLIT, $0-54
   625      MOVQ $PRIME1, prime1
   626      MOVQ $PRIME2, prime2
   627      MOVQ $PRIME3, prime3
   628      MOVQ $PRIME4, prime4
   629  
   630      MOVQ h_base+0(FP), AX
   631      MOVQ h_len+8(FP), CX
   632      MOVQ v_base+24(FP), BX
   633      MOVQ v_len+32(FP), DX
   634  
   635      CMPQ CX, DX
   636      CMOVQGT DX, CX
   637      MOVQ CX, ret+48(FP)
   638  
   639      XORQ SI, SI
   640      CMPQ CX, $16
   641      JB loop
   642      CMPB ·hasAVX512(SB), $0
   643      JE loop
   644  
   645      MOVQ CX, DI
   646      SHRQ $4, DI
   647      SHLQ $4, DI
   648  
   649      VMOVDQU64 prime1vec<>(SB), prime1ZMM
   650      VMOVDQU64 prime2vec<>(SB), prime2ZMM
   651      VMOVDQU64 prime3vec<>(SB), prime3ZMM
   652      VMOVDQU64 prime4vec<>(SB), prime4ZMM
   653      VMOVDQU64 prime5vec16<>(SB), Z6
   654      VMOVDQU64 vpermi2qeven<>(SB), Z7
   655      VMOVDQU64 vpermi2qodd<>(SB), Z8
   656  loop16x64:
   657      // This algorithm is slightly different from the other ones, because it is
   658      // the only case where the input values are larger than the output (128 bits
   659      // vs 64 bits).
   660      //
   661      // Computing the XXH64 of 128 bits values requires doing two passes over the
   662      // lower and upper 64 bits. The lower and upper quad/ words are split in
   663      // separate vectors, the first pass is applied on the vector holding the
   664      // lower bits of 8 input values, then the second pass is applied with the
   665      // vector holding the upper bits.
   666      //
   667      // Following the model used in the other functions, we unroll the work of
   668      // two consecutive groups of 8 values per loop iteration in order to
   669      // maximize utilization of CPU resources.
   670      CMPQ SI, DI
   671      JE loop
   672      VMOVDQA64 Z6, Z0
   673      VMOVDQA64 Z6, Z20
   674      VMOVDQU64 (BX), Z1
   675      VMOVDQU64 64(BX), Z9
   676      VMOVDQU64 128(BX), Z21
   677      VMOVDQU64 192(BX), Z29
   678  
   679      VMOVDQA64 Z7, Z2
   680      VMOVDQA64 Z8, Z3
   681      VMOVDQA64 Z7, Z22
   682      VMOVDQA64 Z8, Z23
   683  
   684      VPERMI2Q Z9, Z1, Z2
   685      VPERMI2Q Z9, Z1, Z3
   686      VPERMI2Q Z29, Z21, Z22
   687      VPERMI2Q Z29, Z21, Z23
   688  
   689      // Compute the rounds on inputs.
   690      VPXORQ Z4, Z4, Z4
   691      VPXORQ Z5, Z5, Z5
   692      VPXORQ Z24, Z24, Z24
   693      VPXORQ Z25, Z25, Z25
   694      round8x64(Z2, Z4)
   695      round8x64(Z3, Z5)
   696      round8x64(Z22, Z24)
   697      round8x64(Z23, Z25)
   698  
   699      // Lower 64 bits.
   700      VPXORQ Z4, Z0, Z0
   701      VPXORQ Z24, Z20, Z20
   702      VPROLQ $27, Z0, Z0
   703      VPROLQ $27, Z20, Z20
   704      VPMULLQ prime1ZMM, Z0, Z0
   705      VPMULLQ prime1ZMM, Z20, Z20
   706      VPADDQ prime4ZMM, Z0, Z0
   707      VPADDQ prime4ZMM, Z20, Z20
   708  
   709      // Upper 64 bits.
   710      VPXORQ Z5, Z0, Z0
   711      VPXORQ Z25, Z20, Z20
   712      VPROLQ $27, Z0, Z0
   713      VPROLQ $27, Z20, Z20
   714      VPMULLQ prime1ZMM, Z0, Z0
   715      VPMULLQ prime1ZMM, Z20, Z20
   716      VPADDQ prime4ZMM, Z0, Z0
   717      VPADDQ prime4ZMM, Z20, Z20
   718  
   719      avalanche8x64(Z1, Z0)
   720      avalanche8x64(Z21, Z20)
   721      VMOVDQU64 Z0, (AX)(SI*8)
   722      VMOVDQU64 Z20, 64(AX)(SI*8)
   723      ADDQ $256, BX
   724      ADDQ $16, SI
   725      JMP loop16x64
   726      VZEROUPPER
   727  loop:
   728      CMPQ SI, CX
   729      JE done
   730      MOVQ $PRIME5+16, R8
   731      MOVQ (BX), DX
   732      MOVQ 8(BX), DI
   733  
   734      XORQ R9, R9
   735      XORQ R10, R10
   736      round(DX, R9)
   737      round(DI, R10)
   738  
   739      XORQ R9, R8
   740      ROLQ $27, R8
   741      IMULQ prime1, R8
   742      ADDQ prime4, R8
   743  
   744      XORQ R10, R8
   745      ROLQ $27, R8
   746      IMULQ prime1, R8
   747      ADDQ prime4, R8
   748  
   749      avalanche(R9, R8)
   750      MOVQ R8, (AX)(SI*8)
   751      ADDQ $16, BX
   752      INCQ SI
   753      JMP loop
   754  done:
   755      RET