Add CFI unwind assembly directives for 64-bit ARM assembly
[libgcrypt.git] / cipher / crc-armv8-aarch64-ce.S
1 /* crc-armv8-aarch64-ce.S - ARMv8/CE PMULL accelerated CRC implementation
2  * Copyright (C) 2019 Jussi Kivilinna <jussi.kivilinna@iki.fi>
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "asm-common-aarch64.h"
21
22 #if defined(__AARCH64EL__) && \
23     defined(HAVE_COMPATIBLE_GCC_AARCH64_PLATFORM_AS) && \
24     defined(HAVE_GCC_INLINE_ASM_AARCH64_CRYPTO)
25
26 .cpu generic+simd+crypto
27
28 .text
29
30 #define GET_DATA_POINTER(reg, name) \
31                 adrp    reg, :got:name ; \
32                 ldr     reg, [reg, #:got_lo12:name] ;
33
34 /* Structure of crc32_consts_s */
35
36 #define consts_k(idx)    ((idx) * 8)
37 #define consts_my_p(idx) (consts_k(6) + (idx) * 8)
38
39 /* Constants */
40
41 .align 6
42 .Lcrc32_constants:
43 .Lcrc32_partial_fold_input_mask:
44   .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
45   .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
46 .Lcrc32_refl_shuf_shift:
47   .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
48   .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
49   .byte 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
50   .byte 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
51 .Lcrc32_shuf_shift:
52   .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
53   .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
54 .Lcrc32_bswap_shuf:
55   .byte 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08
56   .byte 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00
57   .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
58   .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
59
60
61 /*
62  * void _gcry_crc32r_armv8_ce_bulk (u32 *pcrc, const byte *inbuf, size_t inlen,
63  *                                  const struct crc32_consts_s *consts);
64  */
65 .align 3
66 .globl _gcry_crc32r_armv8_ce_bulk
67 ELF(.type  _gcry_crc32r_armv8_ce_bulk,%function;)
68 _gcry_crc32r_armv8_ce_bulk:
69   /* input:
70    *    x0: pcrc
71    *    x1: inbuf
72    *    x2: inlen
73    *    x3: consts
74    */
75   CFI_STARTPROC()
76
77   GET_DATA_POINTER(x7, .Lcrc32_constants)
78   add x9, x3, #consts_k(5 - 1)
79   cmp x2, #128
80
81   b.lo .Lcrc32r_fold_by_one_setup
82
83   eor v4.16b, v4.16b, v4.16b
84   add x4, x3, #consts_k(1 - 1)
85   ld1 {v4.s}[0], [x0]             /* load pcrc */
86   ld1 {v0.16b-v3.16b}, [x1], #64  /* load 64 bytes of input */
87   sub x2, x2, #64
88   ld1 {v6.16b}, [x4]
89   eor v0.16b, v0.16b, v4.16b
90
91   add x4, x3, #consts_k(3 - 1)
92   add x5, x3, #consts_my_p(0)
93
94 .Lcrc32r_fold_by_four:
95
96   /* Fold by 4. */
97   ld1 {v16.16b-v19.16b}, [x1], #64 /* load 64 bytes of input */
98   sub x2, x2, #64
99   pmull v20.1q, v0.1d, v6.1d
100   pmull v21.1q, v1.1d, v6.1d
101   pmull v22.1q, v2.1d, v6.1d
102   pmull v23.1q, v3.1d, v6.1d
103   cmp x2, #64
104   pmull2 v24.1q, v0.2d, v6.2d
105   pmull2 v25.1q, v1.2d, v6.2d
106   pmull2 v26.1q, v2.2d, v6.2d
107   pmull2 v27.1q, v3.2d, v6.2d
108   eor v0.16b, v20.16b, v16.16b
109   eor v1.16b, v21.16b, v17.16b
110   eor v2.16b, v22.16b, v18.16b
111   eor v3.16b, v23.16b, v19.16b
112   eor v0.16b, v0.16b, v24.16b
113   eor v1.16b, v1.16b, v25.16b
114   eor v2.16b, v2.16b, v26.16b
115   eor v3.16b, v3.16b, v27.16b
116   b.hs .Lcrc32r_fold_by_four
117
118   ld1 {v6.16b}, [x4]
119   ld1 {v5.16b}, [x5]
120
121   cmp x2, #16
122
123   /* Fold 4 to 1. */
124
125   pmull v16.1q, v0.1d, v6.1d
126   pmull2 v4.1q, v0.2d, v6.2d
127   eor v0.16b, v16.16b, v1.16b
128   eor v0.16b, v0.16b, v4.16b
129
130   pmull v16.1q, v0.1d, v6.1d
131   pmull2 v4.1q, v0.2d, v6.2d
132   eor v0.16b, v16.16b, v2.16b
133   eor v0.16b, v0.16b, v4.16b
134
135   pmull v16.1q, v0.1d, v6.1d
136   pmull2 v4.1q, v0.2d, v6.2d
137   eor v0.16b, v16.16b, v3.16b
138   eor v0.16b, v0.16b, v4.16b
139
140   b.lo .Lcrc32r_fold_by_one_done
141   b .Lcrc32r_fold_by_one
142
143 .Lcrc32r_fold_by_one_setup:
144
145   eor v1.16b, v1.16b, v1.16b
146   add x4, x3, #consts_k(3 - 1)
147   add x5, x3, #consts_my_p(0)
148   sub x2, x2, #16
149   ld1 {v1.s}[0], [x0]             /* load pcrc */
150   ld1 {v0.16b}, [x1], #16         /* load 16 bytes of input */
151   cmp x2, #16
152   ld1 {v6.16b}, [x4]              /* load k3k4 */
153   ld1 {v5.16b}, [x5]              /* load my_p */
154   eor v0.16b, v0.16b, v1.16b
155   b.lo .Lcrc32r_fold_by_one_done
156
157 .Lcrc32r_fold_by_one:
158   sub x2, x2, #16
159   ld1 {v2.16b}, [x1], #16         /* load 16 bytes of input */
160   pmull v3.1q, v0.1d, v6.1d
161   pmull2 v1.1q, v0.2d, v6.2d
162   cmp x2, #16
163   eor v0.16b, v3.16b, v2.16b
164   eor v0.16b, v0.16b, v1.16b
165
166   b.hs .Lcrc32r_fold_by_one
167
168 .Lcrc32r_fold_by_one_done:
169
170   cmp x2, #0
171   b.eq .Lcrc32r_final_fold
172
173   /* Partial fold. */
174
175   add x4, x7, #.Lcrc32_refl_shuf_shift - .Lcrc32_constants
176   add x5, x7, #.Lcrc32_refl_shuf_shift - .Lcrc32_constants + 16
177   add x6, x7, #.Lcrc32_partial_fold_input_mask - .Lcrc32_constants
178   sub x8, x2, #16
179   add x4, x4, x2
180   add x5, x5, x2
181   add x6, x6, x2
182   add x8, x1, x8
183
184   /* Load last input and add padding zeros. */
185   ld1 {v4.16b}, [x4]
186   eor x2, x2, x2
187   ld1 {v3.16b}, [x5]
188   ld1 {v2.16b}, [x6]
189   tbl v30.16b, {v0.16b}, v4.16b
190   ld1 {v4.16b}, [x8]
191   tbl v1.16b, {v0.16b}, v3.16b
192
193   pmull v0.1q, v30.1d, v6.1d
194   and v2.16b, v2.16b, v4.16b
195   pmull2 v31.1q, v30.2d, v6.2d
196   orr v2.16b, v2.16b, v1.16b
197   eor v0.16b, v0.16b, v31.16b
198   eor v0.16b, v0.16b, v2.16b
199
200 .Lcrc32r_final_fold:
201
202   /* Final fold. */
203
204   eor v2.16b, v2.16b, v2.16b      /* zero reg */
205   ld1 {v7.16b}, [x9]
206
207   /* reduce 128-bits to 96-bits */
208   ext v6.16b, v6.16b, v6.16b, #8  /* swap high and low parts */
209   mov v1.16b, v0.16b
210   pmull v0.1q, v0.1d, v6.1d
211   ext v6.16b, v5.16b, v5.16b, #8  /* swap high and low parts */
212   ext v1.16b, v1.16b, v2.16b, #8  /* high to low, high zeroed */
213   eor v3.16b, v0.16b, v1.16b
214
215   /* reduce 96-bits to 64-bits */
216   eor v1.16b, v1.16b, v1.16b
217   ext v0.16b, v3.16b, v2.16b, #4  /* [00][00][x2][x1] */
218   mov v1.s[0], v3.s[0]            /* [00][00][00][x0] */
219   eor v3.16b, v3.16b, v3.16b
220   pmull v1.1q, v1.1d, v7.1d       /* [00][00][xx][xx] */
221   eor v0.16b, v0.16b, v1.16b      /* top 64-bit are zero */
222
223   /* barrett reduction */
224   mov v3.s[1], v0.s[0]            /* [00][00][x1][00] */
225   ext v0.16b, v2.16b, v0.16b, #12 /* [??][x1][??][00] */
226   pmull v1.1q, v3.1d, v5.1d       /* [00][xx][xx][00] */
227   pmull v1.1q, v1.1d, v6.1d       /* [00][xx][xx][00] */
228   eor v0.16b, v0.16b, v1.16b
229
230   /* store CRC */
231   st1 {v0.s}[2], [x0]
232
233   ret
234   CFI_ENDPROC()
235 ELF(.size _gcry_crc32r_armv8_ce_bulk,.-_gcry_crc32r_armv8_ce_bulk;)
236
237 /*
238  * void _gcry_crc32r_armv8_ce_reduction_4 (u32 *pcrc, u32 data, u32 crc,
239  *                                         const struct crc32_consts_s *consts);
240  */
241 .align 3
242 .globl _gcry_crc32r_armv8_ce_reduction_4
243 ELF(.type  _gcry_crc32r_armv8_ce_reduction_4,%function;)
244 _gcry_crc32r_armv8_ce_reduction_4:
245   /* input:
246    *    w0: data
247    *    w1: crc
248    *    x2: crc32 constants
249    */
250   CFI_STARTPROC()
251
252   eor v0.16b, v0.16b, v0.16b
253   add x2, x2, #consts_my_p(0)
254   eor v1.16b, v1.16b, v1.16b
255   ld1 {v5.16b}, [x2]
256
257   mov v0.s[0], w0
258   pmull v0.1q, v0.1d, v5.1d     /* [00][00][xx][xx] */
259   mov v1.s[1], w1
260   mov v0.s[2], v0.s[0]          /* [00][x0][x1][x0] */
261   pmull2 v0.1q, v0.2d, v5.2d    /* [00][00][xx][xx] */
262   eor v0.16b, v0.16b, v1.16b
263
264   mov w0, v0.s[1]
265
266   ret
267   CFI_ENDPROC()
268 ELF(.size _gcry_crc32r_armv8_ce_reduction_4,.-_gcry_crc32r_armv8_ce_reduction_4;)
269
270 /*
271  * void _gcry_crc32_armv8_ce_bulk (u32 *pcrc, const byte *inbuf, size_t inlen,
272  *                                 const struct crc32_consts_s *consts);
273  */
274 .align 3
275 .globl _gcry_crc32_armv8_ce_bulk
276 ELF(.type  _gcry_crc32_armv8_ce_bulk,%function;)
277 _gcry_crc32_armv8_ce_bulk:
278   /* input:
279    *    x0: pcrc
280    *    x1: inbuf
281    *    x2: inlen
282    *    x3: consts
283    */
284   CFI_STARTPROC()
285
286   GET_DATA_POINTER(x7, .Lcrc32_constants)
287   add x4, x7, #.Lcrc32_bswap_shuf - .Lcrc32_constants
288   cmp x2, #128
289   ld1 {v7.16b}, [x4]
290
291   b.lo .Lcrc32_fold_by_one_setup
292
293   eor v4.16b, v4.16b, v4.16b
294   add x4, x3, #consts_k(1 - 1)
295   ld1 {v4.s}[0], [x0]            /* load pcrc */
296   ld1 {v0.16b-v3.16b}, [x1], #64 /* load 64 bytes of input */
297   sub x2, x2, #64
298   ld1 {v6.16b}, [x4]
299   eor v0.16b, v0.16b, v4.16b
300   ext v4.16b, v6.16b, v6.16b, #8
301   tbl v0.16b, { v0.16b }, v7.16b /* byte swap */
302   tbl v1.16b, { v1.16b }, v7.16b /* byte swap */
303   tbl v2.16b, { v2.16b }, v7.16b /* byte swap */
304   tbl v3.16b, { v3.16b }, v7.16b /* byte swap */
305
306   add x4, x3, #consts_k(3 - 1)
307   add x5, x3, #consts_my_p(0)
308
309 .Lcrc32_fold_by_four:
310
311   /* Fold by 4. */
312   ld1 {v16.16b-v19.16b}, [x1], #64 /* load 64 bytes of input */
313   sub x2, x2, #64
314   tbl v16.16b, { v16.16b }, v7.16b /* byte swap */
315   tbl v17.16b, { v17.16b }, v7.16b /* byte swap */
316   tbl v18.16b, { v18.16b }, v7.16b /* byte swap */
317   tbl v19.16b, { v19.16b }, v7.16b /* byte swap */
318   cmp x2, #64
319   pmull2 v20.1q, v0.2d, v4.2d
320   pmull2 v21.1q, v1.2d, v4.2d
321   pmull2 v22.1q, v2.2d, v4.2d
322   pmull2 v23.1q, v3.2d, v4.2d
323   pmull v24.1q, v0.1d, v4.1d
324   pmull v25.1q, v1.1d, v4.1d
325   pmull v26.1q, v2.1d, v4.1d
326   pmull v27.1q, v3.1d, v4.1d
327   eor v0.16b, v20.16b, v16.16b
328   eor v1.16b, v21.16b, v17.16b
329   eor v2.16b, v22.16b, v18.16b
330   eor v3.16b, v23.16b, v19.16b
331   eor v0.16b, v0.16b, v24.16b
332   eor v1.16b, v1.16b, v25.16b
333   eor v2.16b, v2.16b, v26.16b
334   eor v3.16b, v3.16b, v27.16b
335   b.hs .Lcrc32_fold_by_four
336
337   ld1 {v6.16b}, [x4]
338   ld1 {v5.16b}, [x5]
339   ext v6.16b, v6.16b, v6.16b, #8
340   ext v5.16b, v5.16b, v5.16b, #8
341
342   cmp x2, #16
343
344   /* Fold 4 to 1. */
345
346   pmull2 v16.1q, v0.2d, v6.2d
347   pmull v4.1q, v0.1d, v6.1d
348   eor v0.16b, v16.16b, v1.16b
349   eor v0.16b, v0.16b, v4.16b
350
351   pmull2 v16.1q, v0.2d, v6.2d
352   pmull v4.1q, v0.1d, v6.1d
353   eor v0.16b, v16.16b, v2.16b
354   eor v0.16b, v0.16b, v4.16b
355
356   pmull2 v16.1q, v0.2d, v6.2d
357   pmull v4.1q, v0.1d, v6.1d
358   eor v0.16b, v16.16b, v3.16b
359   eor v0.16b, v0.16b, v4.16b
360
361   b.lo .Lcrc32_fold_by_one_done
362   b .Lcrc32_fold_by_one
363
364 .Lcrc32_fold_by_one_setup:
365
366   eor v1.16b, v1.16b, v1.16b
367   add x4, x3, #consts_k(3 - 1)
368   add x5, x3, #consts_my_p(0)
369   ld1 {v1.s}[0], [x0]            /* load pcrc */
370   sub x2, x2, #16
371   ld1 {v0.16b}, [x1], #16        /* load 16 bytes of input */
372   ld1 {v6.16b}, [x4]             /* load k3k4 */
373   ld1 {v5.16b}, [x5]             /* load my_p */
374   eor v0.16b, v0.16b, v1.16b
375   cmp x2, #16
376   ext v6.16b, v6.16b, v6.16b, #8 /* swap high and low parts */
377   ext v5.16b, v5.16b, v5.16b, #8 /* swap high and low parts */
378   tbl v0.16b, { v0.16b }, v7.16b /* byte swap */
379   b.lo .Lcrc32_fold_by_one_done
380
381 .Lcrc32_fold_by_one:
382   sub x2, x2, #16
383   ld1 {v2.16b}, [x1], #16        /* load 16 bytes of input */
384   pmull2 v3.1q, v0.2d, v6.2d
385   tbl v2.16b, { v2.16b }, v7.16b /* byte swap */
386   pmull v1.1q, v0.1d, v6.1d
387   cmp x2, #16
388   eor v0.16b, v3.16b, v2.16b
389   eor v0.16b, v0.16b, v1.16b
390
391   b.hs .Lcrc32_fold_by_one
392
393 .Lcrc32_fold_by_one_done:
394
395   cmp x2, #0
396   b.eq .Lcrc32_final_fold
397
398   /* Partial fold. */
399
400   add x4, x7, #.Lcrc32_refl_shuf_shift - .Lcrc32_constants + 32
401   add x5, x7, #.Lcrc32_shuf_shift - .Lcrc32_constants + 16
402   add x6, x7, #.Lcrc32_partial_fold_input_mask - .Lcrc32_constants
403   sub x8, x2, #16
404   sub x4, x4, x2
405   add x5, x5, x2
406   add x6, x6, x2
407   add x8, x1, x8
408
409   /* Load last input and add padding zeros. */
410   ld1 {v4.16b}, [x4]
411   eor x2, x2, x2
412   ld1 {v3.16b}, [x5]
413   ld1 {v2.16b}, [x6]
414   tbl v30.16b, {v0.16b}, v4.16b
415   ld1 {v4.16b}, [x8]
416   tbl v1.16b, {v0.16b}, v3.16b
417   and v2.16b, v2.16b, v4.16b
418
419   pmull2 v0.1q, v30.2d, v6.2d
420   orr v2.16b, v2.16b, v1.16b
421   pmull v1.1q, v30.1d, v6.1d
422   tbl v2.16b, {v2.16b}, v7.16b   /* byte swap */
423   eor v0.16b, v0.16b, v1.16b
424   eor v0.16b, v0.16b, v2.16b
425
426 .Lcrc32_final_fold:
427
428   /* Final fold. */
429
430   eor v2.16b, v2.16b, v2.16b     /* zero reg */
431
432   /* reduce 128-bits to 96-bits */
433   add x4, x3, #consts_k(4)
434   ext v3.16b, v6.16b, v6.16b, #8 /* swap high and low parts */
435   eor v6.16b, v6.16b, v6.16b
436   mov v1.16b, v0.16b
437   pmull2 v0.1q, v0.2d, v3.2d
438   ld1 {v6.d}[1], [x4]            /* load k4 */
439   ext v1.16b, v2.16b, v1.16b, #8 /* low to high, low zeroed */
440   eor v3.16b, v0.16b, v1.16b     /* bottom 32-bit are zero */
441
442   /* reduce 96-bits to 64-bits */
443   eor v0.16b, v0.16b, v0.16b
444   eor v1.16b, v1.16b, v1.16b
445   mov v0.s[1], v3.s[1]           /* [00][00][x1][00] */
446   mov v1.s[2], v3.s[3]           /* [00][x3][00][00] */
447   mov v0.s[2], v3.s[2]           /* [00][x2][x1][00] */
448   eor v3.16b, v3.16b, v3.16b
449   pmull2 v1.1q, v1.2d, v6.2d     /* [00][xx][xx][00] */
450   eor v0.16b, v0.16b, v1.16b     /* top and bottom 32-bit are zero */
451
452   /* barrett reduction */
453   mov v3.s[0], v0.s[1]           /* [00][00][00][x1] */
454   pmull2 v0.1q, v0.2d, v5.2d     /* [00][xx][xx][xx] */
455   ext v0.16b, v0.16b, v2.16b, #4 /* [00][00][xx][xx] */
456   pmull v0.1q, v0.1d, v5.1d
457   eor v0.16b, v0.16b, v3.16b
458
459   /* store CRC in input endian */
460   rev32 v0.8b, v0.8b             /* byte swap */
461   st1 {v0.s}[0], [x0]
462
463   ret
464   CFI_ENDPROC()
465 ELF(.size _gcry_crc32_armv8_ce_bulk,.-_gcry_crc32_armv8_ce_bulk;)
466
467 /*
468  * void _gcry_crc32_armv8_ce_reduction_4 (u32 *pcrc, u32 data, u32 crc,
469  *                                        const struct crc32_consts_s *consts);
470  */
471 .align 3
472 .globl _gcry_crc32_armv8_ce_reduction_4
473 ELF(.type  _gcry_crc32_armv8_ce_reduction_4,%function;)
474 _gcry_crc32_armv8_ce_reduction_4:
475   /* input:
476    *    w0: data
477    *    w1: crc
478    *    x2: crc32 constants
479    */
480   CFI_STARTPROC()
481
482   eor v0.16b, v0.16b, v0.16b
483   add x2, x2, #consts_my_p(0)
484   eor v1.16b, v1.16b, v1.16b
485   ld1 {v5.16b}, [x2]
486
487   mov v0.s[1], w0
488   pmull v0.1q, v0.1d, v5.1d     /* [00][xx][xx][00] */
489   mov v1.s[0], w1
490   pmull2 v0.1q, v0.2d, v5.2d    /* [00][00][xx][xx] */
491   eor v0.16b, v0.16b, v1.16b
492
493   rev32 v0.8b, v0.8b            /* Return in input endian */
494   mov w0, v0.s[0]
495
496   ret
497   CFI_ENDPROC()
498 ELF(.size _gcry_crc32_armv8_ce_reduction_4,.-_gcry_crc32_armv8_ce_reduction_4;)
499
500 #endif