Goto sanos source index
;-----------------------------------------------------------------------------
; pow.asm - floating point power
; Ported from Al Maromaty's free C Runtime Library
;-----------------------------------------------------------------------------
SECTION .text
global pow
global _pow
global __CIpow
fzero: dq 0.0e0 ; Floating point zero
pow:
_pow:
push ebp
mov ebp,esp
sub esp,12 ; Allocate temporary space
push edi ; Save register edi
push eax ; Save register eax
mov dword [ebp-12],0 ; Set negation flag to zero
fld qword [ebp+16] ; Load real from stack
fld qword [ebp+8] ; Load real from stack
mov edi, fzero ; Point to real zero
fcom qword [edi] ; Compare x with zero
fstsw ax ; Get the FPU status word
mov al,ah ; Move condition flags to AL
lahf ; Load Flags into AH
and al, 01000101B ; Isolate C0, C2 and C3
and ah,~01000101B ; Turn off CF, PF and ZF
or ah,al ; Set new CF, PF and ZF
sahf ; Store AH into Flags
jb __fpow1 ; Re-direct if x < 0
ja __fpow3 ; Re-direct if x > 0
fxch ; Swap st, st(1)
fcom qword [edi] ; Compare y with zero
fxch ; Restore x as top of stack
fstsw ax ; Get the FPU status word
mov al,ah ; Move condition flags to AL
lahf ; Load Flags into AH
and al, 01000101B ; Isolate C0, C2 and C3
and ah,~01000101B ; Turn off CF, PF and ZF
or ah,al ; Set new CF, PF and ZF
sahf ; Store AH into Flags
ja __fpow3 ; Re-direct if y > 0
fstp st1 ; Set new stack top and pop
mov eax,1 ; Set domain error (EDOM)
jmp __fpow5 ; End of case
__fpow1: fxch ; Put y on top of stack
fld st0 ; Duplicate y as st1
frndint ; Round to integer
fxch ; Put y on top of stack
fcomp ; y = int(y) ?
fstsw ax ; Get the FPU status word
mov al,ah ; Move condition flags to AL
lahf ; Load Flags into AH
and al, 01000101B ; Isolate C0, C2 and C3
and ah,~01000101B ; Turn off CF, PF and ZF
or ah,al ; Set new CF, PF and ZF
sahf ; Store AH into Flags
je __fpow2 ; Proceed if y = int(y)
fstp st1 ; Set new stack top and pop
fldz ; Set result to zero
fstp st1 ; Set new stack top and pop
mov eax,1 ; Set domain error (EDOM)
jmp __fpow5 ; End of case
__fpow2: fist dword [ebp-12] ; Store y as integer
and dword [ebp-12],1 ; Set bit if y is odd
fxch ; Put x on top of stack
fabs ; x = |x|
__fpow3: fldln2 ; Load log base e of 2
fxch st1 ; Exchange st0, st1
fyl2x ; Compute the natural log(x)
fmul ; Compute y * ln(x)
fldl2e ; Load log base 2(e)
fmulp st1,st0 ; Multiply x * log base 2(e)
fst st1 ; Push result
frndint ; Round to integer
fsub st1,st0 ; Subtract
fxch ; Exchange st0, st1
f2xm1 ; Compute 2 to the (x - 1)
fld1 ; Load real number 1
fadd ; 2 to the x
fscale ; Scale by power of 2
fstp st1 ; Set new stack top and pop
test dword [ebp-12],1 ; Negation required ?
jz __fpow4 ; No, re-direct
fchs ; Negate the result
__fpow4: fstp qword [ebp-8] ; Save (double)pow(x, y)
fld qword [ebp-8] ; Load (double)pow(x, y)
fxam ; Examine st
fstsw ax ; Get the FPU status word
cmp ah,5 ; Infinity ?
jne __fpow6 ; No, end of case
mov eax,2 ; Set range error (ERANGE)
; Get errno pointer offset
__fpow5: int 3
mov edi,0 ; TODO: offset flat:__crt_errno
mov edi,[edi] ; Get C errno variable pointer
mov dword [edi],eax ; Set errno
__fpow6: pop eax ; Restore register eax
pop edi ; Restore register edi
mov esp,ebp ; Deallocate temporary space
pop ebp
ret
__CIpow:
sub esp,16 ; Allocate stack space for args
fstp qword [esp+8] ; Copy y onto stack
fstp qword [esp] ; Copy x onto stack
call _pow ; Call pow
add esp,16 ; Remove args from stack
ret