1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  23  */
  24 /*
  25  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  26  * Use is subject to license terms.
  27  */
  28 
  29         .file "powl.s"
  30 
  31 / Special cases:
  32 /
  33 / x ** 0 is 1
  34 / 1 ** y is 1                           (C99)
  35 / x ** NaN is NaN
  36 / NaN ** y (except 0) is NaN
  37 / x ** 1 is x
  38 / +-(|x| > 1) **  +inf is +inf
  39 / +-(|x| > 1) **  -inf is +0
  40 / +-(|x| < 1) **  +inf is +0
  41 / +-(|x| < 1) **  -inf is +inf
  42 / (-1) ** +-inf is +1                   (C99)
  43 / +0 ** +y (except 0, NaN)              is +0
  44 / -0 ** +y (except 0, NaN, odd int)     is +0
  45 / +0 ** -y (except 0, NaN)              is +inf (z flag)
  46 / -0 ** -y (except 0, NaN, odd int)     is +inf (z flag)
  47 / -0 ** y (odd int)                     is - (+0 ** x)
  48 / +inf ** +y (except 0, NaN)            is +inf
  49 / +inf ** -y (except 0, NaN)            is +0
  50 / -inf ** +-y (except 0, NaN)           is -0 ** -+y (NO z flag)
  51 / x ** -1 is 1/x
  52 / x ** 2 is x*x
  53 / -x ** y (an integer) is (-1)**(y) * (+x)**(y)
  54 / x ** y (x negative & y not integer) is NaN (i flag)
  55 
  56 #include "libm.h"
  57 LIBM_ANSI_PRAGMA_WEAK(powl,function)
  58 #include "libm_synonyms.h"
  59 #include "xpg6.h"
  60 
  61 #undef fabs
  62 
  63         .data
  64         .align  4
  65 negzero:
  66         .float  -0.0
  67 half:
  68         .float  0.5
  69 one:
  70         .float  1.0
  71 negone:
  72         .float  -1.0
  73 two:
  74         .float  2.0
  75 Snan:
  76         .long   0x7f800001
  77 pinfinity:
  78         .long   0x7f800000
  79 ninfinity:
  80         .long   0xff800000
  81 
  82 
  83         ENTRY(powl)
  84         pushl   %ebp
  85         movl    %esp,%ebp
  86         PIC_SETUP(1)
  87 
  88         fldt    8(%ebp)                 / x
  89         fxam                            / determine class of x
  90         fnstsw  %ax                     / store status in %ax
  91         movb    %ah,%dh                 / %dh <- condition code of x
  92 
  93         fldt    20(%ebp)                / y , x
  94         fxam                            / determine class of y
  95         fnstsw  %ax                     / store status in %ax
  96         movb    %ah,%dl                 / %dl <- condition code of y
  97 
  98         call    .pow_main               /// LOCAL
  99         PIC_WRAPUP
 100         leave
 101         ret
 102 
 103 .pow_main:
 104         / x ** 0 is 1
 105         movb    %dl,%cl
 106         andb    $0x45,%cl
 107         cmpb    $0x40,%cl               / C3=1 C2=0 C1=? C0=0 when +-0
 108         jne     1f
 109         fstp    %st(0)                  / x
 110         fstp    %st(0)                  / stack empty
 111         fld1                            / 1
 112         ret
 113 
 114 1:      / y is not zero
 115         PIC_G_LOAD(movzwl,__xpg6,eax)
 116         andl    $_C99SUSv3_pow_treats_Inf_as_an_even_int,%eax
 117         cmpl    $0,%eax
 118         je      1f
 119 
 120         / C99: 1 ** anything is 1
 121         fld1                            / 1, y, x
 122         fucomp  %st(2)                  / y, x
 123         fnstsw  %ax                     / store status in %ax
 124         sahf                            / 80387 flags in %ax to 80386 flags
 125         jp      1f                      / so that pow(NaN1,NaN2) returns NaN2
 126         jne     1f
 127         fstp    %st(0)                  / x
 128         ret
 129 
 130 1:
 131         / x ** NaN is NaN
 132         movb    %dl,%cl
 133         andb    $0x45,%cl
 134         cmpb    $0x01,%cl               / C3=0 C2=0 C1=? C0=1 when +-NaN
 135         jne     1f
 136         fstp    %st(1)                  / y
 137         ret
 138 
 139 1:      / y is not NaN
 140         / NaN ** y (except 0) is NaN
 141         movb    %dh,%cl
 142         andb    $0x45,%cl
 143         cmpb    $0x01,%cl               / C3=0 C2=0 C1=? C0=1 when +-NaN
 144         jne     1f
 145         fstp    %st(0)                  / x
 146         ret
 147 
 148 1:      / x is not NaN
 149         / x ** 1 is x
 150         fcoms   PIC_L(one)              / y , x
 151         fnstsw  %ax                     / store status in %ax
 152         sahf                            / 80387 flags in %ax to 80386 flags
 153         jne     1f
 154         fstp    %st(0)                  / x
 155         ret
 156 
 157 1:      / y is not 1
 158         / +-(|x| > 1) **  +inf is +inf
 159         / +-(|x| > 1) **  -inf is +0
 160         / +-(|x| < 1) **  +inf is +0
 161         / +-(|x| < 1) **  -inf is +inf
 162         / +-(|x| = 1) ** +-inf is NaN
 163         movb    %dl,%cl
 164         andb    $0x47,%cl
 165         cmpb    $0x05,%cl               / C3=0 C2=1 C1=0 C0=1 when +inf
 166         je      .yispinf
 167         cmpb    $0x07,%cl               / C3=0 C2=1 C1=1 C0=1 when -inf
 168         je      .yisninf
 169 
 170         / +0 ** +y (except 0, NaN)              is +0
 171         / -0 ** +y (except 0, NaN, odd int)     is +0
 172         / +0 ** -y (except 0, NaN)              is +inf (z flag)
 173         / -0 ** -y (except 0, NaN, odd int)     is +inf (z flag)
 174         / -0 ** y (odd int)                     is - (+0 ** x)
 175         movb    %dh,%cl
 176         andb    $0x47,%cl
 177         cmpb    $0x40,%cl               / C3=1 C2=0 C1=0 C0=0 when +0
 178         je      .xispzero
 179         cmpb    $0x42,%cl               / C3=1 C2=0 C1=1 C0=0 when -0
 180         je      .xisnzero
 181 
 182         / +inf ** +y (except 0, NaN)    is +inf
 183         / +inf ** -y (except 0, NaN)    is +0
 184         / -inf ** +-y (except 0, NaN)   is -0 ** -+y (NO z flag)
 185         movb    %dh,%cl
 186         andb    $0x47,%cl
 187         cmpb    $0x05,%cl               / C3=0 C2=1 C1=0 C0=1 when +inf
 188         je      .xispinf
 189         cmpb    $0x07,%cl               / C3=0 C2=1 C1=1 C0=1 when -inf
 190         je      .xisninf
 191 
 192         / x ** -1 is 1/x
 193         fcoms   PIC_L(negone)           / y , x
 194         fnstsw  %ax                     / store status in %ax
 195         sahf                            / 80387 flags in %ax to 80386 flags
 196         jne     1f
 197         fld     %st(1)                  / x , y , x
 198         fdivrs  PIC_L(one)              / 1/x , y , x
 199         jmp     .signok                 / check for over/underflow
 200 
 201 1:      / y is not -1
 202         / x ** 2 is x*x
 203         fcoms   PIC_L(two)              / y , x
 204         fnstsw  %ax                     / store status in %ax
 205         sahf                            / 80387 flags in %ax to 80386 flags
 206         jne     1f
 207         fld     %st(1)                  / x , y , x
 208         fld     %st(0)                  / x , x , y , x
 209         fmulp                           / x^2 , y , x
 210         jmp     .signok                 / check for over/underflow
 211 
 212 1:      / y is not 2
 213         / x ** 1/2 is sqrt(x)
 214         fcoms   PIC_L(half)             / y , x
 215         fnstsw  %ax                     / store status in %ax
 216         sahf                            / 80387 flags in %ax to 80386 flags
 217         jne     1f
 218         fld     %st(1)                  / x , y , x
 219         fsqrt                           / sqrt(x) , y , x
 220         jmp     .signok                 / check for over/underflow
 221 
 222 1:      / y is not 1/2
 223         / make copies of x & y
 224         fld     %st(1)                  / x , y , x
 225         fld     %st(1)                  / y , x , y , x
 226 
 227         / -x ** y (an integer) is (-1)**(y) * (+x)**(y)
 228         / x ** y (x negative & y not integer) is  NaN
 229         movl    $0,%ecx                 / track whether to flip sign of result
 230         fld     %st(1)                  / x , y , x , y , x
 231         ftst                            / compare %st(0) with 0
 232         fnstsw  %ax                     / store status in %ax
 233         sahf                            / 80387 flags in %ax to 80386 flags
 234         fstp    %st(0)                  / y , x , y , x
 235         ja      .merge                  / x > 0
 236         / x < 0
 237         call    .y_is_int
 238         cmpl    $0,%ecx
 239         jne     1f
 240         / x < 0 & y != int so x**y = NaN (i flag)
 241         fstp    %st(0)                  / x , y , x
 242         fstp    %st(0)                  / y , x
 243         fstp    %st(0)                  / x
 244         fstp    %st(0)                  / stack empty
 245         fldz
 246         fdiv    %st,%st(0)              / 0/0
 247         ret
 248 
 249 1:      / x < 0 & y = int
 250         fxch                            / x , y , y , x
 251         fchs                            / px = -x , y , y , x
 252         fxch                            / y , px , y , x
 253 .merge:
 254         / px > 0
 255         fxch                            / px , y , y , x
 256 
 257         / x**y   =   exp(y*ln(x))
 258         fyl2x                           / t=y*log2(px) , y , x
 259         fld     %st(0)                  / t , t , y , x
 260         frndint                         / [t] , t , y , x
 261         fxch                            / t , [t] , y , x
 262         fucom
 263         fnstsw  %ax                     / store status in %ax
 264         sahf                            / 80387 flags in %ax to 80386 flags
 265         je      1f                      / t is integral
 266         fsub    %st(1),%st              / t-[t] , [t] , y , x
 267         f2xm1                           / 2**(t-[t])-1 , [t] , y , x
 268         fadds   PIC_L(one)              / 2**(t-[t]) , [t] , y , x
 269         fscale                          / 2**t = px**y , [t] , y , x
 270         jmp     2f
 271 1:
 272         fstp    %st(0)                  / t=[t] , y , x
 273         fld1                            / 1 , t , y , x
 274         fscale                          / 1*2**t = x**y , t , y , x
 275 2:
 276         fstp    %st(1)                  / x**y , y , x
 277         cmpl    $1,%ecx
 278         jne     .signok
 279         fchs                            / change sign since x<0 & y=-int
 280 .signok:
 281         fstp    %st(2)                  / y , x**y
 282         fstp    %st(0)                  / x**y
 283         ret
 284 
 285 / ------------------------------------------------------------------------
 286 
 287 .xispinf:
 288         ftst                            / compare %st(0) with 0
 289         fnstsw  %ax                     / store status in %ax
 290         sahf                            / 80387 flags in %ax to 80386 flags
 291         ja      .retpinf                / y > 0
 292         jmp     .retpzero               / y < 0
 293 
 294 .xisninf:
 295         / -inf ** +-y is -0 ** -+y
 296         fchs                            / -y , x
 297         flds    PIC_L(negzero)          / -0 , -y , x
 298         fstp    %st(2)                  / -y , -0
 299         jmp     .xisnzero
 300 
 301 .yispinf:
 302         fld     %st(1)                  / x , y , x
 303         fabs                            / |x| , y , x
 304         fcomps  PIC_L(one)              / y , x
 305         fnstsw  %ax                     / store status in %ax
 306         sahf                            / 80387 flags in %ax to 80386 flags
 307         je      .retponeorinvalid       / x == -1       C99
 308         ja      .retpinf                / |x| > 1
 309         jmp     .retpzero               / |x| < 1
 310 
 311 .yisninf:
 312         fld     %st(1)                  / x , y , x
 313         fabs                            / |x| , y , x
 314         fcomps  PIC_L(one)              / y , x
 315         fnstsw  %ax                     / store status in %ax
 316         sahf                            / 80387 flags in %ax to 80386 flags
 317         je      .retponeorinvalid       / x == -1       C99
 318         ja      .retpzero               / |x| > 1
 319         jmp     .retpinf                / |x| < 1
 320 
 321 .xispzero:
 322         / y cannot be 0 or NaN ; stack has      y , x
 323         ftst                            / compare %st(0) with 0
 324         fnstsw  %ax                     / store status in %ax
 325         sahf                            / 80387 flags in %ax to 80386 flags
 326         ja      .retpzero               / y > 0
 327         / x = +0 & y < 0 so x**y = +inf
 328         jmp     .retpinfzflag           / ret +inf & z flag
 329 
 330 .xisnzero:
 331         / y cannot be 0 or NaN ; stack has      y , x
 332         call    .y_is_int
 333         cmpl    $1,%ecx
 334         jne     1f                      / y is not an odd integer
 335         / y is an odd integer
 336         ftst                            / compare %st(0) with 0
 337         fnstsw  %ax                     / store status in %ax
 338         sahf                            / 80387 flags in %ax to 80386 flags
 339         ja      .retnzero               / y > 0
 340         / x = -0 & y < 0 (odd int)       return -inf (z flag)
 341         / x = -inf & y != 0 or NaN  return -inf (NO z flag)
 342         movb    %dh,%cl
 343         andb    $0x45,%cl
 344         cmpb    $0x05,%cl               / C3=0 C2=1 C1=? C0=1 when +-inf
 345         je      2f
 346         fdiv    %st,%st(1)              / y / x, x (raise z flag)
 347 2:
 348         fstp    %st(0)                  / x
 349         fstp    %st(0)                  / stack empty
 350         flds    PIC_L(ninfinity)        / -inf
 351         ret
 352 
 353 1:      / y is not an odd integer
 354         ftst                            / compare %st(0) with 0
 355         fnstsw  %ax                     / store status in %ax
 356         sahf                            / 80387 flags in %ax to 80386 flags
 357         ja      .retpzero               / y > 0
 358         / x = -0 & y < 0 (not odd int)   return +inf (z flag)
 359         / x = -inf & y not 0 or NaN         return +inf (NO z flag)
 360         movb    %dh,%cl
 361         andb    $0x45,%cl
 362         cmpb    $0x05,%cl               / C3=0 C2=1 C1=? C0=1 when +-inf
 363         jne     .retpinfzflag           / ret +inf & divide-by-0 flag
 364         jmp     .retpinf                / return +inf (NO z flag)
 365 
 366 .retpzero:
 367         fstp    %st(0)                  / x
 368         fstp    %st(0)                  / stack empty
 369         fldz                            / +0
 370         ret
 371 
 372 .retnzero:
 373         fstp    %st(0)                  / x
 374         fstp    %st(0)                  / stack empty
 375         flds    PIC_L(negzero)          / -0
 376         ret
 377 
 378 .retponeorinvalid:
 379         PIC_G_LOAD(movzwl,__xpg6,eax)
 380         andl    $_C99SUSv3_pow_treats_Inf_as_an_even_int,%eax
 381         cmpl    $0,%eax
 382         je      1f
 383         fstp    %st(0)                  / x
 384         fstp    %st(0)                  / stack empty
 385         fld1                            / 1
 386         ret
 387 
 388 1:
 389         fstp    %st(0)                  / x
 390         fstp    %st(0)                  / stack empty
 391         flds    PIC_L(Snan)             / Q NaN (i flag)
 392         fwait
 393         ret
 394 
 395 .retpinf:
 396         fstp    %st(0)                  / x
 397         fstp    %st(0)                  / stack empty
 398         flds    PIC_L(pinfinity)        / +inf
 399         ret
 400 
 401 .retpinfzflag:
 402         fstp    %st(0)                  / x
 403         fstp    %st(0)                  / stack empty
 404         fldz
 405         fdivrs  PIC_L(one)              / 1/0
 406         ret
 407 
 408 / Set %ecx to 2 if y is an even integer, 1 if y is an odd integer,
 409 / 0 otherwise.  Assume y is not zero.  Do not raise inexact or modify
 410 / %edx.
 411 .y_is_int:
 412         movl    28(%ebp),%eax
 413         andl    $0x7fff,%eax            / exponent of y
 414         cmpl    $0x403f,%eax
 415         jae     1f                      / |y| >= 2^64, an even int
 416         cmpl    $0x3fff,%eax
 417         jb      2f                      / |y| < 1, can't be an int
 418         movl    %eax,%ecx
 419         subl    $0x403e,%ecx
 420         negl    %ecx                    / 63 - unbiased exponent of y
 421         movl    20(%ebp),%eax
 422         bsfl    %eax,%eax               / index of least sig. 1 bit
 423         jne     3f                      / jump if 1 bit found
 424         movl    24(%ebp),%eax
 425         bsfl    %eax,%eax
 426         addl    $32,%eax                / 32 + index of least sig. 1 bit
 427 3:
 428         cmpl    %ecx,%eax
 429         jb      2f
 430         ja      1f
 431         movl    $1,%ecx
 432         ret
 433 1:
 434         movl    $2,%ecx
 435         ret
 436 2:
 437         xorl    %ecx,%ecx
 438         ret
 439         .align  4
 440         SET_SIZE(powl)