Support for "multiply high" instruction, see BN_UMULT_HIGH comment in
[openssl.git] / crypto / bn / bn_asm.c
index c9eb0e9..a62fdcf 100644 (file)
 #include "cryptlib.h"
 #include "bn_lcl.h"
 
-#ifdef BN_LLONG 
+#if defined(BN_LLONG) || defined(BN_UMULT_HIGH)
 
-BN_ULONG bn_mul_add_words(rp,ap,num,w)
-BN_ULONG *rp,*ap;
-int num;
-BN_ULONG w;
+BN_ULONG bn_mul_add_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
        {
        BN_ULONG c1=0;
 
        bn_check_num(num);
        if (num <= 0) return(c1);
 
-       for (;;)
+       while (num&~3)
                {
                mul_add(rp[0],ap[0],w,c1);
-               if (--num == 0) break;
                mul_add(rp[1],ap[1],w,c1);
-               if (--num == 0) break;
                mul_add(rp[2],ap[2],w,c1);
-               if (--num == 0) break;
                mul_add(rp[3],ap[3],w,c1);
-               if (--num == 0) break;
-               ap+=4;
-               rp+=4;
+               ap+=4; rp+=4; num-=4;
+               }
+       if (num)
+               {
+               mul_add(rp[0],ap[0],w,c1); if (--num==0) return c1;
+               mul_add(rp[1],ap[1],w,c1); if (--num==0) return c1;
+               mul_add(rp[2],ap[2],w,c1); return c1;
                }
        
        return(c1);
        } 
 
-BN_ULONG bn_mul_words(rp,ap,num,w)
-BN_ULONG *rp,*ap;
-int num;
-BN_ULONG w;
+BN_ULONG bn_mul_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
        {
        BN_ULONG c1=0;
 
        bn_check_num(num);
        if (num <= 0) return(c1);
 
-       for (;;)
+       while (num&~3)
                {
                mul(rp[0],ap[0],w,c1);
-               if (--num == 0) break;
                mul(rp[1],ap[1],w,c1);
-               if (--num == 0) break;
                mul(rp[2],ap[2],w,c1);
-               if (--num == 0) break;
                mul(rp[3],ap[3],w,c1);
-               if (--num == 0) break;
-               ap+=4;
-               rp+=4;
+               ap+=4; rp+=4; num-=4;
+               }
+       if (num)
+               {
+               mul(rp[0],ap[0],w,c1); if (--num == 0) return c1;
+               mul(rp[1],ap[1],w,c1); if (--num == 0) return c1;
+               mul(rp[2],ap[2],w,c1);
                }
        return(c1);
        } 
 
-void bn_sqr_words(r,a,n)
-BN_ULONG *r,*a;
-int n;
+void bn_sqr_words(BN_ULONG *r, BN_ULONG *a, int n)
         {
        bn_check_num(n);
        if (n <= 0) return;
-       for (;;)
+       while (n&~3)
                {
-               BN_ULLONG t;
-
-               t=(BN_ULLONG)(a[0])*(a[0]);
-               r[0]=Lw(t); r[1]=Hw(t);
-               if (--n == 0) break;
-
-               t=(BN_ULLONG)(a[1])*(a[1]);
-               r[2]=Lw(t); r[3]=Hw(t);
-               if (--n == 0) break;
-
-               t=(BN_ULLONG)(a[2])*(a[2]);
-               r[4]=Lw(t); r[5]=Hw(t);
-               if (--n == 0) break;
-
-               t=(BN_ULLONG)(a[3])*(a[3]);
-               r[6]=Lw(t); r[7]=Hw(t);
-               if (--n == 0) break;
-
-               a+=4;
-               r+=8;
+               sqr(r[0],r[1],a[0]);
+               sqr(r[2],r[3],a[1]);
+               sqr(r[4],r[5],a[2]);
+               sqr(r[6],r[7],a[3]);
+               a+=4; r+=8; n-=4;
+               }
+       if (n)
+               {
+               sqr(r[0],r[1],a[0]); if (--n == 0) return;
+               sqr(r[2],r[3],a[1]); if (--n == 0) return;
+               sqr(r[4],r[5],a[2]);
                }
        }
 
 #else
 
