xref: /freebsd-src/sys/contrib/zstd/lib/decompress/huf_decompress_amd64.S (revision 5ff13fbc199bdf5f0572845351c68ee5ca828e71)
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