]> Cypherpunks.ru repositories - govpn.git/blob - internal/chacha20/asm_ppc64le.s
cde3fc989b729e5ebddb2f7b1cb0e2eb76ca4563
[govpn.git] / internal / chacha20 / asm_ppc64le.s
1 // Copyright 2019 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // Based on CRYPTOGAMS code with the following comment:
6 // # ====================================================================
7 // # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
8 // # project. The module is, however, dual licensed under OpenSSL and
9 // # CRYPTOGAMS licenses depending on where you obtain it. For further
10 // # details see http://www.openssl.org/~appro/cryptogams/.
11 // # ====================================================================
12
13 // Original code can be found at the link below:
14 // https://github.com/dot-asm/cryptogams/commit/a60f5b50ed908e91e5c39ca79126a4a876d5d8ff
15
16 // There are some differences between CRYPTOGAMS code and this one. The round
17 // loop for "_int" isn't the same as the original. Some adjustments were
18 // necessary because there are less vector registers available.  For example, some
19 // X variables (r12, r13, r14, and r15) share the same register used by the
20 // counter. The original code uses ctr to name the counter. Here we use CNT
21 // because golang uses CTR as the counter register name.
22
23 // +build ppc64le,!gccgo,!appengine
24
25 #include "textflag.h"
26
27 #define OUT  R3
28 #define INP  R4
29 #define LEN  R5
30 #define KEY  R6
31 #define CNT  R7
32
33 #define TEMP R8
34
35 #define X0   R11
36 #define X1   R12
37 #define X2   R14
38 #define X3   R15
39 #define X4   R16
40 #define X5   R17
41 #define X6   R18
42 #define X7   R19
43 #define X8   R20
44 #define X9   R21
45 #define X10  R22
46 #define X11  R23
47 #define X12  R24
48 #define X13  R25
49 #define X14  R26
50 #define X15  R27
51
52 #define CON0 X0
53 #define CON1 X1
54 #define CON2 X2
55 #define CON3 X3
56
57 #define KEY0 X4
58 #define KEY1 X5
59 #define KEY2 X6
60 #define KEY3 X7
61 #define KEY4 X8
62 #define KEY5 X9
63 #define KEY6 X10
64 #define KEY7 X11
65
66 #define CNT0 X12
67 #define CNT1 X13
68 #define CNT2 X14
69 #define CNT3 X15
70
71 #define TMP0 R9
72 #define TMP1 R10
73 #define TMP2 R28
74 #define TMP3 R29
75
76 #define CONSTS  R8
77
78 #define A0      V0
79 #define B0      V1
80 #define C0      V2
81 #define D0      V3
82 #define A1      V4
83 #define B1      V5
84 #define C1      V6
85 #define D1      V7
86 #define A2      V8
87 #define B2      V9
88 #define C2      V10
89 #define D2      V11
90 #define T0      V12
91 #define T1      V13
92 #define T2      V14
93
94 #define K0      V15
95 #define K1      V16
96 #define K2      V17
97 #define K3      V18
98 #define K4      V19
99 #define K5      V20
100
101 #define FOUR    V21
102 #define SIXTEEN V22
103 #define TWENTY4 V23
104 #define TWENTY  V24
105 #define TWELVE  V25
106 #define TWENTY5 V26
107 #define SEVEN   V27
108
109 #define INPPERM V28
110 #define OUTPERM V29
111 #define OUTMASK V30
112
113 #define DD0     V31
114 #define DD1     SEVEN
115 #define DD2     T0
116 #define DD3     T1
117 #define DD4     T2
118
119 DATA  ·consts+0x00(SB)/8, $0x3320646e61707865
120 DATA  ·consts+0x08(SB)/8, $0x6b20657479622d32
121 DATA  ·consts+0x10(SB)/8, $0x0000000000000001
122 DATA  ·consts+0x18(SB)/8, $0x0000000000000000
123 DATA  ·consts+0x20(SB)/8, $0x0000000000000004
124 DATA  ·consts+0x28(SB)/8, $0x0000000000000000
125 DATA  ·consts+0x30(SB)/8, $0x0a0b08090e0f0c0d
126 DATA  ·consts+0x38(SB)/8, $0x0203000106070405
127 DATA  ·consts+0x40(SB)/8, $0x090a0b080d0e0f0c
128 DATA  ·consts+0x48(SB)/8, $0x0102030005060704
129 GLOBL ·consts(SB), RODATA, $80
130
131 //func chaCha20_ctr32_vmx(out, inp *byte, len int, key *[32]byte, counter *[16]byte)
132 TEXT ·chaCha20_ctr32_vmx(SB),NOSPLIT|NOFRAME,$0
133         // Load the arguments inside the registers
134         MOVD out+0(FP), OUT
135         MOVD inp+8(FP), INP
136         MOVD len+16(FP), LEN
137         MOVD key+24(FP), KEY
138         MOVD counter+32(FP), CNT
139
140         MOVD $·consts(SB), CONSTS // point to consts addr
141
142         MOVD $16, X0
143         MOVD $32, X1
144         MOVD $48, X2
145         MOVD $64, X3
146         MOVD $31, X4
147         MOVD $15, X5
148
149         // Load key
150         LVX  (KEY)(R0), K1
151         LVSR (KEY)(R0), T0
152         LVX  (KEY)(X0), K2
153         LVX  (KEY)(X4), DD0
154
155         // Load counter
156         LVX  (CNT)(R0), K3
157         LVSR (CNT)(R0), T1
158         LVX  (CNT)(X5), DD1
159
160         // Load constants
161         LVX (CONSTS)(R0), K0
162         LVX (CONSTS)(X0), K5
163         LVX (CONSTS)(X1), FOUR
164         LVX (CONSTS)(X2), SIXTEEN
165         LVX (CONSTS)(X3), TWENTY4
166
167         // Align key and counter
168         VPERM K2,  K1, T0, K1
169         VPERM DD0, K2, T0, K2
170         VPERM DD1, K3, T1, K3
171
172         // Load counter to GPR
173         MOVWZ 0(CNT), CNT0
174         MOVWZ 4(CNT), CNT1
175         MOVWZ 8(CNT), CNT2
176         MOVWZ 12(CNT), CNT3
177
178         // Adjust vectors for the initial state
179         VADDUWM K3, K5, K3
180         VADDUWM K3, K5, K4
181         VADDUWM K4, K5, K5
182
183         // Synthesized constants
184         VSPLTISW $-12, TWENTY
185         VSPLTISW $12, TWELVE
186         VSPLTISW $-7, TWENTY5
187
188         VXOR T0, T0, T0
189         VSPLTISW $-1, OUTMASK
190         LVSR (INP)(R0), INPPERM
191         LVSL (OUT)(R0), OUTPERM
192         VPERM OUTMASK, T0, OUTPERM, OUTMASK
193
194 loop_outer_vmx:
195         // Load constant
196         MOVD $0x61707865, CON0
197         MOVD $0x3320646e, CON1
198         MOVD $0x79622d32, CON2
199         MOVD $0x6b206574, CON3
200
201         VOR K0, K0, A0
202         VOR K0, K0, A1
203         VOR K0, K0, A2
204         VOR K1, K1, B0
205
206         MOVD $10, TEMP
207
208         // Load key to GPR
209         MOVWZ 0(KEY), X4
210         MOVWZ 4(KEY), X5
211         MOVWZ 8(KEY), X6
212         MOVWZ 12(KEY), X7
213         VOR K1, K1, B1
214         VOR K1, K1, B2
215         MOVWZ 16(KEY), X8
216         MOVWZ  0(CNT), X12
217         MOVWZ 20(KEY), X9
218         MOVWZ 4(CNT), X13
219         VOR K2, K2, C0
220         VOR K2, K2, C1
221         MOVWZ 24(KEY), X10
222         MOVWZ 8(CNT), X14
223         VOR K2, K2, C2
224         VOR K3, K3, D0
225         MOVWZ 28(KEY), X11
226         MOVWZ 12(CNT), X15
227         VOR K4, K4, D1
228         VOR K5, K5, D2
229
230         MOVD X4, TMP0
231         MOVD X5, TMP1
232         MOVD X6, TMP2
233         MOVD X7, TMP3
234         VSPLTISW $7, SEVEN
235
236         MOVD TEMP, CTR
237
238 loop_vmx:
239         // CRYPTOGAMS uses a macro to create a loop using perl. This isn't possible
240         // using assembly macros.  Therefore, the macro expansion result was used
241         // in order to maintain the algorithm efficiency.
242         // This loop generates three keystream blocks using VMX instructions and,
243         // in parallel, one keystream block using scalar instructions.
244         ADD X4, X0, X0
245         ADD X5, X1, X1
246         VADDUWM A0, B0, A0
247         VADDUWM A1, B1, A1
248         ADD X6, X2, X2
249         ADD X7, X3, X3
250         VADDUWM A2, B2, A2
251         VXOR D0, A0, D0
252         XOR X0, X12, X12
253         XOR X1, X13, X13
254         VXOR D1, A1, D1
255         VXOR D2, A2, D2
256         XOR X2, X14, X14
257         XOR X3, X15, X15
258         VPERM D0, D0, SIXTEEN, D0
259         VPERM D1, D1, SIXTEEN, D1
260         ROTLW $16, X12, X12
261         ROTLW $16, X13, X13
262         VPERM D2, D2, SIXTEEN, D2
263         VADDUWM C0, D0, C0
264         ROTLW $16, X14, X14
265         ROTLW $16, X15, X15
266         VADDUWM C1, D1, C1
267         VADDUWM C2, D2, C2
268         ADD X12, X8, X8
269         ADD X13, X9, X9
270         VXOR B0, C0, T0
271         VXOR B1, C1, T1
272         ADD X14, X10, X10
273         ADD X15, X11, X11
274         VXOR B2, C2, T2
275         VRLW T0, TWELVE, B0
276         XOR X8, X4, X4
277         XOR X9, X5, X5
278         VRLW T1, TWELVE, B1
279         VRLW T2, TWELVE, B2
280         XOR X10, X6, X6
281         XOR X11, X7, X7
282         VADDUWM A0, B0, A0
283         VADDUWM A1, B1, A1
284         ROTLW $12, X4, X4
285         ROTLW $12, X5, X5
286         VADDUWM A2, B2, A2
287         VXOR D0, A0, D0
288         ROTLW $12, X6, X6
289         ROTLW $12, X7, X7
290         VXOR D1, A1, D1
291         VXOR D2, A2, D2
292         ADD X4, X0, X0
293         ADD X5, X1, X1
294         VPERM D0, D0, TWENTY4, D0
295         VPERM D1, D1, TWENTY4, D1
296         ADD X6, X2, X2
297         ADD X7, X3, X3
298         VPERM D2, D2, TWENTY4, D2
299         VADDUWM C0, D0, C0
300         XOR X0, X12, X12
301         XOR X1, X13, X13
302         VADDUWM C1, D1, C1
303         VADDUWM C2, D2, C2
304         XOR X2, X14, X14
305         XOR X3, X15, X15
306         VXOR B0, C0, T0
307         VXOR B1, C1, T1
308         ROTLW $8, X12, X12
309         ROTLW $8, X13, X13
310         VXOR B2, C2, T2
311         VRLW T0, SEVEN, B0
312         ROTLW $8, X14, X14
313         ROTLW $8, X15, X15
314         VRLW T1, SEVEN, B1
315         VRLW T2, SEVEN, B2
316         ADD X12, X8, X8
317         ADD X13, X9, X9
318         VSLDOI $8, C0, C0, C0
319         VSLDOI $8, C1, C1, C1
320         ADD X14, X10, X10
321         ADD X15, X11, X11
322         VSLDOI $8, C2, C2, C2
323         VSLDOI $12, B0, B0, B0
324         XOR X8, X4, X4
325         XOR X9, X5, X5
326         VSLDOI $12, B1, B1, B1
327         VSLDOI $12, B2, B2, B2
328         XOR X10, X6, X6
329         XOR X11, X7, X7
330         VSLDOI $4, D0, D0, D0
331         VSLDOI $4, D1, D1, D1
332         ROTLW $7, X4, X4
333         ROTLW $7, X5, X5
334         VSLDOI $4, D2, D2, D2
335         VADDUWM A0, B0, A0
336         ROTLW $7, X6, X6
337         ROTLW $7, X7, X7
338         VADDUWM A1, B1, A1
339         VADDUWM A2, B2, A2
340         ADD X5, X0, X0
341         ADD X6, X1, X1
342         VXOR D0, A0, D0
343         VXOR D1, A1, D1
344         ADD X7, X2, X2
345         ADD X4, X3, X3
346         VXOR D2, A2, D2
347         VPERM D0, D0, SIXTEEN, D0
348         XOR X0, X15, X15
349         XOR X1, X12, X12
350         VPERM D1, D1, SIXTEEN, D1
351         VPERM D2, D2, SIXTEEN, D2
352         XOR X2, X13, X13
353         XOR X3, X14, X14
354         VADDUWM C0, D0, C0
355         VADDUWM C1, D1, C1
356         ROTLW $16, X15, X15
357         ROTLW $16, X12, X12
358         VADDUWM C2, D2, C2
359         VXOR B0, C0, T0
360         ROTLW $16, X13, X13
361         ROTLW $16, X14, X14
362         VXOR B1, C1, T1
363         VXOR B2, C2, T2
364         ADD X15, X10, X10
365         ADD X12, X11, X11
366         VRLW T0, TWELVE, B0
367         VRLW T1, TWELVE, B1
368         ADD X13, X8, X8
369         ADD X14, X9, X9
370         VRLW T2, TWELVE, B2
371         VADDUWM A0, B0, A0
372         XOR X10, X5, X5
373         XOR X11, X6, X6
374         VADDUWM A1, B1, A1
375         VADDUWM A2, B2, A2
376         XOR X8, X7, X7
377         XOR X9, X4, X4
378         VXOR D0, A0, D0
379         VXOR D1, A1, D1
380         ROTLW $12, X5, X5
381         ROTLW $12, X6, X6
382         VXOR D2, A2, D2
383         VPERM D0, D0, TWENTY4, D0
384         ROTLW $12, X7, X7
385         ROTLW $12, X4, X4
386         VPERM D1, D1, TWENTY4, D1
387         VPERM D2, D2, TWENTY4, D2
388         ADD X5, X0, X0
389         ADD X6, X1, X1
390         VADDUWM C0, D0, C0
391         VADDUWM C1, D1, C1
392         ADD X7, X2, X2
393         ADD X4, X3, X3
394         VADDUWM C2, D2, C2
395         VXOR B0, C0, T0
396         XOR X0, X15, X15
397         XOR X1, X12, X12
398         VXOR B1, C1, T1
399         VXOR B2, C2, T2
400         XOR X2, X13, X13
401         XOR X3, X14, X14
402         VRLW T0, SEVEN, B0
403         VRLW T1, SEVEN, B1
404         ROTLW $8, X15, X15
405         ROTLW $8, X12, X12
406         VRLW T2, SEVEN, B2
407         VSLDOI $8, C0, C0, C0
408         ROTLW $8, X13, X13
409         ROTLW $8, X14, X14
410         VSLDOI $8, C1, C1, C1
411         VSLDOI $8, C2, C2, C2
412         ADD X15, X10, X10
413         ADD X12, X11, X11
414         VSLDOI $4, B0, B0, B0
415         VSLDOI $4, B1, B1, B1
416         ADD X13, X8, X8
417         ADD X14, X9, X9
418         VSLDOI $4, B2, B2, B2
419         VSLDOI $12, D0, D0, D0
420         XOR X10, X5, X5
421         XOR X11, X6, X6
422         VSLDOI $12, D1, D1, D1
423         VSLDOI $12, D2, D2, D2
424         XOR X8, X7, X7
425         XOR X9, X4, X4
426         ROTLW $7, X5, X5
427         ROTLW $7, X6, X6
428         ROTLW $7, X7, X7
429         ROTLW $7, X4, X4
430         BC 0x10, 0, loop_vmx
431
432         SUB $256, LEN, LEN
433
434         // Accumulate key block
435         ADD $0x61707865, X0, X0
436         ADD $0x3320646e, X1, X1
437         ADD $0x79622d32, X2, X2
438         ADD $0x6b206574, X3, X3
439         ADD TMP0, X4, X4
440         ADD TMP1, X5, X5
441         ADD TMP2, X6, X6
442         ADD TMP3, X7, X7
443         MOVWZ 16(KEY), TMP0
444         MOVWZ 20(KEY), TMP1
445         MOVWZ 24(KEY), TMP2
446         MOVWZ 28(KEY), TMP3
447         ADD TMP0, X8, X8
448         ADD TMP1, X9, X9
449         ADD TMP2, X10, X10
450         ADD TMP3, X11, X11
451
452         MOVWZ 12(CNT), TMP0
453         MOVWZ 8(CNT), TMP1
454         MOVWZ 4(CNT), TMP2
455         MOVWZ 0(CNT), TEMP
456         ADD TMP0, X15, X15
457         ADD TMP1, X14, X14
458         ADD TMP2, X13, X13
459         ADD TEMP, X12, X12
460
461         // Accumulate key block
462         VADDUWM A0, K0, A0
463         VADDUWM A1, K0, A1
464         VADDUWM A2, K0, A2
465         VADDUWM B0, K1, B0
466         VADDUWM B1, K1, B1
467         VADDUWM B2, K1, B2
468         VADDUWM C0, K2, C0
469         VADDUWM C1, K2, C1
470         VADDUWM C2, K2, C2
471         VADDUWM D0, K3, D0
472         VADDUWM D1, K4, D1
473         VADDUWM D2, K5, D2
474
475         // Increment counter
476         ADD $4, TEMP, TEMP
477         MOVW TEMP, 0(CNT)
478
479         VADDUWM K3, FOUR, K3
480         VADDUWM K4, FOUR, K4
481         VADDUWM K5, FOUR, K5
482
483         // XOR the input slice (INP) with the keystream, which is stored in GPRs (X0-X3).
484
485         // Load input (aligned or not)
486         MOVWZ 0(INP), TMP0
487         MOVWZ 4(INP), TMP1
488         MOVWZ 8(INP), TMP2
489         MOVWZ 12(INP), TMP3
490
491         // XOR with input
492         XOR TMP0, X0, X0
493         XOR TMP1, X1, X1
494         XOR TMP2, X2, X2
495         XOR TMP3, X3, X3
496         MOVWZ 16(INP), TMP0
497         MOVWZ 20(INP), TMP1
498         MOVWZ 24(INP), TMP2
499         MOVWZ 28(INP), TMP3
500         XOR TMP0, X4, X4
501         XOR TMP1, X5, X5
502         XOR TMP2, X6, X6
503         XOR TMP3, X7, X7
504         MOVWZ 32(INP), TMP0
505         MOVWZ 36(INP), TMP1
506         MOVWZ 40(INP), TMP2
507         MOVWZ 44(INP), TMP3
508         XOR TMP0, X8, X8
509         XOR TMP1, X9, X9
510         XOR TMP2, X10, X10
511         XOR TMP3, X11, X11
512         MOVWZ 48(INP), TMP0
513         MOVWZ 52(INP), TMP1
514         MOVWZ 56(INP), TMP2
515         MOVWZ 60(INP), TMP3
516         XOR TMP0, X12, X12
517         XOR TMP1, X13, X13
518         XOR TMP2, X14, X14
519         XOR TMP3, X15, X15
520
521         // Store output (aligned or not)
522         MOVW X0, 0(OUT)
523         MOVW X1, 4(OUT)
524         MOVW X2, 8(OUT)
525         MOVW X3, 12(OUT)
526
527         ADD $64, INP, INP // INP points to the end of the slice for the alignment code below
528
529         MOVW X4, 16(OUT)
530         MOVD $16, TMP0
531         MOVW X5, 20(OUT)
532         MOVD $32, TMP1
533         MOVW X6, 24(OUT)
534         MOVD $48, TMP2
535         MOVW X7, 28(OUT)
536         MOVD $64, TMP3
537         MOVW X8, 32(OUT)
538         MOVW X9, 36(OUT)
539         MOVW X10, 40(OUT)
540         MOVW X11, 44(OUT)
541         MOVW X12, 48(OUT)
542         MOVW X13, 52(OUT)
543         MOVW X14, 56(OUT)
544         MOVW X15, 60(OUT)
545         ADD $64, OUT, OUT
546
547         // Load input
548         LVX (INP)(R0), DD0
549         LVX (INP)(TMP0), DD1
550         LVX (INP)(TMP1), DD2
551         LVX (INP)(TMP2), DD3
552         LVX (INP)(TMP3), DD4
553         ADD $64, INP, INP
554
555         VPERM DD1, DD0, INPPERM, DD0 // Align input
556         VPERM DD2, DD1, INPPERM, DD1
557         VPERM DD3, DD2, INPPERM, DD2
558         VPERM DD4, DD3, INPPERM, DD3
559         VXOR A0, DD0, A0 // XOR with input
560         VXOR B0, DD1, B0
561         LVX (INP)(TMP0), DD1 // Keep loading input
562         VXOR C0, DD2, C0
563         LVX (INP)(TMP1), DD2
564         VXOR D0, DD3, D0
565         LVX (INP)(TMP2), DD3
566         LVX (INP)(TMP3), DD0
567         ADD $64, INP, INP
568         MOVD $63, TMP3 // 63 is not a typo
569         VPERM A0, A0, OUTPERM, A0
570         VPERM B0, B0, OUTPERM, B0
571         VPERM C0, C0, OUTPERM, C0
572         VPERM D0, D0, OUTPERM, D0
573
574         VPERM DD1, DD4, INPPERM, DD4 // Align input
575         VPERM DD2, DD1, INPPERM, DD1
576         VPERM DD3, DD2, INPPERM, DD2
577         VPERM DD0, DD3, INPPERM, DD3
578         VXOR A1, DD4, A1
579         VXOR B1, DD1, B1
580         LVX (INP)(TMP0), DD1 // Keep loading
581         VXOR C1, DD2, C1
582         LVX (INP)(TMP1), DD2
583         VXOR D1, DD3, D1
584         LVX (INP)(TMP2), DD3
585
586         // Note that the LVX address is always rounded down to the nearest 16-byte
587         // boundary, and that it always points to at most 15 bytes beyond the end of
588         // the slice, so we cannot cross a page boundary.
589         LVX (INP)(TMP3), DD4 // Redundant in aligned case.
590         ADD $64, INP, INP
591         VPERM A1, A1, OUTPERM, A1 // Pre-misalign output
592         VPERM B1, B1, OUTPERM, B1
593         VPERM C1, C1, OUTPERM, C1
594         VPERM D1, D1, OUTPERM, D1
595
596         VPERM DD1, DD0, INPPERM, DD0 // Align Input
597         VPERM DD2, DD1, INPPERM, DD1
598         VPERM DD3, DD2, INPPERM, DD2
599         VPERM DD4, DD3, INPPERM, DD3
600         VXOR A2, DD0, A2
601         VXOR B2, DD1, B2
602         VXOR C2, DD2, C2
603         VXOR D2, DD3, D2
604         VPERM A2, A2, OUTPERM, A2
605         VPERM B2, B2, OUTPERM, B2
606         VPERM C2, C2, OUTPERM, C2
607         VPERM D2, D2, OUTPERM, D2
608
609         ANDCC $15, OUT, X1 // Is out aligned?
610         MOVD OUT, X0
611
612         VSEL A0, B0, OUTMASK, DD0 // Collect pre-misaligned output
613         VSEL B0, C0, OUTMASK, DD1
614         VSEL C0, D0, OUTMASK, DD2
615         VSEL D0, A1, OUTMASK, DD3
616         VSEL A1, B1, OUTMASK, B0
617         VSEL B1, C1, OUTMASK, C0
618         VSEL C1, D1, OUTMASK, D0
619         VSEL D1, A2, OUTMASK, A1
620         VSEL A2, B2, OUTMASK, B1
621         VSEL B2, C2, OUTMASK, C1
622         VSEL C2, D2, OUTMASK, D1
623
624         STVX DD0, (OUT+TMP0)
625         STVX DD1, (OUT+TMP1)
626         STVX DD2, (OUT+TMP2)
627         ADD $64, OUT, OUT
628         STVX DD3, (OUT+R0)
629         STVX B0, (OUT+TMP0)
630         STVX C0, (OUT+TMP1)
631         STVX D0, (OUT+TMP2)
632         ADD $64, OUT, OUT
633         STVX A1, (OUT+R0)
634         STVX B1, (OUT+TMP0)
635         STVX C1, (OUT+TMP1)
636         STVX D1, (OUT+TMP2)
637         ADD $64, OUT, OUT
638
639         BEQ aligned_vmx
640
641         SUB X1, OUT, X2 // in misaligned case edges
642         MOVD $0, X3 // are written byte-by-byte
643
644 unaligned_tail_vmx:
645         STVEBX D2, (X2+X3)
646         ADD $1, X3, X3
647         CMPW X3, X1
648         BNE unaligned_tail_vmx
649         SUB X1, X0, X2
650
651 unaligned_head_vmx:
652         STVEBX A0, (X2+X1)
653         CMPW X1, $15
654         ADD $1, X1, X1
655         BNE unaligned_head_vmx
656
657         CMPU LEN, $255 // done with 256-byte block yet?
658         BGT loop_outer_vmx
659
660         JMP done_vmx
661
662 aligned_vmx:
663         STVX A0, (X0+R0)
664         CMPU LEN, $255 // done with 256-byte block yet?
665         BGT loop_outer_vmx
666
667 done_vmx:
668         RET