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