-BN_ULONG bn_mul_add_words(rp,ap,num,w)
-BN_ULONG *rp,*ap;
-int num;
-BN_ULONG w;
+BN_ULONG bn_mul_add_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
        {
        BN_ULONG c=0;
        BN_ULONG bl,bh;
@@ -178,10 +160,7 @@ BN_ULONG w;
        return(c);
        } 
 
-BN_ULONG bn_mul_words(rp,ap,num,w)
-BN_ULONG *rp,*ap;
-int num;
-BN_ULONG w;
+BN_ULONG bn_mul_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
        {
        BN_ULONG carry=0;
        BN_ULONG bl,bh;
@@ -208,9 +187,7 @@ BN_ULONG w;
        return(carry);
        } 
 
-void bn_sqr_words(r,a,n)
-BN_ULONG *r,*a;
-int n;
+void bn_sqr_words(BN_ULONG *r, BN_ULONG *a, int n)
         {
        bn_check_num(n);
        if (n <= 0) return;
@@ -237,8 +214,7 @@ int n;
 
 #if defined(BN_LLONG) && defined(BN_DIV2W)
 
-BN_ULONG bn_div_words(h,l,d)
-BN_ULONG h,l,d;
+BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d)
        {
        return((BN_ULONG)(((((BN_ULLONG)h)<<BN_BITS2)|l)/(BN_ULLONG)d));
        }
@@ -247,8 +223,7 @@ BN_ULONG h,l,d;
 
 /* Divide h-l by d and return the result. */
 /* I need to test this some more :-( */
-BN_ULONG bn_div_words(h,l,d)
-BN_ULONG h,l,d;
+BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d)
        {
        BN_ULONG dh,dl,q,ret=0,th,tl,t;
        int i,count=2;
@@ -281,18 +256,20 @@ BN_ULONG h,l,d;
                else
                        q=h/dh;
 
+               th=q*dh;
+               tl=dl*q;
                for (;;)
                        {
-                       t=(h-q*dh);
+                       t=h-th;
                        if ((t&BN_MASK2h) ||
-                               ((dl*q) <= (
-                                       (t<<BN_BITS4)+
+                               ((tl) <= (
+                                       (t<<BN_BITS4)|
                                        ((l&BN_MASK2h)>>BN_BITS4))))
                                break;
                        q--;
+                       th-=dh;
+                       tl-=dl;
                        }
-               th=q*dh;
-               tl=q*dl;
                t=(tl>>BN_BITS4);
                tl=(tl<<BN_BITS4)&BN_MASK2h;
                th+=t;
@@ -318,9 +295,7 @@ BN_ULONG h,l,d;
 #endif
 
 #ifdef BN_LLONG
-BN_ULONG bn_add_words(r,a,b,n)
-BN_ULONG *r,*a,*b;
-int n;
+BN_ULONG bn_add_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
         {
        BN_ULLONG ll=0;
 
@@ -356,9 +331,7 @@ int n;
        return((BN_ULONG)ll);
        }
 #else
-BN_ULONG bn_add_words(r,a,b,n)
-BN_ULONG *r,*a,*b;
-int n;
+BN_ULONG bn_add_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
         {
        BN_ULONG c,l,t;
 
@@ -408,9 +381,7 @@ int n;
        }
 #endif
 
-BN_ULONG bn_sub_words(r,a,b,n)
-BN_ULONG *r,*a,*b;
-int n;
+BN_ULONG bn_sub_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
         {
        BN_ULONG t1,t2;
        int c=0;
@@ -447,7 +418,7 @@ int n;
        return(c);
        }
 
-#ifdef BN_COMBA
+#ifdef BN_MUL_COMBA
 
 #undef bn_mul_comba8
 #undef bn_mul_comba4
@@ -481,6 +452,38 @@ int n;
 
 #define sqr_add_c2(a,i,j,c0,c1,c2) \
        mul_add_c2((a)[i],(a)[j],c0,c1,c2)
+
+#elif defined(BN_UMULT_HIGH)
+
+#define mul_add_c(a,b,c0,c1,c2)        {       \
+       BN_ULONG ta=(a),tb=(b);         \
+       t1 = ta * tb;                   \
+       t2 = BN_UMULT_HIGH(ta,tb);      \
+       c0 += t1; t2 += (c0<t1)?1:0;    \
+       c1 += t2; c2 += (c1<t2)?1:0;    \
+       }
+
+#define mul_add_c2(a,b,c0,c1,c2) {     \
+       BN_ULONG ta=(a),tb=(b),t0;      \
+       t1 = BN_UMULT_HIGH(ta,tb);      \
+       t0 = ta * tb;                   \
+       t2 = t1+t1; c2 += (t2<t1)?1:0;  \
+       t1 = t0+t0; t2 += (t1<t0)?1:0;  \
+       c0 += t1; t2 += (c0<t1)?1:0;    \
+       c1 += t2; c2 += (c1<t2)?1:0;    \
+       }
+
+#define sqr_add_c(a,i,c0,c1,c2)        {       \
+       BN_ULONG ta=(a)[i];             \
+       t1 = ta * ta;                   \
+       t2 = BN_UMULT_HIGH(ta,ta);      \
+       c0 += t1; t2 += (c0<t1)?1:0;    \
+       c1 += t2; c2 += (c1<t2)?1:0;    \
+       }
+
+#define sqr_add_c2(a,i,j,c0,c1,c2)     \
+       mul_add_c2((a)[i],(a)[j],c0,c1,c2)
+
 #else
 #define mul_add_c(a,b,c0,c1,c2) \
        t1=LBITS(a); t2=HBITS(a); \
