//===----------------------Hexagon builtin routine ------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/* ==================================================================== */
/*   FUNCTIONS Optimized double floating point operators                */
/* ==================================================================== */
/*      c = dadd_asm(a, b)                                              */
/* ==================================================================== *
fast2_QDOUBLE fast2_dadd(fast2_QDOUBLE a,fast2_QDOUBLE b) {
      fast2_QDOUBLE c;
      lint manta = a & MANTMASK;
      int  expa  = Q6_R_sxth_R(a) ;
      lint mantb = b & MANTMASK;
      int  expb  = Q6_R_sxth_R(b) ;
      int  exp, expdiff, j, k, hi, lo, cn;
      lint mant;

        expdiff = (int) Q6_P_vabsdiffh_PP(a, b);
        expdiff = Q6_R_sxth_R(expdiff) ;
        if (expdiff > 63) { expdiff = 62;}
        if (expa > expb) {
          exp = expa + 1;
          expa = 1;
          expb = expdiff + 1;
        } else {
          exp = expb + 1;
          expb = 1;
          expa = expdiff + 1;
        }
        mant = (manta>>expa) + (mantb>>expb);

        hi = (int) (mant>>32);
        lo = (int) (mant);

        k =  Q6_R_normamt_R(hi);
        if(hi == 0 || hi == -1) k = 31+Q6_R_normamt_R(lo);

        mant = (mant << k);
        cn  = (mant == 0x8000000000000000LL);
        exp = exp - k + cn;

        if (mant ==  0 || mant == -1)  exp = 0x8001;
        c = (mant & MANTMASK) | (((lint) exp) & EXP_MASK);
      return(c);
 }
 * ==================================================================== */
        .text
        .global fast2_dadd_asm
        .type fast2_dadd_asm, @function
