Merge Intel copyright notice into standard
[openssl.git] / crypto / bn / asm / ia64.S
index 7dfda85..abc1100 100644 (file)
@@ -1,8 +1,15 @@
 .explicit
 .text
-.ident "ia64.S, Version 2.0"
+.ident "ia64.S, Version 2.1"
 .ident "IA-64 ISA artwork by Andy Polyakov <appro@fy.chalmers.se>"
 
+// Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved.
+//
+// Licensed under the OpenSSL license (the "License").  You may not use
+// this file except in compliance with the License.  You can obtain a copy
+// in the file LICENSE in the source distribution or at
+// https://www.openssl.org/source/license.html
+
 //
 // ====================================================================
 // Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
@@ -22,7 +29,7 @@
 // ports is the same, i.e. 2, while I need 4. In other words, to this
 // module Itanium2 remains effectively as "wide" as Itanium. Yet it's
 // essentially different in respect to this module, and a re-tune was
-// required. Well, because some intruction latencies has changed. Most
+// required. Well, because some instruction latencies has changed. Most
 // noticeably those intensively used:
 //
 //                     Itanium Itanium2
@@ -35,7 +42,7 @@
 // What does it mean? You might ratiocinate that the original code
 // should run just faster... Because sum of latencies is smaller...
 // Wrong! Note that getf latency increased. This means that if a loop is
-// scheduled for lower latency (and they are), then it will suffer from
+// scheduled for lower latency (as they were), then it will suffer from
 // stall condition and the code will therefore turn anti-scalable, e.g.
 // original bn_mul_words spun at 5*n or 2.5 times slower than expected
 // on Itanium2! What to do? Reschedule loops for Itanium2? But then
 //     -Drum=nop.m in command line.
 //
 
+#if defined(_HPUX_SOURCE) && !defined(_LP64)
+#define        ADDP    addp4
+#else
+#define        ADDP    add
+#endif
+
 #if 1
 //
 // bn_[add|sub]_words routines.
 .skip  32      // makes the loop body aligned at 64-byte boundary
 bn_add_words:
        .prologue
-       .fframe 0
        .save   ar.pfs,r2
 { .mii;        alloc           r2=ar.pfs,4,12,0,16
        cmp4.le         p6,p0=r35,r0    };;
 { .mfb;        mov             r8=r0                   // return value
 (p6)   br.ret.spnt.many        b0      };;
 
-       .save   ar.lc,r3
 { .mib;        sub             r10=r35,r0,1
+       .save   ar.lc,r3
        mov             r3=ar.lc
        brp.loop.imp    .L_bn_add_words_ctop,.L_bn_add_words_cend-16
                                        }