@@ -510,8 +513,7 @@ int n;
        mul_add_c2((a)[i],(a)[j],c0,c1,c2)
 #endif
 
-void bn_mul_comba8(r,a,b)
-BN_ULONG *r,*a,*b;
+void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
        {
 #ifdef BN_LLONG
        BN_ULLONG t;
@@ -620,8 +622,7 @@ BN_ULONG *r,*a,*b;
        r[15]=c1;
        }
 
-void bn_mul_comba4(r,a,b)
-BN_ULONG *r,*a,*b;
+void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
        {
 #ifdef BN_LLONG
        BN_ULLONG t;
@@ -666,8 +667,7 @@ BN_ULONG *r,*a,*b;
        r[7]=c2;
        }
 
-void bn_sqr_comba8(r,a)
-BN_ULONG *r,*a;
+void bn_sqr_comba8(BN_ULONG *r, BN_ULONG *a)
        {
 #ifdef BN_LLONG
        BN_ULLONG t,tt;
@@ -748,8 +748,7 @@ BN_ULONG *r,*a;
        r[15]=c1;
        }
 
-void bn_sqr_comba4(r,a)
-BN_ULONG *r,*a;
+void bn_sqr_comba4(BN_ULONG *r, BN_ULONG *a)
        {
 #ifdef BN_LLONG
        BN_ULLONG t,tt;
@@ -790,22 +789,21 @@ BN_ULONG *r,*a;
 #else
 
 /* hmm... is it faster just to do a multiply? */
-void bn_sqr_comba4(r,a)
-BN_ULONG *r,*a;
+#undef bn_sqr_comba4
+void bn_sqr_comba4(BN_ULONG *r, BN_ULONG *a)
        {
        BN_ULONG t[8];
        bn_sqr_normal(r,a,4,t);
        }
 
-void bn_sqr_comba8(r,a)
-BN_ULONG *r,*a;
+#undef bn_sqr_comba8
+void bn_sqr_comba8(BN_ULONG *r, BN_ULONG *a)
        {
        BN_ULONG t[16];
        bn_sqr_normal(r,a,8,t);
        }
 
-void bn_mul_comba4(r,a,b)
-BN_ULONG *r,*a,*b;
+void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
        {
        r[4]=bn_mul_words(    &(r[0]),a,4,b[0]);
        r[5]=bn_mul_add_words(&(r[1]),a,4,b[1]);
@@ -813,8 +811,7 @@ BN_ULONG *r,*a,*b;
        r[7]=bn_mul_add_words(&(r[3]),a,4,b[3]);
        }
 
-void bn_mul_comba8(r,a,b)
-BN_ULONG *r,*a,*b;
+void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
        {
        r[ 8]=bn_mul_words(    &(r[0]),a,8,b[0]);
        r[ 9]=bn_mul_add_words(&(r[1]),a,8,b[1]);