1*5ff13fbcSAllan Jude/* 2*5ff13fbcSAllan Jude * Copyright (c) Facebook, Inc. 3*5ff13fbcSAllan Jude * All rights reserved. 4*5ff13fbcSAllan Jude * 5*5ff13fbcSAllan Jude * This source code is licensed under both the BSD-style license (found in the 6*5ff13fbcSAllan Jude * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7*5ff13fbcSAllan Jude * in the COPYING file in the root directory of this source tree). 8*5ff13fbcSAllan Jude * You may select, at your option, one of the above-listed licenses. 9*5ff13fbcSAllan Jude */ 10*5ff13fbcSAllan Jude 11*5ff13fbcSAllan Jude#include "../common/portability_macros.h" 12*5ff13fbcSAllan Jude 13*5ff13fbcSAllan Jude/* Stack marking 14*5ff13fbcSAllan Jude * ref: https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart 15*5ff13fbcSAllan Jude */ 16*5ff13fbcSAllan Jude#if defined(__ELF__) && defined(__GNUC__) 17*5ff13fbcSAllan Jude.section .note.GNU-stack,"",%progbits 18*5ff13fbcSAllan Jude#endif 19*5ff13fbcSAllan Jude 20*5ff13fbcSAllan Jude#if ZSTD_ENABLE_ASM_X86_64_BMI2 21*5ff13fbcSAllan Jude 22*5ff13fbcSAllan Jude/* Calling convention: 23*5ff13fbcSAllan Jude * 24*5ff13fbcSAllan Jude * %rdi contains the first argument: HUF_DecompressAsmArgs*. 25*5ff13fbcSAllan Jude * %rbp isn't maintained (no frame pointer). 26*5ff13fbcSAllan Jude * %rsp contains the stack pointer that grows down. 27*5ff13fbcSAllan Jude * No red-zone is assumed, only addresses >= %rsp are used. 28*5ff13fbcSAllan Jude * All register contents are preserved. 29*5ff13fbcSAllan Jude * 30*5ff13fbcSAllan Jude * TODO: Support Windows calling convention. 31*5ff13fbcSAllan Jude */ 32*5ff13fbcSAllan Jude 33*5ff13fbcSAllan JudeZSTD_HIDE_ASM_FUNCTION(HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop) 34*5ff13fbcSAllan JudeZSTD_HIDE_ASM_FUNCTION(HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop) 35*5ff13fbcSAllan JudeZSTD_HIDE_ASM_FUNCTION(_HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop) 36*5ff13fbcSAllan JudeZSTD_HIDE_ASM_FUNCTION(_HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop) 37*5ff13fbcSAllan Jude.global HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop 38*5ff13fbcSAllan Jude.global HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop 39*5ff13fbcSAllan Jude.global _HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop 40*5ff13fbcSAllan Jude.global _HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop 41*5ff13fbcSAllan Jude.text 42*5ff13fbcSAllan Jude 43*5ff13fbcSAllan Jude/* Sets up register mappings for clarity. 44*5ff13fbcSAllan Jude * op[], bits[], dtable & ip[0] each get their own register. 45*5ff13fbcSAllan Jude * ip[1,2,3] & olimit alias var[]. 46*5ff13fbcSAllan Jude * %rax is a scratch register. 47*5ff13fbcSAllan Jude */ 48*5ff13fbcSAllan Jude 49*5ff13fbcSAllan Jude#define op0 rsi 50*5ff13fbcSAllan Jude#define op1 rbx 51*5ff13fbcSAllan Jude#define op2 rcx 52*5ff13fbcSAllan Jude#define op3 rdi 53*5ff13fbcSAllan Jude 54*5ff13fbcSAllan Jude#define ip0 r8 55*5ff13fbcSAllan Jude#define ip1 r9 56*5ff13fbcSAllan Jude#define ip2 r10 57*5ff13fbcSAllan Jude#define ip3 r11 58*5ff13fbcSAllan Jude 59*5ff13fbcSAllan Jude#define bits0 rbp 60*5ff13fbcSAllan Jude#define bits1 rdx 61*5ff13fbcSAllan Jude#define bits2 r12 62*5ff13fbcSAllan Jude#define bits3 r13 63*5ff13fbcSAllan Jude#define dtable r14 64*5ff13fbcSAllan Jude#define olimit r15 65*5ff13fbcSAllan Jude 66*5ff13fbcSAllan Jude/* var[] aliases ip[1,2,3] & olimit 67*5ff13fbcSAllan Jude * ip[1,2,3] are saved every iteration. 68*5ff13fbcSAllan Jude * olimit is only used in compute_olimit. 69*5ff13fbcSAllan Jude */ 70*5ff13fbcSAllan Jude#define var0 r15 71*5ff13fbcSAllan Jude#define var1 r9 72*5ff13fbcSAllan Jude#define var2 r10 73*5ff13fbcSAllan Jude#define var3 r11 74*5ff13fbcSAllan Jude 75*5ff13fbcSAllan Jude/* 32-bit var registers */ 76*5ff13fbcSAllan Jude#define vard0 r15d 77*5ff13fbcSAllan Jude#define vard1 r9d 78*5ff13fbcSAllan Jude#define vard2 r10d 79*5ff13fbcSAllan Jude#define vard3 r11d 80*5ff13fbcSAllan Jude 81*5ff13fbcSAllan Jude/* Calls X(N) for each stream 0, 1, 2, 3. */ 82*5ff13fbcSAllan Jude#define FOR_EACH_STREAM(X) \ 83*5ff13fbcSAllan Jude X(0); \ 84*5ff13fbcSAllan Jude X(1); \ 85*5ff13fbcSAllan Jude X(2); \ 86*5ff13fbcSAllan Jude X(3) 87*5ff13fbcSAllan Jude 88*5ff13fbcSAllan Jude/* Calls X(N, idx) for each stream 0, 1, 2, 3. */ 89*5ff13fbcSAllan Jude#define FOR_EACH_STREAM_WITH_INDEX(X, idx) \ 90*5ff13fbcSAllan Jude X(0, idx); \ 91*5ff13fbcSAllan Jude X(1, idx); \ 92*5ff13fbcSAllan Jude X(2, idx); \ 93*5ff13fbcSAllan Jude X(3, idx) 94*5ff13fbcSAllan Jude 95*5ff13fbcSAllan Jude/* Define both _HUF_* & HUF_* symbols because MacOS 96*5ff13fbcSAllan Jude * C symbols are prefixed with '_' & Linux symbols aren't. 97*5ff13fbcSAllan Jude */ 98*5ff13fbcSAllan Jude_HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop: 99*5ff13fbcSAllan JudeHUF_decompress4X1_usingDTable_internal_bmi2_asm_loop: 100*5ff13fbcSAllan Jude /* Save all registers - even if they are callee saved for simplicity. */ 101*5ff13fbcSAllan Jude push %rax 102*5ff13fbcSAllan Jude push %rbx 103*5ff13fbcSAllan Jude push %rcx 104*5ff13fbcSAllan Jude push %rdx 105*5ff13fbcSAllan Jude push %rbp 106*5ff13fbcSAllan Jude push %rsi 107*5ff13fbcSAllan Jude push %rdi 108*5ff13fbcSAllan Jude push %r8 109*5ff13fbcSAllan Jude push %r9 110*5ff13fbcSAllan Jude push %r10 111*5ff13fbcSAllan Jude push %r11 112*5ff13fbcSAllan Jude push %r12 113*5ff13fbcSAllan Jude push %r13 114*5ff13fbcSAllan Jude push %r14 115*5ff13fbcSAllan Jude push %r15 116*5ff13fbcSAllan Jude 117*5ff13fbcSAllan Jude /* Read HUF_DecompressAsmArgs* args from %rax */ 118*5ff13fbcSAllan Jude movq %rdi, %rax 119*5ff13fbcSAllan Jude movq 0(%rax), %ip0 120*5ff13fbcSAllan Jude movq 8(%rax), %ip1 121*5ff13fbcSAllan Jude movq 16(%rax), %ip2 122*5ff13fbcSAllan Jude movq 24(%rax), %ip3 123*5ff13fbcSAllan Jude movq 32(%rax), %op0 124*5ff13fbcSAllan Jude movq 40(%rax), %op1 125*5ff13fbcSAllan Jude movq 48(%rax), %op2 126*5ff13fbcSAllan Jude movq 56(%rax), %op3 127*5ff13fbcSAllan Jude movq 64(%rax), %bits0 128*5ff13fbcSAllan Jude movq 72(%rax), %bits1 129*5ff13fbcSAllan Jude movq 80(%rax), %bits2 130*5ff13fbcSAllan Jude movq 88(%rax), %bits3 131*5ff13fbcSAllan Jude movq 96(%rax), %dtable 132*5ff13fbcSAllan Jude push %rax /* argument */ 133*5ff13fbcSAllan Jude push 104(%rax) /* ilimit */ 134*5ff13fbcSAllan Jude push 112(%rax) /* oend */ 135*5ff13fbcSAllan Jude push %olimit /* olimit space */ 136*5ff13fbcSAllan Jude 137*5ff13fbcSAllan Jude subq $24, %rsp 138*5ff13fbcSAllan Jude 139*5ff13fbcSAllan Jude.L_4X1_compute_olimit: 140*5ff13fbcSAllan Jude /* Computes how many iterations we can do safely 141*5ff13fbcSAllan Jude * %r15, %rax may be clobbered 142*5ff13fbcSAllan Jude * rbx, rdx must be saved 143*5ff13fbcSAllan Jude * op3 & ip0 mustn't be clobbered 144*5ff13fbcSAllan Jude */ 145*5ff13fbcSAllan Jude movq %rbx, 0(%rsp) 146*5ff13fbcSAllan Jude movq %rdx, 8(%rsp) 147*5ff13fbcSAllan Jude 148*5ff13fbcSAllan Jude movq 32(%rsp), %rax /* rax = oend */ 149*5ff13fbcSAllan Jude subq %op3, %rax /* rax = oend - op3 */ 150*5ff13fbcSAllan Jude 151*5ff13fbcSAllan Jude /* r15 = (oend - op3) / 5 */ 152*5ff13fbcSAllan Jude movabsq $-3689348814741910323, %rdx 153*5ff13fbcSAllan Jude mulq %rdx 154*5ff13fbcSAllan Jude movq %rdx, %r15 155*5ff13fbcSAllan Jude shrq $2, %r15 156*5ff13fbcSAllan Jude 157*5ff13fbcSAllan Jude movq %ip0, %rax /* rax = ip0 */ 158*5ff13fbcSAllan Jude movq 40(%rsp), %rdx /* rdx = ilimit */ 159*5ff13fbcSAllan Jude subq %rdx, %rax /* rax = ip0 - ilimit */ 160*5ff13fbcSAllan Jude movq %rax, %rbx /* rbx = ip0 - ilimit */ 161*5ff13fbcSAllan Jude 162*5ff13fbcSAllan Jude /* rdx = (ip0 - ilimit) / 7 */ 163*5ff13fbcSAllan Jude movabsq $2635249153387078803, %rdx 164*5ff13fbcSAllan Jude mulq %rdx 165*5ff13fbcSAllan Jude subq %rdx, %rbx 166*5ff13fbcSAllan Jude shrq %rbx 167*5ff13fbcSAllan Jude addq %rbx, %rdx 168*5ff13fbcSAllan Jude shrq $2, %rdx 169*5ff13fbcSAllan Jude 170*5ff13fbcSAllan Jude /* r15 = min(%rdx, %r15) */ 171*5ff13fbcSAllan Jude cmpq %rdx, %r15 172*5ff13fbcSAllan Jude cmova %rdx, %r15 173*5ff13fbcSAllan Jude 174*5ff13fbcSAllan Jude /* r15 = r15 * 5 */ 175*5ff13fbcSAllan Jude leaq (%r15, %r15, 4), %r15 176*5ff13fbcSAllan Jude 177*5ff13fbcSAllan Jude /* olimit = op3 + r15 */ 178*5ff13fbcSAllan Jude addq %op3, %olimit 179*5ff13fbcSAllan Jude 180*5ff13fbcSAllan Jude movq 8(%rsp), %rdx 181*5ff13fbcSAllan Jude movq 0(%rsp), %rbx 182*5ff13fbcSAllan Jude 183*5ff13fbcSAllan Jude /* If (op3 + 20 > olimit) */ 184*5ff13fbcSAllan Jude movq %op3, %rax /* rax = op3 */ 185*5ff13fbcSAllan Jude addq $20, %rax /* rax = op3 + 20 */ 186*5ff13fbcSAllan Jude cmpq %rax, %olimit /* op3 + 20 > olimit */ 187*5ff13fbcSAllan Jude jb .L_4X1_exit 188*5ff13fbcSAllan Jude 189*5ff13fbcSAllan Jude /* If (ip1 < ip0) go to exit */ 190*5ff13fbcSAllan Jude cmpq %ip0, %ip1 191*5ff13fbcSAllan Jude jb .L_4X1_exit 192*5ff13fbcSAllan Jude 193*5ff13fbcSAllan Jude /* If (ip2 < ip1) go to exit */ 194*5ff13fbcSAllan Jude cmpq %ip1, %ip2 195*5ff13fbcSAllan Jude jb .L_4X1_exit 196*5ff13fbcSAllan Jude 197*5ff13fbcSAllan Jude /* If (ip3 < ip2) go to exit */ 198*5ff13fbcSAllan Jude cmpq %ip2, %ip3 199*5ff13fbcSAllan Jude jb .L_4X1_exit 200*5ff13fbcSAllan Jude 201*5ff13fbcSAllan Jude/* Reads top 11 bits from bits[n] 202*5ff13fbcSAllan Jude * Loads dt[bits[n]] into var[n] 203*5ff13fbcSAllan Jude */ 204*5ff13fbcSAllan Jude#define GET_NEXT_DELT(n) \ 205*5ff13fbcSAllan Jude movq $53, %var##n; \ 206*5ff13fbcSAllan Jude shrxq %var##n, %bits##n, %var##n; \ 207*5ff13fbcSAllan Jude movzwl (%dtable,%var##n,2),%vard##n 208*5ff13fbcSAllan Jude 209*5ff13fbcSAllan Jude/* var[n] must contain the DTable entry computed with GET_NEXT_DELT 210*5ff13fbcSAllan Jude * Moves var[n] to %rax 211*5ff13fbcSAllan Jude * bits[n] <<= var[n] & 63 212*5ff13fbcSAllan Jude * op[n][idx] = %rax >> 8 213*5ff13fbcSAllan Jude * %ah is a way to access bits [8, 16) of %rax 214*5ff13fbcSAllan Jude */ 215*5ff13fbcSAllan Jude#define DECODE_FROM_DELT(n, idx) \ 216*5ff13fbcSAllan Jude movq %var##n, %rax; \ 217*5ff13fbcSAllan Jude shlxq %var##n, %bits##n, %bits##n; \ 218*5ff13fbcSAllan Jude movb %ah, idx(%op##n) 219*5ff13fbcSAllan Jude 220*5ff13fbcSAllan Jude/* Assumes GET_NEXT_DELT has been called. 221*5ff13fbcSAllan Jude * Calls DECODE_FROM_DELT then GET_NEXT_DELT 222*5ff13fbcSAllan Jude */ 223*5ff13fbcSAllan Jude#define DECODE_AND_GET_NEXT(n, idx) \ 224*5ff13fbcSAllan Jude DECODE_FROM_DELT(n, idx); \ 225*5ff13fbcSAllan Jude GET_NEXT_DELT(n) \ 226*5ff13fbcSAllan Jude 227*5ff13fbcSAllan Jude/* // ctz & nbBytes is stored in bits[n] 228*5ff13fbcSAllan Jude * // nbBits is stored in %rax 229*5ff13fbcSAllan Jude * ctz = CTZ[bits[n]] 230*5ff13fbcSAllan Jude * nbBits = ctz & 7 231*5ff13fbcSAllan Jude * nbBytes = ctz >> 3 232*5ff13fbcSAllan Jude * op[n] += 5 233*5ff13fbcSAllan Jude * ip[n] -= nbBytes 234*5ff13fbcSAllan Jude * // Note: x86-64 is little-endian ==> no bswap 235*5ff13fbcSAllan Jude * bits[n] = MEM_readST(ip[n]) | 1 236*5ff13fbcSAllan Jude * bits[n] <<= nbBits 237*5ff13fbcSAllan Jude */ 238*5ff13fbcSAllan Jude#define RELOAD_BITS(n) \ 239*5ff13fbcSAllan Jude bsfq %bits##n, %bits##n; \ 240*5ff13fbcSAllan Jude movq %bits##n, %rax; \ 241*5ff13fbcSAllan Jude andq $7, %rax; \ 242*5ff13fbcSAllan Jude shrq $3, %bits##n; \ 243*5ff13fbcSAllan Jude leaq 5(%op##n), %op##n; \ 244*5ff13fbcSAllan Jude subq %bits##n, %ip##n; \ 245*5ff13fbcSAllan Jude movq (%ip##n), %bits##n; \ 246*5ff13fbcSAllan Jude orq $1, %bits##n; \ 247*5ff13fbcSAllan Jude shlx %rax, %bits##n, %bits##n 248*5ff13fbcSAllan Jude 249*5ff13fbcSAllan Jude /* Store clobbered variables on the stack */ 250*5ff13fbcSAllan Jude movq %olimit, 24(%rsp) 251*5ff13fbcSAllan Jude movq %ip1, 0(%rsp) 252*5ff13fbcSAllan Jude movq %ip2, 8(%rsp) 253*5ff13fbcSAllan Jude movq %ip3, 16(%rsp) 254*5ff13fbcSAllan Jude 255*5ff13fbcSAllan Jude /* Call GET_NEXT_DELT for each stream */ 256*5ff13fbcSAllan Jude FOR_EACH_STREAM(GET_NEXT_DELT) 257*5ff13fbcSAllan Jude 258*5ff13fbcSAllan Jude .p2align 6 259*5ff13fbcSAllan Jude 260*5ff13fbcSAllan Jude.L_4X1_loop_body: 261*5ff13fbcSAllan Jude /* Decode 5 symbols in each of the 4 streams (20 total) 262*5ff13fbcSAllan Jude * Must have called GET_NEXT_DELT for each stream 263*5ff13fbcSAllan Jude */ 264*5ff13fbcSAllan Jude FOR_EACH_STREAM_WITH_INDEX(DECODE_AND_GET_NEXT, 0) 265*5ff13fbcSAllan Jude FOR_EACH_STREAM_WITH_INDEX(DECODE_AND_GET_NEXT, 1) 266*5ff13fbcSAllan Jude FOR_EACH_STREAM_WITH_INDEX(DECODE_AND_GET_NEXT, 2) 267*5ff13fbcSAllan Jude FOR_EACH_STREAM_WITH_INDEX(DECODE_AND_GET_NEXT, 3) 268*5ff13fbcSAllan Jude FOR_EACH_STREAM_WITH_INDEX(DECODE_FROM_DELT, 4) 269*5ff13fbcSAllan Jude 270*5ff13fbcSAllan Jude /* Load ip[1,2,3] from stack (var[] aliases them) 271*5ff13fbcSAllan Jude * ip[] is needed for RELOAD_BITS 272*5ff13fbcSAllan Jude * Each will be stored back to the stack after RELOAD 273*5ff13fbcSAllan Jude */ 274*5ff13fbcSAllan Jude movq 0(%rsp), %ip1 275*5ff13fbcSAllan Jude movq 8(%rsp), %ip2 276*5ff13fbcSAllan Jude movq 16(%rsp), %ip3 277*5ff13fbcSAllan Jude 278*5ff13fbcSAllan Jude /* Reload each stream & fetch the next table entry 279*5ff13fbcSAllan Jude * to prepare for the next iteration 280*5ff13fbcSAllan Jude */ 281*5ff13fbcSAllan Jude RELOAD_BITS(0) 282*5ff13fbcSAllan Jude GET_NEXT_DELT(0) 283*5ff13fbcSAllan Jude 284*5ff13fbcSAllan Jude RELOAD_BITS(1) 285*5ff13fbcSAllan Jude movq %ip1, 0(%rsp) 286*5ff13fbcSAllan Jude GET_NEXT_DELT(1) 287*5ff13fbcSAllan Jude 288*5ff13fbcSAllan Jude RELOAD_BITS(2) 289*5ff13fbcSAllan Jude movq %ip2, 8(%rsp) 290*5ff13fbcSAllan Jude GET_NEXT_DELT(2) 291*5ff13fbcSAllan Jude 292*5ff13fbcSAllan Jude RELOAD_BITS(3) 293*5ff13fbcSAllan Jude movq %ip3, 16(%rsp) 294*5ff13fbcSAllan Jude GET_NEXT_DELT(3) 295*5ff13fbcSAllan Jude 296*5ff13fbcSAllan Jude /* If op3 < olimit: continue the loop */ 297*5ff13fbcSAllan Jude cmp %op3, 24(%rsp) 298*5ff13fbcSAllan Jude ja .L_4X1_loop_body 299*5ff13fbcSAllan Jude 300*5ff13fbcSAllan Jude /* Reload ip[1,2,3] from stack */ 301*5ff13fbcSAllan Jude movq 0(%rsp), %ip1 302*5ff13fbcSAllan Jude movq 8(%rsp), %ip2 303*5ff13fbcSAllan Jude movq 16(%rsp), %ip3 304*5ff13fbcSAllan Jude 305*5ff13fbcSAllan Jude /* Re-compute olimit */ 306*5ff13fbcSAllan Jude jmp .L_4X1_compute_olimit 307*5ff13fbcSAllan Jude 308*5ff13fbcSAllan Jude#undef GET_NEXT_DELT 309*5ff13fbcSAllan Jude#undef DECODE_FROM_DELT 310*5ff13fbcSAllan Jude#undef DECODE 311*5ff13fbcSAllan Jude#undef RELOAD_BITS 312*5ff13fbcSAllan Jude.L_4X1_exit: 313*5ff13fbcSAllan Jude addq $24, %rsp 314*5ff13fbcSAllan Jude 315*5ff13fbcSAllan Jude /* Restore stack (oend & olimit) */ 316*5ff13fbcSAllan Jude pop %rax /* olimit */ 317*5ff13fbcSAllan Jude pop %rax /* oend */ 318*5ff13fbcSAllan Jude pop %rax /* ilimit */ 319*5ff13fbcSAllan Jude pop %rax /* arg */ 320*5ff13fbcSAllan Jude 321*5ff13fbcSAllan Jude /* Save ip / op / bits */ 322*5ff13fbcSAllan Jude movq %ip0, 0(%rax) 323*5ff13fbcSAllan Jude movq %ip1, 8(%rax) 324*5ff13fbcSAllan Jude movq %ip2, 16(%rax) 325*5ff13fbcSAllan Jude movq %ip3, 24(%rax) 326*5ff13fbcSAllan Jude movq %op0, 32(%rax) 327*5ff13fbcSAllan Jude movq %op1, 40(%rax) 328*5ff13fbcSAllan Jude movq %op2, 48(%rax) 329*5ff13fbcSAllan Jude movq %op3, 56(%rax) 330*5ff13fbcSAllan Jude movq %bits0, 64(%rax) 331*5ff13fbcSAllan Jude movq %bits1, 72(%rax) 332*5ff13fbcSAllan Jude movq %bits2, 80(%rax) 333*5ff13fbcSAllan Jude movq %bits3, 88(%rax) 334*5ff13fbcSAllan Jude 335*5ff13fbcSAllan Jude /* Restore registers */ 336*5ff13fbcSAllan Jude pop %r15 337*5ff13fbcSAllan Jude pop %r14 338*5ff13fbcSAllan Jude pop %r13 339*5ff13fbcSAllan Jude pop %r12 340*5ff13fbcSAllan Jude pop %r11 341*5ff13fbcSAllan Jude pop %r10 342*5ff13fbcSAllan Jude pop %r9 343*5ff13fbcSAllan Jude pop %r8 344*5ff13fbcSAllan Jude pop %rdi 345*5ff13fbcSAllan Jude pop %rsi 346*5ff13fbcSAllan Jude pop %rbp 347*5ff13fbcSAllan Jude pop %rdx 348*5ff13fbcSAllan Jude pop %rcx 349*5ff13fbcSAllan Jude pop %rbx 350*5ff13fbcSAllan Jude pop %rax 351*5ff13fbcSAllan Jude ret 352*5ff13fbcSAllan Jude 353*5ff13fbcSAllan Jude_HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop: 354*5ff13fbcSAllan JudeHUF_decompress4X2_usingDTable_internal_bmi2_asm_loop: 355*5ff13fbcSAllan Jude /* Save all registers - even if they are callee saved for simplicity. */ 356*5ff13fbcSAllan Jude push %rax 357*5ff13fbcSAllan Jude push %rbx 358*5ff13fbcSAllan Jude push %rcx 359*5ff13fbcSAllan Jude push %rdx 360*5ff13fbcSAllan Jude push %rbp 361*5ff13fbcSAllan Jude push %rsi 362*5ff13fbcSAllan Jude push %rdi 363*5ff13fbcSAllan Jude push %r8 364*5ff13fbcSAllan Jude push %r9 365*5ff13fbcSAllan Jude push %r10 366*5ff13fbcSAllan Jude push %r11 367*5ff13fbcSAllan Jude push %r12 368*5ff13fbcSAllan Jude push %r13 369*5ff13fbcSAllan Jude push %r14 370*5ff13fbcSAllan Jude push %r15 371*5ff13fbcSAllan Jude 372*5ff13fbcSAllan Jude movq %rdi, %rax 373*5ff13fbcSAllan Jude movq 0(%rax), %ip0 374*5ff13fbcSAllan Jude movq 8(%rax), %ip1 375*5ff13fbcSAllan Jude movq 16(%rax), %ip2 376*5ff13fbcSAllan Jude movq 24(%rax), %ip3 377*5ff13fbcSAllan Jude movq 32(%rax), %op0 378*5ff13fbcSAllan Jude movq 40(%rax), %op1 379*5ff13fbcSAllan Jude movq 48(%rax), %op2 380*5ff13fbcSAllan Jude movq 56(%rax), %op3 381*5ff13fbcSAllan Jude movq 64(%rax), %bits0 382*5ff13fbcSAllan Jude movq 72(%rax), %bits1 383*5ff13fbcSAllan Jude movq 80(%rax), %bits2 384*5ff13fbcSAllan Jude movq 88(%rax), %bits3 385*5ff13fbcSAllan Jude movq 96(%rax), %dtable 386*5ff13fbcSAllan Jude push %rax /* argument */ 387*5ff13fbcSAllan Jude push %rax /* olimit */ 388*5ff13fbcSAllan Jude push 104(%rax) /* ilimit */ 389*5ff13fbcSAllan Jude 390*5ff13fbcSAllan Jude movq 112(%rax), %rax 391*5ff13fbcSAllan Jude push %rax /* oend3 */ 392*5ff13fbcSAllan Jude 393*5ff13fbcSAllan Jude movq %op3, %rax 394*5ff13fbcSAllan Jude push %rax /* oend2 */ 395*5ff13fbcSAllan Jude 396*5ff13fbcSAllan Jude movq %op2, %rax 397*5ff13fbcSAllan Jude push %rax /* oend1 */ 398*5ff13fbcSAllan Jude 399*5ff13fbcSAllan Jude movq %op1, %rax 400*5ff13fbcSAllan Jude push %rax /* oend0 */ 401*5ff13fbcSAllan Jude 402*5ff13fbcSAllan Jude /* Scratch space */ 403*5ff13fbcSAllan Jude subq $8, %rsp 404*5ff13fbcSAllan Jude 405*5ff13fbcSAllan Jude.L_4X2_compute_olimit: 406*5ff13fbcSAllan Jude /* Computes how many iterations we can do safely 407*5ff13fbcSAllan Jude * %r15, %rax may be clobbered 408*5ff13fbcSAllan Jude * rdx must be saved 409*5ff13fbcSAllan Jude * op[1,2,3,4] & ip0 mustn't be clobbered 410*5ff13fbcSAllan Jude */ 411*5ff13fbcSAllan Jude movq %rdx, 0(%rsp) 412*5ff13fbcSAllan Jude 413*5ff13fbcSAllan Jude /* We can consume up to 7 input bytes each iteration. */ 414*5ff13fbcSAllan Jude movq %ip0, %rax /* rax = ip0 */ 415*5ff13fbcSAllan Jude movq 40(%rsp), %rdx /* rdx = ilimit */ 416*5ff13fbcSAllan Jude subq %rdx, %rax /* rax = ip0 - ilimit */ 417*5ff13fbcSAllan Jude movq %rax, %r15 /* r15 = ip0 - ilimit */ 418*5ff13fbcSAllan Jude 419*5ff13fbcSAllan Jude /* rdx = rax / 7 */ 420*5ff13fbcSAllan Jude movabsq $2635249153387078803, %rdx 421*5ff13fbcSAllan Jude mulq %rdx 422*5ff13fbcSAllan Jude subq %rdx, %r15 423*5ff13fbcSAllan Jude shrq %r15 424*5ff13fbcSAllan Jude addq %r15, %rdx 425*5ff13fbcSAllan Jude shrq $2, %rdx 426*5ff13fbcSAllan Jude 427*5ff13fbcSAllan Jude /* r15 = (ip0 - ilimit) / 7 */ 428*5ff13fbcSAllan Jude movq %rdx, %r15 429*5ff13fbcSAllan Jude 430*5ff13fbcSAllan Jude movabsq $-3689348814741910323, %rdx 431*5ff13fbcSAllan Jude movq 8(%rsp), %rax /* rax = oend0 */ 432*5ff13fbcSAllan Jude subq %op0, %rax /* rax = oend0 - op0 */ 433*5ff13fbcSAllan Jude mulq %rdx 434*5ff13fbcSAllan Jude shrq $3, %rdx /* rdx = rax / 10 */ 435*5ff13fbcSAllan Jude 436*5ff13fbcSAllan Jude /* r15 = min(%rdx, %r15) */ 437*5ff13fbcSAllan Jude cmpq %rdx, %r15 438*5ff13fbcSAllan Jude cmova %rdx, %r15 439*5ff13fbcSAllan Jude 440*5ff13fbcSAllan Jude movabsq $-3689348814741910323, %rdx 441*5ff13fbcSAllan Jude movq 16(%rsp), %rax /* rax = oend1 */ 442*5ff13fbcSAllan Jude subq %op1, %rax /* rax = oend1 - op1 */ 443*5ff13fbcSAllan Jude mulq %rdx 444*5ff13fbcSAllan Jude shrq $3, %rdx /* rdx = rax / 10 */ 445*5ff13fbcSAllan Jude 446*5ff13fbcSAllan Jude /* r15 = min(%rdx, %r15) */ 447*5ff13fbcSAllan Jude cmpq %rdx, %r15 448*5ff13fbcSAllan Jude cmova %rdx, %r15 449*5ff13fbcSAllan Jude 450*5ff13fbcSAllan Jude movabsq $-3689348814741910323, %rdx 451*5ff13fbcSAllan Jude movq 24(%rsp), %rax /* rax = oend2 */ 452*5ff13fbcSAllan Jude subq %op2, %rax /* rax = oend2 - op2 */ 453*5ff13fbcSAllan Jude mulq %rdx 454*5ff13fbcSAllan Jude shrq $3, %rdx /* rdx = rax / 10 */ 455*5ff13fbcSAllan Jude 456*5ff13fbcSAllan Jude /* r15 = min(%rdx, %r15) */ 457*5ff13fbcSAllan Jude cmpq %rdx, %r15 458*5ff13fbcSAllan Jude cmova %rdx, %r15 459*5ff13fbcSAllan Jude 460*5ff13fbcSAllan Jude movabsq $-3689348814741910323, %rdx 461*5ff13fbcSAllan Jude movq 32(%rsp), %rax /* rax = oend3 */ 462*5ff13fbcSAllan Jude subq %op3, %rax /* rax = oend3 - op3 */ 463*5ff13fbcSAllan Jude mulq %rdx 464*5ff13fbcSAllan Jude shrq $3, %rdx /* rdx = rax / 10 */ 465*5ff13fbcSAllan Jude 466*5ff13fbcSAllan Jude /* r15 = min(%rdx, %r15) */ 467*5ff13fbcSAllan Jude cmpq %rdx, %r15 468*5ff13fbcSAllan Jude cmova %rdx, %r15 469*5ff13fbcSAllan Jude 470*5ff13fbcSAllan Jude /* olimit = op3 + 5 * r15 */ 471*5ff13fbcSAllan Jude movq %r15, %rax 472*5ff13fbcSAllan Jude leaq (%op3, %rax, 4), %olimit 473*5ff13fbcSAllan Jude addq %rax, %olimit 474*5ff13fbcSAllan Jude 475*5ff13fbcSAllan Jude movq 0(%rsp), %rdx 476*5ff13fbcSAllan Jude 477*5ff13fbcSAllan Jude /* If (op3 + 10 > olimit) */ 478*5ff13fbcSAllan Jude movq %op3, %rax /* rax = op3 */ 479*5ff13fbcSAllan Jude addq $10, %rax /* rax = op3 + 10 */ 480*5ff13fbcSAllan Jude cmpq %rax, %olimit /* op3 + 10 > olimit */ 481*5ff13fbcSAllan Jude jb .L_4X2_exit 482*5ff13fbcSAllan Jude 483*5ff13fbcSAllan Jude /* If (ip1 < ip0) go to exit */ 484*5ff13fbcSAllan Jude cmpq %ip0, %ip1 485*5ff13fbcSAllan Jude jb .L_4X2_exit 486*5ff13fbcSAllan Jude 487*5ff13fbcSAllan Jude /* If (ip2 < ip1) go to exit */ 488*5ff13fbcSAllan Jude cmpq %ip1, %ip2 489*5ff13fbcSAllan Jude jb .L_4X2_exit 490*5ff13fbcSAllan Jude 491*5ff13fbcSAllan Jude /* If (ip3 < ip2) go to exit */ 492*5ff13fbcSAllan Jude cmpq %ip2, %ip3 493*5ff13fbcSAllan Jude jb .L_4X2_exit 494*5ff13fbcSAllan Jude 495*5ff13fbcSAllan Jude#define DECODE(n, idx) \ 496*5ff13fbcSAllan Jude movq %bits##n, %rax; \ 497*5ff13fbcSAllan Jude shrq $53, %rax; \ 498*5ff13fbcSAllan Jude movzwl 0(%dtable,%rax,4),%r8d; \ 499*5ff13fbcSAllan Jude movzbl 2(%dtable,%rax,4),%r15d; \ 500*5ff13fbcSAllan Jude movzbl 3(%dtable,%rax,4),%eax; \ 501*5ff13fbcSAllan Jude movw %r8w, (%op##n); \ 502*5ff13fbcSAllan Jude shlxq %r15, %bits##n, %bits##n; \ 503*5ff13fbcSAllan Jude addq %rax, %op##n 504*5ff13fbcSAllan Jude 505*5ff13fbcSAllan Jude#define RELOAD_BITS(n) \ 506*5ff13fbcSAllan Jude bsfq %bits##n, %bits##n; \ 507*5ff13fbcSAllan Jude movq %bits##n, %rax; \ 508*5ff13fbcSAllan Jude shrq $3, %bits##n; \ 509*5ff13fbcSAllan Jude andq $7, %rax; \ 510*5ff13fbcSAllan Jude subq %bits##n, %ip##n; \ 511*5ff13fbcSAllan Jude movq (%ip##n), %bits##n; \ 512*5ff13fbcSAllan Jude orq $1, %bits##n; \ 513*5ff13fbcSAllan Jude shlxq %rax, %bits##n, %bits##n 514*5ff13fbcSAllan Jude 515*5ff13fbcSAllan Jude 516*5ff13fbcSAllan Jude movq %olimit, 48(%rsp) 517*5ff13fbcSAllan Jude 518*5ff13fbcSAllan Jude .p2align 6 519*5ff13fbcSAllan Jude 520*5ff13fbcSAllan Jude.L_4X2_loop_body: 521*5ff13fbcSAllan Jude /* We clobber r8, so store it on the stack */ 522*5ff13fbcSAllan Jude movq %r8, 0(%rsp) 523*5ff13fbcSAllan Jude 524*5ff13fbcSAllan Jude /* Decode 5 symbols from each of the 4 streams (20 symbols total). */ 525*5ff13fbcSAllan Jude FOR_EACH_STREAM_WITH_INDEX(DECODE, 0) 526*5ff13fbcSAllan Jude FOR_EACH_STREAM_WITH_INDEX(DECODE, 1) 527*5ff13fbcSAllan Jude FOR_EACH_STREAM_WITH_INDEX(DECODE, 2) 528*5ff13fbcSAllan Jude FOR_EACH_STREAM_WITH_INDEX(DECODE, 3) 529*5ff13fbcSAllan Jude FOR_EACH_STREAM_WITH_INDEX(DECODE, 4) 530*5ff13fbcSAllan Jude 531*5ff13fbcSAllan Jude /* Reload r8 */ 532*5ff13fbcSAllan Jude movq 0(%rsp), %r8 533*5ff13fbcSAllan Jude 534*5ff13fbcSAllan Jude FOR_EACH_STREAM(RELOAD_BITS) 535*5ff13fbcSAllan Jude 536*5ff13fbcSAllan Jude cmp %op3, 48(%rsp) 537*5ff13fbcSAllan Jude ja .L_4X2_loop_body 538*5ff13fbcSAllan Jude jmp .L_4X2_compute_olimit 539*5ff13fbcSAllan Jude 540*5ff13fbcSAllan Jude#undef DECODE 541*5ff13fbcSAllan Jude#undef RELOAD_BITS 542*5ff13fbcSAllan Jude.L_4X2_exit: 543*5ff13fbcSAllan Jude addq $8, %rsp 544*5ff13fbcSAllan Jude /* Restore stack (oend & olimit) */ 545*5ff13fbcSAllan Jude pop %rax /* oend0 */ 546*5ff13fbcSAllan Jude pop %rax /* oend1 */ 547*5ff13fbcSAllan Jude pop %rax /* oend2 */ 548*5ff13fbcSAllan Jude pop %rax /* oend3 */ 549*5ff13fbcSAllan Jude pop %rax /* ilimit */ 550*5ff13fbcSAllan Jude pop %rax /* olimit */ 551*5ff13fbcSAllan Jude pop %rax /* arg */ 552*5ff13fbcSAllan Jude 553*5ff13fbcSAllan Jude /* Save ip / op / bits */ 554*5ff13fbcSAllan Jude movq %ip0, 0(%rax) 555*5ff13fbcSAllan Jude movq %ip1, 8(%rax) 556*5ff13fbcSAllan Jude movq %ip2, 16(%rax) 557*5ff13fbcSAllan Jude movq %ip3, 24(%rax) 558*5ff13fbcSAllan Jude movq %op0, 32(%rax) 559*5ff13fbcSAllan Jude movq %op1, 40(%rax) 560*5ff13fbcSAllan Jude movq %op2, 48(%rax) 561*5ff13fbcSAllan Jude movq %op3, 56(%rax) 562*5ff13fbcSAllan Jude movq %bits0, 64(%rax) 563*5ff13fbcSAllan Jude movq %bits1, 72(%rax) 564*5ff13fbcSAllan Jude movq %bits2, 80(%rax) 565*5ff13fbcSAllan Jude movq %bits3, 88(%rax) 566*5ff13fbcSAllan Jude 567*5ff13fbcSAllan Jude /* Restore registers */ 568*5ff13fbcSAllan Jude pop %r15 569*5ff13fbcSAllan Jude pop %r14 570*5ff13fbcSAllan Jude pop %r13 571*5ff13fbcSAllan Jude pop %r12 572*5ff13fbcSAllan Jude pop %r11 573*5ff13fbcSAllan Jude pop %r10 574*5ff13fbcSAllan Jude pop %r9 575*5ff13fbcSAllan Jude pop %r8 576*5ff13fbcSAllan Jude pop %rdi 577*5ff13fbcSAllan Jude pop %rsi 578*5ff13fbcSAllan Jude pop %rbp 579*5ff13fbcSAllan Jude pop %rdx 580*5ff13fbcSAllan Jude pop %rcx 581*5ff13fbcSAllan Jude pop %rbx 582*5ff13fbcSAllan Jude pop %rax 583*5ff13fbcSAllan Jude ret 584*5ff13fbcSAllan Jude 585*5ff13fbcSAllan Jude#endif 586