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