/* Copyright (C) 2011 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */ #include .data NaN: .long 0xFFC00000 pinf: .long 0x7F800000 .text one: .float 1. frac: /* Calculate st(0) - nint(st(0)) */ fld %st(0) /* x x */ frndint /* nint(x) x */ fxch %st(1) /* x nint(x) */ fsub %st(1), %st ret /* fract(x) nint(x) */ Lpow2: /* Find 2^(fract(st(0))) * 2^st(1) */ call frac /* fract(x) nint(x) */ f2xm1 /* 2^fract(x)-1 nint(x) */ fadds one /* 2^fract(x) nint(x) */ fscale /* 2^x */ fstp %st(1) ret .globl _pow _pow: subl $12, %esp movl 20(%esp), %eax cmpl $0x7FF00000, %eax /* Control flows straight through for */ jae abx testl %eax, %eax /* 0 < x < +inf */ je xverysmall movl 28(%esp), %eax /* Now test y. */ andl $0x7FF00000, %eax cmpl $0x7FF00000, %eax je aby /* y is inf or NaN */ argok: fldl 24(%esp) fldl 16(%esp) fyl2x /* y*log2(x) */ call Lpow2 jmp test_result xverysmall: /* exp = max negative */ movl 16(%esp), %eax testl %eax, %eax jne argok /* x > 0; proceed */ fldl 24(%esp) /* Load y */ xzero: /* x == 0; y is in st(0); test y */ ftst fnstsw %ax sahf fstp %st(0) ja zeroresult /* x = 0 y > 0 */ jb infresult /* x = 0, y < 0 (including y = -inf) */ /* x = 0, y = 0: */ fld1 /* return 1 but raise EDOM */ movl $1, _errno jmp CleanUp badresult: movl $1, _errno flds NaN jmp CleanUp zeroresult: fldz jmp CleanUp infresult: flds pinf jmp CleanUp aby: /* y is inf or NaN */ testl $0x000FFFFF, 28(%esp) jnz badresult /* Test for y = NaN */ movl 24(%esp), %eax testl %eax, %eax jnz badresult /* y = NaN */ /* At this point y = +/- inf. x < 0, y= inf --> return NaN |x| < 1, y=+inf or |x| > 1, y=-inf --> return 0; |x| < 1, y=-inf or |x| > 1, y=+inf --> return +inf; |x| = 1, y = +/- inf --> return NaN */ movl 20(%esp), %eax /* Get x */ testl $0x80000000, %eax jnz badresult /* x < 0, y = inf */ andl $0x7FF00000, %eax movl 16(%esp), %edx orw %dx, %ax /* OR in low bits of mantissa */ shrl $16, %edx orw %dx, %ax subl $0x3FF00000, %eax /* Integer comparison of x against 1 */ testl $0x80000000, 28(%esp) /* Test sign of y */ jns ns negl %eax ns: testl %eax, %eax jz badresult js zeroresult jmp infresult abx: andl $0x7FF00000, %eax cmpl $0x7FF00000, %eax je badx /* x = inf or NaN */ testl %eax, %eax /* x is -finite -- must test for -0 */ jnz xltz movl 16(%esp), %eax testl %eax, %eax fldl 24(%esp) jz xzero /* x = -0 */ xltz: movl 28(%esp), %eax /* Test y. */ andl $0x7FF00000, %eax cmpl $0x7FF00000, %eax je aby /* y is inf or NaN */ fldl 24(%esp) /* x < 0 */ fldl 16(%esp) fabs fxch %st(1) call frac ftst fnstsw %ax fstp %st(0) sahf je yisint fstp %st(0) /* x < 0, y != integer */ fstp %st(0) jmp badresult yisint: fld %st fistpq (%esp) fxch %st(1) fyl2x call Lpow2 andl $1, (%esp) jz yeven fchs yeven: jmp test_result badx: /* x = inf or NaN */ testl $0x000FFFFF, 20(%esp) jnz badresult /* x = NaN */ movl 16(%esp), %eax testl %eax, %eax jnz badresult /* x = NaN */ fldl 24(%esp) /* x = inf; pow(inf, y) = pow(0,-y) */ fchs jmp xzero test_result: fstl (%esp) movl 4(%esp), %eax andl $0x7FFFFFFF, %eax cmpl $0x7FF00000, %eax /* Overflow */ jge range_error cmpl $0x00080000, %eax /* Underflow */ jl range_error CleanUp: addl $12, %esp ret range_error: movl $2, _errno jmp CleanUp