Page 1 sur 1

Log10() optimisé MMX

Publié : dim. 01/mai/2005 15:47
par KarLKoX
Bonjour, je vous présente mon premier code asm ... honteusement copié depuis le Visual C++ Processor Pack.
J'avais besoin d'une telle fonction et je l'ai adaptée pour PureBasic :

Code : Tout sélectionner

;- Start Of Misc Asm Functions

; Taken from the VisualC++ Processor Pack and adapted for use with PureBasic
Global  fval.f
Global  mant
Global  expo
Global  one
Global  half
Global  two
Global  rt2
Global  edec
Global  bias
Global  ln2lo
Global  ln2hi
Global  c2
Global  c1
Global  c0
Global  maxn
Global  rle10

Procedure a_log()

        !movd        mm6, [v_mant]    ; mask for mantissa           
        !movq        mm4, mm0         ; save x                            
        !movd        mm2, [v_expo]    ; mask for exponent      
        !pand        mm0, mm6         ; extract mantissa of x => m 
        !movd        mm3, [v_one]     ; 1.0                            
        !pand        mm4, mm2         ; extract biased exponent of x => e 
        !por         mm0, mm3         ; float(m)                            
        !movd        mm3, [v_rt2]     ; sqrt(2)                             
        !psrld       mm4, 23          ; biased exponent e               
        !movq        mm2, mm0         ; save m                    
        !pxor        mm5, mm5         ; create 0                     
        !movd        mm6, [v_edec]    ; 0x0080000                         
        !pcmpgtd     mm0, mm3         ; m > sqrt(2) ? 0xFFFFFFFF : 0        
        !pcmpeqd     mm5, mm4         ; sel = (e == 0) ? 0xFFFFFFFFL : 0
        !psubd       mm4, mm0         ; increment e if m > sqrt(2)          
        !movd        mm3, [v_bias]    ; 127                             
        !pand        mm0, mm6         ; m > sqrt(2) ? 0x00800000 : 0
        !movd        mm6, [v_one]     ; 1.0                                
        !psubd       mm2, mm0         ; if m > sqrt(2),  m = m/2      
        !psubd       mm4, mm3         ; true exponent = i                  
        !movq        mm0, mm2         ; save m                             
        !pfadd       mm2, mm6         ; m + 1
        !pfsub       mm0, mm6         ; m - 1                          
        !pi2fd       mm4, mm4         ; float(i)
        !movd        mm7, [v_ln2lo]   ; lower 24 bits of ln(2)
        !pfrcp       mm6, mm2         ; approx 1/mm+1) lo
        !movd        mm3, [v_ln2hi]   ; upper 16 bits of ln(2)
        !pfrcpit1    mm2, mm6         ; refine 1/mm+1) 
        !pfmul       mm7, mm4         ; i*ln2lo
        !pfmul       mm3, mm4         ; i*ln2hi
        !movd        mm4, [v_c2]      ; c2             
        !pfrcpit2    mm2, mm6         ; 1/mm+1)        
        !movd        mm1, [v_c1]      ; c1        
        !pfmul       mm2, mm0         ; z=mm+1)/mm-1)                         
        !movq        mm0, mm2         ; save z                            
        !pfadd       mm0, mm0         ; 2*z
        !pfmul       mm2, mm2         ; z^2                             
        !movq        mm6, mm2         ; save z^2                             
        !pfmul       mm2, mm4         ; c2 * z^2                          
        !movd        mm4, [v_c0]      ; c0               
        !pfadd       mm2, mm1         ; c2 * z^2 + c1        
        !pfmul       mm2, mm6         ; (c2 * z^2 + c1) * z^2
        !movd        mm1, [v_maxn]    ; maxn (negative largest normal)             
        !pfmul       mm6, mm0         ; 2*z^3
        !pfadd       mm2, mm4         ; px = (c2 * z^2 + c1) * z^2 + c0
        !pfmul       mm2, mm6         ; px*2*z^3
        !pfadd       mm2, mm0         ; px*2*z^3+2*z
        !movq        mm0, mm5         ; sel                               
        !pand        mm5, mm1         ; select largest negative normal if e = 0
        !pfadd       mm2, mm7         ; px*2*z^3+2*z+i*ln2lo
        !pfadd       mm2, mm3         ; ln(z)=px*2*z^3+2*z+i*ln2lo+i*ln2hi
        !pandn       mm0, mm2         ; select regular result if e != 0
        !por         mm0, mm5         ; mux in either normal or special result

EndProcedure

Procedure a_Log10(x.f, *out.f)

        mant      = $007FFFFF
        expo      = $7F800000
        one       = $3F800000
        half      = $3F000000
        two       = $40000000
        rt2       = $3FB504F3
        edec      = $00800000
        bias      = $0000007F
        ln2lo     = $35BFBE8E
        ln2hi     = $3F317200
        c2        = $3E18EFE2
        c1        = $3E4CAF6F
        c0        = $3EAAAABD
        maxn      = $FF7FFFFF
        rle10     = $3EDE5BDB

        !FEMMS
        !movd        mm0, dword [esp]
         a_log()                      ; mm0 = ln(x)
        !movd        mm1, [v_rle10]   ; mm1 = 1/ln(10)
        !pfmul       mm0, mm1         ; mm0 = ln(x) / ln(10)
        !movd        [v_fval], mm0    ; Result in mm0
        !FEMMS
  
        PokeF(*out, fval)

EndProcedure