710ca3c1f4c0161c45ae56ed78617f3f29454b9d
[openssl.git] / crypto / bn / asm / ia64-mont.pl
1 #!/usr/bin/env perl
2 #
3 # ====================================================================
4 # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
5 # project. The module is, however, dual licensed under OpenSSL and
6 # CRYPTOGAMS licenses depending on where you obtain it. For further
7 # details see http://www.openssl.org/~appro/cryptogams/.
8 # ====================================================================
9
10 # January 2010
11 #
12 # "Teaser" Montgomery multiplication module for IA-64. There are
13 # several possibilities for improvement:
14 #
15 # - modulo-scheduling outer loop would eliminate quite a number of
16 #   stalls after ldf8, xma and getf.sig outside inner loop and
17 #   improve shorter key performance;
18 # - shorter vector support [with input vectors being fetched only
19 #   once] should be added;
20 # - 2x unroll with help of n0[1] would make the code scalable on
21 #   "wider" IA-64, "wider" than Itanium 2 that is, which is not of
22 #   acute interest, because upcoming Tukwila's individual cores are
23 #   reportedly based on Itanium 2 design;
24 # - dedicated squaring procedure(?);
25 #
26 # January 2010
27 #
28 # Shorter vector support is implemented by zero-padding ap and np
29 # vectors up to 8 elements, or 512 bits. This means that 256-bit
30 # inputs will be processed only 2 times faster than 512-bit inputs,
31 # not 4 [as one would expect, because algorithm complexity is n^2].
32 # The reason for padding is that inputs shorter than 512 bits won't
33 # be processed faster anyway, because minimal critical path of the
34 # core loop happens to match 512-bit timing. Either way, it resulted
35 # in >100% improvement of 512-bit RSA sign benchmark and 50% - of
36 # 1024-bit one [in comparison to original version of *this* module].
37 #
38 # So far 'openssl speed rsa dsa' output on 900MHz Itanium 2 *with*
39 # this module is:
40 #                   sign    verify    sign/s verify/s
41 # rsa  512 bits 0.000290s 0.000024s   3452.8  42031.4
42 # rsa 1024 bits 0.000793s 0.000058s   1261.7  17172.0
43 # rsa 2048 bits 0.005908s 0.000148s    169.3   6754.0
44 # rsa 4096 bits 0.033456s 0.000469s     29.9   2133.6
45 # dsa  512 bits 0.000253s 0.000198s   3949.9   5057.0
46 # dsa 1024 bits 0.000585s 0.000607s   1708.4   1647.4
47 # dsa 2048 bits 0.001453s 0.001703s    688.1    587.4
48 #
49 # ... and *without* (but still with ia64.S):
50 #
51 # rsa  512 bits 0.000670s 0.000041s   1491.8  24145.5
52 # rsa 1024 bits 0.001988s 0.000080s    502.9  12499.3
53 # rsa 2048 bits 0.008702s 0.000189s    114.9   5293.9
54 # rsa 4096 bits 0.043860s 0.000533s     22.8   1875.9
55 # dsa  512 bits 0.000441s 0.000427s   2265.3   2340.6
56 # dsa 1024 bits 0.000823s 0.000867s   1215.6   1153.2
57 # dsa 2048 bits 0.001894s 0.002179s    528.1    458.9
58 #
59 # As it can be seen, RSA sign performance improves by 130-30%,
60 # hereafter less for longer keys, while verify - by 74-13%.
61 # DSA performance improves by 115-30%.
62
63 $output=pop;
64
65 if ($^O eq "hpux") {
66     $ADDP="addp4";
67     for (@ARGV) { $ADDP="add" if (/[\+DD|\-mlp]64/); }
68 } else { $ADDP="add"; }
69
70 $code=<<___;
71 .explicit
72 .text
73
74 // int bn_mul_mont (BN_ULONG *rp,const BN_ULONG *ap,
75 //                  const BN_ULONG *bp,const BN_ULONG *np,
76 //                  const BN_ULONG *n0p,int num);                       
77 .align  64
78 .global bn_mul_mont#
79 .proc   bn_mul_mont#
80 bn_mul_mont:
81         .prologue
82         .body
83 { .mmi; cmp4.le         p6,p7=2,r37;;
84 (p6)    cmp4.lt.unc     p8,p9=8,r37
85         mov             ret0=r0         };;
86 { .bbb;
87 (p9)    br.cond.dptk.many       bn_mul_mont_8
88 (p8)    br.cond.dpnt.many       bn_mul_mont_general
89 (p7)    br.ret.spnt.many        b0      };;
90 .endp   bn_mul_mont#
91 \f
92 prevfs=r2;      prevpr=r3;      prevlc=r10;     prevsp=r11;
93
94 rptr=r8;        aptr=r9;        bptr=r14;       nptr=r15;
95 tptr=r16;       // &tp[0]
96 tp_1=r17;       // &tp[-1]
97 num=r18;        len=r19;        lc=r20;
98 topbit=r21;     // carry bit from tmp[num]
99
100 n0=f6;
101 m0=f7;
102 bi=f8;
103
104 .align  64
105 .local  bn_mul_mont_general#
106 .proc   bn_mul_mont_general#
107 bn_mul_mont_general:
108         .prologue
109 { .mmi; .save   ar.pfs,prevfs
110         alloc   prevfs=ar.pfs,6,2,0,8
111         $ADDP   aptr=0,in1
112         .save   ar.lc,prevlc
113         mov     prevlc=ar.lc            }
114 { .mmi; .vframe prevsp
115         mov     prevsp=sp
116         $ADDP   bptr=0,in2
117         .save   pr,prevpr
118         mov     prevpr=pr               };;
119
120         .body
121         .rotf           alo[6],nlo[4],ahi[8],nhi[6]
122         .rotr           a[3],n[3],t[2]
123
124 { .mmi; ldf8            bi=[bptr],8             // (*bp++)
125         ldf8            alo[4]=[aptr],16        // ap[0]
126         $ADDP           r30=8,in1       };;
127 { .mmi; ldf8            alo[3]=[r30],16         // ap[1]
128         ldf8            alo[2]=[aptr],16        // ap[2]
129         $ADDP           in4=0,in4       };;
130 { .mmi; ldf8            alo[1]=[r30]            // ap[3]
131         ldf8            n0=[in4]                // n0
132         $ADDP           rptr=0,in0              }
133 { .mmi; $ADDP           nptr=0,in3
134         mov             r31=16
135         zxt4            num=in5         };;
136 { .mmi; ldf8            nlo[2]=[nptr],8         // np[0]
137         shladd          len=num,3,r0
138         shladd          r31=num,3,r31   };;
139 { .mmi; ldf8            nlo[1]=[nptr],8         // np[1]
140         add             lc=-5,num
141         sub             r31=sp,r31      };;
142 { .mfb; and             sp=-16,r31              // alloca
143         xmpy.hu         ahi[2]=alo[4],bi        // ap[0]*bp[0]
144         nop.b           0               }
145 { .mfb; nop.m           0
146         xmpy.lu         alo[4]=alo[4],bi
147         brp.loop.imp    .L1st_ctop,.L1st_cend-16
148                                         };;
149 { .mfi; nop.m           0
150         xma.hu          ahi[1]=alo[3],bi,ahi[2] // ap[1]*bp[0]
151         add             tp_1=8,sp       }
152 { .mfi; nop.m           0
153         xma.lu          alo[3]=alo[3],bi,ahi[2]
154         mov             pr.rot=0x20001f<<16
155                         // ------^----- (p40) at first (p23)
156                         // ----------^^ p[16:20]=1
157                                         };;
158 { .mfi; nop.m           0
159         xmpy.lu         m0=alo[4],n0            // (ap[0]*bp[0])*n0
160         mov             ar.lc=lc        }
161 { .mfi; nop.m           0
162         fcvt.fxu.s1     nhi[1]=f0
163         mov             ar.ec=8         };;
164
165 .align  32
166 .L1st_ctop:
167 .pred.rel       "mutex",p40,p42
168 { .mfi; (p16)   ldf8            alo[0]=[aptr],8             // *(aptr++)
169         (p18)   xma.hu          ahi[0]=alo[2],bi,ahi[1]
170         (p40)   add             n[2]=n[2],a[2]          }   // (p23)                                    }
171 { .mfi; (p18)   ldf8            nlo[0]=[nptr],8             // *(nptr++)(p16)
172         (p18)   xma.lu          alo[2]=alo[2],bi,ahi[1]
173         (p42)   add             n[2]=n[2],a[2],1        };; // (p23)
174 { .mfi; (p21)   getf.sig        a[0]=alo[5]
175         (p20)   xma.hu          nhi[0]=nlo[2],m0,nhi[1]
176         (p42)   cmp.leu         p41,p39=n[2],a[2]       }   // (p23)
177 { .mfi; (p23)   st8             [tp_1]=n[2],8
178         (p20)   xma.lu          nlo[2]=nlo[2],m0,nhi[1]
179         (p40)   cmp.ltu         p41,p39=n[2],a[2]       }   // (p23)
180 { .mmb; (p21)   getf.sig        n[0]=nlo[3]
181         (p16)   nop.m           0
182         br.ctop.sptk    .L1st_ctop                      };;
183 .L1st_cend:
184
185 { .mmi; getf.sig        a[0]=ahi[6]             // (p24)
186         getf.sig        n[0]=nhi[4]
187         add             num=-1,num      };;     // num--
188 { .mmi; .pred.rel       "mutex",p40,p42
189 (p40)   add             n[0]=n[0],a[0]
190 (p42)   add             n[0]=n[0],a[0],1
191         sub             aptr=aptr,len   };;     // rewind
192 { .mmi; .pred.rel       "mutex",p40,p42
193 (p40)   cmp.ltu         p41,p39=n[0],a[0]
194 (p42)   cmp.leu         p41,p39=n[0],a[0]
195         sub             nptr=nptr,len   };;
196 { .mmi; .pred.rel       "mutex",p39,p41
197 (p39)   add             topbit=r0,r0
198 (p41)   add             topbit=r0,r0,1
199         nop.i           0               }       
200 { .mmi; st8             [tp_1]=n[0]
201         add             tptr=16,sp
202         add             tp_1=8,sp       };;
203 \f
204 .Louter:
205 { .mmi; ldf8            bi=[bptr],8             // (*bp++)
206         ldf8            ahi[3]=[tptr]           // tp[0]
207         add             r30=8,aptr      };;
208 { .mmi; ldf8            alo[4]=[aptr],16        // ap[0]
209         ldf8            alo[3]=[r30],16         // ap[1]
210         add             r31=8,nptr      };;
211 { .mfb; ldf8            alo[2]=[aptr],16        // ap[2]
212         xma.hu          ahi[2]=alo[4],bi,ahi[3] // ap[0]*bp[i]+tp[0]
213         brp.loop.imp    .Linner_ctop,.Linner_cend-16
214                                         }
215 { .mfb; ldf8            alo[1]=[r30]            // ap[3]
216         xma.lu          alo[4]=alo[4],bi,ahi[3]
217         clrrrb.pr                       };;
218 { .mfi; ldf8            nlo[2]=[nptr],16        // np[0]
219         xma.hu          ahi[1]=alo[3],bi,ahi[2] // ap[1]*bp[i]
220         nop.i           0               }
221 { .mfi; ldf8            nlo[1]=[r31]            // np[1]
222         xma.lu          alo[3]=alo[3],bi,ahi[2]
223         mov             pr.rot=0x20101f<<16
224                         // ------^----- (p40) at first (p23)
225                         // --------^--- (p30) at first (p22)
226                         // ----------^^ p[16:20]=1
227                                         };;
228 { .mfi; st8             [tptr]=r0               // tp[0] is already accounted
229         xmpy.lu         m0=alo[4],n0            // (ap[0]*bp[i]+tp[0])*n0
230         mov             ar.lc=lc        }
231 { .mfi;
232         fcvt.fxu.s1     nhi[1]=f0
233         mov             ar.ec=8         };;
234
235 // This loop spins in 4*(n+7) ticks on Itanium 2 and should spin in
236 // 7*(n+7) ticks on Itanium (the one codenamed Merced). Factor of 7
237 // in latter case accounts for two-tick pipeline stall, which means
238 // that its performance would be ~20% lower than optimal one. No
239 // attempt was made to address this, because original Itanium is
240 // hardly represented out in the wild...
241 .align  32
242 .Linner_ctop:
243 .pred.rel       "mutex",p40,p42
244 .pred.rel       "mutex",p30,p32
245 { .mfi; (p16)   ldf8            alo[0]=[aptr],8             // *(aptr++)
246         (p18)   xma.hu          ahi[0]=alo[2],bi,ahi[1]
247         (p40)   add             n[2]=n[2],a[2]          }   // (p23)
248 { .mfi; (p16)   nop.m           0
249         (p18)   xma.lu          alo[2]=alo[2],bi,ahi[1]
250         (p42)   add             n[2]=n[2],a[2],1        };; // (p23)
251 { .mfi; (p21)   getf.sig        a[0]=alo[5]
252         (p16)   nop.f           0
253         (p40)   cmp.ltu         p41,p39=n[2],a[2]       }   // (p23)
254 { .mfi; (p21)   ld8             t[0]=[tptr],8
255         (p16)   nop.f           0
256         (p42)   cmp.leu         p41,p39=n[2],a[2]       };; // (p23)
257 { .mfi; (p18)   ldf8            nlo[0]=[nptr],8             // *(nptr++)
258         (p20)   xma.hu          nhi[0]=nlo[2],m0,nhi[1]
259         (p30)   add             a[1]=a[1],t[1]          }   // (p22)
260 { .mfi; (p16)   nop.m           0
261         (p20)   xma.lu          nlo[2]=nlo[2],m0,nhi[1]
262         (p32)   add             a[1]=a[1],t[1],1        };; // (p22)
263 { .mmi; (p21)   getf.sig        n[0]=nlo[3]
264         (p16)   nop.m           0
265         (p30)   cmp.ltu         p31,p29=a[1],t[1]       }   // (p22)
266 { .mmb; (p23)   st8             [tp_1]=n[2],8
267         (p32)   cmp.leu         p31,p29=a[1],t[1]           // (p22)
268         br.ctop.sptk    .Linner_ctop                    };;
269 .Linner_cend:
270
271 { .mmi; getf.sig        a[0]=ahi[6]             // (p24)
272         getf.sig        n[0]=nhi[4]
273         nop.i           0               };;
274
275 { .mmi; .pred.rel       "mutex",p31,p33
276 (p31)   add             a[0]=a[0],topbit
277 (p33)   add             a[0]=a[0],topbit,1
278         mov             topbit=r0       };;
279 { .mfi; .pred.rel       "mutex",p31,p33
280 (p31)   cmp.ltu         p32,p30=a[0],topbit
281 (p33)   cmp.leu         p32,p30=a[0],topbit
282                                         }
283 { .mfi; .pred.rel       "mutex",p40,p42
284 (p40)   add             n[0]=n[0],a[0]
285 (p42)   add             n[0]=n[0],a[0],1
286                                         };;
287 { .mmi; .pred.rel       "mutex",p44,p46
288 (p40)   cmp.ltu         p41,p39=n[0],a[0]
289 (p42)   cmp.leu         p41,p39=n[0],a[0]
290 (p32)   add             topbit=r0,r0,1  }
291
292 { .mmi; st8             [tp_1]=n[0],8
293         cmp4.ne         p6,p0=1,num
294         sub             aptr=aptr,len   };;     // rewind
295 { .mmi; sub             nptr=nptr,len
296 (p41)   add             topbit=r0,r0,1
297         add             tptr=16,sp      }
298 { .mmb; add             tp_1=8,sp
299         add             num=-1,num              // num--
300 (p6)    br.cond.sptk.many       .Louter };;
301 \f
302 { .mbb; add             lc=4,lc
303         brp.loop.imp    .Lsub_ctop,.Lsub_cend-16
304         clrrrb.pr                       };;
305 { .mii; nop.m           0
306         mov             pr.rot=0x10001<<16
307                         // ------^---- (p33) at first (p17)
308         mov             ar.lc=lc        }
309 { .mii; nop.m           0
310         mov             ar.ec=3
311         nop.i           0               };;
312
313 .Lsub_ctop:
314 .pred.rel       "mutex",p33,p35
315 { .mfi; (p16)   ld8             t[0]=[tptr],8               // t=*(tp++)
316         (p16)   nop.f           0
317         (p33)   sub             n[1]=t[1],n[1]          }   // (p17)
318 { .mfi; (p16)   ld8             n[0]=[nptr],8               // n=*(np++)
319         (p16)   nop.f           0
320         (p35)   sub             n[1]=t[1],n[1],1        };; // (p17)
321 { .mib; (p18)   st8             [rptr]=n[2],8               // *(rp++)=r
322         (p33)   cmp.gtu         p34,p32=n[1],t[1]           // (p17)
323         (p18)   nop.b           0                       }
324 { .mib; (p18)   nop.m           0
325         (p35)   cmp.geu         p34,p32=n[1],t[1]           // (p17)
326         br.ctop.sptk    .Lsub_ctop                      };;
327 .Lsub_cend:
328
329 { .mmb; .pred.rel       "mutex",p34,p36
330 (p34)   sub     topbit=topbit,r0        // (p19)
331 (p36)   sub     topbit=topbit,r0,1
332         brp.loop.imp    .Lcopy_ctop,.Lcopy_cend-16
333                                         }
334 { .mmb; sub     rptr=rptr,len           // rewind
335         sub     tptr=tptr,len
336         clrrrb.pr                       };;
337 { .mmi; and     aptr=tptr,topbit
338         andcm   bptr=rptr,topbit
339         mov     pr.rot=1<<16            };;
340 { .mii; or      nptr=aptr,bptr
341         mov     ar.lc=lc
342         mov     ar.ec=3                 };;
343
344 .Lcopy_ctop:
345 { .mmb; (p16)   ld8     n[0]=[nptr],8
346         (p18)   st8     [tptr]=r0,8
347         (p16)   nop.b   0               }
348 { .mmb; (p16)   nop.m   0
349         (p18)   st8     [rptr]=n[2],8
350         br.ctop.sptk    .Lcopy_ctop     };;
351 .Lcopy_cend:
352
353 { .mmi; mov             ret0=1                  // signal "handled"
354         rum             1<<5                    // clear um.mfh
355         mov             ar.lc=prevlc    }
356 { .mib; .restore        sp
357         mov             sp=prevsp
358         mov             pr=prevpr,0x1ffff
359         br.ret.sptk.many        b0      };;
360 .endp   bn_mul_mont_general#
361 \f
362 a1=r16;  a2=r17;  a3=r18;  a4=r19;  a5=r20;  a6=r21;  a7=r22;  a8=r23;
363 n1=r24;  n2=r25;  n3=r26;  n4=r27;  n5=r28;  n6=r29;  n7=r30;  n8=r31;
364 t0=r15;
365
366 ai0=f8;  ai1=f9;  ai2=f10; ai3=f11; ai4=f12; ai5=f13; ai6=f14; ai7=f15;
367 ni0=f16; ni1=f17; ni2=f18; ni3=f19; ni4=f20; ni5=f21; ni6=f22; ni7=f23;
368
369 .align  64
370 .skip   48              // aligns loop body
371 .local  bn_mul_mont_8#
372 .proc   bn_mul_mont_8#
373 bn_mul_mont_8:
374         .prologue
375 { .mmi; .save           ar.pfs,prevfs
376         alloc           prevfs=ar.pfs,6,2,0,8
377         .vframe         prevsp
378         mov             prevsp=sp
379         .save           ar.lc,prevlc
380         mov             prevlc=ar.lc    }
381 { .mmi; add             r17=-6*16,sp
382         add             sp=-7*16,sp
383         .save           pr,prevpr
384         mov             prevpr=pr       };;
385
386 { .mmi; .save.gf        0,0x10
387         stf.spill       [sp]=f16,-16
388         .save.gf        0,0x20
389         stf.spill       [r17]=f17,32
390         add             r16=-5*16,prevsp};;
391 { .mmi; .save.gf        0,0x40
392         stf.spill       [r16]=f18,32
393         .save.gf        0,0x80
394         stf.spill       [r17]=f19,32
395         $ADDP           aptr=0,in1      };;
396 { .mmi; .save.gf        0,0x100
397         stf.spill       [r16]=f20,32
398         .save.gf        0,0x200
399         stf.spill       [r17]=f21,32
400         $ADDP           r29=8,in1       };;
401 { .mmi; .save.gf        0,0x400
402         stf.spill       [r16]=f22
403         .save.gf        0,0x800
404         stf.spill       [r17]=f23
405         $ADDP           rptr=0,in0      };;
406 \f
407         .body
408         .rotf           bj[8],mj[2],tf[2],alo[10],ahi[10],nlo[10],nhi[10]
409         .rotr           t[8]
410
411 // load input vectors padding them to 8 elements
412 { .mmi; ldf8            ai0=[aptr],16           // ap[0]
413         ldf8            ai1=[r29],16            // ap[1]
414         $ADDP           bptr=0,in2      }
415 { .mmi; $ADDP           r30=8,in2
416         $ADDP           nptr=0,in3
417         $ADDP           r31=8,in3       };;
418 { .mmi; ldf8            bj[7]=[bptr],16         // bp[0]
419         ldf8            bj[6]=[r30],16          // bp[1]
420         cmp4.le         p4,p5=3,in5     }
421 { .mmi; ldf8            ni0=[nptr],16           // np[0]
422         ldf8            ni1=[r31],16            // np[1]
423         cmp4.le         p6,p7=4,in5     };;
424
425 { .mfi; (p4)ldf8        ai2=[aptr],16           // ap[2]
426         (p5)fcvt.fxu    ai2=f0
427         cmp4.le         p8,p9=5,in5     }
428 { .mfi; (p6)ldf8        ai3=[r29],16            // ap[3]
429         (p7)fcvt.fxu    ai3=f0
430         cmp4.le         p10,p11=6,in5   }
431 { .mfi; (p4)ldf8        bj[5]=[bptr],16         // bp[2]
432         (p5)fcvt.fxu    bj[5]=f0
433         cmp4.le         p12,p13=7,in5   }
434 { .mfi; (p6)ldf8        bj[4]=[r30],16          // bp[3]
435         (p7)fcvt.fxu    bj[4]=f0
436         cmp4.le         p14,p15=8,in5   }
437 { .mfi; (p4)ldf8        ni2=[nptr],16           // np[2]
438         (p5)fcvt.fxu    ni2=f0
439         addp4           r28=-1,in5      }
440 { .mfi; (p6)ldf8        ni3=[r31],16            // np[3]
441         (p7)fcvt.fxu    ni3=f0
442         $ADDP           in4=0,in4       };;
443
444 { .mfi; ldf8            n0=[in4]
445         fcvt.fxu        tf[1]=f0
446         nop.i           0               }
447
448 { .mfi; (p8)ldf8        ai4=[aptr],16           // ap[4]
449         (p9)fcvt.fxu    ai4=f0
450         mov             t[0]=r0         }
451 { .mfi; (p10)ldf8       ai5=[r29],16            // ap[5]
452         (p11)fcvt.fxu   ai5=f0
453         mov             t[1]=r0         }
454 { .mfi; (p8)ldf8        bj[3]=[bptr],16         // bp[4]
455         (p9)fcvt.fxu    bj[3]=f0
456         mov             t[2]=r0         }
457 { .mfi; (p10)ldf8       bj[2]=[r30],16          // bp[5]
458         (p11)fcvt.fxu   bj[2]=f0
459         mov             t[3]=r0         }
460 { .mfi; (p8)ldf8        ni4=[nptr],16           // np[4]
461         (p9)fcvt.fxu    ni4=f0
462         mov             t[4]=r0         }
463 { .mfi; (p10)ldf8       ni5=[r31],16            // np[5]
464         (p11)fcvt.fxu   ni5=f0
465         mov             t[5]=r0         };;
466
467 { .mfi; (p12)ldf8       ai6=[aptr],16           // ap[6]
468         (p13)fcvt.fxu   ai6=f0
469         mov             t[6]=r0         }
470 { .mfi; (p14)ldf8       ai7=[r29],16            // ap[7]
471         (p15)fcvt.fxu   ai7=f0
472         mov             t[7]=r0         }
473 { .mfi; (p12)ldf8       bj[1]=[bptr],16         // bp[6]
474         (p13)fcvt.fxu   bj[1]=f0
475         mov             ar.lc=r28       }
476 { .mfi; (p14)ldf8       bj[0]=[r30],16          // bp[7]
477         (p15)fcvt.fxu   bj[0]=f0
478         mov             ar.ec=1         }
479 { .mfi; (p12)ldf8       ni6=[nptr],16           // np[6]
480         (p13)fcvt.fxu   ni6=f0
481         mov             pr.rot=1<<16    }
482 { .mfb; (p14)ldf8       ni7=[r31],16            // np[7]
483         (p15)fcvt.fxu   ni7=f0
484         brp.loop.imp    .Louter_8_ctop,.Louter_8_cend-16
485                                         };;
486 \f
487 // The loop is scheduled for 32*n ticks on Itanium 2. Actual attempt
488 // to measure with help of Interval Time Counter indicated that the
489 // factor is a tad higher: 33 or 34, if not 35. Exact measurement and
490 // addressing the issue is problematic, because I don't have access
491 // to platform-specific instruction-level profiler. On Itanium it
492 // should run in 56*n ticks, because of higher xma latency...
493 .Louter_8_ctop:
494         .pred.rel               "mutex",p40,p42
495         .pred.rel               "mutex",p48,p50
496 { .mfi; (p16)   nop.m           0                       // 0:
497         (p16)   xma.hu          ahi[0]=ai0,bj[7],tf[1]  //      ap[0]*b[i]+t[0]
498         (p40)   add             a3=a3,n3        }       //      (p17) a3+=n3
499 { .mfi; (p42)   add             a3=a3,n3,1
500         (p16)   xma.lu          alo[0]=ai0,bj[7],tf[1]
501         (p16)   nop.i           0               };;
502 { .mii; (p17)   getf.sig        a7=alo[8]               // 1:
503         (p48)   add             t[6]=t[6],a3            //      (p17) t[6]+=a3
504         (p50)   add             t[6]=t[6],a3,1  };;
505 { .mfi; (p17)   getf.sig        a8=ahi[8]               // 2:
506         (p17)   xma.hu          nhi[7]=ni6,mj[1],nhi[6] //      np[6]*m0
507         (p40)   cmp.ltu         p43,p41=a3,n3   }
508 { .mfi; (p42)   cmp.leu         p43,p41=a3,n3
509         (p17)   xma.lu          nlo[7]=ni6,mj[1],nhi[6]
510         (p16)   nop.i           0               };;
511 { .mii; (p17)   getf.sig        n5=nlo[6]               // 3:
512         (p48)   cmp.ltu         p51,p49=t[6],a3
513         (p50)   cmp.leu         p51,p49=t[6],a3 };;
514         .pred.rel               "mutex",p41,p43
515         .pred.rel               "mutex",p49,p51
516 { .mfi; (p16)   nop.m           0                       // 4:
517         (p16)   xma.hu          ahi[1]=ai1,bj[7],ahi[0] //      ap[1]*b[i]
518         (p41)   add             a4=a4,n4        }       //      (p17) a4+=n4
519 { .mfi; (p43)   add             a4=a4,n4,1
520         (p16)   xma.lu          alo[1]=ai1,bj[7],ahi[0]
521         (p16)   nop.i           0               };;
522 { .mfi; (p49)   add             t[5]=t[5],a4            // 5:   (p17) t[5]+=a4
523         (p16)   xmpy.lu         mj[0]=alo[0],n0         //      (ap[0]*b[i]+t[0])*n0
524         (p51)   add             t[5]=t[5],a4,1  };;
525 { .mfi; (p16)   nop.m           0                       // 6:
526         (p17)   xma.hu          nhi[8]=ni7,mj[1],nhi[7] //      np[7]*m0
527         (p41)   cmp.ltu         p42,p40=a4,n4   }
528 { .mfi; (p43)   cmp.leu         p42,p40=a4,n4
529         (p17)   xma.lu          nlo[8]=ni7,mj[1],nhi[7]
530         (p16)   nop.i           0               };;
531 { .mii; (p17)   getf.sig        n6=nlo[7]               // 7:
532         (p49)   cmp.ltu         p50,p48=t[5],a4
533         (p51)   cmp.leu         p50,p48=t[5],a4 };;
534         .pred.rel               "mutex",p40,p42
535         .pred.rel               "mutex",p48,p50
536 { .mfi; (p16)   nop.m           0                       // 8:
537         (p16)   xma.hu          ahi[2]=ai2,bj[7],ahi[1] //      ap[2]*b[i]
538         (p40)   add             a5=a5,n5        }       //      (p17) a5+=n5
539 { .mfi; (p42)   add             a5=a5,n5,1
540         (p16)   xma.lu          alo[2]=ai2,bj[7],ahi[1]
541         (p16)   nop.i           0               };;
542 { .mii; (p16)   getf.sig        a1=alo[1]               // 9:
543         (p48)   add             t[4]=t[4],a5            //      p(17) t[4]+=a5
544         (p50)   add             t[4]=t[4],a5,1  };;
545 { .mfi; (p16)   nop.m           0                       // 10:
546         (p16)   xma.hu          nhi[0]=ni0,mj[0],alo[0] //      np[0]*m0
547         (p40)   cmp.ltu         p43,p41=a5,n5   }
548 { .mfi; (p42)   cmp.leu         p43,p41=a5,n5
549         (p16)   xma.lu          nlo[0]=ni0,mj[0],alo[0]
550         (p16)   nop.i           0               };;
551 { .mii; (p17)   getf.sig        n7=nlo[8]               // 11:
552         (p48)   cmp.ltu         p51,p49=t[4],a5
553         (p50)   cmp.leu         p51,p49=t[4],a5 };;
554         .pred.rel               "mutex",p41,p43
555         .pred.rel               "mutex",p49,p51
556 { .mfi; (p17)   getf.sig        n8=nhi[8]               // 12:
557         (p16)   xma.hu          ahi[3]=ai3,bj[7],ahi[2] //      ap[3]*b[i]
558         (p41)   add             a6=a6,n6        }       //      (p17) a6+=n6
559 { .mfi; (p43)   add             a6=a6,n6,1
560         (p16)   xma.lu          alo[3]=ai3,bj[7],ahi[2]
561         (p16)   nop.i           0               };;
562 { .mii; (p16)   getf.sig        a2=alo[2]               // 13:
563         (p49)   add             t[3]=t[3],a6            //      (p17) t[3]+=a6
564         (p51)   add             t[3]=t[3],a6,1  };;
565 { .mfi; (p16)   nop.m           0                       // 14:
566         (p16)   xma.hu          nhi[1]=ni1,mj[0],nhi[0] //      np[1]*m0
567         (p41)   cmp.ltu         p42,p40=a6,n6   }
568 { .mfi; (p43)   cmp.leu         p42,p40=a6,n6
569         (p16)   xma.lu          nlo[1]=ni1,mj[0],nhi[0]
570         (p16)   nop.i           0               };;
571 { .mii; (p16)   nop.m           0                       // 15:
572         (p49)   cmp.ltu         p50,p48=t[3],a6
573         (p51)   cmp.leu         p50,p48=t[3],a6 };;
574         .pred.rel               "mutex",p40,p42
575         .pred.rel               "mutex",p48,p50
576 { .mfi; (p16)   nop.m           0                       // 16:
577         (p16)   xma.hu          ahi[4]=ai4,bj[7],ahi[3] //      ap[4]*b[i]
578         (p40)   add             a7=a7,n7        }       //      (p17) a7+=n7
579 { .mfi; (p42)   add             a7=a7,n7,1
580         (p16)   xma.lu          alo[4]=ai4,bj[7],ahi[3]
581         (p16)   nop.i           0               };;
582 { .mii; (p16)   getf.sig        a3=alo[3]               // 17:
583         (p48)   add             t[2]=t[2],a7            //      (p17) t[2]+=a7
584         (p50)   add             t[2]=t[2],a7,1  };;
585 { .mfi; (p16)   nop.m           0                       // 18:
586         (p16)   xma.hu          nhi[2]=ni2,mj[0],nhi[1] //      np[2]*m0
587         (p40)   cmp.ltu         p43,p41=a7,n7   }
588 { .mfi; (p42)   cmp.leu         p43,p41=a7,n7
589         (p16)   xma.lu          nlo[2]=ni2,mj[0],nhi[1]
590         (p16)   nop.i           0               };;
591 { .mii; (p16)   getf.sig        n1=nlo[1]               // 19:
592         (p48)   cmp.ltu         p51,p49=t[2],a7
593         (p50)   cmp.leu         p51,p49=t[2],a7 };;
594         .pred.rel               "mutex",p41,p43
595         .pred.rel               "mutex",p49,p51
596 { .mfi; (p16)   nop.m           0                       // 20:
597         (p16)   xma.hu          ahi[5]=ai5,bj[7],ahi[4] //      ap[5]*b[i]
598         (p41)   add             a8=a8,n8        }       //      (p17) a8+=n8
599 { .mfi; (p43)   add             a8=a8,n8,1
600         (p16)   xma.lu          alo[5]=ai5,bj[7],ahi[4]
601         (p16)   nop.i           0               };;
602 { .mii; (p16)   getf.sig        a4=alo[4]               // 21:
603         (p49)   add             t[1]=t[1],a8            //      (p17) t[1]+=a8
604         (p51)   add             t[1]=t[1],a8,1  };;
605 { .mfi; (p16)   nop.m           0                       // 22:
606         (p16)   xma.hu          nhi[3]=ni3,mj[0],nhi[2] //      np[3]*m0
607         (p41)   cmp.ltu         p42,p40=a8,n8   }
608 { .mfi; (p43)   cmp.leu         p42,p40=a8,n8
609         (p16)   xma.lu          nlo[3]=ni3,mj[0],nhi[2]
610         (p16)   nop.i           0               };;
611 { .mii; (p16)   getf.sig        n2=nlo[2]               // 23:
612         (p49)   cmp.ltu         p50,p48=t[1],a8
613         (p51)   cmp.leu         p50,p48=t[1],a8 };;
614 { .mfi; (p16)   nop.m           0                       // 24:
615         (p16)   xma.hu          ahi[6]=ai6,bj[7],ahi[5] //      ap[6]*b[i]
616         (p16)   add             a1=a1,n1        }       //      (p16) a1+=n1
617 { .mfi; (p16)   nop.m           0
618         (p16)   xma.lu          alo[6]=ai6,bj[7],ahi[5]
619         (p17)   mov             t[0]=r0         };;
620 { .mii; (p16)   getf.sig        a5=alo[5]               // 25:
621         (p16)   add             t0=t[7],a1              //      (p16) t[7]+=a1
622         (p42)   add             t[0]=t[0],r0,1  };;
623 { .mfi; (p16)   setf.sig        tf[0]=t0                // 26:
624         (p16)   xma.hu          nhi[4]=ni4,mj[0],nhi[3] //      np[4]*m0
625         (p50)   add             t[0]=t[0],r0,1  }
626 { .mfi; (p16)   cmp.ltu.unc     p42,p40=a1,n1
627         (p16)   xma.lu          nlo[4]=ni4,mj[0],nhi[3]
628         (p16)   nop.i           0               };;
629 { .mii; (p16)   getf.sig        n3=nlo[3]               // 27:
630         (p16)   cmp.ltu.unc     p50,p48=t0,a1
631         (p16)   nop.i           0               };;
632         .pred.rel               "mutex",p40,p42
633         .pred.rel               "mutex",p48,p50
634 { .mfi; (p16)   nop.m           0                       // 28:
635         (p16)   xma.hu          ahi[7]=ai7,bj[7],ahi[6] //      ap[7]*b[i]
636         (p40)   add             a2=a2,n2        }       //      (p16) a2+=n2
637 { .mfi; (p42)   add             a2=a2,n2,1
638         (p16)   xma.lu          alo[7]=ai7,bj[7],ahi[6]
639         (p16)   nop.i           0               };;
640 { .mii; (p16)   getf.sig        a6=alo[6]               // 29:
641         (p48)   add             t[6]=t[6],a2            //      (p16) t[6]+=a2
642         (p50)   add             t[6]=t[6],a2,1  };;
643 { .mfi; (p16)   nop.m           0                       // 30:
644         (p16)   xma.hu          nhi[5]=ni5,mj[0],nhi[4] //      np[5]*m0
645         (p40)   cmp.ltu         p41,p39=a2,n2   }
646 { .mfi; (p42)   cmp.leu         p41,p39=a2,n2
647         (p16)   xma.lu          nlo[5]=ni5,mj[0],nhi[4]
648         (p16)   nop.i           0               };;
649 { .mfi; (p16)   getf.sig        n4=nlo[4]               // 31:
650         (p16)   nop.f           0
651         (p48)   cmp.ltu         p49,p47=t[6],a2 }
652 { .mfb; (p50)   cmp.leu         p49,p47=t[6],a2
653         (p16)   nop.f           0
654         br.ctop.sptk.many       .Louter_8_ctop  };;
655 .Louter_8_cend:
656 \f
657 // above loop has to execute one more time, without (p16), which is
658 // replaced with merged move of np[8] to GPR bank
659         .pred.rel               "mutex",p40,p42
660         .pred.rel               "mutex",p48,p50
661 { .mmi; (p0)    getf.sig        n1=ni0                  // 0:
662         (p40)   add             a3=a3,n3                //      (p17) a3+=n3
663         (p42)   add             a3=a3,n3,1      };;
664 { .mii; (p17)   getf.sig        a7=alo[8]               // 1:
665         (p48)   add             t[6]=t[6],a3            //      (p17) t[6]+=a3
666         (p50)   add             t[6]=t[6],a3,1  };;
667 { .mfi; (p17)   getf.sig        a8=ahi[8]               // 2:
668         (p17)   xma.hu          nhi[7]=ni6,mj[1],nhi[6] //      np[6]*m0
669         (p40)   cmp.ltu         p43,p41=a3,n3   }
670 { .mfi; (p42)   cmp.leu         p43,p41=a3,n3
671         (p17)   xma.lu          nlo[7]=ni6,mj[1],nhi[6]
672         (p0)    nop.i           0               };;
673 { .mii; (p17)   getf.sig        n5=nlo[6]               // 3:
674         (p48)   cmp.ltu         p51,p49=t[6],a3
675         (p50)   cmp.leu         p51,p49=t[6],a3 };;
676         .pred.rel               "mutex",p41,p43
677         .pred.rel               "mutex",p49,p51
678 { .mmi; (p0)    getf.sig        n2=ni1                  // 4:
679         (p41)   add             a4=a4,n4                //      (p17) a4+=n4
680         (p43)   add             a4=a4,n4,1      };;
681 { .mfi; (p49)   add             t[5]=t[5],a4            // 5:   (p17) t[5]+=a4
682         (p0)    nop.f           0
683         (p51)   add             t[5]=t[5],a4,1  };;
684 { .mfi; (p0)    getf.sig        n3=ni2                  // 6:
685         (p17)   xma.hu          nhi[8]=ni7,mj[1],nhi[7] //      np[7]*m0
686         (p41)   cmp.ltu         p42,p40=a4,n4   }
687 { .mfi; (p43)   cmp.leu         p42,p40=a4,n4
688         (p17)   xma.lu          nlo[8]=ni7,mj[1],nhi[7]
689         (p0)    nop.i           0               };;
690 { .mii; (p17)   getf.sig        n6=nlo[7]               // 7:
691         (p49)   cmp.ltu         p50,p48=t[5],a4
692         (p51)   cmp.leu         p50,p48=t[5],a4 };;
693         .pred.rel               "mutex",p40,p42
694         .pred.rel               "mutex",p48,p50
695 { .mii; (p0)    getf.sig        n4=ni3                  // 8:
696         (p40)   add             a5=a5,n5                //      (p17) a5+=n5
697         (p42)   add             a5=a5,n5,1      };;
698 { .mii; (p0)    nop.m           0                       // 9:
699         (p48)   add             t[4]=t[4],a5            //      p(17) t[4]+=a5
700         (p50)   add             t[4]=t[4],a5,1  };;
701 { .mii; (p0)    nop.m           0                       // 10:
702         (p40)   cmp.ltu         p43,p41=a5,n5
703         (p42)   cmp.leu         p43,p41=a5,n5   };;
704 { .mii; (p17)   getf.sig        n7=nlo[8]               // 11:
705         (p48)   cmp.ltu         p51,p49=t[4],a5
706         (p50)   cmp.leu         p51,p49=t[4],a5 };;
707         .pred.rel               "mutex",p41,p43
708         .pred.rel               "mutex",p49,p51
709 { .mii; (p17)   getf.sig        n8=nhi[8]               // 12:
710         (p41)   add             a6=a6,n6                //      (p17) a6+=n6
711         (p43)   add             a6=a6,n6,1      };;
712 { .mii; (p0)    getf.sig        n5=ni4                  // 13:
713         (p49)   add             t[3]=t[3],a6            //      (p17) t[3]+=a6
714         (p51)   add             t[3]=t[3],a6,1  };;
715 { .mii; (p0)    nop.m           0                       // 14:
716         (p41)   cmp.ltu         p42,p40=a6,n6
717         (p43)   cmp.leu         p42,p40=a6,n6   };;
718 { .mii; (p0)    getf.sig        n6=ni5                  // 15:
719         (p49)   cmp.ltu         p50,p48=t[3],a6
720         (p51)   cmp.leu         p50,p48=t[3],a6 };;
721         .pred.rel               "mutex",p40,p42
722         .pred.rel               "mutex",p48,p50
723 { .mii; (p0)    nop.m           0                       // 16:
724         (p40)   add             a7=a7,n7                //      (p17) a7+=n7
725         (p42)   add             a7=a7,n7,1      };;
726 { .mii; (p0)    nop.m           0                       // 17:
727         (p48)   add             t[2]=t[2],a7            //      (p17) t[2]+=a7
728         (p50)   add             t[2]=t[2],a7,1  };;
729 { .mii; (p0)    nop.m           0                       // 18:
730         (p40)   cmp.ltu         p43,p41=a7,n7
731         (p42)   cmp.leu         p43,p41=a7,n7   };;
732 { .mii; (p0)    getf.sig        n7=ni6                  // 19:
733         (p48)   cmp.ltu         p51,p49=t[2],a7
734         (p50)   cmp.leu         p51,p49=t[2],a7 };;
735         .pred.rel               "mutex",p41,p43
736         .pred.rel               "mutex",p49,p51
737 { .mii; (p0)    nop.m           0                       // 20:
738         (p41)   add             a8=a8,n8                //      (p17) a8+=n8
739         (p43)   add             a8=a8,n8,1      };;
740 { .mmi; (p0)    nop.m           0                       // 21:
741         (p49)   add             t[1]=t[1],a8            //      (p17) t[1]+=a8
742         (p51)   add             t[1]=t[1],a8,1  }
743 { .mmi; (p17)   mov             t[0]=r0
744         (p41)   cmp.ltu         p42,p40=a8,n8
745         (p43)   cmp.leu         p42,p40=a8,n8   };;
746 { .mmi; (p0)    getf.sig        n8=ni7                  // 22:
747         (p49)   cmp.ltu         p50,p48=t[1],a8
748         (p51)   cmp.leu         p50,p48=t[1],a8 }
749 { .mmi; (p42)   add             t[0]=t[0],r0,1
750         (p0)    add             r16=-7*16,prevsp
751         (p0)    add             r17=-6*16,prevsp        };;
752 \f
753 // subtract np[8] from carrybit|tmp[8]
754 // carrybit|tmp[8] layout upon exit from above loop is:
755 //      t[0]|t[1]|t[2]|t[3]|t[4]|t[5]|t[6]|t[7]|t0 (least significant)
756 { .mmi; (p50)add        t[0]=t[0],r0,1
757         add             r18=-5*16,prevsp
758         sub             n1=t0,n1        };;
759 { .mmi; cmp.gtu         p34,p32=n1,t0;;
760         .pred.rel       "mutex",p32,p34
761         (p32)sub        n2=t[7],n2
762         (p34)sub        n2=t[7],n2,1    };;
763 { .mii; (p32)cmp.gtu    p35,p33=n2,t[7]
764         (p34)cmp.geu    p35,p33=n2,t[7];;
765         .pred.rel       "mutex",p33,p35
766         (p33)sub        n3=t[6],n3      }
767 { .mmi; (p35)sub        n3=t[6],n3,1;;
768         (p33)cmp.gtu    p34,p32=n3,t[6]
769         (p35)cmp.geu    p34,p32=n3,t[6] };;
770         .pred.rel       "mutex",p32,p34
771 { .mii; (p32)sub        n4=t[5],n4
772         (p34)sub        n4=t[5],n4,1;;
773         (p32)cmp.gtu    p35,p33=n4,t[5] }
774 { .mmi; (p34)cmp.geu    p35,p33=n4,t[5];;
775         .pred.rel       "mutex",p33,p35
776         (p33)sub        n5=t[4],n5
777         (p35)sub        n5=t[4],n5,1    };;
778 { .mii; (p33)cmp.gtu    p34,p32=n5,t[4]
779         (p35)cmp.geu    p34,p32=n5,t[4];;
780         .pred.rel       "mutex",p32,p34
781         (p32)sub        n6=t[3],n6      }
782 { .mmi; (p34)sub        n6=t[3],n6,1;;
783         (p32)cmp.gtu    p35,p33=n6,t[3]
784         (p34)cmp.geu    p35,p33=n6,t[3] };;
785         .pred.rel       "mutex",p33,p35
786 { .mii; (p33)sub        n7=t[2],n7
787         (p35)sub        n7=t[2],n7,1;;
788         (p33)cmp.gtu    p34,p32=n7,t[2] }
789 { .mmi; (p35)cmp.geu    p34,p32=n7,t[2];;
790         .pred.rel       "mutex",p32,p34
791         (p32)sub        n8=t[1],n8
792         (p34)sub        n8=t[1],n8,1    };;
793 { .mii; (p32)cmp.gtu    p35,p33=n8,t[1]
794         (p34)cmp.geu    p35,p33=n8,t[1];;
795         .pred.rel       "mutex",p33,p35
796         (p33)sub        a8=t[0],r0      }
797 { .mmi; (p35)sub        a8=t[0],r0,1;;
798         (p33)cmp.gtu    p34,p32=a8,t[0]
799         (p35)cmp.geu    p34,p32=a8,t[0] };;
800 \f
801 // save the result, either tmp[num] or tmp[num]-np[num]
802         .pred.rel       "mutex",p32,p34
803 { .mmi; (p32)st8        [rptr]=n1,8
804         (p34)st8        [rptr]=t0,8
805         add             r19=-4*16,prevsp};;
806 { .mmb; (p32)st8        [rptr]=n2,8
807         (p34)st8        [rptr]=t[7],8
808         (p5)br.cond.dpnt.few    .Ldone  };;
809 { .mmb; (p32)st8        [rptr]=n3,8
810         (p34)st8        [rptr]=t[6],8
811         (p7)br.cond.dpnt.few    .Ldone  };;
812 { .mmb; (p32)st8        [rptr]=n4,8
813         (p34)st8        [rptr]=t[5],8
814         (p9)br.cond.dpnt.few    .Ldone  };;
815 { .mmb; (p32)st8        [rptr]=n5,8
816         (p34)st8        [rptr]=t[4],8
817         (p11)br.cond.dpnt.few   .Ldone  };;
818 { .mmb; (p32)st8        [rptr]=n6,8
819         (p34)st8        [rptr]=t[3],8
820         (p13)br.cond.dpnt.few   .Ldone  };;
821 { .mmb; (p32)st8        [rptr]=n7,8
822         (p34)st8        [rptr]=t[2],8
823         (p15)br.cond.dpnt.few   .Ldone  };;
824 { .mmb; (p32)st8        [rptr]=n8,8
825         (p34)st8        [rptr]=t[1],8
826         nop.b           0               };;
827 .Ldone:                                         // epilogue
828 { .mmi; ldf.fill        f16=[r16],64
829         ldf.fill        f17=[r17],64
830         nop.i           0               }
831 { .mmi; ldf.fill        f18=[r18],64
832         ldf.fill        f19=[r19],64
833         mov             pr=prevpr,0x1ffff       };;
834 { .mmi; ldf.fill        f20=[r16]
835         ldf.fill        f21=[r17]
836         mov             ar.lc=prevlc    }
837 { .mmi; ldf.fill        f22=[r18]
838         ldf.fill        f23=[r19]
839         mov             ret0=1          }       // signal "handled"
840 { .mib; rum             1<<5
841         .restore        sp
842         mov             sp=prevsp
843         br.ret.sptk.many        b0      };;
844 .endp   bn_mul_mont_8#
845
846 .type   copyright#,\@object
847 copyright:
848 stringz "Montgomery multiplication for IA-64, CRYPTOGAMS by <appro\@openssl.org>"
849 ___
850
851 open STDOUT,">$output" if $output;
852 print $code;
853 close STDOUT;