-       .body
-{ .mib;
-#if defined(_HPUX_SOURCE) && defined(_ILP32)
-       addp4           r14=0,r32               // rp
-#else
-       mov             r14=r32                 // rp
-#endif
+{ .mib;        ADDP            r14=0,r32               // rp
+       .save   pr,r9
        mov             r9=pr           };;
-{ .mii;
-#if defined(_HPUX_SOURCE) && defined(_ILP32)
-       addp4           r15=0,r33               // ap
-#else
-       mov             r15=r33                 // ap
-#endif
+       .body
+{ .mii;        ADDP            r15=0,r33               // ap
        mov             ar.lc=r10
        mov             ar.ec=6         }
-{ .mib;
-#if defined(_HPUX_SOURCE) && defined(_ILP32)
-       addp4           r16=0,r34               // bp
-#else
-       mov             r16=r34                 // bp
-#endif
+{ .mib;        ADDP            r16=0,r34               // bp
        mov             pr.rot=1<<16    };;
 
 .L_bn_add_words_ctop:
@@ -233,40 +231,25 @@ bn_add_words:
 .skip  32      // makes the loop body aligned at 64-byte boundary
 bn_sub_words:
        .prologue
-       .fframe 0
        .save   ar.pfs,r2
 { .mii;        alloc           r2=ar.pfs,4,12,0,16
        cmp4.le         p6,p0=r35,r0    };;
 { .mfb;        mov             r8=r0                   // return value
 (p6)   br.ret.spnt.many        b0      };;
 
-       .save   ar.lc,r3
 { .mib;        sub             r10=r35,r0,1
+       .save   ar.lc,r3
        mov             r3=ar.lc
        brp.loop.imp    .L_bn_sub_words_ctop,.L_bn_sub_words_cend-16
                                        }
-       .body
-{ .mib;
-#if defined(_HPUX_SOURCE) && defined(_ILP32)
-       addp4           r14=0,r32               // rp
-#else
-       mov             r14=r32                 // rp
-#endif
+{ .mib;        ADDP            r14=0,r32               // rp
+       .save   pr,r9
        mov             r9=pr           };;
-{ .mii;
-#if defined(_HPUX_SOURCE) && defined(_ILP32)
-       addp4           r15=0,r33               // ap
-#else
-       mov             r15=r33                 // ap
-#endif
+       .body
+{ .mii;        ADDP            r15=0,r33               // ap
        mov             ar.lc=r10
        mov             ar.ec=6         }
-{ .mib;
-#if defined(_HPUX_SOURCE) && defined(_ILP32)
-       addp4           r16=0,r34               // bp
-#else
-       mov             r16=r34                 // bp
-#endif
+{ .mib;        ADDP            r16=0,r34               // bp
        mov             pr.rot=1<<16    };;
 
 .L_bn_sub_words_ctop:
@@ -307,7 +290,6 @@ bn_sub_words:
 .skip  32      // makes the loop body aligned at 64-byte boundary
 bn_mul_words:
        .prologue
-       .fframe 0
        .save   ar.pfs,r2
 #ifdef XMA_TEMPTATION
 { .mfi;        alloc           r2=ar.pfs,4,0,0,0       };;
@@ -318,9 +300,10 @@ bn_mul_words:
        cmp4.le         p6,p0=r34,r0
 (p6)   br.ret.spnt.many        b0              };;
 
-       .save   ar.lc,r3
 { .mii;        sub     r10=r34,r0,1
+       .save   ar.lc,r3
        mov     r3=ar.lc
+       .save   pr,r9
        mov     r9=pr                   };;
 
        .body
@@ -332,16 +315,10 @@ bn_mul_words:
 
 #ifndef XMA_TEMPTATION
 
-{ .mii;
-#if defined(_HPUX_SOURCE) && defined(_ILP32)
-       addp4           r14=0,r32       // rp
-       addp4           r15=0,r33       // ap
-#else
-       mov             r14=r32         // rp
-       mov             r15=r33         // ap
-#endif
+{ .mmi;        ADDP            r14=0,r32       // rp
+       ADDP            r15=0,r33       // ap
        mov             ar.lc=r10       }
-{ .mii;        mov             r40=0   // serves as r35 at first (p27)
+{ .mmi;        mov             r40=0           // serves as r35 at first (p27)
        mov             ar.ec=13        };;
 
 // This loop spins in 2*(n+12) ticks. It's scheduled for data in Itanium
@@ -393,7 +370,7 @@ bn_mul_words:
 // The loop therefore spins at the latency of xma minus 1, or in other
 // words at 6*(n+4) ticks:-( Compare to the "production" loop above
 // that runs in 2*(n+11) where the low latency problem is worked around
-// by moving the dependency to one-tick latent interger ALU. Note that
+// by moving the dependency to one-tick latent integer ALU. Note that
 // "distance" between ldf8 and xma is not latency of ldf8, but the
 // *difference* between xma and ldf8 latencies.
 .L_bn_mul_words_ctop:
@@ -424,89 +401,63 @@ bn_mul_words:
 .global        bn_mul_add_words#
 .proc  bn_mul_add_words#
 .align 64
-//.skip        0       // makes the loop split at 64-byte boundary
+.skip  48      // makes the loop body aligned at 64-byte boundary
 bn_mul_add_words:
        .prologue
-       .fframe 0
        .save   ar.pfs,r2
-{ .mii;        alloc           r2=ar.pfs,4,12,0,16
-       cmp4.le         p6,p0=r34,r0    };;
-{ .mfb;        mov             r8=r0                   // return value
-(p6)   br.ret.spnt.many        b0      };;
-
+{ .mmi;        alloc           r2=ar.pfs,4,4,0,8
+       cmp4.le         p6,p0=r34,r0
        .save   ar.lc,r3
-{ .mii;        sub     r10=r34,r0,1
-       mov     r3=ar.lc
-       mov     r9=pr                   };;
+       mov             r3=ar.lc        };;
+{ .mib;        mov             r8=r0           // return value
+       sub             r10=r34,r0,1
+(p6)   br.ret.spnt.many        b0      };;
 
-       .body
-{ .mib;        setf.sig        f8=r35  // w
-       mov             pr.rot=0x800001<<16
-                       // ------^----- serves as (p50) at first (p27)
+{ .mib;        setf.sig        f8=r35          // w
+       .save   pr,r9
+       mov             r9=pr
        brp.loop.imp    .L_bn_mul_add_words_ctop,.L_bn_mul_add_words_cend-16
                                        }
-{ .mii;
-#if defined(_HPUX_SOURCE) && defined(_ILP32)
-       addp4           r14=0,r32       // rp
-       addp4           r15=0,r33       // ap
-#else
-       mov             r14=r32         // rp
-       mov             r15=r33         // ap
-#endif
+       .body
+{ .mmi;        ADDP            r14=0,r32       // rp
+       ADDP            r15=0,r33       // ap
        mov             ar.lc=r10       }
-{ .mii;        mov             r40=0   // serves as r35 at first (p27)
-#if defined(_HPUX_SOURCE) && defined(_ILP32)
-       addp4           r18=0,r32       // rp copy
-#else
-       mov             r18=r32         // rp copy
-#endif
-       mov             ar.ec=15        };;
-
-// This loop spins in 3*(n+14) ticks on Itanium and should spin in
-// 2*(n+14) on "wider" IA-64 implementations (to be verified with new
-// µ-architecture manuals as they become available). As usual it's
-// possible to compress the epilogue, down to 10 in this case, at the
-// cost of scalability. Compressed (and therefore non-scalable) loop
-// running at 3*(n+11) would buy you ~10% on Itanium but take ~35%
-// from "wider" IA-64 so let it be scalable! Special attention was
-// paid for having the loop body split at 64-byte boundary. ld8 is
-// scheduled for L1 cache as the data is more than likely there.
-// Indeed, bn_mul_words has put it there a moment ago:-)
+{ .mii;        ADDP            r16=0,r32       // rp copy
+       mov             pr.rot=0x2001<<16
+                       // ------^----- serves as (p40) at first (p27)
+       mov             ar.ec=11        };;
+
+// This loop spins in 3*(n+10) ticks on Itanium and in 2*(n+10) on
+// Itanium 2. Yes, unlike previous versions it scales:-) Previous
+// version was performing *all* additions in IALU and was starving
+// for those even on Itanium 2. In this version one addition is
+// moved to FPU and is folded with multiplication. This is at cost
+// of propagating the result from previous call to this subroutine
+// to L2 cache... In other words negligible even for shorter keys.
+// *Overall* performance improvement [over previous version] varies
+// from 11 to 22 percent depending on key length.
 .L_bn_mul_add_words_ctop:
-{ .mfi;        (p25)   getf.sig        r36=f52                 // low
-       (p21)   xmpy.lu         f48=f37,f8
-       (p28)   cmp.ltu         p54,p50=r41,r39 }
-{ .mfi;        (p16)   ldf8            f32=[r15],8
-       (p21)   xmpy.hu         f40=f37,f8
-       (p28)   add             r45=r45,r41     };;
-{ .mii;        (p25)   getf.sig        r32=f44                 // high
-       .pred.rel       "mutex",p50,p54
-       (p50)   add             r40=r38,r35             // (p27)
-       (p54)   add             r40=r38,r35,1   }       // (p27)
-{ .mfb;        (p28)   cmp.ltu.unc     p60,p0=r45,r41
-       (p0)    nop.f           0x0
-       (p0)    nop.b           0x0             }
-{ .mii;        (p27)   ld8             r44=[r18],8
-       (p62)   cmp.eq.or       p61,p0=-1,r46
-       (p62)   add             r46=1,r46       }
-{ .mfb;        (p30)   st8             [r14]=r47,8
-       (p0)    nop.f           0x0
+.pred.rel      "mutex",p40,p42
+{ .mfi;        (p23)   getf.sig        r36=f45                 // low
+       (p20)   xma.lu          f42=f36,f8,f50          // low
+       (p40)   add             r39=r39,r35     }       // (p27)
+{ .mfi;        (p16)   ldf8            f32=[r15],8             // *(ap++)
+       (p20)   xma.hu          f36=f36,f8,f50          // high
+       (p42)   add             r39=r39,r35,1   };;     // (p27)
+{ .mmi;        (p24)   getf.sig        r32=f40                 // high
+       (p16)   ldf8            f46=[r16],8             // *(rp1++)
+       (p40)   cmp.ltu         p41,p39=r39,r35 }       // (p27)
+{ .mib;        (p26)   st8             [r14]=r39,8             // *(rp2++)
+       (p42)   cmp.leu         p41,p39=r39,r35         // (p27)
        br.ctop.sptk    .L_bn_mul_add_words_ctop};;
 .L_bn_mul_add_words_cend:
 
-{ .mii;        nop.m           0x0
-.pred.rel      "mutex",p53,p57
-(p53)  add             r8=r38,r0
-(p57)  add             r8=r38,r0,1     }
-{ .mfb;        nop.m   0x0
-       nop.f   0x0
-       nop.b   0x0                     };;
-{ .mii;
-(p63)  add             r8=1,r8
-       mov             pr=r9,0x1ffff
-       mov             ar.lc=r3        }
-{ .mfb;        rum             1<<5            // clear um.mfh
-       nop.f           0x0
+{ .mmi;        .pred.rel       "mutex",p40,p42
+(p40)  add             r8=r35,r0
+(p42)  add             r8=r35,r0,1
+       mov             pr=r9,0x1ffff   }
+{ .mib;        rum             1<<5            // clear um.mfh
+       mov             ar.lc=r3
        br.ret.sptk.many        b0      };;
 .endp  bn_mul_add_words#
 #endif
@@ -521,26 +472,23 @@ bn_mul_add_words:
 .skip  32      // makes the loop body aligned at 64-byte boundary 
 bn_sqr_words:
        .prologue
-       .fframe 0
        .save   ar.pfs,r2
 { .mii;        alloc           r2=ar.pfs,3,0,0,0
        sxt4            r34=r34         };;
 { .mii;        cmp.le          p6,p0=r34,r0
        mov             r8=r0           }       // return value
-{ .mfb;        nop.f           0x0
+{ .mfb;        ADDP            r32=0,r32
+       nop.f           0x0
 (p6)   br.ret.spnt.many        b0      };;
 
-       .save   ar.lc,r3
 { .mii;        sub     r10=r34,r0,1
+       .save   ar.lc,r3
        mov     r3=ar.lc
+       .save   pr,r9
        mov     r9=pr                   };;
 
        .body
-#if defined(_HPUX_SOURCE) && defined(_ILP32)
-{ .mii; addp4          r32=0,r32
-       addp4           r33=0,r33       };;
-#endif
-{ .mib;
+{ .mib;        ADDP            r33=0,r33
        mov             pr.rot=1<<16
        brp.loop.imp    .L_bn_sqr_words_ctop,.L_bn_sqr_words_cend-16
                                        }
@@ -554,7 +502,7 @@ bn_sqr_words:
 // scalability. The decision will very likely be reconsidered after the
 // benchmark program is profiled. I.e. if perfomance gain on Itanium
 // will appear larger than loss on "wider" IA-64, then the loop should
-// be explicitely split and the epilogue compressed.
+// be explicitly split and the epilogue compressed.
 .L_bn_sqr_words_ctop:
 { .mfi;        (p16)   ldf8            f32=[r33],8
        (p25)   xmpy.lu         f42=f41,f41
@@ -603,9 +551,8 @@ bn_sqr_words:
 .align 64
 bn_sqr_comba8:
        .prologue
-       .fframe 0
        .save   ar.pfs,r2
-#if defined(_HPUX_SOURCE) && defined(_ILP32)
+#if defined(_HPUX_SOURCE) && !defined(_LP64)
 { .mii;        alloc   r2=ar.pfs,2,1,0,0
        addp4   r33=0,r33
        addp4   r32=0,r32               };;
@@ -628,9 +575,13 @@ bn_sqr_comba8:
 // I've estimated this routine to run in ~120 ticks, but in reality
 // (i.e. according to ar.itc) it takes ~160 ticks. Are those extra
 // cycles consumed for instructions fetch? Or did I misinterpret some
-// clause in Itanium µ-architecture manual? Comments are welcomed and
+// clause in Itanium Âµ-architecture manual? Comments are welcomed and
 // highly appreciated.
 //
+// On Itanium 2 it takes ~190 ticks. This is because of stalls on
+// result from getf.sig. I do nothing about it at this point for
+// reasons depicted below.
+//
 // However! It should be noted that even 160 ticks is darn good result
 // as it's over 10 (yes, ten, spelled as t-e-n) times faster than the
 // C version (compiled with gcc with inline assembler). I really
@@ -671,9 +622,8 @@ bn_sqr_comba8:
 .align 64
 bn_mul_comba8:
        .prologue
-       .fframe 0
        .save   ar.pfs,r2
-#if defined(_HPUX_SOURCE) && defined(_ILP32)
+#if defined(_HPUX_SOURCE) && !defined(_LP64)
 { .mii;        alloc   r2=ar.pfs,3,0,0,0
        addp4   r33=0,r33
        addp4   r34=0,r34               };;
@@ -1229,9 +1179,8 @@ bn_mul_comba8:
 .align 64
 bn_sqr_comba4:
        .prologue
-       .fframe 0
        .save   ar.pfs,r2
-#if defined(_HPUX_SOURCE) && defined(_ILP32)
+#if defined(_HPUX_SOURCE) && !defined(_LP64)
 { .mii;        alloc   r2=ar.pfs,2,1,0,0
        addp4   r32=0,r32
        addp4   r33=0,r33               };;
@@ -1262,9 +1211,8 @@ bn_sqr_comba4:
 .align 64
 bn_mul_comba4:
        .prologue
-       .fframe 0
        .save   ar.pfs,r2
-#if defined(_HPUX_SOURCE) && defined(_ILP32)
+#if defined(_HPUX_SOURCE) && !defined(_LP64)
 { .mii;        alloc   r2=ar.pfs,3,0,0,0
        addp4   r33=0,r33
        addp4   r34=0,r34               };;
@@ -1448,8 +1396,8 @@ bn_mul_comba4:
 #define        I       r21
 
 #if 0
-// Some preprocessors (most notably HP-UX) apper to be allergic to
-// macros enclosed to parenthesis as these three will be.
+// Some preprocessors (most notably HP-UX) appear to be allergic to
+// macros enclosed to parenthesis [as these three were].
 #define        cont    p16
 #define        break   p0      // p20
 #define        equ     p24
@@ -1465,11 +1413,11 @@ equ=p24
 .align 64
 bn_div_words:
        .prologue
-       .fframe 0
        .save   ar.pfs,r2
-       .save   b0,r3
 { .mii;        alloc           r2=ar.pfs,3,5,0,8
+       .save   b0,r3
        mov             r3=b0
+       .save   pr,r10
        mov             r10=pr          };;
 { .mmb;        cmp.eq          p6,p0=r34,r0
        mov             r8=-1
@@ -1581,9 +1529,17 @@ bn_div_words:
 // output:     f8 = (int)(a/b)
 // clobbered:  f8,f9,f10,f11,pred
 pred=p15
-// This procedure is essentially Intel code and therefore is
-// copyrighted to Intel Corporation (I suppose...). It's sligtly
-// modified for specific needs.
+// This snippet is based on text found in the "Divide, Square
+// Root and Remainder" section at
+// http://www.intel.com/software/products/opensource/libraries/num.htm.
+// Yes, I admit that the referred code was used as template,
+// but after I realized that there hardly is any other instruction
+// sequence which would perform this operation. I mean I figure that
+// any independent attempt to implement high-performance division
+// will result in code virtually identical to the Intel code. It
+// should be noted though that below division kernel is 1 cycle
+// faster than Intel one (note commented splits:-), not to mention
+// original prologue (rather lack of one) and epilogue.
 .align 32
 .skip  16
 .L_udiv64_32_b6: