]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/check/crc64_x86.S
Updated the x86 assembler code:
[icculus/xz.git] / src / liblzma / check / crc64_x86.S
1 /*
2  * Speed-optimized CRC64 using slicing-by-four algorithm
3  * Instruction set: i386
4  * Optimized for:   i686
5  *
6  * This code has been put into the public domain by its authors:
7  * Igor Pavlov <http://7-zip.org/>
8  * Lasse Collin <lasse.collin@tukaani.org>
9  *
10  * This code needs lzma_crc64_table, which can be created using the
11  * following C code:
12
13 uint64_t lzma_crc64_table[4][256];
14
15 void
16 init_table(void)
17 {
18         static const uint64_t poly64 = UINT64_C(0xC96C5795D7870F42);
19
20         for (size_t s = 0; s < 4; ++s) {
21                 for (size_t b = 0; b < 256; ++b) {
22                         uint64_t r = s == 0 ? b : lzma_crc64_table[s - 1][b];
23
24                         for (size_t i = 0; i < 8; ++i) {
25                                 if (r & 1)
26                                         r = (r >> 1) ^ poly64;
27                                 else
28                                         r >>= 1;
29                         }
30
31                         lzma_crc64_table[s][b] = r;
32                 }
33         }
34 }
35
36  * The prototype of the CRC64 function:
37  * extern uint64_t lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc);
38  */
39
40 /*
41  * On some systems, the functions need to be prefixed. The prefix is
42  * usually an underscore.
43  */
44 #ifndef __USER_LABEL_PREFIX__
45 #       define __USER_LABEL_PREFIX__
46 #endif
47 #define MAKE_SYM_CAT(prefix, sym) prefix ## sym
48 #define MAKE_SYM(prefix, sym) MAKE_SYM_CAT(prefix, sym)
49 #define LZMA_CRC64 MAKE_SYM(__USER_LABEL_PREFIX__, lzma_crc64)
50 #define LZMA_CRC64_TABLE MAKE_SYM(__USER_LABEL_PREFIX__, lzma_crc64_table)
51
52 /*
53  * Solaris assembler doesn't have .p2align, and Darwin uses .align
54  * differently than GNU/Linux and Solaris.
55  */
56 #ifdef __MACH__
57 #       define ALIGN(pow2, abs) .align pow2
58 #else
59 #       define ALIGN(pow2, abs) .align abs
60 #endif
61
62         .text
63         .globl  LZMA_CRC64
64
65 #if !defined(__MACH__) && !defined(_WIN32)
66         .type   LZMA_CRC64, @function
67 #endif
68
69         ALIGN(4, 16)
70 LZMA_CRC64:
71         /*
72          * Register usage:
73          * %eax crc LSB
74          * %edx crc MSB
75          * %esi buf
76          * %edi size or buf + size
77          * %ebx lzma_crc64_table
78          * %ebp Table index
79          * %ecx Temporary
80          */
81         pushl   %ebx
82         pushl   %esi
83         pushl   %edi
84         pushl   %ebp
85         movl    0x14(%esp), %esi /* buf */
86         movl    0x18(%esp), %edi /* size */
87         movl    0x1C(%esp), %eax /* crc LSB */
88         movl    0x20(%esp), %edx /* crc MSB */
89
90         /*
91          * Store the address of lzma_crc64_table to %ebx. This is needed to
92          * get position-independent code (PIC).
93          *
94          * The PIC macro is defined by libtool, while __PIC__ is defined
95          * by GCC but only on some systems. Testing for both makes it simpler
96          * to test this code without libtool, and keeps the code working also
97          * when built with libtool but using something else than GCC.
98          */
99 #if !defined(PIC) && !defined(__PIC__)
100         /* Not PIC */
101         movl    $LZMA_CRC64_TABLE, %ebx
102 #elif defined(__MACH__)
103         /* Mach-O */
104         call    .L_get_pc
105 .L_pic:
106         leal    .L_lzma_crc64_table$non_lazy_ptr-.L_pic(%ebx), %ebx
107         movl    (%ebx), %ebx
108 #else
109         /* ELF */
110         call    .L_get_pc
111         addl    $_GLOBAL_OFFSET_TABLE_, %ebx
112         movl    LZMA_CRC64_TABLE@GOT(%ebx), %ebx
113 #endif
114
115         /* Complement the initial value. */
116         notl    %eax
117         notl    %edx
118
119 .L_align:
120         /*
121          * Check if there is enough input to use slicing-by-four.
122          * We need eight bytes, because the loop pre-reads four bytes.
123          */
124         cmpl    $8, %edi
125         jl      .L_rest
126
127         /* Check if we have reached alignment of four bytes. */
128         testl   $3, %esi
129         jz      .L_slice
130
131         /* Calculate CRC of the next input byte. */
132         movzbl  (%esi), %ebp
133         incl    %esi
134         movzbl  %al, %ecx
135         xorl    %ecx, %ebp
136         shrdl   $8, %edx, %eax
137         xorl    (%ebx, %ebp, 8), %eax
138         shrl    $8, %edx
139         xorl    4(%ebx, %ebp, 8), %edx
140         decl    %edi
141         jmp     .L_align
142
143 .L_slice:
144         /*
145          * If we get here, there's at least eight bytes of aligned input
146          * available. Make %edi multiple of four bytes. Store the possible
147          * remainder over the "size" variable in the argument stack.
148          */
149         movl    %edi, 0x18(%esp)
150         andl    $-4, %edi
151         subl    %edi, 0x18(%esp)
152
153         /*
154          * Let %edi be buf + size - 4 while running the main loop. This way
155          * we can compare for equality to determine when exit the loop.
156          */
157         addl    %esi, %edi
158         subl    $4, %edi
159
160         /* Read in the first four aligned bytes. */
161         movl    (%esi), %ecx
162
163 .L_loop:
164         xorl    %eax, %ecx
165         movzbl  %cl, %ebp
166         movl    0x1800(%ebx, %ebp, 8), %eax
167         xorl    %edx, %eax
168         movl    0x1804(%ebx, %ebp, 8), %edx
169         movzbl  %ch, %ebp
170         xorl    0x1000(%ebx, %ebp, 8), %eax
171         xorl    0x1004(%ebx, %ebp, 8), %edx
172         shrl    $16, %ecx
173         movzbl  %cl, %ebp
174         xorl    0x0800(%ebx, %ebp, 8), %eax
175         xorl    0x0804(%ebx, %ebp, 8), %edx
176         movzbl  %ch, %ebp
177         addl    $4, %esi
178         xorl    (%ebx, %ebp, 8), %eax
179         xorl    4(%ebx, %ebp, 8), %edx
180
181         /* Check for end of aligned input. */
182         cmpl    %edi, %esi
183
184         /*
185          * Copy the next input byte to %ecx. It is slightly faster to
186          * read it here than at the top of the loop.
187          */
188         movl    (%esi), %ecx
189         jl      .L_loop
190
191         /*
192          * Process the remaining four bytes, which we have already
193          * copied to %ecx.
194          */
195         xorl    %eax, %ecx
196         movzbl  %cl, %ebp
197         movl    0x1800(%ebx, %ebp, 8), %eax
198         xorl    %edx, %eax
199         movl    0x1804(%ebx, %ebp, 8), %edx
200         movzbl  %ch, %ebp
201         xorl    0x1000(%ebx, %ebp, 8), %eax
202         xorl    0x1004(%ebx, %ebp, 8), %edx
203         shrl    $16, %ecx
204         movzbl  %cl, %ebp
205         xorl    0x0800(%ebx, %ebp, 8), %eax
206         xorl    0x0804(%ebx, %ebp, 8), %edx
207         movzbl  %ch, %ebp
208         addl    $4, %esi
209         xorl    (%ebx, %ebp, 8), %eax
210         xorl    4(%ebx, %ebp, 8), %edx
211
212         /* Copy the number of remaining bytes to %edi. */
213         movl    0x18(%esp), %edi
214
215 .L_rest:
216         /* Check for end of input. */
217         testl   %edi, %edi
218         jz      .L_return
219
220         /* Calculate CRC of the next input byte. */
221         movzbl  (%esi), %ebp
222         incl    %esi
223         movzbl  %al, %ecx
224         xorl    %ecx, %ebp
225         shrdl   $8, %edx, %eax
226         xorl    (%ebx, %ebp, 8), %eax
227         shrl    $8, %edx
228         xorl    4(%ebx, %ebp, 8), %edx
229         decl    %edi
230         jmp     .L_rest
231
232 .L_return:
233         /* Complement the final value. */
234         notl    %eax
235         notl    %edx
236
237         popl    %ebp
238         popl    %edi
239         popl    %esi
240         popl    %ebx
241         ret
242
243 #if defined(PIC) || defined(__PIC__)
244         ALIGN(4, 16)
245 .L_get_pc:
246         movl    (%esp), %ebx
247         ret
248 #endif
249
250 #if defined(__MACH__) && (defined(PIC) || defined(__PIC__))
251         /* Mach-O PIC */
252         .section __IMPORT,__pointers,non_lazy_symbol_pointers
253 .L_lzma_crc64_table$non_lazy_ptr:
254         .indirect_symbol LZMA_CRC64_TABLE
255         .long 0
256
257 #elif defined(_WIN32)
258         /* This is equivalent of __declspec(dllexport). */
259         .section .drectve
260         .ascii " -export:lzma_crc64"
261
262 #else
263         /* ELF */
264         .size   LZMA_CRC64, .-LZMA_CRC64
265 #endif
266
267 /*
268  * This is needed to support non-executable stack. It's ugly to
269  * use __linux__ here, but I don't know a way to detect when
270  * we are using GNU assembler.
271  */
272 #if defined(__ELF__) && defined(__linux__)
273         .section        .note.GNU-stack,"",@progbits
274 #endif