Further TLS extension updates
[oweals/openssl.git] / crypto / md5 / asm / md5-ia64.S
1 /* Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
2
3 Permission is hereby granted, free of charge, to any person obtaining
4 a copy of this software and associated documentation files (the
5 "Software"), to deal in the Software without restriction, including
6 without limitation the rights to use, copy, modify, merge, publish,
7 distribute, sublicense, and/or sell copies of the Software, and to
8 permit persons to whom the Software is furnished to do so, subject to
9 the following conditions:
10
11 The above copyright notice and this permission notice shall be
12 included in all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
21
22 //      Common registers are assigned as follows:
23 //
24 //      COMMON
25 //
26 //      t0              Const Tbl Ptr   TPtr
27 //      t1              Round Constant  TRound
28 //      t4              Block residual  LenResid
29 //      t5              Residual Data   DTmp
30 //
31 //      {in,out}0       Block 0 Cycle   RotateM0
32 //      {in,out}1       Block Value 12  M12
33 //      {in,out}2       Block Value 8   M8
34 //      {in,out}3       Block Value 4   M4
35 //      {in,out}4       Block Value 0   M0
36 //      {in,out}5       Block 1 Cycle   RotateM1
37 //      {in,out}6       Block Value 13  M13
38 //      {in,out}7       Block Value 9   M9
39 //      {in,out}8       Block Value 5   M5
40 //      {in,out}9       Block Value 1   M1
41 //      {in,out}10      Block 2 Cycle   RotateM2
42 //      {in,out}11      Block Value 14  M14
43 //      {in,out}12      Block Value 10  M10
44 //      {in,out}13      Block Value 6   M6
45 //      {in,out}14      Block Value 2   M2
46 //      {in,out}15      Block 3 Cycle   RotateM3
47 //      {in,out}16      Block Value 15  M15
48 //      {in,out}17      Block Value 11  M11
49 //      {in,out}18      Block Value 7   M7
50 //      {in,out}19      Block Value 3   M3
51 //      {in,out}20      Scratch                 Z
52 //      {in,out}21      Scratch                 Y
53 //      {in,out}22      Scratch                 X
54 //      {in,out}23      Scratch                 W
55 //      {in,out}24      Digest A                A
56 //      {in,out}25      Digest B                B
57 //      {in,out}26      Digest C                C
58 //      {in,out}27      Digest D                D
59 //      {in,out}28      Active Data Ptr DPtr
60 //      in28            Dummy Value             -
61 //      out28           Dummy Value             -
62 //      bt0                     Coroutine Link  QUICK_RTN
63 //
64 ///     These predicates are used for computing the padding block(s) and
65 ///     are shared between the driver and digest co-routines
66 //
67 //      pt0                     Extra Pad Block pExtra
68 //      pt1                     Load next word  pLoad
69 //      pt2                     Skip next word  pSkip
70 //      pt3                     Search for Pad  pNoPad
71 //      pt4                     Pad Word 0              pPad0
72 //      pt5                     Pad Word 1              pPad1
73 //      pt6                     Pad Word 2              pPad2
74 //      pt7                     Pad Word 3              pPad3
75
76 #define DTmp            r19
77 #define LenResid        r18
78 #define QUICK_RTN       b6
79 #define TPtr            r14
80 #define TRound          r15
81 #define pExtra          p6
82 #define pLoad           p7
83 #define pNoPad          p9
84 #define pPad0           p10
85 #define pPad1           p11
86 #define pPad2           p12
87 #define pPad3           p13
88 #define pSkip           p8
89 //      This two below shall remain constant througout whole routine
90 #define pDataOrder      p14
91 #define pHostOrder      p15
92
93 #define A_              out24
94 #define B_              out25
95 #define C_              out26
96 #define D_              out27
97 #define DPtr_           out28
98 #define M0_             out4
99 #define M1_             out9
100 #define M10_            out12
101 #define M11_            out17
102 #define M12_            out1
103 #define M13_            out6
104 #define M14_            out11
105 #define M15_            out16
106 #define M2_             out14
107 #define M3_             out19
108 #define M4_             out3
109 #define M5_             out8
110 #define M6_             out13
111 #define M7_             out18
112 #define M8_             out2
113 #define M9_             out7
114 #define RotateM0_       out0
115 #define RotateM1_       out5
116 #define RotateM2_       out10
117 #define RotateM3_       out15
118 #define W_              out23
119 #define X_              out22
120 #define Y_              out21
121 #define Z_              out20
122
123 #define A               in24
124 #define B               in25
125 #define C               in26
126 #define D               in27
127 #define DPtr            in28
128 #define M0              in4
129 #define M1              in9
130 #define M10             in12
131 #define M11             in17
132 #define M12             in1
133 #define M13             in6
134 #define M14             in11
135 #define M15             in16
136 #define M2              in14
137 #define M3              in19
138 #define M4              in3
139 #define M5              in8
140 #define M6              in13
141 #define M7              in18
142 #define M8              in2
143 #define M9              in7
144 #define RotateM0        in0
145 #define RotateM1        in5
146 #define RotateM2        in10
147 #define RotateM3        in15
148 #define W               in23
149 #define X               in22
150 #define Y               in21
151 #define Z               in20
152
153 /* register stack configuration for md5_block_asm_host_order(): */
154 #define MD5_NINP        3
155 #define MD5_NLOC        0
156 #define MD5_NOUT        29
157 #define MD5_NROT        0
158
159 /* register stack configuration for helpers: */
160 #define _NINPUTS        MD5_NOUT
161 #define _NLOCALS        0
162 #define _NOUTPUT        0
163 #define _NROTATE        24      /* this must be <= _NINPUTS */
164
165 #if defined(_HPUX_SOURCE) && !defined(_LP64)
166 #define ADDP    addp4
167 #else
168 #define ADDP    add
169 #endif
170
171 #if defined(_HPUX_SOURCE) || defined(B_ENDIAN)
172 #define HOST_IS_BIG_ENDIAN
173 #endif
174
175 //      Macros for getting the left and right portions of little-endian words
176
177 #define GETLW(dst, src, align)  dep.z dst = src, 32 - 8 * align, 8 * align
178 #define GETRW(dst, src, align)  extr.u dst = src, 8 * align, 32 - 8 * align
179
180 //      MD5 driver
181 //
182 //              Reads an input block, then calls the digest block
183 //              subroutine and adds the results to the accumulated
184 //              digest.  It allocates 32 outs which the subroutine
185 //              uses as it's inputs and rotating
186 //              registers. Initializes the round constant pointer and
187 //              takes care of saving/restoring ar.lc
188 //
189 ///     INPUT
190 //
191 //      in0             Context Ptr             CtxPtr0
192 //      in1             Input Data Ptr          DPtrIn
193 //      in2             Integral Blocks         BlockCount
194 //      rp              Return Address          -
195 //
196 ///     CODE
197 //
198 //      v2              Input Align             InAlign
199 //      t0              Shared w/digest         -
200 //      t1              Shared w/digest         -
201 //      t2              Shared w/digest         -
202 //      t3              Shared w/digest         -
203 //      t4              Shared w/digest         -
204 //      t5              Shared w/digest         -
205 //      t6              PFS Save                PFSSave
206 //      t7              ar.lc Save              LCSave
207 //      t8              Saved PR                PRSave
208 //      t9              2nd CtxPtr              CtxPtr1
209 //      t10             Table Base              CTable
210 //      t11             Table[0]                CTable0
211 //      t13             Accumulator A           AccumA
212 //      t14             Accumulator B           AccumB
213 //      t15             Accumulator C           AccumC
214 //      t16             Accumulator D           AccumD
215 //      pt0             Shared w/digest         -
216 //      pt1             Shared w/digest         -
217 //      pt2             Shared w/digest         -
218 //      pt3             Shared w/digest         -
219 //      pt4             Shared w/digest         -
220 //      pt5             Shared w/digest         -
221 //      pt6             Shared w/digest         -
222 //      pt7             Shared w/digest         -
223 //      pt8             Not Aligned             pOff
224 //      pt8             Blocks Left             pAgain
225
226 #define AccumA          r27
227 #define AccumB          r28
228 #define AccumC          r29
229 #define AccumD          r30
230 #define CTable          r24
231 #define CTable0         r25
232 #define CtxPtr0         in0
233 #define CtxPtr1         r23
234 #define DPtrIn          in1
235 #define BlockCount      in2
236 #define InAlign         r10
237 #define LCSave          r21
238 #define PFSSave         r20
239 #define PRSave          r22
240 #define pAgain          p63
241 #define pOff            p63
242
243         .text
244
245 /* md5_block_asm_host_order(MD5_CTX *c, const void *data, size_t num)
246
247      where:
248       c: a pointer to a structure of this type:
249
250            typedef struct MD5state_st
251              {
252                MD5_LONG A,B,C,D;
253                MD5_LONG Nl,Nh;
254                MD5_LONG data[MD5_LBLOCK];
255                unsigned int num;
256              }
257            MD5_CTX;
258
259       data: a pointer to the input data (may be misaligned)
260       num:  the number of 16-byte blocks to hash (i.e., the length
261             of DATA is 16*NUM.
262
263    */
264
265         .type   md5_block_asm_data_order, @function
266         .global md5_block_asm_data_order
267         .align  32
268         .proc   md5_block_asm_data_order
269 md5_block_asm_data_order:
270 {       .mib
271         cmp.eq  pDataOrder,pHostOrder = r0,r0
272         br.sptk.many    .md5_block
273 };;
274         .endp   md5_block_asm_data_order
275
276         .type   md5_block_asm_host_order, @function
277         .global md5_block_asm_host_order
278
279         .proc   md5_block_asm_host_order
280 md5_block_asm_host_order:
281         .prologue
282 {       .mib
283         cmp.eq  pHostOrder,pDataOrder = r0,r0
284 };;
285 .md5_block:
286 {       .mmi
287         .save   ar.pfs, PFSSave
288         alloc   PFSSave = ar.pfs, MD5_NINP, MD5_NLOC, MD5_NOUT, MD5_NROT
289         ADDP    CtxPtr1 = 8, CtxPtr0
290         mov     CTable = ip
291 }
292 {       .mmi
293         ADDP    DPtrIn = 0, DPtrIn
294         ADDP    CtxPtr0 = 0, CtxPtr0
295         .save   ar.lc, LCSave
296         mov     LCSave = ar.lc
297 }
298 ;;
299 .pred.rel       "mutex",pDataOrder,pHostOrder
300 {       .mmi
301 (pDataOrder)    add     CTable = .md5_tbl_data_order#-.md5_block#, CTable
302 (pHostOrder)    add     CTable = .md5_tbl_host_order#-.md5_block#, CTable       
303         and     InAlign = 0x3, DPtrIn
304 }
305
306 {       .mmi
307         ld4     AccumA = [CtxPtr0], 4
308         ld4     AccumC = [CtxPtr1], 4
309         .save pr, PRSave
310         mov     PRSave = pr
311         .body
312 }
313 ;;
314 {       .mmi
315         ld4     AccumB = [CtxPtr0]
316         ld4     AccumD = [CtxPtr1]
317         dep     DPtr_ = 0, DPtrIn, 0, 2
318 } ;;
319 #ifdef HOST_IS_BIG_ENDIAN
320 (pDataOrder)    rum     psr.be;;        // switch to little-endian
321 #endif
322 {       .mmb
323         ld4     CTable0 = [CTable], 4
324         cmp.ne  pOff, p0 = 0, InAlign
325 (pOff)  br.cond.spnt.many .md5_unaligned
326 } ;;
327
328 //      The FF load/compute loop rotates values three times, so that
329 //      loading into M12 here produces the M0 value, M13 -> M1, etc.
330
331 .md5_block_loop0:
332 {       .mmi
333         ld4     M12_ = [DPtr_], 4
334         mov     TPtr = CTable
335         mov     TRound = CTable0
336 } ;;
337 {       .mmi
338         ld4     M13_ = [DPtr_], 4
339         mov     A_ = AccumA
340         mov     B_ = AccumB
341 } ;;
342 {       .mmi
343         ld4     M14_ = [DPtr_], 4
344         mov     C_ = AccumC
345         mov     D_ = AccumD
346 } ;;
347 {       .mmb
348         ld4     M15_ = [DPtr_], 4
349         add     BlockCount = -1, BlockCount
350         br.call.sptk.many QUICK_RTN = md5_digest_block0
351 } ;;
352
353 //      Now, we add the new digest values and do some clean-up
354 //      before checking if there's another full block to process
355
356 {       .mmi
357         add     AccumA = AccumA, A_
358         add     AccumB = AccumB, B_
359         cmp.ne  pAgain, p0 = 0, BlockCount
360 }
361 {       .mib
362         add     AccumC = AccumC, C_
363         add     AccumD = AccumD, D_
364 (pAgain) br.cond.dptk.many .md5_block_loop0
365 } ;;
366
367 .md5_exit:
368 #ifdef HOST_IS_BIG_ENDIAN
369 (pDataOrder)    sum     psr.be;;        // switch back to big-endian mode
370 #endif
371 {       .mmi
372         st4     [CtxPtr0] = AccumB, -4
373         st4     [CtxPtr1] = AccumD, -4
374         mov     pr = PRSave, 0x1ffff ;;
375 }
376 {       .mmi
377         st4     [CtxPtr0] = AccumA
378         st4     [CtxPtr1] = AccumC
379         mov     ar.lc = LCSave
380 } ;;
381 {       .mib
382         mov     ar.pfs = PFSSave
383         br.ret.sptk.few rp
384 } ;;
385
386 #define MD5UNALIGNED(offset)                                            \
387 .md5_process##offset:                                                   \
388 {       .mib ;                                                          \
389         nop     0x0     ;                                               \
390         GETRW(DTmp, DTmp, offset) ;                                     \
391 } ;;                                                                    \
392 .md5_block_loop##offset:                                                \
393 {       .mmi ;                                                          \
394         ld4     Y_ = [DPtr_], 4 ;                                       \
395         mov     TPtr = CTable ;                                         \
396         mov     TRound = CTable0 ;                                      \
397 } ;;                                                                    \
398 {       .mmi ;                                                          \
399         ld4     M13_ = [DPtr_], 4 ;                                     \
400         mov     A_ = AccumA ;                                           \
401         mov     B_ = AccumB ;                                           \
402 } ;;                                                                    \
403 {       .mii ;                                                          \
404         ld4     M14_ = [DPtr_], 4 ;                                     \
405         GETLW(W_, Y_, offset) ;                                         \
406         mov     C_ = AccumC ;                                           \
407 }                                                                       \
408 {       .mmi ;                                                          \
409         mov     D_ = AccumD ;;                                          \
410         or      M12_ = W_, DTmp ;                                       \
411         GETRW(DTmp, Y_, offset) ;                                       \
412 }                                                                       \
413 {       .mib ;                                                          \
414         ld4     M15_ = [DPtr_], 4 ;                                     \
415         add     BlockCount = -1, BlockCount ;                           \
416         br.call.sptk.many QUICK_RTN = md5_digest_block##offset;         \
417 } ;;                                                                    \
418 {       .mmi ;                                                          \
419         add     AccumA = AccumA, A_ ;                                   \
420         add     AccumB = AccumB, B_ ;                                   \
421         cmp.ne  pAgain, p0 = 0, BlockCount ;                            \
422 }                                                                       \
423 {       .mib ;                                                          \
424         add     AccumC = AccumC, C_ ;                                   \
425         add     AccumD = AccumD, D_ ;                                   \
426 (pAgain) br.cond.dptk.many .md5_block_loop##offset ;                    \
427 } ;;                                                                    \
428 {       .mib ;                                                          \
429         nop     0x0 ;                                                   \
430         nop     0x0 ;                                                   \
431         br.cond.sptk.many .md5_exit ;                                   \
432 } ;;
433
434         .align  32
435 .md5_unaligned:
436 //
437 //      Because variable shifts are expensive, we special case each of
438 //      the four alignements. In practice, this won't hurt too much
439 //      since only one working set of code will be loaded.
440 //
441 {       .mib
442         ld4     DTmp = [DPtr_], 4
443         cmp.eq  pOff, p0 = 1, InAlign
444 (pOff)  br.cond.dpnt.many .md5_process1
445 } ;;
446 {       .mib
447         cmp.eq  pOff, p0 = 2, InAlign
448         nop     0x0
449 (pOff)  br.cond.dpnt.many .md5_process2
450 } ;;
451         MD5UNALIGNED(3)
452         MD5UNALIGNED(1)
453         MD5UNALIGNED(2)
454
455         .endp md5_block_asm_host_order
456
457
458 // MD5 Perform the F function and load
459 //
460 // Passed the first 4 words (M0 - M3) and initial (A, B, C, D) values,
461 // computes the FF() round of functions, then branches to the common
462 // digest code to finish up with GG(), HH, and II().
463 //
464 // INPUT
465 //
466 // rp Return Address -
467 //
468 // CODE
469 //
470 // v0 PFS bit bucket PFS
471 // v1 Loop Trip Count LTrip
472 // pt0 Load next word pMore
473
474 /* For F round: */
475 #define LTrip   r9
476 #define PFS     r8
477 #define pMore   p6
478
479 /* For GHI rounds: */
480 #define T       r9
481 #define U       r10
482 #define V       r11
483
484 #define COMPUTE(a, b, s, M, R)                  \
485 {                                               \
486         .mii ;                                  \
487         ld4 TRound = [TPtr], 4 ;                \
488         dep.z Y = Z, 32, 32 ;;                  \
489         shrp Z = Z, Y, 64 - s ;                 \
490 } ;;                                            \
491 {                                               \
492         .mmi ;                                  \
493         add a = Z, b ;                          \
494         mov R = M ;                             \
495         nop 0x0 ;                               \
496 } ;;
497
498 #define LOOP(a, b, s, M, R, label)              \
499 {       .mii ;                                  \
500         ld4 TRound = [TPtr], 4 ;                \
501         dep.z Y = Z, 32, 32 ;;                  \
502         shrp Z = Z, Y, 64 - s ;                 \
503 } ;;                                            \
504 {       .mib ;                                  \
505         add a = Z, b ;                          \
506         mov R = M ;                             \
507         br.ctop.sptk.many label ;               \
508 } ;;
509
510 // G(B, C, D) = (B & D) | (C & ~D)
511
512 #define G(a, b, c, d, M)                        \
513 {       .mmi ;                                  \
514         add Z = M, TRound ;                     \
515         and Y = b, d ;                          \
516         andcm X = c, d ;                        \
517 } ;;                                            \
518 {       .mii ;                                  \
519         add Z = Z, a ;                          \
520         or Y = Y, X ;;                          \
521         add Z = Z, Y ;                          \
522 } ;;
523
524 // H(B, C, D) = B ^ C ^ D
525
526 #define H(a, b, c, d, M)                        \
527 {       .mmi ;                                  \
528         add Z = M, TRound ;                     \
529         xor Y = b, c ;                          \
530         nop 0x0 ;                               \
531 } ;;                                            \
532 {       .mii ;                                  \
533         add Z = Z, a ;                          \
534         xor Y = Y, d ;;                         \
535         add Z = Z, Y ;                          \
536 } ;;
537
538 // I(B, C, D) = C ^ (B | ~D)
539 //
540 // However, since we have an andcm operator, we use the fact that
541 //
542 // Y ^ Z == ~Y ^ ~Z
543 //
544 // to rewrite the expression as
545 //
546 // I(B, C, D) = ~C ^ (~B & D)
547
548 #define I(a, b, c, d, M)                        \
549 {       .mmi ;                                  \
550         add Z = M, TRound ;                     \
551         andcm Y = d, b ;                        \
552         andcm X = -1, c ;                       \
553 } ;;                                            \
554 {       .mii ;                                  \
555         add Z = Z, a ;                          \
556         xor Y = Y, X ;;                         \
557         add Z = Z, Y ;                          \
558 } ;;
559
560 #define GG4(label)                              \
561         G(A, B, C, D, M0)                       \
562         COMPUTE(A, B, 5, M0, RotateM0)          \
563         G(D, A, B, C, M1)                       \
564         COMPUTE(D, A, 9, M1, RotateM1)          \
565         G(C, D, A, B, M2)                       \
566         COMPUTE(C, D, 14, M2, RotateM2)         \
567         G(B, C, D, A, M3)                       \
568         LOOP(B, C, 20, M3, RotateM3, label)
569
570 #define HH4(label)                              \
571         H(A, B, C, D, M0)                       \
572         COMPUTE(A, B, 4, M0, RotateM0)          \
573         H(D, A, B, C, M1)                       \
574         COMPUTE(D, A, 11, M1, RotateM1)         \
575         H(C, D, A, B, M2)                       \
576         COMPUTE(C, D, 16, M2, RotateM2)         \
577         H(B, C, D, A, M3)                       \
578         LOOP(B, C, 23, M3, RotateM3, label)
579
580 #define II4(label)                              \
581         I(A, B, C, D, M0)                       \
582         COMPUTE(A, B, 6, M0, RotateM0)          \
583         I(D, A, B, C, M1)                       \
584         COMPUTE(D, A, 10, M1, RotateM1)         \
585         I(C, D, A, B, M2)                       \
586         COMPUTE(C, D, 15, M2, RotateM2)         \
587         I(B, C, D, A, M3)                       \
588         LOOP(B, C, 21, M3, RotateM3, label)
589
590 #define FFLOAD(a, b, c, d, M, N, s)             \
591 {       .mii ;                                  \
592 (pMore) ld4 N = [DPtr], 4 ;                     \
593         add Z = M, TRound ;                     \
594         and Y = c, b ;                          \
595 }                                               \
596 {       .mmi ;                                  \
597         andcm X = d, b ;;                       \
598         add Z = Z, a ;                          \
599         or Y = Y, X ;                           \
600 } ;;                                            \
601 {       .mii ;                                  \
602         ld4 TRound = [TPtr], 4 ;                \
603         add Z = Z, Y ;;                         \
604         dep.z Y = Z, 32, 32 ;                   \
605 } ;;                                            \
606 {       .mii ;                                  \
607         nop 0x0 ;                               \
608         shrp Z = Z, Y, 64 - s ;;                \
609         add a = Z, b ;                          \
610 } ;;
611
612 #define FFLOOP(a, b, c, d, M, N, s, dest)       \
613 {       .mii ;                                  \
614 (pMore) ld4 N = [DPtr], 4 ;                     \
615         add Z = M, TRound ;                     \
616         and Y = c, b ;                          \
617 }                                               \
618 {       .mmi ;                                  \
619         andcm X = d, b ;;                       \
620         add Z = Z, a ;                          \
621         or Y = Y, X ;                           \
622 } ;;                                            \
623 {       .mii ;                                  \
624         ld4 TRound = [TPtr], 4 ;                \
625         add Z = Z, Y ;;                         \
626         dep.z Y = Z, 32, 32 ;                   \
627 } ;;                                            \
628 {       .mii ;                                  \
629         nop 0x0 ;                               \
630         shrp Z = Z, Y, 64 - s ;;                \
631         add a = Z, b ;                          \
632 }                                               \
633 {       .mib ;                                  \
634         cmp.ne pMore, p0 = 0, LTrip ;           \
635         add LTrip = -1, LTrip ;                 \
636         br.ctop.dptk.many dest ;                \
637 } ;;
638
639         .type md5_digest_block0, @function
640         .align 32
641
642         .proc md5_digest_block0
643         .prologue
644 md5_digest_block0:
645         .altrp QUICK_RTN
646         .body
647 {       .mmi
648         alloc PFS = ar.pfs, _NINPUTS, _NLOCALS, _NOUTPUT, _NROTATE
649         mov LTrip = 2
650         mov ar.lc = 3
651 } ;;
652 {       .mii
653         cmp.eq pMore, p0 = r0, r0
654         mov ar.ec = 0
655         nop 0x0
656 } ;;
657
658 .md5_FF_round0:
659         FFLOAD(A, B, C, D, M12, RotateM0, 7)
660         FFLOAD(D, A, B, C, M13, RotateM1, 12)
661         FFLOAD(C, D, A, B, M14, RotateM2, 17)
662         FFLOOP(B, C, D, A, M15, RotateM3, 22, .md5_FF_round0)
663         //
664         // !!! Fall through to md5_digest_GHI
665         //
666         .endp md5_digest_block0
667
668         .type md5_digest_GHI, @function
669         .align 32
670
671         .proc md5_digest_GHI
672         .prologue
673         .regstk _NINPUTS, _NLOCALS, _NOUTPUT, _NROTATE
674 md5_digest_GHI:
675         .altrp QUICK_RTN
676         .body
677 //
678 // The following sequence shuffles the block counstants round for the
679 // next round:
680 //
681 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
682 // 1 6 11 0 5 10 14 4 9 14 3 8 13 2 7 12
683 //
684 {       .mmi
685         mov Z = M0
686         mov Y = M15
687         mov ar.lc = 3
688 }
689 {       .mmi
690         mov X = M2
691         mov W = M9
692         mov V = M4
693 } ;;
694
695 {       .mmi
696         mov M0 = M1
697         mov M15 = M12
698         mov ar.ec = 1
699 }
700 {       .mmi
701         mov M2 = M11
702         mov M9 = M14
703         mov M4 = M5
704 } ;;
705
706 {       .mmi
707         mov M1 = M6
708         mov M12 = M13
709         mov U = M3
710 }
711 {       .mmi
712         mov M11 = M8
713         mov M14 = M7
714         mov M5 = M10
715 } ;;
716
717 {       .mmi
718         mov M6 = Y
719         mov M13 = X
720         mov M3 = Z
721 }
722 {       .mmi
723         mov M8 = W
724         mov M7 = V
725         mov M10 = U
726 } ;;
727
728 .md5_GG_round:
729         GG4(.md5_GG_round)
730
731 // The following sequence shuffles the block constants round for the
732 // next round:
733 //
734 // 1 6 11 0 5 10 14 4 9 14 3 8 13 2 7 12
735 // 5 8 11 14 1 4 7 10 13 0 3 6 9 12 15 2
736
737 {       .mmi
738         mov Z = M0
739         mov Y = M1
740         mov ar.lc = 3
741 }
742 {       .mmi
743         mov X = M3
744         mov W = M5
745         mov V = M6
746 } ;;
747
748 {       .mmi
749         mov M0 = M4
750         mov M1 = M11
751         mov ar.ec = 1
752 }
753 {       .mmi
754         mov M3 = M9
755         mov U = M8
756         mov T = M13
757 } ;;
758
759 {       .mmi
760         mov M4 = Z
761         mov M11 = Y
762         mov M5 = M7
763 }
764 {       .mmi
765         mov M6 = M14
766         mov M8 = M12
767         mov M13 = M15
768 } ;;
769
770 {       .mmi
771         mov M7 = W
772         mov M14 = V
773         nop 0x0
774 }
775 {       .mmi
776         mov M9 = X
777         mov M12 = U
778         mov M15 = T
779 } ;;
780
781 .md5_HH_round:
782         HH4(.md5_HH_round)
783
784 // The following sequence shuffles the block constants round for the
785 // next round:
786 //
787 // 5 8 11 14 1 4 7 10 13 0 3 6 9 12 15 2
788 // 0 7 14 5 12 3 10 1 8 15 6 13 4 11 2 9
789
790 {       .mmi
791         mov Z = M0
792         mov Y = M15
793         mov ar.lc = 3
794 }
795 {       .mmi
796         mov X = M10
797         mov W = M1
798         mov V = M4
799 } ;;
800
801 {       .mmi
802         mov M0 = M9
803         mov M15 = M12
804         mov ar.ec = 1
805 }
806 {       .mmi
807         mov M10 = M11
808         mov M1 = M6
809         mov M4 = M13
810 } ;;
811
812 {       .mmi
813         mov M9 = M14
814         mov M12 = M5
815         mov U = M3
816 }
817 {       .mmi
818         mov M11 = M8
819         mov M6 = M7
820         mov M13 = M2
821 } ;;
822
823 {       .mmi
824         mov M14 = Y
825         mov M5 = X
826         mov M3 = Z
827 }
828 {       .mmi
829         mov M8 = W
830         mov M7 = V
831         mov M2 = U
832 } ;;
833
834 .md5_II_round:
835         II4(.md5_II_round)
836
837 {       .mib
838         nop 0x0
839         nop 0x0
840         br.ret.sptk.many QUICK_RTN
841 } ;;
842
843         .endp md5_digest_GHI
844
845 #define FFLOADU(a, b, c, d, M, P, N, s, offset) \
846 {       .mii ;                                  \
847 (pMore) ld4 N = [DPtr], 4 ;                     \
848         add Z = M, TRound ;                     \
849         and Y = c, b ;                          \
850 }                                               \
851 {       .mmi ;                                  \
852         andcm X = d, b ;;                       \
853         add Z = Z, a ;                          \
854         or Y = Y, X ;                           \
855 } ;;                                            \
856 {       .mii ;                                  \
857         ld4 TRound = [TPtr], 4 ;                \
858         GETLW(W, P, offset) ;                   \
859         add Z = Z, Y ;                          \
860 } ;;                                            \
861 {       .mii ;                                  \
862         or W = W, DTmp ;                        \
863         dep.z Y = Z, 32, 32 ;;                  \
864         shrp Z = Z, Y, 64 - s ;                 \
865 } ;;                                            \
866 {       .mii ;                                  \
867         add a = Z, b ;                          \
868         GETRW(DTmp, P, offset) ;                \
869         mov P = W ;                             \
870 } ;;
871
872 #define FFLOOPU(a, b, c, d, M, P, N, s, offset)         \
873 {       .mii ;                                          \
874 (pMore) ld4 N = [DPtr], 4 ;                             \
875         add Z = M, TRound ;                             \
876         and Y = c, b ;                                  \
877 }                                                       \
878 {       .mmi ;                                          \
879         andcm X = d, b ;;                               \
880         add Z = Z, a ;                                  \
881         or Y = Y, X ;                                   \
882 } ;;                                                    \
883 {       .mii ;                                          \
884         ld4 TRound = [TPtr], 4 ;                        \
885 (pMore) GETLW(W, P, offset)     ;                       \
886         add Z = Z, Y ;                                  \
887 } ;;                                                    \
888 {       .mii ;                                          \
889 (pMore) or W = W, DTmp ;                                \
890         dep.z Y = Z, 32, 32 ;;                          \
891         shrp Z = Z, Y, 64 - s ;                         \
892 } ;;                                                    \
893 {       .mii ;                                          \
894         add a = Z, b ;                                  \
895 (pMore) GETRW(DTmp, P, offset)  ;                       \
896 (pMore) mov P = W ;                                     \
897 }                                                       \
898 {       .mib ;                                          \
899         cmp.ne pMore, p0 = 0, LTrip ;                   \
900         add LTrip = -1, LTrip ;                         \
901         br.ctop.sptk.many .md5_FF_round##offset ;       \
902 } ;;
903
904 #define MD5FBLOCK(offset)                                               \
905         .type md5_digest_block##offset, @function ;                     \
906                                                                         \
907         .align 32 ;                                                     \
908         .proc md5_digest_block##offset ;                                \
909         .prologue ;                                                     \
910         .altrp QUICK_RTN ;                                              \
911         .body ;                                                         \
912 md5_digest_block##offset:                                               \
913 {       .mmi ;                                                          \
914         alloc PFS = ar.pfs, _NINPUTS, _NLOCALS, _NOUTPUT, _NROTATE ;    \
915         mov LTrip = 2 ;                                                 \
916         mov ar.lc = 3 ;                                                 \
917 } ;;                                                                    \
918 {       .mii ;                                                          \
919         cmp.eq pMore, p0 = r0, r0 ;                                     \
920         mov ar.ec = 0 ;                                                 \
921         nop 0x0 ;                                                       \
922 } ;;                                                                    \
923                                                                         \
924         .pred.rel "mutex", pLoad, pSkip ;                               \
925 .md5_FF_round##offset:                                                  \
926         FFLOADU(A, B, C, D, M12, M13, RotateM0, 7, offset)              \
927         FFLOADU(D, A, B, C, M13, M14, RotateM1, 12, offset)             \
928         FFLOADU(C, D, A, B, M14, M15, RotateM2, 17, offset)             \
929         FFLOOPU(B, C, D, A, M15, RotateM0, RotateM3, 22, offset)        \
930                                                                         \
931 {       .mib ;                                                          \
932         nop 0x0 ;                                                       \
933         nop 0x0 ;                                                       \
934         br.cond.sptk.many md5_digest_GHI ;                              \
935 } ;;                                                                    \
936         .endp md5digestBlock ## offset
937
938 MD5FBLOCK(1)
939 MD5FBLOCK(2)
940 MD5FBLOCK(3)
941
942         .align 64
943         .type md5_constants, @object
944 md5_constants:
945 .md5_tbl_data_order:                    // To ensure little-endian data
946                                         // order, code as bytes.
947         data1 0x78, 0xa4, 0x6a, 0xd7    //     0
948         data1 0x56, 0xb7, 0xc7, 0xe8    //     1
949         data1 0xdb, 0x70, 0x20, 0x24    //     2
950         data1 0xee, 0xce, 0xbd, 0xc1    //     3
951         data1 0xaf, 0x0f, 0x7c, 0xf5    //     4
952         data1 0x2a, 0xc6, 0x87, 0x47    //     5
953         data1 0x13, 0x46, 0x30, 0xa8    //     6
954         data1 0x01, 0x95, 0x46, 0xfd    //     7
955         data1 0xd8, 0x98, 0x80, 0x69    //     8
956         data1 0xaf, 0xf7, 0x44, 0x8b    //     9
957         data1 0xb1, 0x5b, 0xff, 0xff    //    10
958         data1 0xbe, 0xd7, 0x5c, 0x89    //    11
959         data1 0x22, 0x11, 0x90, 0x6b    //    12
960         data1 0x93, 0x71, 0x98, 0xfd    //    13
961         data1 0x8e, 0x43, 0x79, 0xa6    //    14
962         data1 0x21, 0x08, 0xb4, 0x49    //    15
963         data1 0x62, 0x25, 0x1e, 0xf6    //    16
964         data1 0x40, 0xb3, 0x40, 0xc0    //    17
965         data1 0x51, 0x5a, 0x5e, 0x26    //    18
966         data1 0xaa, 0xc7, 0xb6, 0xe9    //    19
967         data1 0x5d, 0x10, 0x2f, 0xd6    //    20
968         data1 0x53, 0x14, 0x44, 0x02    //    21
969         data1 0x81, 0xe6, 0xa1, 0xd8    //    22
970         data1 0xc8, 0xfb, 0xd3, 0xe7    //    23
971         data1 0xe6, 0xcd, 0xe1, 0x21    //    24
972         data1 0xd6, 0x07, 0x37, 0xc3    //    25
973         data1 0x87, 0x0d, 0xd5, 0xf4    //    26
974         data1 0xed, 0x14, 0x5a, 0x45    //    27
975         data1 0x05, 0xe9, 0xe3, 0xa9    //    28
976         data1 0xf8, 0xa3, 0xef, 0xfc    //    29
977         data1 0xd9, 0x02, 0x6f, 0x67    //    30
978         data1 0x8a, 0x4c, 0x2a, 0x8d    //    31
979         data1 0x42, 0x39, 0xfa, 0xff    //    32
980         data1 0x81, 0xf6, 0x71, 0x87    //    33
981         data1 0x22, 0x61, 0x9d, 0x6d    //    34
982         data1 0x0c, 0x38, 0xe5, 0xfd    //    35
983         data1 0x44, 0xea, 0xbe, 0xa4    //    36
984         data1 0xa9, 0xcf, 0xde, 0x4b    //    37
985         data1 0x60, 0x4b, 0xbb, 0xf6    //    38
986         data1 0x70, 0xbc, 0xbf, 0xbe    //    39
987         data1 0xc6, 0x7e, 0x9b, 0x28    //    40
988         data1 0xfa, 0x27, 0xa1, 0xea    //    41
989         data1 0x85, 0x30, 0xef, 0xd4    //    42
990         data1 0x05, 0x1d, 0x88, 0x04    //    43
991         data1 0x39, 0xd0, 0xd4, 0xd9    //    44
992         data1 0xe5, 0x99, 0xdb, 0xe6    //    45
993         data1 0xf8, 0x7c, 0xa2, 0x1f    //    46
994         data1 0x65, 0x56, 0xac, 0xc4    //    47
995         data1 0x44, 0x22, 0x29, 0xf4    //    48
996         data1 0x97, 0xff, 0x2a, 0x43    //    49
997         data1 0xa7, 0x23, 0x94, 0xab    //    50
998         data1 0x39, 0xa0, 0x93, 0xfc    //    51
999         data1 0xc3, 0x59, 0x5b, 0x65    //    52
1000         data1 0x92, 0xcc, 0x0c, 0x8f    //    53
1001         data1 0x7d, 0xf4, 0xef, 0xff    //    54
1002         data1 0xd1, 0x5d, 0x84, 0x85    //    55
1003         data1 0x4f, 0x7e, 0xa8, 0x6f    //    56
1004         data1 0xe0, 0xe6, 0x2c, 0xfe    //    57
1005         data1 0x14, 0x43, 0x01, 0xa3    //    58
1006         data1 0xa1, 0x11, 0x08, 0x4e    //    59
1007         data1 0x82, 0x7e, 0x53, 0xf7    //    60
1008         data1 0x35, 0xf2, 0x3a, 0xbd    //    61
1009         data1 0xbb, 0xd2, 0xd7, 0x2a    //    62
1010         data1 0x91, 0xd3, 0x86, 0xeb    //    63
1011
1012 .md5_tbl_host_order:                    // OS data order, might as well
1013                                         // be little-endian.
1014         data4 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee    // 0
1015         data4 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501    // 4
1016         data4 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be    // 8
1017         data4 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821    // 12
1018         data4 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa    // 16
1019         data4 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8    // 20
1020         data4 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed    // 24
1021         data4 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a    // 28
1022         data4 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c    // 32
1023         data4 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70    // 36
1024         data4 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05    // 40
1025         data4 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665    // 44
1026         data4 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039    // 48
1027         data4 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1    // 52
1028         data4 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1    // 56
1029         data4 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391    // 60
1030 .size   md5_constants#,64*4*2