1 //===----------------------Hexagon builtin routine ------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // Double Precision square root
21 #define SFHALF_SONE r5:4
29 #define FRACRAD r11:10
46 #define SF_MANTBITS 23
49 #define DF_MANTBITS 52
53 #define DFCLASS_ZERO 0x01
54 #define DFCLASS_NORMAL 0x02
55 #define DFCLASS_DENORMAL 0x02
56 #define DFCLASS_INFINITE 0x08
57 #define DFCLASS_NAN 0x10
59 #define Q6_ALIAS(TAG) .global __qdsp_##TAG ; .set __qdsp_##TAG, __hexagon_##TAG; .type __qdsp_##TAG,@function
60 #define FAST_ALIAS(TAG) .global __hexagon_fast_##TAG ; .set __hexagon_fast_##TAG, __hexagon_##TAG; .type __hexagon_fast_##TAG,@function
61 #define FAST2_ALIAS(TAG) .global __hexagon_fast2_##TAG ; .set __hexagon_fast2_##TAG, __hexagon_##TAG; .type __hexagon_fast2_##TAG,@function
62 #define END(TAG) .size TAG,.-TAG
65 .global __hexagon_sqrtdf2
66 .type __hexagon_sqrtdf2,@function
67 .global __hexagon_sqrt
68 .type __hexagon_sqrt,@function
80 PROD = extractu(A,#SF_MANTBITS+1,#DF_MANTBITS-SF_MANTBITS)
81 EXP = extractu(AH,#DF_EXPBITS,#DF_MANTBITS-32)
82 SFHALF_SONE = combine(##0x3f000004,#1)
85 NORMAL = dfclass(A,#DFCLASS_NORMAL) // Is it normal
86 NORMAL = cmp.gt(AH,#-1) // and positive?
87 if (!NORMAL.new) jump:nt .Lsqrt_abnormal
88 SFRAD = or(SFHALF,PRODLO)
94 SF_E,P_TMP = sfinvsqrta(SFRAD)
95 SFHALF = and(SFHALF,#-16)
104 // SF_E : reciprocal square root
106 // sf_S : square root
110 SF_S += sfmpy(SF_E,SFRAD):lib // s0: root
111 SF_H += sfmpy(SF_E,SFHALF):lib // h0: 0.5*y0. Could also decrement exponent...
115 SHIFTAMT = and(EXP,#1)
118 SF_D -= sfmpy(SF_S,SF_H):lib // d0: 0.5-H*S = 0.5-0.5*~1
119 FRACRADH = insert(S_ONE,#DF_EXPBITS+1,#DF_MANTBITS-32) // replace upper bits with hidden
120 P_EXP1 = cmp.gtu(SHIFTAMT,#0)
123 SF_S += sfmpy(SF_S,SF_D):lib // s1: refine sqrt
124 SF_H += sfmpy(SF_H,SF_D):lib // h1: refine half-recip
126 SHIFTAMT = mux(P_EXP1,#8,#9)
129 SF_D -= sfmpy(SF_S,SF_H):lib // d1: error term
130 FRACRAD = asl(FRACRAD,SHIFTAMT) // Move fracrad bits to right place
131 SHIFTAMT = mux(P_EXP1,#3,#2)
134 SF_H += sfmpy(SF_H,SF_D):lib // d2: rsqrt
135 // cool trick: half of 1/sqrt(x) has same mantissa as 1/sqrt(x).
136 PROD = asl(FRACRAD,SHIFTAMT) // fracrad<<(2+exp1)
139 SF_H = and(SF_H,##0x007fffff)
142 SF_H = add(SF_H,##0x00800000 - 3)
143 SHIFTAMT = mux(P_EXP1,#7,#8)
146 RECIPEST = asl(SF_H,SHIFTAMT)
147 SHIFTAMT = mux(P_EXP1,#15-(1+1),#15-(1+0))
150 ROOT = mpyu(RECIPEST,PRODHI) // root = mpyu_full(recipest,hi(fracrad<<(2+exp1)))
158 #undef SFHALF_SONE // r5:4
172 // Maybe we can save a cycle by starting with ERROR=asl(fracrad), then as we multiply
173 // We can shift and subtract instead of shift and add?
175 ERROR = asl(FRACRAD,#15)
176 PROD = mpyu(ROOTHI,ROOTHI)
177 P_CARRY0 = cmp.eq(r0,r0)
180 ERROR -= asl(PROD,#15)
181 PROD = mpyu(ROOTHI,ROOTLO)
182 P_CARRY1 = cmp.eq(r0,r0)
185 ERROR -= lsr(PROD,#16)
186 P_CARRY2 = cmp.eq(r0,r0)
189 ERROR = mpyu(ERRORHI,RECIPEST)
192 ROOT += lsr(ERROR,SHIFTAMT)
193 SHIFTAMT = add(SHIFTAMT,#16)
194 ERROR = asl(FRACRAD,#31) // for next iter
198 PROD = mpyu(ROOTHI,ROOTHI)
199 ERROR -= mpyu(ROOTHI,ROOTLO) // amount is 31, no shift needed
202 ERROR -= asl(PROD,#31)
203 PROD = mpyu(ROOTLO,ROOTLO)
206 ERROR -= lsr(PROD,#33)
209 ERROR = mpyu(ERRORHI,RECIPEST)
212 ROOT += lsr(ERROR,SHIFTAMT)
213 SHIFTAMT = add(SHIFTAMT,#16)
214 ERROR = asl(FRACRAD,#47) // for next iter
218 PROD = mpyu(ROOTHI,ROOTHI)
221 ERROR -= asl(PROD,#47)
222 PROD = mpyu(ROOTHI,ROOTLO)
225 ERROR -= asl(PROD,#16) // bidir shr 31-47
226 PROD = mpyu(ROOTLO,ROOTLO)
229 ERROR -= lsr(PROD,#17) // 64-47
232 ERROR = mpyu(ERRORHI,RECIPEST)
235 ROOT += lsr(ERROR,SHIFTAMT)
241 #define REM_HI r15:14
242 #define REM_HI_HI r15
246 #define TWOROOT_LO r9:8
249 HL = mpyu(ROOTHI,ROOTLO)
250 LL = mpyu(ROOTLO,ROOTLO)
257 P_CARRY0 = cmp.eq(r0,r0)
260 HH = mpyu(ROOTHI,ROOTHI)
261 REM_LO = sub(REM_LO,LL,P_CARRY0):carry
266 TWOROOT_LO += asl(ROOT,#1)
270 #define REM_HI_TMP r3:2
271 #define REM_HI_TMP_HI r3
272 #define REM_LO_TMP r5:4
274 REM_HI = sub(FRACRAD,HH,P_CARRY0):carry
275 REM_LO_TMP = sub(REM_LO,TWOROOT_LO,P_CARRY1):carry
284 REM_HI_TMP = sub(REM_HI,ZERO,P_CARRY1):carry
286 EXP = add(EXP,#-DF_BIAS) // subtract bias --> signed exp
289 // If carry set, no borrow: result was still positive
290 if (P_CARRY1) ROOT = ONE
291 if (P_CARRY1) REM_LO = REM_LO_TMP
292 if (P_CARRY1) REM_HI = REM_HI_TMP
295 REM_LO_TMP = sub(REM_LO,TWOROOT_LO,P_CARRY2):carry
297 EXP = asr(EXP,#1) // divide signed exp by 2
300 REM_HI_TMP = sub(REM_HI,ZERO,P_CARRY2):carry
304 if (P_CARRY2) ROOT = ONE
305 if (P_CARRY2) REM_LO = REM_LO_TMP
306 // since tworoot <= 2^32, remhi must be zero
314 P_TMP = cmp.eq(REM_LO,ZERO) // is the low part zero
315 if (!P_TMP.new) ROOTLO = or(ROOTLO,S_ONE) // if so, it's exact... hopefully
323 RET = convert_ud2df(ROOT) // set up mantissa, maybe set inexact flag
324 EXP = add(EXP,ADJ) // add back bias
327 RETHI += asl(EXP,#DF_MANTBITS-32) // add exponent adjust
353 P_TMP = dfclass(A,#DFCLASS_ZERO) // zero?
354 if (P_TMP.new) jumpr:t r31
357 P_TMP = dfclass(A,#DFCLASS_NAN)
358 if (P_TMP.new) jump:nt .Lsqrt_nan
361 P_TMP = cmp.gt(AH,#-1)
362 if (!P_TMP.new) jump:nt .Lsqrt_invalid_neg
363 if (!P_TMP.new) EXP = ##0x7F800001 // sNaN
366 P_TMP = dfclass(A,#DFCLASS_INFINITE)
367 if (P_TMP.new) jumpr:nt r31
369 // If we got here, we're denormal
370 // prepare to restart
372 A = extractu(A,#DF_MANTBITS,#0) // Extract mantissa
375 EXP = add(clb(A),#-DF_EXPBITS) // how much to normalize?
378 A = asl(A,EXP) // Shift mantissa
379 EXP = sub(#1,EXP) // Form exponent
382 AH = insert(EXP,#1,#DF_MANTBITS-32) // insert lsb of exponent
385 TMP = extractu(A,#SF_MANTBITS+1,#DF_MANTBITS-SF_MANTBITS) // get sf value (mant+exp1)
386 SFHALF = ##0x3f000004 // form half constant
389 SFRAD = or(SFHALF,TMPLO) // form sf value
390 SFHALF = and(SFHALF,#-16)
391 jump .Ldenormal_restart // restart
395 EXP = convert_df2sf(A) // if sNaN, get invalid
401 A = convert_sf2df(EXP) // Invalid,NaNval
405 END(__hexagon_sqrtdf2)