//===----------------------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
//
//===----------------------------------------------------------------------===//
/* ==================================================================== *

fast2_QLDOUBLE fast2_ldadd(fast2_QLDOUBLE a,fast2_QLDOUBLE b) {
      fast2_QLDOUBLE 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_ldadd_asm
        .type fast2_ldadd_asm, @function
fast2_ldadd_asm:
#define manta      R1:0
#define lmanta     R1:0
#define mantb      R3:2
#define lmantb     R3:2
#define expa       R4
#define expb       R5
#define expd       R6
#define exp        R8
#define c63        R9
#define lmant      R1:0
#define k          R4
#define ce         P0
#define zero       R3:2
        .falign
      {
        expa = memw(r29+#8)
        expb = memw(r29+#24)
        r7 = r0
      }
      {
        expd = sub(expa, expb):sat
        ce = CMP.GT(expa, expb);
        if ( ce.new) exp = add(expa, #1)
        if (!ce.new) exp = add(expb, #1)
      } {
        expd = abs(expd):sat
        if ( ce) expa = #1
        if (!ce) expb = #1
        c63 = #62
      } {
        expd = MIN(expd, c63)
        manta = memd(r29+#0)
        mantb = memd(r29+#16)
      } {
        if (!ce) expa = add(expd, #1)
        if ( ce) expb = add(expd, #1)
      } {
        lmanta = ASR(lmanta, expa)
        lmantb = ASR(lmantb, expb)
      } {
        lmant = add(lmanta, lmantb)
        zero = #0
      } {
        k  = clb(lmant)
        c63.L =#0x0001
      } {
        exp -= add(k, #-1)  //exp =  exp - (k-1)
        k = add(k, #-1)
        p0 = cmp.gt(k, #58)
        c63.H =#0x8000
      } {
        if(!p0)memw(r7+#8) = exp
        lmant = ASL(lmant, k)
        if(p0) jump .Ldenorma
      } {
        memd(r7+#0) = lmant
        jumpr  r31
      }
.Ldenorma:
        memd(r7+#0) = zero
      {
        memw(r7+#8) = c63
        jumpr  r31
      }
/* =================================================================== *
 fast2_QLDOUBLE fast2_ldsub(fast2_QLDOUBLE a,fast2_QLDOUBLE b) {
      fast2_QLDOUBLE 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_ldsub_asm
        .type fast2_ldsub_asm, @function
fast2_ldsub_asm:
#define manta      R1:0
#define lmanta     R1:0
#define mantb      R3:2
#define lmantb     R3:2
#define expa       R4
#define expb       R5
#define expd       R6
#define exp        R8
#define c63        R9
#define lmant      R1:0
#define k          R4
#define ce         P0
#define zero       R3:2
        .falign
      {
        expa = memw(r29+#8)
        expb = memw(r29+#24)
        r7 = r0
      }
      {
        expd = sub(expa, expb):sat
        ce = CMP.GT(expa, expb);
        if ( ce.new) exp = add(expa, #1)
        if (!ce.new) exp = add(expb, #1)
      } {
        expd = abs(expd):sat
        if ( ce) expa = #1
        if (!ce) expb = #1
        c63 = #62
      } {
        expd = min(expd, c63)
        manta = memd(r29+#0)
        mantb = memd(r29+#16)
      } {
        if (!ce) expa = add(expd, #1)
        if ( ce) expb = add(expd, #1)
      } {
        lmanta = ASR(lmanta, expa)
        lmantb = ASR(lmantb, expb)
      } {
        lmant = sub(lmanta, lmantb)
        zero = #0
      } {
        k  = clb(lmant)
        c63.L =#0x0001
      } {
        exp -= add(k, #-1)  //exp =  exp - (k+1)
        k = add(k, #-1)
        p0 = cmp.gt(k, #58)
        c63.H =#0x8000
      } {
        if(!p0)memw(r7+#8) = exp
        lmant = asl(lmant, k)
        if(p0) jump .Ldenorma_s
      } {
        memd(r7+#0) = lmant
        jumpr  r31
      }
.Ldenorma_s:
        memd(r7+#0) = zero
      {
        memw(r7+#8) = c63
        jumpr  r31
      }

/* ==================================================================== *
 fast2_QLDOUBLE fast2_ldmpy(fast2_QLDOUBLE a,fast2_QLDOUBLE b) {
        fast2_QLDOUBLE 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_ldmpy_asm
        .type fast2_ldmpy_asm, @function
fast2_ldmpy_asm:

#define mantxl_    R9
#define mantxl     R14
#define mantxh     R15
#define mantx      R15:14
#define mantbl     R2
#define mantbl_    R8
#define mantbh     R3
#define mantb      R3:2
#define expa       R4
#define expb       R5
#define c8001      R8
#define mantd      R7:6
#define lmantc     R11:10
#define kp         R9
#define min        R13:12
#define minh       R13
#define max        R13:12
#define maxh       R13
#define ret        R0

        .falign
      {
        mantx = memd(r29+#0)
        mantb = memd(r29+#16)
        min = #0
      }
      {
        mantbl_= extractu(mantbl, #31, #1)
        mantxl_= extractu(mantxl, #31, #1)
        minh.H = #0x8000
      }
      {
        lmantc = mpy(mantxh, mantbh)
        mantd = mpy(mantxh, mantbl_)
        expa = memw(r29+#8)
        expb = memw(r29+#24)
      }
      {
        lmantc = add(lmantc, lmantc)
        mantd += mpy(mantbh, mantxl_)
      }
      {
        mantd = asr(mantd, #30)
        c8001.L =  #0x0001
        p1 = cmp.eq(mantx, mantb)
      }
      {
        mantd = add(mantd, lmantc)
        expa= add(expa, expb)
        p2 = cmp.eq(mantb, min)
      }
      {
        kp  = clb(mantd)
        c8001.H =  #0x8000
        p1 = and(p1, p2)
      }
      {
        expa-= add(kp, #-1)
        kp = add(kp, #-1)
        if(p1) jump .Lsat
      }
      {
        mantd = asl(mantd, kp)
        memw(ret+#8) = expa
	p0 = cmp.gt(kp, #58)
        if(p0.new) jump:NT .Ldenorm   //rarely happens
      }
      {
        memd(ret+#0) = mantd
        jumpr  r31
      }
.Lsat:
      {
        max = #0
        expa+= add(kp, #1)
      }
      {
        maxh.H = #0x4000
        memw(ret+#8) = expa
      }
      {
        memd(ret+#0) = max
        jumpr  r31
      }
.Ldenorm:
      {
        memw(ret+#8) = c8001
        mantx = #0
      }
      {
        memd(ret+#0) = mantx
        jumpr  r31
      }
