Thread: Anyone knows why sqrt() call checks this?

  1. #1
    Registered User
    Join Date
    Feb 2019
    Posts
    647

    Anyone knows why sqrt() call checks this?

    In this simple code, for x86-64:

    Code:
    double f( double x ) { return sqrt( x ); }
    The compiler creates code like this:

    Code:
    f:
      pxor    xmm2, xmm2
      sqrtsd  xmm1, xmm0
      ucomisd xmm2, xmm0
      ja  .L8             ; 0 > x?
      movapd  xmm0, xmm1
      ret
    .L8:
      sub     rsp, 24
    
      ; store SQRTSD result on stack.
      movsd   QWORD [rsp+8], xmm1
    
      call    sqrt   ; why? sqrt() doesn't use the stack!
    
      ; Get result back from stack (zeroing upper bits).
      movsd   xmm1, QWORD [rsp+8]
    
      add     rsp, 24
    
      ; Use SQRTSD result anyway!
      movapd  xmm0, xmm1
      ret
    Testing the direct use of SQRTSD against this routine with invalid values (x < 0.0, x = -0.0, +/-NAN or +/-INFINITE) I see no difference. And why calls sqrt() if it will recover XMM1 from stack?

    The compiler does something similar if using fp87 instructions.

    Strange...
    Last edited by flp1969; 04-09-2019 at 05:54 PM.

  2. #2
    Registered User
    Join Date
    Feb 2019
    Posts
    647
    The same thing happens for other processors... What am I missing?

    Cortex-A53 AArch64 code:
    Code:
    f:
      fsqrt d1, d0
      fcmp  d0, #0.0
      bmi .L8
      fmov  d0, d1
      ret
    .L8:
      stp x29, x30, [sp, -32]!
      add x29, sp, 0
      str d1, [x29, 24]
      bl  sqrt
      ldr d1, [x29, 24]
      ldp x29, x30, [sp], 32
      fmov  d0, d1
      ret

  3. #3
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,859
    Have you considered posting that question on a non-C specific board?

    You may get better answers
    Fact - Beethoven wrote his first symphony in C

  4. #4
    Programming Wraith GReaper's Avatar
    Join Date
    Apr 2009
    Location
    Greece
    Posts
    2,728
    It's up to the compiler's discretion how the parameters are passed to functions. Unless mandatory by some specification (such as stdcall), the parameters don't have to be pushed on the stack.
    Devoted my life to programming...

  5. #5
    Registered User
    Join Date
    Feb 2019
    Posts
    647
    Quote Originally Posted by GReaper View Post
    It's up to the compiler's discretion how the parameters are passed to functions. Unless mandatory by some specification (such as stdcall), the parameters don't have to be pushed on the stack.
    That's not the question and I forgot to say under SysV ABI x86-64 (and AArch64) calling convention.

    The question is: Why the C compiler is testing for x < 0, calling the sqrt() library function and using the result of a previous instruction anyways?

  6. #6
    Registered User
    Join Date
    Feb 2019
    Posts
    647
    My test code:
    Code:
    #ifndef __GNUC__
    #error Compiles only on GCC.
    #endif
    
    #if !defined(__386__) && !defined(__x86_64__)
    #error Compiles only for Intel/AMD processors.
    #endif
    
    #include <stdio.h>
    #include <x86intrin.h>
    #include <math.h>
    
    __attribute__((noinline))
    static float sqrtf_sse( float );
    
    __attribute__((noinline))
    static float sqrtf_lm( float );
    
    int main( void )
    {
      static float invalid[] = { -0.0f, -1.0f, NAN, -NAN, INFINITY, -INFINITY };
      float f;
      int i;
    
      for (i = 0; i < sizeof invalid / sizeof invalid[0]; i++)
      {
        f = invalid[i];
    
        printf( "libm sqrtf(%1$f) = %2$f,\n"
                "sse  sqrtf(%1$f) = %3$f\n\n",
          invalid[i], 
          sqrtf_lm( f ),
          sqrtf_sse( f ) );
      }   
    }
    
    // This will be a strange multiple instructions (+RET) not inline code.
    float sqrtf_lm( float x )
    {
      return sqrtf( x );
    }
    
    // This will be a single instruction (+RET) not inline code.
    float sqrtf_sse( float x )
    {
      __m128 r;
    
      __asm__ __volatile__ (
        "sqrtss %0,%1"
        : "=x" (r) : "xm" (x)
      );
    
      return _mm_cvtss_f32( r );
    }
    sqrt_libm() is a code like I showed before. The results (I didn't test for sNaN):

    libm sqrtf(-0.000000) = -0.000000,
    sse sqrtf(-0.000000) = -0.000000

    libm sqrtf(-1.000000) = -nan,
    sse sqrtf(-1.000000) = -nan

    libm sqrtf(nan) = nan,
    sse sqrtf(nan) = nan

    libm sqrtf(-nan) = -nan,
    sse sqrtf(-nan) = -nan

    libm sqrtf(inf) = inf,
    sse sqrtf(inf) = inf

    libm sqrtf(-inf) = -nan,
    sse sqrtf(-inf) = -nan

  7. #7
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,859
    Have you considered sending an email to the developers for your compiler?
    Fact - Beethoven wrote his first symphony in C

  8. #8
    Registered User
    Join Date
    Feb 2019
    Posts
    647
    FYI: This is a BUG of GCC until version 7.3 (Ubuntu/Debian), for i386 and amd64 and ARM AArch64, and version 6.3 for ARM AArch32. MinGW-w64 GCC version 7.3 generates the correct code.

    This bug is inoffensive, since it just ignores the result of libm's sqrtf() -- or sqrt() for doubles -- and uses sqrtss (or sqrtsd or fp87 equivalents if -mfpmath=387) results anyway.

    I don't know if it was fixed on gcc 8.

    PS: Visual Studio (CL.EXE, from VC 14 on VSC 2019) create a simple call to sqrtf(), which is inside MSVCRT??.DLL, and it is slower. NO source code is available (what a surprise!).

  9. #9
    Registered User
    Join Date
    Feb 2019
    Posts
    647
    Follow up from GCC bugzilla... sqrtf(), from libm, is called just to set errno.
    Technically, not a bug, but inefficient code (my comment)...

  10. #10
    Registered User
    Join Date
    Feb 2019
    Posts
    647
    And you can avoid using assembly inline using -ffast-math option (enabled by default only on -Ofast optimization).

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Using Checks in C - Help!
    By saddists in forum C Programming
    Replies: 4
    Last Post: 12-26-2011, 11:14 PM
  2. Replies: 3
    Last Post: 11-12-2009, 10:39 AM
  3. Heuristic Checks
    By cloudy in forum C++ Programming
    Replies: 2
    Last Post: 02-12-2006, 04:08 PM
  4. checks for bad input
    By kocika73 in forum C Programming
    Replies: 8
    Last Post: 09-10-2004, 10:28 AM
  5. No Checks i CheckBox
    By CodeJerk in forum Windows Programming
    Replies: 1
    Last Post: 06-09-2003, 10:50 AM

Tags for this Thread