fast2_dadd_asm:
#define manta      R0
#define mantexpa   R1:0
#define lmanta     R1:0
#define mantb      R2
#define mantexpb   R3:2
#define lmantb     R3:2
#define expa       R4
#define expb       R5
#define mantexpd   R7:6
#define expd       R6
#define exp        R8
#define c63        R9
#define lmant      R1:0
#define manth      R1
#define mantl      R0
#define minmin     R11:10  // exactly 0x000000000000008001LL
#define minminl    R10
#define k          R4
#define ce         P0
        .falign
      {
        mantexpd = VABSDIFFH(mantexpa, mantexpb) //represented as 0x08001LL
        c63 = #62
        expa = SXTH(manta)
        expb = SXTH(mantb)
      } {
        expd = SXTH(expd)
        ce = CMP.GT(expa, expb);
        if ( ce.new) exp = add(expa, #1)
        if (!ce.new) exp = add(expb, #1)
      } {
        if ( ce) expa = #1
        if (!ce) expb = #1
        manta.L = #0
        expd = MIN(expd, c63)
      } {
        if (!ce) expa = add(expd, #1)
        if ( ce) expb = add(expd, #1)
        mantb.L = #0
        minmin = #0
      } {
        lmanta = ASR(lmanta, expa)
        lmantb = ASR(lmantb, expb)
      } {
        lmant = add(lmanta, lmantb)
        minminl.L = #0x8001
      } {
        k  = clb(lmant)
        c63 = #58
      } {
        k = add(k, #-1)
        p0 = cmp.gt(k, c63)
      } {
        mantexpa = ASL(lmant, k)
        exp = SUB(exp, k)
        if(p0) jump .Ldenorma
      } {
        manta = insert(exp, #16, #0)
        jumpr  r31
      }
.Ldenorma:
      {
        mantexpa = minmin
        jumpr  r31
      }
/* =================================================================== *
 fast2_QDOUBLE fast2_dsub(fast2_QDOUBLE a,fast2_QDOUBLE b) {
      fast2_QDOUBLE c;
      lint manta = a & MANTMASK;
      int  expa  = Q6_R_sxth_R(a) ;
      lint mantb = b & MANTMASK;
      int  expb  = Q6_R_sxth_R(b) ;
      int  exp, expdiff, j, k;
      lint mant;

        expdiff = (int) Q6_P_vabsdiffh_PP(a, b);
        expdiff = Q6_R_sxth_R(expdiff) ;
        if (expdiff > 63) { expdiff = 62;}
        if (expa > expb) {
          exp = expa + 1;
          expa = 1;
          expb = expdiff + 1;
        } else {
          exp = expb + 1;
          expb = 1;
          expa = expdiff + 1;
        }
        mant = (manta>>expa) - (mantb>>expb);
        k =  Q6_R_clb_P(mant)-1;
        mant = (mant << k);
        exp = exp - k;
        if (mant ==  0 || mant == -1)  exp = 0x8001;
        c = (mant & MANTMASK) | (((lint) exp) & EXP_MASK);
      return(c);
 }
 * ==================================================================== */
        .text
        .global fast2_dsub_asm
        .type fast2_dsub_asm, @function
fast2_dsub_asm:

#define manta      R0
#define mantexpa   R1:0
#define lmanta     R1:0
#define mantb      R2
#define mantexpb   R3:2
#define lmantb     R3:2
#define expa       R4
#define expb       R5
#define mantexpd   R7:6
#define expd       R6
#define exp        R8
#define c63        R9
#define lmant      R1:0
#define manth      R1
#define mantl      R0
#define minmin     R11:10  // exactly 0x000000000000008001LL
#define minminl    R10
#define k          R4
#define ce         P0
        .falign
      {
        mantexpd = VABSDIFFH(mantexpa, mantexpb) //represented as 0x08001LL
        c63 = #62
        expa = SXTH(manta)
        expb = SXTH(mantb)
      } {
        expd = SXTH(expd)
        ce = CMP.GT(expa, expb);
        if ( ce.new) exp = add(expa, #1)
        if (!ce.new) exp = add(expb, #1)
      } {
        if ( ce) expa = #1
        if (!ce) expb = #1
        manta.L = #0
        expd = MIN(expd, c63)
      } {
        if (!ce) expa = add(expd, #1)
        if ( ce) expb = add(expd, #1)
        mantb.L = #0
        minmin = #0
      } {
        lmanta = ASR(lmanta, expa)
        lmantb = ASR(lmantb, expb)
      } {
        lmant = sub(lmanta, lmantb)
        minminl.L = #0x8001
      } {
        k  = clb(lmant)
        c63 = #58
      } {
        k = add(k, #-1)
        p0 = cmp.gt(k, c63)
      } {
        mantexpa = ASL(lmant, k)
        exp = SUB(exp, k)
        if(p0) jump .Ldenorm
      } {
        manta = insert(exp, #16, #0)
        jumpr  r31
      }
.Ldenorm:
      {
        mantexpa = minmin
        jumpr  r31
      }
/* ==================================================================== *
 fast2_QDOUBLE fast2_dmpy(fast2_QDOUBLE a,fast2_QDOUBLE b) {
        fast2_QDOUBLE c;
        lint manta = a & MANTMASK;
        int  expa  = Q6_R_sxth_R(a) ;
        lint mantb = b & MANTMASK;
        int  expb  = Q6_R_sxth_R(b) ;
        int exp, k;
        lint mant;
        int          hia, hib, hi, lo;
        unsigned int loa, lob;

        hia = (int)(a >> 32);
        loa = Q6_R_extractu_RII((int)manta, 31, 1);
        hib = (int)(b >> 32);
        lob = Q6_R_extractu_RII((int)mantb, 31, 1);

        mant = Q6_P_mpy_RR(hia, lob);
        mant = Q6_P_mpyacc_RR(mant,hib, loa);
        mant = (mant >> 30) + (Q6_P_mpy_RR(hia, hib)<<1);

        hi = (int) (mant>>32);

        k =  Q6_R_normamt_R(hi);
        mant = mant << k;
        exp = expa + expb - k;
        if (mant ==  0 || mant == -1)  exp = 0x8001;
        c = (mant & MANTMASK) | (((lint) exp) & EXP_MASK);
        return(c);
 }
 * ==================================================================== */
        .text
        .global fast2_dmpy_asm
        .type fast2_dmpy_asm, @function
fast2_dmpy_asm:

#define mantal     R0
#define mantah     R1
#define mantexpa   R1:0
#define mantbl     R2
#define mantbh     R3
#define mantexpb   R3:2
#define expa       R4
#define expb       R5
#define c8001      R12
#define mantexpd   R7:6
#define mantdh     R7
#define exp        R8
#define lmantc     R11:10
#define kb         R9
#define guard      R11
#define mantal_    R12
#define mantbl_    R13
#define min        R15:14
#define minh       R15

        .falign
      {
        mantbl_= lsr(mantbl, #16)
        expb = sxth(mantbl)
        expa = sxth(mantal)
        mantal_= lsr(mantal, #16)
      }
      {
        lmantc = mpy(mantah, mantbh)
        mantexpd = mpy(mantah, mantbl_)
        mantal.L = #0x0
        min = #0
      }
      {
        lmantc = add(lmantc, lmantc)
        mantexpd+= mpy(mantbh, mantal_)
        mantbl.L = #0x0
        minh.H = #0x8000
      }
      {
        mantexpd = asr(mantexpd, #15)
        c8001.L =  #0x8001
        p1 = cmp.eq(mantexpa, mantexpb)
      }
      {
        mantexpd = add(mantexpd, lmantc)
        exp = add(expa, expb)
        p2 = cmp.eq(mantexpa, min)
      }
      {
        kb  = clb(mantexpd)
        mantexpb = abs(mantexpd)
        guard = #58
      }
      {
        p1 = and(p1, p2)
        exp = sub(exp, kb)
        kb = add(kb, #-1)
	p0 = cmp.gt(kb, guard)
      }
      {
        exp = add(exp, #1)
        mantexpa = asl(mantexpd, kb)
        if(p1) jump .Lsat   //rarely happens
      }
      {
        mantal = insert(exp,#16, #0)
        if(!p0) jumpr  r31
      }
      {
        mantal = insert(c8001,#16, #0)
        jumpr  r31
      }
.Lsat:
      {
        mantexpa = #-1
      }
      {
        mantexpa = lsr(mantexpa, #1)
      }
      {
        mantal = insert(exp,#16, #0)
        jumpr  r31
      }

/* ==================================================================== *
 int fast2_qd2f(fast2_QDOUBLE a) {
        int exp;
        long long int manta;
        int ic, rnd, mantb;

        manta = a>>32;
        exp = Q6_R_sxth_R(a) ;
        ic = 0x80000000 & manta;
        manta = Q6_R_abs_R_sat(manta);
        mantb = (manta + rnd)>>7;
        rnd = 0x40
        exp = (exp + 126);
        if((manta & 0xff) == rnd) rnd = 0x00;
        if((manta & 0x7fffffc0) == 0x7fffffc0) {
           manta = 0x0; exp++;
        } else {
           manta= mantb & 0x007fffff;
        }
        exp = (exp << 23) & 0x7fffffc0;
        ic = Q6_R_addacc_RR(ic, exp, manta);
        return (ic);
 }
 * ==================================================================== */

        .text
        .global fast2_qd2f_asm
        .type fast2_qd2f_asm, @function
fast2_qd2f_asm:
#define mantah   R1
#define mantal   R0
#define cff      R0
#define mant     R3
#define expo     R4
#define rnd      R5
#define mask     R6
#define c07f     R7
#define c80      R0
#define mantb    R2
#define ic       R0

      .falign
     {
       mant = abs(mantah):sat
       expo = sxth(mantal)
       rnd = #0x40
       mask.L = #0xffc0
     }
     {
       cff = extractu(mant, #8, #0)
       p2 = cmp.gt(expo, #126)
       p3 = cmp.ge(expo, #-126)
       mask.H = #0x7fff
     }
     {
       p1 = cmp.eq(cff,#0x40)
       if(p1.new) rnd = #0
       expo = add(expo, #126)
       if(!p3) jump .Lmin
     }
     {
       p0 = bitsset(mant, mask)
       c80.L = #0x0000
       mantb = add(mant, rnd)
       c07f = lsr(mask, #8)
     }
     {
       if(p0) expo = add(expo, #1)
       if(p0) mant = #0
       mantb = lsr(mantb, #7)
       c80.H = #0x8000
     }
     {
       ic = and(c80, mantah)
       mask &= asl(expo, #23)
       if(!p0) mant = and(mantb, c07f)
       if(p2) jump .Lmax
     }
     {
       ic += add(mask, mant)
       jumpr r31
     }
.Lmax:
     {
       ic.L = #0xffff;
     }
     {
       ic.H = #0x7f7f;
       jumpr r31
     }
.Lmin:
     {
       ic = #0x0
       jumpr r31
     }

/* ==================================================================== *
fast2_QDOUBLE fast2_f2qd(int ia) {
        lint exp;
        lint mant;
        fast2_QDOUBLE c;

        mant = ((ia << 7) | 0x40000000)&0x7fffff80 ;
        if (ia & 0x80000000) mant = -mant;
        exp =  ((ia >> 23) & 0xFFLL) - 126;
        c = (mant<<32) | Q6_R_zxth_R(exp);;
        return(c);
}
 * ==================================================================== */
        .text
        .global fast2_f2qd_asm
        .type fast2_f2qd_asm, @function
fast2_f2qd_asm:
#define ia    R0
#define mag   R3
#define mantr R1
#define expr  R0
#define zero  R2
#define maxneg R5:4
#define maxnegl R4
        .falign
  {
       mantr = asl(ia, #7)
       p0 = tstbit(ia, #31)
       maxneg = #0
       mag = add(ia,ia)
  }
  {
       mantr = setbit(mantr, #30)
       expr= extractu(ia,#8,#23)
       maxnegl.L = #0x8001
       p1 = cmp.eq(mag, #0)
  }
  {
       mantr= extractu(mantr, #31, #0)
       expr= add(expr, #-126)
       zero = #0
       if(p1) jump .Lminqd
  }
  {
       expr = zxth(expr)
       if(p0) mantr= sub(zero, mantr)
       jumpr r31
  }
.Lminqd:
  {
       R1:0 = maxneg
       jumpr r31
  }
